From 4ecf7c97795a405e652e54b35d4528aa5012ab60 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 9 Feb 2020 10:03:11 +0800 Subject: [PATCH 001/562] implement projection in one unit. other descriptors does not work due to the change of interface --- source/lib/include/ComputeDescriptor.h | 126 +++++++++++++ source/op/CMakeLists.txt | 2 +- source/tests/common.py | 18 +- source/tests/test_descrpt_nonsmth.py | 1 + source/tests/test_descrpt_se_ar.py | 1 + source/tests/test_descrpt_se_r.py | 1 + source/tests/test_descrpt_sea_ef.py | 184 ++++++++++++++++++ source/tests/test_descrpt_smooth.py | 1 + source/train/DescrptSeA.py | 1 + source/train/DescrptSeAEf.py | 248 +++++++++++++++++++++++++ source/train/Model.py | 4 +- source/train/Trainer.py | 3 + 12 files changed, 586 insertions(+), 4 deletions(-) create mode 100644 source/tests/test_descrpt_sea_ef.py create mode 100644 source/train/DescrptSeAEf.py diff --git a/source/lib/include/ComputeDescriptor.h b/source/lib/include/ComputeDescriptor.h index 4082f7b19a..7b579cd3d2 100644 --- a/source/lib/include/ComputeDescriptor.h +++ b/source/lib/include/ComputeDescriptor.h @@ -82,6 +82,22 @@ void compute_descriptor_se_a (vector & descrpt_a, const double & rmin, const double & rmax); +inline +void compute_descriptor_se_a_extf (vector & descrpt_a, + vector & descrpt_a_deriv, + vector & rij_a, + const vector & posi, + const int & ntypes, + const vector & type, + const SimulationRegion & region, + const bool & b_pbc, + const vector & efield, + const int & i_idx, + const vector & fmt_nlist_a, + const vector & sec_a, + const double & rmin, + const double & rmax); + inline void compute_descriptor_se_r (vector & descrpt_r, vector & descrpt_r_deriv, @@ -1087,4 +1103,114 @@ void compute_descriptor_se_r (vector & descrpt, } +// output deriv size: n_sel_a_nei x 4 x 12 +// (1./rr, cos_theta, cos_phi, sin_phi) x 4 x (x, y, z) +void compute_descriptor_se_a_extf (vector & descrpt_a, + vector & descrpt_a_deriv, + vector & rij_a, + const vector & posi, + const int & ntypes, + const vector & type, + const SimulationRegion & region, + const bool & b_pbc, + const vector & efield, + const int & i_idx, + const vector & fmt_nlist_a, + const vector & sec_a, + const double & rmin, + const double & rmax) +{ + const double * ef_ = &efield[i_idx*3+0]; + double ef[3] = {0.}; + if (isnan(ef_[0]) || isnan(ef_[1]) || isnan(ef_[2])){ + ef[0] = 1.; + ef[1] = ef[2] = 0.; + } + else { + for (int ii = 0; ii < 3; ++ii){ + ef[ii] = ef_[ii]; + } + } + assert( fabs(MathUtilities::dot(ef, ef) - 1.0) < 1e-12 ), "ef should be a normalized vector"; + + // compute the diff of the neighbors + vector > sel_a_diff (sec_a.back()); + rij_a.resize (sec_a.back() * 3); + fill (rij_a.begin(), rij_a.end(), 0.0); + for (int ii = 0; ii < int(sec_a.size()) - 1; ++ii){ + for (int jj = sec_a[ii]; jj < sec_a[ii+1]; ++jj){ + if (fmt_nlist_a[jj] < 0) break; + sel_a_diff[jj].resize(3); + const int & j_idx = fmt_nlist_a[jj]; + if (b_pbc){ + region.diffNearestNeighbor (posi[j_idx*3+0], posi[j_idx*3+1], posi[j_idx*3+2], + posi[i_idx*3+0], posi[i_idx*3+1], posi[i_idx*3+2], + sel_a_diff[jj][0], sel_a_diff[jj][1], sel_a_diff[jj][2]); + } + else { + for (int dd = 0; dd < 3; ++dd) sel_a_diff[jj][dd] = posi[j_idx*3+dd] - posi[i_idx*3+dd]; + } + for (int dd = 0; dd < 3; ++dd) rij_a[jj*3+dd] = sel_a_diff[jj][dd]; + } + } + + // 1./rr, cos(theta), cos(phi), sin(phi) + descrpt_a.resize (sec_a.back() * 4); + fill (descrpt_a.begin(), descrpt_a.end(), 0.0); + // deriv wrt center: 3 + descrpt_a_deriv.resize (sec_a.back() * 4 * 3); + fill (descrpt_a_deriv.begin(), descrpt_a_deriv.end(), 0.0); + + for (int sec_iter = 0; sec_iter < int(sec_a.size()) - 1; ++sec_iter){ + for (int nei_iter = sec_a[sec_iter]; nei_iter < sec_a[sec_iter+1]; ++nei_iter) { + if (fmt_nlist_a[nei_iter] < 0) break; + const double * rr = &sel_a_diff[nei_iter][0]; + // check validity of ef + double nr2 = MathUtilities::dot(rr, rr); + double inr = 1./sqrt(nr2); + double nr = nr2 * inr; + double inr2 = inr * inr; + double inr4 = inr2 * inr2; + double inr3 = inr4 * nr; + double sw, dsw; + spline5_switch(sw, dsw, nr, rmin, rmax); + int idx_deriv = nei_iter * 4 * 3; // 4 components time 3 directions + int idx_value = nei_iter * 4; // 4 components + // projections + double rp = MathUtilities::dot(rr, ef); + double rv[3]; + rv[0] = rr[0] - rp * ef[0]; + rv[1] = rr[1] - rp * ef[1]; + rv[2] = rr[2] - rp * ef[2]; + // 4 value components + descrpt_a[idx_value + 0] = rp / nr2; + descrpt_a[idx_value + 1] = rv[0] / nr2; + descrpt_a[idx_value + 2] = rv[1] / nr2; + descrpt_a[idx_value + 3] = rv[2] / nr2; + // deriv of component rp/r2 + descrpt_a_deriv[idx_deriv + 0] = (2. * inr4 * rp * rr[0] - inr2 * ef[0]) * sw - descrpt_a[idx_value + 0] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv + 1] = (2. * inr4 * rp * rr[1] - inr2 * ef[1]) * sw - descrpt_a[idx_value + 0] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv + 2] = (2. * inr4 * rp * rr[2] - inr2 * ef[2]) * sw - descrpt_a[idx_value + 0] * dsw * rr[2] * inr; + // deriv of component rvx/r2 + descrpt_a_deriv[idx_deriv + 3] = (2. * inr4 * rv[0] * rr[0] - inr2 * (1. - ef[0] * ef[0])) * sw - descrpt_a[idx_value + 1] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv + 4] = (2. * inr4 * rv[0] * rr[1] - inr2 * ( - ef[0] * ef[1])) * sw - descrpt_a[idx_value + 1] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv + 5] = (2. * inr4 * rv[0] * rr[2] - inr2 * ( - ef[0] * ef[2])) * sw - descrpt_a[idx_value + 1] * dsw * rr[2] * inr; + // deriv of component rvy/r2 + descrpt_a_deriv[idx_deriv + 6] = (2. * inr4 * rv[1] * rr[0] - inr2 * ( - ef[1] * ef[0])) * sw - descrpt_a[idx_value + 2] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv + 7] = (2. * inr4 * rv[1] * rr[1] - inr2 * (1. - ef[1] * ef[1])) * sw - descrpt_a[idx_value + 2] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv + 8] = (2. * inr4 * rv[1] * rr[2] - inr2 * ( - ef[1] * ef[2])) * sw - descrpt_a[idx_value + 2] * dsw * rr[2] * inr; + // deriv of component rvz/r2 + descrpt_a_deriv[idx_deriv + 9] = (2. * inr4 * rv[2] * rr[0] - inr2 * ( - ef[2] * ef[0])) * sw - descrpt_a[idx_value + 3] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv +10] = (2. * inr4 * rv[2] * rr[1] - inr2 * ( - ef[2] * ef[1])) * sw - descrpt_a[idx_value + 3] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv +11] = (2. * inr4 * rv[2] * rr[2] - inr2 * (1. - ef[2] * ef[2])) * sw - descrpt_a[idx_value + 3] * dsw * rr[2] * inr; + // 4 value components + descrpt_a[idx_value + 0] *= sw; + descrpt_a[idx_value + 1] *= sw; + descrpt_a[idx_value + 2] *= sw; + descrpt_a[idx_value + 3] *= sw; + } + } +} + + diff --git a/source/op/CMakeLists.txt b/source/op/CMakeLists.txt index 89416056e1..fac2bfb7a2 100644 --- a/source/op/CMakeLists.txt +++ b/source/op/CMakeLists.txt @@ -3,7 +3,7 @@ set(OP_LIB ${PROJECT_SOURCE_DIR}/lib/src/SimulationRegion.cpp ${PROJECT_SOURCE_DIR}/lib/src/NeighborList.cpp) set (OP_CXX_FLAG -D_GLIBCXX_USE_CXX11_ABI=${OP_CXX_ABI} ) -file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_r.cc tab_inter.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc) +file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_r.cc tab_inter.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc) file(GLOB OP_CUDA_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a_gpu.cc descrpt_se_r_gpu.cc tab_inter.cc prod_force_se_a_gpu.cc prod_virial_se_a_gpu.cc prod_force_se_r_gpu.cc prod_virial_se_r_gpu.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ) file(GLOB OP_GRADS_SRC prod_force_grad.cc prod_force_se_a_grad.cc prod_force_se_r_grad.cc prod_virial_grad.cc prod_virial_se_a_grad.cc prod_virial_se_r_grad.cc soft_min_force_grad.cc soft_min_virial_grad.cc ) file(GLOB OP_PY *.py) diff --git a/source/tests/common.py b/source/tests/common.py index f92fe397cc..b3374cff80 100644 --- a/source/tests/common.py +++ b/source/tests/common.py @@ -58,6 +58,7 @@ def __init__ (self, self.coord = self.coord.reshape([self.nframes, -1, 3]) self.coord = self.coord[:,self.idx_map,:] self.coord = self.coord.reshape([self.nframes, -1]) + self.efield = np.random.random(self.coord.shape) self.atype = self.atype[self.idx_map] self.datype = self._copy_nframes(self.atype) @@ -128,6 +129,7 @@ def get_test_box_data (self, all_coord = [coord.reshape([nframes, natoms*3])] all_box = [box.reshape([nframes,9])] all_atype = [atype] + all_efield = [self.efield] for ii in range(3): for jj in range(3): box3p = np.copy(box3) @@ -146,10 +148,13 @@ def get_test_box_data (self, all_box.append(boxm) all_atype.append(atype) all_atype.append(atype) + all_efield.append(self.efield) + all_efield.append(self.efield) all_coord = np.reshape(all_coord, [-1, natoms * 3]) all_box = np.reshape(all_box, [-1, 9]) all_atype = np.reshape(all_atype, [-1, natoms]) - return all_coord, all_box, all_atype + all_efield = np.reshape(all_efield, [-1, natoms * 3]) + return all_coord, all_box, all_atype, all_efield def force_test (inter, @@ -166,12 +171,14 @@ def force_test (inter, inter.sess.run (tf.global_variables_initializer()) # get data dcoord, dbox, dtype = inter.data.get_data () + defield = inter.data.efield # cmp e0, f0 [energy, force] = inter.sess.run ([t_energy, t_force], feed_dict = { inter.coord: dcoord, inter.box: dbox, inter.type: dtype, + inter.efield: defield, inter.tnatoms: inter.natoms} ) # dim force @@ -187,6 +194,7 @@ def force_test (inter, inter.coord: dcoordp, inter.box: dbox, inter.type: dtype, + inter.efield: defield, inter.tnatoms: inter.natoms} ) [enerm] = inter.sess.run ([t_energy], @@ -194,6 +202,7 @@ def force_test (inter, inter.coord: dcoordm, inter.box: dbox, inter.type: dtype, + inter.efield: defield, inter.tnatoms: inter.natoms} ) c_force = -(enerp[0] - enerm[0]) / (2*hh) @@ -217,7 +226,7 @@ def virial_test (inter, = inter.comp_ef (inter.coord, inter.box, inter.type, inter.tnatoms, name = "test_v" + suffix) inter.sess.run (tf.global_variables_initializer()) # get data - dcoord, dbox, dtype = inter.data.get_test_box_data(hh) + dcoord, dbox, dtype, defield = inter.data.get_test_box_data(hh) # cmp e, f, v [energy, force, virial] \ = inter.sess.run ([t_energy, t_force, t_virial], @@ -225,6 +234,7 @@ def virial_test (inter, inter.coord: dcoord, inter.box: dbox, inter.type: dtype, + inter.efield: defield, inter.tnatoms: inter.natoms} ) ana_vir = virial[0].reshape([3,3]) @@ -251,10 +261,12 @@ def force_dw_test (inter, hh = global_default_dw_hh, suffix = '') : dcoord, dbox, dtype = inter.data.get_data() + defield = inter.data.efield feed_dict_test0 = { inter.coord: dcoord, inter.box: dbox, inter.type: dtype, + inter.efield: defield, inter.tnatoms: inter.natoms} w0 = np.ones (inter.ndescrpt) @@ -297,10 +309,12 @@ def virial_dw_test (inter, hh = global_default_dw_hh, suffix = '') : dcoord, dbox, dtype = inter.data.get_data() + defield = inter.data.efield feed_dict_test0 = { inter.coord: dcoord, inter.box: dbox, inter.type: dtype, + inter.efield: defield, inter.tnatoms: inter.natoms} w0 = np.ones (inter.ndescrpt) diff --git a/source/tests/test_descrpt_nonsmth.py b/source/tests/test_descrpt_nonsmth.py index 7d12e01e74..450e30295d 100644 --- a/source/tests/test_descrpt_nonsmth.py +++ b/source/tests/test_descrpt_nonsmth.py @@ -59,6 +59,7 @@ def setUp (self, self.box = tf.placeholder(global_tf_float_precision, [None, 9], name='t_box') self.type = tf.placeholder(tf.int32, [None, self.natoms[0]], name = "t_type") self.tnatoms = tf.placeholder(tf.int32, [None], name = "t_natoms") + self.efield = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_efield') def _net (self, diff --git a/source/tests/test_descrpt_se_ar.py b/source/tests/test_descrpt_se_ar.py index 01c9e99496..ed49a71e08 100644 --- a/source/tests/test_descrpt_se_ar.py +++ b/source/tests/test_descrpt_se_ar.py @@ -68,6 +68,7 @@ def setUp (self, self.box = tf.placeholder(global_tf_float_precision, [None, 9], name='t_box') self.type = tf.placeholder(tf.int32, [None, self.natoms[0]], name = "t_type") self.tnatoms = tf.placeholder(tf.int32, [None], name = "t_natoms") + self.efield = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_efield') def _net (self, inputs, diff --git a/source/tests/test_descrpt_se_r.py b/source/tests/test_descrpt_se_r.py index fa21712f90..f1ab40ac52 100644 --- a/source/tests/test_descrpt_se_r.py +++ b/source/tests/test_descrpt_se_r.py @@ -55,6 +55,7 @@ def setUp (self, self.box = tf.placeholder(global_tf_float_precision, [None, 9], name='t_box') self.type = tf.placeholder(tf.int32, [None, self.natoms[0]], name = "t_type") self.tnatoms = tf.placeholder(tf.int32, [None], name = "t_natoms") + self.efield = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_efield') def _net (self, inputs, diff --git a/source/tests/test_descrpt_sea_ef.py b/source/tests/test_descrpt_sea_ef.py new file mode 100644 index 0000000000..8537bf30f0 --- /dev/null +++ b/source/tests/test_descrpt_sea_ef.py @@ -0,0 +1,184 @@ +import os,sys +import numpy as np +import unittest + +from deepmd.env import tf +from tensorflow.python.framework import ops + +# load grad of force module +import deepmd._prod_force_grad +import deepmd._prod_virial_grad +import deepmd._prod_force_se_a_grad +import deepmd._prod_virial_se_a_grad +import deepmd._soft_min_force_grad +import deepmd._soft_min_virial_grad + +from common import force_test +from common import virial_test +from common import force_dw_test +from common import virial_dw_test +from common import Data + +from deepmd.DescrptLocFrame import op_module + +from deepmd.RunOptions import global_tf_float_precision +from deepmd.RunOptions import global_np_float_precision +from deepmd.RunOptions import global_ener_float_precision + +class Inter(): + def setUp (self, + data, + pbc = True) : + self.sess = tf.Session() + self.data = data + self.natoms = self.data.get_natoms() + self.ntypes = self.data.get_ntypes() + self.sel_a = [12,24] + self.sel_r = [0,0] + self.rcut_a = -1 + self.rcut_r_smth = 2.45 + self.rcut_r = 10.0 + self.nnei_a = np.cumsum(self.sel_a)[-1] + self.nnei_r = np.cumsum(self.sel_r)[-1] + self.nnei = self.nnei_a + self.nnei_r + self.ndescrpt_a = self.nnei_a * 4 + self.ndescrpt_r = self.nnei_r * 1 + self.ndescrpt = self.ndescrpt_a + self.ndescrpt_r + davg = np.zeros ([self.ntypes, self.ndescrpt]) + dstd = np.ones ([self.ntypes, self.ndescrpt]) + self.t_avg = tf.constant(davg.astype(global_np_float_precision)) + self.t_std = tf.constant(dstd.astype(global_np_float_precision)) + if pbc: + self.default_mesh = np.zeros (6, dtype = np.int32) + self.default_mesh[3] = 2 + self.default_mesh[4] = 2 + self.default_mesh[5] = 2 + else: + self.default_mesh = np.array([], dtype = np.int32) + # make place holder + self.coord = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_coord') + self.efield = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_efield') + self.box = tf.placeholder(global_tf_float_precision, [None, 9], name='t_box') + self.type = tf.placeholder(tf.int32, [None, self.natoms[0]], name = "t_type") + self.tnatoms = tf.placeholder(tf.int32, [None], name = "t_natoms") + + def _net (self, + inputs, + name, + reuse = False) : + with tf.variable_scope(name, reuse=reuse): + net_w = tf.get_variable ('net_w', + [self.ndescrpt], + global_tf_float_precision, + tf.constant_initializer (self.net_w_i)) + dot_v = tf.matmul (tf.reshape (inputs, [-1, self.ndescrpt]), + tf.reshape (net_w, [self.ndescrpt, 1])) + return tf.reshape (dot_v, [-1]) + + def comp_ef (self, + dcoord, + dbox, + dtype, + tnatoms, + name, + reuse = None) : + descrpt, descrpt_deriv, rij, nlist \ + = op_module.descrpt_se_a_ef (dcoord, + dtype, + tnatoms, + dbox, + tf.constant(self.default_mesh), + self.efield, + self.t_avg, + self.t_std, + rcut_a = self.rcut_a, + rcut_r = self.rcut_r, + rcut_r_smth = self.rcut_r_smth, + sel_a = self.sel_a, + sel_r = self.sel_r) + inputs_reshape = tf.reshape (descrpt, [-1, self.ndescrpt]) + atom_ener = self._net (inputs_reshape, name, reuse = reuse) + atom_ener_reshape = tf.reshape(atom_ener, [-1, self.natoms[0]]) + energy = tf.reduce_sum (atom_ener_reshape, axis = 1) + net_deriv_ = tf.gradients (atom_ener, inputs_reshape) + net_deriv = net_deriv_[0] + net_deriv_reshape = tf.reshape (net_deriv, [-1, self.natoms[0] * self.ndescrpt]) + + force = op_module.prod_force_se_a (net_deriv_reshape, + descrpt_deriv, + nlist, + tnatoms, + n_a_sel = self.nnei_a, + n_r_sel = self.nnei_r) + virial, atom_vir = op_module.prod_virial_se_a (net_deriv_reshape, + descrpt_deriv, + rij, + nlist, + tnatoms, + n_a_sel = self.nnei_a, + n_r_sel = self.nnei_r) + return energy, force, virial + + + def comp_f_dw (self, + dcoord, + dbox, + dtype, + tnatoms, + name, + reuse = None) : + energy, force, virial = self.comp_ef (dcoord, dbox, dtype, tnatoms, name, reuse) + with tf.variable_scope(name, reuse=True): + net_w = tf.get_variable ('net_w', [self.ndescrpt], global_tf_float_precision, tf.constant_initializer (self.net_w_i)) + f_mag = tf.reduce_sum (tf.nn.tanh(force)) + f_mag_dw = tf.gradients (f_mag, net_w) + assert (len(f_mag_dw) == 1), "length of dw is wrong" + return f_mag, f_mag_dw[0] + + + def comp_v_dw (self, + dcoord, + dbox, + dtype, + tnatoms, + name, + reuse = None) : + energy, force, virial = self.comp_ef (dcoord, dbox, dtype, tnatoms, name, reuse) + with tf.variable_scope(name, reuse=True): + net_w = tf.get_variable ('net_w', [self.ndescrpt], global_tf_float_precision, tf.constant_initializer (self.net_w_i)) + v_mag = tf.reduce_sum (virial) + v_mag_dw = tf.gradients (v_mag, net_w) + assert (len(v_mag_dw) == 1), "length of dw is wrong" + return v_mag, v_mag_dw[0] + + + +class TestSmooth(Inter, unittest.TestCase): + # def __init__ (self, *args, **kwargs): + # data = Data() + # Inter.__init__(self, data) + # unittest.TestCase.__init__(self, *args, **kwargs) + # self.controller = object() + + def setUp(self): + self.places = 5 + data = Data() + Inter.setUp(self, data) + + def test_force (self) : + force_test(self, self, suffix = '_sea_ef') + + def test_virial (self) : + virial_test(self, self, suffix = '_sea_ef') + + def test_force_dw (self) : + force_dw_test(self, self, suffix = '_sea_ef') + + def test_virial_dw (self) : + virial_dw_test(self, self, suffix = '_sea_ef') + + + + +if __name__ == '__main__': + unittest.main() diff --git a/source/tests/test_descrpt_smooth.py b/source/tests/test_descrpt_smooth.py index 7876fbfc3b..4b8183fb68 100644 --- a/source/tests/test_descrpt_smooth.py +++ b/source/tests/test_descrpt_smooth.py @@ -60,6 +60,7 @@ def setUp (self, self.box = tf.placeholder(global_tf_float_precision, [None, 9], name='t_box') self.type = tf.placeholder(tf.int32, [None, self.natoms[0]], name = "t_type") self.tnatoms = tf.placeholder(tf.int32, [None], name = "t_natoms") + self.efield = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_efield') def _net (self, inputs, diff --git a/source/train/DescrptSeA.py b/source/train/DescrptSeA.py index 9a8ee47fb6..831e56c646 100644 --- a/source/train/DescrptSeA.py +++ b/source/train/DescrptSeA.py @@ -134,6 +134,7 @@ def build (self, natoms, box_, mesh, + input_dict, suffix = '', reuse = None): davg = self.davg diff --git a/source/train/DescrptSeAEf.py b/source/train/DescrptSeAEf.py new file mode 100644 index 0000000000..17529bada1 --- /dev/null +++ b/source/train/DescrptSeAEf.py @@ -0,0 +1,248 @@ +import numpy as np +from deepmd.env import tf +from deepmd.common import ClassArg, add_data_requirement +from deepmd.RunOptions import global_tf_float_precision +from deepmd.RunOptions import global_np_float_precision +from deepmd.env import op_module +from deepmd.env import default_tf_session_config +from deepmd.DescrptSeA import DescrptSeA + +class DescrptSeAEf (DescrptSeA): + def __init__ (self, jdata): + args = ClassArg()\ + .add('sel', list, must = True) \ + .add('rcut', float, default = 6.0) \ + .add('rcut_smth',float, default = 5.5) \ + .add('neuron', list, default = [10, 20, 40]) \ + .add('axis_neuron', int, default = 4, alias = 'n_axis_neuron') \ + .add('resnet_dt',bool, default = False) \ + .add('trainable',bool, default = True) \ + .add('seed', int) + class_data = args.parse(jdata) + self.sel_a = class_data['sel'] + self.rcut_r = class_data['rcut'] + self.rcut_r_smth = class_data['rcut_smth'] + self.filter_neuron = class_data['neuron'] + self.n_axis_neuron = class_data['axis_neuron'] + self.filter_resnet_dt = class_data['resnet_dt'] + self.seed = class_data['seed'] + self.trainable = class_data['trainable'] + + # descrpt config + self.sel_r = [ 0 for ii in range(len(self.sel_a)) ] + self.ntypes = len(self.sel_a) + assert(self.ntypes == len(self.sel_r)) + self.rcut_a = -1 + # numb of neighbors and numb of descrptors + self.nnei_a = np.cumsum(self.sel_a)[-1] + self.nnei_r = np.cumsum(self.sel_r)[-1] + self.nnei = self.nnei_a + self.nnei_r + self.ndescrpt_a = self.nnei_a * 4 + self.ndescrpt_r = self.nnei_r * 1 + self.ndescrpt = self.ndescrpt_a + self.ndescrpt_r + self.useBN = False + self.dstd = None + self.davg = None + + add_data_requirement('efield', 3, atomic=True, must=True, high_prec=False) + + self.place_holders = {} + avg_zero = np.zeros([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) + std_ones = np.ones ([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) + sub_graph = tf.Graph() + with sub_graph.as_default(): + name_pfx = 'd_sea_ef_' + for ii in ['coord', 'box']: + self.place_holders[ii] = tf.placeholder(global_np_float_precision, [None, None], name = name_pfx+'t_'+ii) + self.place_holders['type'] = tf.placeholder(tf.int32, [None, None], name=name_pfx+'t_type') + self.place_holders['natoms_vec'] = tf.placeholder(tf.int32, [self.ntypes+2], name=name_pfx+'t_natoms') + self.place_holders['default_mesh'] = tf.placeholder(tf.int32, [None], name=name_pfx+'t_mesh') + self.place_holders['efield'] = tf.placeholder(global_np_float_precision, [None, None], name=name_pfx+'t_efield') + self.stat_descrpt, descrpt_deriv, rij, nlist \ + = op_module.descrpt_se_a_ef(self.place_holders['coord'], + self.place_holders['type'], + self.place_holders['natoms_vec'], + self.place_holders['box'], + self.place_holders['default_mesh'], + self.place_holders['efield'], + tf.constant(avg_zero), + tf.constant(std_ones), + rcut_a = self.rcut_a, + rcut_r = self.rcut_r, + rcut_r_smth = self.rcut_r_smth, + sel_a = self.sel_a, + sel_r = self.sel_r) + self.sub_sess = tf.Session(graph = sub_graph, config=default_tf_session_config) + + + + def compute_input_stats (self, + data_coord, + data_box, + data_atype, + natoms_vec, + mesh, + input_dict) : + data_efield = input_dict['efield'] + all_davg = [] + all_dstd = [] + if True: + sumr = [] + suma = [] + sumn = [] + sumr2 = [] + suma2 = [] + for cc,bb,tt,nn,mm,ee in zip(data_coord,data_box,data_atype,natoms_vec,mesh,data_efield) : + sysr,sysr2,sysa,sysa2,sysn \ + = self._compute_dstats_sys_smth(cc,bb,tt,nn,mm,ee) + sumr.append(sysr) + suma.append(sysa) + sumn.append(sysn) + sumr2.append(sysr2) + suma2.append(sysa2) + sumr = np.sum(sumr, axis = 0) + suma = np.sum(suma, axis = 0) + sumn = np.sum(sumn, axis = 0) + sumr2 = np.sum(sumr2, axis = 0) + suma2 = np.sum(suma2, axis = 0) + for type_i in range(self.ntypes) : + davgunit = [sumr[type_i]/sumn[type_i], 0, 0, 0] + dstdunit = [self._compute_std(sumr2[type_i], sumr[type_i], sumn[type_i]), + self._compute_std(suma2[type_i], suma[type_i], sumn[type_i]), + self._compute_std(suma2[type_i], suma[type_i], sumn[type_i]), + self._compute_std(suma2[type_i], suma[type_i], sumn[type_i]) + ] + davg = np.tile(davgunit, self.ndescrpt // 4) + dstd = np.tile(dstdunit, self.ndescrpt // 4) + all_davg.append(davg) + all_dstd.append(dstd) + + self.davg = np.array(all_davg) + self.dstd = np.array(all_dstd) + + def _normalize_3d(self, a): + na = tf.norm(a, axis = 1) + na = tf.tile(tf.reshape(na, [-1,1]), tf.constant([1, 3])) + return tf.divide(a, na) + + def build (self, + coord_, + atype_, + natoms, + box_, + mesh, + input_dict, + suffix = '', + reuse = None): + efield = input_dict['efield'] + davg = self.davg + dstd = self.dstd + with tf.variable_scope('descrpt_attr' + suffix, reuse = reuse) : + if davg is None: + davg = np.zeros([self.ntypes, self.ndescrpt]) + if dstd is None: + dstd = np.ones ([self.ntypes, self.ndescrpt]) + t_rcut = tf.constant(np.max([self.rcut_r, self.rcut_a]), + name = 'rcut', + dtype = global_tf_float_precision) + t_ntypes = tf.constant(self.ntypes, + name = 'ntypes', + dtype = tf.int32) + t_ndescrpt = tf.constant(self.ndescrpt, + name = 'ndescrpt', + dtype = tf.int32) + t_sel = tf.constant(self.sel_a, + name = 'sel', + dtype = tf.int32) + self.t_avg = tf.get_variable('t_avg', + davg.shape, + dtype = global_tf_float_precision, + trainable = False, + initializer = tf.constant_initializer(davg)) + self.t_std = tf.get_variable('t_std', + dstd.shape, + dtype = global_tf_float_precision, + trainable = False, + initializer = tf.constant_initializer(dstd)) + + coord = tf.reshape (coord_, [-1, natoms[1] * 3]) + box = tf.reshape (box_, [-1, 9]) + atype = tf.reshape (atype_, [-1, natoms[1]]) + efield = tf.reshape(efield, [-1, 3]) + efield = self._normalize_3d(efield) + efield = tf.reshape(efield, [-1, natoms[0] * 3]) + + self.descrpt, self.descrpt_deriv, self.rij, self.nlist \ + = op_module.descrpt_se_a_ef (coord, + atype, + natoms, + box, + mesh, + efield, + self.t_avg, + self.t_std, + rcut_a = self.rcut_a, + rcut_r = self.rcut_r, + rcut_r_smth = self.rcut_r_smth, + sel_a = self.sel_a, + sel_r = self.sel_r) + + self.descrpt_reshape = tf.reshape(self.descrpt, [-1, self.ndescrpt]) + self.descrpt_reshape = tf.identity(self.descrpt_reshape, name = 'o_rmat') + self.descrpt_deriv = tf.identity(self.descrpt_deriv, name = 'o_rmat_deriv') + self.rij = tf.identity(self.rij, name = 'o_rij') + self.nlist = tf.identity(self.nlist, name = 'o_nlist') + + self.dout, self.qmat = self._pass_filter(self.descrpt_reshape, natoms, suffix = suffix, reuse = reuse, trainable = self.trainable) + + return self.dout + + + + def _compute_dstats_sys_smth (self, + data_coord, + data_box, + data_atype, + natoms_vec, + mesh, + data_efield) : + dd_all \ + = self.sub_sess.run(self.stat_descrpt, + feed_dict = { + self.place_holders['coord']: data_coord, + self.place_holders['type']: data_atype, + self.place_holders['natoms_vec']: natoms_vec, + self.place_holders['box']: data_box, + self.place_holders['default_mesh']: mesh, + self.place_holders['efield']: data_efield, + }) + natoms = natoms_vec + dd_all = np.reshape(dd_all, [-1, self.ndescrpt * natoms[0]]) + start_index = 0 + sysr = [] + sysa = [] + sysn = [] + sysr2 = [] + sysa2 = [] + for type_i in range(self.ntypes): + end_index = start_index + self.ndescrpt * natoms[2+type_i] + dd = dd_all[:, start_index:end_index] + dd = np.reshape(dd, [-1, self.ndescrpt]) + start_index = end_index + # compute + dd = np.reshape (dd, [-1, 4]) + ddr = dd[:,:1] + dda = dd[:,1:] + sumr = np.sum(ddr) + suma = np.sum(dda) / 3. + sumn = dd.shape[0] + sumr2 = np.sum(np.multiply(ddr, ddr)) + suma2 = np.sum(np.multiply(dda, dda)) / 3. + sysr.append(sumr) + sysa.append(suma) + sysn.append(sumn) + sysr2.append(sumr2) + sysa2.append(suma2) + return sysr, sysr2, sysa, sysa2, sysn + + diff --git a/source/train/Model.py b/source/train/Model.py index ba48bbc0a0..7d1d3426e4 100644 --- a/source/train/Model.py +++ b/source/train/Model.py @@ -121,7 +121,8 @@ def _compute_input_stat (self, all_stat, protection = 1e-2) : all_stat['box'], all_stat['type'], all_stat['natoms_vec'], - all_stat['default_mesh']) + all_stat['default_mesh'], + all_stat) self.fitting.compute_input_stats(all_stat, protection = protection) def _compute_output_stat (self, all_stat) : @@ -168,6 +169,7 @@ def build (self, natoms, box, mesh, + input_dict, suffix = suffix, reuse = reuse) dout = tf.identity(dout, name='o_descriptor') diff --git a/source/train/Trainer.py b/source/train/Trainer.py index 50db1adfbc..f132ffdad7 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -10,6 +10,7 @@ from deepmd.Fitting import EnerFitting, WFCFitting, PolarFittingLocFrame, PolarFittingSeA, GlobalPolarFittingSeA, DipoleFittingSeA from deepmd.DescrptLocFrame import DescrptLocFrame from deepmd.DescrptSeA import DescrptSeA +from deepmd.DescrptSeAEf import DescrptSeAEf from deepmd.DescrptSeR import DescrptSeR from deepmd.DescrptSeAR import DescrptSeAR from deepmd.Model import Model, WFCModel, DipoleModel, PolarModel, GlobalPolarModel @@ -59,6 +60,8 @@ def _init_param(self, jdata): self.descrpt = DescrptLocFrame(descrpt_param) elif descrpt_type == 'se_a' : self.descrpt = DescrptSeA(descrpt_param) + elif descrpt_type == 'se_a_ef' : + self.descrpt = DescrptSeAEf(descrpt_param) elif descrpt_type == 'se_r' : self.descrpt = DescrptSeR(descrpt_param) elif descrpt_type == 'se_ar' : From 201dc973a8ab8b4b46a9065622678fe2a9c50fbb Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 10 Feb 2020 10:10:13 +0800 Subject: [PATCH 002/562] add missing file --- source/op/descrpt_se_a_ef.cc | 389 +++++++++++++++++++++++++++++++++++ 1 file changed, 389 insertions(+) create mode 100644 source/op/descrpt_se_a_ef.cc diff --git a/source/op/descrpt_se_a_ef.cc b/source/op/descrpt_se_a_ef.cc new file mode 100644 index 0000000000..cc9a89c31b --- /dev/null +++ b/source/op/descrpt_se_a_ef.cc @@ -0,0 +1,389 @@ +#include "tensorflow/core/framework/op.h" +#include "tensorflow/core/framework/op_kernel.h" +#include "tensorflow/core/framework/shape_inference.h" +#include + +#include "ComputeDescriptor.h" +#include "NeighborList.h" + +typedef double boxtensor_t ; +typedef double compute_t; + +using namespace tensorflow; +using namespace std; + +#ifdef HIGH_PREC +typedef double VALUETYPE ; +#else +typedef float VALUETYPE ; +#endif + +#ifdef HIGH_PREC +REGISTER_OP("DescrptSeAEf") +.Input("coord: double") +.Input("type: int32") +.Input("natoms: int32") +.Input("box: double") +.Input("mesh: int32") +.Input("ef: double") +.Input("davg: double") +.Input("dstd: double") +.Attr("rcut_a: float") +.Attr("rcut_r: float") +.Attr("rcut_r_smth: float") +.Attr("sel_a: list(int)") +.Attr("sel_r: list(int)") +.Output("descrpt: double") +.Output("descrpt_deriv: double") +.Output("rij: double") +.Output("nlist: int32"); +#else +REGISTER_OP("DescrptSeAEf") +.Input("coord: float") +.Input("type: int32") +.Input("natoms: int32") +.Input("box: float") +.Input("mesh: int32") +.Input("ef: float") +.Input("davg: float") +.Input("dstd: float") +.Attr("rcut_a: float") +.Attr("rcut_r: float") +.Attr("rcut_r_smth: float") +.Attr("sel_a: list(int)") +.Attr("sel_r: list(int)") +.Output("descrpt: float") +.Output("descrpt_deriv: float") +.Output("rij: float") +.Output("nlist: int32"); +#endif + +class DescrptSeAEfOp : public OpKernel { +public: + explicit DescrptSeAEfOp(OpKernelConstruction* context) : OpKernel(context) { + OP_REQUIRES_OK(context, context->GetAttr("rcut_a", &rcut_a)); + OP_REQUIRES_OK(context, context->GetAttr("rcut_r", &rcut_r)); + OP_REQUIRES_OK(context, context->GetAttr("rcut_r_smth", &rcut_r_smth)); + OP_REQUIRES_OK(context, context->GetAttr("sel_a", &sel_a)); + OP_REQUIRES_OK(context, context->GetAttr("sel_r", &sel_r)); + cum_sum (sec_a, sel_a); + cum_sum (sec_r, sel_r); + ndescrpt_a = sec_a.back() * 4; + ndescrpt_r = sec_r.back() * 1; + ndescrpt = ndescrpt_a + ndescrpt_r; + nnei_a = sec_a.back(); + nnei_r = sec_r.back(); + nnei = nnei_a + nnei_r; + fill_nei_a = (rcut_a < 0); + count_nei_idx_overflow = 0; + } + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& coord_tensor = context->input(context_input_index++); + const Tensor& type_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); + const Tensor& box_tensor = context->input(context_input_index++); + const Tensor& mesh_tensor = context->input(context_input_index++); + const Tensor& ef_tensor = context->input(context_input_index++); + const Tensor& avg_tensor = context->input(context_input_index++); + const Tensor& std_tensor = context->input(context_input_index++); + + // set size of the sample + OP_REQUIRES (context, (coord_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of coord should be 2")); + OP_REQUIRES (context, (type_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of type should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + OP_REQUIRES (context, (box_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of box should be 2")); + OP_REQUIRES (context, (mesh_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of mesh should be 1")); + OP_REQUIRES (context, (ef_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of ef should be 2")); + OP_REQUIRES (context, (avg_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of avg should be 2")); + OP_REQUIRES (context, (std_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of std should be 2")); + OP_REQUIRES (context, (fill_nei_a), errors::InvalidArgument ("Rotational free descriptor only support the case rcut_a < 0")); + OP_REQUIRES (context, (sec_r.back() == 0), errors::InvalidArgument ("Rotational free descriptor only support all-angular information: sel_r should be all zero.")); + + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + auto natoms = natoms_tensor .flat(); + int nloc = natoms(0); + int nall = natoms(1); + int ntypes = natoms_tensor.shape().dim_size(0) - 2; + int nsamples = coord_tensor.shape().dim_size(0); + + // check the sizes + OP_REQUIRES (context, (nsamples == type_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nsamples == box_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nsamples == ef_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (ntypes == avg_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of avg should be ntype")); + OP_REQUIRES (context, (ntypes == std_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of std should be ntype")); + + OP_REQUIRES (context, (nall * 3 == coord_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); + OP_REQUIRES (context, (nall == type_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); + OP_REQUIRES (context, (9 == box_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of box should be 9")); + OP_REQUIRES (context, (nloc * 3 == ef_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of ef should be 3")); + OP_REQUIRES (context, (ndescrpt == avg_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of avg should be ndescrpt")); + OP_REQUIRES (context, (ndescrpt == std_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of std should be ndescrpt")); + + int nei_mode = 0; + if (mesh_tensor.shape().dim_size(0) == 16) { + // lammps neighbor list + nei_mode = 3; + } + else if (mesh_tensor.shape().dim_size(0) == 12) { + // user provided extended mesh + nei_mode = 2; + } + else if (mesh_tensor.shape().dim_size(0) == 6) { + // manual copied pbc + assert (nloc == nall); + nei_mode = 1; + } + else if (mesh_tensor.shape().dim_size(0) == 0) { + // no pbc + nei_mode = -1; + } + else { + throw runtime_error("invalid mesh tensor"); + } + bool b_pbc = true; + // if region is given extended, do not use pbc + if (nei_mode >= 1 || nei_mode == -1) { + b_pbc = false; + } + bool b_norm_atom = false; + if (nei_mode == 1){ + b_norm_atom = true; + } + + // Create an output tensor + TensorShape descrpt_shape ; + descrpt_shape.AddDim (nsamples); + descrpt_shape.AddDim (nloc * ndescrpt); + TensorShape descrpt_deriv_shape ; + descrpt_deriv_shape.AddDim (nsamples); + descrpt_deriv_shape.AddDim (nloc * ndescrpt * 3); + TensorShape rij_shape ; + rij_shape.AddDim (nsamples); + rij_shape.AddDim (nloc * nnei * 3); + TensorShape nlist_shape ; + nlist_shape.AddDim (nsamples); + nlist_shape.AddDim (nloc * nnei); + + int context_output_index = 0; + Tensor* descrpt_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + descrpt_shape, + &descrpt_tensor)); + Tensor* descrpt_deriv_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + descrpt_deriv_shape, + &descrpt_deriv_tensor)); + Tensor* rij_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + rij_shape, + &rij_tensor)); + Tensor* nlist_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + nlist_shape, + &nlist_tensor)); + + auto coord = coord_tensor .matrix(); + auto type = type_tensor .matrix(); + auto box = box_tensor .matrix(); + auto mesh = mesh_tensor .flat(); + auto ef = ef_tensor .matrix(); + auto avg = avg_tensor .matrix(); + auto std = std_tensor .matrix(); + auto descrpt = descrpt_tensor ->matrix(); + auto descrpt_deriv = descrpt_deriv_tensor ->matrix(); + auto rij = rij_tensor ->matrix(); + auto nlist = nlist_tensor ->matrix(); + + // // check the types + // int max_type_v = 0; + // for (int ii = 0; ii < natoms; ++ii){ + // if (type(0, ii) > max_type_v) max_type_v = type(0, ii); + // } + // int ntypes = max_type_v + 1; + OP_REQUIRES (context, (ntypes == int(sel_a.size())), errors::InvalidArgument ("number of types should match the length of sel array")); + OP_REQUIRES (context, (ntypes == int(sel_r.size())), errors::InvalidArgument ("number of types should match the length of sel array")); + + for (int kk = 0; kk < nsamples; ++kk){ + // set region + boxtensor_t boxt [9] = {0}; + for (int dd = 0; dd < 9; ++dd) { + boxt[dd] = box(kk, dd); + } + SimulationRegion region; + region.reinitBox (boxt); + + // set & normalize coord + vector d_coord3 (nall*3); + for (int ii = 0; ii < nall; ++ii){ + for (int dd = 0; dd < 3; ++dd){ + d_coord3[ii*3+dd] = coord(kk, ii*3+dd); + } + if (b_norm_atom){ + compute_t inter[3]; + region.phys2Inter (inter, &d_coord3[3*ii]); + for (int dd = 0; dd < 3; ++dd){ + if (inter[dd] < 0 ) inter[dd] += 1.; + else if (inter[dd] >= 1) inter[dd] -= 1.; + } + region.inter2Phys (&d_coord3[3*ii], inter); + } + } + + // set efield + vector d_ef(nloc * 3); + for (int ii = 0; ii < nloc; ++ii){ + for (int dd = 0; dd < 3; ++dd){ + d_ef[ii*3+dd] = ef(kk, ii*3+dd); + } + } + + // set type + vector d_type (nall); + for (int ii = 0; ii < nall; ++ii) d_type[ii] = type(kk, ii); + + // build nlist + vector > d_nlist_a; + vector > d_nlist_r; + vector nlist_map; + bool b_nlist_map = false; + if (nei_mode == 3) { + int * pilist, *pjrange, *pjlist; + memcpy (&pilist, &mesh(4), sizeof(int *)); + memcpy (&pjrange, &mesh(8), sizeof(int *)); + memcpy (&pjlist, &mesh(12), sizeof(int *)); + int inum = mesh(1); + assert (inum == nloc); + d_nlist_a.resize (inum); + d_nlist_r.resize (inum); + for (unsigned ii = 0; ii < inum; ++ii){ + d_nlist_r.reserve (pjrange[inum] / inum + 10); + } + for (unsigned ii = 0; ii < inum; ++ii){ + int i_idx = pilist[ii]; + for (unsigned jj = pjrange[ii]; jj < pjrange[ii+1]; ++jj){ + int j_idx = pjlist[jj]; + d_nlist_r[i_idx].push_back (j_idx); + } + } + } + else if (nei_mode == 2) { + vector nat_stt = {mesh(1-1), mesh(2-1), mesh(3-1)}; + vector nat_end = {mesh(4-1), mesh(5-1), mesh(6-1)}; + vector ext_stt = {mesh(7-1), mesh(8-1), mesh(9-1)}; + vector ext_end = {mesh(10-1), mesh(11-1), mesh(12-1)}; + vector global_grid (3); + for (int dd = 0; dd < 3; ++dd) global_grid[dd] = nat_end[dd] - nat_stt[dd]; + ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, rcut_a, rcut_r, nat_stt, nat_end, ext_stt, ext_end, region, global_grid); + } + else if (nei_mode == 1) { + vector bk_d_coord3 = d_coord3; + vector bk_d_type = d_type; + vector ncell, ngcell; + copy_coord(d_coord3, d_type, nlist_map, ncell, ngcell, bk_d_coord3, bk_d_type, rcut_r, region); + b_nlist_map = true; + vector nat_stt(3, 0); + vector ext_stt(3), ext_end(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, rcut_a, rcut_r, nat_stt, ncell, ext_stt, ext_end, region, ncell); + } + else if (nei_mode == -1){ + ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, rcut_a, rcut_r, NULL); + } + else { + throw runtime_error("unknow neighbor mode"); + } + + // loop over atoms, compute descriptors for each atom +#pragma omp parallel for + for (int ii = 0; ii < nloc; ++ii){ + vector fmt_nlist_a; + vector fmt_nlist_r; + int ret = -1; + if (fill_nei_a){ + if ((ret = format_nlist_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ + if (count_nei_idx_overflow == 0) { + cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << endl; + flush(cout); + count_nei_idx_overflow ++; + } + } + } + + vector d_descrpt_a; + vector d_descrpt_a_deriv; + vector d_descrpt_r; + vector d_descrpt_r_deriv; + vector d_rij_a; + vector d_rij_r; + compute_descriptor_se_a_extf (d_descrpt_a, + d_descrpt_a_deriv, + d_rij_a, + d_coord3, + ntypes, + d_type, + region, + b_pbc, + d_ef, + ii, + fmt_nlist_a, + sec_a, + rcut_r_smth, + rcut_r); + + // check sizes + assert (d_descrpt_a.size() == ndescrpt_a); + assert (d_descrpt_a_deriv.size() == ndescrpt_a * 3); + assert (d_rij_a.size() == nnei_a * 3); + assert (int(fmt_nlist_a.size()) == nnei_a); + // record outputs + for (int jj = 0; jj < ndescrpt_a; ++jj) { + descrpt(kk, ii * ndescrpt + jj) = (d_descrpt_a[jj] - avg(d_type[ii], jj)) / std(d_type[ii], jj); + } + for (int jj = 0; jj < ndescrpt_a * 3; ++jj) { + descrpt_deriv(kk, ii * ndescrpt * 3 + jj) = d_descrpt_a_deriv[jj] / std(d_type[ii], jj/3); + } + for (int jj = 0; jj < nnei_a * 3; ++jj){ + rij (kk, ii * nnei * 3 + jj) = d_rij_a[jj]; + } + for (int jj = 0; jj < nnei_a; ++jj){ + int record = fmt_nlist_a[jj]; + if (b_nlist_map && record >= 0) { + record = nlist_map[record]; + } + nlist (kk, ii * nnei + jj) = record; + } + } + } + } +private: + float rcut_a; + float rcut_r; + float rcut_r_smth; + vector sel_r; + vector sel_a; + vector sec_a; + vector sec_r; + int ndescrpt, ndescrpt_a, ndescrpt_r; + int nnei, nnei_a, nnei_r; + bool fill_nei_a; + int count_nei_idx_overflow; + void + cum_sum (vector & sec, + const vector & n_sel) const { + sec.resize (n_sel.size() + 1); + sec[0] = 0; + for (int ii = 1; ii < sec.size(); ++ii){ + sec[ii] = sec[ii-1] + n_sel[ii-1]; + } + } +}; + +REGISTER_KERNEL_BUILDER(Name("DescrptSeAEf").Device(DEVICE_CPU), DescrptSeAEfOp); + From d5b1a66e8e25e2d91beb6e2a28e7c9a14abdb2f5 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 10 Feb 2020 10:11:24 +0800 Subject: [PATCH 003/562] backup, seperate para and vert descriptors --- source/lib/include/ComputeDescriptor.h | 247 ++++++++++++++ source/op/CMakeLists.txt | 2 +- source/op/descrpt_se_a_ef_para.cc | 389 +++++++++++++++++++++++ source/op/descrpt_se_a_ef_vert.cc | 389 +++++++++++++++++++++++ source/tests/test_descrpt_se_ar.py | 2 +- source/tests/test_descrpt_sea_ef_para.py | 184 +++++++++++ source/tests/test_descrpt_sea_ef_vert.py | 184 +++++++++++ source/train/DescrptLocFrame.py | 12 +- source/train/DescrptSeA.py | 13 +- source/train/DescrptSeAEf.py | 126 ++++++-- source/train/DescrptSeAR.py | 5 +- source/train/DescrptSeR.py | 12 +- source/train/Model.py | 4 +- 13 files changed, 1520 insertions(+), 49 deletions(-) create mode 100644 source/op/descrpt_se_a_ef_para.cc create mode 100644 source/op/descrpt_se_a_ef_vert.cc create mode 100644 source/tests/test_descrpt_sea_ef_para.py create mode 100644 source/tests/test_descrpt_sea_ef_vert.py diff --git a/source/lib/include/ComputeDescriptor.h b/source/lib/include/ComputeDescriptor.h index 7b579cd3d2..0f7b2b43f7 100644 --- a/source/lib/include/ComputeDescriptor.h +++ b/source/lib/include/ComputeDescriptor.h @@ -97,6 +97,36 @@ void compute_descriptor_se_a_extf (vector & descrpt_a, const vector & sec_a, const double & rmin, const double & rmax); +inline +void compute_descriptor_se_a_ef_para (vector & descrpt_a, + vector & descrpt_a_deriv, + vector & rij_a, + const vector & posi, + const int & ntypes, + const vector & type, + const SimulationRegion & region, + const bool & b_pbc, + const vector & efield, + const int & i_idx, + const vector & fmt_nlist_a, + const vector & sec_a, + const double & rmin, + const double & rmax); +inline +void compute_descriptor_se_a_ef_vert (vector & descrpt_a, + vector & descrpt_a_deriv, + vector & rij_a, + const vector & posi, + const int & ntypes, + const vector & type, + const SimulationRegion & region, + const bool & b_pbc, + const vector & efield, + const int & i_idx, + const vector & fmt_nlist_a, + const vector & sec_a, + const double & rmin, + const double & rmax); inline void compute_descriptor_se_r (vector & descrpt_r, @@ -1212,5 +1242,222 @@ void compute_descriptor_se_a_extf (vector & descrpt_a, } } +// output deriv size: n_sel_a_nei x 4 x 12 +// (1./rr, cos_theta, cos_phi, sin_phi) x 4 x (x, y, z) +void compute_descriptor_se_a_ef_para (vector & descrpt_a, + vector & descrpt_a_deriv, + vector & rij_a, + const vector & posi, + const int & ntypes, + const vector & type, + const SimulationRegion & region, + const bool & b_pbc, + const vector & efield, + const int & i_idx, + const vector & fmt_nlist_a, + const vector & sec_a, + const double & rmin, + const double & rmax) +{ + const double * ef_ = &efield[i_idx*3+0]; + double ef[3] = {0.}; + if (isnan(ef_[0]) || isnan(ef_[1]) || isnan(ef_[2])){ + ef[0] = 1.; + ef[1] = ef[2] = 0.; + } + else { + for (int ii = 0; ii < 3; ++ii){ + ef[ii] = ef_[ii]; + } + } + assert( fabs(MathUtilities::dot(ef, ef) - 1.0) < 1e-12 ), "ef should be a normalized vector"; + + // compute the diff of the neighbors + vector > sel_a_diff (sec_a.back()); + rij_a.resize (sec_a.back() * 3); + fill (rij_a.begin(), rij_a.end(), 0.0); + for (int ii = 0; ii < int(sec_a.size()) - 1; ++ii){ + for (int jj = sec_a[ii]; jj < sec_a[ii+1]; ++jj){ + if (fmt_nlist_a[jj] < 0) break; + sel_a_diff[jj].resize(3); + const int & j_idx = fmt_nlist_a[jj]; + if (b_pbc){ + region.diffNearestNeighbor (posi[j_idx*3+0], posi[j_idx*3+1], posi[j_idx*3+2], + posi[i_idx*3+0], posi[i_idx*3+1], posi[i_idx*3+2], + sel_a_diff[jj][0], sel_a_diff[jj][1], sel_a_diff[jj][2]); + } + else { + for (int dd = 0; dd < 3; ++dd) sel_a_diff[jj][dd] = posi[j_idx*3+dd] - posi[i_idx*3+dd]; + } + for (int dd = 0; dd < 3; ++dd) rij_a[jj*3+dd] = sel_a_diff[jj][dd]; + } + } + + // 1./rr, cos(theta), cos(phi), sin(phi) + descrpt_a.resize (sec_a.back() * 4); + fill (descrpt_a.begin(), descrpt_a.end(), 0.0); + // deriv wrt center: 3 + descrpt_a_deriv.resize (sec_a.back() * 4 * 3); + fill (descrpt_a_deriv.begin(), descrpt_a_deriv.end(), 0.0); + + for (int sec_iter = 0; sec_iter < int(sec_a.size()) - 1; ++sec_iter){ + for (int nei_iter = sec_a[sec_iter]; nei_iter < sec_a[sec_iter+1]; ++nei_iter) { + if (fmt_nlist_a[nei_iter] < 0) break; + const double * rr = &sel_a_diff[nei_iter][0]; + // check validity of ef + double nr2 = MathUtilities::dot(rr, rr); + double inr = 1./sqrt(nr2); + double nr = nr2 * inr; + double inr2 = inr * inr; + double inr4 = inr2 * inr2; + double inr3 = inr4 * nr; + double sw, dsw; + spline5_switch(sw, dsw, nr, rmin, rmax); + int idx_deriv = nei_iter * 4 * 3; // 4 components time 3 directions + int idx_value = nei_iter * 4; // 4 components + // projections + double rp[3]; + rp[0] = MathUtilities::dot(rr, ef) * ef[0]; + rp[1] = MathUtilities::dot(rr, ef) * ef[1]; + rp[2] = MathUtilities::dot(rr, ef) * ef[2]; + // 4 value components + descrpt_a[idx_value + 0] = 1 / nr; + descrpt_a[idx_value + 1] = rp[0] / nr2; + descrpt_a[idx_value + 2] = rp[1] / nr2; + descrpt_a[idx_value + 3] = rp[2] / nr2; + // deriv of component 1/r + descrpt_a_deriv[idx_deriv + 0] = rr[0] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv + 1] = rr[1] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv + 2] = rr[2] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[2] * inr; + // deriv of component rpx/r2 + descrpt_a_deriv[idx_deriv + 3] = (2. * inr4 * rp[0] * rr[0] - inr2 * (ef[0] * ef[0])) * sw - descrpt_a[idx_value + 1] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv + 4] = (2. * inr4 * rp[0] * rr[1] - inr2 * (ef[0] * ef[1])) * sw - descrpt_a[idx_value + 1] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv + 5] = (2. * inr4 * rp[0] * rr[2] - inr2 * (ef[0] * ef[2])) * sw - descrpt_a[idx_value + 1] * dsw * rr[2] * inr; + // deriv of component rpy/r2 + descrpt_a_deriv[idx_deriv + 6] = (2. * inr4 * rp[1] * rr[0] - inr2 * (ef[1] * ef[0])) * sw - descrpt_a[idx_value + 2] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv + 7] = (2. * inr4 * rp[1] * rr[1] - inr2 * (ef[1] * ef[1])) * sw - descrpt_a[idx_value + 2] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv + 8] = (2. * inr4 * rp[1] * rr[2] - inr2 * (ef[1] * ef[2])) * sw - descrpt_a[idx_value + 2] * dsw * rr[2] * inr; + // deriv of component rpz/r2 + descrpt_a_deriv[idx_deriv + 9] = (2. * inr4 * rp[2] * rr[0] - inr2 * (ef[2] * ef[0])) * sw - descrpt_a[idx_value + 3] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv +10] = (2. * inr4 * rp[2] * rr[1] - inr2 * (ef[2] * ef[1])) * sw - descrpt_a[idx_value + 3] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv +11] = (2. * inr4 * rp[2] * rr[2] - inr2 * (ef[2] * ef[2])) * sw - descrpt_a[idx_value + 3] * dsw * rr[2] * inr; + // 4 value components + descrpt_a[idx_value + 0] *= sw; + descrpt_a[idx_value + 1] *= sw; + descrpt_a[idx_value + 2] *= sw; + descrpt_a[idx_value + 3] *= sw; + } + } +} + +// output deriv size: n_sel_a_nei x 4 x 12 +// (1./rr, cos_theta, cos_phi, sin_phi) x 4 x (x, y, z) +void compute_descriptor_se_a_ef_vert (vector & descrpt_a, + vector & descrpt_a_deriv, + vector & rij_a, + const vector & posi, + const int & ntypes, + const vector & type, + const SimulationRegion & region, + const bool & b_pbc, + const vector & efield, + const int & i_idx, + const vector & fmt_nlist_a, + const vector & sec_a, + const double & rmin, + const double & rmax) +{ + const double * ef_ = &efield[i_idx*3+0]; + double ef[3] = {0.}; + if (isnan(ef_[0]) || isnan(ef_[1]) || isnan(ef_[2])){ + ef[0] = 1.; + ef[1] = ef[2] = 0.; + } + else { + for (int ii = 0; ii < 3; ++ii){ + ef[ii] = ef_[ii]; + } + } + assert( fabs(MathUtilities::dot(ef, ef) - 1.0) < 1e-12 ), "ef should be a normalized vector"; + + // compute the diff of the neighbors + vector > sel_a_diff (sec_a.back()); + rij_a.resize (sec_a.back() * 3); + fill (rij_a.begin(), rij_a.end(), 0.0); + for (int ii = 0; ii < int(sec_a.size()) - 1; ++ii){ + for (int jj = sec_a[ii]; jj < sec_a[ii+1]; ++jj){ + if (fmt_nlist_a[jj] < 0) break; + sel_a_diff[jj].resize(3); + const int & j_idx = fmt_nlist_a[jj]; + if (b_pbc){ + region.diffNearestNeighbor (posi[j_idx*3+0], posi[j_idx*3+1], posi[j_idx*3+2], + posi[i_idx*3+0], posi[i_idx*3+1], posi[i_idx*3+2], + sel_a_diff[jj][0], sel_a_diff[jj][1], sel_a_diff[jj][2]); + } + else { + for (int dd = 0; dd < 3; ++dd) sel_a_diff[jj][dd] = posi[j_idx*3+dd] - posi[i_idx*3+dd]; + } + for (int dd = 0; dd < 3; ++dd) rij_a[jj*3+dd] = sel_a_diff[jj][dd]; + } + } + + // 1./rr, cos(theta), cos(phi), sin(phi) + descrpt_a.resize (sec_a.back() * 4); + fill (descrpt_a.begin(), descrpt_a.end(), 0.0); + // deriv wrt center: 3 + descrpt_a_deriv.resize (sec_a.back() * 4 * 3); + fill (descrpt_a_deriv.begin(), descrpt_a_deriv.end(), 0.0); + + for (int sec_iter = 0; sec_iter < int(sec_a.size()) - 1; ++sec_iter){ + for (int nei_iter = sec_a[sec_iter]; nei_iter < sec_a[sec_iter+1]; ++nei_iter) { + if (fmt_nlist_a[nei_iter] < 0) break; + const double * rr = &sel_a_diff[nei_iter][0]; + // check validity of ef + double nr2 = MathUtilities::dot(rr, rr); + double inr = 1./sqrt(nr2); + double nr = nr2 * inr; + double inr2 = inr * inr; + double inr4 = inr2 * inr2; + double inr3 = inr4 * nr; + double sw, dsw; + spline5_switch(sw, dsw, nr, rmin, rmax); + int idx_deriv = nei_iter * 4 * 3; // 4 components time 3 directions + int idx_value = nei_iter * 4; // 4 components + // projections + double rp = MathUtilities::dot(rr, ef); + double rv[3]; + rv[0] = rr[0] - rp * ef[0]; + rv[1] = rr[1] - rp * ef[1]; + rv[2] = rr[2] - rp * ef[2]; + // 4 value components + descrpt_a[idx_value + 0] = 1 / nr; + descrpt_a[idx_value + 1] = rv[0] / nr2; + descrpt_a[idx_value + 2] = rv[1] / nr2; + descrpt_a[idx_value + 3] = rv[2] / nr2; + // deriv of component 1/r + descrpt_a_deriv[idx_deriv + 0] = rr[0] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv + 1] = rr[1] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv + 2] = rr[2] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[2] * inr; + // deriv of component rvx/r2 + descrpt_a_deriv[idx_deriv + 3] = (2. * inr4 * rv[0] * rr[0] - inr2 * (1. - ef[0] * ef[0])) * sw - descrpt_a[idx_value + 1] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv + 4] = (2. * inr4 * rv[0] * rr[1] - inr2 * ( - ef[0] * ef[1])) * sw - descrpt_a[idx_value + 1] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv + 5] = (2. * inr4 * rv[0] * rr[2] - inr2 * ( - ef[0] * ef[2])) * sw - descrpt_a[idx_value + 1] * dsw * rr[2] * inr; + // deriv of component rvy/r2 + descrpt_a_deriv[idx_deriv + 6] = (2. * inr4 * rv[1] * rr[0] - inr2 * ( - ef[1] * ef[0])) * sw - descrpt_a[idx_value + 2] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv + 7] = (2. * inr4 * rv[1] * rr[1] - inr2 * (1. - ef[1] * ef[1])) * sw - descrpt_a[idx_value + 2] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv + 8] = (2. * inr4 * rv[1] * rr[2] - inr2 * ( - ef[1] * ef[2])) * sw - descrpt_a[idx_value + 2] * dsw * rr[2] * inr; + // deriv of component rvz/r2 + descrpt_a_deriv[idx_deriv + 9] = (2. * inr4 * rv[2] * rr[0] - inr2 * ( - ef[2] * ef[0])) * sw - descrpt_a[idx_value + 3] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv +10] = (2. * inr4 * rv[2] * rr[1] - inr2 * ( - ef[2] * ef[1])) * sw - descrpt_a[idx_value + 3] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv +11] = (2. * inr4 * rv[2] * rr[2] - inr2 * (1. - ef[2] * ef[2])) * sw - descrpt_a[idx_value + 3] * dsw * rr[2] * inr; + // 4 value components + descrpt_a[idx_value + 0] *= sw; + descrpt_a[idx_value + 1] *= sw; + descrpt_a[idx_value + 2] *= sw; + descrpt_a[idx_value + 3] *= sw; + } + } +} + diff --git a/source/op/CMakeLists.txt b/source/op/CMakeLists.txt index fac2bfb7a2..c0de3acea6 100644 --- a/source/op/CMakeLists.txt +++ b/source/op/CMakeLists.txt @@ -3,7 +3,7 @@ set(OP_LIB ${PROJECT_SOURCE_DIR}/lib/src/SimulationRegion.cpp ${PROJECT_SOURCE_DIR}/lib/src/NeighborList.cpp) set (OP_CXX_FLAG -D_GLIBCXX_USE_CXX11_ABI=${OP_CXX_ABI} ) -file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_r.cc tab_inter.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc) +file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc descrpt_se_r.cc tab_inter.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc) file(GLOB OP_CUDA_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a_gpu.cc descrpt_se_r_gpu.cc tab_inter.cc prod_force_se_a_gpu.cc prod_virial_se_a_gpu.cc prod_force_se_r_gpu.cc prod_virial_se_r_gpu.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ) file(GLOB OP_GRADS_SRC prod_force_grad.cc prod_force_se_a_grad.cc prod_force_se_r_grad.cc prod_virial_grad.cc prod_virial_se_a_grad.cc prod_virial_se_r_grad.cc soft_min_force_grad.cc soft_min_virial_grad.cc ) file(GLOB OP_PY *.py) diff --git a/source/op/descrpt_se_a_ef_para.cc b/source/op/descrpt_se_a_ef_para.cc new file mode 100644 index 0000000000..fed1ef670d --- /dev/null +++ b/source/op/descrpt_se_a_ef_para.cc @@ -0,0 +1,389 @@ +#include "tensorflow/core/framework/op.h" +#include "tensorflow/core/framework/op_kernel.h" +#include "tensorflow/core/framework/shape_inference.h" +#include + +#include "ComputeDescriptor.h" +#include "NeighborList.h" + +typedef double boxtensor_t ; +typedef double compute_t; + +using namespace tensorflow; +using namespace std; + +#ifdef HIGH_PREC +typedef double VALUETYPE ; +#else +typedef float VALUETYPE ; +#endif + +#ifdef HIGH_PREC +REGISTER_OP("DescrptSeAEfPara") +.Input("coord: double") +.Input("type: int32") +.Input("natoms: int32") +.Input("box: double") +.Input("mesh: int32") +.Input("ef: double") +.Input("davg: double") +.Input("dstd: double") +.Attr("rcut_a: float") +.Attr("rcut_r: float") +.Attr("rcut_r_smth: float") +.Attr("sel_a: list(int)") +.Attr("sel_r: list(int)") +.Output("descrpt: double") +.Output("descrpt_deriv: double") +.Output("rij: double") +.Output("nlist: int32"); +#else +REGISTER_OP("DescrptSeAEfPara") +.Input("coord: float") +.Input("type: int32") +.Input("natoms: int32") +.Input("box: float") +.Input("mesh: int32") +.Input("ef: float") +.Input("davg: float") +.Input("dstd: float") +.Attr("rcut_a: float") +.Attr("rcut_r: float") +.Attr("rcut_r_smth: float") +.Attr("sel_a: list(int)") +.Attr("sel_r: list(int)") +.Output("descrpt: float") +.Output("descrpt_deriv: float") +.Output("rij: float") +.Output("nlist: int32"); +#endif + +class DescrptSeAEfParaOp : public OpKernel { +public: + explicit DescrptSeAEfParaOp(OpKernelConstruction* context) : OpKernel(context) { + OP_REQUIRES_OK(context, context->GetAttr("rcut_a", &rcut_a)); + OP_REQUIRES_OK(context, context->GetAttr("rcut_r", &rcut_r)); + OP_REQUIRES_OK(context, context->GetAttr("rcut_r_smth", &rcut_r_smth)); + OP_REQUIRES_OK(context, context->GetAttr("sel_a", &sel_a)); + OP_REQUIRES_OK(context, context->GetAttr("sel_r", &sel_r)); + cum_sum (sec_a, sel_a); + cum_sum (sec_r, sel_r); + ndescrpt_a = sec_a.back() * 4; + ndescrpt_r = sec_r.back() * 1; + ndescrpt = ndescrpt_a + ndescrpt_r; + nnei_a = sec_a.back(); + nnei_r = sec_r.back(); + nnei = nnei_a + nnei_r; + fill_nei_a = (rcut_a < 0); + count_nei_idx_overflow = 0; + } + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& coord_tensor = context->input(context_input_index++); + const Tensor& type_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); + const Tensor& box_tensor = context->input(context_input_index++); + const Tensor& mesh_tensor = context->input(context_input_index++); + const Tensor& ef_tensor = context->input(context_input_index++); + const Tensor& avg_tensor = context->input(context_input_index++); + const Tensor& std_tensor = context->input(context_input_index++); + + // set size of the sample + OP_REQUIRES (context, (coord_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of coord should be 2")); + OP_REQUIRES (context, (type_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of type should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + OP_REQUIRES (context, (box_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of box should be 2")); + OP_REQUIRES (context, (mesh_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of mesh should be 1")); + OP_REQUIRES (context, (ef_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of ef should be 2")); + OP_REQUIRES (context, (avg_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of avg should be 2")); + OP_REQUIRES (context, (std_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of std should be 2")); + OP_REQUIRES (context, (fill_nei_a), errors::InvalidArgument ("Rotational free descriptor only support the case rcut_a < 0")); + OP_REQUIRES (context, (sec_r.back() == 0), errors::InvalidArgument ("Rotational free descriptor only support all-angular information: sel_r should be all zero.")); + + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + auto natoms = natoms_tensor .flat(); + int nloc = natoms(0); + int nall = natoms(1); + int ntypes = natoms_tensor.shape().dim_size(0) - 2; + int nsamples = coord_tensor.shape().dim_size(0); + + // check the sizes + OP_REQUIRES (context, (nsamples == type_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nsamples == box_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nsamples == ef_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (ntypes == avg_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of avg should be ntype")); + OP_REQUIRES (context, (ntypes == std_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of std should be ntype")); + + OP_REQUIRES (context, (nall * 3 == coord_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); + OP_REQUIRES (context, (nall == type_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); + OP_REQUIRES (context, (9 == box_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of box should be 9")); + OP_REQUIRES (context, (nloc * 3 == ef_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of ef should be 3")); + OP_REQUIRES (context, (ndescrpt == avg_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of avg should be ndescrpt")); + OP_REQUIRES (context, (ndescrpt == std_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of std should be ndescrpt")); + + int nei_mode = 0; + if (mesh_tensor.shape().dim_size(0) == 16) { + // lammps neighbor list + nei_mode = 3; + } + else if (mesh_tensor.shape().dim_size(0) == 12) { + // user provided extended mesh + nei_mode = 2; + } + else if (mesh_tensor.shape().dim_size(0) == 6) { + // manual copied pbc + assert (nloc == nall); + nei_mode = 1; + } + else if (mesh_tensor.shape().dim_size(0) == 0) { + // no pbc + nei_mode = -1; + } + else { + throw runtime_error("invalid mesh tensor"); + } + bool b_pbc = true; + // if region is given extended, do not use pbc + if (nei_mode >= 1 || nei_mode == -1) { + b_pbc = false; + } + bool b_norm_atom = false; + if (nei_mode == 1){ + b_norm_atom = true; + } + + // Create an output tensor + TensorShape descrpt_shape ; + descrpt_shape.AddDim (nsamples); + descrpt_shape.AddDim (nloc * ndescrpt); + TensorShape descrpt_deriv_shape ; + descrpt_deriv_shape.AddDim (nsamples); + descrpt_deriv_shape.AddDim (nloc * ndescrpt * 3); + TensorShape rij_shape ; + rij_shape.AddDim (nsamples); + rij_shape.AddDim (nloc * nnei * 3); + TensorShape nlist_shape ; + nlist_shape.AddDim (nsamples); + nlist_shape.AddDim (nloc * nnei); + + int context_output_index = 0; + Tensor* descrpt_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + descrpt_shape, + &descrpt_tensor)); + Tensor* descrpt_deriv_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + descrpt_deriv_shape, + &descrpt_deriv_tensor)); + Tensor* rij_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + rij_shape, + &rij_tensor)); + Tensor* nlist_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + nlist_shape, + &nlist_tensor)); + + auto coord = coord_tensor .matrix(); + auto type = type_tensor .matrix(); + auto box = box_tensor .matrix(); + auto mesh = mesh_tensor .flat(); + auto ef = ef_tensor .matrix(); + auto avg = avg_tensor .matrix(); + auto std = std_tensor .matrix(); + auto descrpt = descrpt_tensor ->matrix(); + auto descrpt_deriv = descrpt_deriv_tensor ->matrix(); + auto rij = rij_tensor ->matrix(); + auto nlist = nlist_tensor ->matrix(); + + // // check the types + // int max_type_v = 0; + // for (int ii = 0; ii < natoms; ++ii){ + // if (type(0, ii) > max_type_v) max_type_v = type(0, ii); + // } + // int ntypes = max_type_v + 1; + OP_REQUIRES (context, (ntypes == int(sel_a.size())), errors::InvalidArgument ("number of types should match the length of sel array")); + OP_REQUIRES (context, (ntypes == int(sel_r.size())), errors::InvalidArgument ("number of types should match the length of sel array")); + + for (int kk = 0; kk < nsamples; ++kk){ + // set region + boxtensor_t boxt [9] = {0}; + for (int dd = 0; dd < 9; ++dd) { + boxt[dd] = box(kk, dd); + } + SimulationRegion region; + region.reinitBox (boxt); + + // set & normalize coord + vector d_coord3 (nall*3); + for (int ii = 0; ii < nall; ++ii){ + for (int dd = 0; dd < 3; ++dd){ + d_coord3[ii*3+dd] = coord(kk, ii*3+dd); + } + if (b_norm_atom){ + compute_t inter[3]; + region.phys2Inter (inter, &d_coord3[3*ii]); + for (int dd = 0; dd < 3; ++dd){ + if (inter[dd] < 0 ) inter[dd] += 1.; + else if (inter[dd] >= 1) inter[dd] -= 1.; + } + region.inter2Phys (&d_coord3[3*ii], inter); + } + } + + // set efield + vector d_ef(nloc * 3); + for (int ii = 0; ii < nloc; ++ii){ + for (int dd = 0; dd < 3; ++dd){ + d_ef[ii*3+dd] = ef(kk, ii*3+dd); + } + } + + // set type + vector d_type (nall); + for (int ii = 0; ii < nall; ++ii) d_type[ii] = type(kk, ii); + + // build nlist + vector > d_nlist_a; + vector > d_nlist_r; + vector nlist_map; + bool b_nlist_map = false; + if (nei_mode == 3) { + int * pilist, *pjrange, *pjlist; + memcpy (&pilist, &mesh(4), sizeof(int *)); + memcpy (&pjrange, &mesh(8), sizeof(int *)); + memcpy (&pjlist, &mesh(12), sizeof(int *)); + int inum = mesh(1); + assert (inum == nloc); + d_nlist_a.resize (inum); + d_nlist_r.resize (inum); + for (unsigned ii = 0; ii < inum; ++ii){ + d_nlist_r.reserve (pjrange[inum] / inum + 10); + } + for (unsigned ii = 0; ii < inum; ++ii){ + int i_idx = pilist[ii]; + for (unsigned jj = pjrange[ii]; jj < pjrange[ii+1]; ++jj){ + int j_idx = pjlist[jj]; + d_nlist_r[i_idx].push_back (j_idx); + } + } + } + else if (nei_mode == 2) { + vector nat_stt = {mesh(1-1), mesh(2-1), mesh(3-1)}; + vector nat_end = {mesh(4-1), mesh(5-1), mesh(6-1)}; + vector ext_stt = {mesh(7-1), mesh(8-1), mesh(9-1)}; + vector ext_end = {mesh(10-1), mesh(11-1), mesh(12-1)}; + vector global_grid (3); + for (int dd = 0; dd < 3; ++dd) global_grid[dd] = nat_end[dd] - nat_stt[dd]; + ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, rcut_a, rcut_r, nat_stt, nat_end, ext_stt, ext_end, region, global_grid); + } + else if (nei_mode == 1) { + vector bk_d_coord3 = d_coord3; + vector bk_d_type = d_type; + vector ncell, ngcell; + copy_coord(d_coord3, d_type, nlist_map, ncell, ngcell, bk_d_coord3, bk_d_type, rcut_r, region); + b_nlist_map = true; + vector nat_stt(3, 0); + vector ext_stt(3), ext_end(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, rcut_a, rcut_r, nat_stt, ncell, ext_stt, ext_end, region, ncell); + } + else if (nei_mode == -1){ + ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, rcut_a, rcut_r, NULL); + } + else { + throw runtime_error("unknow neighbor mode"); + } + + // loop over atoms, compute descriptors for each atom +#pragma omp parallel for + for (int ii = 0; ii < nloc; ++ii){ + vector fmt_nlist_a; + vector fmt_nlist_r; + int ret = -1; + if (fill_nei_a){ + if ((ret = format_nlist_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ + if (count_nei_idx_overflow == 0) { + cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << endl; + flush(cout); + count_nei_idx_overflow ++; + } + } + } + + vector d_descrpt_a; + vector d_descrpt_a_deriv; + vector d_descrpt_r; + vector d_descrpt_r_deriv; + vector d_rij_a; + vector d_rij_r; + compute_descriptor_se_a_ef_para (d_descrpt_a, + d_descrpt_a_deriv, + d_rij_a, + d_coord3, + ntypes, + d_type, + region, + b_pbc, + d_ef, + ii, + fmt_nlist_a, + sec_a, + rcut_r_smth, + rcut_r); + + // check sizes + assert (d_descrpt_a.size() == ndescrpt_a); + assert (d_descrpt_a_deriv.size() == ndescrpt_a * 3); + assert (d_rij_a.size() == nnei_a * 3); + assert (int(fmt_nlist_a.size()) == nnei_a); + // record outputs + for (int jj = 0; jj < ndescrpt_a; ++jj) { + descrpt(kk, ii * ndescrpt + jj) = (d_descrpt_a[jj] - avg(d_type[ii], jj)) / std(d_type[ii], jj); + } + for (int jj = 0; jj < ndescrpt_a * 3; ++jj) { + descrpt_deriv(kk, ii * ndescrpt * 3 + jj) = d_descrpt_a_deriv[jj] / std(d_type[ii], jj/3); + } + for (int jj = 0; jj < nnei_a * 3; ++jj){ + rij (kk, ii * nnei * 3 + jj) = d_rij_a[jj]; + } + for (int jj = 0; jj < nnei_a; ++jj){ + int record = fmt_nlist_a[jj]; + if (b_nlist_map && record >= 0) { + record = nlist_map[record]; + } + nlist (kk, ii * nnei + jj) = record; + } + } + } + } +private: + float rcut_a; + float rcut_r; + float rcut_r_smth; + vector sel_r; + vector sel_a; + vector sec_a; + vector sec_r; + int ndescrpt, ndescrpt_a, ndescrpt_r; + int nnei, nnei_a, nnei_r; + bool fill_nei_a; + int count_nei_idx_overflow; + void + cum_sum (vector & sec, + const vector & n_sel) const { + sec.resize (n_sel.size() + 1); + sec[0] = 0; + for (int ii = 1; ii < sec.size(); ++ii){ + sec[ii] = sec[ii-1] + n_sel[ii-1]; + } + } +}; + +REGISTER_KERNEL_BUILDER(Name("DescrptSeAEfPara").Device(DEVICE_CPU), DescrptSeAEfParaOp); + diff --git a/source/op/descrpt_se_a_ef_vert.cc b/source/op/descrpt_se_a_ef_vert.cc new file mode 100644 index 0000000000..9a7199c9f9 --- /dev/null +++ b/source/op/descrpt_se_a_ef_vert.cc @@ -0,0 +1,389 @@ +#include "tensorflow/core/framework/op.h" +#include "tensorflow/core/framework/op_kernel.h" +#include "tensorflow/core/framework/shape_inference.h" +#include + +#include "ComputeDescriptor.h" +#include "NeighborList.h" + +typedef double boxtensor_t ; +typedef double compute_t; + +using namespace tensorflow; +using namespace std; + +#ifdef HIGH_PREC +typedef double VALUETYPE ; +#else +typedef float VALUETYPE ; +#endif + +#ifdef HIGH_PREC +REGISTER_OP("DescrptSeAEfVert") +.Input("coord: double") +.Input("type: int32") +.Input("natoms: int32") +.Input("box: double") +.Input("mesh: int32") +.Input("ef: double") +.Input("davg: double") +.Input("dstd: double") +.Attr("rcut_a: float") +.Attr("rcut_r: float") +.Attr("rcut_r_smth: float") +.Attr("sel_a: list(int)") +.Attr("sel_r: list(int)") +.Output("descrpt: double") +.Output("descrpt_deriv: double") +.Output("rij: double") +.Output("nlist: int32"); +#else +REGISTER_OP("DescrptSeAEfVert") +.Input("coord: float") +.Input("type: int32") +.Input("natoms: int32") +.Input("box: float") +.Input("mesh: int32") +.Input("ef: float") +.Input("davg: float") +.Input("dstd: float") +.Attr("rcut_a: float") +.Attr("rcut_r: float") +.Attr("rcut_r_smth: float") +.Attr("sel_a: list(int)") +.Attr("sel_r: list(int)") +.Output("descrpt: float") +.Output("descrpt_deriv: float") +.Output("rij: float") +.Output("nlist: int32"); +#endif + +class DescrptSeAEfVertOp : public OpKernel { +public: + explicit DescrptSeAEfVertOp(OpKernelConstruction* context) : OpKernel(context) { + OP_REQUIRES_OK(context, context->GetAttr("rcut_a", &rcut_a)); + OP_REQUIRES_OK(context, context->GetAttr("rcut_r", &rcut_r)); + OP_REQUIRES_OK(context, context->GetAttr("rcut_r_smth", &rcut_r_smth)); + OP_REQUIRES_OK(context, context->GetAttr("sel_a", &sel_a)); + OP_REQUIRES_OK(context, context->GetAttr("sel_r", &sel_r)); + cum_sum (sec_a, sel_a); + cum_sum (sec_r, sel_r); + ndescrpt_a = sec_a.back() * 4; + ndescrpt_r = sec_r.back() * 1; + ndescrpt = ndescrpt_a + ndescrpt_r; + nnei_a = sec_a.back(); + nnei_r = sec_r.back(); + nnei = nnei_a + nnei_r; + fill_nei_a = (rcut_a < 0); + count_nei_idx_overflow = 0; + } + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& coord_tensor = context->input(context_input_index++); + const Tensor& type_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); + const Tensor& box_tensor = context->input(context_input_index++); + const Tensor& mesh_tensor = context->input(context_input_index++); + const Tensor& ef_tensor = context->input(context_input_index++); + const Tensor& avg_tensor = context->input(context_input_index++); + const Tensor& std_tensor = context->input(context_input_index++); + + // set size of the sample + OP_REQUIRES (context, (coord_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of coord should be 2")); + OP_REQUIRES (context, (type_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of type should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + OP_REQUIRES (context, (box_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of box should be 2")); + OP_REQUIRES (context, (mesh_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of mesh should be 1")); + OP_REQUIRES (context, (ef_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of ef should be 2")); + OP_REQUIRES (context, (avg_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of avg should be 2")); + OP_REQUIRES (context, (std_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of std should be 2")); + OP_REQUIRES (context, (fill_nei_a), errors::InvalidArgument ("Rotational free descriptor only support the case rcut_a < 0")); + OP_REQUIRES (context, (sec_r.back() == 0), errors::InvalidArgument ("Rotational free descriptor only support all-angular information: sel_r should be all zero.")); + + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + auto natoms = natoms_tensor .flat(); + int nloc = natoms(0); + int nall = natoms(1); + int ntypes = natoms_tensor.shape().dim_size(0) - 2; + int nsamples = coord_tensor.shape().dim_size(0); + + // check the sizes + OP_REQUIRES (context, (nsamples == type_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nsamples == box_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nsamples == ef_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (ntypes == avg_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of avg should be ntype")); + OP_REQUIRES (context, (ntypes == std_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of std should be ntype")); + + OP_REQUIRES (context, (nall * 3 == coord_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); + OP_REQUIRES (context, (nall == type_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); + OP_REQUIRES (context, (9 == box_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of box should be 9")); + OP_REQUIRES (context, (nloc * 3 == ef_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of ef should be 3")); + OP_REQUIRES (context, (ndescrpt == avg_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of avg should be ndescrpt")); + OP_REQUIRES (context, (ndescrpt == std_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of std should be ndescrpt")); + + int nei_mode = 0; + if (mesh_tensor.shape().dim_size(0) == 16) { + // lammps neighbor list + nei_mode = 3; + } + else if (mesh_tensor.shape().dim_size(0) == 12) { + // user provided extended mesh + nei_mode = 2; + } + else if (mesh_tensor.shape().dim_size(0) == 6) { + // manual copied pbc + assert (nloc == nall); + nei_mode = 1; + } + else if (mesh_tensor.shape().dim_size(0) == 0) { + // no pbc + nei_mode = -1; + } + else { + throw runtime_error("invalid mesh tensor"); + } + bool b_pbc = true; + // if region is given extended, do not use pbc + if (nei_mode >= 1 || nei_mode == -1) { + b_pbc = false; + } + bool b_norm_atom = false; + if (nei_mode == 1){ + b_norm_atom = true; + } + + // Create an output tensor + TensorShape descrpt_shape ; + descrpt_shape.AddDim (nsamples); + descrpt_shape.AddDim (nloc * ndescrpt); + TensorShape descrpt_deriv_shape ; + descrpt_deriv_shape.AddDim (nsamples); + descrpt_deriv_shape.AddDim (nloc * ndescrpt * 3); + TensorShape rij_shape ; + rij_shape.AddDim (nsamples); + rij_shape.AddDim (nloc * nnei * 3); + TensorShape nlist_shape ; + nlist_shape.AddDim (nsamples); + nlist_shape.AddDim (nloc * nnei); + + int context_output_index = 0; + Tensor* descrpt_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + descrpt_shape, + &descrpt_tensor)); + Tensor* descrpt_deriv_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + descrpt_deriv_shape, + &descrpt_deriv_tensor)); + Tensor* rij_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + rij_shape, + &rij_tensor)); + Tensor* nlist_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + nlist_shape, + &nlist_tensor)); + + auto coord = coord_tensor .matrix(); + auto type = type_tensor .matrix(); + auto box = box_tensor .matrix(); + auto mesh = mesh_tensor .flat(); + auto ef = ef_tensor .matrix(); + auto avg = avg_tensor .matrix(); + auto std = std_tensor .matrix(); + auto descrpt = descrpt_tensor ->matrix(); + auto descrpt_deriv = descrpt_deriv_tensor ->matrix(); + auto rij = rij_tensor ->matrix(); + auto nlist = nlist_tensor ->matrix(); + + // // check the types + // int max_type_v = 0; + // for (int ii = 0; ii < natoms; ++ii){ + // if (type(0, ii) > max_type_v) max_type_v = type(0, ii); + // } + // int ntypes = max_type_v + 1; + OP_REQUIRES (context, (ntypes == int(sel_a.size())), errors::InvalidArgument ("number of types should match the length of sel array")); + OP_REQUIRES (context, (ntypes == int(sel_r.size())), errors::InvalidArgument ("number of types should match the length of sel array")); + + for (int kk = 0; kk < nsamples; ++kk){ + // set region + boxtensor_t boxt [9] = {0}; + for (int dd = 0; dd < 9; ++dd) { + boxt[dd] = box(kk, dd); + } + SimulationRegion region; + region.reinitBox (boxt); + + // set & normalize coord + vector d_coord3 (nall*3); + for (int ii = 0; ii < nall; ++ii){ + for (int dd = 0; dd < 3; ++dd){ + d_coord3[ii*3+dd] = coord(kk, ii*3+dd); + } + if (b_norm_atom){ + compute_t inter[3]; + region.phys2Inter (inter, &d_coord3[3*ii]); + for (int dd = 0; dd < 3; ++dd){ + if (inter[dd] < 0 ) inter[dd] += 1.; + else if (inter[dd] >= 1) inter[dd] -= 1.; + } + region.inter2Phys (&d_coord3[3*ii], inter); + } + } + + // set efield + vector d_ef(nloc * 3); + for (int ii = 0; ii < nloc; ++ii){ + for (int dd = 0; dd < 3; ++dd){ + d_ef[ii*3+dd] = ef(kk, ii*3+dd); + } + } + + // set type + vector d_type (nall); + for (int ii = 0; ii < nall; ++ii) d_type[ii] = type(kk, ii); + + // build nlist + vector > d_nlist_a; + vector > d_nlist_r; + vector nlist_map; + bool b_nlist_map = false; + if (nei_mode == 3) { + int * pilist, *pjrange, *pjlist; + memcpy (&pilist, &mesh(4), sizeof(int *)); + memcpy (&pjrange, &mesh(8), sizeof(int *)); + memcpy (&pjlist, &mesh(12), sizeof(int *)); + int inum = mesh(1); + assert (inum == nloc); + d_nlist_a.resize (inum); + d_nlist_r.resize (inum); + for (unsigned ii = 0; ii < inum; ++ii){ + d_nlist_r.reserve (pjrange[inum] / inum + 10); + } + for (unsigned ii = 0; ii < inum; ++ii){ + int i_idx = pilist[ii]; + for (unsigned jj = pjrange[ii]; jj < pjrange[ii+1]; ++jj){ + int j_idx = pjlist[jj]; + d_nlist_r[i_idx].push_back (j_idx); + } + } + } + else if (nei_mode == 2) { + vector nat_stt = {mesh(1-1), mesh(2-1), mesh(3-1)}; + vector nat_end = {mesh(4-1), mesh(5-1), mesh(6-1)}; + vector ext_stt = {mesh(7-1), mesh(8-1), mesh(9-1)}; + vector ext_end = {mesh(10-1), mesh(11-1), mesh(12-1)}; + vector global_grid (3); + for (int dd = 0; dd < 3; ++dd) global_grid[dd] = nat_end[dd] - nat_stt[dd]; + ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, rcut_a, rcut_r, nat_stt, nat_end, ext_stt, ext_end, region, global_grid); + } + else if (nei_mode == 1) { + vector bk_d_coord3 = d_coord3; + vector bk_d_type = d_type; + vector ncell, ngcell; + copy_coord(d_coord3, d_type, nlist_map, ncell, ngcell, bk_d_coord3, bk_d_type, rcut_r, region); + b_nlist_map = true; + vector nat_stt(3, 0); + vector ext_stt(3), ext_end(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, rcut_a, rcut_r, nat_stt, ncell, ext_stt, ext_end, region, ncell); + } + else if (nei_mode == -1){ + ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, rcut_a, rcut_r, NULL); + } + else { + throw runtime_error("unknow neighbor mode"); + } + + // loop over atoms, compute descriptors for each atom +#pragma omp parallel for + for (int ii = 0; ii < nloc; ++ii){ + vector fmt_nlist_a; + vector fmt_nlist_r; + int ret = -1; + if (fill_nei_a){ + if ((ret = format_nlist_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ + if (count_nei_idx_overflow == 0) { + cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << endl; + flush(cout); + count_nei_idx_overflow ++; + } + } + } + + vector d_descrpt_a; + vector d_descrpt_a_deriv; + vector d_descrpt_r; + vector d_descrpt_r_deriv; + vector d_rij_a; + vector d_rij_r; + compute_descriptor_se_a_ef_vert (d_descrpt_a, + d_descrpt_a_deriv, + d_rij_a, + d_coord3, + ntypes, + d_type, + region, + b_pbc, + d_ef, + ii, + fmt_nlist_a, + sec_a, + rcut_r_smth, + rcut_r); + + // check sizes + assert (d_descrpt_a.size() == ndescrpt_a); + assert (d_descrpt_a_deriv.size() == ndescrpt_a * 3); + assert (d_rij_a.size() == nnei_a * 3); + assert (int(fmt_nlist_a.size()) == nnei_a); + // record outputs + for (int jj = 0; jj < ndescrpt_a; ++jj) { + descrpt(kk, ii * ndescrpt + jj) = (d_descrpt_a[jj] - avg(d_type[ii], jj)) / std(d_type[ii], jj); + } + for (int jj = 0; jj < ndescrpt_a * 3; ++jj) { + descrpt_deriv(kk, ii * ndescrpt * 3 + jj) = d_descrpt_a_deriv[jj] / std(d_type[ii], jj/3); + } + for (int jj = 0; jj < nnei_a * 3; ++jj){ + rij (kk, ii * nnei * 3 + jj) = d_rij_a[jj]; + } + for (int jj = 0; jj < nnei_a; ++jj){ + int record = fmt_nlist_a[jj]; + if (b_nlist_map && record >= 0) { + record = nlist_map[record]; + } + nlist (kk, ii * nnei + jj) = record; + } + } + } + } +private: + float rcut_a; + float rcut_r; + float rcut_r_smth; + vector sel_r; + vector sel_a; + vector sec_a; + vector sec_r; + int ndescrpt, ndescrpt_a, ndescrpt_r; + int nnei, nnei_a, nnei_r; + bool fill_nei_a; + int count_nei_idx_overflow; + void + cum_sum (vector & sec, + const vector & n_sel) const { + sec.resize (n_sel.size() + 1); + sec[0] = 0; + for (int ii = 1; ii < sec.size(); ++ii){ + sec[ii] = sec[ii-1] + n_sel[ii-1]; + } + } +}; + +REGISTER_KERNEL_BUILDER(Name("DescrptSeAEfVert").Device(DEVICE_CPU), DescrptSeAEfVertOp); + diff --git a/source/tests/test_descrpt_se_ar.py b/source/tests/test_descrpt_se_ar.py index ed49a71e08..a7042f7f1b 100644 --- a/source/tests/test_descrpt_se_ar.py +++ b/source/tests/test_descrpt_se_ar.py @@ -90,7 +90,7 @@ def comp_ef (self, tnatoms, name, reuse = None) : - dout = self.descrpt.build(dcoord, dtype, tnatoms, dbox, self.default_mesh, suffix=name, reuse=reuse) + dout = self.descrpt.build(dcoord, dtype, tnatoms, dbox, self.default_mesh, {"efield": self.efield}, suffix=name, reuse=reuse) inputs_reshape = tf.reshape (dout, [-1, self.descrpt.get_dim_out()]) atom_ener = self._net (inputs_reshape, name, reuse = reuse) atom_ener_reshape = tf.reshape(atom_ener, [-1, self.natoms[0]]) diff --git a/source/tests/test_descrpt_sea_ef_para.py b/source/tests/test_descrpt_sea_ef_para.py new file mode 100644 index 0000000000..3ae3549406 --- /dev/null +++ b/source/tests/test_descrpt_sea_ef_para.py @@ -0,0 +1,184 @@ +import os,sys +import numpy as np +import unittest + +from deepmd.env import tf +from tensorflow.python.framework import ops + +# load grad of force module +import deepmd._prod_force_grad +import deepmd._prod_virial_grad +import deepmd._prod_force_se_a_grad +import deepmd._prod_virial_se_a_grad +import deepmd._soft_min_force_grad +import deepmd._soft_min_virial_grad + +from common import force_test +from common import virial_test +from common import force_dw_test +from common import virial_dw_test +from common import Data + +from deepmd.DescrptLocFrame import op_module + +from deepmd.RunOptions import global_tf_float_precision +from deepmd.RunOptions import global_np_float_precision +from deepmd.RunOptions import global_ener_float_precision + +class Inter(): + def setUp (self, + data, + pbc = True) : + self.sess = tf.Session() + self.data = data + self.natoms = self.data.get_natoms() + self.ntypes = self.data.get_ntypes() + self.sel_a = [12,24] + self.sel_r = [0,0] + self.rcut_a = -1 + self.rcut_r_smth = 2.45 + self.rcut_r = 10.0 + self.nnei_a = np.cumsum(self.sel_a)[-1] + self.nnei_r = np.cumsum(self.sel_r)[-1] + self.nnei = self.nnei_a + self.nnei_r + self.ndescrpt_a = self.nnei_a * 4 + self.ndescrpt_r = self.nnei_r * 1 + self.ndescrpt = self.ndescrpt_a + self.ndescrpt_r + davg = np.zeros ([self.ntypes, self.ndescrpt]) + dstd = np.ones ([self.ntypes, self.ndescrpt]) + self.t_avg = tf.constant(davg.astype(global_np_float_precision)) + self.t_std = tf.constant(dstd.astype(global_np_float_precision)) + if pbc: + self.default_mesh = np.zeros (6, dtype = np.int32) + self.default_mesh[3] = 2 + self.default_mesh[4] = 2 + self.default_mesh[5] = 2 + else: + self.default_mesh = np.array([], dtype = np.int32) + # make place holder + self.coord = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_coord') + self.efield = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_efield') + self.box = tf.placeholder(global_tf_float_precision, [None, 9], name='t_box') + self.type = tf.placeholder(tf.int32, [None, self.natoms[0]], name = "t_type") + self.tnatoms = tf.placeholder(tf.int32, [None], name = "t_natoms") + + def _net (self, + inputs, + name, + reuse = False) : + with tf.variable_scope(name, reuse=reuse): + net_w = tf.get_variable ('net_w', + [self.ndescrpt], + global_tf_float_precision, + tf.constant_initializer (self.net_w_i)) + dot_v = tf.matmul (tf.reshape (inputs, [-1, self.ndescrpt]), + tf.reshape (net_w, [self.ndescrpt, 1])) + return tf.reshape (dot_v, [-1]) + + def comp_ef (self, + dcoord, + dbox, + dtype, + tnatoms, + name, + reuse = None) : + descrpt, descrpt_deriv, rij, nlist \ + = op_module.descrpt_se_a_ef_para (dcoord, + dtype, + tnatoms, + dbox, + tf.constant(self.default_mesh), + self.efield, + self.t_avg, + self.t_std, + rcut_a = self.rcut_a, + rcut_r = self.rcut_r, + rcut_r_smth = self.rcut_r_smth, + sel_a = self.sel_a, + sel_r = self.sel_r) + inputs_reshape = tf.reshape (descrpt, [-1, self.ndescrpt]) + atom_ener = self._net (inputs_reshape, name, reuse = reuse) + atom_ener_reshape = tf.reshape(atom_ener, [-1, self.natoms[0]]) + energy = tf.reduce_sum (atom_ener_reshape, axis = 1) + net_deriv_ = tf.gradients (atom_ener, inputs_reshape) + net_deriv = net_deriv_[0] + net_deriv_reshape = tf.reshape (net_deriv, [-1, self.natoms[0] * self.ndescrpt]) + + force = op_module.prod_force_se_a (net_deriv_reshape, + descrpt_deriv, + nlist, + tnatoms, + n_a_sel = self.nnei_a, + n_r_sel = self.nnei_r) + virial, atom_vir = op_module.prod_virial_se_a (net_deriv_reshape, + descrpt_deriv, + rij, + nlist, + tnatoms, + n_a_sel = self.nnei_a, + n_r_sel = self.nnei_r) + return energy, force, virial + + + def comp_f_dw (self, + dcoord, + dbox, + dtype, + tnatoms, + name, + reuse = None) : + energy, force, virial = self.comp_ef (dcoord, dbox, dtype, tnatoms, name, reuse) + with tf.variable_scope(name, reuse=True): + net_w = tf.get_variable ('net_w', [self.ndescrpt], global_tf_float_precision, tf.constant_initializer (self.net_w_i)) + f_mag = tf.reduce_sum (tf.nn.tanh(force)) + f_mag_dw = tf.gradients (f_mag, net_w) + assert (len(f_mag_dw) == 1), "length of dw is wrong" + return f_mag, f_mag_dw[0] + + + def comp_v_dw (self, + dcoord, + dbox, + dtype, + tnatoms, + name, + reuse = None) : + energy, force, virial = self.comp_ef (dcoord, dbox, dtype, tnatoms, name, reuse) + with tf.variable_scope(name, reuse=True): + net_w = tf.get_variable ('net_w', [self.ndescrpt], global_tf_float_precision, tf.constant_initializer (self.net_w_i)) + v_mag = tf.reduce_sum (virial) + v_mag_dw = tf.gradients (v_mag, net_w) + assert (len(v_mag_dw) == 1), "length of dw is wrong" + return v_mag, v_mag_dw[0] + + + +class TestSmooth(Inter, unittest.TestCase): + # def __init__ (self, *args, **kwargs): + # data = Data() + # Inter.__init__(self, data) + # unittest.TestCase.__init__(self, *args, **kwargs) + # self.controller = object() + + def setUp(self): + self.places = 5 + data = Data() + Inter.setUp(self, data) + + def test_force (self) : + force_test(self, self, suffix = '_sea_ef_para') + + def test_virial (self) : + virial_test(self, self, suffix = '_sea_ef_para') + + def test_force_dw (self) : + force_dw_test(self, self, suffix = '_sea_ef_para') + + def test_virial_dw (self) : + virial_dw_test(self, self, suffix = '_sea_ef_para') + + + + +if __name__ == '__main__': + unittest.main() diff --git a/source/tests/test_descrpt_sea_ef_vert.py b/source/tests/test_descrpt_sea_ef_vert.py new file mode 100644 index 0000000000..efea0da716 --- /dev/null +++ b/source/tests/test_descrpt_sea_ef_vert.py @@ -0,0 +1,184 @@ +import os,sys +import numpy as np +import unittest + +from deepmd.env import tf +from tensorflow.python.framework import ops + +# load grad of force module +import deepmd._prod_force_grad +import deepmd._prod_virial_grad +import deepmd._prod_force_se_a_grad +import deepmd._prod_virial_se_a_grad +import deepmd._soft_min_force_grad +import deepmd._soft_min_virial_grad + +from common import force_test +from common import virial_test +from common import force_dw_test +from common import virial_dw_test +from common import Data + +from deepmd.DescrptLocFrame import op_module + +from deepmd.RunOptions import global_tf_float_precision +from deepmd.RunOptions import global_np_float_precision +from deepmd.RunOptions import global_ener_float_precision + +class Inter(): + def setUp (self, + data, + pbc = True) : + self.sess = tf.Session() + self.data = data + self.natoms = self.data.get_natoms() + self.ntypes = self.data.get_ntypes() + self.sel_a = [12,24] + self.sel_r = [0,0] + self.rcut_a = -1 + self.rcut_r_smth = 2.45 + self.rcut_r = 10.0 + self.nnei_a = np.cumsum(self.sel_a)[-1] + self.nnei_r = np.cumsum(self.sel_r)[-1] + self.nnei = self.nnei_a + self.nnei_r + self.ndescrpt_a = self.nnei_a * 4 + self.ndescrpt_r = self.nnei_r * 1 + self.ndescrpt = self.ndescrpt_a + self.ndescrpt_r + davg = np.zeros ([self.ntypes, self.ndescrpt]) + dstd = np.ones ([self.ntypes, self.ndescrpt]) + self.t_avg = tf.constant(davg.astype(global_np_float_precision)) + self.t_std = tf.constant(dstd.astype(global_np_float_precision)) + if pbc: + self.default_mesh = np.zeros (6, dtype = np.int32) + self.default_mesh[3] = 2 + self.default_mesh[4] = 2 + self.default_mesh[5] = 2 + else: + self.default_mesh = np.array([], dtype = np.int32) + # make place holder + self.coord = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_coord') + self.efield = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_efield') + self.box = tf.placeholder(global_tf_float_precision, [None, 9], name='t_box') + self.type = tf.placeholder(tf.int32, [None, self.natoms[0]], name = "t_type") + self.tnatoms = tf.placeholder(tf.int32, [None], name = "t_natoms") + + def _net (self, + inputs, + name, + reuse = False) : + with tf.variable_scope(name, reuse=reuse): + net_w = tf.get_variable ('net_w', + [self.ndescrpt], + global_tf_float_precision, + tf.constant_initializer (self.net_w_i)) + dot_v = tf.matmul (tf.reshape (inputs, [-1, self.ndescrpt]), + tf.reshape (net_w, [self.ndescrpt, 1])) + return tf.reshape (dot_v, [-1]) + + def comp_ef (self, + dcoord, + dbox, + dtype, + tnatoms, + name, + reuse = None) : + descrpt, descrpt_deriv, rij, nlist \ + = op_module.descrpt_se_a_ef_vert (dcoord, + dtype, + tnatoms, + dbox, + tf.constant(self.default_mesh), + self.efield, + self.t_avg, + self.t_std, + rcut_a = self.rcut_a, + rcut_r = self.rcut_r, + rcut_r_smth = self.rcut_r_smth, + sel_a = self.sel_a, + sel_r = self.sel_r) + inputs_reshape = tf.reshape (descrpt, [-1, self.ndescrpt]) + atom_ener = self._net (inputs_reshape, name, reuse = reuse) + atom_ener_reshape = tf.reshape(atom_ener, [-1, self.natoms[0]]) + energy = tf.reduce_sum (atom_ener_reshape, axis = 1) + net_deriv_ = tf.gradients (atom_ener, inputs_reshape) + net_deriv = net_deriv_[0] + net_deriv_reshape = tf.reshape (net_deriv, [-1, self.natoms[0] * self.ndescrpt]) + + force = op_module.prod_force_se_a (net_deriv_reshape, + descrpt_deriv, + nlist, + tnatoms, + n_a_sel = self.nnei_a, + n_r_sel = self.nnei_r) + virial, atom_vir = op_module.prod_virial_se_a (net_deriv_reshape, + descrpt_deriv, + rij, + nlist, + tnatoms, + n_a_sel = self.nnei_a, + n_r_sel = self.nnei_r) + return energy, force, virial + + + def comp_f_dw (self, + dcoord, + dbox, + dtype, + tnatoms, + name, + reuse = None) : + energy, force, virial = self.comp_ef (dcoord, dbox, dtype, tnatoms, name, reuse) + with tf.variable_scope(name, reuse=True): + net_w = tf.get_variable ('net_w', [self.ndescrpt], global_tf_float_precision, tf.constant_initializer (self.net_w_i)) + f_mag = tf.reduce_sum (tf.nn.tanh(force)) + f_mag_dw = tf.gradients (f_mag, net_w) + assert (len(f_mag_dw) == 1), "length of dw is wrong" + return f_mag, f_mag_dw[0] + + + def comp_v_dw (self, + dcoord, + dbox, + dtype, + tnatoms, + name, + reuse = None) : + energy, force, virial = self.comp_ef (dcoord, dbox, dtype, tnatoms, name, reuse) + with tf.variable_scope(name, reuse=True): + net_w = tf.get_variable ('net_w', [self.ndescrpt], global_tf_float_precision, tf.constant_initializer (self.net_w_i)) + v_mag = tf.reduce_sum (virial) + v_mag_dw = tf.gradients (v_mag, net_w) + assert (len(v_mag_dw) == 1), "length of dw is wrong" + return v_mag, v_mag_dw[0] + + + +class TestSmooth(Inter, unittest.TestCase): + # def __init__ (self, *args, **kwargs): + # data = Data() + # Inter.__init__(self, data) + # unittest.TestCase.__init__(self, *args, **kwargs) + # self.controller = object() + + def setUp(self): + self.places = 5 + data = Data() + Inter.setUp(self, data) + + def test_force (self) : + force_test(self, self, suffix = '_sea_ef_vert') + + def test_virial (self) : + virial_test(self, self, suffix = '_sea_ef_vert') + + def test_force_dw (self) : + force_dw_test(self, self, suffix = '_sea_ef_vert') + + def test_virial_dw (self) : + virial_dw_test(self, self, suffix = '_sea_ef_vert') + + + + +if __name__ == '__main__': + unittest.main() diff --git a/source/train/DescrptLocFrame.py b/source/train/DescrptLocFrame.py index 69c1473db0..6b8408b1d6 100644 --- a/source/train/DescrptLocFrame.py +++ b/source/train/DescrptLocFrame.py @@ -72,11 +72,12 @@ def get_nlist (self) : return self.nlist, self.rij, self.sel_a, self.sel_r def compute_input_stats (self, - data_coord, - data_box, - data_atype, - natoms_vec, - mesh) : + data_coord, + data_box, + data_atype, + natoms_vec, + mesh, + input_dict) : all_davg = [] all_dstd = [] if True: @@ -110,6 +111,7 @@ def build (self, natoms, box_, mesh, + input_dict, suffix = '', reuse = None): davg = self.davg diff --git a/source/train/DescrptSeA.py b/source/train/DescrptSeA.py index 831e56c646..01c1089f5f 100644 --- a/source/train/DescrptSeA.py +++ b/source/train/DescrptSeA.py @@ -86,11 +86,12 @@ def get_nlist (self) : return self.nlist, self.rij, self.sel_a, self.sel_r def compute_input_stats (self, - data_coord, - data_box, - data_atype, - natoms_vec, - mesh) : + data_coord, + data_box, + data_atype, + natoms_vec, + mesh, + input_dict) : all_davg = [] all_dstd = [] if True: @@ -373,7 +374,7 @@ def _filter(self, # qmat = tf.slice(xyz_scatter_2, [0,1,0], [-1, 3, -1]) # natom x 3 x outputs_size_1 qmat = tf.slice(xyz_scatter_1, [0,1,0], [-1, 3, -1]) - # natom x outputs_size_2 x 3 + # natom x outputs_size_1 x 3 qmat = tf.transpose(qmat, perm = [0, 2, 1]) # natom x outputs_size x outputs_size_2 result = tf.matmul(xyz_scatter_1, xyz_scatter_2, transpose_a = True) diff --git a/source/train/DescrptSeAEf.py b/source/train/DescrptSeAEf.py index 17529bada1..287029e970 100644 --- a/source/train/DescrptSeAEf.py +++ b/source/train/DescrptSeAEf.py @@ -7,8 +7,77 @@ from deepmd.env import default_tf_session_config from deepmd.DescrptSeA import DescrptSeA -class DescrptSeAEf (DescrptSeA): - def __init__ (self, jdata): +class DescrptSeAEf (): + def __init__(self, jdata): + self.descrpt_para = DescrptSeAEfLower(jdata, op_module.descrpt_se_a_ef_para) + self.descrpt_vert = DescrptSeAEfLower(jdata, op_module.descrpt_se_a_ef_vert) + + def get_rcut (self) : + return self.descrpt_vert.rcut_r + + def get_ntypes (self) : + return self.descrpt_vert.ntypes + + def get_dim_out (self) : + return self.descrpt_vert.get_dim_out() + self.descrpt_para.get_dim_out() + + def get_dim_rot_mat_1 (self) : + return self.descrpt_vert.filter_neuron[-1] + + def get_rot_mat(self) : + return self.qmat + + + def get_nlist (self) : + return \ + self.descrpt_vert.nlist, \ + self.descrpt_vert.rij, \ + self.descrpt_vert.sel_a, \ + self.descrpt_vert.sel_r + + def compute_input_stats (self, + data_coord, + data_box, + data_atype, + natoms_vec, + mesh, + input_dict) : + self.descrpt_vert.compute_input_stats(data_coord, data_box, data_atype, natoms_vec, mesh, input_dict) + self.descrpt_para.compute_input_stats(data_coord, data_box, data_atype, natoms_vec, mesh, input_dict) + + def build (self, + coord_, + atype_, + natoms, + box_, + mesh, + input_dict, + suffix = '', + reuse = None): + self.dout_vert = self.descrpt_vert.build(coord_, atype_, natoms, box_, mesh, input_dict) + self.dout_para = self.descrpt_para.build(coord_, atype_, natoms, box_, mesh, input_dict, reuse = True) + coord = tf.reshape(coord_, [-1, natoms[1] * 3]) + nframes = tf.shape(coord)[0] + self.dout_vert = tf.reshape(self.dout_vert, [nframes * natoms[0], self.descrpt_vert.get_dim_out()]) + self.dout_para = tf.reshape(self.dout_para, [nframes * natoms[0], self.descrpt_para.get_dim_out()]) + self.dout = tf.concat([self.dout_vert, self.dout_para], axis = 1) + self.dout = tf.reshape(self.dout, [nframes, natoms[0] * self.get_dim_out()]) + self.qmat = self.descrpt_vert.qmat + self.descrpt_para.qmat + return self.dout + + def prod_force_virial(self, atom_ener, natoms) : + f_vert, v_vert, av_vert \ + = self.descrpt_vert.prod_force_virial(atom_ener, natoms) + f_para, v_para, av_para \ + = self.descrpt_para.prod_force_virial(atom_ener, natoms) + force = f_vert + f_para + virial = v_vert + v_para + atom_vir = av_vert + av_para + return force, virial, atom_vir + + +class DescrptSeAEfLower (DescrptSeA): + def __init__ (self, jdata, op): args = ClassArg()\ .add('sel', list, must = True) \ .add('rcut', float, default = 6.0) \ @@ -27,6 +96,7 @@ def __init__ (self, jdata): self.filter_resnet_dt = class_data['resnet_dt'] self.seed = class_data['seed'] self.trainable = class_data['trainable'] + self.op = op # descrpt config self.sel_r = [ 0 for ii in range(len(self.sel_a)) ] @@ -59,19 +129,19 @@ def __init__ (self, jdata): self.place_holders['default_mesh'] = tf.placeholder(tf.int32, [None], name=name_pfx+'t_mesh') self.place_holders['efield'] = tf.placeholder(global_np_float_precision, [None, None], name=name_pfx+'t_efield') self.stat_descrpt, descrpt_deriv, rij, nlist \ - = op_module.descrpt_se_a_ef(self.place_holders['coord'], - self.place_holders['type'], - self.place_holders['natoms_vec'], - self.place_holders['box'], - self.place_holders['default_mesh'], - self.place_holders['efield'], - tf.constant(avg_zero), - tf.constant(std_ones), - rcut_a = self.rcut_a, - rcut_r = self.rcut_r, - rcut_r_smth = self.rcut_r_smth, - sel_a = self.sel_a, - sel_r = self.sel_r) + = self.op(self.place_holders['coord'], + self.place_holders['type'], + self.place_holders['natoms_vec'], + self.place_holders['box'], + self.place_holders['default_mesh'], + self.place_holders['efield'], + tf.constant(avg_zero), + tf.constant(std_ones), + rcut_a = self.rcut_a, + rcut_r = self.rcut_r, + rcut_r_smth = self.rcut_r_smth, + sel_a = self.sel_a, + sel_r = self.sel_r) self.sub_sess = tf.Session(graph = sub_graph, config=default_tf_session_config) @@ -173,19 +243,19 @@ def build (self, efield = tf.reshape(efield, [-1, natoms[0] * 3]) self.descrpt, self.descrpt_deriv, self.rij, self.nlist \ - = op_module.descrpt_se_a_ef (coord, - atype, - natoms, - box, - mesh, - efield, - self.t_avg, - self.t_std, - rcut_a = self.rcut_a, - rcut_r = self.rcut_r, - rcut_r_smth = self.rcut_r_smth, - sel_a = self.sel_a, - sel_r = self.sel_r) + = self.op (coord, + atype, + natoms, + box, + mesh, + efield, + self.t_avg, + self.t_std, + rcut_a = self.rcut_a, + rcut_r = self.rcut_r, + rcut_r_smth = self.rcut_r_smth, + sel_a = self.sel_a, + sel_r = self.sel_r) self.descrpt_reshape = tf.reshape(self.descrpt, [-1, self.ndescrpt]) self.descrpt_reshape = tf.identity(self.descrpt_reshape, name = 'o_rmat') diff --git a/source/train/DescrptSeAR.py b/source/train/DescrptSeAR.py index dadc2f3d95..2902ee6fee 100644 --- a/source/train/DescrptSeAR.py +++ b/source/train/DescrptSeAR.py @@ -53,6 +53,7 @@ def build (self, natoms, box, mesh, + input_dict, suffix = '', reuse = None): davg = self.davg @@ -64,8 +65,8 @@ def build (self, dstd = [np.ones ([self.descrpt_a.ntypes, self.descrpt_a.ndescrpt]), np.ones ([self.descrpt_r.ntypes, self.descrpt_r.ndescrpt])] # dout - self.dout_a = self.descrpt_a.build(coord_, atype_, natoms, box, mesh, suffix=suffix+'_a', reuse=reuse) - self.dout_r = self.descrpt_r.build(coord_, atype_, natoms, box, mesh, suffix=suffix , reuse=reuse) + self.dout_a = self.descrpt_a.build(coord_, atype_, natoms, box, mesh, input_dict, suffix=suffix+'_a', reuse=reuse) + self.dout_r = self.descrpt_r.build(coord_, atype_, natoms, box, mesh, input_dict, suffix=suffix , reuse=reuse) self.dout_a = tf.reshape(self.dout_a, [-1, self.descrpt_a.get_dim_out()]) self.dout_r = tf.reshape(self.dout_r, [-1, self.descrpt_r.get_dim_out()]) self.dout = tf.concat([self.dout_a, self.dout_r], axis = 1) diff --git a/source/train/DescrptSeR.py b/source/train/DescrptSeR.py index 7a2d2125e5..b72e6648a9 100644 --- a/source/train/DescrptSeR.py +++ b/source/train/DescrptSeR.py @@ -77,11 +77,12 @@ def get_nlist (self) : return self.nlist, self.rij, self.sel_a, self.sel_r def compute_input_stats (self, - data_coord, - data_box, - data_atype, - natoms_vec, - mesh) : + data_coord, + data_box, + data_atype, + natoms_vec, + mesh, + input_dict) : all_davg = [] all_dstd = [] sumr = [] @@ -114,6 +115,7 @@ def build (self, natoms, box_, mesh, + input_dict, suffix = '', reuse = None): davg = self.davg diff --git a/source/train/Model.py b/source/train/Model.py index 7d1d3426e4..af7eb77e35 100644 --- a/source/train/Model.py +++ b/source/train/Model.py @@ -307,7 +307,8 @@ def _compute_input_stat(self, all_stat, protection = 1e-2) : all_stat['box'], all_stat['type'], all_stat['natoms_vec'], - all_stat['default_mesh']) + all_stat['default_mesh'], + all_stat) if hasattr(self.fitting, 'compute_input_stats'): self.fitting.compute_input_stats(all_stat, protection = protection) @@ -345,6 +346,7 @@ def build (self, natoms, box, mesh, + input_dict, suffix = suffix, reuse = reuse) dout = tf.identity(dout, name='o_descriptor') From bd365216b65ee138abba329b47b3ee0b776e1a6f Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 14 Feb 2020 14:36:53 +0800 Subject: [PATCH 004/562] make the testing code work. option to shift the total energy zero --- source/train/DeepPot.py | 35 ++++++++++++++++++++++++++--------- source/train/Fitting.py | 11 +++++++++++ source/train/main.py | 2 ++ source/train/test.py | 19 ++++++++++++++++--- 4 files changed, 55 insertions(+), 12 deletions(-) diff --git a/source/train/DeepPot.py b/source/train/DeepPot.py index 2a75bb7388..b69a67b04a 100644 --- a/source/train/DeepPot.py +++ b/source/train/DeepPot.py @@ -25,6 +25,12 @@ def __init__(self, self.t_natoms = self.graph.get_tensor_by_name ('load/t_natoms:0') self.t_box = self.graph.get_tensor_by_name ('load/t_box:0') self.t_mesh = self.graph.get_tensor_by_name ('load/t_mesh:0') + try: + self.t_efield = self.graph.get_tensor_by_name ('load/t_efield:0') + self.has_efield = True + except: + self.t_efield = None + self.has_efield = False # outputs self.t_energy = self.graph.get_tensor_by_name ('load/o_energy:0') self.t_force = self.graph.get_tensor_by_name ('load/o_force:0') @@ -88,13 +94,14 @@ def eval(self, atom_types, fparam = None, aparam = None, - atomic = False) : + atomic = False, + efield = None) : if atomic : if self.modifier_type is not None: raise RuntimeError('modifier does not support atomic modification') - return self.eval_inner(coords, cells, atom_types, fparam = fparam, aparam = aparam, atomic = atomic) + return self.eval_inner(coords, cells, atom_types, fparam = fparam, aparam = aparam, atomic = atomic, efield = efield) else : - e, f, v = self.eval_inner(coords, cells, atom_types, fparam = fparam, aparam = aparam, atomic = atomic) + e, f, v = self.eval_inner(coords, cells, atom_types, fparam = fparam, aparam = aparam, atomic = atomic, efield = efield) if self.modifier_type is not None: me, mf, mv = self.dm.eval(coords, cells, atom_types) e += me.reshape(e.shape) @@ -103,12 +110,13 @@ def eval(self, return e, f, v def eval_inner(self, - coords, - cells, - atom_types, - fparam = None, - aparam = None, - atomic = False) : + coords, + cells, + atom_types, + fparam = None, + aparam = None, + atomic = False, + efield = None) : # standarize the shape of inputs atom_types = np.array(atom_types, dtype = int).reshape([-1]) natoms = atom_types.size @@ -128,6 +136,9 @@ def eval_inner(self, if self.has_aparam : assert(aparam is not None) aparam = np.array(aparam) + if self.has_efield : + assert(efield is not None), "you are using a model with external field, parameter efield should be provided" + efield = np.array(efield) # reshape the inputs if self.has_fparam : @@ -151,6 +162,10 @@ def eval_inner(self, # sort inputs coords, atom_types, imap = self.sort_input(coords, atom_types) + if self.has_efield: + efield = np.reshape(efield, [nframes, natoms, 3]) + efield = efield[:,imap,:] + efield = np.reshape(efield, [nframes, natoms*3]) # make natoms_vec and default_mesh natoms_vec = self.make_natoms_vec(atom_types) @@ -174,6 +189,8 @@ def eval_inner(self, for ii in range(nframes) : feed_dict_test[self.t_coord] = np.reshape(coords[ii:ii+1, :], [-1]) feed_dict_test[self.t_box ] = np.reshape(cells [ii:ii+1, :], [-1]) + if self.has_efield: + feed_dict_test[self.t_efield]= np.reshape(efield[ii:ii+1, :], [-1]) if pbc: feed_dict_test[self.t_mesh ] = make_default_mesh(cells[ii:ii+1, :]) else: diff --git a/source/train/Fitting.py b/source/train/Fitting.py index c940bcbcb1..d042d84f8d 100644 --- a/source/train/Fitting.py +++ b/source/train/Fitting.py @@ -7,6 +7,7 @@ from deepmd.DescrptLocFrame import DescrptLocFrame from deepmd.DescrptSeA import DescrptSeA +from deepmd.RunOptions import global_cvt_2_tf_float from deepmd.RunOptions import global_tf_float_precision class EnerFitting (): @@ -20,6 +21,7 @@ def __init__ (self, jdata, descrpt): .add('neuron', list, default = [120,120,120], alias = 'n_neuron')\ .add('resnet_dt', bool, default = True)\ .add('rcond', float, default = 1e-3) \ + .add('tot_ener_zero', bool, default = False) \ .add('seed', int) class_data = args.parse(jdata) self.numb_fparam = class_data['numb_fparam'] @@ -28,6 +30,7 @@ def __init__ (self, jdata, descrpt): self.resnet_dt = class_data['resnet_dt'] self.rcond = class_data['rcond'] self.seed = class_data['seed'] + self.tot_ener_zero = class_data['tot_ener_zero'] self.useBN = False self.bias_atom_e = None # data requirement @@ -206,6 +209,14 @@ def build (self, else: outs = tf.concat([outs, final_layer], axis = 1) + if self.tot_ener_zero: + force_tot_ener = 0.0 + outs = tf.reshape(outs, [-1, natoms[0]]) + outs_mean = tf.reshape(tf.reduce_mean(outs, axis = 1), [-1, 1]) + outs_mean = outs_mean - tf.ones_like(outs_mean, dtype = global_tf_float_precision) * (force_tot_ener/global_cvt_2_tf_float(natoms[0])) + outs = outs - outs_mean + outs = tf.reshape(outs, [-1]) + return tf.reshape(outs, [-1]) diff --git a/source/train/main.py b/source/train/main.py index 49aea59084..d6987feb52 100644 --- a/source/train/main.py +++ b/source/train/main.py @@ -48,6 +48,8 @@ def main () : help="Shuffle test data") parser_tst.add_argument("-d", "--detail-file", type=str, help="The file containing details of energy force and virial accuracy") + parser_tst.add_argument("-a", "--atomic-energy", action = 'store_true', + help="Test the accuracy of atomic energy") args = parser.parse_args() diff --git a/source/train/test.py b/source/train/test.py index 6269947758..3e03bb5230 100644 --- a/source/train/test.py +++ b/source/train/test.py @@ -44,12 +44,17 @@ def l2err (diff) : def test_ener (args) : if args.rand_seed is not None : np.random.seed(args.rand_seed % (2**32)) - + has_atom_ener = args.atomic_energy + dp = DeepPot(args.model) data = DeepmdData(args.system, args.set_prefix, shuffle_test = args.shuffle_test, type_map = dp.get_type_map()) data.add('energy', 1, atomic=False, must=False, high_prec=True) data.add('force', 3, atomic=True, must=False, high_prec=False) data.add('virial', 9, atomic=False, must=False, high_prec=False) + if dp.has_efield: + data.add('efield', 3, atomic=True, must=True, high_prec=False) + if has_atom_ener: + data.add('atom_ener', 1, atomic=True, must=True, high_prec=False) if dp.get_dim_fparam() > 0: data.add('fparam', dp.get_dim_fparam(), atomic=False, must=True, high_prec=False) if dp.get_dim_aparam() > 0: @@ -63,6 +68,10 @@ def test_ener (args) : coord = test_data["coord"][:numb_test].reshape([numb_test, -1]) box = test_data["box"][:numb_test] + if dp.has_efield: + efield = test_data["efield"][:numb_test].reshape([numb_test, -1]) + else : + efield = None if not data.pbc: box = None atype = test_data["type"][0] @@ -75,12 +84,12 @@ def test_ener (args) : else : aparam = None detail_file = args.detail_file - if detail_file is not None: + if detail_file is not None or has_atom_ener: atomic = True else: atomic = False - ret = dp.eval(coord, box, atype, fparam = fparam, aparam = aparam, atomic = atomic) + ret = dp.eval(coord, box, atype, fparam = fparam, aparam = aparam, atomic = atomic, efield = efield) energy = ret[0] force = ret[1] virial = ret[2] @@ -98,6 +107,8 @@ def test_ener (args) : l2v = (l2err (virial - test_data["virial"][:numb_test])) l2ea= l2e/natoms l2va= l2v/natoms + if has_atom_ener: + l2ae = (l2err(test_data['atom_ener'][:numb_test].reshape([-1]) - ae.reshape([-1]))) # print ("# energies: %s" % energy) print ("# number of test data : %d " % numb_test) @@ -106,6 +117,8 @@ def test_ener (args) : print ("Force L2err : %e eV/A" % l2f) print ("Virial L2err : %e eV" % l2v) print ("Virial L2err/Natoms : %e eV" % l2va) + if has_atom_ener: + print ("Atomic ener L2err : %e eV" % l2ae) if detail_file is not None : pe = np.concatenate((np.reshape(test_data["energy"][:numb_test], [-1,1]), From 991514f3488c18e0e6728db288cda4059fc9ee35 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 9 Mar 2020 22:04:15 +0800 Subject: [PATCH 005/562] add rotation test --- source/tests/test_descrpt_sea_ef_rot.py | 364 ++++++++++++++++++++++++ 1 file changed, 364 insertions(+) create mode 100644 source/tests/test_descrpt_sea_ef_rot.py diff --git a/source/tests/test_descrpt_sea_ef_rot.py b/source/tests/test_descrpt_sea_ef_rot.py new file mode 100644 index 0000000000..8d2b0234fd --- /dev/null +++ b/source/tests/test_descrpt_sea_ef_rot.py @@ -0,0 +1,364 @@ +import os,sys +import numpy as np +import unittest + +from deepmd.env import tf +from tensorflow.python.framework import ops +from deepmd.RunOptions import global_tf_float_precision +from deepmd.RunOptions import global_np_float_precision +from deepmd.RunOptions import global_ener_float_precision + +from deepmd.env import op_module +from deepmd.DescrptSeA import DescrptSeA +from deepmd.DescrptSeAEf import DescrptSeAEfLower + +class TestEfRot(unittest.TestCase): + def setUp(self): + self.sess = tf.Session() + self.natoms = [5, 5, 2, 3] + self.ntypes = 2 + self.sel_a = [12,24] + self.sel_r = [0,0] + self.rcut_a = -1 + self.rcut_r_smth = 2.45 + self.rcut_r = 10.0 + self.nnei_a = np.cumsum(self.sel_a)[-1] + self.nnei_r = np.cumsum(self.sel_r)[-1] + self.nnei = self.nnei_a + self.nnei_r + self.ndescrpt_a = self.nnei_a * 4 + self.ndescrpt_r = self.nnei_r * 1 + self.ndescrpt = self.ndescrpt_a + self.ndescrpt_r + davg = np.zeros ([self.ntypes, self.ndescrpt]) + dstd = np.ones ([self.ntypes, self.ndescrpt]) + self.t_avg = tf.constant(davg.astype(global_np_float_precision)) + self.t_std = tf.constant(dstd.astype(global_np_float_precision)) + # no pbc + self.default_mesh = np.array([], dtype = np.int32) + # make place holder + self.coord = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_coord') + self.efield = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_efield') + self.box = tf.placeholder(global_tf_float_precision, [None, 9], name='t_box') + self.type = tf.placeholder(tf.int32, [None, self.natoms[0]], name = "t_type") + self.tnatoms = tf.placeholder(tf.int32, [None], name = "t_natoms") + + + def _normalize_3d(self, a): + na = tf.norm(a, axis = 1) + na = tf.tile(tf.reshape(na, [-1,1]), tf.constant([1, 3])) + b = tf.divide(a, na) + return b + + def build_efv(self, + dcoord, + dbox, + dtype, + tnatoms, + name, + op, + reuse = None): + efield = tf.reshape(self.efield, [-1, 3]) + efield = self._normalize_3d(efield) + efield = tf.reshape(efield, [-1, tnatoms[0] * 3]) + if op != op_module.descrpt_se_a : + descrpt = DescrptSeAEfLower({'sel':self.sel_a}, op) + else: + descrpt = DescrptSeA({'sel':self.sel_a}) + dout = descrpt.build(dcoord, + dtype, + tnatoms, + dbox, + tf.constant(self.default_mesh), + {'efield': efield}, + suffix = name, + reuse = reuse) + dout = tf.reshape(dout, [-1, descrpt.get_dim_out()]) + atom_ener = tf.reduce_sum(dout, axis = 1) + atom_ener_reshape = tf.reshape(atom_ener, [-1, self.natoms[0]]) + energy = tf.reduce_sum (atom_ener_reshape, axis = 1) + force, virial, atom_vir \ + = descrpt.prod_force_virial (atom_ener, tnatoms) + return energy, force, virial, atom_ener, atom_vir + + def make_test_data(self, nframes): + dcoord = np.random.random([nframes, self.natoms[0], 3]) + for ii in range(nframes): + dcoord[ii, :, :] = dcoord[ii, :, :] - np.tile(dcoord[ii, 0, :], [self.natoms[0], 1]) + dcoord = dcoord.reshape([nframes, -1]) + one_box = np.eye(3).reshape([1, 9]) + dbox = np.tile(one_box, [nframes, 1]) + one_type = [] + for ii in range(2, 2+self.ntypes): + one_type = one_type + [ii-2 for jj in range(self.natoms[ii])] + np.random.shuffle(one_type) + one_type = np.array(one_type, dtype = int).reshape([1,-1]) + dtype = np.tile(one_type, [nframes, 1]) + defield = np.random.random(dcoord.shape) + return dcoord, dbox, dtype, defield + + def rotate_mat(self, axis_, theta): + axis = axis_ / np.linalg.norm(axis_) + onemcc = (1. - np.cos(theta)) + cc = np.cos(theta) + ss = np.sin(theta) + r = [ + cc + axis[0]**2 * onemcc, + axis[0] * axis[1] * onemcc - axis[2] * ss, + axis[0] * axis[2] * onemcc + axis[1] * ss, + axis[0] * axis[1] * onemcc + axis[2] * ss, + cc + axis[1]**2 * onemcc, + axis[1] * axis[2] * onemcc - axis[0] * ss, + axis[0] * axis[2] * onemcc - axis[1] * ss, + axis[1] * axis[2] * onemcc + axis[0] * ss, + cc + axis[2]**2 * onemcc] + return np.array(r).reshape(3, 3) + + def test_rot_axis(self, suffix=''): + suffix = '_axis' + t_p_e, t_p_f, t_p_f, t_p_ae, t_p_av \ + = self.build_efv (self.coord, self.box, self.type, self.tnatoms, name = "test_rot" + suffix, op = op_module.descrpt_se_a_ef_para) + t_v_e, t_v_f, t_v_f, t_v_ae, t_v_av \ + = self.build_efv (self.coord, self.box, self.type, self.tnatoms, name = "test_rot" + suffix, op = op_module.descrpt_se_a_ef_vert, reuse = True) + t_e, t_f, t_f, t_ae, t_av \ + = self.build_efv (self.coord, self.box, self.type, self.tnatoms, name = "test_rot" + suffix, op = op_module.descrpt_se_a, reuse = True) + self.sess.run (tf.global_variables_initializer()) + + np.random.seed(0) + # make test data + nframes = 2 + dcoord, dbox, dtype, defield = self.make_test_data(nframes) + [p_ae0] = self.sess.run ([t_p_ae], + feed_dict = { + self.coord: dcoord, + self.box: dbox, + self.type: dtype, + self.efield: defield, + self.tnatoms: self.natoms}) + [v_ae0] = self.sess.run ([t_v_ae], + feed_dict = { + self.coord: dcoord, + self.box: dbox, + self.type: dtype, + self.efield: defield, + self.tnatoms: self.natoms}) + [ae0] = self.sess.run ([t_ae], + feed_dict = { + self.coord: dcoord, + self.box: dbox, + self.type: dtype, + self.efield: defield, + self.tnatoms: self.natoms}) + # print(p_ae0) + # print(v_ae0) + # print(ae0) + + for kk in range(0, self.natoms[0]): + # print(f0) + theta = 45. / 180. * np.pi + rr0 = self.rotate_mat(defield[0][kk*3:kk*3+3], theta) + # rr0 = self.rotate_mat([0, 0, 1], theta) + rr1 = self.rotate_mat(defield[1][kk*3:kk*3+3], theta) + # print(rr0, np.matmul(rr0, rr0.T), np.matmul(rr0.T, rr0)) + # print(rr1) + dcoord_ = np.copy(dcoord).reshape([nframes, -1, 3]) + dcoord0 = np.matmul(dcoord_[0], rr0) + dcoord1 = np.matmul(dcoord_[1], rr1) + new_dcoord = np.concatenate([dcoord0, dcoord1], axis = 0).reshape([nframes, -1]) + defield_ = np.copy(defield).reshape([nframes, -1, 3]) + defield0 = np.matmul(defield_[0], rr0) + defield1 = np.matmul(defield_[1], rr1) + new_defield = np.concatenate([defield0, defield1], axis = 0).reshape([nframes, -1]) + + [p_ae1] = self.sess.run ([t_p_ae], + feed_dict = { + self.coord: new_dcoord, + self.box: dbox, + self.type: dtype, + self.efield: defield, + self.tnatoms: self.natoms}) + [v_ae1] = self.sess.run ([t_v_ae], + feed_dict = { + self.coord: new_dcoord, + self.box: dbox, + self.type: dtype, + self.efield: defield, + self.tnatoms: self.natoms}) + [ae1] = self.sess.run ([t_ae], + feed_dict = { + self.coord: new_dcoord, + self.box: dbox, + self.type: dtype, + self.efield: defield, + self.tnatoms: self.natoms}) + for ii in range(0, self.natoms[0]): + for jj in range(0, self.natoms[0]): + diff = dcoord[0][3*jj:3*jj+3] - dcoord[0][3*ii:3*ii+3] + dot = np.dot(dcoord[0][3*jj:3*jj+3] , dcoord[0][3*ii:3*ii+3]) + diff1 = new_dcoord[0][3*jj:3*jj+3] - new_dcoord[0][3*ii:3*ii+3] + dot1 = np.dot(new_dcoord[0][3*jj:3*jj+3] , new_dcoord[0][3*ii:3*ii+3]) + assert(np.abs(np.linalg.norm(diff) - np.linalg.norm(diff1)) < 1e-15) + assert(np.abs(dot - dot1) < 1e-15) + + for ii in range(1, self.natoms[0]): + if ii == kk: + self.assertAlmostEqual(p_ae0[ii], p_ae1[ii]) + self.assertAlmostEqual(v_ae0[ii], v_ae1[ii]) + else: + self.assertNotAlmostEqual(p_ae0[ii], p_ae1[ii]) + self.assertNotAlmostEqual(v_ae0[ii], v_ae1[ii]) + + + def test_rot_diff_axis(self, suffix=''): + suffix = '_diff_axis' + t_p_e, t_p_f, t_p_f, t_p_ae, t_p_av \ + = self.build_efv (self.coord, self.box, self.type, self.tnatoms, name = "test_rot" + suffix, op = op_module.descrpt_se_a_ef_para) + t_v_e, t_v_f, t_v_f, t_v_ae, t_v_av \ + = self.build_efv (self.coord, self.box, self.type, self.tnatoms, name = "test_rot" + suffix, op = op_module.descrpt_se_a_ef_vert, reuse = True) + t_e, t_f, t_f, t_ae, t_av \ + = self.build_efv (self.coord, self.box, self.type, self.tnatoms, name = "test_rot" + suffix, op = op_module.descrpt_se_a, reuse = True) + self.sess.run (tf.global_variables_initializer()) + + np.random.seed(0) + # make test data + nframes = 2 + dcoord, dbox, dtype, defield = self.make_test_data(nframes) + [p_ae0] = self.sess.run ([t_p_ae], + feed_dict = { + self.coord: dcoord, + self.box: dbox, + self.type: dtype, + self.efield: defield, + self.tnatoms: self.natoms}) + [v_ae0] = self.sess.run ([t_v_ae], + feed_dict = { + self.coord: dcoord, + self.box: dbox, + self.type: dtype, + self.efield: defield, + self.tnatoms: self.natoms}) + [ae0] = self.sess.run ([t_ae], + feed_dict = { + self.coord: dcoord, + self.box: dbox, + self.type: dtype, + self.efield: defield, + self.tnatoms: self.natoms}) + + # print(f0) + theta = 45. / 180. * np.pi + rr0 = self.rotate_mat([0, 0, 1], theta) + rr1 = self.rotate_mat([1, 0, 0], theta) + dcoord_ = np.copy(dcoord).reshape([nframes, -1, 3]) + dcoord0 = np.matmul(dcoord_[0], rr0) + dcoord1 = np.matmul(dcoord_[1], rr1) + new_dcoord = np.concatenate([dcoord0, dcoord1], axis = 0).reshape([nframes, -1]) + defield_ = np.copy(defield).reshape([nframes, -1, 3]) + defield0 = np.matmul(defield_[0], rr0) + defield1 = np.matmul(defield_[1], rr1) + new_defield = np.concatenate([defield0, defield1], axis = 0).reshape([nframes, -1]) + + [p_ae1] = self.sess.run ([t_p_ae], + feed_dict = { + self.coord: new_dcoord, + self.box: dbox, + self.type: dtype, + self.efield: defield, + self.tnatoms: self.natoms}) + [v_ae1] = self.sess.run ([t_v_ae], + feed_dict = { + self.coord: new_dcoord, + self.box: dbox, + self.type: dtype, + self.efield: defield, + self.tnatoms: self.natoms}) + [ae1] = self.sess.run ([t_ae], + feed_dict = { + self.coord: new_dcoord, + self.box: dbox, + self.type: dtype, + self.efield: defield, + self.tnatoms: self.natoms}) + + for ii in range(0, self.natoms[0]): + self.assertNotAlmostEqual(p_ae0[ii], p_ae1[ii]) + self.assertNotAlmostEqual(v_ae0[ii], v_ae1[ii]) + + def test_rot_field_corot(self, suffix=''): + suffix = '_field_corot' + t_p_e, t_p_f, t_p_f, t_p_ae, t_p_av \ + = self.build_efv (self.coord, self.box, self.type, self.tnatoms, name = "test_rot" + suffix, op = op_module.descrpt_se_a_ef_para) + t_v_e, t_v_f, t_v_f, t_v_ae, t_v_av \ + = self.build_efv (self.coord, self.box, self.type, self.tnatoms, name = "test_rot" + suffix, op = op_module.descrpt_se_a_ef_vert, reuse = True) + t_e, t_f, t_f, t_ae, t_av \ + = self.build_efv (self.coord, self.box, self.type, self.tnatoms, name = "test_rot" + suffix, op = op_module.descrpt_se_a, reuse = True) + self.sess.run (tf.global_variables_initializer()) + + np.random.seed(0) + # make test data + nframes = 2 + dcoord, dbox, dtype, defield = self.make_test_data(nframes) + [p_ae0] = self.sess.run ([t_p_ae], + feed_dict = { + self.coord: dcoord, + self.box: dbox, + self.type: dtype, + self.efield: defield, + self.tnatoms: self.natoms}) + [v_ae0] = self.sess.run ([t_v_ae], + feed_dict = { + self.coord: dcoord, + self.box: dbox, + self.type: dtype, + self.efield: defield, + self.tnatoms: self.natoms}) + [ae0] = self.sess.run ([t_ae], + feed_dict = { + self.coord: dcoord, + self.box: dbox, + self.type: dtype, + self.efield: defield, + self.tnatoms: self.natoms}) + + # print(f0) + theta = 45. / 180. * np.pi + rr0 = self.rotate_mat(defield[0][0:3], theta) + rr1 = self.rotate_mat(defield[1][0:3], theta) + dcoord_ = np.copy(dcoord).reshape([nframes, -1, 3]) + dcoord0 = np.matmul(dcoord_[0], rr0) + dcoord1 = np.matmul(dcoord_[1], rr1) + new_dcoord = np.concatenate([dcoord0, dcoord1], axis = 0).reshape([nframes, -1]) + defield_ = np.copy(defield).reshape([nframes, -1, 3]) + defield0 = np.matmul(defield_[0], rr0) + defield1 = np.matmul(defield_[1], rr1) + new_defield = np.concatenate([defield0, defield1], axis = 0).reshape([nframes, -1]) + + [p_ae1] = self.sess.run ([t_p_ae], + feed_dict = { + self.coord: new_dcoord, + self.box: dbox, + self.type: dtype, + self.efield: new_defield, + self.tnatoms: self.natoms}) + [v_ae1] = self.sess.run ([t_v_ae], + feed_dict = { + self.coord: new_dcoord, + self.box: dbox, + self.type: dtype, + self.efield: new_defield, + self.tnatoms: self.natoms}) + [ae1] = self.sess.run ([t_ae], + feed_dict = { + self.coord: new_dcoord, + self.box: dbox, + self.type: dtype, + self.efield: new_defield, + self.tnatoms: self.natoms}) + + for ii in range(0, self.natoms[0]): + self.assertAlmostEqual(p_ae0[ii], p_ae1[ii]) + self.assertAlmostEqual(v_ae0[ii], v_ae1[ii]) + self.assertAlmostEqual(ae0[ii], ae1[ii]) + + + +if __name__ == '__main__': + unittest.main() From afef04a910cfd98ea4cc6157095e3548b2349074 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 11 Mar 2020 06:32:02 +0800 Subject: [PATCH 006/562] fix bug --- source/train/Fitting.py | 1 - 1 file changed, 1 deletion(-) diff --git a/source/train/Fitting.py b/source/train/Fitting.py index 7b3faa911b..9462f6266b 100644 --- a/source/train/Fitting.py +++ b/source/train/Fitting.py @@ -21,7 +21,6 @@ def __init__ (self, jdata, descrpt): .add('neuron', list, default = [120,120,120], alias = 'n_neuron')\ .add('resnet_dt', bool, default = True)\ .add('rcond', float, default = 1e-3) \ - .add('seed', int) .add('tot_ener_zero', bool, default = False) \ .add('seed', int) \ .add('atom_ener', list, default = [])\ From f4ae7b27b22ac6eecd031286c7ad8eb4e7fe11e1 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 11 Mar 2020 07:06:55 +0800 Subject: [PATCH 007/562] fix bug of initializing base class DescrptSeA --- source/train/DescrptSeAEf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/source/train/DescrptSeAEf.py b/source/train/DescrptSeAEf.py index 287029e970..b1006f9c91 100644 --- a/source/train/DescrptSeAEf.py +++ b/source/train/DescrptSeAEf.py @@ -78,6 +78,7 @@ def prod_force_virial(self, atom_ener, natoms) : class DescrptSeAEfLower (DescrptSeA): def __init__ (self, jdata, op): + DescrptSeA.__init__(self, jdata) args = ClassArg()\ .add('sel', list, must = True) \ .add('rcut', float, default = 6.0) \ From 9128bc14a3a6de73c5b8ac03edcc373a64433af6 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 27 Mar 2020 13:58:25 +0800 Subject: [PATCH 008/562] first working version of type embedding --- source/train/DescrptSeAEbd.py | 614 ++++++++++++++++++++++++++++++++++ source/train/Network.py | 10 +- source/train/Trainer.py | 5 +- 3 files changed, 625 insertions(+), 4 deletions(-) create mode 100644 source/train/DescrptSeAEbd.py diff --git a/source/train/DescrptSeAEbd.py b/source/train/DescrptSeAEbd.py new file mode 100644 index 0000000000..65e0c3e6b6 --- /dev/null +++ b/source/train/DescrptSeAEbd.py @@ -0,0 +1,614 @@ +import numpy as np +from deepmd.env import tf +from deepmd.common import ClassArg, get_activation_func, get_precision +from deepmd.Network import one_layer +from deepmd.RunOptions import global_tf_float_precision +from deepmd.RunOptions import global_np_float_precision +from deepmd.env import op_module +from deepmd.env import default_tf_session_config + +class DescrptSeAEbd (): + def __init__ (self, jdata): + args = ClassArg()\ + .add('sel', list, must = True) \ + .add('rcut', float, default = 6.0) \ + .add('rcut_smth', float, default = 5.5) \ + .add('neuron', list, default = [10, 20, 40]) \ + .add('axis_neuron', int, default = 4, alias = 'n_axis_neuron') \ + .add('type_nchanl', int, default = 4) \ + .add('type_nlayer', int, default = 2) \ + .add('resnet_dt', bool, default = False) \ + .add('trainable', bool, default = True) \ + .add('seed', int) \ + .add('exclude_types', list, default = []) \ + .add('set_davg_zero', bool, default = False) \ + .add('activation_function', str, default = 'tanh') \ + .add('precision', str, default = "default") + class_data = args.parse(jdata) + self.sel_a = class_data['sel'] + self.rcut_r = class_data['rcut'] + self.rcut_r_smth = class_data['rcut_smth'] + self.filter_neuron = class_data['neuron'] + self.n_axis_neuron = class_data['axis_neuron'] + self.filter_resnet_dt = class_data['resnet_dt'] + self.seed = class_data['seed'] + self.type_nchanl = class_data['type_nchanl'] + self.type_nlayer = class_data['type_nlayer'] + self.trainable = class_data['trainable'] + self.filter_activation_fn = get_activation_func(class_data['activation_function']) + self.filter_precision = get_precision(class_data['precision']) + exclude_types = class_data['exclude_types'] + self.exclude_types = set() + for tt in exclude_types: + assert(len(tt) == 2) + self.exclude_types.add((tt[0], tt[1])) + self.exclude_types.add((tt[1], tt[0])) + self.set_davg_zero = class_data['set_davg_zero'] + + # descrpt config + self.sel_r = [ 0 for ii in range(len(self.sel_a)) ] + self.ntypes = len(self.sel_a) + assert(self.ntypes == len(self.sel_r)) + self.rcut_a = -1 + # numb of neighbors and numb of descrptors + self.nnei_a = np.cumsum(self.sel_a)[-1] + self.nnei_r = np.cumsum(self.sel_r)[-1] + self.nnei = self.nnei_a + self.nnei_r + self.ndescrpt_a = self.nnei_a * 4 + self.ndescrpt_r = self.nnei_r * 1 + self.ndescrpt = self.ndescrpt_a + self.ndescrpt_r + self.useBN = False + self.dstd = None + self.davg = None + + self.place_holders = {} + avg_zero = np.zeros([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) + std_ones = np.ones ([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) + sub_graph = tf.Graph() + with sub_graph.as_default(): + name_pfx = 'd_sea_' + for ii in ['coord', 'box']: + self.place_holders[ii] = tf.placeholder(global_np_float_precision, [None, None], name = name_pfx+'t_'+ii) + self.place_holders['type'] = tf.placeholder(tf.int32, [None, None], name=name_pfx+'t_type') + self.place_holders['natoms_vec'] = tf.placeholder(tf.int32, [self.ntypes+2], name=name_pfx+'t_natoms') + self.place_holders['default_mesh'] = tf.placeholder(tf.int32, [None], name=name_pfx+'t_mesh') + self.stat_descrpt, descrpt_deriv, rij, nlist \ + = op_module.descrpt_se_a(self.place_holders['coord'], + self.place_holders['type'], + self.place_holders['natoms_vec'], + self.place_holders['box'], + self.place_holders['default_mesh'], + tf.constant(avg_zero), + tf.constant(std_ones), + rcut_a = self.rcut_a, + rcut_r = self.rcut_r, + rcut_r_smth = self.rcut_r_smth, + sel_a = self.sel_a, + sel_r = self.sel_r) + self.sub_sess = tf.Session(graph = sub_graph, config=default_tf_session_config) + + + def get_rcut (self) : + return self.rcut_r + + def get_ntypes (self) : + return self.ntypes + + def get_dim_out (self) : + return self.filter_neuron[-1] * self.n_axis_neuron + + def get_dim_rot_mat_1 (self) : + return self.filter_neuron[-1] + + def get_nlist (self) : + return self.nlist, self.rij, self.sel_a, self.sel_r + + def compute_input_stats (self, + data_coord, + data_box, + data_atype, + natoms_vec, + mesh) : + all_davg = [] + all_dstd = [] + if True: + sumr = [] + suma = [] + sumn = [] + sumr2 = [] + suma2 = [] + for cc,bb,tt,nn,mm in zip(data_coord,data_box,data_atype,natoms_vec,mesh) : + sysr,sysr2,sysa,sysa2,sysn \ + = self._compute_dstats_sys_smth(cc,bb,tt,nn,mm) + sumr.append(sysr) + suma.append(sysa) + sumn.append(sysn) + sumr2.append(sysr2) + suma2.append(sysa2) + sumr = np.sum(sumr, axis = 0) + suma = np.sum(suma, axis = 0) + sumn = np.sum(sumn, axis = 0) + sumr2 = np.sum(sumr2, axis = 0) + suma2 = np.sum(suma2, axis = 0) + for type_i in range(self.ntypes) : + davgunit = [sumr[type_i]/sumn[type_i], 0, 0, 0] + dstdunit = [self._compute_std(sumr2[type_i], sumr[type_i], sumn[type_i]), + self._compute_std(suma2[type_i], suma[type_i], sumn[type_i]), + self._compute_std(suma2[type_i], suma[type_i], sumn[type_i]), + self._compute_std(suma2[type_i], suma[type_i], sumn[type_i]) + ] + davg = np.tile(davgunit, self.ndescrpt // 4) + dstd = np.tile(dstdunit, self.ndescrpt // 4) + all_davg.append(davg) + all_dstd.append(dstd) + + if not self.set_davg_zero: + self.davg = np.array(all_davg) + self.dstd = np.array(all_dstd) + + + def build (self, + coord_, + atype_, + natoms, + box_, + mesh, + suffix = '', + reuse = None): + davg = self.davg + dstd = self.dstd + with tf.variable_scope('descrpt_attr' + suffix, reuse = reuse) : + if davg is None: + davg = np.zeros([self.ntypes, self.ndescrpt]) + if dstd is None: + dstd = np.ones ([self.ntypes, self.ndescrpt]) + t_rcut = tf.constant(np.max([self.rcut_r, self.rcut_a]), + name = 'rcut', + dtype = global_tf_float_precision) + t_ntypes = tf.constant(self.ntypes, + name = 'ntypes', + dtype = tf.int32) + t_ndescrpt = tf.constant(self.ndescrpt, + name = 'ndescrpt', + dtype = tf.int32) + t_sel = tf.constant(self.sel_a, + name = 'sel', + dtype = tf.int32) + self.t_avg = tf.get_variable('t_avg', + davg.shape, + dtype = global_tf_float_precision, + trainable = False, + initializer = tf.constant_initializer(davg)) + self.t_std = tf.get_variable('t_std', + dstd.shape, + dtype = global_tf_float_precision, + trainable = False, + initializer = tf.constant_initializer(dstd)) + + nei_type = np.array([]) + for ii in range(self.ntypes): + nei_type = np.append(nei_type, ii * np.ones(self.sel_a[ii])) + self.nei_type = tf.get_variable('t_nei_type', + [self.nnei], + dtype = global_tf_float_precision, + trainable = False, + initializer = tf.constant_initializer(nei_type)) + + coord = tf.reshape (coord_, [-1, natoms[1] * 3]) + box = tf.reshape (box_, [-1, 9]) + atype = tf.reshape (atype_, [-1, natoms[1]]) + + self.descrpt, self.descrpt_deriv, self.rij, self.nlist \ + = op_module.descrpt_se_a (coord, + atype, + natoms, + box, + mesh, + self.t_avg, + self.t_std, + rcut_a = self.rcut_a, + rcut_r = self.rcut_r, + rcut_r_smth = self.rcut_r_smth, + sel_a = self.sel_a, + sel_r = self.sel_r) + + self.descrpt_reshape = tf.reshape(self.descrpt, [-1, self.ndescrpt]) + self.descrpt_reshape = tf.identity(self.descrpt_reshape, name = 'o_rmat') + self.descrpt_deriv = tf.identity(self.descrpt_deriv, name = 'o_rmat_deriv') + self.rij = tf.identity(self.rij, name = 'o_rij') + self.nlist = tf.identity(self.nlist, name = 'o_nlist') + + self.dout, self.qmat = self._pass_filter(self.descrpt_reshape, + atype, + natoms, + suffix = suffix, + reuse = reuse, + trainable = self.trainable) + + return self.dout + + + def get_rot_mat(self) : + return self.qmat + + + def prod_force_virial(self, atom_ener, natoms) : + [net_deriv] = tf.gradients (atom_ener, self.descrpt_reshape) + net_deriv_reshape = tf.reshape (net_deriv, [-1, natoms[0] * self.ndescrpt]) + force \ + = op_module.prod_force_se_a (net_deriv_reshape, + self.descrpt_deriv, + self.nlist, + natoms, + n_a_sel = self.nnei_a, + n_r_sel = self.nnei_r) + virial, atom_virial \ + = op_module.prod_virial_se_a (net_deriv_reshape, + self.descrpt_deriv, + self.rij, + self.nlist, + natoms, + n_a_sel = self.nnei_a, + n_r_sel = self.nnei_r) + return force, virial, atom_virial + + + def _type_embed(self, + atype, + reuse = None, + suffix = '', + trainable = True): + ebd_type = tf.cast(atype, self.filter_precision) + ebd_type = tf.reshape(ebd_type, [-1, 1]) + for ii in range(self.type_nlayer): + name = 'type_embed_layer_' + str(ii) + ebd_type = one_layer(ebd_type, + self.type_nchanl, + activation_fn = self.filter_activation_fn, + precision = self.filter_precision, + name = name, + reuse = reuse, + seed = self.seed + ii, + trainable = trainable) + name = 'type_embed_layer_' + str(self.type_nlayer) + ebd_type = one_layer(ebd_type, + self.type_nchanl, + activation_fn = None, + precision = self.filter_precision, + name = name, + reuse = reuse, + seed = self.seed + ii, + trainable = trainable) + ebd_type = tf.reshape(ebd_type, [-1, self.type_nchanl]) + return ebd_type + + + def _pass_filter(self, + inputs, + atype, + natoms, + reuse = None, + suffix = '', + trainable = True) : + start_index = 0 + # nf x na x ndescrpt + # nf x na x (nnei x 4) + inputs = tf.reshape(inputs, [-1, natoms[0], self.ndescrpt]) + layer, qmat = self._filter(tf.cast(inputs, self.filter_precision), + atype, + natoms, + name='filter_type_all'+suffix, + reuse=reuse, + seed = self.seed, + trainable = trainable, + activation_fn = self.filter_activation_fn) + output = tf.reshape(layer, [tf.shape(inputs)[0], natoms[0] * self.get_dim_out()]) + output_qmat = tf.reshape(qmat, [tf.shape(inputs)[0], natoms[0] * self.get_dim_rot_mat_1() * 3]) + return output, output_qmat + + + def _compute_dstats_sys_smth (self, + data_coord, + data_box, + data_atype, + natoms_vec, + mesh) : + dd_all \ + = self.sub_sess.run(self.stat_descrpt, + feed_dict = { + self.place_holders['coord']: data_coord, + self.place_holders['type']: data_atype, + self.place_holders['natoms_vec']: natoms_vec, + self.place_holders['box']: data_box, + self.place_holders['default_mesh']: mesh, + }) + natoms = natoms_vec + dd_all = np.reshape(dd_all, [-1, self.ndescrpt * natoms[0]]) + start_index = 0 + sysr = [] + sysa = [] + sysn = [] + sysr2 = [] + sysa2 = [] + for type_i in range(self.ntypes): + end_index = start_index + self.ndescrpt * natoms[2+type_i] + dd = dd_all[:, start_index:end_index] + dd = np.reshape(dd, [-1, self.ndescrpt]) + start_index = end_index + # compute + dd = np.reshape (dd, [-1, 4]) + ddr = dd[:,:1] + dda = dd[:,1:] + sumr = np.sum(ddr) + suma = np.sum(dda) / 3. + sumn = dd.shape[0] + sumr2 = np.sum(np.multiply(ddr, ddr)) + suma2 = np.sum(np.multiply(dda, dda)) / 3. + sysr.append(sumr) + sysa.append(suma) + sysn.append(sumn) + sysr2.append(sumr2) + sysa2.append(suma2) + return sysr, sysr2, sysa, sysa2, sysn + + + def _compute_std (self,sumv2, sumv, sumn) : + val = np.sqrt(sumv2/sumn - np.multiply(sumv/sumn, sumv/sumn)) + if np.abs(val) < 1e-2: + val = 1e-2 + return val + + + def _embedding_net(self, + inputs, + natoms, + activation_fn=tf.nn.tanh, + stddev=1.0, + bavg=0.0, + name='linear', + reuse=None, + seed=None, + trainable = True): + # natom x (nei x 4) + inputs = tf.reshape(inputs, [-1, self.ndescrpt]) + shape = inputs.get_shape().as_list() + outputs_size = [1] + self.filter_neuron + outputs_size_2 = self.n_axis_neuron + with tf.variable_scope(name, reuse=reuse): + start_index = 0 + xyz_scatter_total = [] + # with natom x (nei x 4) + inputs_i = inputs + shape_i = inputs_i.get_shape().as_list() + # with (natom x nei) x 4 + inputs_reshape = tf.reshape(inputs_i, [-1, 4]) + xyz_scatter = tf.reshape(tf.slice(inputs_reshape, [0,0],[-1,1]),[-1,1]) + for ii in range(1, len(outputs_size)): + w = tf.get_variable('matrix_'+str(ii), + [outputs_size[ii - 1], outputs_size[ii]], + self.filter_precision, + tf.random_normal_initializer(stddev=stddev/np.sqrt(outputs_size[ii]+outputs_size[ii-1]), seed = seed), + trainable = trainable) + b = tf.get_variable('bias_'+str(ii), + [1, outputs_size[ii]], + self.filter_precision, + tf.random_normal_initializer(stddev=stddev, mean = bavg, seed = seed), + trainable = trainable) + if self.filter_resnet_dt : + idt = tf.get_variable('idt_'+str(ii), + [1, outputs_size[ii]], + self.filter_precision, + tf.random_normal_initializer(stddev=0.001, mean = 1.0, seed = seed), + trainable = trainable) + if outputs_size[ii] == outputs_size[ii-1]: + if self.filter_resnet_dt : + xyz_scatter += activation_fn(tf.matmul(xyz_scatter, w) + b) * idt + else : + xyz_scatter += activation_fn(tf.matmul(xyz_scatter, w) + b) + elif outputs_size[ii] == outputs_size[ii-1] * 2: + if self.filter_resnet_dt : + xyz_scatter = tf.concat([xyz_scatter,xyz_scatter], 1) + activation_fn(tf.matmul(xyz_scatter, w) + b) * idt + else : + xyz_scatter = tf.concat([xyz_scatter,xyz_scatter], 1) + activation_fn(tf.matmul(xyz_scatter, w) + b) + else: + xyz_scatter = activation_fn(tf.matmul(xyz_scatter, w) + b) + # natom x nei x out_size + xyz_scatter = tf.reshape(xyz_scatter, (-1, shape_i[1]//4, outputs_size[-1])) + xyz_scatter_total.append(xyz_scatter) + # natom x nei x outputs_size + xyz_scatter = tf.concat(xyz_scatter_total, axis=1) + # nf x natom x nei x outputs_size + xyz_scatter = tf.reshape(xyz_scatter, [tf.shape(inputs)[0], natoms[0], self.nnei, outputs_size[-1]]) + return xyz_scatter + + + def _filter(self, + inputs, + atype, + natoms, + activation_fn=tf.nn.tanh, + stddev=1.0, + bavg=0.0, + name='linear', + reuse=None, + seed=None, + trainable = True): + outputs_size = self.filter_neuron[-1] + outputs_size_2 = self.n_axis_neuron + # nf x natom x (nei x 4) + nframes = tf.shape(inputs)[0] + shape = tf.reshape(inputs, [-1, self.ndescrpt]).get_shape().as_list() + # (nf x natom) x nei x outputs_size + mat_g = self._embedding_net(inputs, + natoms, + activation_fn = activation_fn, + stddev = stddev, + bavg = bavg, + name = name, + reuse = reuse, + seed = seed, + trainable = trainable) + # (nf x natom x nei) x outputs_size + mat_g = tf.reshape(mat_g, [nframes * natoms[0] * self.nnei, outputs_size]) + # (nf x natom x nei) x (outputs_size x chnl x chnl) + mat_g = one_layer(mat_g, + outputs_size * self.type_nchanl * self.type_nchanl, + activation_fn = None, + precision = self.filter_precision, + name = name, + reuse = reuse, + seed = self.seed, + trainable = trainable) + # nf x natom x nei x outputs_size x chnl x chnl + mat_g = tf.reshape(mat_g, [nframes, natoms[0], self.nnei, outputs_size, self.type_nchanl, self.type_nchanl]) + # nf x natom x outputs_size x chnl x nei x chnl + mat_g = tf.transpose(mat_g, perm = [0, 1, 3, 4, 2, 5]) + # nf x natom x outputs_size x chnl x (nei x chnl) + mat_g = tf.reshape(mat_g, [nframes, natoms[0], outputs_size, self.type_nchanl, self.nnei * self.type_nchanl]) + + # nei x nchnl + ebd_nei_type = self._type_embed(self.nei_type, + reuse = reuse, + trainable = True, + suffix = '') + # (nei x nchnl) + ebd_nei_type = tf.reshape(ebd_nei_type, [self.nnei * self.type_nchanl]) + # (nframes x natom) x nchnl + ebd_atm_type = self._type_embed(atype, + reuse = True, + trainable = True, + suffix = '') + # (nframes x natom x nchnl) + ebd_atm_type = tf.reshape(ebd_atm_type, [nframes * natoms[0] * self.type_nchanl]) + + # nf x natom x outputs_size x chnl x (nei x chnl) + mat_g = tf.multiply(mat_g, ebd_nei_type) + # nf x natom x outputs_size x chnl x nei x chnl + mat_g = tf.reshape(mat_g, [nframes, natoms[0], outputs_size, self.type_nchanl, self.nnei, self.type_nchanl]) + # nf x natom x outputs_size x chnl x nei + mat_g = tf.reduce_mean(mat_g, axis = 5) + # outputs_size x nei x nf x natom x chnl + mat_g = tf.transpose(mat_g, perm = [2, 4, 0, 1, 3]) + # outputs_size x nei x (nf x natom x chnl) + mat_g = tf.reshape(mat_g, [outputs_size, self.nnei, nframes * natoms[0] * self.type_nchanl]) + # outputs_size x nei x (nf x natom x chnl) + mat_g = tf.multiply(mat_g, ebd_atm_type) + # outputs_size x nei x nf x natom x chnl + mat_g = tf.reshape(mat_g, [outputs_size, self.nnei, nframes, natoms[0], self.type_nchanl]) + # outputs_size x nei x nf x natom + mat_g = tf.reduce_mean(mat_g, axis = 4) + # nf x natom x nei x outputs_size + mat_g = tf.transpose(mat_g, perm = [2, 3, 1, 0]) + # (nf x natom) x nei x outputs_size + mat_g = tf.reshape(mat_g, [nframes * natoms[0], self.nnei, outputs_size]) + xyz_scatter = mat_g + + # natom x nei x 4 + inputs_reshape = tf.reshape(inputs, [-1, shape[1]//4, 4]) + # natom x 4 x outputs_size + xyz_scatter_1 = tf.matmul(inputs_reshape, xyz_scatter, transpose_a = True) + xyz_scatter_1 = xyz_scatter_1 * (4.0 / shape[1]) + # natom x 4 x outputs_size_2 + xyz_scatter_2 = tf.slice(xyz_scatter_1, [0,0,0],[-1,-1,outputs_size_2]) + # # natom x 3 x outputs_size_2 + # qmat = tf.slice(xyz_scatter_2, [0,1,0], [-1, 3, -1]) + # natom x 3 x outputs_size_1 + qmat = tf.slice(xyz_scatter_1, [0,1,0], [-1, 3, -1]) + # natom x outputs_size_2 x 3 + qmat = tf.transpose(qmat, perm = [0, 2, 1]) + # natom x outputs_size x outputs_size_2 + result = tf.matmul(xyz_scatter_1, xyz_scatter_2, transpose_a = True) + # natom x (outputs_size x outputs_size_2) + result = tf.reshape(result, [-1, outputs_size_2 * outputs_size]) + + return result, qmat + + def _filter_type_ext(self, + inputs, + natoms, + activation_fn=tf.nn.tanh, + stddev=1.0, + bavg=0.0, + name='linear', + reuse=None, + seed=None, + trainable = True): + # natom x (nei x 4) + outputs_size = [1] + self.filter_neuron + outputs_size_2 = self.n_axis_neuron + with tf.variable_scope(name, reuse=reuse): + start_index = 0 + result_all = [] + xyz_scatter_1_all = [] + xyz_scatter_2_all = [] + for type_i in range(self.ntypes): + # cut-out inputs + # with natom x (nei_type_i x 4) + inputs_i = tf.slice (inputs, + [ 0, start_index* 4], + [-1, self.sel_a[type_i]* 4] ) + start_index += self.sel_a[type_i] + shape_i = inputs_i.get_shape().as_list() + # with (natom x nei_type_i) x 4 + inputs_reshape = tf.reshape(inputs_i, [-1, 4]) + xyz_scatter = tf.reshape(tf.slice(inputs_reshape, [0,0],[-1,1]),[-1,1]) + for ii in range(1, len(outputs_size)): + w = tf.get_variable('matrix_'+str(ii)+'_'+str(type_i), + [outputs_size[ii - 1], outputs_size[ii]], + self.filter_precision, + tf.random_normal_initializer(stddev=stddev/np.sqrt(outputs_size[ii]+outputs_size[ii-1]), seed = seed), + trainable = trainable) + b = tf.get_variable('bias_'+str(ii)+'_'+str(type_i), + [1, outputs_size[ii]], + self.filter_precision, + tf.random_normal_initializer(stddev=stddev, mean = bavg, seed = seed), + trainable = trainable) + if self.filter_resnet_dt : + idt = tf.get_variable('idt_'+str(ii)+'_'+str(type_i), + [1, outputs_size[ii]], + self.filter_precision, + tf.random_normal_initializer(stddev=0.001, mean = 1.0, seed = seed), + trainable = trainable) + if outputs_size[ii] == outputs_size[ii-1]: + if self.filter_resnet_dt : + xyz_scatter += activation_fn(tf.matmul(xyz_scatter, w) + b) * idt + else : + xyz_scatter += activation_fn(tf.matmul(xyz_scatter, w) + b) + elif outputs_size[ii] == outputs_size[ii-1] * 2: + if self.filter_resnet_dt : + xyz_scatter = tf.concat([xyz_scatter,xyz_scatter], 1) + activation_fn(tf.matmul(xyz_scatter, w) + b) * idt + else : + xyz_scatter = tf.concat([xyz_scatter,xyz_scatter], 1) + activation_fn(tf.matmul(xyz_scatter, w) + b) + else: + xyz_scatter = activation_fn(tf.matmul(xyz_scatter, w) + b) + # natom x nei_type_i x out_size + xyz_scatter = tf.reshape(xyz_scatter, (-1, shape_i[1]//4, outputs_size[-1])) + # natom x nei_type_i x 4 + inputs_i_reshape = tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]) + # natom x 4 x outputs_size + xyz_scatter_1 = tf.matmul(inputs_i_reshape, xyz_scatter, transpose_a = True) + xyz_scatter_1 = xyz_scatter_1 * (4.0 / shape_i[1]) + # natom x 4 x outputs_size_2 + xyz_scatter_2 = tf.slice(xyz_scatter_1, [0,0,0],[-1,-1,outputs_size_2]) + xyz_scatter_1_all.append(xyz_scatter_1) + xyz_scatter_2_all.append(xyz_scatter_2) + + # for type_i in range(self.ntypes): + # for type_j in range(type_i, self.ntypes): + # # natom x outputs_size x outputs_size_2 + # result = tf.matmul(xyz_scatter_1_all[type_i], xyz_scatter_2_all[type_j], transpose_a = True) + # # natom x (outputs_size x outputs_size_2) + # result = tf.reshape(result, [-1, outputs_size_2 * outputs_size[-1]]) + # result_all.append(tf.identity(result)) + xyz_scatter_2_coll = tf.concat(xyz_scatter_2_all, axis = 2) + for type_i in range(self.ntypes) : + # natom x outputs_size x (outputs_size_2 x ntypes) + result = tf.matmul(xyz_scatter_1_all[type_i], xyz_scatter_2_coll, transpose_a = True) + # natom x (outputs_size x outputs_size_2 x ntypes) + result = tf.reshape(result, [-1, outputs_size_2 * self.ntypes * outputs_size[-1]]) + result_all.append(tf.identity(result)) + + # natom x (ntypes x outputs_size x outputs_size_2 x ntypes) + result_all = tf.concat(result_all, axis = 1) + + return result_all diff --git a/source/train/Network.py b/source/train/Network.py index fb87075942..ed188c085d 100644 --- a/source/train/Network.py +++ b/source/train/Network.py @@ -13,23 +13,27 @@ def one_layer(inputs, reuse=None, seed=None, use_timestep = False, + trainable = True, useBN = False): with tf.variable_scope(name, reuse=reuse): shape = inputs.get_shape().as_list() w = tf.get_variable('matrix', [shape[1], outputs_size], precision, - tf.random_normal_initializer(stddev=stddev/np.sqrt(shape[1]+outputs_size), seed = seed)) + tf.random_normal_initializer(stddev=stddev/np.sqrt(shape[1]+outputs_size), seed = seed), + trainable = trainable) b = tf.get_variable('bias', [outputs_size], precision, - tf.random_normal_initializer(stddev=stddev, mean = bavg, seed = seed)) + tf.random_normal_initializer(stddev=stddev, mean = bavg, seed = seed), + trainable = trainable) hidden = tf.matmul(inputs, w) + b if activation_fn != None and use_timestep : idt = tf.get_variable('idt', [outputs_size], precision, - tf.random_normal_initializer(stddev=0.001, mean = 0.1, seed = seed)) + tf.random_normal_initializer(stddev=0.001, mean = 0.1, seed = seed), + trainable = trainable) if activation_fn != None: if useBN: None diff --git a/source/train/Trainer.py b/source/train/Trainer.py index 50db1adfbc..af1d6a9888 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -10,6 +10,7 @@ from deepmd.Fitting import EnerFitting, WFCFitting, PolarFittingLocFrame, PolarFittingSeA, GlobalPolarFittingSeA, DipoleFittingSeA from deepmd.DescrptLocFrame import DescrptLocFrame from deepmd.DescrptSeA import DescrptSeA +from deepmd.DescrptSeAEbd import DescrptSeAEbd from deepmd.DescrptSeR import DescrptSeR from deepmd.DescrptSeAR import DescrptSeAR from deepmd.Model import Model, WFCModel, DipoleModel, PolarModel, GlobalPolarModel @@ -59,6 +60,8 @@ def _init_param(self, jdata): self.descrpt = DescrptLocFrame(descrpt_param) elif descrpt_type == 'se_a' : self.descrpt = DescrptSeA(descrpt_param) + elif descrpt_type == 'se_a_ebd' : + self.descrpt = DescrptSeAEbd(descrpt_param) elif descrpt_type == 'se_r' : self.descrpt = DescrptSeR(descrpt_param) elif descrpt_type == 'se_ar' : @@ -467,7 +470,7 @@ def test_on_the_fly (self, else: feed_dict_test[self.place_holders[kk]] = np.reshape(test_data[kk][:self.numb_test], [-1]) for ii in ['type'] : - feed_dict_test[self.place_holders[ii]] = np.reshape(test_data[ii][:self.numb_test], [-1]) + feed_dict_test[self.place_holders[ii]] = np.reshape(test_data[ii][:self.numb_test], [-1]) for ii in ['natoms_vec', 'default_mesh'] : feed_dict_test[self.place_holders[ii]] = test_data[ii] feed_dict_test[self.place_holders['is_training']] = False From 95c50e611b6dc9ebe287b3fc0b82f0003ecf3b7e Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 27 Mar 2020 15:09:40 +0800 Subject: [PATCH 009/562] simplify the implementation --- source/train/DescrptSeA.py | 8 +- source/train/DescrptSeAEbd.py | 427 +++------------------------------- 2 files changed, 45 insertions(+), 390 deletions(-) diff --git a/source/train/DescrptSeA.py b/source/train/DescrptSeA.py index d409f7134f..cafcda214e 100644 --- a/source/train/DescrptSeA.py +++ b/source/train/DescrptSeA.py @@ -204,7 +204,12 @@ def build (self, self.rij = tf.identity(self.rij, name = 'o_rij') self.nlist = tf.identity(self.nlist, name = 'o_nlist') - self.dout, self.qmat = self._pass_filter(self.descrpt_reshape, natoms, suffix = suffix, reuse = reuse, trainable = self.trainable) + self.dout, self.qmat = self._pass_filter(self.descrpt_reshape, + atype, + natoms, + suffix = suffix, + reuse = reuse, + trainable = self.trainable) return self.dout @@ -236,6 +241,7 @@ def prod_force_virial(self, atom_ener, natoms) : def _pass_filter(self, inputs, + atype, natoms, reuse = None, suffix = '', diff --git a/source/train/DescrptSeAEbd.py b/source/train/DescrptSeAEbd.py index 65e0c3e6b6..c78f2e6281 100644 --- a/source/train/DescrptSeAEbd.py +++ b/source/train/DescrptSeAEbd.py @@ -6,145 +6,17 @@ from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module from deepmd.env import default_tf_session_config +from deepmd.DescrptSeA import DescrptSeA -class DescrptSeAEbd (): +class DescrptSeAEbd (DescrptSeA): def __init__ (self, jdata): + DescrptSeA.__init__(self, jdata) args = ClassArg()\ - .add('sel', list, must = True) \ - .add('rcut', float, default = 6.0) \ - .add('rcut_smth', float, default = 5.5) \ - .add('neuron', list, default = [10, 20, 40]) \ - .add('axis_neuron', int, default = 4, alias = 'n_axis_neuron') \ .add('type_nchanl', int, default = 4) \ - .add('type_nlayer', int, default = 2) \ - .add('resnet_dt', bool, default = False) \ - .add('trainable', bool, default = True) \ - .add('seed', int) \ - .add('exclude_types', list, default = []) \ - .add('set_davg_zero', bool, default = False) \ - .add('activation_function', str, default = 'tanh') \ - .add('precision', str, default = "default") + .add('type_nlayer', int, default = 2) class_data = args.parse(jdata) - self.sel_a = class_data['sel'] - self.rcut_r = class_data['rcut'] - self.rcut_r_smth = class_data['rcut_smth'] - self.filter_neuron = class_data['neuron'] - self.n_axis_neuron = class_data['axis_neuron'] - self.filter_resnet_dt = class_data['resnet_dt'] - self.seed = class_data['seed'] self.type_nchanl = class_data['type_nchanl'] self.type_nlayer = class_data['type_nlayer'] - self.trainable = class_data['trainable'] - self.filter_activation_fn = get_activation_func(class_data['activation_function']) - self.filter_precision = get_precision(class_data['precision']) - exclude_types = class_data['exclude_types'] - self.exclude_types = set() - for tt in exclude_types: - assert(len(tt) == 2) - self.exclude_types.add((tt[0], tt[1])) - self.exclude_types.add((tt[1], tt[0])) - self.set_davg_zero = class_data['set_davg_zero'] - - # descrpt config - self.sel_r = [ 0 for ii in range(len(self.sel_a)) ] - self.ntypes = len(self.sel_a) - assert(self.ntypes == len(self.sel_r)) - self.rcut_a = -1 - # numb of neighbors and numb of descrptors - self.nnei_a = np.cumsum(self.sel_a)[-1] - self.nnei_r = np.cumsum(self.sel_r)[-1] - self.nnei = self.nnei_a + self.nnei_r - self.ndescrpt_a = self.nnei_a * 4 - self.ndescrpt_r = self.nnei_r * 1 - self.ndescrpt = self.ndescrpt_a + self.ndescrpt_r - self.useBN = False - self.dstd = None - self.davg = None - - self.place_holders = {} - avg_zero = np.zeros([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) - std_ones = np.ones ([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) - sub_graph = tf.Graph() - with sub_graph.as_default(): - name_pfx = 'd_sea_' - for ii in ['coord', 'box']: - self.place_holders[ii] = tf.placeholder(global_np_float_precision, [None, None], name = name_pfx+'t_'+ii) - self.place_holders['type'] = tf.placeholder(tf.int32, [None, None], name=name_pfx+'t_type') - self.place_holders['natoms_vec'] = tf.placeholder(tf.int32, [self.ntypes+2], name=name_pfx+'t_natoms') - self.place_holders['default_mesh'] = tf.placeholder(tf.int32, [None], name=name_pfx+'t_mesh') - self.stat_descrpt, descrpt_deriv, rij, nlist \ - = op_module.descrpt_se_a(self.place_holders['coord'], - self.place_holders['type'], - self.place_holders['natoms_vec'], - self.place_holders['box'], - self.place_holders['default_mesh'], - tf.constant(avg_zero), - tf.constant(std_ones), - rcut_a = self.rcut_a, - rcut_r = self.rcut_r, - rcut_r_smth = self.rcut_r_smth, - sel_a = self.sel_a, - sel_r = self.sel_r) - self.sub_sess = tf.Session(graph = sub_graph, config=default_tf_session_config) - - - def get_rcut (self) : - return self.rcut_r - - def get_ntypes (self) : - return self.ntypes - - def get_dim_out (self) : - return self.filter_neuron[-1] * self.n_axis_neuron - - def get_dim_rot_mat_1 (self) : - return self.filter_neuron[-1] - - def get_nlist (self) : - return self.nlist, self.rij, self.sel_a, self.sel_r - - def compute_input_stats (self, - data_coord, - data_box, - data_atype, - natoms_vec, - mesh) : - all_davg = [] - all_dstd = [] - if True: - sumr = [] - suma = [] - sumn = [] - sumr2 = [] - suma2 = [] - for cc,bb,tt,nn,mm in zip(data_coord,data_box,data_atype,natoms_vec,mesh) : - sysr,sysr2,sysa,sysa2,sysn \ - = self._compute_dstats_sys_smth(cc,bb,tt,nn,mm) - sumr.append(sysr) - suma.append(sysa) - sumn.append(sysn) - sumr2.append(sysr2) - suma2.append(sysa2) - sumr = np.sum(sumr, axis = 0) - suma = np.sum(suma, axis = 0) - sumn = np.sum(sumn, axis = 0) - sumr2 = np.sum(sumr2, axis = 0) - suma2 = np.sum(suma2, axis = 0) - for type_i in range(self.ntypes) : - davgunit = [sumr[type_i]/sumn[type_i], 0, 0, 0] - dstdunit = [self._compute_std(sumr2[type_i], sumr[type_i], sumn[type_i]), - self._compute_std(suma2[type_i], suma[type_i], sumn[type_i]), - self._compute_std(suma2[type_i], suma[type_i], sumn[type_i]), - self._compute_std(suma2[type_i], suma[type_i], sumn[type_i]) - ] - davg = np.tile(davgunit, self.ndescrpt // 4) - dstd = np.tile(dstdunit, self.ndescrpt // 4) - all_davg.append(davg) - all_dstd.append(dstd) - - if not self.set_davg_zero: - self.davg = np.array(all_davg) - self.dstd = np.array(all_dstd) def build (self, @@ -155,36 +27,6 @@ def build (self, mesh, suffix = '', reuse = None): - davg = self.davg - dstd = self.dstd - with tf.variable_scope('descrpt_attr' + suffix, reuse = reuse) : - if davg is None: - davg = np.zeros([self.ntypes, self.ndescrpt]) - if dstd is None: - dstd = np.ones ([self.ntypes, self.ndescrpt]) - t_rcut = tf.constant(np.max([self.rcut_r, self.rcut_a]), - name = 'rcut', - dtype = global_tf_float_precision) - t_ntypes = tf.constant(self.ntypes, - name = 'ntypes', - dtype = tf.int32) - t_ndescrpt = tf.constant(self.ndescrpt, - name = 'ndescrpt', - dtype = tf.int32) - t_sel = tf.constant(self.sel_a, - name = 'sel', - dtype = tf.int32) - self.t_avg = tf.get_variable('t_avg', - davg.shape, - dtype = global_tf_float_precision, - trainable = False, - initializer = tf.constant_initializer(davg)) - self.t_std = tf.get_variable('t_std', - dstd.shape, - dtype = global_tf_float_precision, - trainable = False, - initializer = tf.constant_initializer(dstd)) - nei_type = np.array([]) for ii in range(self.ntypes): nei_type = np.append(nei_type, ii * np.ones(self.sel_a[ii])) @@ -193,65 +35,10 @@ def build (self, dtype = global_tf_float_precision, trainable = False, initializer = tf.constant_initializer(nei_type)) - - coord = tf.reshape (coord_, [-1, natoms[1] * 3]) - box = tf.reshape (box_, [-1, 9]) - atype = tf.reshape (atype_, [-1, natoms[1]]) - - self.descrpt, self.descrpt_deriv, self.rij, self.nlist \ - = op_module.descrpt_se_a (coord, - atype, - natoms, - box, - mesh, - self.t_avg, - self.t_std, - rcut_a = self.rcut_a, - rcut_r = self.rcut_r, - rcut_r_smth = self.rcut_r_smth, - sel_a = self.sel_a, - sel_r = self.sel_r) - - self.descrpt_reshape = tf.reshape(self.descrpt, [-1, self.ndescrpt]) - self.descrpt_reshape = tf.identity(self.descrpt_reshape, name = 'o_rmat') - self.descrpt_deriv = tf.identity(self.descrpt_deriv, name = 'o_rmat_deriv') - self.rij = tf.identity(self.rij, name = 'o_rij') - self.nlist = tf.identity(self.nlist, name = 'o_nlist') - - self.dout, self.qmat = self._pass_filter(self.descrpt_reshape, - atype, - natoms, - suffix = suffix, - reuse = reuse, - trainable = self.trainable) + self.dout = DescrptSeA.build(self, coord_, atype_, natoms, box_, mesh, suffix = suffix, reuse = reuse) return self.dout - - def get_rot_mat(self) : - return self.qmat - - - def prod_force_virial(self, atom_ener, natoms) : - [net_deriv] = tf.gradients (atom_ener, self.descrpt_reshape) - net_deriv_reshape = tf.reshape (net_deriv, [-1, natoms[0] * self.ndescrpt]) - force \ - = op_module.prod_force_se_a (net_deriv_reshape, - self.descrpt_deriv, - self.nlist, - natoms, - n_a_sel = self.nnei_a, - n_r_sel = self.nnei_r) - virial, atom_virial \ - = op_module.prod_virial_se_a (net_deriv_reshape, - self.descrpt_deriv, - self.rij, - self.nlist, - natoms, - n_a_sel = self.nnei_a, - n_r_sel = self.nnei_r) - return force, virial, atom_virial - def _type_embed(self, atype, @@ -279,89 +66,14 @@ def _type_embed(self, reuse = reuse, seed = self.seed + ii, trainable = trainable) - ebd_type = tf.reshape(ebd_type, [-1, self.type_nchanl]) - return ebd_type - - - def _pass_filter(self, - inputs, - atype, - natoms, - reuse = None, - suffix = '', - trainable = True) : - start_index = 0 - # nf x na x ndescrpt - # nf x na x (nnei x 4) - inputs = tf.reshape(inputs, [-1, natoms[0], self.ndescrpt]) - layer, qmat = self._filter(tf.cast(inputs, self.filter_precision), - atype, - natoms, - name='filter_type_all'+suffix, - reuse=reuse, - seed = self.seed, - trainable = trainable, - activation_fn = self.filter_activation_fn) - output = tf.reshape(layer, [tf.shape(inputs)[0], natoms[0] * self.get_dim_out()]) - output_qmat = tf.reshape(qmat, [tf.shape(inputs)[0], natoms[0] * self.get_dim_rot_mat_1() * 3]) - return output, output_qmat - - - def _compute_dstats_sys_smth (self, - data_coord, - data_box, - data_atype, - natoms_vec, - mesh) : - dd_all \ - = self.sub_sess.run(self.stat_descrpt, - feed_dict = { - self.place_holders['coord']: data_coord, - self.place_holders['type']: data_atype, - self.place_holders['natoms_vec']: natoms_vec, - self.place_holders['box']: data_box, - self.place_holders['default_mesh']: mesh, - }) - natoms = natoms_vec - dd_all = np.reshape(dd_all, [-1, self.ndescrpt * natoms[0]]) - start_index = 0 - sysr = [] - sysa = [] - sysn = [] - sysr2 = [] - sysa2 = [] - for type_i in range(self.ntypes): - end_index = start_index + self.ndescrpt * natoms[2+type_i] - dd = dd_all[:, start_index:end_index] - dd = np.reshape(dd, [-1, self.ndescrpt]) - start_index = end_index - # compute - dd = np.reshape (dd, [-1, 4]) - ddr = dd[:,:1] - dda = dd[:,1:] - sumr = np.sum(ddr) - suma = np.sum(dda) / 3. - sumn = dd.shape[0] - sumr2 = np.sum(np.multiply(ddr, ddr)) - suma2 = np.sum(np.multiply(dda, dda)) / 3. - sysr.append(sumr) - sysa.append(suma) - sysn.append(sumn) - sysr2.append(sumr2) - sysa2.append(suma2) - return sysr, sysr2, sysa, sysa2, sysn - - - def _compute_std (self,sumv2, sumv, sumn) : - val = np.sqrt(sumv2/sumn - np.multiply(sumv/sumn, sumv/sumn)) - if np.abs(val) < 1e-2: - val = 1e-2 - return val + ebd_type = tf.reshape(ebd_type, [tf.shape(atype)[0], self.type_nchanl]) + return ebd_type def _embedding_net(self, inputs, natoms, + filter_neuron, activation_fn=tf.nn.tanh, stddev=1.0, bavg=0.0, @@ -369,13 +81,15 @@ def _embedding_net(self, reuse=None, seed=None, trainable = True): + ''' + inputs: nf x na x (nei x 4) + outputs: nf x na x nei x output_size + ''' # natom x (nei x 4) inputs = tf.reshape(inputs, [-1, self.ndescrpt]) shape = inputs.get_shape().as_list() - outputs_size = [1] + self.filter_neuron - outputs_size_2 = self.n_axis_neuron + outputs_size = [1] + filter_neuron with tf.variable_scope(name, reuse=reuse): - start_index = 0 xyz_scatter_total = [] # with natom x (nei x 4) inputs_i = inputs @@ -422,6 +136,29 @@ def _embedding_net(self, return xyz_scatter + def _pass_filter(self, + inputs, + atype, + natoms, + reuse = None, + suffix = '', + trainable = True) : + # nf x na x ndescrpt + # nf x na x (nnei x 4) + inputs = tf.reshape(inputs, [-1, natoms[0], self.ndescrpt]) + layer, qmat = self._filter(tf.cast(inputs, self.filter_precision), + atype, + natoms, + name='filter_type_all'+suffix, + reuse=reuse, + seed = self.seed, + trainable = trainable, + activation_fn = self.filter_activation_fn) + output = tf.reshape(layer, [tf.shape(inputs)[0], natoms[0] * self.get_dim_out()]) + output_qmat = tf.reshape(qmat, [tf.shape(inputs)[0], natoms[0] * self.get_dim_rot_mat_1() * 3]) + return output, output_qmat + + def _filter(self, inputs, atype, @@ -438,9 +175,10 @@ def _filter(self, # nf x natom x (nei x 4) nframes = tf.shape(inputs)[0] shape = tf.reshape(inputs, [-1, self.ndescrpt]).get_shape().as_list() - # (nf x natom) x nei x outputs_size + # nf x natom x nei x outputs_size mat_g = self._embedding_net(inputs, natoms, + self.filter_neuron, activation_fn = activation_fn, stddev = stddev, bavg = bavg, @@ -523,92 +261,3 @@ def _filter(self, return result, qmat - def _filter_type_ext(self, - inputs, - natoms, - activation_fn=tf.nn.tanh, - stddev=1.0, - bavg=0.0, - name='linear', - reuse=None, - seed=None, - trainable = True): - # natom x (nei x 4) - outputs_size = [1] + self.filter_neuron - outputs_size_2 = self.n_axis_neuron - with tf.variable_scope(name, reuse=reuse): - start_index = 0 - result_all = [] - xyz_scatter_1_all = [] - xyz_scatter_2_all = [] - for type_i in range(self.ntypes): - # cut-out inputs - # with natom x (nei_type_i x 4) - inputs_i = tf.slice (inputs, - [ 0, start_index* 4], - [-1, self.sel_a[type_i]* 4] ) - start_index += self.sel_a[type_i] - shape_i = inputs_i.get_shape().as_list() - # with (natom x nei_type_i) x 4 - inputs_reshape = tf.reshape(inputs_i, [-1, 4]) - xyz_scatter = tf.reshape(tf.slice(inputs_reshape, [0,0],[-1,1]),[-1,1]) - for ii in range(1, len(outputs_size)): - w = tf.get_variable('matrix_'+str(ii)+'_'+str(type_i), - [outputs_size[ii - 1], outputs_size[ii]], - self.filter_precision, - tf.random_normal_initializer(stddev=stddev/np.sqrt(outputs_size[ii]+outputs_size[ii-1]), seed = seed), - trainable = trainable) - b = tf.get_variable('bias_'+str(ii)+'_'+str(type_i), - [1, outputs_size[ii]], - self.filter_precision, - tf.random_normal_initializer(stddev=stddev, mean = bavg, seed = seed), - trainable = trainable) - if self.filter_resnet_dt : - idt = tf.get_variable('idt_'+str(ii)+'_'+str(type_i), - [1, outputs_size[ii]], - self.filter_precision, - tf.random_normal_initializer(stddev=0.001, mean = 1.0, seed = seed), - trainable = trainable) - if outputs_size[ii] == outputs_size[ii-1]: - if self.filter_resnet_dt : - xyz_scatter += activation_fn(tf.matmul(xyz_scatter, w) + b) * idt - else : - xyz_scatter += activation_fn(tf.matmul(xyz_scatter, w) + b) - elif outputs_size[ii] == outputs_size[ii-1] * 2: - if self.filter_resnet_dt : - xyz_scatter = tf.concat([xyz_scatter,xyz_scatter], 1) + activation_fn(tf.matmul(xyz_scatter, w) + b) * idt - else : - xyz_scatter = tf.concat([xyz_scatter,xyz_scatter], 1) + activation_fn(tf.matmul(xyz_scatter, w) + b) - else: - xyz_scatter = activation_fn(tf.matmul(xyz_scatter, w) + b) - # natom x nei_type_i x out_size - xyz_scatter = tf.reshape(xyz_scatter, (-1, shape_i[1]//4, outputs_size[-1])) - # natom x nei_type_i x 4 - inputs_i_reshape = tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]) - # natom x 4 x outputs_size - xyz_scatter_1 = tf.matmul(inputs_i_reshape, xyz_scatter, transpose_a = True) - xyz_scatter_1 = xyz_scatter_1 * (4.0 / shape_i[1]) - # natom x 4 x outputs_size_2 - xyz_scatter_2 = tf.slice(xyz_scatter_1, [0,0,0],[-1,-1,outputs_size_2]) - xyz_scatter_1_all.append(xyz_scatter_1) - xyz_scatter_2_all.append(xyz_scatter_2) - - # for type_i in range(self.ntypes): - # for type_j in range(type_i, self.ntypes): - # # natom x outputs_size x outputs_size_2 - # result = tf.matmul(xyz_scatter_1_all[type_i], xyz_scatter_2_all[type_j], transpose_a = True) - # # natom x (outputs_size x outputs_size_2) - # result = tf.reshape(result, [-1, outputs_size_2 * outputs_size[-1]]) - # result_all.append(tf.identity(result)) - xyz_scatter_2_coll = tf.concat(xyz_scatter_2_all, axis = 2) - for type_i in range(self.ntypes) : - # natom x outputs_size x (outputs_size_2 x ntypes) - result = tf.matmul(xyz_scatter_1_all[type_i], xyz_scatter_2_coll, transpose_a = True) - # natom x (outputs_size x outputs_size_2 x ntypes) - result = tf.reshape(result, [-1, outputs_size_2 * self.ntypes * outputs_size[-1]]) - result_all.append(tf.identity(result)) - - # natom x (ntypes x outputs_size x outputs_size_2 x ntypes) - result_all = tf.concat(result_all, axis = 1) - - return result_all From 2d6fb959e2ea41989cde32ed4f1bb372ed9cee11 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 31 Mar 2020 11:05:00 +0800 Subject: [PATCH 010/562] implement one-side type embedding, fix bug of type normalization --- source/train/DescrptSeAEbd.py | 192 ++++++++++++++++++++++++---------- 1 file changed, 138 insertions(+), 54 deletions(-) diff --git a/source/train/DescrptSeAEbd.py b/source/train/DescrptSeAEbd.py index c78f2e6281..a8e860f810 100644 --- a/source/train/DescrptSeAEbd.py +++ b/source/train/DescrptSeAEbd.py @@ -13,10 +13,12 @@ def __init__ (self, jdata): DescrptSeA.__init__(self, jdata) args = ClassArg()\ .add('type_nchanl', int, default = 4) \ - .add('type_nlayer', int, default = 2) + .add('type_nlayer', int, default = 2) \ + .add('type_one_side', bool, default = True) class_data = args.parse(jdata) self.type_nchanl = class_data['type_nchanl'] self.type_nlayer = class_data['type_nlayer'] + self.type_one_side = class_data['type_one_side'] def build (self, @@ -46,6 +48,7 @@ def _type_embed(self, suffix = '', trainable = True): ebd_type = tf.cast(atype, self.filter_precision) + ebd_type = ebd_type / float(self.ntypes) ebd_type = tf.reshape(ebd_type, [-1, 1]) for ii in range(self.type_nlayer): name = 'type_embed_layer_' + str(ii) @@ -135,6 +138,119 @@ def _embedding_net(self, xyz_scatter = tf.reshape(xyz_scatter, [tf.shape(inputs)[0], natoms[0], self.nnei, outputs_size[-1]]) return xyz_scatter + + def _type_embedding_net_two_sides(self, + mat_g, + atype, + natoms, + name = '', + reuse = None, + seed = None, + trainable = True): + outputs_size = self.filter_neuron[-1] + nframes = tf.shape(mat_g)[0] + # (nf x natom x nei) x (outputs_size x chnl x chnl) + mat_g = tf.reshape(mat_g, [nframes * natoms[0] * self.nnei, outputs_size]) + mat_g = one_layer(mat_g, + outputs_size * self.type_nchanl * self.type_nchanl, + activation_fn = None, + precision = self.filter_precision, + name = name+'_amplify', + reuse = reuse, + seed = self.seed, + trainable = trainable) + # nf x natom x nei x outputs_size x chnl x chnl + mat_g = tf.reshape(mat_g, [nframes, natoms[0], self.nnei, outputs_size, self.type_nchanl, self.type_nchanl]) + # nf x natom x outputs_size x chnl x nei x chnl + mat_g = tf.transpose(mat_g, perm = [0, 1, 3, 4, 2, 5]) + # nf x natom x outputs_size x chnl x (nei x chnl) + mat_g = tf.reshape(mat_g, [nframes, natoms[0], outputs_size, self.type_nchanl, self.nnei * self.type_nchanl]) + + # nei x nchnl + ebd_nei_type = self._type_embed(self.nei_type, + reuse = reuse, + trainable = True, + suffix = '') + # (nei x nchnl) + ebd_nei_type = tf.reshape(ebd_nei_type, [self.nnei * self.type_nchanl]) + # (nframes x natom) x nchnl + ebd_atm_type = self._type_embed(atype, + reuse = True, + trainable = True, + suffix = '') + # (nframes x natom x nchnl) + ebd_atm_type = tf.reshape(ebd_atm_type, [nframes * natoms[0] * self.type_nchanl]) + + # nf x natom x outputs_size x chnl x (nei x chnl) + mat_g = tf.multiply(mat_g, ebd_nei_type) + # nf x natom x outputs_size x chnl x nei x chnl + mat_g = tf.reshape(mat_g, [nframes, natoms[0], outputs_size, self.type_nchanl, self.nnei, self.type_nchanl]) + # nf x natom x outputs_size x chnl x nei + mat_g = tf.reduce_mean(mat_g, axis = 5) + # outputs_size x nei x nf x natom x chnl + mat_g = tf.transpose(mat_g, perm = [2, 4, 0, 1, 3]) + # outputs_size x nei x (nf x natom x chnl) + mat_g = tf.reshape(mat_g, [outputs_size, self.nnei, nframes * natoms[0] * self.type_nchanl]) + # outputs_size x nei x (nf x natom x chnl) + mat_g = tf.multiply(mat_g, ebd_atm_type) + # outputs_size x nei x nf x natom x chnl + mat_g = tf.reshape(mat_g, [outputs_size, self.nnei, nframes, natoms[0], self.type_nchanl]) + # outputs_size x nei x nf x natom + mat_g = tf.reduce_mean(mat_g, axis = 4) + # nf x natom x nei x outputs_size + mat_g = tf.transpose(mat_g, perm = [2, 3, 1, 0]) + # (nf x natom) x nei x outputs_size + mat_g = tf.reshape(mat_g, [nframes * natoms[0], self.nnei, outputs_size]) + return mat_g + + + def _type_embedding_net_one_side(self, + mat_g, + atype, + natoms, + name = '', + reuse = None, + seed = None, + trainable = True): + outputs_size = self.filter_neuron[-1] + nframes = tf.shape(mat_g)[0] + # (nf x natom x nei) x (outputs_size x chnl x chnl) + mat_g = tf.reshape(mat_g, [nframes * natoms[0] * self.nnei, outputs_size]) + mat_g = one_layer(mat_g, + outputs_size * self.type_nchanl, + activation_fn = None, + precision = self.filter_precision, + name = name+'_amplify', + reuse = reuse, + seed = self.seed, + trainable = trainable) + # nf x natom x nei x outputs_size x chnl + mat_g = tf.reshape(mat_g, [nframes, natoms[0], self.nnei, outputs_size, self.type_nchanl]) + # nf x natom x outputs_size x nei x chnl + mat_g = tf.transpose(mat_g, perm = [0, 1, 3, 2, 4]) + # nf x natom x outputs_size x (nei x chnl) + mat_g = tf.reshape(mat_g, [nframes, natoms[0], outputs_size, self.nnei * self.type_nchanl]) + + # nei x nchnl + ebd_nei_type = self._type_embed(self.nei_type, + reuse = reuse, + trainable = True, + suffix = '') + # (nei x nchnl) + ebd_nei_type = tf.reshape(ebd_nei_type, [self.nnei * self.type_nchanl]) + + # nf x natom x outputs_size x (nei x chnl) + mat_g = tf.multiply(mat_g, ebd_nei_type) + # nf x natom x outputs_size x nei x chnl + mat_g = tf.reshape(mat_g, [nframes, natoms[0], outputs_size, self.nnei, self.type_nchanl]) + # nf x natom x outputs_size x nei + mat_g = tf.reduce_mean(mat_g, axis = 4) + # nf x natom x nei x outputs_size + mat_g = tf.transpose(mat_g, perm = [0, 1, 3, 2]) + # (nf x natom) x nei x outputs_size + mat_g = tf.reshape(mat_g, [nframes * natoms[0], self.nnei, outputs_size]) + return mat_g + def _pass_filter(self, inputs, @@ -175,7 +291,7 @@ def _filter(self, # nf x natom x (nei x 4) nframes = tf.shape(inputs)[0] shape = tf.reshape(inputs, [-1, self.ndescrpt]).get_shape().as_list() - # nf x natom x nei x outputs_size + # nf x natom x nei x outputs_size mat_g = self._embedding_net(inputs, natoms, self.filter_neuron, @@ -186,60 +302,28 @@ def _filter(self, reuse = reuse, seed = seed, trainable = trainable) - # (nf x natom x nei) x outputs_size - mat_g = tf.reshape(mat_g, [nframes * natoms[0] * self.nnei, outputs_size]) - # (nf x natom x nei) x (outputs_size x chnl x chnl) - mat_g = one_layer(mat_g, - outputs_size * self.type_nchanl * self.type_nchanl, - activation_fn = None, - precision = self.filter_precision, - name = name, - reuse = reuse, - seed = self.seed, - trainable = trainable) - # nf x natom x nei x outputs_size x chnl x chnl - mat_g = tf.reshape(mat_g, [nframes, natoms[0], self.nnei, outputs_size, self.type_nchanl, self.type_nchanl]) - # nf x natom x outputs_size x chnl x nei x chnl - mat_g = tf.transpose(mat_g, perm = [0, 1, 3, 4, 2, 5]) - # nf x natom x outputs_size x chnl x (nei x chnl) - mat_g = tf.reshape(mat_g, [nframes, natoms[0], outputs_size, self.type_nchanl, self.nnei * self.type_nchanl]) + # nf x natom x nei x outputs_size + mat_g = tf.reshape(mat_g, [nframes, natoms[0], self.nnei, outputs_size]) - # nei x nchnl - ebd_nei_type = self._type_embed(self.nei_type, - reuse = reuse, - trainable = True, - suffix = '') - # (nei x nchnl) - ebd_nei_type = tf.reshape(ebd_nei_type, [self.nnei * self.type_nchanl]) - # (nframes x natom) x nchnl - ebd_atm_type = self._type_embed(atype, - reuse = True, - trainable = True, - suffix = '') - # (nframes x natom x nchnl) - ebd_atm_type = tf.reshape(ebd_atm_type, [nframes * natoms[0] * self.type_nchanl]) - - # nf x natom x outputs_size x chnl x (nei x chnl) - mat_g = tf.multiply(mat_g, ebd_nei_type) - # nf x natom x outputs_size x chnl x nei x chnl - mat_g = tf.reshape(mat_g, [nframes, natoms[0], outputs_size, self.type_nchanl, self.nnei, self.type_nchanl]) - # nf x natom x outputs_size x chnl x nei - mat_g = tf.reduce_mean(mat_g, axis = 5) - # outputs_size x nei x nf x natom x chnl - mat_g = tf.transpose(mat_g, perm = [2, 4, 0, 1, 3]) - # outputs_size x nei x (nf x natom x chnl) - mat_g = tf.reshape(mat_g, [outputs_size, self.nnei, nframes * natoms[0] * self.type_nchanl]) - # outputs_size x nei x (nf x natom x chnl) - mat_g = tf.multiply(mat_g, ebd_atm_type) - # outputs_size x nei x nf x natom x chnl - mat_g = tf.reshape(mat_g, [outputs_size, self.nnei, nframes, natoms[0], self.type_nchanl]) - # outputs_size x nei x nf x natom - mat_g = tf.reduce_mean(mat_g, axis = 4) - # nf x natom x nei x outputs_size - mat_g = tf.transpose(mat_g, perm = [2, 3, 1, 0]) # (nf x natom) x nei x outputs_size - mat_g = tf.reshape(mat_g, [nframes * natoms[0], self.nnei, outputs_size]) - xyz_scatter = mat_g + if self.type_one_side: + xyz_scatter \ + = self._type_embedding_net_one_side(mat_g, + atype, + natoms, + name = name, + reuse = reuse, + seed = seed, + trainable = trainable) + else: + xyz_scatter \ + = self._type_embedding_net_two_sides(mat_g, + atype, + natoms, + name = name, + reuse = reuse, + seed = seed, + trainable = trainable) # natom x nei x 4 inputs_reshape = tf.reshape(inputs, [-1, shape[1]//4, 4]) From d9de699f317beb3a25ab6a9274fec084e7423459 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 15 Apr 2020 14:22:34 +0800 Subject: [PATCH 011/562] work around the gcc bug --- source/lib/include/ComputeDescriptor.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/lib/include/ComputeDescriptor.h b/source/lib/include/ComputeDescriptor.h index 0f7b2b43f7..7d9f571980 100644 --- a/source/lib/include/ComputeDescriptor.h +++ b/source/lib/include/ComputeDescriptor.h @@ -1152,7 +1152,7 @@ void compute_descriptor_se_a_extf (vector & descrpt_a, { const double * ef_ = &efield[i_idx*3+0]; double ef[3] = {0.}; - if (isnan(ef_[0]) || isnan(ef_[1]) || isnan(ef_[2])){ + if (std::isnan(ef_[0]) || std::isnan(ef_[1]) || std::isnan(ef_[2])){ ef[0] = 1.; ef[1] = ef[2] = 0.; } @@ -1261,7 +1261,7 @@ void compute_descriptor_se_a_ef_para (vector & descrpt_a, { const double * ef_ = &efield[i_idx*3+0]; double ef[3] = {0.}; - if (isnan(ef_[0]) || isnan(ef_[1]) || isnan(ef_[2])){ + if (std::isnan(ef_[0]) || std::isnan(ef_[1]) || std::isnan(ef_[2])){ ef[0] = 1.; ef[1] = ef[2] = 0.; } @@ -1369,7 +1369,7 @@ void compute_descriptor_se_a_ef_vert (vector & descrpt_a, { const double * ef_ = &efield[i_idx*3+0]; double ef[3] = {0.}; - if (isnan(ef_[0]) || isnan(ef_[1]) || isnan(ef_[2])){ + if (std::isnan(ef_[0]) || std::isnan(ef_[1]) || std::isnan(ef_[2])){ ef[0] = 1.; ef[1] = ef[2] = 0.; } From ab761004e1035648e9a72263304e81980b96bac6 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 17 Apr 2020 21:11:38 +0800 Subject: [PATCH 012/562] fix bug of pass_filter interface --- source/train/DescrptSeAEf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/train/DescrptSeAEf.py b/source/train/DescrptSeAEf.py index b1006f9c91..518f6de1b8 100644 --- a/source/train/DescrptSeAEf.py +++ b/source/train/DescrptSeAEf.py @@ -264,7 +264,7 @@ def build (self, self.rij = tf.identity(self.rij, name = 'o_rij') self.nlist = tf.identity(self.nlist, name = 'o_nlist') - self.dout, self.qmat = self._pass_filter(self.descrpt_reshape, natoms, suffix = suffix, reuse = reuse, trainable = self.trainable) + self.dout, self.qmat = self._pass_filter(self.descrpt_reshape, atype, natoms, suffix = suffix, reuse = reuse, trainable = self.trainable) return self.dout From a71f481ab7afcb4c728ad731193284c3ab6da7a8 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 18 Apr 2020 15:48:10 +0800 Subject: [PATCH 013/562] first working version of aparam embedding --- source/op/CMakeLists.txt | 2 +- source/op/map_aparam.cc | 116 ++++++++++++++++++++++++++ source/train/DescrptSeA.py | 2 + source/train/DescrptSeAEbd.py | 149 ++++++++++++++++++++++++++-------- source/train/DescrptSeAEf.py | 2 +- 5 files changed, 237 insertions(+), 34 deletions(-) create mode 100644 source/op/map_aparam.cc diff --git a/source/op/CMakeLists.txt b/source/op/CMakeLists.txt index c0de3acea6..65327e2c64 100644 --- a/source/op/CMakeLists.txt +++ b/source/op/CMakeLists.txt @@ -3,7 +3,7 @@ set(OP_LIB ${PROJECT_SOURCE_DIR}/lib/src/SimulationRegion.cpp ${PROJECT_SOURCE_DIR}/lib/src/NeighborList.cpp) set (OP_CXX_FLAG -D_GLIBCXX_USE_CXX11_ABI=${OP_CXX_ABI} ) -file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc descrpt_se_r.cc tab_inter.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc) +file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc descrpt_se_r.cc tab_inter.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc map_aparam.cc) file(GLOB OP_CUDA_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a_gpu.cc descrpt_se_r_gpu.cc tab_inter.cc prod_force_se_a_gpu.cc prod_virial_se_a_gpu.cc prod_force_se_r_gpu.cc prod_virial_se_r_gpu.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ) file(GLOB OP_GRADS_SRC prod_force_grad.cc prod_force_se_a_grad.cc prod_force_se_r_grad.cc prod_virial_grad.cc prod_virial_se_a_grad.cc prod_virial_se_r_grad.cc soft_min_force_grad.cc soft_min_virial_grad.cc ) file(GLOB OP_PY *.py) diff --git a/source/op/map_aparam.cc b/source/op/map_aparam.cc new file mode 100644 index 0000000000..4cbcc098e2 --- /dev/null +++ b/source/op/map_aparam.cc @@ -0,0 +1,116 @@ +#include "tensorflow/core/framework/op.h" +#include "tensorflow/core/framework/op_kernel.h" +#include "tensorflow/core/framework/shape_inference.h" +#include + +using namespace tensorflow; +using namespace std; + +#ifdef HIGH_PREC +typedef double VALUETYPE; +#else +typedef float VALUETYPE; +#endif + +#ifdef HIGH_PREC +REGISTER_OP("MapAparam") +.Input("aparam: double") +.Input("nlist: int32") +.Input("natoms: int32") +.Attr("n_a_sel: int") +.Attr("n_r_sel: int") +.Output("output: double"); +#else +REGISTER_OP("MapAparam") +.Input("aparam: float") +.Input("nlist: int32") +.Input("natoms: int32") +.Attr("n_a_sel: int") +.Attr("n_r_sel: int") +.Output("mapped: float"); +#endif + +using namespace tensorflow; + +class MapAparamOp : public OpKernel { + public: + explicit MapAparamOp(OpKernelConstruction* context) : OpKernel(context) { + OP_REQUIRES_OK(context, context->GetAttr("n_a_sel", &n_a_sel)); + OP_REQUIRES_OK(context, context->GetAttr("n_r_sel", &n_r_sel)); + n_a_shift = n_a_sel * 4; + } + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& aparam_tensor = context->input(context_input_index++); + const Tensor& nlist_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); + + // set size of the sample + OP_REQUIRES (context, (aparam_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of aparam should be 2")); + OP_REQUIRES (context, (nlist_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + auto natoms = natoms_tensor .flat(); + + int nframes = aparam_tensor.shape().dim_size(0); + int nloc = natoms(0); + int nall = natoms(1); + int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int numb_aparam = aparam_tensor.shape().dim_size(1) / nall; + + // check the sizes + OP_REQUIRES (context, (nframes == nlist_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nnei == n_a_sel + n_r_sel), errors::InvalidArgument ("number of neighbors should match")); + + // Create an output tensor + TensorShape output_shape ; + output_shape.AddDim (nframes); + output_shape.AddDim (nloc * nnei * numb_aparam); + Tensor* output_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(0, output_shape, &output_tensor)); + + // flat the tensors + auto aparam = aparam_tensor.flat(); + auto nlist = nlist_tensor.flat(); + auto output = output_tensor->flat(); + + // loop over samples +#pragma omp parallel for + for (int kk = 0; kk < nframes; ++kk){ + int output_iter = kk * nloc * nnei * numb_aparam; + int aparam_iter = kk * nall * numb_aparam; + int nlist_iter = kk * nloc * nnei; + + for (int ii = 0; ii < nloc; ++ii){ + int i_idx = ii; + for (int dd = 0; dd < nnei * numb_aparam; ++dd) { + output(output_iter + i_idx * nnei * numb_aparam + dd) = 0.; + } + } + + // loop over loc atoms + for (int ii = 0; ii < nloc; ++ii){ + int i_idx = ii; + // loop over neighbor atoms + for (int jj = 0; jj < nnei; ++jj){ + int j_idx = nlist (nlist_iter + i_idx * nnei + jj); + if (j_idx < 0) continue; + // loop over elements of aparam + for (int dd = 0; dd < numb_aparam; ++dd){ + output(output_iter + ii * nnei * numb_aparam + jj * numb_aparam + dd) = aparam(aparam_iter + j_idx * numb_aparam + dd); + } + } + } + } + } +private: + int n_r_sel, n_a_sel, n_a_shift; +}; + +REGISTER_KERNEL_BUILDER(Name("MapAparam").Device(DEVICE_CPU), MapAparamOp); + + + diff --git a/source/train/DescrptSeA.py b/source/train/DescrptSeA.py index 35ba171f72..707f42ea61 100644 --- a/source/train/DescrptSeA.py +++ b/source/train/DescrptSeA.py @@ -209,6 +209,7 @@ def build (self, self.dout, self.qmat = self._pass_filter(self.descrpt_reshape, atype, natoms, + input_dict, suffix = suffix, reuse = reuse, trainable = self.trainable) @@ -245,6 +246,7 @@ def _pass_filter(self, inputs, atype, natoms, + input_dict, reuse = None, suffix = '', trainable = True) : diff --git a/source/train/DescrptSeAEbd.py b/source/train/DescrptSeAEbd.py index a8e860f810..0d432b9bc0 100644 --- a/source/train/DescrptSeAEbd.py +++ b/source/train/DescrptSeAEbd.py @@ -1,6 +1,6 @@ import numpy as np from deepmd.env import tf -from deepmd.common import ClassArg, get_activation_func, get_precision +from deepmd.common import ClassArg, get_activation_func, get_precision, add_data_requirement from deepmd.Network import one_layer from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision @@ -14,11 +14,15 @@ def __init__ (self, jdata): args = ClassArg()\ .add('type_nchanl', int, default = 4) \ .add('type_nlayer', int, default = 2) \ - .add('type_one_side', bool, default = True) + .add('type_one_side', bool, default = True) \ + .add('numb_aparam', int, default = 0) class_data = args.parse(jdata) self.type_nchanl = class_data['type_nchanl'] self.type_nlayer = class_data['type_nlayer'] self.type_one_side = class_data['type_one_side'] + self.numb_aparam = class_data['numb_aparam'] + if self.numb_aparam > 0: + add_data_requirement('aparam', 3, atomic=True, must=True, high_prec=False) def build (self, @@ -27,6 +31,7 @@ def build (self, natoms, box_, mesh, + input_dict, suffix = '', reuse = None): nei_type = np.array([]) @@ -37,19 +42,20 @@ def build (self, dtype = global_tf_float_precision, trainable = False, initializer = tf.constant_initializer(nei_type)) - self.dout = DescrptSeA.build(self, coord_, atype_, natoms, box_, mesh, suffix = suffix, reuse = reuse) + self.dout = DescrptSeA.build(self, coord_, atype_, natoms, box_, mesh, input_dict, suffix = suffix, reuse = reuse) return self.dout def _type_embed(self, atype, + ndim = 1, reuse = None, suffix = '', trainable = True): ebd_type = tf.cast(atype, self.filter_precision) ebd_type = ebd_type / float(self.ntypes) - ebd_type = tf.reshape(ebd_type, [-1, 1]) + ebd_type = tf.reshape(ebd_type, [-1, ndim]) for ii in range(self.type_nlayer): name = 'type_embed_layer_' + str(ii) ebd_type = one_layer(ebd_type, @@ -230,7 +236,7 @@ def _type_embedding_net_one_side(self, mat_g = tf.transpose(mat_g, perm = [0, 1, 3, 2, 4]) # nf x natom x outputs_size x (nei x chnl) mat_g = tf.reshape(mat_g, [nframes, natoms[0], outputs_size, self.nnei * self.type_nchanl]) - + # nei x nchnl ebd_nei_type = self._type_embed(self.nei_type, reuse = reuse, @@ -252,45 +258,112 @@ def _type_embedding_net_one_side(self, return mat_g + def _type_embedding_net_one_side_aparam(self, + mat_g, + atype, + natoms, + aparam, + name = '', + reuse = None, + seed = None, + trainable = True): + outputs_size = self.filter_neuron[-1] + nframes = tf.shape(mat_g)[0] + # (nf x natom x nei) x (outputs_size x chnl x chnl) + mat_g = tf.reshape(mat_g, [nframes * natoms[0] * self.nnei, outputs_size]) + mat_g = one_layer(mat_g, + outputs_size * self.type_nchanl, + activation_fn = None, + precision = self.filter_precision, + name = name+'_amplify', + reuse = reuse, + seed = self.seed, + trainable = trainable) + # nf x natom x nei x outputs_size x chnl + mat_g = tf.reshape(mat_g, [nframes, natoms[0], self.nnei, outputs_size, self.type_nchanl]) + # outputs_size x nf x natom x nei x chnl + mat_g = tf.transpose(mat_g, perm = [3, 0, 1, 2, 4]) + # outputs_size x (nf x natom x nei x chnl) + mat_g = tf.reshape(mat_g, [outputs_size, nframes * natoms[0] * self.nnei * self.type_nchanl]) + # nf x natom x nnei + embed_type = tf.tile(tf.reshape(self.nei_type, [1, self.nnei]), + [nframes * natoms[0], 1]) + # (nf x natom x nnei) x 1 + embed_type = tf.reshape(embed_type, [nframes * natoms[0] * self.nnei, 1]) + # nf x (natom x naparam) + aparam = tf.reshape(aparam, [nframes, -1]) + # nf x natom x nnei x naparam + embed_aparam = op_module.map_aparam(aparam, self.nlist, natoms, n_a_sel = self.nnei_a, n_r_sel = self.nnei_r) + # (nf x natom x nnei) x naparam + embed_aparam = tf.reshape(embed_aparam, [nframes * natoms[0] * self.nnei, self.numb_aparam]) + # (nf x natom x nnei) x (naparam+1) + embed_input = tf.concat((embed_type, embed_aparam), axis = 1) + + # (nf x natom x nnei) x nchnl + ebd_nei_type = self._type_embed(embed_input, + ndim = self.numb_aparam + 1, + reuse = reuse, + trainable = True, + suffix = '') + # (nf x natom x nei x nchnl) + ebd_nei_type = tf.reshape(ebd_nei_type, [nframes * natoms[0] * self.nnei * self.type_nchanl]) + + # outputs_size x (nf x natom x nei x chnl) + mat_g = tf.multiply(mat_g, ebd_nei_type) + # outputs_size x nf x natom x nei x chnl + mat_g = tf.reshape(mat_g, [outputs_size, nframes, natoms[0], self.nnei, self.type_nchanl]) + # outputs_size x nf x natom x nei + mat_g = tf.reduce_mean(mat_g, axis = 4) + # nf x natom x nei x outputs_size + mat_g = tf.transpose(mat_g, perm = [1, 2, 3, 0]) + # (nf x natom) x nei x outputs_size + mat_g = tf.reshape(mat_g, [nframes * natoms[0], self.nnei, outputs_size]) + return mat_g + + def _pass_filter(self, inputs, atype, natoms, + input_dict, reuse = None, suffix = '', trainable = True) : # nf x na x ndescrpt # nf x na x (nnei x 4) inputs = tf.reshape(inputs, [-1, natoms[0], self.ndescrpt]) - layer, qmat = self._filter(tf.cast(inputs, self.filter_precision), - atype, - natoms, - name='filter_type_all'+suffix, - reuse=reuse, - seed = self.seed, - trainable = trainable, - activation_fn = self.filter_activation_fn) + layer, qmat = self._ebd_filter(tf.cast(inputs, self.filter_precision), + atype, + natoms, + input_dict, + name='filter_type_all'+suffix, + reuse=reuse, + seed = self.seed, + trainable = trainable, + activation_fn = self.filter_activation_fn) output = tf.reshape(layer, [tf.shape(inputs)[0], natoms[0] * self.get_dim_out()]) output_qmat = tf.reshape(qmat, [tf.shape(inputs)[0], natoms[0] * self.get_dim_rot_mat_1() * 3]) return output, output_qmat - def _filter(self, - inputs, - atype, - natoms, - activation_fn=tf.nn.tanh, - stddev=1.0, - bavg=0.0, - name='linear', - reuse=None, - seed=None, - trainable = True): + def _ebd_filter(self, + inputs, + atype, + natoms, + input_dict, + activation_fn=tf.nn.tanh, + stddev=1.0, + bavg=0.0, + name='linear', + reuse=None, + seed=None, + trainable = True): outputs_size = self.filter_neuron[-1] outputs_size_2 = self.n_axis_neuron # nf x natom x (nei x 4) nframes = tf.shape(inputs)[0] shape = tf.reshape(inputs, [-1, self.ndescrpt]).get_shape().as_list() + # nf x natom x nei x outputs_size mat_g = self._embedding_net(inputs, natoms, @@ -307,14 +380,26 @@ def _filter(self, # (nf x natom) x nei x outputs_size if self.type_one_side: - xyz_scatter \ - = self._type_embedding_net_one_side(mat_g, - atype, - natoms, - name = name, - reuse = reuse, - seed = seed, - trainable = trainable) + if self.numb_aparam > 0: + aparam = input_dict['aparam'] + xyz_scatter \ + = self._type_embedding_net_one_side_aparam(mat_g, + atype, + natoms, + aparam, + name = name, + reuse = reuse, + seed = seed, + trainable = trainable) + else: + xyz_scatter \ + = self._type_embedding_net_one_side(mat_g, + atype, + natoms, + name = name, + reuse = reuse, + seed = seed, + trainable = trainable) else: xyz_scatter \ = self._type_embedding_net_two_sides(mat_g, diff --git a/source/train/DescrptSeAEf.py b/source/train/DescrptSeAEf.py index 518f6de1b8..b30706d21e 100644 --- a/source/train/DescrptSeAEf.py +++ b/source/train/DescrptSeAEf.py @@ -264,7 +264,7 @@ def build (self, self.rij = tf.identity(self.rij, name = 'o_rij') self.nlist = tf.identity(self.nlist, name = 'o_nlist') - self.dout, self.qmat = self._pass_filter(self.descrpt_reshape, atype, natoms, suffix = suffix, reuse = reuse, trainable = self.trainable) + self.dout, self.qmat = self._pass_filter(self.descrpt_reshape, atype, natoms, input_dict, suffix = suffix, reuse = reuse, trainable = self.trainable) return self.dout From 2abc7a7f695d33302bba50e678bfa310c94afe8b Mon Sep 17 00:00:00 2001 From: Lu Date: Tue, 5 May 2020 01:55:48 +0800 Subject: [PATCH 014/562] add tensorboard support! visualize the training of deepmd-kit --- source/train/DescrptLocFrame.py | 8 ++- source/train/DescrptSeA.py | 22 ++++++- source/train/DescrptSeAR.py | 7 +- source/train/DescrptSeR.py | 15 ++++- source/train/Fitting.py | 11 +++- source/train/Loss.py | 109 +++++++++++++++++++++++++++++++- source/train/Network.py | 4 ++ source/train/Trainer.py | 66 +++++++++++++++++-- source/train/common.py | 28 ++++++++ 9 files changed, 255 insertions(+), 15 deletions(-) diff --git a/source/train/DescrptLocFrame.py b/source/train/DescrptLocFrame.py index 69c1473db0..f854b7d633 100644 --- a/source/train/DescrptLocFrame.py +++ b/source/train/DescrptLocFrame.py @@ -1,6 +1,6 @@ import numpy as np from deepmd.env import tf -from deepmd.common import ClassArg +from deepmd.common import ClassArg, variable_summaries from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module @@ -154,6 +154,8 @@ def build (self, sel_r = self.sel_r, axis_rule = self.axis_rule) self.descrpt = tf.reshape(self.descrpt, [-1, self.ndescrpt]) + tf.summary.histogram('descrpt', self.descrpt) + return self.descrpt def get_rot_mat(self) : @@ -161,6 +163,7 @@ def get_rot_mat(self) : def prod_force_virial(self, atom_ener, natoms) : [net_deriv] = tf.gradients (atom_ener, self.descrpt) + tf.summary.histogram('net_derivative', net_deriv) net_deriv_reshape = tf.reshape (net_deriv, [-1, natoms[0] * self.ndescrpt]) force = op_module.prod_force (net_deriv_reshape, self.descrpt_deriv, @@ -178,6 +181,9 @@ def prod_force_virial(self, atom_ener, natoms) : natoms, n_a_sel = self.nnei_a, n_r_sel = self.nnei_r) + tf.summary.histogram('force', force) + tf.summary.histogram('virial', virial) + tf.summary.histogram('atom_virial', atom_virial) return force, virial, atom_virial diff --git a/source/train/DescrptSeA.py b/source/train/DescrptSeA.py index d409f7134f..a094049832 100644 --- a/source/train/DescrptSeA.py +++ b/source/train/DescrptSeA.py @@ -1,6 +1,6 @@ import numpy as np from deepmd.env import tf -from deepmd.common import ClassArg, get_activation_func, get_precision +from deepmd.common import ClassArg, get_activation_func, get_precision, variable_summaries from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module @@ -197,6 +197,10 @@ def build (self, rcut_r_smth = self.rcut_r_smth, sel_a = self.sel_a, sel_r = self.sel_r) + # only used when tensorboard was set as true + tf.summary.histogram('descrpt', self.descrpt) + tf.summary.histogram('rij', self.rij) + tf.summary.histogram('nlist', self.nlist) self.descrpt_reshape = tf.reshape(self.descrpt, [-1, self.ndescrpt]) self.descrpt_reshape = tf.identity(self.descrpt_reshape, name = 'o_rmat') @@ -205,7 +209,8 @@ def build (self, self.nlist = tf.identity(self.nlist, name = 'o_nlist') self.dout, self.qmat = self._pass_filter(self.descrpt_reshape, natoms, suffix = suffix, reuse = reuse, trainable = self.trainable) - + # only used when tensorboard was set as true + tf.summary.histogram('embedding_net_output', self.dout) return self.dout @@ -215,6 +220,7 @@ def get_rot_mat(self) : def prod_force_virial(self, atom_ener, natoms) : [net_deriv] = tf.gradients (atom_ener, self.descrpt_reshape) + tf.summary.histogram('net_derivative', net_deriv) net_deriv_reshape = tf.reshape (net_deriv, [-1, natoms[0] * self.ndescrpt]) force \ = op_module.prod_force_se_a (net_deriv_reshape, @@ -231,6 +237,10 @@ def prod_force_virial(self, atom_ener, natoms) : natoms, n_a_sel = self.nnei_a, n_r_sel = self.nnei_r) + tf.summary.histogram('force', force) + tf.summary.histogram('virial', virial) + tf.summary.histogram('atom_virial', atom_virial) + return force, virial, atom_virial @@ -348,17 +358,22 @@ def _filter(self, self.filter_precision, tf.random_normal_initializer(stddev=stddev/np.sqrt(outputs_size[ii]+outputs_size[ii-1]), seed = seed), trainable = trainable) + # only used when tensorboard was set as true + variable_summaries(w, 'matrix_'+str(ii)+'_'+str(type_i)) b = tf.get_variable('bias_'+str(ii)+'_'+str(type_i), [1, outputs_size[ii]], self.filter_precision, tf.random_normal_initializer(stddev=stddev, mean = bavg, seed = seed), trainable = trainable) + # only used when tensorboard was set as true + variable_summaries(b, 'bias_'+str(ii)+'_'+str(type_i)) if self.filter_resnet_dt : idt = tf.get_variable('idt_'+str(ii)+'_'+str(type_i), [1, outputs_size[ii]], self.filter_precision, tf.random_normal_initializer(stddev=0.001, mean = 1.0, seed = seed), trainable = trainable) + variable_summaries(idt, 'idt_'+str(ii)+'_'+str(type_i)) if outputs_size[ii] == outputs_size[ii-1]: if self.filter_resnet_dt : xyz_scatter += activation_fn(tf.matmul(xyz_scatter, w) + b) * idt @@ -435,17 +450,20 @@ def _filter_type_ext(self, self.filter_precision, tf.random_normal_initializer(stddev=stddev/np.sqrt(outputs_size[ii]+outputs_size[ii-1]), seed = seed), trainable = trainable) + variable_summaries(w, 'matrix_'+str(ii)+'_'+str(type_i)) b = tf.get_variable('bias_'+str(ii)+'_'+str(type_i), [1, outputs_size[ii]], self.filter_precision, tf.random_normal_initializer(stddev=stddev, mean = bavg, seed = seed), trainable = trainable) + variable_summaries(b, 'bias_'+str(ii)+'_'+str(type_i)) if self.filter_resnet_dt : idt = tf.get_variable('idt_'+str(ii)+'_'+str(type_i), [1, outputs_size[ii]], self.filter_precision, tf.random_normal_initializer(stddev=0.001, mean = 1.0, seed = seed), trainable = trainable) + variable_summaries(idt, 'idt_'+str(ii)+'_'+str(type_i)) if outputs_size[ii] == outputs_size[ii-1]: if self.filter_resnet_dt : xyz_scatter += activation_fn(tf.matmul(xyz_scatter, w) + b) * idt diff --git a/source/train/DescrptSeAR.py b/source/train/DescrptSeAR.py index dadc2f3d95..c9735d2edc 100644 --- a/source/train/DescrptSeAR.py +++ b/source/train/DescrptSeAR.py @@ -1,6 +1,6 @@ import numpy as np from deepmd.env import tf -from deepmd.common import ClassArg +from deepmd.common import ClassArg, variable_summaries from deepmd.DescrptSeA import DescrptSeA from deepmd.DescrptSeR import DescrptSeR @@ -70,6 +70,8 @@ def build (self, self.dout_r = tf.reshape(self.dout_r, [-1, self.descrpt_r.get_dim_out()]) self.dout = tf.concat([self.dout_a, self.dout_r], axis = 1) self.dout = tf.reshape(self.dout, [-1, natoms[0] * self.get_dim_out()]) + + tf.summary.histogram('embedding_net_output', self.dout) return self.dout @@ -79,6 +81,9 @@ def prod_force_virial(self, atom_ener, natoms) : force = f_a + f_r virial = v_a + v_r atom_virial = av_a + av_r + tf.summary.histogram('force', force) + tf.summary.histogram('virial', virial) + tf.summary.histogram('atom_virial', atom_virial) return force, virial, atom_virial diff --git a/source/train/DescrptSeR.py b/source/train/DescrptSeR.py index ed53a3bcd4..3b03e2ba84 100644 --- a/source/train/DescrptSeR.py +++ b/source/train/DescrptSeR.py @@ -1,6 +1,6 @@ import numpy as np from deepmd.env import tf -from deepmd.common import ClassArg, get_activation_func, get_precision +from deepmd.common import ClassArg, get_activation_func, get_precision, variable_summaries from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module @@ -171,14 +171,20 @@ def build (self, sel = self.sel_r) self.descrpt_reshape = tf.reshape(self.descrpt, [-1, self.ndescrpt]) + # only used when tensorboard was set as true + tf.summary.histogram('descrpt', self.descrpt) + tf.summary.histogram('rij', self.rij) + tf.summary.histogram('nlist', self.nlist) self.dout = self._pass_filter(self.descrpt_reshape, natoms, suffix = suffix, reuse = reuse, trainable = self.trainable) + tf.summary.histogram('embedding_net_output', self.dout) return self.dout def prod_force_virial(self, atom_ener, natoms) : [net_deriv] = tf.gradients (atom_ener, self.descrpt_reshape) + tf.summary.histogram('net_derivative', net_deriv) net_deriv_reshape = tf.reshape (net_deriv, [-1, natoms[0] * self.ndescrpt]) force \ = op_module.prod_force_se_r (net_deriv_reshape, @@ -191,6 +197,10 @@ def prod_force_virial(self, atom_ener, natoms) : self.rij, self.nlist, natoms) + tf.summary.histogram('force', force) + tf.summary.histogram('virial', virial) + tf.summary.histogram('atom_virial', atom_virial) + return force, virial, atom_virial @@ -293,17 +303,20 @@ def _filter_r(self, self.filter_precision, tf.random_normal_initializer(stddev=stddev/np.sqrt(outputs_size[ii]+outputs_size[ii-1]), seed = seed), trainable = trainable) + variable_summaries(w, 'matrix_'+str(ii)+'_'+str(type_i)) b = tf.get_variable('bias_'+str(ii)+'_'+str(type_i), [1, outputs_size[ii]], self.filter_precision, tf.random_normal_initializer(stddev=stddev, mean = bavg, seed = seed), trainable = trainable) + variable_summaries(b, 'bias_'+str(ii)+'_'+str(type_i)) if self.filter_resnet_dt : idt = tf.get_variable('idt_'+str(ii)+'_'+str(type_i), [1, outputs_size[ii]], self.filter_precision, tf.random_normal_initializer(stddev=0.001, mean = 1.0, seed = seed), trainable = trainable) + variable_summaries(idt, 'idt_'+str(ii)+'_'+str(type_i)) if outputs_size[ii] == outputs_size[ii-1]: if self.filter_resnet_dt : xyz_scatter += activation_fn(tf.matmul(xyz_scatter, w) + b) * idt diff --git a/source/train/Fitting.py b/source/train/Fitting.py index 49ca40b2c7..efb0fea937 100644 --- a/source/train/Fitting.py +++ b/source/train/Fitting.py @@ -237,7 +237,7 @@ def build (self, outs = final_layer else: outs = tf.concat([outs, final_layer], axis = 1) - + tf.summary.histogram('fitting_net_output', outs) return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) @@ -320,7 +320,8 @@ def build (self, else: outs = tf.concat([outs, final_layer], axis = 1) count += 1 - + + tf.summary.histogram('fitting_net_output', outs) return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) @@ -403,6 +404,7 @@ def build (self, outs = tf.concat([outs, final_layer], axis = 1) count += 1 + tf.summary.histogram('fitting_net_output', outs) return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) @@ -534,7 +536,8 @@ def build (self, else: outs = tf.concat([outs, final_layer], axis = 1) count += 1 - + + tf.summary.histogram('fitting_net_output', outs) return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) @@ -563,6 +566,7 @@ def build (self, # nframes x natoms x 9 outs = tf.reshape(outs, [tf.shape(inputs)[0], -1, 9]) outs = tf.reduce_sum(outs, axis = 1) + tf.summary.histogram('fitting_net_output', outs) return tf.reshape(outs, [-1]) @@ -642,5 +646,6 @@ def build (self, outs = tf.concat([outs, final_layer], axis = 1) count += 1 + tf.summary.histogram('fitting_net_output', outs) return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) # return tf.reshape(outs, [tf.shape(inputs)[0] * natoms[0] * 3 // 3]) diff --git a/source/train/Loss.py b/source/train/Loss.py index d939273f26..cdc0a4b0bf 100644 --- a/source/train/Loss.py +++ b/source/train/Loss.py @@ -114,6 +114,12 @@ def build (self, l2_loss += global_cvt_2_ener_float(pref_pf * l2_pref_force_loss) more_loss['l2_pref_force_loss'] = l2_pref_force_loss + # only used when tensorboard was set as true + self.l2_loss_summary = tf.summary.scalar('l2_loss', tf.sqrt(l2_loss)) + self.l2_loss_ener_summary = tf.summary.scalar('l2_ener_loss', tf.sqrt(l2_ener_loss) / tf.cast(natoms[0], tf.float64)) + self.l2_loss_force_summary = tf.summary.scalar('l2_force_loss', tf.sqrt(l2_force_loss)) + self.l2_loss_virial_summary = tf.summary.scalar('l2_virial_loss', tf.sqrt(l2_virial_loss) / tf.cast(natoms[0], tf.float64)) + self.l2_l = l2_loss self.l2_more = more_loss return l2_loss, more_loss @@ -171,7 +177,50 @@ def print_on_training(self, if self.has_pf: print_str += prop_fmt % (np.sqrt(error_pf_test), np.sqrt(error_pf_train)) - return print_str + return print_str + + def print_on_training_with_tensorboard(self, + test_writer, + cur_batch, + sess, + natoms, + feed_dict_test, + feed_dict_batch) : + summary_merged_op = tf.summary.merge([self.l2_loss_summary, self.l2_loss_ener_summary, self.l2_loss_force_summary, self.l2_loss_virial_summary]) + summary, error_test, error_e_test, error_f_test, error_v_test, error_ae_test, error_pf_test \ + = sess.run([summary_merged_op, \ + self.l2_l, \ + self.l2_more['l2_ener_loss'], \ + self.l2_more['l2_force_loss'], \ + self.l2_more['l2_virial_loss'], \ + self.l2_more['l2_atom_ener_loss'],\ + self.l2_more['l2_pref_force_loss']], + feed_dict=feed_dict_test) + test_writer.add_summary(summary, cur_batch) + + error_train, error_e_train, error_f_train, error_v_train, error_ae_train, error_pf_train \ + = sess.run([self.l2_l, \ + self.l2_more['l2_ener_loss'], \ + self.l2_more['l2_force_loss'], \ + self.l2_more['l2_virial_loss'], \ + self.l2_more['l2_atom_ener_loss'],\ + self.l2_more['l2_pref_force_loss']], + feed_dict=feed_dict_batch) + print_str = "" + prop_fmt = " %9.2e %9.2e" + print_str += prop_fmt % (np.sqrt(error_test), np.sqrt(error_train)) + if self.has_e : + print_str += prop_fmt % (np.sqrt(error_e_test) / natoms[0], np.sqrt(error_e_train) / natoms[0]) + if self.has_ae : + print_str += prop_fmt % (np.sqrt(error_ae_test), np.sqrt(error_ae_train)) + if self.has_f : + print_str += prop_fmt % (np.sqrt(error_f_test), np.sqrt(error_f_train)) + if self.has_v : + print_str += prop_fmt % (np.sqrt(error_v_test) / natoms[0], np.sqrt(error_v_train) / natoms[0]) + if self.has_pf: + print_str += prop_fmt % (np.sqrt(error_pf_test), np.sqrt(error_pf_train)) + + return print_str class EnerDipoleLoss () : @@ -232,6 +281,10 @@ def build (self, more_loss['l2_ener_loss'] = l2_ener_loss more_loss['l2_ener_dipole_loss'] = l2_ener_dipole_loss + self.l2_loss_summary = tf.summary.scalar('l2_loss', tf.sqrt(l2_loss)) + self.l2_loss_ener_summary = tf.summary.scalar('l2_ener_loss', tf.sqrt(l2_ener_loss) / tf.cast(natoms[0], tf.float64)) + self.l2_ener_dipole_loss_summary = tf.summary.scalar('l2_ener_dipole_loss', tf.sqrt(l2_ener_dipole_loss)) + self.l2_l = l2_loss self.l2_more = more_loss return l2_loss, more_loss @@ -266,7 +319,35 @@ def print_on_training(self, print_str += prop_fmt % (np.sqrt(error_test), np.sqrt(error_train)) print_str += prop_fmt % (np.sqrt(error_e_test) / natoms[0], np.sqrt(error_e_train) / natoms[0]) print_str += prop_fmt % (np.sqrt(error_ed_test), np.sqrt(error_ed_train)) - return print_str + return print_str + + def print_on_training_with_tensorboard(self, + test_writer, + cur_batch, + sess, + natoms, + feed_dict_test, + feed_dict_batch) : + summary_merged_op = tf.summary.merge([self.l2_loss_summary, self.l2_loss_ener_summary, self.l2_ener_dipole_loss_summary]) + summary, error_test, error_e_test, error_ed_test\ + = sess.run([summary_merged_op, \ + self.l2_l, \ + self.l2_more['l2_ener_loss'], \ + self.l2_more['l2_ener_dipole_loss']], + feed_dict=feed_dict_test) + test_writer.add_summary(summary, cur_batch) + + error_train, error_e_train, error_ed_train\ + = sess.run([self.l2_l, \ + self.l2_more['l2_ener_loss'], \ + self.l2_more['l2_ener_dipole_loss']], + feed_dict=feed_dict_batch) + print_str = "" + prop_fmt = " %9.2e %9.2e" + print_str += prop_fmt % (np.sqrt(error_test), np.sqrt(error_train)) + print_str += prop_fmt % (np.sqrt(error_e_test) / natoms[0], np.sqrt(error_e_train) / natoms[0]) + print_str += prop_fmt % (np.sqrt(error_ed_test), np.sqrt(error_ed_train)) + return print_str class TensorLoss () : @@ -306,7 +387,7 @@ def build (self, l2_loss = l2_loss * atom_norm self.l2_l = l2_loss more_loss = {} - + self.l2_loss_summary = tf.summary.scalar('l2_loss', tf.sqrt(l2_loss)) return l2_loss, more_loss def print_header(self) : @@ -332,4 +413,26 @@ def print_on_training(self, return print_str + def print_on_training_with_tensorboard(self, + test_writer, + cur_batch, + sess, + natoms, + feed_dict_test, + feed_dict_batch) : + summary_merged_op = tf.summary.merge([self.l2_loss_summary]) + summary, error_test\ + = sess.run([summary_merged_op, \ + self.l2_l], \ + feed_dict=feed_dict_test) + test_writer.add_summary(summary, cur_batch) + + error_train\ + = sess.run([self.l2_l], \ + feed_dict=feed_dict_batch) + print_str = "" + prop_fmt = " %9.2e %9.2e" + print_str += prop_fmt % (np.sqrt(error_test), np.sqrt(error_train)) + + return print_str diff --git a/source/train/Network.py b/source/train/Network.py index ed188c085d..2d61315723 100644 --- a/source/train/Network.py +++ b/source/train/Network.py @@ -1,6 +1,7 @@ import numpy as np from deepmd.env import tf +from deepmd.common import variable_summaries from deepmd.RunOptions import global_tf_float_precision def one_layer(inputs, @@ -22,11 +23,13 @@ def one_layer(inputs, precision, tf.random_normal_initializer(stddev=stddev/np.sqrt(shape[1]+outputs_size), seed = seed), trainable = trainable) + variable_summaries(w, 'matrix') b = tf.get_variable('bias', [outputs_size], precision, tf.random_normal_initializer(stddev=stddev, mean = bavg, seed = seed), trainable = trainable) + variable_summaries(b, 'bias') hidden = tf.matmul(inputs, w) + b if activation_fn != None and use_timestep : idt = tf.get_variable('idt', @@ -34,6 +37,7 @@ def one_layer(inputs, precision, tf.random_normal_initializer(stddev=0.001, mean = 0.1, seed = seed), trainable = trainable) + variable_summaries(idt, 'idt') if activation_fn != None: if useBN: None diff --git a/source/train/Trainer.py b/source/train/Trainer.py index b6428c987e..c1aa926016 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -30,7 +30,7 @@ import deepmd._soft_min_virial_grad import deepmd._gelu -from deepmd.common import j_must_have, ClassArg +from deepmd.common import j_must_have, ClassArg, delete_file_folder def _is_subdir(path, directory): path = os.path.realpath(path) @@ -179,6 +179,8 @@ def _init_param(self, jdata): .add('timing_in_training', bool, default = True)\ .add('profiling', bool, default = False)\ .add('profiling_file',str, default = 'timeline.json')\ + .add('tensorboard', bool, default = False)\ + .add('tensorboard_log_file',str, default = 'log')\ .add('sys_probs', list )\ .add('auto_prob_style', str, default = "prob_sys_size") tr_data = tr_args.parse(training_param) @@ -191,6 +193,8 @@ def _init_param(self, jdata): self.timing_in_training = tr_data['timing_in_training'] self.profiling = tr_data['profiling'] self.profiling_file = tr_data['profiling_file'] + self.tensorboard = tr_data['tensorboard'] + self.tensorboard_log_file = tr_data['tensorboard_log_file'] self.sys_probs = tr_data['sys_probs'] self.auto_prob_style = tr_data['auto_prob_style'] self.useBN = False @@ -392,6 +396,16 @@ def train (self, prf_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE) prf_run_metadata = tf.RunMetadata() + # set tensorboard execution environment + if self.tensorboard : + summary_merged_op = tf.summary.merge_all() + if os.path.exists(self.tensorboard_log_file + '/train'): + delete_file_folder(self.tensorboard_log_file + '/train') + if os.path.exists(self.tensorboard_log_file + '/test'): + delete_file_folder (self.tensorboard_log_file + '/test') + train_writer = tf.summary.FileWriter(self.tensorboard_log_file + '/train', self.sess.graph) + test_writer = tf.summary.FileWriter(self.tensorboard_log_file + '/test') + train_time = 0 while cur_batch < stop_batch : batch_data = data.get_batch (sys_probs = self.sys_probs, @@ -412,10 +426,19 @@ def train (self, feed_dict_batch[self.place_holders['is_training']] = True if self.display_in_training and is_first_step : - self.test_on_the_fly(fp, data, feed_dict_batch) + if self.tensorboard : + self.test_on_the_fly_with_tensorboard(test_writer, fp, data, feed_dict_batch) + else : + self.test_on_the_fly(fp, data, feed_dict_batch) is_first_step = False if self.timing_in_training : tic = time.time() - self.sess.run([self.train_op], feed_dict = feed_dict_batch, options=prf_options, run_metadata=prf_run_metadata) + # use tensorboard to visualize the training of deepmd-kit + # it will takes some extra execution time to generate the tensorboard data + if self.tensorboard : + summary, _ = self.sess.run([summary_merged_op, self.train_op], feed_dict = feed_dict_batch, options=prf_options, run_metadata=prf_run_metadata) + train_writer.add_summary(summary, cur_batch) + else : + self.sess.run([self.train_op], feed_dict = feed_dict_batch, options=prf_options, run_metadata=prf_run_metadata) if self.timing_in_training : toc = time.time() if self.timing_in_training : train_time += toc - tic cur_batch = self.sess.run(self.global_step) @@ -423,7 +446,10 @@ def train (self, if self.display_in_training and (cur_batch % self.disp_freq == 0) : tic = time.time() - self.test_on_the_fly(fp, data, feed_dict_batch) + if self.tensorboard : + self.test_on_the_fly_with_tensorboard(test_writer, fp, data, feed_dict_batch) + else : + self.test_on_the_fly(fp, data, feed_dict_batch) toc = time.time() test_time = toc - tic if self.timing_in_training : @@ -485,4 +511,36 @@ def test_on_the_fly (self, fp.write(print_str) fp.flush () +def test_on_the_fly_with_tensorboard (self, + test_writer, + fp, + data, + feed_dict_batch) : + test_data = data.get_test(ntests = self.numb_test) + feed_dict_test = {} + for kk in test_data.keys(): + if kk == 'find_type' or kk == 'type' : + continue + if 'find_' in kk: + feed_dict_test[self.place_holders[kk]] = test_data[kk] + else: + feed_dict_test[self.place_holders[kk]] = np.reshape(test_data[kk][:self.numb_test], [-1]) + for ii in ['type'] : + feed_dict_test[self.place_holders[ii]] = np.reshape(test_data[ii][:self.numb_test], [-1]) + for ii in ['natoms_vec', 'default_mesh'] : + feed_dict_test[self.place_holders[ii]] = test_data[ii] + feed_dict_test[self.place_holders['is_training']] = False + cur_batch = self.cur_batch + current_lr = self.sess.run(self.learning_rate) + if self.run_opt.is_chief: + print_str = "%7d" % cur_batch + print_str += self.loss.print_on_training_with_tensorboard(test_writer, + cur_batch, + self.sess, + test_data['natoms_vec'], + feed_dict_test, + feed_dict_batch) + print_str += " %8.1e\n" % current_lr + fp.write(print_str) + fp.flush () \ No newline at end of file diff --git a/source/train/common.py b/source/train/common.py index 887669a278..b5514249d1 100644 --- a/source/train/common.py +++ b/source/train/common.py @@ -188,3 +188,31 @@ def get_precision(precision): else: raise RuntimeError("%d is not a valid precision" % precision) +def delete_file_folder(src): + '''delete files and folders''' + if os.path.isfile(src): + try: + os.remove(src) + except: + pass + elif os.path.isdir(src): + for item in os.listdir(src): + itemsrc=os.path.join(src,item) + delete_file_folder(itemsrc) + try: + os.rmdir(src) + except: + pass + +def variable_summaries(var, name): + """Attach a lot of summaries to a Tensor (for TensorBoard visualization).""" + with tf.name_scope(name): + mean = tf.reduce_mean(var) + tf.summary.scalar('mean', mean) + + with tf.name_scope('stddev'): + stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean))) + tf.summary.scalar('stddev', stddev) + tf.summary.scalar('max', tf.reduce_max(var)) + tf.summary.scalar('min', tf.reduce_min(var)) + tf.summary.histogram('histogram', var) \ No newline at end of file From 84ed2f308b8c6dba00380ff0396200619cbf7ce4 Mon Sep 17 00:00:00 2001 From: Lu Date: Tue, 5 May 2020 03:14:19 +0800 Subject: [PATCH 015/562] fix potential bugs --- source/train/Loss.py | 6 +++--- source/train/Trainer.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/train/Loss.py b/source/train/Loss.py index cdc0a4b0bf..3c57fe5f69 100644 --- a/source/train/Loss.py +++ b/source/train/Loss.py @@ -116,9 +116,9 @@ def build (self, # only used when tensorboard was set as true self.l2_loss_summary = tf.summary.scalar('l2_loss', tf.sqrt(l2_loss)) - self.l2_loss_ener_summary = tf.summary.scalar('l2_ener_loss', tf.sqrt(l2_ener_loss) / tf.cast(natoms[0], tf.float64)) + self.l2_loss_ener_summary = tf.summary.scalar('l2_ener_loss', tf.sqrt(l2_ener_loss) / global_cvt_2_tf_float(natoms[0])) self.l2_loss_force_summary = tf.summary.scalar('l2_force_loss', tf.sqrt(l2_force_loss)) - self.l2_loss_virial_summary = tf.summary.scalar('l2_virial_loss', tf.sqrt(l2_virial_loss) / tf.cast(natoms[0], tf.float64)) + self.l2_loss_virial_summary = tf.summary.scalar('l2_virial_loss', tf.sqrt(l2_virial_loss) / global_cvt_2_tf_float(natoms[0])) self.l2_l = l2_loss self.l2_more = more_loss @@ -282,7 +282,7 @@ def build (self, more_loss['l2_ener_dipole_loss'] = l2_ener_dipole_loss self.l2_loss_summary = tf.summary.scalar('l2_loss', tf.sqrt(l2_loss)) - self.l2_loss_ener_summary = tf.summary.scalar('l2_ener_loss', tf.sqrt(l2_ener_loss) / tf.cast(natoms[0], tf.float64)) + self.l2_loss_ener_summary = tf.summary.scalar('l2_ener_loss', tf.sqrt(l2_ener_loss) / global_cvt_2_tf_float(natoms[0])) self.l2_ener_dipole_loss_summary = tf.summary.scalar('l2_ener_dipole_loss', tf.sqrt(l2_ener_dipole_loss)) self.l2_l = l2_loss diff --git a/source/train/Trainer.py b/source/train/Trainer.py index c1aa926016..154fd1b35e 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -511,7 +511,7 @@ def test_on_the_fly (self, fp.write(print_str) fp.flush () -def test_on_the_fly_with_tensorboard (self, + def test_on_the_fly_with_tensorboard (self, test_writer, fp, data, From 97ee2a73e424e596543986b8f3ad71510143c7c6 Mon Sep 17 00:00:00 2001 From: Lu Date: Tue, 5 May 2020 14:01:45 +0800 Subject: [PATCH 016/562] Add tensorboard tutorial --- README.md | 52 ++++++----- examples/water/train/water_se_a.json | 6 +- media/docs/dp-tensorboard-tutorial.md | 84 ++++++++++++++++++ {doc => media/docs}/install-tf.1.12.md | 0 {doc => media/docs}/install-tf.1.14-gpu.md | 0 {doc => media/docs}/install-tf.1.14.md | 0 {doc => media/docs}/install-tf.1.8.md | 0 .../docs}/lammps-pair-style-deepmd.md | 0 media/images/l2_energy_loss.png | Bin 0 -> 228358 bytes media/images/l2_force_loss.png | Bin 0 -> 181164 bytes media/images/l2_loss.png | Bin 0 -> 139425 bytes media/images/tensorboard-distribution.png | Bin 0 -> 272198 bytes media/images/tensorboard-graph.png | Bin 0 -> 375349 bytes media/images/tensorboard-histograms.png | Bin 0 -> 834319 bytes media/images/tensorboard-scalar.png | Bin 0 -> 353432 bytes 15 files changed, 118 insertions(+), 24 deletions(-) create mode 100644 media/docs/dp-tensorboard-tutorial.md rename {doc => media/docs}/install-tf.1.12.md (100%) rename {doc => media/docs}/install-tf.1.14-gpu.md (100%) rename {doc => media/docs}/install-tf.1.14.md (100%) rename {doc => media/docs}/install-tf.1.8.md (100%) rename {doc => media/docs}/lammps-pair-style-deepmd.md (100%) create mode 100644 media/images/l2_energy_loss.png create mode 100644 media/images/l2_force_loss.png create mode 100644 media/images/l2_loss.png create mode 100644 media/images/tensorboard-distribution.png create mode 100644 media/images/tensorboard-graph.png create mode 100644 media/images/tensorboard-histograms.png create mode 100644 media/images/tensorboard-scalar.png diff --git a/README.md b/README.md index 178758f5db..4a3b386939 100644 --- a/README.md +++ b/README.md @@ -3,37 +3,43 @@ # Table of contents +- [DeePMD-kit Manual](#deepmd-kit-manual) +- [Table of contents](#table-of-contents) - [About DeePMD-kit](#about-deepmd-kit) - - [Highlighted features](#highlighted-features) - - [Code structure](#code-structure) - - [License and credits](#license-and-credits) - - [Deep Potential in a nutshell](#deep-potential-in-a-nutshell) + - [Highlighted features](#highlighted-features) + - [Code structure](#code-structure) + - [License and credits](#license-and-credits) + - [Deep Potential in a nutshell](#deep-potential-in-a-nutshell) - [Download and install](#download-and-install) - - [Easy installation methods](#easy-installation-methods) - - [With Docker](#with-docker) - - [With conda](#with-conda) - - [Offline packages](#offline-packages) - - [Install the python interaction](#install-the-python-interface) - - [Install the Tensorflow's python interface](#install-the-tensorflows-python-interface) - - [Install the DeePMD-kit's python interface](#install-the-deepmd-kits-python-interface) - - [Install the C++ interface](#install-the-c-interface) - - [Install the Tensorflow's C++ interface](#install-the-tensorflows-c-interface) - - [Install the DeePMD-kit's C++ interface](#install-the-deepmd-kits-c-interface) - - [Install LAMMPS's DeePMD-kit module](#install-lammpss-deepmd-kit-module) + - [Easy installation methods](#easy-installation-methods) + - [With Docker](#with-docker) + - [With conda](#with-conda) + - [Offline packages](#offline-packages) + - [Install the python interface](#install-the-python-interface) + - [Install the Tensorflow's python interface](#install-the-tensorflows-python-interface) + - [Install the DeePMD-kit's python interface](#install-the-deepmd-kits-python-interface) + - [Install the C++ interface](#install-the-c-interface) + - [Install the Tensorflow's C++ interface](#install-the-tensorflows-c-interface) + - [Install the DeePMD-kit's C++ interface](#install-the-deepmd-kits-c-interface) + - [Install LAMMPS's DeePMD-kit module](#install-lammpss-deepmd-kit-module) - [Use DeePMD-kit](#use-deepmd-kit) - [Prepare data](#prepare-data) - [Train a model](#train-a-model) - - [The DeePMD model](#the-deepmd-model) - - [The DeepPot-SE model](#the-deeppot-se-model) + - [Write the input script](#write-the-input-script) + - [Training](#training) - [Freeze a model](#freeze-a-model) - [Test a model](#test-a-model) - [Model inference](#model-inference) - - [Run MD with Lammps](#run-md-with-lammps) - - [Include deepmd in the pair style](#include-deepmd-in-the-pair-style) - - [Long-range interaction](#long-range-interaction) + - [Run MD with LAMMPS](#run-md-with-lammps) + - [Include deepmd in the pair style](#include-deepmd-in-the-pair-style) + - [Long-range interaction](#long-range-interaction) - [Run path-integral MD with i-PI](#run-path-integral-md-with-i-pi) - [Use deep potential with ASE](#use-deep-potential-with-ase) - [Troubleshooting](#troubleshooting) + - [Model compatability](#model-compatability) + - [Installation: inadequate versions of gcc/g++](#installation-inadequate-versions-of-gccg) + - [Installation: build files left in DeePMD-kit](#installation-build-files-left-in-deepmd-kit) + - [MD: cannot run LAMMPS after installing a new version of DeePMD-kit](#md-cannot-run-lammps-after-installing-a-new-version-of-deepmd-kit) # About DeePMD-kit DeePMD-kit is a package written in Python/C++, designed to minimize the effort required to build deep learning based model of interatomic potential energy and force field and to perform molecular dynamics (MD). This brings new hopes to addressing the accuracy-versus-efficiency dilemma in molecular simulations. Applications of DeePMD-kit span from finite molecules to extended systems and from metallic systems to chemically bonded systems. @@ -186,7 +192,7 @@ gcc --version The C++ interface of DeePMD-kit was tested with compiler gcc >= 4.8. It is noticed that the I-Pi support is only compiled with gcc >= 4.9. -First the C++ interface of Tensorflow should be installed. It is noted that the version of Tensorflow should be in consistent with the python interface. We assume that you have followed our instruction and installed tensorflow python interface 1.14.0 with, then you may follow [the instruction for CPU](doc/install-tf.1.14.md) to install the corresponding C++ interface (CPU only). If one wants GPU supports, he/she should follow [the instruction for GPU](doc/install-tf.1.14-gpu.md) to install the C++ interface. +First the C++ interface of Tensorflow should be installed. It is noted that the version of Tensorflow should be in consistent with the python interface. We assume that you have followed our instruction and installed tensorflow python interface 1.14.0 with, then you may follow [the instruction for CPU](/media/docs/install-tf.1.14.md) to install the corresponding C++ interface (CPU only). If one wants GPU supports, he/she should follow [the instruction for GPU](/media/docs/install-tf.1.14-gpu.md) to install the C++ interface. ### Install the DeePMD-kit's C++ interface @@ -432,6 +438,8 @@ During the training, the error of the model is tested every **`disp_freq`** batc ``` The first column displays the number of batches. The second and third columns display the loss function evaluated by `numb_test` frames randomly chosen from the test set and that evaluated by the current training batch, respectively. The fourth and fifth columns display the RMS energy error (normalized by number of atoms) evaluated by `numb_test` frames randomly chosen from the test set and that evaluated by the current training batch, respectively. The sixth and seventh columns display the RMS force error (component-wise) evaluated by `numb_test` frames randomly chosen from the test set and that evaluated by the current training batch, respectively. The last column displays the current learning rate. +**For tracking and visualizing the training process, TensorBoard is now avaible with deepmd-kit.**[A detailed documentation of how to enable the tensorboard analysis is available.](/media/docs/dp-tensorboard-tutorial.md) + Checkpoints will be written to files with prefix **`save_ckpt`** every **`save_freq`** batches. If **`restart`** is set to `true`, then the training will start from the checkpoint named **`load_ckpt`**, rather than from scratch. Several command line options can be passed to `dp train`, which can be checked with @@ -528,7 +536,7 @@ Running an MD simulation with LAMMPS is simpler. In the LAMMPS input file, one n pair_style deepmd graph.pb pair_coeff ``` -where `graph.pb` is the file name of the frozen model. The `pair_coeff` should be left blank. It should be noted that LAMMPS counts atom types starting from 1, therefore, all LAMMPS atom type will be firstly subtracted by 1, and then passed into the DeePMD-kit engine to compute the interactions. [A detailed documentation of this pair style is available.](doc/lammps-pair-style-deepmd.md). +where `graph.pb` is the file name of the frozen model. The `pair_coeff` should be left blank. It should be noted that LAMMPS counts atom types starting from 1, therefore, all LAMMPS atom type will be firstly subtracted by 1, and then passed into the DeePMD-kit engine to compute the interactions. [A detailed documentation of this pair style is available.](/media/docs/lammps-pair-style-deepmd.md). ### Long-range interaction The reciprocal space part of the long-range interaction can be calculated by LAMMPS command `kspace_style`. To use it with DeePMD-kit, one writes diff --git a/examples/water/train/water_se_a.json b/examples/water/train/water_se_a.json index cb005530c1..969081b56f 100644 --- a/examples/water/train/water_se_a.json +++ b/examples/water/train/water_se_a.json @@ -4,10 +4,10 @@ "type_map": ["O", "H"], "descriptor" :{ "type": "se_a", - "sel": [46, 92], + "sel": [48, 96], "rcut_smth": 5.80, "rcut": 6.00, - "neuron": [25, 50, 100], + "neuron": [24, 48, 96], "resnet_dt": false, "axis_neuron": 16, "seed": 1, @@ -59,6 +59,8 @@ "load_ckpt": "model.ckpt", "disp_training":true, "time_training":true, + "tensorboard": false, + "tensorboard_log_file":"log", "profiling": false, "profiling_file":"timeline.json", "_comment": "that's all" diff --git a/media/docs/dp-tensorboard-tutorial.md b/media/docs/dp-tensorboard-tutorial.md new file mode 100644 index 0000000000..81d7d0eaa7 --- /dev/null +++ b/media/docs/dp-tensorboard-tutorial.md @@ -0,0 +1,84 @@ +# DeePMD-kit TensorBoard tutorial + +TensorBoard provides the visualization and tooling needed for machine learning experimentation. A full instruction of tensorboard can be found [here](https://tensorflow.google.cn/tensorboard). + +## Highlighted features + +DeePMD-kit can now use most of the interesting features enabled by tensorboard! + +* **Tracking and visualizing metrics,** such as l2_loss, l2_energy_loss and l2_force_loss +* **Visualizing the model graph** (ops and layers) +* **Viewing histograms of weights, biases, or other tensors as they change over time.** +* **Viewing summaries of trainable viriables** + + + +## How to use + +Before running TensorBoard, make sure you have generated summary data in a log directory by modifying the the input script, set "tensorboard" true will enable the tensorboard data analysis. eg. **water_se_a.json**. + +```json + "training" : { + "systems": ["../data/"], + "set_prefix": "set", + "stop_batch": 1000000, + "batch_size": 1, + + "seed": 1, + + "_comment": " display and restart", + "_comment": " frequencies counted in batch", + "disp_file": "lcurve.out", + "disp_freq": 100, + "numb_test": 10, + "save_freq": 1000, + "save_ckpt": "model.ckpt", + "load_ckpt": "model.ckpt", + "disp_training":true, + "time_training":true, + "tensorboard": true, + "tensorboard_log_file":"log", + "profiling": false, + "profiling_file":"timeline.json", + "_comment": "that's all" + } +``` + +Once you have event files, run TensorBoard and provide the log directory. This should print that TensorBoard has started. Next, connect to http://tensorboard_server_ip:6006. + +TensorBoard requires a logdir to read logs from. For info on configuring TensorBoard, run tensorboard --help. +One can easily change the log name with "tensorboard_log_file". + +```bash +tensorboard --logdir path/to/logs +``` + +## Examples + +### Tracking and visualizing loss metrics(red:train, blue:test) + +![ALT](/media/images/l2_loss.png "l2 loss") + +![ALT](/media/images/l2_energy_loss.png "l2 energy loss") + +![ALT](/media/images/l2_force_loss.png "l2 force loss") + +### Visualizing deepmd-kit model graph + +![ALT](/media/images/tensorboard-graph.png "deepmd-kit graph") + +### Viewing histograms of weights, biases, or other tensors as they change over time + +![ALT](/media/images/tensorboard-histograms.png "deepmd-kit histograms") + +![ALT](/media/images/tensorboard-distribution.png "deepmd-kit distribution") + +### Viewing summaries of trainable viriables +![ALT](/media/images/tensorboard-scalar.png "deepmd-kit scalar") + +## Atention + +**Allowing the tensorboard analysis will takes extra execution time.**(eg, 15% increasing @Nvidia GTX 1080Ti double precision with default water sample) + +**TensorBoard can be used in Google Chrome or Firefox.** Other browsers might work, but there may be bugs or performance issues. diff --git a/doc/install-tf.1.12.md b/media/docs/install-tf.1.12.md similarity index 100% rename from doc/install-tf.1.12.md rename to media/docs/install-tf.1.12.md diff --git a/doc/install-tf.1.14-gpu.md b/media/docs/install-tf.1.14-gpu.md similarity index 100% rename from doc/install-tf.1.14-gpu.md rename to media/docs/install-tf.1.14-gpu.md diff --git a/doc/install-tf.1.14.md b/media/docs/install-tf.1.14.md similarity index 100% rename from doc/install-tf.1.14.md rename to media/docs/install-tf.1.14.md diff --git a/doc/install-tf.1.8.md b/media/docs/install-tf.1.8.md similarity index 100% rename from doc/install-tf.1.8.md rename to media/docs/install-tf.1.8.md diff --git a/doc/lammps-pair-style-deepmd.md b/media/docs/lammps-pair-style-deepmd.md similarity index 100% rename from doc/lammps-pair-style-deepmd.md rename to media/docs/lammps-pair-style-deepmd.md diff --git a/media/images/l2_energy_loss.png b/media/images/l2_energy_loss.png new file mode 100644 index 0000000000000000000000000000000000000000..70fd38e960a62c86005477070f99556d6879f5ab GIT binary patch literal 228358 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

yjHZ$xy@KyHt)5|VCv>lq!5b< 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

g+i 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 r!6FD4>BkK(90Ph*ajT)as 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 Mhrp+-jAkuD*SL+-#%v$U8@^ya$ue zT6%kLd2+I1Z;5avOPp}i4J(X6sa97a`=v7VZd`N1m(jSG=IN^}N^wQ|SikA zk{ak7pjRFj``w~5aYei?`6S`8J8nr1aAHWg2R4ht5LSLXpwlGv_-<4^p2CEAa=+EH z3Em+~gR_ zAJo|2zqLQ8XEo=?kpkbx<`vSNRLE5w=CWRV1(;tx=+A&)n>MCe6k#<);kl}PlaOkH z?fyD>x3B}XTOG8NL`<%Ilcz$CarH#|s!zXu!e?)kbJIQzUpr%WQd_zkMjrLh!K-b+ z!uYN)593PHN^(tseLvixTli$;%>3{%yYa~l*=xRYE9}P+EIP%eiXZ{{oF{@s=5sW* zNaPcXr5Ru8VxPK73Fin=YHN-4GeQ)7GKo3#C02G(H2b0e>K{1*o0>dVKPsl^MDu^c z186veD<8LeIDJ!b3B5PlLg=#0dtC=D=#60Nv3g%}^-a!Q?a@-B09tZk!GR=oiP}44}#6UevI_My|7@JqSG1P1JR6)HZf5mTq%!qAepgljH zOWRH|>^tpRp_;JbosxjF!w;Rg7JHNtLrbR}{^~5~Z0gRd(oB-&$4h#SN}=ukIfYqr z=0q$kI3Ehw)yL#qJR6;vtEu%)SLDEvufbAEJxp- zB{6}XOhlH}d@|r_(x{@a=P12SRzHt%S^S%Aio@qkhg75mIvrJVf|-nhCuW&Wj*T>? z=c1j}OkVBF_N**>P{Km`GG)4*PX;9IK92wD8+BH-uO4B`(X-QFBduo4$koy77-!V- zVo3tu_5cxn+e_zBya1`$*zUF#OZ3?O5n9ZKJ4x-LOEjL@s&;Dxqo zl^!ae-}af#8Zr_J>Pl!v2@GtT2TMybiiL8%*X?D`)Ku-GH1$GXsQY^J%nYbi4K#)&&?#*R z-SLl)CArMuUqKdm2_yh}T-={Pl}cA^G17)G*Qj5^dZkmx8zu{TYw}HDyPV~+Y1o#s zUX<5vaIsg`Z;sJZ&#TtxCrTV18O3bWV-%`iy+#y*Kl^4NvU|wXsq;s=SWUV57`jVz zn8#FGv=Nb8 z(2y(OSLmW@GoPWPCRln*$J$o1VBNWQFm^u@zdPAc{h=2=CGrx`w9wxYIwS%tWvI=a z*e$;2?Jv;hp2)C#4)Y7xccGKd{*@HQ+WBPL{UhH$8pNN8HCA_`eN>6MF{eS}-TOg{D!nP$+2d6lO1b95g7V-&3}-FpDA zwxga$h|JGwntVv*b?>i_COmte^qtivmsB;5%SQZp6!z=Z@SYa*Vw^FfDQ5*x!6vmr zp=wvrozZ33izBRDC4Aq($^5+OM-J7#Lx%OB=ZxL~As(G_pJ~n1jjTY=VRp-SzGZIH zNoN7$$co(|yCtvtGY(={N#Z1N+;)2r;F;$d@YoFdKI$}ilY}(8%(DqX8y6{y>n>D;(}rZm?~x-H`K-s2*c<$K~<;YTq1 zGPkNVg2iAg$wMiKY*P*6V0Saolc?31nP<{E+;i~(l|hi<4pWT?mXu8hUvAiG~N|I z4ljlIjyR)HH7X+F_rf~MeHrR~1yD=x_-vo-%Myq%*TXiQ!lxo!lt)j^G4Uo@#5ie{ zsuj($l{Rf?b-3u1(Ol<#i!Y}@owAN(Hy5sWpGAKrq5#H;!Qx$s!pUNx5aZ?rwdk7s zJOdPvU}UwDkVxYcAgbsYucj%yJhkc}Ydlt&wFu)}F+7io5g$+|sRT&xX-yGVNN z=LxUx6~;O2DYdua_ACeQtZn1b=da1Py6C}2g${1L+^7R~1+>og?VOUBiG|Z|;^*yD zXB9HTa9ShgOItdH&EFpUdcCiwwp_acJA~z!0qGGQ)`7A~XCu8hoAA!Xk{>#U!RNsw zMvE-@}RjpIbt0sI3ZFJO0j12;1DC<4X3T{g-wYs_y?uo`4Dv0C))HtMikZ zlbxc+gfQO1J2We2NYz$(>MfL9gg4=rk%m z-l(1I%waoQdg)RKsjXoOTAu?Z>QTvuW24+g)RX-o{^{!|WGKrDdB*m*^1XHr8@BDN zy9a<3&?;A}y-^ILr+USx3X&aTQQWu$#Xv%lR&VE3Pm(wZd>B;8PxkkWw6R-BbgSN=ivEiEs<{Id-OxtJLdH^du*-7Iq0UF4iysbV=HH)X^j-Tdx z6?a48BS^S_IDnIbedlTA{Ij}(0Q=Do(-ezZ93STF#!rj8Q}?2!M0p&pB%SDn9k6M zafW0PegXY}5~w|U!#(_?0PVTM{`%UnXU(S2+GqJ;!d=9xRge+-Yy>Y?yAwkss+Evt zfdv=91YG?k{)rPt0!Q(|FRb|K3( zy4jj=$IQ!7WO4f&Ces1E8tm&0e3tqTw}_WnZAFY9OeWqSG#J(jcshUD1-kebS-n~o zQgk#KK&D6uv#SC{ZS_8ypD8E5zPesr18trA0KKySxc`x*)z)MThuI!7@i=v4eQZVi z$L;rAs3qKK%{tzmQ#>*FQdTtT!&0-&?u z3hXj-QhA5+~5dAD3y(S^lBKGZxhE_gzjl^&^H3Bbl{M{7q8o6&_}T zgXFw#YyI@Wdy(V4wY6X|#!bzjA(U7s;-qm$SsuuVS(g<%Nf#IQ5>FC#8vL-uxMc)G z&pZjQ(c2|vBuR(Sx9BQpIF;-hw92Q*m{hBN;6&$jn-pbgi(qkYmRpvfB8dubiHEB+ zL12FaJIpctMC?~lw?(TkS+`&750M=j=FASt9`sZg%T~eB=yUu+ZE4*obs2x)oD`?pdCcS@t7wa&# zDqpIDihDmi9w?RuLfIWuS!)xe3Yl(TJ)=fD)CdcZZiJ)LQ*Is1keuto$7Mc$#JGE^ z4^O0$P0dPACueY#z}goUrbWWMoc>7wN%<7N3|;t3TQK$&GUx_O$1=lMwq755T=TeX z17ZJy%)5#Ob*5OByAl}-{ZR+t*^yM)12XLzHSeK_KaaO){m#l@XJ_6G((AW~@_A2w z-bUZ(1}(}=pS#!fQG379t=9XKe4dJOdwbDp_DzxxG%G+}N7^cUbiO@C59T@>CUT|c zvq*^XxOx=p; z(oSw|1HqP7Fs&6TZ5R{wo#LhotlX44y;chvqVOWI^YJp(rJ8-a!D&h zAqD+@>2cuX{DcWXmeeEsU27=?jC=W*H}uJ4bfjH{D$vOx4Gv_>|&Mksl6E#Q zI)`CjGvp+AJ#4KsK(oAU3qTM+1FjyVV)}sp!;n#4_588uSmKH_Qowp|!n3Q#pdz?_ z)l_sP0P6*ruu`UVks>f>_H#ZosU4!r^KP@6DB)K7=ws!*xf^0n3gy5o-n z@$z0VZ#0sQU$hmr>_6G*;@<;}2KEm;SZtf^m{h+!{MnPF#ee;jA*i`CBS$QPaSybO z4FRWN0%xF(r`yy5rtkC@@P8wi%r+A2K!#{#s33XYY)cOm&r2b-QjOjK0ye`7kzVlT zn=Z*!J3V3s-Wr6EU>|+?1`>!W zGmFn~^m4zAQM0?){k=17svlUZ)AA8(i9Miga+r*41fL~(I2KWt7 zljeW~ZEHU*db;TzZGd>X$BXfpT?Z`#XjfGX3-l0VCq(y*H;t~9P2R_L5H?O`15$?Y znwSh}u4d>CB!d@i1`l9Mm3c!bzxtGzF1E1!^dc-n5dD-2(hp zUv|CaC%?q{l%7z~bn_zgZ*Hk=Qkib4NLzT#gGS54+E;^IKS2h>?U+Ge(WCmz82`xp z(#RLp3*?M$I|f?-q2+U>d^p|4WU|+-7N+K~*BbHz4fQVL?QmLT>_*3>tIW8uQ;C96 zEL1`6^;bbZ(muCMatMvX2LV);wR(g(eJG9BUfXK9JI?X`#(wSo12hUG!J%@{0W}w? z$dCU-8>4lJ66{XyyI^rwa?~*G?oGp&FF`E^Cy+!MNf@-xVKmEb-fIzk)!DJez8d9u zvbEBmt!om)Avz%RdR#>G)nW85yV)?j_DIu4MJcEdxB6V>aWK%@PP2#WbVmZN7-~E@ zZ<;Z%y6G>ykMbVYvS_9(oc9oroM>1(zTUDrdXj`3xa!Q~d#OrHi$KB~7KZSWi<(_F zN~Vx4&-zeJd!}5DyrT54vA2ADwN?*aD`MkKapjxDF#+TNvH$@mOrHaO$DOzOLJrnx)}f%7-z^J>zw-L)Jhz zEu5cUrFcN+N`bZKH2Dlm>e;h99AB#q*NT^mXO7B7H$xA+a=v{wT|VI+6X>4Jk+(5pVYTse-=St9c0po0(V2H)ySfWf z6U|Ibe3J&pR@VIdC?`J>2QKO1?c%Yfp?E^q{#bs{so40(FnzzQT3*by;1whkEWUsI z;TlaRwSb=2Ki0O;dWY|d>+*wymi>*YObo+26_}5rPy&}X+dZ0;pcUS8(O{T)lBeyc zm$xM(DEJ{OJ8||F;wtTs+^rhWUTHdfXWX?4h^v-W2^)m)Vfc3*7vV`wHvwZo^d;+L zRY)5Jr9<-7{s4pRE4y&ww)Udbn<4ZpZmPRQ*g6}*XxZYUnoZSn{IFnx5szfkM-2R_ zDMdINp~83I&a@pb-qfZk7it6X3`TST<^s@@P5JndQ=9ZFpt}R?;gsbQWPb8@SCG-b z{D^=2fe=fu?dKxyxCXs8X(*o$l?46I<2ia;`;Z&XY#*eYhClErVXpod`}x5)UAAeY z#MnSYM8p=fP^u7bRENJ)%768&nV*V^Y6PSKP~)m;OBhh49;w)fV8NL935tW(A-Z*= zZ~U$xv%O4E@?>=NnTRgo{uPaf7FzaoPt8GfI>^5_n_t0>lff?~rK1nPAUaV|QR_B! zBmj0{p~R=5f)87?hSCCQy*jsXW6;-{W}ONv<4+(%VJR~yiH((QV_vkA!d5lBNyu(3LR!)G76b_(+(`;dOFoOf*NYN0 z0)#S*fk$+$nRGtRS(~h#1ez6CLyedySm{y7IhDI5>5KR5He<@-GErn$DZeax-yNDg ztvSq**snPgTLG$lAkONjR)7i158OUQj;q2GwU+yq3?tcJ9o7Q+^X(B2S%8vJ1W}TX zrvASl{~uq4rd<*H8k)wa1#OuQP2e;_P4SDSN7h-vq>2oAiZs8EuQ&WV`9mD!Lsb9! zPYsR2naZ%$MI1}As#doRV}dl)Oo)#@MQqSVzd;OHT3V{cj#k)YiM{jn^J^azGE1sH7|KM@DV%=S zILZdzAXT90$%dVhgh-IL=cE6;Uw>V;t zRY4qHQaD=fa&1@*TLlDlseC_U)b>$FDqo@SqOFre;e^ON<5lEo2@N zrnE`|Vf@zDOQ@QxBZ?=BRMO`^PgMHe(~3Sx(j+S$ zOXDi#msxMD=8>XKd1FolLIPbFPjwqRixAsxBoUzE%i(a@)sa$@7=Y3>Q?lJ%O{ZwQ z%b@(l{Wj%e!{K|phx|@qt3%ycsV@q(o;{wpWgh-Dtki>jx112n{e zz{h|cP?^fqj`c@@PepcO`o z@@_EUNa|c#c-TnwM#2kw1okp@EDx>5W4$Kn?=N08tvi)!ODIoS9{GJ~j4pm!qN?;t zs|%B1+w$wNT|_XST)SwCf9BDh%nX8XO>ej-3P;0WdV0EJi@&!lXiG+~f5c0L+LSjH zX`6b0XLvq!kntsLZYb0|qgC~?v*P*-mTuEy^wUN}^(MIISQE&PCuVofC8M>KCSP_4 zIh=3Sn0WfDlc9xSe>;xJi_GHAH;YfnQ8DtoO>B8xdu{Cg&n66VkDHNBx;(?cPcPOxCe8Ay$tqs0;;_iLhl=IT&1(4yC z!%3B|>4LUI*DrGBX`n{}cWico&R@-TSZBRNGf`98Tzp$AnCoDZjx!Z?|0eGF^EDEp z^Wxg+Sk3GXestQ)SMd%h5`|-pSS|_@iecc_XL&N;Jk?X&OeSOqoW%@64JE3U(RQom zIQ7v&<)#87vsrk?6gq-HD(i!J!B)ll1`D77T1juM|pT1VSC^D(T!$zjY!o`1`6O*dE z-KXud6I=>@odDndQ{&O{CU%pyLjGZ1x%owwUt}v!cf5md=s@M2EKyt%k_~XK#^GOZ z!%u$hOFQ<;uz0hAYVX;UvPLuKGe|hl>?^cB(d<8vkBP8qD6;}cZ^KUWD2bzsH zR7!OvYO?&jylg~B3oHum-oe*V?)~)P>k=}x8meFH_hH*t=R9qD!QO5v3#BF|?sj@s z*0k$42I9aJ0Vdn;yX)iJ`PpqC+BYdvC>Ok4YcKSR`E)RoC<(R;X_s&y4vJcjj&TK^ z6RQrUds71~Oy?TPD{>PW3%R0XK-RwSXp&kRC>8&JVPjv#cB(i7I``LZusk_xsfnTqX3a_0t&P!;jiV53Yt z1?jB(RQEfSE{hv3z&T*9$ghv$CSx4iCFNQGrF!|%#=}7TJiy zr10^C_VHdEH{AvWr{xgZqn&VB{6&d*>!)q#8NiE5zv(V+cu%iJ40$2?Jgb1pL$-OkPvSJ^@bcqmM zQm|$)f+yQmfmTd}v@R?;bP9PH9O~*R27U zKo0^<+9e>>8>KMA{{}ksAf0^%a`NwM8`RY_121FP+Zn5VJ?Hp5{UzMi0U%e%7B9u7 zXgVOdmxk(ZFe!{r*c%{B{p0w1Q-g)yj9v5q!Jph)*Ww*(mFm~;O?J+-P9B(%MStM4 zK-H`^#LKDnB0`)lPD!kXB2=pFO8}|S&h!i5xGMqohe50yBF=5QYL0k#%b{QRk-@A& zBaL;M%ZXjSx#1ITg%K~~1msnZRF7bzrCw#Eb$4zh@nI@hbVB}aiS znjZ--&p}s}U_v7%QF}|N-y}nE&WgO^KzK311`=Nj3c({&-S!c?f`RcP<>xY@Ew+rG z_W@{Q{6WD_!lejtlV5~1C@9Edhkfv63vNu+tQsP^0w^M4tf@?pEIzsQrmdEi9oJY? zITmOu`ur5tmL^*O6LCyk&bH&%dc>GYfDphC0K!*-IlyWdf_kR!I5>jq_I>-1-a(4P zIU~Z&XIcZq;BlSF0X&8Qyk}o%MT)@$l3eePjY$vwyboxhaaVlwBH}2?p%260U8OHD zd-+Xj6(nBQ?vv~W5Ir@drrXWV?5OLlYOyUTMTJYt#j$1&v37ssv#Fj_gH>}|thm&o zh$zLoQaQ>!cZQHVV2`t8)BIy@VAv3it7UWh>?#&&d&SVe4WlBZwB+j95i3#-TP@UU z11e@EKY*ds1f7P6IsCW_zOd|WDy8}Q;4Su_a z3-Oh(ql)*+5_a#;2VG7hDz_`rb@WyBoJpnLqb%Et#oF-LkPXoBVccmkIxvPAe_58GwS-RCoK&I5go0@DQ}DqSu~- z3zX^4msIBX;eN3!as?~Lse`ZJg#CW>yF`R9-(aqq8mt*qj#UreFl;0hZoXiXc(Szq zit@djpzPe8u$sJ$(_9>5(3$m#PARW4hHWYBvp*!h!|*ey^+EKItn9a@mJr_08ZQI{ zh5%Y)x>0*xQ;DtY^#Gojm+HkvY5xQie%Gs=^@$j6_ny&5Orzgu#zgrh&WC+`QzoWD zC{j&1gGtCmY?)oSgrAx$TVdgT%6(5_F{%X7``-A%(P%| z*^aW#BTB-%ceU;VonSF>@nV2~HbGEs1qP|8s+?w8IJ<0c)5kmH*&rM`3@<5%3U3ir%l0e%sA!mz(Za=uAY>U3=D_XX3@>` zwn&{*t2sL|D(h2vEpkuCPS+#gvp|!S7d&$-QD+n<1}uR-R3>rATb38S0S4N5yBI1;ON<{e z_W%Mb!&__$MG|D;q*5s;Jv}{JaRF3o2Do&AQw$lY2MM#!D3RfJag4o*oqM;KogIIb zA!duh6VSs>60M}d0zlL41W+El|IssZ_6{N8O6D8d0{IqVZxv`bRhI5_d}X+hZ0yQt zS)SNgm#qtavBvq)Af&n;ft6Vw1S!W=ZuGDASdDK7NW`3 zCN-KlKkPZEw7b;X1hTIcMo|&c%$>wkZoja|WOPB1--8$7b}?&rW$km zrvmqCNjjl)jt1$pdi&h@DBdUr)~b(7m#})I&(h3oY2r>1QJ7X-J<=X&%ro3hjzr#Vt2Bq*n}Kz76=?C zierZXqGAknKY^^eT;Psco@Ux)@gv{q*y*^**)5RoRiw0cJl$6<3-t{aannkijL`ej z&RuaW!hVGwS+uQX27TxXr%(8dJf1?3X@Gx^lAsH&&S!US3g$jZP|#X@i@yQZY{H71RI_%THuc z0lLU5WH3Zh*X)y=X;j;diM8SkU_SjY@`pgEa}?BE46YB3f8AXf4(H2qiDL$<@wg%Jo^e0W!C zTIh8PNyRFw)BVOri0Ph3%y%3iIP!)&v=krSWxB-D8b~^|9&Z@xs5&5c=fOfCw}pCe4YE3!CGOF#vm=P0 zSqtNUZdM9rOiix~@?Q3`521`xyhfPuDiobgU3Z;YzK@QM4kpG`fA!ql+)OnwtUE;} zej}ZW44Dz)r}o8NT7V1Gbc=*Xb#Wo(luxW9ebyO7S8Jf?^=Ldw0&+2#MSSKkEm2X? z8nN!{NSXA`mLw!0K*e+`S7A-OSJXvM)iI+7&`~mg&fvO2EBdDUc`~aUlxza zX&}M)GB@m+qAt)I9I^xvNb!0Ic$qPBP9zF|w3u)MdPNQ(J=}fbD&K5w%*gKwi335z zHlTZ5(%jq}NNzS+=HR@d~!S`J#zZgI+2^R$brI?f7$gOZw9@8eQ5mn!8Q_;C0p6#<|LSyvoXLKK0c= zOIuer8us|~%c5Nuk3GaxT3azwNWpH9Hc7j5A$|E6%%0C^HxPLz|4sy@&X6;g6TSRE zCHdN|RIlq2^I0jWsq-;3y`L4u#eK!@p|5`R!NBg?PZF}Xx1Wj>y-^OBZaKivxti$g zKKH^Sa5*{Hv<2cl?nHYUXLA}rTd3wCrCGZ24`74V0MXGpL=m2rw+|v7yAVAf$jTz| zg?3o@w7)o@aq#mhu-!%=JXCoV3kaj-D*!IkNN@q^6%^m3>H%1SREh|RvV_)4dQ)r- zkYyMXe@rU4B!jekT;+6Jwh&C>AU+Lvo6CnpsYKIAI{*lBOy;v7SF2Qn4M}}q()|(n z8k!y<#$()<-fcimcXw(38M*)$Zv)eApVXR@G;;$9_~~flXdLl%q&bXR8h8+*kC&&Is0|pVKzuek{gfxlAIbXH0KH~ zU+X|f_k~Gy~*Ky{bTl1`K%djw%>& zV+_bWjLi7}z*?sWeewm2@bu}iqr&#qz z83$NH5nv51-ElW^-@N7pXeB!^b08!Ee?h&@fck%EP+^Sp4vUm-ac~|tKhh(-Ra;3j{ zPlh%prBVdCL5QAd$h!BfPiR>hwa#_9RYFjdk0y(Rc;Ax@XJe?mOSBMr1y^kt{ckOR zr83|WMHkUQ<#QVuuX#}8&J&A@m-3)<3GT?Vnxs3`n5ouGvB2RZ@bU{a*d zj;i>$e?Ka%R9G-?hc!A7{4`gSL#@xd!J^keR0as2rnw_RzwRk-39dn$KoGxCACRm6 z2HK@4QRN;8h$R}}Kj0M+Xse>3rI3T_+hU<|4Oy+(^SH}nLznn|_exM|aX;qxvHRPM z0Vx(}mMEB=GYmkZaYV++$&V=3@fEjtM7>T{?DY*P_z!BS~;V zkPBqhIhFxkQSTx*0nZ+`mk$uM)p()2sx5B_los?SG5`~jnHd(6(79ZQT*~jAJ5D$s zo2-CVZ3r-vd!`K}k8D8>dqlE*5vxmmNA>nLsf!N_&w#3nBPBpFVh_5okYQEc5*G>Z zcJg*`-q!jw5f3(o-F8)RP(y576$tGy&U=XZ?(8q%|FyyYe3=Ae6vMb3<>4C*G{3_# z5cUI(VGNuh9k_>zmZQwKsj&zP6iX|stCVvHfAtW_vwGQIdJXtl^vCINuQMgY7^QLF zIY{>Jl8|VGr`0I}OMVsApM=*GT*jNKZvlY7z|742>l0qT7+87vUq#+Eg@D8Y0$I_5 z+gZ!1nc;IyOPU+PLYEy*8FYbALnd1Y61aG5xCki=3yb;e$B!rHq3CDyT^Vlb^^J|; zi^7y^8cB6azt_qHS}RoEtVJJskuA>-hR2V~lU@eRT;eI&loPbsI*cCS;ssn1m|g-I z$w@#V%KZK}rAvO=ACWC&f$oCqH6&*(@b@eHbNT=LyUbKjqC#vt{LKFU|GvLJb=AZS zydq-^=emfUFLO};`F99eaB4FTtIg#vd)Pn!j;{a}pfc>Z#Fycke?P>(50+~tEr2@v zPt-Z-F4@k1f8W2pN*DsMKTeFd|DV75vJK(u#{tV}=*$$0`)3|;$##)S8H4@umUwa5 z>H610{CgV`3^BlRven{sU|jO)zrXKaU(u9;{c1=}BL5#BhYc)eM)V}69)tz|=hj^M zzc?yjzcgjL@BD9%lO7G0Q?7l(qv&5(=Fd&~=a2G+s`dpLiy!~D$N7Ko_>*~$hx~Oq z<@jAeA~Os%8i4v*$?B>xK!u8-f01*VX@NL0pUi8uvKobr;FOH9w zClj(n5bwW)Q1DAAkZY?{@p^(3%CLaCHCF)7#LN0)gl-0 z;@Dq(y)sQyduh1|t&a~0{;uyUQ=AwS5gG=6oo?`11GK@CzCO8#E3i9ve!_S`5DY;& zY+i0gFQ7|>#*frcUVFM`2I!~L)2gPXxx_qjbx>Yvbfw(E9egqM>kf3I z_}-w=E9QTNMC2ivZ76*NO@TQ8tds}h;lIA{QZ--pa~%KjC*?iZqRL(5lqJ04zZC;9Fb-;~&9u zAXTXxOGyoAf6$WCq89hHL6hGVmSzA=y{tWkBf^rx_BTSEu#8UA@pNxU%ayYXO#92U z3y!_ms6P#k+()pFxZi#}yI2~yYyyaMz|tvHg26#hBUad3I1%B+61uYBrGprPv||n6 zyFZ%r_%3%g>GvUP7_i}0bg^8Vn6BhP{)&>4{&WH7$t0)E4Chcz-`3W~?IS(>JN|Xe zd|(bTCB9ff9x#UY?Od2(Y!<=fO+D8?9~Zp%3k(6d**Z=ju?LxQT!ws5{c!+Mo4B12 zH6`URunJ?eKftsDa0<2W+;RWreJ05X@uS}H4TD9g29nOHh6>(RSFhi)eviG-+7TJ_ z?^E%QuhJQjf7l};%)GZR-h(FWE6BY}%El~xDp~D;{LLOn55EI&Rwc7w2>tg0Wl|+@ z?gO=NXnwYY#X3mVAl)z zP%CU-1#@R#A4aqui*mADyaYZ5O$Rj5(l4D8kA%dGsd^`v7@)W}0=`LIEXW^!ND-qL zDtLy>68*knG&x^E$pdH*)Rusv#Fq!4&aB4^l#N8L&@#{*U)*&$T3`>nu&J+2$HIuA zxqa9RnSEvTEtk4ZDQ4snN&6hlTMg2`UoxEtDXd|#*dPSddK3)}GqX@&xVVVN)ZeB5 zdH^jX#Bn4T5$j_`Pyr^~r~ZGTd06R6$Z}UQlqNY8z+@4$K4DitZ62YHchm&+nv$Iz zYpB_#oV7ymjLN(l+TS-Av$L}((_`Sut%CbZ+2OIE(2ls=e0}B<2#Vi&@cR(GCY35P zRReQe0|A)S4jTJ)v>JWU$0&)fMKn=fymgazn`AHKM0KshI@NGhaLVI~8!v$3pYB0#N;H3kg+}OMU`)(@=2`e+0kn zzPNV@1Q`10k*Jt=LACiiz*(gCfGVX7K`nuEKC{DA!0-uk#vOG`_5bhIJhF&B-Lw76z>*WOco0v->G3fbEV zzb1)sA4h>S=?n3a=fyMd+2BMzeC<|A#|2;*(3)ce z_K@l@naepSmKFNve8S+Y0eyjCFegvhepQ;w z55s>wqk9%`H$RWsE!8gn_5bzrrL-Ue$*jSKcj<}#B$U#gjxRm>{#ItN@P2T zi;b-X&gr@h2oqlbWPfhgQu^Zc*u+Qyv=6AUV=t(wsVnuSRojn4M!$GVa0V@YO4vG*n6| zs%!RxSqhy{m{HfyyYm_ZOKKz%frk?4WYKa)fC>Z#1nv6bK8L|z^nistS>3ER9<&xe z2m8WwbKYDVI=5(^GFv0`6 zSMVl5#9;(Ny}{JyDqyv8z^In>Hy*Y}XYave?TVT^chb(VzXdq&kQ?=-2UP=TRc|D$ z^Up0nLV-(xvx!kZ|98+J<%l$nn)BHYOLm~f$zf2)i+bcGwq=E^@(d^_u;!nGp4v4SpLGprAGa9A16>Hw4|`GY ze=`$ZrI3Ltg1MKMH=VZysGf2&4A2fIzuKPBFprfbq4Y_&|2RDm1><|v$mG0<389#T z>gc{BdSHr9DQNN{1T%#inwly*L!V@1Dt32wvqJ?+z`#}s*9D8nxYTVkef_d6Oo5=9 zB@HC%zby+YYN&Cd<#x3BmP+01Z5IcN_!1XDZW{YODHNhz*YvAwB9C^--X;8!IO9=O}c6TBU-VD~BSX#lEsciI+>LFvsCt z?lU6BW{H4=1bQG8{p1A3 zCO1FKm+fcRzW};7RrtY(7d-Ie&fjCE417M?B9RE&)8m^UxDe z?=c2VNDwOnnXp0KTeKYpswibq{P?4?J3%;NF4R+`?$PhnkXog*70Sfsd3O6?yVSMd z8XAn-Xg@{!Hg$qP3JHxz>EQVRN|7qhS_|T9nq1cbje!G(Xx78q$z*na|2+S*gZXsQ zfD7Y)KU2PhfbLxF#BiQXe-JN^vD$)bJ`9`y{aqp>h{e7Xtgfc~UzUMLjfW*NnmLkO z>uUWafy+fE2jIV4UhvM$)zsUAfjbkb076d&onD933IBCDXd1tUJZ`t6=pD-TtyenB*cZ^ zP#7=o1?qBz8amv+K3l4<$AaWr7W)4DDF$EofQB7H3UR*c(J?U#LTc*jHXug;8!|s# z?-9fCC{3sk?2MTxUWPY+zPS(GF0l0+bOeL*mW&>Bc~RS1P>by^4{;XP=Np?>M}sNX zAt=MttKt2hGuA);cHC%M8qe4zkgrUp%y$J9W)r$2e{QV)4|HH z5Us0Q>s+AVdI#1)E#kumm9MN>0wcMaUG?SznZXd4|GTanxKCF>I}QBrBlh9J1*qQ; zoUPh(L=_;I!mIG{W3iK8+L-{%g{%2Dt9z*}NB(`eZ5B2QdJ!9QQc<76RKrqb~pQBhH#cSqY!Dauh>$}g)7B=&&XF{dIN z@!hGj1xP$|9EGeCO*zX%XI}0*QJ;11MY4^91J{AX>EBG`1EL*4(8QMGBek=R!9eor zbvM-#0zkD_0>X;MT?HnzjJZt|A1(+4PXHS#l>PHP`^OXRBT4u%jE(SZ z_g{~nia0^;`%S=GQPrF%WT#o?L<3=Mb!g=1Pr>@($GWcu{9-DtO7FOCbzvl`?A#g( z0srPk);s$9k85gt0yj+|M;rJwDv3(LZoQSqtH{8(maot+lpC%`O=f%H2rt8=a}U>d z_2d|l{b|!NE`}Wru|L4s4&#yimfJcK06PWb(&nHa~S3F+rxL}b60&h>s zZHNR3SrG>c)r9-1GXdU$P8-gDQ*EjQxdK-?&OYu+NX#K>um18pF8A4=^z%Pn0r0KZ z*fyGwpcly!XreQs3XL{zh&$B*IOu;zfmO!>c^ zCAmIeU>^FRFhlj{?_M~6HmZ2PYuw5$GKjn8t8LZKx1TevE)*_4G&B11%u^vE^3BuV z1s{M`5twgwYiny_^yL}xAOChe0;?4>cm}UOx_9ZXAC`*yQ%flD?o|gQ6VB}KMLY~F zI|*te|LZ{2;P(L=a@aw6-!7@uNYrz&m@*I*Tr!tFM|*m#23l$J z^aVSYSy^;u2dNZnG#XfPk4j#2P(b!IFv$+PdY=I+`woGdTXiKureAS7@wB%)_;=)r z2;w<>M(H6OnvKT?cb;r)CL_;!D2|V3?B_!_hPU?3Iyae^dTN|4t?E6T_b6USYA>-Z z&F9So+%UU;B~vt45Jc*bG0@PM0b`SWQ3X6X2MU)FJHJ0PmvzGuID1`sn~u#)O=E9Z z(yAw0cqbNNCkyjY>hK$uw?-P3TzpRe`ovoNtV>V7+BT;EQ%8G+P#)HoDrdFQ-w=RU z>8sT^4j7k12?h$9MND3!A2|7#ZgTifn+-qT8H zrZVBUmhW&N*utIz^A`A^#8Fv+3R4u%A^TH0~0I?uyJ$g6qeMbq%6wrD6*zdQ> z8;UuI?r{S$4+U#&BhjyGP(wv-`(TAAwkoZTthwsK9Oc)qlhzpSxR?6((Q^|$bcFI8 z9~!(OmUz9#&;r@L{=+#o=y0;IqDBsVz}fe3*$H?aY5XsNP(49?IZAp-`soxJ&;s3`U~CfichZ?Esu{4~2=XCmIICaSm@y*Cr{2d|5&w z!s+ztTaKtH=@#HG@=iPoJ}=Zk(zJ-^1(?~~+=~ex+_80UQeyN9%pjXfr|!#emQ4w# z^rgySE`_A36yC@)sdMD;$A?iu<@G{v6eDnqyPz(Eg>bmh`}DJ|{GbZZkqlT&I0ZOn zH>6ZTx8=@8eA`g9k>_UX9u#^57!FR@*%k>#F;-?~01#SkWUAF8LGZ>ZupU4SP?472 zYw5)8Q1>2K3K!ZA=6SqzmrF*k_=I2hrn?o~y%#Rwt1p>~PM48Cr;tr!_nj9}pp-b? z#JElC^ZGNuYu2*S^wUf{9ro*3+_XvZvGqEBYHz80ll%Hy_;%5y9i9%7)+&&NQey~m zJypUD4UHQq0;Zi-q9v}hh9XjCM#kD2!B|`)uMG`muKK!Hi=3w9tyS*;)71BgGD~>} zH{kkN15rS1yFx%}mxRObHwwZ!vX}V(#fOz`3vL|^wB7q{h;4b`vum-m*CZ2RI7Hx6 zb&-TiPk)xBd-D+>WmQ!XTmszF;p()y@y-lfR_)FcaSa{7?fU$9kFngl?li~HYv}IE zc(q|k`;MsP7!A%SI`d9LxJ;&E>`XXs>Wbj#X+q{CyJ@KaA3APt%fZ2(dP z8QReG;L*XB0UUo6tknfFp*OfYq!h*sUNsSM`$(Ja@i%a|WY@?6StCJ|s#76|2dM;% zghVkHrpb4DQ4isjE4u|?@$+6^6bL(&f8^;VkGfb<6OnzGEcW5I8yZ|5Qodk4OGIEs zp%Sk0{Eho?zA0r_M^DN7?g=i(l^odTonyq0K5;s)j?lWtso|}3tyR$7$Hl4@$Ds}8 z)q61EBk!(WCkE5QYKluhD7!r4^lbJ9SlK|N$}GiWjS?w2KcEM6?uumpRSt~GPNed( z7DKsFF|sx7_1YQSyLp-`0faBS@5F)~^E_G3e&azaj{)qmciPMX01N88gXj@*iO5qR zW~}0NFPh~@;Aeu-8i*6&}QP7N8K zaGZAGvaA1Z`1A5hf~D)Rd%eWQqr^qlRdEt-j90E)f2rL$uTlOmZIC6p|L%}LMggMZ zrU*VDBC{&v={Q=n;+wqcLV62nRI|3E4+}#6J`?o=ZTq(vi8nGBu6 ztht&kz*Vtjfby7PQBGQA`BMH9NKnh6q7>NB3sci-6EP6?5*-%y4DcxBU_-5$wV-G4 z*j*m_PvfeKIN)q+JqkpJfKkm7_!!|&^FeuTpLFPrwGg`H02VgQCy&8%E0R)EOzLy* z>PL~|ZO;xyhMLNXHaK0>67RMAU&JjfZ8`zmHe4C1;RX6pzckMazl=v`j%keR6)~j3k(1y zwlB#8ykuc=I9FtP3QptEGH4xg)a2*WdZq6Bb|&We9Ej6-nJeE9xJ1FiBa1rFnOwV& zmE_*p%5|CmfTY<-zqEtQOrebVNpPe+(JonTqqB25UY-QZr!|n@aNT!xZUS80KN#%uN!^#tDvDU5oZ4T#azlDQ z1pC4qq+n#Ujg5oW{8Khe8A}7-62I4xleUkP3-`(2y-8eo2}(OV)AG41f?9iD&AuG}g?}t8=yg${R_QJ#RzR zMMf|5Bl-;I=q6-b(A+y1>qWlw#;q8yr3Bn?Af^vY8FyJ7EwPOOzKg1T`O8B(q2fp8 zO(_KHc0jU(i>J&#QEvO zQ}uZluSN|48Q4@fyF2%2!^xI{i(olRgT}Ox3)M=>lK)`A6 zP@&mrY3zG6x6ZR_Bj2@|tBwVTGUwqMw_3^GCs7h$P-rX(bW71|($T&<&0g}z`*hc( zPN*x~PefYRTK$`5>XU2;+SUFpr4W{rb1y1dnm7ajoT)OOAC{8$68{!X@RJ3i3%t?{$bna?;Pc+M#7fsC4i~TQ-+6~Cr*clu+^D4a z=C4`v(2A#N@q=KA!(!iA{R) zQ~H$dGqV!2pYGW+ILBI{D-T4n^ih06fqsI!lq+SbfctDw?c5mFxrx3J9ZPnnZ$ zWG~^<*fw!`R)PfsvP)EHxl>%YW;y*gU<6Y&&nQr7e@gfF%KJa3o(cnz4nd{}(h9op z0Eg?ZpaiF0nbAy4iAHOj2R|@%-+CN|nj8PqMP;IVHHgJ>CtqvO@8il3+`GWQE#tSI z!wZmUTr&?$`TnaKJ#?BDv)~~`1K>TunHgqpevgxfXT7{v(#91uof!_1!!I;|B01aY ztBuLwJcB3wyZAkoUiqZ&ZcErjaP$-10FF7sZ0r+Tb-7ajp15dNQfL%b&0N$bPOlo# znET=R?z8R%`Ujq$ql?5Un4ef1yst1HSiK`{qD>gc`XM~dnmt&FtF_cdrp9Kxh6xjL z6ko)lh}6u!-&&JbSi^zAr%dx%4S#FB#?`E*3t#x5eZb~QmisYfWl#T^9QBdGRiPWM zKh7R^8RMTPd*iEdz^_-yZCGbm~v2 zTa{pbbzm%pF$CiOLNNa4b$t}KlZ7so2~SmcXwGTDY1|4-xv%h z=l||&RjA{0L>gY#znq0_FhoBqV|d^+n)sSUn~y2eEUKBumQKvwDauXv1cuqGLIoD@ES+k*#V%c94Zlq;)kHJ zlK4*-LC~wC?lB-Q8XXimzah&ZY>x*E^n#>P?)EVA6gVw)|LSU#y%5ia9QD>Zs`Q_i)t4DG#j%=(^c z_|NlG#f`zV3m47DAjX)S;>%&qk*I1<|dVYV>`Ajiry?cP}@ zZJh+dgFKv9KVMhkRgKyIU_AeMBmB}Jb@eQ|lb`AJ!%^aNo6ZZ0JuF##7i(8$eRC@x zIy6g9Gc;u7dZycad!^81?x5g8o(D1&YISHnnHqutT;JR{I3giom1T@CC7t4kL)G}Z z4VbI2;~I#xr&j&xsM^}Ykw$z)&Rji*e>M^8`vXe&IC20k2ySPum!OeqME|%$899S} ztfZjeXu4(WvBobbHw4WyKAEP5zWXksZW54Vj!x7$AF?p*0jGDhUy=ONoFllHi0LuotF;4frcl-GplTXDD z4r3ZmGT6B-4{0@TsfMRTBcUZAC|0DQZFoP&JCw>ANdCCBU}e6?n>YR&dCImVsHm%T zRnn@6nE6xCvqhqK{IbDI)CDy$TE8Gnovgy+eSVth)gL~37;mGvPu?vGEjp#Q3p(`1RX=6(A4wWp}1?=Rqc#D+YFYgrIeHRji`ygKPW z1S{%ZZe+p{#;>z2k6pM`S>?OKJ-p$te7cHyhr71}hwCZSz2{Xp_fAFO^I|h(wgUUm zBw;^@yDR`Ui_F>0BX^}Il1iG{r(6$v^K~PrVH8~eK$Z&;bxxp_^0p$u8?S-IKc0g0B=h6P z#6%mtkgiaNU3$sA)CSERAZwdU>$y1=LcjQ%Dpv-08!;V*UwQ9kr@cZ7U=-})3 z+iXap?#_g!tf;_3Rp9nI_QgV|#Cu`E(VU!e>iI*5(lRpVoz-C!!LzK=mh5OS>alE8 zpGu-Wj2JiupGNotwVs1M zPDmJeQk7vdX$_1*E-s|WOXfh)XM0akA;a95AFc=>_YTcel`Wq*mX}U3c1@YY^kRIv znH`*(44dnpwbW1&C7HQQ$ZAjw7+>?Od=-Tm!5A|hOaOgI_c~pjH@I#MVPxKQz958i zO2oybEc*5LsR_Hf&9|caso@fQ($8j>?!zgl1rMcghz6LAh;)-5HN54pgOPTDC>xcI~4^f0O6v%`6cyY&ELtamfn=h&ORe;A%!9j!I zT^t3o212exNg??FKE&%AAyICK@(lDjqFZZE|8X#HC#rrz5@OMGe7sro1FvTbSIDFq zp7uWV(&kzQk&Ot2>g=sS0Ov52>d9_g^9N(Q@~b-HY1Tn2O?h@W$yF=OR*tIfkG!`J zxQhN8*9I6Mutu&nsBvF7OZY|grs#r3jwO6Fdam&FRr!xN4jJG$=v0{bS~6KjY4+eO z%!6%7>Z$|?NXX1k=ewSXVy^%TQK50l#0;yuK=|y344Ha3RVpDg%i^g>1X5k z<*0ItdP=f0O*H@xU;^PZ@MQ6+8*X!94|9%E_h#<{7*_A*f~@l=DUGS@-xrK3K~of0 zNU~5=xz1pT3wCm8W)c8F27)*`IPc>QM)!iuWsTgPlxw3vB8lc24E^$4EnDa+2mWfM zclH4dhcop9RxWLpP(aI9&qbaBYPbxHr0Guu|84rbpz#RuHT;PA!Vc*dh=`PugeqPI zU@vDdsa%JSn#iHl)LSG4_!NgV`6HFB01l_@C9DbjZH}Ha_>6JFmHdzLpJH-%j1-2b z3<@(j5*ZhKf!<2UZ7X2z-g865$sc*A!skz?!RNE2Z<$f=t%7}z@ms~Kr6+-mL=o2^ zqb7LB?Z0wpYZ|V~NF0SNJ^D+M@sGnV+X%w1iq?b5eyfEaeo`Y^9u6jR^K6`H54)X} zJG4k8SXv;d$r-(wCoYnL z01kILSNfOerD5a;KmTNOE}ZuPq*?8}5kyaOvkD83O%YE4{^C{DgTk}W3-swN3BAy(&oHDl2$sG1 z9o&{NCs*h^-2Fd1Wc`ba`9I%91qHp5x5NYfbnAVpBfL1hvWg)weB~h*njG)(4Ky6w zhwQEs{J>QOe_H`E`qHJo|4C)}lwAgYuTGY6o9Vg^EgpSFAvCzKtC`yYd;MA9|Kl58 zg{%*On2QULwHW}ySFZ{=%)L{4c+`U+WOZF+ z1u*}14z30zM}#;r})kLK9`>YO0@tyeAu7j`9BzI z22MbmhmT{?k7h@q-z=drBy^{y(S_72E8+B%6cn99FrmytUb*u-v)Zo|Nw9Prc>i$; zA-w5}7dp<)l@+#A<3Od}xmzPiiriUL)vtEQK!E&s9ZA;6%YU-c|DfG~z5nLfxz&@= zzog2vFqK+oh80X>W4sW@I!SLw2QMsPZhpR6%A#LZj@HtB&2Asf@WAzMFA1 zI$m+~uH91~0Q7jg;g=5Je&&D?n*fzO^_45nyiboYHULo&uo}MO0l7gBH-B5Yf%ZE* zLVfkiBN`ALwA;D+8e}oKbX;rV?GBX_DQ3*_HPL%zEYU;M-l%eXzFh*Q4CMRcfO<6` zFnz-6V@@m#b1Vb_&5@7Yal0cEl*$jDLBv!DqEKSVmfqw@S_1!{!1t z9gXoHGHkfZ&giM8lw5FhDQOP1-U?*;-~ug zpoS7Ogv$3wPvGPpYRc)>IORazMwr{zbzc(hS5c2OUK-C@3BLiHwjPAX!}bw{xvmbt z+tEoA(h(#vqD9IaF8A@#0;x%OZ!4- z0~7Y^ETfOsy*Go5tK@Gs`20rR4KjFO#RoV+>(L)Ii}fLSuEXUP>cE}ZjEieN?fk!SFT~))9rUw{wSpwWUsN7OP}?nw(9B(Jl6c%r_x({*FEy}v?z7!pNGK@8U?2i?X1jzKx6Kj ztQ-@tGXRO;2Op>QSIq8|Qskwxoo%rL(LR|nAaeAFlErCR?omFb)~c|&jYTP8k)_uu zDbA_?9v770kNZjPT?{ltwKnpvR4LwdPIyB?uq`>*K1d!Xsy)RYPr;UV&yhd)(bg{% z_W^Q;AFuu`OhetZafRZnK=7DgFei98L8CkG)Dv;gtGxou8KOyTs*F(wr@&+Vg3)us zM>H9z{io`&eJO898AJwwhd2JS&fht43^7njBZ4rRN5{n5d-t}BBr$4JOG3D*(sulr zMIL%I+50#Xx5wk+F{C7^{gG{zBhyQy{gymPWJh@JUa2+SGJefas;zC! z-|%JBXrbRD*uhc?GcgR#_9!(M{q37#41M;;jH+~@0-dz<=-;UPiOvpG)&$a3f(+#s zH6&pAY;sb^YojI2nj>577aN>m=4?oIX(OQ0?Ql_xXsw%V109@#A#didbV=GH#;TdE}h(*pFx0!ajDHikCEq*ttSgnjBc>GCzv0`3n)l};V7`KU7 zKKYUtihhbZ*@SE-PSYIQjJXyw3L~Qbjpi?;p_bdPw+7ScgLVqw|pEPgrSv`4GYO%4$ENqg#_1JE%DvN+T6E`2_X0gDS`zP{#s8n zV*uEmvPB4zz3(ZKtHnLfW7O#I;!+7-V ztxjt98|FPe1qa7i6i2Q5_>;45CrKUG1Hw4Q4Xfr!|~yp&HG_7))Z z7;Crj{`&np0s?#G8DAyWw2dY-*rlL_kX>aYRVPyjiSgP`99{#+zrzR~yglFWM9%h+qUlsSU%kL`&S-2FVZl7cZ(&|~l#8Vm+Zb9EL*`F4eh4DL3t5=c4xq#0s{fEii)@)^d(G z+6;j%L8WJQ)V-%|UV|$M+jYFO=W7xL=N#h2W=ZUx|H`(REbbgfd~M8^{$#R2()-kG zSfH!Bo78&f@QF-&)%HX^=RjRVMf#jZ9%Yz>6LxwY#_!s3YjbzG)@pJ=lUdb2_=r@^ zfIs}3jlKaaEVFw;$4T*L#!=L(Qem55g$Hsr{abv!pHWvgpO5scakEPsz744o=u^im zd}_LF-AOYGx5b?&CGphirx7+XjRGnnw*|LJvB=e*jl+)FgrPGxq)b3aF}Y?=b|BQE z>*OM3HKQ=UhL9=2hLCY1yg|HU&Ah%7UXMT;#mKRH3PtnD-Gzs+Z%Pv1axVZ$au)_? z!5~87Hg<2sK2j&G`pqp?dcqF)SXcT$Qv)AH1FAV>I*B8mVGHS@ZbbidDL?)C>NAq+d=T;-t@0s=)C zOZkRH{!c-922n+h?*w%xoF}mP_1K6mJ9^qh)gok_p;POb;~kuZfXk7ZsJCn5XR{~u zAAF(}g{w}BSDe3=^_2>XG>%VWLZr@<={x1qG=?wF)BTd&Q=LFBydKG_zpc-Zu)$XZ}_+NTXY8x38YPy5Um)cdE6Lr8b+G+C6Pt1uBi9__ zHyZ6+H3^Zjo_&vcKzOjB`#c=$I$PiCVy%qko;n^I5}XcOr^n-sdu#pPoLwMCKf|!n zr`ze7G2*rvwB?%D^XEdX?2h~^Rz{~VFYNFO5m-b!cfHM8E(}|dt7Txnt4!b(=w4#x z5`A0+ujM|hS+f1{i)&&mvwUdUZ>R@od-kLwMC|HM0z4T*y^eXXxJI0JBl>hJI!^U@ zbJWO5(C+HCRJAA9{p~j6@fDM2y-fdig>& zOW*rdjo7DJ-cYH@T>NW2uw6|QsvVkHiWIW6L-8dKwS)5>Q%Ia;-tgI%9QKDhvvJ&``+A-ehvZe>m_Z zM#0YvT)I{q9Beb`(Ns@UJrO>M!??8EC<+M)G}Y}7OIpW=IJ-E%bp9nAA|2zlkDH{M z0Bnzg#nTnshSQs$D~5BW;*K%HA7dnn{qM&t9Mn%W=yTR$J!0Ig9wD?( z^W?T|zD%g+KO3N8_55HGkZKbXE$qi!c=t=F;nG-RQG^PA z>sX-KUdFL7Rxo@9m$W-lxxueY&{%him-jp9ba_!>IsYP38&{@TXg?PfB0WQjq9mb1 zijYg73Y9kK!jT zS;h@_3cKGix;v0@6+B(H=@?qd*NL zs7&selRC^sy49X3pb9C_&}-H(S1Vg+QMi=Nmy8?P9GArQgvpEwrQ1@+c4ejd<0S?W zzJSlSJ94vhmHf`2a-%HM}Qfu+O9*UgJc+V>#lQodm{U`R#A0lxf14ybN3j^ zwUg*g8eM0&dnw#1Zr<;M5ur-_#y-j5d94{T_z ziA@jzV3S=gXGsT_MBTmiaN~@^lxD;oo71N~7x#}{PLtjgCXXW=FCJ;=46GP zcH^Op)y-f2XyZ^ATuy#4fZq%L%XZvu5 znaAFr{yy{M#%-Q3f2_itZJ?(d1+|5!4}DS=dMDSw#-4Iy+0T4z_pm_D1>=Rr)XBC3 z@xFRoVls$wRuU2hGdE=2aU81w`)}YNYw*qgDt!Y_NjaDuDY!6Hv%jnVz7hWNq}zmr5}Q%(ME6RBS@2KJHna+5(WZ}3~S6QR~n=iCPOaY zE~@JmL9ESUIqSRfPS<-go$gXfxQQ~K(JgUG;`%7sJ#;ut?rpV+C=>h~DY8%zbNW0_ z>(0Fl1Tjr_)gM=oAT6(|pEik7&h=|z3wbwFqZ1#pURH*fP)$wk))a?E>~uKUTY+Zg z%6H5UK1|4_Z#_LOLnOsCw}V`ZM9Khxs2%4WfU_C9B#!*j0Vv#*myNhZnlhdK#cH=j zt|b6Jj=mumH}^hhW`tTeGX!D5Zr}mDfQs?j6p@PuAOnh3duoF~I5*pl z_z6@J0g>zzR0FC?taz8y(_qTWY|4cFXsiQhL|i)GSod96XYnLK;b_7bxfw3ET5PeV zWi?!bT44J=M0{%DtM(tEA4gX=a};NTgGF~m#dUaGrz;&v24o7g z2PERHy2W_gU?XHCnmG#@E?3H`lZ2#}45%j1t4;|{)7>VQFA>Wk4{G%#Ls&Uu^2@wk zQ)x5YROO?|jNGYPB~C?#aW;JgcIRt{9c5Jw+;P==GmOS)Qn0ljltipj_XcO&d6Foy z+4@Twmf}AwQjPSJ(bC#;p*J#88v$1U#Zx21kR~K~iXX1W;IJ;XvSGs_89WiLCLlqD z#VikU!3}cip{XcdFP;DyO1Wc?aC-)$qu>|hyNLc~Xd5jDq?R5?XM=(Y?3WJ9@mHy6 zn?ZNz)HYux1Zmk;&r|O|FfLZt^H!(gbH@Iz=l!!p@*(I<1Lemz&-lzRt5l8j25zHv zh<>-an)-g0RsLkZu6$~a*-|SbOmjpdu@37=iC8vXpU1ZXTa(yY$g8#3YWC=VganY8 z#$u#xX^|RR2`rIn(oAQcxEd^HXoj7W(G8(CI-<%bQO!SKG3>TiPAIlT?6rMbe?8Ot z2;sFE(3uN(C$XbT_UQRIhf&I>Y{U6_%OTzR733%hjZahp4M72F%TywDPWMd3JWG7~ zlg!g(ZoS(eyWCh)?&1h8=_l*yYBL|o|-RmTXK%Ry8klx;IPF*B|* z@JkDdNP93*wC*@uk;IjPnl?{{0FW|0=Y#P<$Y$zz(+%u54_M>X={k`T^h}q#3B&1_ zMFK(t@b1d8Cn<-_Zc9pYEh(cFUZJ9u*wIO0_eIHD(_Gw0PEFl#rO2 zifDhCBCf$ypgF5DPMIM}EZwzdk;R37wWe_3;*N2wsc!E~Y$ngBR{aV~f4OFDpW$uy z*-cDphCB)-XHcNy;?bJAim?y4M=tv4-NoK&=HqpeMD0R@jwAB*6m|Vslx?R8TkuCD z8cIvMGQvl^0lcyDrpu7%9VkFt3!lo|5;wMb-|`MPd}H)iP6qAtR(w|yX{|^hbZqLV zzr;iaE#7I<>~a?J89K&>o2#v4o_>2Ofv?#In+GIZnmS^+^3{)+(jh%{bL9!`4rGS) zIN5B6$`AyFgW#a>q?;GW?zw@SYNXet@pwuW&i=2pV)KD#$ZpOrue`VieM&DX-(+DK zE>%h@zOF8A&n^?mJ^wXKishM=lngjHqUx%ACDkyEFH2YqGzgfpwW7hUi{=> zamxEJ3(ICk>aQR%Q}0Gkc!mKTkU?MRdK^r z7C{7AeWi#jl|-+kD(NNLxt){`_utV=_<~uk6>GTEG$WZP<1U3(AyxPk?neyLPmCJk zjVNxh4RwM~&y;i+Aw{k8nnUFw?%3?q1M(5T8T~sw6}&R|Rb@9mg-ZI8RcITyTkK6N z)M!=T8pY3sN(j^ouafW^_!l!mDUeX8p7UZK(*R3cKYC{+roM#TNBZvb2LZIzPC!(8 z`YQg#cqEjJDWwVgSuX)5?Kle<1+u7>$AveK4(vffc$_$GtpF)5_%7<j=T z`2K3kCM7pc_7xzlcj!ku8shjc!k#R)keX{wqI5IiJ)*0ISpT&tS+Mzo%{G|)SsSn=eu4hkjeMO zQ5iIz@WZVPkSoTo;3Sp%BaO0anmjx|lZRgtLd#kIMK3Aa)awR&^|sb_{wm3~FF09M@We0ZC+&L04msCJ7t(A?QF6NlN}j$s zlP+5u?B$lXW8PX87W$FLUOzusFcKSz3$GqBW zPs4wiEnbjLeV2#$)w_9&9k%*J`TD@(>B$aH!G8~Bg+?~~P7*1FibwBO-D z1o8YqY?mArYbaRvpdUf1Jec-@PQjHP$6^}N3B$8nvT=3AJ_g(%$yA+Qg=HpazbjDe zp>vNP$6V^qjBT`s{q)1K&#|Sd#L+euVvOdIu>x;#HBEb^^}XxCt5KZVBF|82pUu;j zGh&P!1a^tKyBL$(F5jS4s5-b^r?fFnQ%l%&5yUosS;#EY6oh6A>V z5_!px8WbYmU6FsH*fMD1DOpcZXv`nd1eYa9zxl?FaVt~2IS6a8L5pf0UCZ!7QPpVE zU)hH1#pHjpe)P1sw>hA6#5St6g*pKb8x<&W+_adk%!zO8|2&vWxq#9wU6`nLsjZ8f zXR}Kf{!IMv9@&ec?g_#5OH;i;F&r;U=^c7WG`Z&^Op?xQDoQHR_>&Sdm;Z5KrS=N9 z)pb$t)YnR{xV{ljG|}bu7tm+sqU#Bjy7#esbn-l+G?IzO| zWmozK#l2Un*T*Q&QSq0S-dh_`mOzkQKdgR1RdFi27AI(zl&3>yaO4-zs7rk(bkHdN zaoFL|YF9-NbORMZm}xQ^g<65X`wp?S9=aPPG57LS`?(RFAm^Nv zM>w2In)ON>LyA=*pM0L(CUJ!gCh1(I`QAnS2dopOUzJZ&MJi^kYL2z1-NO)zVQcrm z9Gj3c8-UTC5wx%*TkYBil59VBT-xe0WTmmM=HM6Ddyu}~XRCB3mG3Sxjy}UV=Zbp0 zikI2T7eU5zb*b4AAH4DzjJuFKU)S9Bt{exC!g?>lJWZOu5ILWyn4*X0SuNQLpUqdW zJkiU#Rp9Mb(QAd{G@ryA_P8WGd`!kn5%aY}K7@`COi};qZT{<*564(vpGjZ!mU({} z+S@lNH(D-GxU>CnshW)$--qa9mmEQYH9^Gy zWba(LH0ESQnNoF&iFb_np;nQ>DvDL9THf3`Ua$}ms+u_S-d61VcqD3lf_43L0wv7X z?#@28&AlkRGE#6!6QwNcu+YIynsDaDz|jyj)xg13eAYrUsw~0r$l$n{3812L(Iifm{4%B>^M+nes=D>Tn*xgasE4%$| zRBE6WkTr@58l`WMQ9geW`vA^5q{}5nw9v*`~%IfnQ^Nk zeytCV?J5Ct_F0OBuIS?<9y$)iEz)J++SnBJRJNSq!_4 zT|6}pAOAv0HFyanLCbHEbURAHq5kbJlFRtxwjk$&4fd|1L?ic)jpBQ+;drM63?OuC z_iwBo=?J;R0a*ywAm*DzvWWfL1nxMrH6sVlH`JuSPG;5fb*y^jE>a(}*6gwcp6A!z zob9UnW{Nmw4Hjy~#(i*k08~c7Djdgx2%VNP9Q)!nU^Bl(lyY<=E`Im}v-iyy`SUS% zmhGH(v_{dRMbU$kS+rzSRB1b-vWxOpN0t;S4lvX@2&@Cw4~Qa;iJQKh#BUW1!b(;Y zYcjc@Y5zG)CC|BXcJS?xzIEfma*B}sOnUu(k+RK5h#2-rW%!xPj`t4z;8>#kNy;L> z(DAsTtHcrM3RY=B(eQ=BLL$YU#dWX!UFEfs^GW0x@XZOT-H-iuJHpjU{i)xp~nHQ_`%Pg|8fKFwGM4T*s_Mpc~$edRtICgVIA`am`Ko zzDkfc1sr#1;4t|Lm8q=Ty}z&EuNAjFGxq0+`+uLx`DAFSJQaQU7W(~L6pMoeMcv6_ zL%(`sEfr|GOPBede^aJR{eyxR*sOG{t-Dn`sx=NIeGA1L0~zPADH`|Ej84*Qrs}4X z4!3*Z&jSE;sCTs2T^LHqT9zm!$&l0}w^C`CF#4<)>*R45D|4qpmrihcO<%Ca=sam{ z3y0V3Uu>%;8pgP<45mAr$~pkUb8h87H9>Y#XC%s5^tCu!Pt4V=-?IYv9Q}?@$Z{?>h29n_rSRHUCM_zV@Bgo-J5m`%xsP_8wdp*CWR8OIX9tK z3%na&P()d87|8hc7G0sVGTgdckkE7g1$$AbKr28eO+e^MDU?een!mK0=>%4Kj1P)~fuf8#}8hEa<_SQzS0K($}@%7!$Hu3$A574&H8LUS6V39X67d|HtTt+dC zJKKVXw4h`p$!%gtQ|}{!Q_!REmdu?V$0eaD%!KeCm!0i5hos4Yk?_i!%_~+x? zBRsSetw~q-v(~^Etxt!vI8|vDm#P{60w#fH3^nL2!Zc0E zeP33JRN0O2;hGW#VW&ZXqF!o~O6%m8@HqZgn!D&G1cuR~S9~kiMz410hSv{atLaRX zqw40ELZtfetu}ogFwXu`^S4MGSO6VOP;HeyWNX6ZDkaV!p0ZofUnBqbb9@I#C@H)! z*KfZCL*1)!LQm}=`6%U#r`12gt=7_GxJ`W)J~7$*ic>IV8xRn*CK)bKPs~N0Ne62) z(^=VLrFw^8DPPn&D2EZSU6oLjyhKb#wTwRfK~kXI_$)<$HX>QRjpy4pA#+g|>rI~R z2LhJklfoY-kt0$9w%@ucmseU-A_W`-!oH@OVXR$(2i6>a^aY8H1T#R~CF`V6WYl$v z*X9omYxdE~?V-DVS4s12zvPskX=<{x1?zRi*nO}@l&~>3R4u<{)JbFMo~$^XU5>|A zE*X2iFjl&;?gyiY$*ym?-*E7vD-*$85Q1UpFL_xY!gBsYB}0uzZ}q^m$I9ts8E#>v zw)&{87N{XmgS|_U9n{8*Hi3t9FMtvJu9q*}3y|Gc+wHe6268p%K+8>QON$?7h8Em@ zpDnIj$h?;KV$3SBh2G_4j`nyzXgyx-16x#JYRtlx{mxfj{kx8_=wB~HeFzzc9iOs# zoMMvo#gwhXKF~AP&G*<`+M2{IVulesz{45O@EDis z)p`enz)SgL=&Pw8KU>+=nb8T_ZL0-nlqGrnadky8#6#;B2(Kvy=-Yzq62%e|IN0`D z7>abtsMl7H^w)zlU>eRR2fQ)T8JVp3zW8!~V&O2^2Wl!Oy<&}(?(D&mL(DJ2%x?o7 z7PH?4Y1Ly5z1WW*CvjdIdwD&ECI|kQ%7$~j#og9nW<__-E#30ya(UXh!1s>;$8 z%h3=d8}i398i%LC?mO>bvN|*M{A=w4N%8W1iLE^3H{#Kjb|X_K%}>KjO<%gM?TM7g zoA$Qh6`wcN#TGWU_=z|#FpNmAE`v%8CZ?}=+_52pOU22~tjf-kfC2&a zClnvZHV02}cEX^qXztX&k-gJ@S{a zznGrMM{x*Gr3Cgb{FIVW3}HjDBOI$d&6SpwZ+$rR!nWTiQeO%CW9N%W(ZrEvyv-cx zg7Bua)-R?J<#hY`kFQcfZ2dMlFt(;Wa{pUP0n z>JSe4jo|(F2j=q_%j(4J}a%mW4 z$ZIZuN^iCnIo#VEVFSr6OA4A8oO6Y@agP2R@(O$4cox0*7ZWfWvEo(SvI@PL?G|c= zC%(!zsf~VBVD7i;BVu9=t2?snW8)v;%J}d-O9*7g4eYH=#7KSnxo_M`84Gmv<6fW$ zcvavlkaNETYogP!+je!JjDNQB0CTovF{fM@H6At#S`GAK2!%$52 zecnE7sC1IzK6Qk+lkNU>E$#FFqwBi^x$e975oIKsLfJbsjAVU`kQK6$RkBx+omrU~ z**lxEvR7yjku9=EWRJ4<@4Rt8zwguC^N)L^&*wc}uk$+RI@h@_e@|Qq>D7{*6xmN~O}%mS#-i%UZ@Y~a8Xax2{dl&UjnR3q$T+wq=4wOa#XH2r zUKh2BS$S}CZF$X|^SE?li2I`f;@NGzEbmEuCmsf z<>G%UAR+(e#=u53^=^EzKyq7BK~LeTu7zxF(GoQd@;gSK(Zkx4bQ&(y?^D~c7SwGq z*wp-bl0m>8B*LF}*L20`RzXBFMdjG(vo^|HnJ=%NH+EZa*`P@rSs<=<_&tHMGZA(x zULSGoPWR}@P`e2Md)_^lbM0(S;ozQrYFV>A%Yn!r-(A}MjR+=7Nl69qw&;baHt1yn z6d*RIm$v?4?bdiVu%%*E`d?5BT~V)dUJ@&@pU z)3Do3FyIf8=!ulfBAkk99^TFyOSh>Qk3D!T)8$~RQ(#fUdFNVlLa+7r?vn&n#UC#( zvuM9ovF}H(Fx)&t4cVGqoW@JOFRS*C+7g9r-?1gYw7mnxb;QHX(*LF^eMci$WyRA< z#(^$S3GTO*TZ~*d!S80J%$90DoS&Ci0OiD~XB;nwJJ;uA9e)F2`yJtpP>^kFrb^+5 zo$!CgY0LlwY-3^P)k^}IjbENY=)jfM|1ucCcaUwNktFqcZDFuEfPYA9OiJ0gMA7ke zH?!-dPxz?URe3cA&sZK`JXaRj8E3bDEApBFID;-S_;9!fb`=0oUVxILIzYsxB$QBc z+<*BRknC?_UI8%}ZXG42uFA~R!2Z|kgsXA2;Yo(M-==R@ zpFeOtdn#TdMwP~MM5{;v_fP-gKmVE%`M$5u)mMx9H1%O?<0B4_S-cTN;JXjR!VW>j zM!78mx!CzCi}_V+ln-$H*m`nq3<%wB!4|I$_qK1|a5Iw4zOBo^oFSF>dSR%lceO(* zruHTuxKUBBF+K_TjonSoyiX5Y{F`Y3r!^hGy65Xi^b^*;$? zkO9`WPCr^TmWWAvlDMBl-6KfTb)CJN6!lY6`KYJbUM+d&s$$+>#JhvEsyj(c-Vs-@ z?oPq1eMd>yCFwXX;#ESzEECM_(=%o_+3a!+cZz-4WSazoEjk*Q5?7?j=Gt>3Y|*}$ zw`vTzfe!D5^?feiwrtt%s5yt?^Mbtixi~ce5wfnH5`g31Qv2QdB`y?-*YFomROiQ z$mun%-4gUAtl6 z!!QD6q0Kor?DFu=d0oF392L3}U71N)>eb%7W}P`nX3DO$X5Y*dHIwioWs(&NAO4bl zn>hTUl^gUnEI`=4F~8|fZKeXF<#kgA?oIpEL-lb)P-7pco96wEhzrj=Xw};rA{t2G z1@+Bst68uA28GT9wMwyHmckpPB*hUc7O)$8P7zzj=zRMfP-v|fWXFkcF zOH2mm8pr0AdiR=bAezL?`Opw%v0}pE6(d5%n}$ApImsY7!ZiS^$DcAN>^T z<|%47pSvXX+|!d`r}M=OCXQa6{noseE5f821M-@JW-U}8n_k5-7WDaGPVb<9En;M) z;?#e3^8b0mDG{jBV3*>c#7F=1E|pR+SJ!ig6I(c*IQYF=Y__AX4e^kqlC$~9nj3QM z2SRPkWBzd2#P+83bq;WixXA*yY;Ir<(i-b9o7%O%mhWD{pUgzxLG=SHi5{)(RgOtl z-^?xMf0G?}+4A&H3SxUk(9r#LvpjjlIML}d;s@;ll0!OO&_=obs{tl`f7a0;6mF9E zciLNT!8cdRXU6^wO%L(96vy zJJfATPG+X+!9-u*op*GB9BWa!iy?{$J^MAk)9@np6J=z5Sq@E~;fE(;?aoDAT<8tM*{v6#|n30Fb|u$NH^z{F57Y0kt@I+hqm};s_LZP%k6#UQg3%@`^8+LMr8h7Bet&{MayIA+ve(JHJTNJV1)CDs zgeKy{^;p+@wRyef?k;PK%is{DTt>L){1yUfGMjWP95|wnRgrwGZI#^yTN$(_zn+i4 zIGmmm+V$ySsjw5;7_?nn!om?@LPX*4|p4|&H|u`7a5&cnV-SuqsWErE+`HN5wrIK2kZJk5fSI3mEsR<3Of zlzZZeE;H@zkW$w1jRM^>lvydg>GeU`vy!~DnH3=-?ER{{W%dd9)51LT(Lg!;n7(8N z>3H1^7LH_h7U(x9@+9+Il>MPb*-`%J2fbj3NkXX7udrJp1$fZXE#7{4HX|tnTa~SA zLX*ieUGf6LrJ7SIQ&p)+L2c5X_oH}vzxiFyL%qi-Jn-r;Xa%1CK}LY(mo!M|J8yp1 zDx*OXi38yT7$s((EBs7W_M(le6;MfOIMf0*--Qd!BAOO+M}U#{%$t_ZlTW$$brEP4 z-`*zLyUS@d4+l773Ttk=5aYv_hEJ5mF#?e=WvMF+8H7DhoypVVga%lv--9~S)OOU_ zDcET1kb?@{-vh4}mb8w6j(+(S(fzpZV}Zp^87)E>7)%ODMi#m43rJHqnH>> zDB8`XJe$ck%$eCqgvwq%hz!X~7+d?~N7wd16O=#s((ke5hAcC3zmya+2<`HY7cIWP zrVyYKMrLgB{p|-x)Fub>82QvP*GQ5+AK83VHANUeL? zK)Bey@*P-GSlzX;lZLld~WuN3`oC4Tr^Q2?@lFD|Z z@Q0Qt^8%u?(erzz+(UBqs^)rG?OqF_UfT6D`QUS<=x|yZqlTL418AKt#G2~<$afbG&5>Q8dY_Bzxt{rfolK!T&Rf)PxulMJ zBN$9UY%^^nIs!9tWIv1^_pQ|v{3XQ%5e)2!>MG@7qoyaw;*`AX$s9=a zOsdwQZLwW|g^(2ou629uTY9Kd5?>?AUyT9FDJ<1%*mk6sf@FS8P3z(UlzCZ3Wdum{Fa{p)Ktn6E&{f@YH#5~X- zr-dWk;-;Kj5g2%M+9elbK%lK~1vmCmILvy&gN#?FJNV4HSv54q&kSvh+}B_bmUw*{ zVGos!{j`3(Z7`1Q8A{(??)Jt-_45b$<|ZLkmEcJM!iO-=*FP78^Xn#`<0#?n>u(XA z-P81)l;6QzNTV2LSy`}84|C5~Y{NW4VD<&=Ft53&T1B$r{mE~`dIui|`OK1Y>*U-EXJ+cO>XNGLZ7O!V1S2q|C8PGt)Fu4 zDJxT7mxoDPZ4TBiY>siN*V{Hk14qcV!WU{?nBt8Ia-#-ACqGtzF+lI<^Mj(iaP~|p z=aucOsNW_qbHhCLbo(p-fpb#UIy=_7*!Bu&^mn08St91dW-d4-1qRTxj%USWJs2FBQoX0>4{pFG=EulC6mf* z3QzdcfWHqW)AlVg%BMYf%OQ?8=G2w6Q$*Ivp7w}}GVWdjkU>t3L2;!RBA)0XcWZ%PDF5>v}yb^-%TKSKPKoJ=x)A(U^=`8*ll zw@WL7Pfb`v&3%}1TFg>layR&5oln)Tq+;?zCQjC0-$g@7%ncKZc7I@=?7^&j(F@{s zqb0lp=Z|O3w<><>c2ROzav%8CG;MND-HHCvQuYn|c9K5!nw8w8yEfwMTFJcgNbWjm zV~1PG@>*%89Vlu)7deEZdn!{TA1dJH>Fvj=w{J&jAkVW@L&v@4Vv}ZSu7VO8v893W zyMH|u4A z;siyv<6KWHIO8Wk8Wni0Vf_9r0bL##Gsh8POluz~>EHb=F{1z?>O*lK`aSx~AEml5 zXxtCz3Iqo=mY?k%1eUs6aSuN5JM9&Y{)`+Mrg)Zh6v=k>G@hkO@`4S)+h(q+i;Ow1 zu~&?O45K{UtmCgaedM#!nHt^|b)JZ3%4CcjLcdyQBc}hUza?@}z=O5FWZpt&VC{5^ z+#<2f9T;PevmC1Y7Cw7%`WoF7UOGjGFd#Y6A>V&J?u{5dWCYp0Nm}F1U*F%RuyC(5 z!296aNg_}pvn$}ZJj$AY{t0R1z@GkZ2q6=kXB%gJrSQR@d8#lZmGQ69EcE7$%zu8k zJc=%try&~Nn%sTz^V4QdPk_)DR0fP%RMT$FHtl613PP zi%`5l{!3Ogg+INdAe~Qgh9u<1KFk6JZ>Fx+;z|+Hwx@}`$rVv@m6~m7^(GI#;X3aYQQv)yiLV>qPXwGs7ke(_2vb6bg<&sBl9E`m zDOZA?@H{a2^pdst{FkWM_7f+Xyf#xeD>@nea;Jt-Xc!@dJ42Ta)8`6o9#id+Qp*v; zs*U-g)Wqi-ANF=~tnPQ3)|$p<8{pCs(mouod$iL};tpBWKm?y<=Xa$#-yJ%bd0|SFFD;kq{j(Gqg z&CtZg;_y_@HAz~sm64Bq@oTN;t1S9HMkGt0UK0J-Nm+)ibLtl3^fj2NZJd-iqanr; z2xfp`qsnthlC-ktQ&&yIrUHROdA%$oiArtxT>L-9;U8}`=^8dI8rvEFRiG}Qk}z?K zEjqd@JgC1m@}y6Huf96uLc-fR@W7YjgYt6LZ&}pLbH@E^qkaLTICgX2)ikt6tBG`k z+t}pL=#2?R==ILf*hFD_U;OP#<%%N~?k4#$M8NjvwNpfvIiMBsapJKAQjEl*o-97C92HDOlse%@_y;y}(=dDU5_v)(CZ-;eGdgn1D$cz@a z?%1;|e=oCsC1*>Xles1*E`@_yefd^-k&gHYOx+3U;?|NVo__82cX9(dc03sIp<2oB zY$GZ4!$@q^T&;SoGTEY*yY}DrPn=8StccPzn6i(0BN0cyd*4PY>Q(x^c1r;Uz_&yO zitpv->Qy!QUFE5E{^F;&OGhLlM%UrOa^2e5mI^j)^OQ!g#T8x6`sd zR4t>M+f8Qka#nA}zG0%Yz@0DEvgT2k7kmh4>}T}7@F#FXBO}Re@Ra?Ffp9lK)K;QE zHzotwBjFXSs|TL3!W!(o#2<J9jQ4SR8{zwE6|#$OL`La@QA=r`f8LwdG$c>)Y3jDQMO41dYh#&N~ z1)xNNAOqKZK>=-05N7VJz98(ZiEx&~PxbP+E2v<(@8RZ|eyDue1GLDeb9zCiY>~J1 z?=w_s5!omXdTb=XTx6&8jL7aCD9-;WC>`R@=kW9HF6L||dg7; z4!9#>Z>eW>S2gOmwatVDl7J*H!v`e*Oinw zmDOvZsIX9IBkZCE*A$UJMAjZO)DkYG0fyL66@U$>KH7(yjdXV_&60D6mrE>% zD~A>1g_QYDer8SaLOpd3%(>CU*OO<+5|E$p@Uwv~w8}WafMboJfy3|O?()#v-MQr- zNcl^hTYSbe_jDf8j^aCPM|s&XBpKQh+zTu~WJmjz|^sRuot1lnu1Bw3gNV63lbKGDO!;IQZ1x zif(`;z}A$O=~GPR;YLCU&?c1`mK3A{$OoBWpU{^n7ksUWX600EK$#W zR2mu+_rb^RbgkO`UN8u!JM~hAK&QkkB3G|=*iTKhmmvL(<~zp%P#Egl-dM6m8a`#9 z=Q!;_G^@jZvRBu{`nKKlC7I@FwdlI#BK}Zmk4SyfYn-~|pq09)< z?!fCEiq%MY>YL)@3d)>T3SrUW^n}kPL-wy{)}H^EYBSkn7GNPg zg@$rem-Ibc=kAUaCQJBe0gZl;Id!C{j-=+{M{bTUseIWWcXJQoZp8(c-OWc-^#e|K z{?P)s^1ydyVS&o3{DYq)B2G4IXk^q6)Z|${xuuG!3;dbLpx;o}FA!kBU*mr?E*Zx9 z`IfD1#|;Vrb-?$lZ=$ULD(*dNbJ(RT#+G?^38X8cxYCM0EA_k@D6`g!O1ua%T1Kt$ zGv0Bbq4%K~$d~TiQJK_j1cJU?WHIbA+R411ZmFqL+J^f|U*erOCY<%xnqP{Yid>^uN} zz%TUSYrL1^nE$SOpaBf(RJ8RCp^1mjI0=IohK`?-@XPR^CYY1T+?X(xD^J1zfWUL> z&~F=^_|ujT1PsE}ONH4&#Yk>3L_f3!y!^|I#MLKJYl zs52PELgdW3H-n_erp0GIGGe?QPmk+ZdQ^eJlAtHZefq{0Ea5akD@R;B1m4-H?8s>+ zHw?mDIdH_(z5bz^`CdTlE2p35_-kqbQeTJby`Gr|qUYs1NaK~9Q|p>W&HItYAikhiBi6MA2C6Q-_5Tz#^-N4+0!2d0sh8jWXw^P9IuAakM^=$ zERIpq3d4EjjyQpUneT1gWQ8jg<}y4fEg6Mp_sbDvf~7yC$R}Q(6cO+sabtyBLM8Dk%G_QLXQ-eip$hQl-qTWkVc@g_Q3oz6+bVGs%D-(t+ z9s`|BTDML*Pui6g&Ge?1?`U;hB6J$q?hJ^~9^(5@;fe&i5;gW~0=|vH3SLCH?*D_P z{EHZcrt(f`2LEt@HC^^Z9Hs;WRX$GmeI9E69Nk%q$@zQ5ESW!D?kZx8Yd3iJ>&wn| zR=XBJqUML6TmbBX#9XF3xt*$2)|%n2OS)qpj0&0fgX)r9>jh-e85qsp&@}HH>irxW zFM&YO8y()!l2>J)BPlZ>s~n~bPS{2n-LFLM*$^eE@!EGOaHcaCB=rP#;s%yMoFk&) z_8|~Zu3qc8s~8Ssky}$Q(wp1?z|v-?z!7IWgM;f8-mfq>usYL)XocA~oOjTiY>H4| zGbDxfyp2gN)MhqzL->bJ{ZIS=_7Rn*Y$DUnm-};pLC4{0GTvj@k&~5?bfz;s;7fcDbxXIn&O;J(1r97C=YzeC zxcNoiG6c{07@h!(9~l{G1UPGPo=#OisCk*no};B8eBQKLx(2Pb zJ1Mpk_mHqoPt=}KBZBpuntGMahB$=ETk-{@#bpSxB>DX1IN~F)0mUcTjJ;p@&FQRS z^D(+80)YqfE!qMBl>1zJ)$L5Flw$a^HtY*hN-uOw^#c|k5g`-4Uw`e ze}yMv$k@sz=}trRH!J}S!#Ehov&O-k!iQ-93X47o-`(;VqDBms%Tv_!tK=6S`J+I6 zsgYhUPP||Bw}iD^EmSUxg>Zd~np$j1j3|L8n{P#nsikplpFBf7{p=#8UIe?^psSx& zvB1yTt&6{W>gaF}Mm+hdS35Gk1HEr_ai)Q@Y;e2@2o_EQg@yr$zgYT7U<=`kq%#c@$WTsxRP}-)B?%`osUP_ROKsd+{e4|wwkX>wH9QI$l0*IB0519%TPZp_OH+Nw%wVSQ&^hIt7-+kU~A;` zsoF?bdeV^Y(h;``+tgQy#0{7@q5_9|R@hjNr4Tw_7MamU|<~H?7i1 z>}dxZaELi~_GaG&ug*j`PAf}hA=24=6ib&>o*%5}I?t5W(NC8w^CvoGonLHV#;`#Y zNGGHVf?8oAsfdS3q)Mdl)uM2 zDSkM1r`{1}Y8u#Vy@v-i+aY+BU!oCoUTcbx?+Z8M{SHTlTw~(<++b@0(yFr#hR8JGjZ?5BXupUEm_@{Abs7;3a5H+{*Y*}5q z0F|2i^|%Pl!W@t)4q4m7*)7%$OvcBjGd_sVJ8tW3AtzmD<;1t&7Pu%-DZFQMVe12d zn}-rhKDUR>--<`2ARMTt8}zttABF5?t z^-0%tP0f6$vIPHv(062~2|n3;m}oG1@^8<_1GNR?XK7E|^1tF9KDbt5&(VzN3(63l zv{8y-c2K-nLaEnN%LE_%#-2#>=K+w=2NLsyS`>ReS%D&m zIh*C)ZwUXDcB+&ABN6&SnDw|bAk>NU7F-gtmcwsh*o0{on<*y+Fl_KL-yx3z37e zfLNHpaEP_#5Qju_Y8NMsJpc9Um!Vywp^-MQ(aHb`y8bBn)lYfz_@2rlBE2WSo+FBb zegwBwRBVLB&0jua18UPlddXaeHx6+4f4|x$M50xMSo2f?jYVf?WcMfkdLu*dvqe*U zSD=#&#@Zv|U3RzT(ziQCZrBW{H1X+11`eyB#$9$<`h)UFcpq0D(HvlIHuS4&X;2 zP~fed&)9kPs?iHJ;lR(#nRyzzPW8glXXuFC->vtXmpUxz?(D9#Er8**y}7|dS}h8u z{muEJw)o8-a8f<)MMkOjW^TD(@w;@iXaE1BIC?;yMRL$w=$n*VI(i~v*l#b}|I~Y| ztsSoeMqWSh#35~Jeb+_5-VQW7{xg>SfoCs&T(f~R7WA(W-_AKKJo56gF{YChPDu_d<^=&NV_*GR$(rp$3Q@b4Mbii;)RMM)$+9a zkRfxk?8lefvfPj%|Mb~r{5fFgDUN2XY0teHc{Sqw_oEqx9<#J|b^d8WB#je=;Q6XV zWAcB564H#=yBnPL#?b|yo@>Tu1kJ(I&aA^3{n)oRr4!5zaE3|qOf>{7o{x9g(Z6a~p#|30ue`T&-&26gEIq*8HSoxaC; zxAf~bO{&Z&Z5zKm=q5il)dR@?f#|_j+k)q*3ym-%gPcul>9~1Xl;o% z%u&Pgb0kcqcG~)!9|dBm9W1;Kp{l$c;6yE5+ZNuunx0aKXjOJv_lX4j2>*3Uhv2j^ z(w{17jv79C=w3wn2J`c7WBm^+L7~|K-u(@x$gcC&p!_0PlnuMbQT zA^}(TOmFC%UK=}L{z}3n))g~r+tuhYK4mh3+}0QtXai|2>q9rT+%Bnqz)91ee*i3|KSsfBxZNDjR# z0X(G{;-i&7$moG56LNCu@OdD&Yk%=SxBIUv@#TYiPFbKbI3iFGMqqwF8_<*=2xbiM zX(&2KT~uV0RR5|`1GVQJNU0|-eoO~V1LXHTZlO^SzQQ~VDuk^0n1q6nz1ERVe*+(Z zJcb9Wz2mpSWyQn4?CXqSYHC{X^Ab?q5c^O_n=keX;~p=G4oM`Pf%z#5;NlZ7KeDG0J4!X+e{EtKwIy0YDqey}nuDJJ>|rzYd|lx#o817t-H-X7kIBDq z^T$@bNS4m>aInC@2a1jFI4Hn$FCf*CYHPsJgZcNGr=`SJ4fGbfB6aj6P)>C1Nn$4u z-gLr`25?-eoXH-LYv7G%iK5^+;cmn92; zp`wq35EGVZux|gAwLu82UMTxc^Aa2`XLRgnORz@(ZgMW%usWpJK9bh5bAdB&)b2!X z@gvYa8b-%06q}wmz$HC`Er|0EB2kUx*{ipL&i%QKk8d>TG>LxZ>(lN6r;lM$8gxIA zRr}%~S*#*(u?DVIl#bJ6gnEU|NQ`fKBE3BINKbz4z%PNWc~W@{P246HYXOia93;Duq)X zrhD+VB{@8SmGB)HO!9NFDzDhcPKmZJ2S@Kk~2|F(9Z?Ltk7+W3fvKkzj-2#x@9{^5i z3joi+0$bEZF+PchJYINvI`x`f#F9J4*E4^Q)uh-V7#XBVD>BDx2ReQ8xn;wJpfS@A z@C_#&-3PIb&(V^!$Kjeb76&we>Y+1lh|utDt7gGE<25ot`xEA52E}At$y-J){g24Z z8i2_jRWEj#`S{Cj(9$M1fV>(tvHLtoU+e>QzluMN&%M0`)ME#T>ZVYlBY-n>s!D;D332u*tjzC_m>PqB!fR~S z=%W-q{5A#{)D}VOvZ9+Cy5szNwXZ-G^Rf8|42xNUFuI~ZfB5>Wo;W6f5}s`g>l5N|Gne(q@*fPdbj3WWFf4haroS%h2o<%+{^0MCQ4` zNk-d~^^)4*qk-5A@@MiiAT1OSa5dLOYl<|-ZgTCevF`tRkx6EzLgB{$T){*C_j26T z4`8ah0QTZ{SU8r@aV>?(?kWH#ZmEr*K3eI7>6jA_(^W44lu`t5dH^hJv~i=GA~>qn zxMefz-yR-)|Me1&_R~*ZbhO}&F3>tIeGND=a*Ay{zCM>`)(_pHIReDYzBJkDQtAQ}eKt)$MI z+_L)xLjO#Hcs|4cM_pbV)Pt8x(g6EdKwR#DG_}_ExY(m*$1xF(yJ{RHXZQ0KElhSn z)KxHTpYXo%=eqdMX>o%^sbX5e6z6!KpdJyo$FkXW@csSJP8T?=hUF{;ffgNB8G>pXDKRh5L}fwrydj z-)Vw~iO$c~guC-?DH6v)<|c{KnwLXo0T9J~Or~bo49#erg=> zHBH}ozdSfP{)Gsq!OrO0>)Q>`1vWlfcHtOCfSOOb!x7UPkN%h{l0|r^Y~b0 zwZ?>s2RWAzUryw80gG$^+Dq|xzJsV^CLgMpLp&LJ&LAMT0FTcihG2AV9gvIrM28I8hsd^!`5;*RIMfG70Zu0C%0>#)LM zpuBVlE|gR9{^zq5FhI$-2;$e|S#g*ce}w);?AcNE?5mD}lmpO5pE~Py|9%R%7%}{( zfc!IufkiWn`4H_(9KOTxM;m&hfGL$%Fp3e1hjRo0!#Nke4QD%3!!&%4=hNdV{a<^8 zR0jG|p1xWCY!FurXT0ldY-|lE7>}@os}yJ|Ki*lA9O!jH9osGcV}W=Uio-|U* z>L}SrLc@5;_qiuuPY=amb-Zm-o}!*S5#pll_@#DP_OI*A^NK8d%(=b$XUUIqmUt8+ zMF`+2;~2ze{EzB7Uo8yZ^Qr6E2BUxOh@<;3^Z>Nr$}-a>%;Vj759jS=bxoD-qvnqZ zBj9py`cIv$>`b`1EOWdy{&`XVKay-g`V=Zkvv_kStAEi*0hKY&-LrO#my?vouqtJW*%I4Hz}JzFK+A4;{h$JGW6XEwSIHV*b* zRYU7Ilc@(nkr#bP5?_^|DH#auE1t!xcuA0sJ zh}DyA$(MZ8{e~noNxMl5;zh3rJ(|J)6(w#kpm3x8*8{KW9lmH*UJRYe#|6E*E-kw5 zdv;X(R`ElRyA-(8nt^WdsNcZMG0ClK?5&IlWL4*6> zZn5`dl?Nu(7c53$VPVa>{|R*v(t4bbK|7gwvt)LeW_M?D=S^jOC z$j(;;V2ARdWXWx#s#TyapT~Mw$iW?ir6VKP5BjPIuCe(S2mc@t`yz(Jev_1u1^$ub z`!EsvB&qP)s^l$FM`h*q6C}Rqil?#ToBYs)N$#Uk9uN{nFy8qhhRG-sw6r^yQ!#wc zh=j_hPtR4Ps0&0|boLVL%+eE`XDuLIj0Ivx6DMAg`+=K7w3k@84yZ$^aVfY#_C@mG zTnAde;LxGZ0;Y=;)hxYr$U z&!XaQ%w)1erVmF{6A#Tz3k%*?OeLB_BPZc*r2IK?kd+?i37r)roxTi77V=WggBKd$ z4U4TUVJyL0`V9sRK^07G$gDqb0^huTbz3x25Ec@Jh9`?wtW=C7qRjxcPZ@HM@9s;I5kyQEvwLZfmyMW~;h()k zOTC=zSqx`o?8zZj9#p1B$SskrIxKhA?-Kx@7nY5<4QPA9+tAca^t6@#4kz}P1rOPFir@|Bd!nt4LD_7pgvcCO*uuMo(6&3v(?onTFGc7Sv@ zS^o<%HoSIkmR}8y_l*DijB%aX>2t;?^ z;t_9c{skLH+na&=GlE6{qXc~O4XC@jou_!9v4B(MC|(J zk;>w!Srbo6UmGPM9yxvz8|@^5LLh?x5U(u3$96Hq9U@?pXUH@>3rhMJwL0RWy5F)irrr@LT#7NOU*m-MjPkMzEY%JtWVG zsUk6FBR<}(?|dV{q1ES~KgK0T-M1e7NE72Zbj(Ea3{%qw#T~92uFL!TyHlbAdI#GY zWpYc|@gQGgMP67c7kTkDOB9i0TWoy}IvbWftEDTFD?+m1%pnGT-D;a9LCWNWEf!pQ zHScDGg?Tu%PCU>WPM3K}zvzhNLCUGsZ8_B()dsC@p|S)9=`)Bl5L>(C8msU=tRsb@ zB3_2Oa$mAoLnP7ZK_c!_`hMo2*X9FmPyNqqLlxUNSVCr7{Tfj2X95DQ~0s z25G!jO7>z4fz&fF&st8gc7AT`+@X)yA3r=D32D(7FNk3E!$FQs8^Vd%DzqYxRPsaB z?5RG5rqCnoX}RB{DEct{T#GYiz^k|3X`#_3s9J4vX3wT18nA35>5*G8NA|_+m(tvW^=&NuODtNrGk@AzCOY z>k_1(7%a&i+X8D2TDtPCF@+DOlS2nG zF(0Ey}p^aLV5 zURZReTvF*Fp`J!En|l3ULTP7Yc7k>vCa)!-|NuHep!G}+4J??CaT z&?lk_qZJcg_)o>?5;Z(SarYY|IHH=P?OFw<$`|xSXMzKttjk4{v8y&>-I?91+n#J( zaSHq+G9UgY$_RJj>(>BV%cI9rnC*cf6kcKg{-J#C`%fB1qwd}*eBc*B!1-;Q1{v5e zT_p2(1aS5MA_0?`U>}Red=99uf(}q%;IQ&GU%%2)EvgT%-)aT?@o>2}U~-hbYzZ)n z{Y(7j{ij?_rix9w23;s+ZnL{%d9k)jw$slC>gtc&Oi`L}i(Md(pE^ib8(tB|j z+{oZc<}0_#!1IDVVBSp>$734G_8#H$aS8eqdYDKRs&v%?dj!GI5$=Ar#0SQgOg-;4 zpW~7ZCf^eJ^^EPQ3^-H_p0-@*?&Pd7xpTI~SzSn$_KWAIn49F6722W0s_VWB7dUS-}sV2VX6*S9fzjz=z=3jl$LLN z^2T3)D=h?D!Otb4uWOJIhjo~!EkAt$p~3(P-n16b^ivsf6U>vi_NUkH?zh0NR45n{ zD0_1VchkJyWcoH3&`!X4JN2|CA}f39g5!Ivph3qUfr|@i+lJ>!`-0gtCl;%g&Ttoz z=W;)eSUC!-e@2tXg!(wqk5TEeM-Mv%XX0zjrA3wI_pJ4Mz&0F`U|WKr2Q|dO*%dg# zi^=HRoK&e_Y1p;)(*d8idVlk&qL%*+^mDkCO8$GGcJYk68V>g|9(l(G8Y7YV;Vq2cDJq+` z{+?D{$DY8(f4|G!>vCP&gZ$-+8$^t5)eJYTtX+5H zUaUL4`wNz8Y~*(~-FJ>BbtB~HAhgf05N0neYpBwsFAeLDq%4UWV&jlwd2hm8gPSGC zdnLKHX`+i-UJFo*A@UJ-AXC<1W;g8fUlV?%Sxem)e4{349`EUbjM>13>GjqTgSQ9l zTE!;iE&Jc~4<>htHK(N4-D^hV-{{Qzs@c!$=(NGbNcq#r8ad$76i3}txnB#uDmn}~ z5QNWT@;H)kY)V9R$(xH3PH^XoQ6-Sb`z#fCuo5yBW(C!GUElrHv^iGfw(0t^tzg!V zT4v>H-P0-QGfh|{0VTN~xLdN+*9jva!pB77D|HYHuvZ$l@M(0MwltJcuGpT<9xAff z4aNMh!YiS@bVKkU-nO*>61MV{tJ^+{H=41K(G#l}FF4o`g51^0bISP+U_Ea9I^82Y zJp9DjI`7&VLg|L}Zcmt@!BZx#Gf_2Z$b*^Z2|K&hQQ->JZ-Sp@J5<<~1 z9+a?QQ<8&`?%>(Fmz?(&*ZvRAkgPHTS;GbJS}OQG*(~iMczeSYSgv`ul#-;R$PIToe{(cp zglhH`n}*HtclS101Ab^#A%HcO14F97U^al7t`ttBL9APEUMaa}Rgz^tOdX<#?2#EWk z+uA&loTGcwFr{M)HxCK53a(S2>5`#C`tOsTmJ16T&96E5xfBwP;O3ms@n769Lhl%r zmo4;wjw;g{zD&ba-f~;WNglrw?^NT6X3*-O?Sby-{FQqq?TRNGzEl* z%CQrz5Bjr11&Ef|pm91n7nUyg2Q$C3XaSi6Yh*TN3;q3w`+@M2J}CFQz$;?$BsZB* zXQiF_?OC_;**}m(a(HQ|s!Sn{k8_Z@8YB!v5l}|Kj@3lc5RP=Khw~6gOR22ib>OGH zUZ9jj5|HLf;u^=g&qy|~E}w9ncl^9AJrZCUl9nn-S};=Hmjhw>k}GBO$&w4#AG6|{ z-P9o~*cSMfv9t}G;!1y4z0CLWoC8-t@dgO^`{auO#j0^$%+71GlNh)q7IE8roNFmp zz-g|x&17K1u3ud_>G_q|EZu65IlQ)^H89%@sV{EtlIhlkwe)RQ&A0kuoBc@1=BoWl z#8ulB&b32f9jod!b(iU6pZVt$y4V|b(9X=7yEWu_*=<@xwL25puz#iwj^vH!+5%H8 zkG2kNh>d5;jQ}k_VkYAFtc%33F6G{GC+dQdVgr7+N#t8EjrGMLsuCwSxJ0c&SZ6(F zif?-oQ>yx_^Dt;yYVhIXYnr}gD;xw+D&yQ&hrvfa)$nkwn2U|*tbryG?hHM!{l#z^ z_uURG_b1CAPI3M4JNfNC8NP|BRI%5S)pHzg4S>cm_UT&&v=SWeA?Bpz|Q0VuPPZal%%&1Wx9ZL{42D)Ew%96HWDx!LbS9u#{ zkV8vgm?p!HC+$3(dF2jUs%r5SPp}LW>qpz+a8La6iN!#K&-;?n?RT@v_oO7jH<722u-drTd-NzE6eMKHvMy=(pe5fA6(sxr9OPE6(#g;unWY<5U9Y2Fz{fkgk{rk$!+v z#bD+eR;MuHCk14T#b%yiJ00i2L@~UQiNNC5T%y8PaOK--v<%vaZyTDcn8R00WFT#oUSon1CR>EdRZWGi|^Kqo~>H3#A z9*D+<$L5j-j)oKC=}4r~x~&J}(RbQBV49nUuGvEIL6D|p*(Zy)v`QmBXl9b_QE!$| zF_DPBl*4zKJ+d>QJ6Bq+92_R1#Hd-Em65B`#%?%wmeJp{<<*x|CM^!Gd3J zj^jVf6p}oUO+WB6-o9x|MME)OQH98L>R=&aYTzE$J>Ptg%x=@vo|+VJuCjS zV8wlJDvdkJk{}$oZ#iBd7)-tNDi9o z4|gZWzAh5k%8qCxpyafoxV6vQh%t7uXus-yOXTV7%LcJdQxPkFyj3bFxD-H(@!T-I zwiMRn5Gsw~zF1T3dob3sI;G~vdT9qsX?YhP%kKEacn;Ht&W6`Xx zf@v14&r_?|lF+Q7y&?y8c?{`yg7grQ+=}6V`Cj!OOlmpNS=_T6Wuwoi2EMc6if7$_ z_h6eZF8eaCJ#>}imfi!6^+`+5!?YGbjkbrbpw2LURHjG8dM&9+R`}A}@r<(UjLNLy+@ew`uBTx3d96xf30KHQW9XyW$vU5r|nG+f1KP0C?f{_XJPrPp9sZwdxBe_N6FFb zuvrlCI^+=H;reh{^mQICA04(3=rPV*erE&q_#5-kuZNkIrv}x0DaHhUx>q^o)OM5+0%2mi4J%e`Bj^%Sww11u~ zt7zokpjSV_tMOMd=p@*ZI!w}H!v6GPtmQV=bWc(DNwV7u*mU2K6Xz?os;uhvY{a7soYwkl&CFr z683^h4K^|9a^qG3ja7~q?~LVx;@FL@^bMq0#^XsgU-bwC+4G<@s;~q=-h8aikIhUXYkljG(plB{@KXSJ z#k^Ub!gOX8fXz?CQHl=daj{NCM`P`}1G@7H@2xyheAW1Cb>W~dY#MK+4x)E`_2Nj( z!&`Jx+*#lBeyr~17n>j77tjsgbz;4cU_m}g-B$*WwpX|By%~|3@XDH9}wnfC42&c#668P^G&B5T{L1%)2`Ctk$ z?>_~P_6x+M33Ze2p5-x4sXarW6VuSn>dr_(a0k`VWj3`AdEnrJI)N+#da2;&Z+QP1 zoUwd~IZG`!7Vogt-H@&q-r2+-6yG&Y_~qw9r+No7Y2@kAaqso;J2}M9y@4fQ5_R&M zy_61W_zvouZ-|`Jh?=?dt}tyRWA+}BxKb&1VD!KY@EIJGy-XfW^{v^G247O{C1Kr5}srni4XO zlohUI$G_gpVBOs_0^a>*PxWD!A#s~KD=Xp{VBA4Ee05IDO4B2gp>(x;KBoXU73DQj zC=c*4{Ak#xxZ;=pXx3JhmR6laW`g6TXjQ%0Z_;5Jl+BaF)!F-e+=1N3iv_ySB}2|l zh$P|y4?{>BZlraV@?^`9D+`HQ)znv$?_|~B2%ZNm(a=gi<#xNk%SnWX1rqlgN~DFM zVPUm*-x~M6=)@Mpo>vh}^TauFqjtS!quG1c?tN9bYui>Fy4iKaXE?6AWj9t$Hw^8`jQ=rCNrD|`+j^GdVaO4goYTnhJ$x>pb`eI!^ppvTeICKBCs5A+KYU6i%k z(9D;D!k=Oho|{*@)Y4{VXs=W~mHUV8V#h%ygG*T0j2{bt791!`h2P}bSr>(HUS@rl zY?DRSh8O(QSPF2D4-t}#fy?xK1FviyD_+1r}^^tjny?ys;xf9~vIPJf;v<{ z`xcZJBNIgOBSP?D!v(m39b0eFbR-xf-sGKEnWBPQWP&v?S*sHk6y~N~i9{eAPXWMB zJCwa_;5NNG@_vPCwlKk6l2BX8Eov8QIlg#)83T1fl({OdqhR-nZm728K_pr{iS;i|$vybpLO(ZuwYS&2V5^4x3>X_!nk@*5hmlrQk z`Fay%PWl&?HZwi^N%s>@?6b4_seZ4I^4o~;i=i#-u*PjX-JO!skB-xRV88mi_}hYI zfZ;bS=TnSq-m4j&II)~HB-HCG6ha7Dg5AnE_0fdQbxQ0ux)2;($Ux4?u4eCY<|Seh z8h&p5P8vM@Rwsp`r=~cJWR*k6yAEljPn*TzSlDS9C{QT}`QsRey7Rp;<@>%}r^DPj z0q5^stGhejCkHXqtuS;rVUl+-B2B2$6!)X4rcSi9>j@YyjK!qW85r2VuLU`n zzhCTFPQ(&ecVcwB>!w{;9X^&lSa|Xu)htp1vO$hy5H1(F2Ns>!V?ra)y9b+z@G{{O zD13%byNH*1x6u|RU88w|9zkVV(HPg8oWzH$l?lS61f?@KQQi#lV=rzm<-rrFuqB~O zp!kAF$~0|tre9F;eAOs6pG99?k41BXtFVjK$g_O&?ZRc#G{ry(W-0rnp4@7nhTJ>h zoWaXfyppi=8p(8HHeEzSKPU+23<4XixWX+UY!nBQaA<_9j z>JK-e=dHKFhn$+|5f-kLvS$*SQh7ZlJLS{*g^a^H!c>h6qkEY!JGs;_jHI&-0{vD@ zu7E7&#cP%8A@)EYHC&LVd$!5EBI_2htDu{Ubrqb>7k9aJmtnS%HjzfF#PqB))2^lJ zb;H6$&yyQ5xaRVL$t-jktihOcRk3>Ta+Ei+nab<$M{w_#QS4BEk-4aOFqlv+vOk?! z%<$?7;jZsSiHJcIDMrYB)xd`F{|nA#gMAOqKcHWmj7_9|R_#d0^InAQ6WGM^`mh*>Za z7PYxwB1~;)As}w}sb)-ca=k@xq)+2hax$1=_~x>_labk_>Dj||mlvG#zHv~-=yb-Y z{#0z5Gid`a0JtUlfi0;i3v{c>6B%FhajiP1r@X02@e@_m7lknHN)_HDLw3l>6YPCGC4_MRR#Zg*fALZej4-RN`1rG1r87)cqWL+`se6m* zdK?ttjkS6P4y}oqb?q7?+SKOeyG@694pu{$KYEFnkFcRx)qR zdBnK)v=O)rmd9l|XrEJHc@Q-~$L`$M^@J30*R~r>&~+|GJVoHxnZy$6Ok<4l!D3P_ zl=16}7r1`@=FA@Ng>wr{>$mc;hqv5JCT^IlYFM<3VA45@&a1VL-MXqMk$0~uW^TN5 zIOWRrxM<&pvi~ln{!h_Le+3@YgIn)Gb_;Jm6^mTkE?8PF*PJGDBWryFES{f9YtlL; zjOYanDN*ht0G;6)NL|Deg~@TxE2sm*#H5$vH6s3ec+e`N6SsKjJx5_MBn};Yn*cW1 zZAcW?(pCVBT|J94pjd$&sJO{2=24g!QH!grP#iqlkyarRIx4z1mH|CmwgKwutRUBQ z=a0RykSG*{43((tChRH#2Yzx37L4Z8=_FMA-8v*{kU^UBN^xcg*PvHMh~pL4yn4h<&XslW)+(2wb3Yw? zpBkB7UQ3G@hu@Z{HxXh~T`kC_;xe7U3AKyH5(3o?={!k^?g<{#0GxOPuZI-t_R==s zWZxR&)Shjbg%#m=C@LiyuD6;$NU0XwTPXOb!c-&bEk_yn>QCs254K+)J;81wg2_#( zrQ9~{44mGIMW}nDute6gly{ud2Puu$Yw6k`m!;lKm?R=$q1QY<4Z5&HGu}e1bbx2w z2W0R88zUeQ`nmx!;5X!-|G)z5(pf7K4I99mOcRlw>BlCqsA=Gci%CCWTx$UK6!Ds4 zCFI?>59ITb`pC?7h$~Bg%%c__W{!vRg5KGS;Sp2A<^1%@x%qu|hFjuIJ?Z;ECStoS z3Bs<6a!o5eyP9IsJKKphB&Z<`O(LA7S@`vhQ{EWprfAX38p3o}fQ8vI>q8lp7Jwy`58dw@ zuBBnV3Y2cFCpy6WiU&{4ix@XqUawvRY|vq5gthlQ!2FBAC9=P$M~6y4mx}UR8{G?b zTS%ShfDB>fZRo6f!WQ^FU^Kfmn?hwJZL#8$Nw;!IW5mZp(~B8M+O{Vg8nF^z4cB&O>N9Yi@tf-~4pa$=HON7C-Saey0O}6*!z((cLw8=|gM02dBwE%^ThB z`ko7}XU@paacpwrayh0aVk#4`zuguhv0(NN^vB^*@sV0_)qOOvqp>7Gq24~n@t9n; zmT)i}=fQ!Z6ywd;B4>r@PM|{HN!406ejN?hJFCL0wblW!*eWz}jaEi#Eqf_83J`TRl?$lug$hf##k{ztoc>af)(`zt8owI z6{0$I_(|x;yoC#uV;0ustpW&fR=wB`aqQmb!08)kwUX>{?R)Q*Ngr+YQAqGEGpUDp z-qClr$e|zy_q-#eimn#JZeq*biaQ=xv5!*aD;R%w?tLbw!=T?$r9ST9S)s8&mtg13 zDDc`9AvHjGMnITePdU-1$O4grMfO~I1Q6W@Pua1 z`rhkQU9m8CDE16B+gxhbcr5xRaIS1P&2I5<_XEP^U`bd^8VvDb1ELG z?a(P9pK%y=+lrvsl~uWZ*I>oxg$jl*nryu?b=kgFEbf-^9cu%KH7Uz31ep7O*#^Q8s+t4>WtCaVIX7{~) z&h8EV&LDQTE1RK>OL9TpI7>S|ar+>d*Kx2ant z7hsPpke8Y6w7@qdIuqaNM4=K|EAI87yc+NvBxhMf+(kT^43()$&-~KbrF+>0{R<-= z+NL=k;k_SB*f38VCQiq=Na4!_U$=$bJbG~VTeCC?sEy-wPuyt3@#7pxQGX{%FvP6+ zG%Q$wDv6W;y9*?8b6klR;#BuK4b5K4Hf4&E5ipooeGv>PuWwkpq|3}4z;YnseIr;* zn1^zuy+}!MU42K7sCi{mY(w;nz?`izk#9~)q6`gXmjC9?u5g= zPf=o5CMG{E#&>9FYXY?^3uwu0XYOrQ0lT+s;pzz-{JWdH)V>&4pU<^!MO0J&+Ovfk_<4s zzaA48LMP_d!fbqJT8s=uwd>Btny<`oE_8W%Ju5yyPr)N8&=6Nv(nP`YIc#D~%C{nM znF7^%!3AhGR|Ua1Vh#@-4L)X<=Y8pypR$)DUEopRtLz9I?XPVD+7&Ag4y;RBnVKaz z^VMz`_r!D`cSdVv3U* zH!i`Z8Fwz0Fz2acOh;D9kZ)WMv~RO+nx&Rv$#K5YD0t=VMF&x^AjO__FcU3=CTzyu z%2f$xkDLLvQ1xOQsqwkY262nK+1@xsB=6&Wu!Qz8BCuF41{irmzjP4gHRD{q3>jk| zK#%90jLWOLm$QsM?xmbh)RsRH2I+;(S4t~IIt36V4cOeFEbXF8G*UAYQs~uOuSlt7 zEMxvCaotK{D`(PXU446j>oBrM%eL9tyPER)>!6(Z@UIHR7^D&N<+}$87_ZQNNW3kP zdD<7hWf$wO!@TF8k3AzSjN#RJI+^q4SKUw7rbl%p1m*;iS8m>Y678?W{{8MRN@Y`O{WfLf*__J^57*j&pPj0LFHCs z1NmUI%BcMus--6Vb|%5A0VpB^1f62B zxtQ+}dl%uz``-4!)5+8G_dj=V`lh7#6>52-#W;mhYSR$2u38ONr)00I1TPV9s0({( zf(M^b6ebaWxVb|#v-YAhJ%YaSvW#n<@^zsp;PDnh%cdV;m3=|xbOCeTzNgC?gr$#{ z;ebMHz{o6L4S~EpZV+b3rQRapOiZL0rlj73vQsU^d9gv_-M4s7^oVS zk_fU<=6Po$Xs$o>-MvpI9f3QA;Q22ffP7xN(iu>2>!qUNu5c4Z!3~%1D!Oky&l*au zEz5xzZo?W$tTs#{l93@ftS#%{dDRQV0-~jP#KN>EuKdLB7-|OAUWGeq*(@)F)_xqy z#W1UkPj9z=Z$XvwgcgU+>p$-lm~$B?haTXvw=O&+@J~)<7!fJ>v*-(SUW_rsIV?!= zUxn4u23vIK>0~9EpO4(gti55F*N~MM@yUIJDW8C{Q|Yhs&Hmj&Z*Zb6HX%lpM%T@H z6A^(<^OJ6jRHKpkwGQHIOd65Gm^Xm5;}vy~BV2S}?1V;s8@@RTi}63G{*{#W9*jY6 zLIGo>w2I=&?)^q7k0f{6D?YL_of)spN{p<`;$>?u`Dx#FJqr|7I&D;_(=4Q54Poj| zp>0x4!JJ@?mh=9*RQP3)2wu+CxIVhmsK@DqD#dsxW%11f6Vm;&JJJdG3VyFaQqhk< z_}us?93#~oI8wC)NfvjHa~dyPYUQ{jnajb3kj1f8yg{1+@;`;fdmU_w@a_*u(i0LV z>)9&T6?;y;WwVfAZhVqbEd~PJ+586?M~Xji|4?fQuRrFLUQ3E$J_pT5-q}myrA(ye zHi(N^)xBEUxu&lFApiM4c;|nIORsukPzcFBlM8nF!OWnekM|jc$Y7U8=py|uS z@D2)=#Nr}!Jj?}8SJhLqgL+c?&7?DRZL zWz)nGpPlD=nGw3f6xo#}6pO^b9&lOuY+aBvNR>d_NSR1Shl)*am=96{jy>is5|#cZ#o{q`;ZH4Lx(cQr^4vXc&5 zw#smqRw!&pS~M1KkN{q z){$p40=7OlpFp%a^|c+t7bjvY!Pp@e$Fozmd916z!?;FP%=>{xm}ta3cC$S36E>7G zfvSkB>`4q2&x}}Mcf2|K z#ekT(;X_(1MHSg$5&SVv=lW;9?ONuu=~1cEYuq9;=S3&Ks+JoPar-)?6*Mt?x6htHz1yO zJoPds_K!G<-L4{Z;!gm)adkxs0yi3@QjFUYBZjmL>HJhl>b?WNs2?;y+F`E|HPr<& zGa+eVDjGoZ3&JPE@t)G^NrsU7iiuY-5Pe^TeS4N*V835jYzj3 z0$E1H886~5DIEjpQAYO6H4qHB5s&i7u+!fQ+BnQIp6K1~6^FbqggGA59p$y1xZIm{ zAH78+w^$9yrFLFo7+y!aKCVunN@Mu7^1?bnQ=VjE@@yayMO4Rw+3sM6+*;rh#@<`h}4 zekvROJNKZAMJRy(!AxK&J;SP9psngN-rILs-Oh?=bC-M*Xc>oP97?JWh87Cf5TaBs zX#1-XtB~pZCtywf=|Y-tjl3OZtAjX}lEUeiABy`leOQ zu@is0%orl$Lm3(C7LE^ox+56+RLonm4U6jx4WIE_o}2MgEdj1!K4_(jC&w=a1-M>V zq-+#b1kR$qxLqldRDP**mbQLY(>^q6j@d~W&02{N3=QCyL^xBy)XXiLazPev+C-S zg`xg%{19K8o6pxEGU0P-C;RW1^D_a;hT}rgOkwUvolEx>8!!|DsovQ8Z7lb3tccHz z@gFa6M^gFCAf$PoQcG;6Uu4?#A%cVW_KU5*z09AdGf~4^EZzdsk0v}nTN?DN@e8!I zBZMetdNlNY^m1iksAR&Oryrif z02LL-s9#y=$o0#LdmX*ljShVL7e9g!!$b3Ayj+Fz5wY!MR?kny+kSJ){_O=wnP8B% ziPQIqcfiLl9k*jq7urq{M)q!l6jtM50>(??%TlFPvY52Eu0V=U!#f1X;n|Mf-3uk) zQJU{*kV5#T_(y2|KS0KDrjvXZ5*!k1>+3)6R9!;ogbowXU+^F9`gS`LM9wC7-7v&b z2qQwe+wf1-g@rIL0Ma5`xC{Xy4(|-_d{%)uAkIkmCk*=;{{QhAh>lPBoi*{#Um+3? zH0IBi#?Vn7V3{?DtMU4=mJISevCfl@1V<;1cV1%>VlSJfPt$pEe3w7o^^da(dDwJ1 z*bpSb<Wq7dJB>2Nmi zur5}Iv%UQgs}s7y@ZP{k0U4c)jI)pc-#ieKKYSovdhDw3%c_jHB!qEys?=8H$C_l< z(yQ}5TZ}jpf_YDj^IV213~_CObn{t>H{Q>3iUtcN#g%B4+4Lg38=$@-o?M8-8q562M^Rz#6`Z#zu#H0Ch+k_XY}8*rj#r`c=bq<^aOPt>_I5jeCJfHFuAmP>`~{Hd zVE2R(96GftUEvb{HOawWwg>Y2>t4eSx8AUB{V5@DSJQ(cm~9@q%}~~TA-+D_bZ_za zUsABd2dctQ>P)zYFDOrh9?9wwR@*#c^V?r+;Ey3)V}N^`{KsCRv&EJQXR|=)2f*C| z+lYg`trB=A4`uaBnSSgZ6Bet9hO<2-$SVQ;>O)XoCdWzZ>;H^Lf8Ub6x?TgT{hS)l zel8Ca)|Ws5Ktld=TEQU%bVZE&2FiA9>9S)ojw^1sgw7VkK7GjJ$gL^(l8^oJP>eg9 ztpIM$?~cQlr-6I+8QYHS2j?ENR1YE)qW~HZVxQ1Vc4Tl zH;AZQz@>j?S~gNHoa%Rx{H_#T{X2QdIl7_$R3fh=^gu)q26Gw^X)ajFKXT|+e;C8Z zQy+7@;0(+#4NDR7HzGf9n2LA^I=?QKhq6=r2J^bOmNdWKM1we1SwUN+P3DgmZD8hw zxOPH~49Xi3#F6Zw@QOt7;p>qpq=E2CN)I@Uo1mfA$k8fWfRP8bm~_}4(aN+pc#io= z|5?^Qm(9y37)l8t7-K(6Sy?j7lsce&0{~hA>1IDz35|q3i2x_KV4?+sozODG2ZL@8 zR|f14kRI(kOdYZKmRCFEJkJWgYZb`U2-qUE3wR%65C+6Q7pDOgMEv|_iRS0WM}xs* zOhLSI5XP|)(Zf*qROKDmvhR?E`Iu%2Mz6tV1>l9UY4;&kGLWW0GbBKd3Sm z{Bfzo-zr^7@Gul=>fx9fAinPYnd8Z?s|qfx;S91q&&08B{X9bN#>4pr8;6JG$Istn zL?NCI;K+81art@FZxbjwUWkzN5`Ox>{fJ)|^Gz~34Eh&>)RF($cmI66|2Wg=B_Kjh zFjylLyWhNwe}0ds9tqg1J|Z3e@_HtafK7e*_et*GPYmQ{#_q%A+&r{0ru=u;^O71C zOGr}P&$IuZm;28<5~4TG9fU1oeWN zmv}8N%Ch`3;=fUWj0=O|irj{cp>OKHi+@L+NbEU@pLON0C&~Xjmgu@;M_sVfxOz%M z-oYP~SN)*dGS%P)J71=&uRXB@q1dCXN&_nbb#TD50EeDYH}>;@Bp{PJHwSE6)Ztqn zmp}E%^DkE)xo4FO9wL()5cM20Q2$>uC|qpQcj9nDc591Y(m$5b@4l2(^a3nUquTvo zV36^A0sv@i^H0&Vp#=JH0o_2EaG6aB&w@hoY6iO3Wx104%wZ{5Jw?}o65Jfl&(vu| zCjstmp%VwpF87jJd;+6vg!Rs=9y`U~Ea zMValR9;~tw9gR>s6sF|DBUW`E|=q-B+1mSD28l<+mz_9p-LAEh>5VWNRSYPG|oH2 z;L%d|gf(1XzX_h8{UG!VzzRy?YCgBHgeEFjwD?DpW4}i*=P46F`S?1J^&pvUF$@TSHDrY*;{j0_N}vAQPJIASQhPxTMC>jdafjr| zJLpGNz*wV?dmej>JT5Rb#R6__)UEFgG`5=F->{pJSHdBFjcA2Rt;fy3PkbJY$KMj4 z@p(bZ?_3BLWHqva2X@u{4od^G`L-~e@zVQ8FnEvK=*#(v$uP|YV0WKd4k{iEw_rpB zw7|WAXv&vrPV-i?_JSnJbGsZdV^Vu=ZadjHiPlGNCrwbv0r{Q}^!c>uVJ@djvLWfH<@@WZtc_}@d5P#9S{$j=7hXk4NRolFFmx$e|^ zR0#Um9Kmt5%|&UY{*|1731V%_oKyM%riF~XP`mya%9Ib&hmc&dy%AYvCc5Kw5q5R4 zS#D+bg#xS54=eB7MQZ;tl-Of4?pG}$i38LttJEt7J()j+cj z`0}6L1db~6zB8~HQv<1)5C)lJHFsfWAes#^8{FK(2pkb^JRIeCw0(fUc#IXkjc^iV zAwD;V+M)*;qlhSrE%sI3nS+ji;;Nmm9PK4~16 zXoR?{U(pk32!scJD8#)^5fO{Hl}K8x+bd7PkYr91oC3<};0ogRszeRYYk!FJ5ulNJ z#W9HdDqLlQAC=; z+vXIt`Q_dcYpG)E zy0A#|8YLzs{e^^4u@1xv#6|8g)vh}>N_77DuSCfV*%bV~ydZX>&Q)St8P1CjjjN~l zN944ok3afTz+r(Q=%vU^9N~Z<-N@?ju+Pn1u9ROWrFAJaU{YcN#v7F`U!r)fnNqdz zPE(iYstW-sLb>s#&VlLXIAEYlM65x?EHG!0uu3NH!lH(0l5T1W7@sd~gRZq=`t-Rg z^f!mAk(_HdaA#p&aZvDZTOU2HnxjQw=>bA(;`ih`cQEM?Adr81#CsFO7grrMBc!-3 z2WB=I^PYtiLlq*aDfi=~_C1GrAY6DWlzkBL1jjoH|5kpo z@4cHFJz*S$IDa}^(`dUc$ADXQmtk>$BB9f6@{R|~bb#;D*Cp`*sD|p|YJh%Z@$s4A z=6r6ZMg5CrP*&!&9<9^9sD5VjAi({g%Y5{M9Q!-es;x=$-NvXAJ!2zTzgGO1eATy| zPD{M*8h54t78hZ`HfVVvW{^-6nZrUuO79Yx0G&+Z_kV(S)+Vr-N_zm?FVxD|F4+jV zEM2~~fy{p^L|iZm1Dl{P^|9&0OeHigd=3Q#a=En?^6G%^vbZ~+`#AUU!nd`l2h(+SNU>YDLb#VJHhQmnab~Q zCmY2CJu6`y3SBu3*UeohFed{c()vn~XOoc_=D~Plm0NX1{k7^W{N|B}2WfFSjZA8m z#?#SCx0#2CEq*jW{-?}=RtPd%4D7idH>KMx_I07Ili=N>)IwmL{%2T%G>#))%G#Pu zsmiAhD%Oy!3BuGngu^3597kHG_I6$c+Dg@SEgG@nUgvNTuLQADekd&PY17J!WSZfO zUYer?yH~t33R5o-W3TbhS^5lQh~78ED-}z!uh_zD^3IWLl}X1Hq#t;@2!2XZWpwDM zUhr@<-;*JIs?RK!3-y9w&qr5Wys49(^lnHNp0zxJOAuSF9GB^InYashVs)~S{QYEX znq(VfoNHVu^Q&UnzA;y0JT)2UE@}_^%QFe^e9 zO;^}g^ol1!w8t4-3ACnybwyr1CM`|0F=e>41zvw-LuFGwtqp+I_ze)rrCm8IMzw0+XREE*_kG2dH(4&8pVrmaj3l z7fM=b3o9I!WUR~-Btrk=1<)qQWirN&rvLUC5BbI3*zQMeQO$2w{iyP`!dWy5<6pCB ze~=1gpxli!+P%5_!FCL5clan<^YJsIMRUA^OWnmQwJ^mbKY*>AjWa1t+>!Pd*x%r> z7qooK7HBmZMSE|z+k|AW+ZdaWcWEZy4NmWDBuW%IgL;G%m8@a~0-Q97m(}6(&Td4H ze1#)=&~Tu2r_7c%j(qGHmE|c`*7qNg8S`e~fwj`PQv7Hd`g4Xr2q#>YoBa!>&}a)i zUsCg;Z}Sh!Rxlz#Rje=e^Ys0(ApNXnHO`J*c8uspvuR9B?{kY_Kl!;UPok1)g7PO@ z-i>(`t$%ow?NzPM>58o{X(pTEC?cH-1l9?K zZ;Kpx+R<|s%<7wU&YY6|5Y0l%y>;Bb{GXPH)d#G!Cs)E$)8$8>%=@W&p>HZ`l(735 z^M*}?-Fb=|K_mGZ@exMGCIH#&wPxZKM_1E63cle-qrT?Jf9~MZ1ql`E9gh_GtdqSDx(kGw%dQu=B4J3M4jm^4hY< zF>q-Q%J1Gj))t+`0&L-o;oV1XxjtZITYg)G_Ne+3~F73;0nvt++(S>dn<>O(g z7nvqiXtSPvbxk)x-m|Uj>fWNQ$3KGgDY_M(8mN_Jf*^~eA;$9*uH{)R`dC4-lHS;l7)ckg8a!Q%`)5bSt~SrY0rfs3YvVvR2%e}!`Q4z zU&P(`C`HC>WcZbj!-DN4S_8-(GwrLhBx12~WS~#zJ*QDFPDq-K${^-bm8P3b$mb93 z6*a-rkIC(H(eO|ZGh^S~9e9C%_zr9qI}}mKBp)2zh^9Y?1hH(V0`U(X?**8>Wap0d za8KDbp=RYZ!Tx$XHxMd4j>6bw=f`rkQ?3+|s~wDm0@gYB)e^&Uvmb)pLN-x*xg+nY zs{Ol;GUNjIhPPs>g6vKjj07PaAY{}SsKub$JcR$AJ^Y_N#*u0)AlRN}4LGcxY*mU3 zrq8AZ7An}#RlAp#gXo3-J#?NBi-tcB?l;Pf}q@#5 zizi3(VWzvrsAW+n#lvqFFsX9Jf>yxwTlUEvpi!32li{Hf5SpsRHQlO#b$Ku{e(f>@ zgY%lBc{?oB-YPQ|YSnq1d|o8C{OOji{T%;msItqwiXr=d>V0p3iefzp#8sBsjo^dX z0-ag1M)dWMID|CO!fJB6><|%)5OqEjzWOl8Np2VWg%I6SEGizhlFzS(Z6A^{yzHUm zOsCm>baDLTgwi+jGc6ym0?4xS38;!oZ>MW)jLFw11mIUj9VCnlA#<19rO00_yeho* z&0|O4-rlRZqt3Jp?3S&AG%NxtPUDfGmIhkHHyuihZ;*rxEWAZzkd-gO1twvZS!(s| zPC~)00oxlrNnh`BshhIL1$6_T z*S!SwXo2lZ9t;JTO;rX%4}-OHwBDMl_ZQjvSoG(A;$;_N%c^>0aT};!AzDrx3B4%hza5_8u8NVuo`?_L>0R~! zP~6_^RFdm$6b!5F;Qj}QLpP3Ue0Hd(6|erV-&lmf!$}Id?3}VBu)m>AVsDf z@Z2o~ZwG^+$Cs}tt}!kWGNqb zbY(1;-wu;E)5P(+6eIJmfJS|;G4?vIdD>m4uG}vdZi(0LCOXKzx&BA3z>&^G0S*Ug zX;L6PU=A-_qk2vy`_*)3&s(fbb>*eT$wIv_yo-E((QeQK@oJ2J1sZ<@vz;za`GO|hD>oos@Ui>C1xgdGE5sYxh)#We&6R)d;fB0W;%*OIS$Rq5 zfQkh&yv(c#%HQQRs9oaBUJ=f$*ne{FW;ci2vIH!X>AU|}_=$M^PZ{cUla%hn-Dvmg zoG^D05`l70oR{HGaLiOf50V^>pIt(E1rjyr#>elu^;6u*S8us6Ux_JVFG-`7E%$Av#f#5eR&UH zfcaNr9X~W%slE)%=>q;CLJZ_G|JDk}>SRuuvz-OXZygMikYR>%Rj^hEH<9W$T-zZ+ z(?+O1BL^7;(MO+OCkMhSEwZy*^lEHj<5sk%1lzUr4t9@Fx55}j1jDCll+P>0oA-tk zKltQKo(EarSZfIVJ$;&}0iN~2w?4b&NImGoZjT*+KEqLvo~uL_(g2;J>TifM1bt0bq9l zba4TSPz1-My6s?Is;k_Ze(VJ~Uji?EzO$b3((5_-R$qTC;VQ7m41XtO#<<7L=xE)Z zEa|uTCt^~QDI$FBSEX%(1_FL*#F1ws@N#}-&0MRX5v_nt9WM#9^>;#l)(D=SDiBF^ zAD&$gS@ghUr-*m_e8eh}&%~K$d+{=KA5Y8nEEp3M8s|w!=NiY~<#6C~42_tC#>)-E zN?#U!X!a!y1^IZ8 z7V9Fd;1cZn6V`~LvI+mVY+}xR{{V4%%Wli6!H>CZ{_XnXM&GlS2IfJ8T~-e23kr3W z?TrF3M4$86D5-_cyOy3$*o`%@4W?3srn-z}R{*H*G>J|+97JKsFG2AG?bPwx_Hz?` z+1!lAq6e|N@;|w6|CK?316c%5%=*OoM9y)A-mX3p-YV$0rwF^YUWhq2R(2M?pqmQUlVrZ_CxRoV2Z((cFL9kN}q zCq>=dwp%?^-%BJVxIX)CA}HlWBsc$RZ%*q9scco!6$Q91g>Kmb6dKHsjA}*0wsX$52c0r?{_?xvlnQG2}xyUmaEAmX` z3}uG9^VMD$Fmr^^@Z9cSkiA$e_GufWMH3Gn%{xytw6(U&H{I#=;r6NOaL@qz`8!*R zEbEo`yS`7}=Gu6ZA<*%#;AYqur9T<#`EsA(0VmkPXNr!t%}HyeHr%oTN!wz*>ro|c zszi$&TichzwTNABiXSnldAS#)rnbAFVl$xeM_RUiIV9=bj|Ern)1InO=My z;gyC@{B``9R?+i+IMNHwjmgAT-o17X^DNQd|4VnmDjb}7l~QSe_lg@7z9T^MIZsx6 z<9(_oWp{KvJ*IShA0Ndz(}DK9se+V(_hm1#@=i}YzNYbKfy%6y5Voigb}^>c<=`{U z^X9`i;TgLu2YCI=M~5XY<0<4H@glTGl$P)8KM&W%r6t^%DjCojDthcxY<$SK)z~5T z)L>(->v8?I*Su>{v(CgyB4Nc1hxN?UVy?YKv#qr;-^bUq11O_+qU7@mD;%vYCr-Wv zxAA$hJ@pd&?^zrDSLW`P$P&vZS2n1fbYzs6@szLAnQFS7b}PtZ^R-%JtWHhnbJk6C z8vo|EOY~w4#1}l-A8+(J-WC=@kDMUiF`5W?S%*zm9LGhS)Zx6&d8i&+n372 zNMYPT_X-x5m>#(89`aQ1YE?1 zjO^XrE*0L35Up2~AHSi3N)lQN z#z+>bzDcTyylzuwucE`Jr}U=`4{}Lzp4N0&3Tm(BWb}?zxPsN@Ik4(fI2pHcl~I zao(DCME&VBQY=_zo4cKosYKWK07rw!lSRF}6VXAbkB)CiHIN(e_D4pPOD3qu-zTKL z*}Abbc$?Y-fU5z3SYo^Ei^VS15jk%8Mmf!FHw3&fH{vv1vwQZKK&!hY<~9!}8Q3t* zFF{-9<$#ep#|W2kYrLKMlLN5&JpJJf;A8sCe+K#~vKtZc`aXOKDUQIG#;J;$=K`@p zM47Fv!G1#bhyX-%o6CQ?ej8B9vc1V`wCe>j+|R!EWUBRSED!hkoHJSaDEnnC_QurS z*Fe&x5b48Fu$!$LA)vQUI!y(z>IPO$JH=J)@`>EE%ufMo<(aweEcU}L3vC_tGxB31 z{xW!X&O7d}2DOw$S>759=+vMeFgg5x=z8n0D7&@&9}r=X7L}4zQ0YeL?hXZ{8%fEb zrMnxXLlEhZMjGjo8oIl?=C^pB{qA?~=l%YUWB!0SIGB58*1gsh=k+;vDNiD&PBznB z85w@hG1Fn5QaTW``Y)LaB~wjdaqr+DKlZ&|QV%UfWW;CJgAk7Tk+d10v|?7+Q=*3} zm%xFq*XjJJ?3+wfJ&nHbw@ZOPj<>+b3ow;VxNn&5o;)i0P^9s+wO7mbH(vj=UzG=|Jswh$BT+_rA#6$0aG_Yopa`&j)mRj+$u!1^Q{TpT*4y*A6mczo zd$;_}(f%k6Ke_Hw#2OX-?76$eg)tRXfp_t_zBlTfTT03%FHOVsmAO^mxyX=57m0G$ zGBM^Yd9M-Y+zQ9Vyh$6+T^LT?T9IP5(4o`D^dI+q6Z~8e?rSplP}hxc*z5`b7NFmt zubjL|uiN8351Rj^?Gb)=24y(#Bzo$Y2<|*%?%%*iB#NaTmy`UibRAR5nh2TQZ1_4X zKD!Vuhg+Zt0-`-og~jx7!sffsO;mp_YXZYCUaa+Ld8Ik_qWafl7oFKr-5A_DasrsB zEhd)T%?Y2X08#A>t#)ij27$Te zW(uu{>p)KLx5Ts2jU48HL+&Dm7DS(Df(MtNCBNYIVt4N(`MJT z!q_CwTbtFq<~%)<&xH^71-+R`#obN(5hB(FWYGkEJeM@*asF!4inhn-c^SgJ z@Z~`Rbn|;8og_qPwlUk&lXzYDc5!M8uwc+LKji;pLMFGE|J+4l1;nrvH)?Mq57vRc z5Bv1_1lYh0gn9iY!a+5dO;f4$O@S7)V(ALnxpckkcJyK<$^FBh(;xCrrHJoW*nd70 zdeMg9pfkqC2_~CZNL#bjel*GwPqmh-%@dkWXDMP+R9kMFUUMgxgs~4ldl`26P;7Lv zy6Surk6NceCuKOjtCd$*W-ntfq52zLGeiO*T4z2$>IGQFsK|LTNsnVgRkZt-vX`Gq zZ*9yz>)_qW&lY;c=#y!mysqEJlY_+hVcPy?i5J1(eWOD)-q9CCIqjENS2Qb-3SvUj zHNJD8C1FD7H(5$BAaTpbqOnuoL(YSipcn^S3Hs(=_}m7*6}wvq*z=cWMEgzc?6jPO zO#X7(TcW$Uv`lXOodFdob%QuA*EQ^l-~=MhLf9PCalFnwV7}eFpXU+T#KK|FV^T00 z@osf2_QEH%L4fpZ*BTWOlD^)TsLq6h(-T5*^%me0Y9#C??ZV0lkohte0yxj= z=Whq@d$r(MocAn{&{W_LMu99}jh`EyUEFq?gO;1Wp1;qurEm{+1|v3HMF2XHc}Mwm z1SEye&ko`DR~Aq?W;f<^Qv!qrjB(a)^ZC{Bp!>gmlKC|`miawi^odyOE`CxEN*IG^Jt`FffRUQfGc^i>y zAghy^6eOAWOWc!v+f;*EHU%g?y2^%%zsb|5Pe-4K4$T9YU{&t@p)<4}qU(3Y70<@t zpP|Lr1zQ8^-=F|EGJfIXjb%ORzn*hA~o!|I3x^w@NJ?NP#T=3kwB zT>IInGb;9O)MUkqs-3zdaZiklGpf|+dWyA^)%#>`bWK0-ziu3Bj-}K3IBSh)o&Hd(KGGz@dG7gWiL8emC2HtoA&hm zf9@S+;C|&%zxzx+?T<BWByL^*v28)rCW7N!Nw(zGJ$CXAGZ*76hBXe z&4ccWZ|$yCi+&fx^A}~xamZ8v{%dQuc|;eq=y zNzK=u1LozxMvwWiN2<{jQ)r9NmkQ!R0Ij-RQC44e5}sQ2F6miIVO%#k8fP}_mTN-P znqFi!8PFd*-*$?DUe0@Z)}0d^8BV&lVSc;Z&s0r%3C@0h?0Gf@h~$od56bCng`SR6 zH${D{v-RS|NN(W_=w4>++rMdSO0DQ+n7z@xUc7ToQGaQ+xxB3`KRY<+KefQ+cr#s* zkb4+G052Y!TzDT5c4hF+tD4+W3(q4q zMG_0ml)HRrAg`p?ml(Q}VJSYJa2m#5MTg#!~6IrS!;B z+*Iqt(4aWKtSEXzHOYCfUYI&bAc7r=~+CJ-7t z{#Quqk3fBjSjH9>V(zf#`F~{VY9`z%%|-um1U)HO>OUO^Xx?3_WVDIOd8+ z@XJBZx_dd8o)|}*G>4QV4L^-);SU@GCKwY}zTe}hM=Vy7*EQnW65TN^?^sdnlhpeW zk_ewtR-6@V#GpvhYl)7l$f@kbM&%OtlKb*AyUt-pJ8lk-vY#s>YDrrS|zjH+2iJd9N7!eC-6S8QfS~m z?qmI!nfJMk&H>%%B&NjIEdHRZixhoHtQA==FbRUkX1mfo1l4D%JMR)Y{uT=Ituk@9y7xj7bCV_={O~LzIGmEAGUF7JGI6YD6A*PYw}>G zb|osp%=Khrfp}t+cRrU-rbGPhR(Iij$Bg?q>70Q=MA6x+UA5*WmC$7S9dMtPT%R|0 zgK9jg7+ATcj}B61VPV9(Q#a zZRvHh+NBRtd@*M)Z|mt!_;Ee_(P{|X4P=Oz7ztuAu`}o(JQC7@R-tyLg{)`3!_|h1 z+T8(_p>Lx6Jw&gxlOh$L`g4YCs3}rYKvpx{BZglECYX&6+b!Vyw093YfqnKI{>+Tb z8X6*cu1-c3lV{cpTfcB9zr^52el9~QKY=glyu5pz)6h)1D9!cV{rGc5R@N@^bv(7p}|2(ZutaB%wGo-*p|?c%TQR?N&(_w0-NoI zR}lf2ADt{nrK7TxwPgeM%?*Xmnbj+GzEK&ihIv;&)08cV_p?@9o0I^D12M1&Prh6K z)v94BC)Wca4&dB_bxnsJo^6=JVgw6CEb39QipMrL4#tnc@jamBy*_nHcV}s#KlTab z)OIYuS9!kWXk^3NLM$FD$^e6+)L#259ip~I?0>Z@-d;uJcweHq*?Ha4sVL8ftNoVj zZaZ}km7kF$GIg(mLw?T5x<=+a^|}VHQTkx_2AxbO+SSuDPeQ<8?|hdiSPP! z36>C0E)R%WDn#C&A|G_NSU9L`=I`UmGlh__b2*TOv2I}#zs=oSPJ9Eyy%^RlPuky< zl1S}jC1oThIDI}(kBN=`!gxLUmG>i|%Nt<$@N>3+y%|#^d`&ULC3YTy6loFaj~6B@ zLN>lp=D@N3DtA%Kiwbn=J);><)hZQDPt$ip#v>%1*Xst2^`3;_7_M|T`XnM@InADu zoll#mUqtc<-`Ew_!?ogFo_EJ7D!B-CCtmn8c-}0x-CipQ@28r?pBEq0MF?+i7k%J6 zYo6tsD{K!J-0^vZ+fD`%1*|m4eqDu1<>6AuK59$%)}L*+i*IFoJmQ!8x{^l0`!D+X zK3dB<4)Su&!N;Zi=&tv5rWGH{7Y-Vstth<$$7Jo-!HQyV5n++uF5z-?JVfdj?MDND zKL4{4isLmc{pF4e&yzgx7q|Z@vnuD)>8em+3SIK&n74r^+qi4KLAZ*-ngZzrx2ict zKTtkDG%z`olsPFVV;bmCd*10DQ~kX&m>`=*9@45tNcrR{mk@PjIB)!Ox01_X=8Y3>?Ry~^zT-%uniK|wD8jWyC zZ+Y!*DTEPA2-oWCl;>CZ*YPqWbv3_Rp$93SNwJq-UZ0kDk~qHVFV40j%8u^Hw<)`j zX)I-3#NI4W!?94Qnv#Zq05+nodr70F{o7+Bg#HmFG(|MlK#S||S(=hUk>9(2QXgH! zV}~4+G~c{~E@pVc_t6Ifa&sJre_nI?*Utucwz2oP$N3vz(4qsx0ynoe{RRk9O$*bhKSRJVsHK!5FR7I|AND^Q4O;~ zpHi3bGM$T!>r5bYNMqNw(5Yh&qd`tnJQT01d^%}IBd9RpWg30^kXo~`NA z`4UrdtND9n4Ni`Fg}-W&d)4ZnMptg9ML%(WCfYz!P$by4s$ESYubXt3*qeLMx98C* z*(H_G)lNo5C3|~4Q|6)2#MXOv%N?M=07^wVlgy4gCV~homeX$YxXj!;ZL~o_{F9$I zGJV_=v#=XrBUF2S_?_1W%x%h-et5PwJ|@xl+85+hR}1zH!8cnU=8wW0f|hODlQ@6l z78%iM_NE9GlK)ptb5n z#-XTsp@O}GV$&rLXj1o(&w3`Umg=Y@IC|8b9#`5PRKBv7)*ZFJhPoXg$_tZYt zPy?35@ZWo2hR5kZ>hU=T4WfkV4N`0X$mXS7R(Sb|_m=#Xv*igR{qcG%R+?zU2Yc7=aA5g+5@mB0K9|yBb-nX( z_=kNOWQ+?bkN}qq4EWw=&b__6SQd7Z(^pVpTqvL+4W`1EV0)gWEhK{=7#OR$i{E@9 zYKpKZ>WhNs{TsCE-xOL%G}DWOABHG<4l4+s=$-c@Khz7{UFI3lXk$o|XGk||ph`j$ z{Cdr`qM=mhHpgk9#yJ0Z=y$VE<0^4Io)3;U6YYK@Cp#SpS8RGV@eXIPzM_g!CSq=w*{S|$;P`d7=NZ21^V>S9>a#wo62 zqSMoM%0QpQZaD(0PSni=DkX&FNYC@M)JIzn=WK+(2gw3ozvI2#az7LLnQtT3!KH_#_Zd%a1Y_{9|gHck@0i9DYqQi zNtLk77~;z|JEi*g$0_@T^CKpAqN~sN)rdK{*{1g7Cv7&^W@*JETIdh? z#Ac1ln3J?3i{jQ9m|<=-$pc#&-1A#?_DERLAEwxUpicoe&7~&z?Soqkzgzd63A4RF zANbEGhY1CB4_6bU-D@&Dubj%GnkZl#>#(ov=6YLS?Mc}oqIm4bcP&kzE5hdT+5+#c z!{YA7DDLr>ul6H+dk1Z(u0PYa-6nJV_J+mh9YgR->_2E8GM`w@*X>WCZ_Q2&;s(rLkjAI!38x`*}UHO#K$Eb;yeUDG2 zghc(z9~%L&M$ST53cUdyZ`v-$+{ZxN1VbQ(K(}hsK4ZA}=6q_H`ElEEcQ!CP{86tx z|Mg8-^X&5bt06uz7bl%YR16HtD9!!PLFZ5(%lQV;_umH2o4HwiNuTj`o{55XR&lV$ zk0FjZxxJ=C{{y5zlPFfkruIcbQEE^D=SD1Cwvfdd-kq_dBkzsL9yuRh=v~@a z@_38zYAK#Czwsp`>-;scUe}2p9AuES{`gzW)MID{^sr+@onUy`uUe}_TMLdg{DKZl zx;ufvj(FF*%flAo&eIA0)izXj{`HRiHAAhyim6)T4{G z5$skoL(Qmh{s)`G**;EfQ(amho4Y%&oOW%#%t(Gn?nnQU2EY38KRTuNzY4J9WH6fM zo=Xj=VJ*KsX&x5$e>Df4#H7VC5HtRoFwo|oTQIp;)kxVd~ zK`*H_4%ONPmGHANA#FkFBDSvD3LA0*((c=~lAFU~f zKpqod-NEUleAfO zzPf!JJS#gHFZoF9OK6FQB3plX&3#?ot3>*i@7hqv51G9GW4v!9i?7q~&SW>LPn5fX zFCuKUT+Sq1HQK~rxxDfHUVrYWE*bW{F*4BrvQqnIm`3>xX8m?TvvOltgcQ* zZ1)@N#NqC7md2F9Z+9zi8zw4FJ;wWd7oI*)M4l6}Ei;A28}&-@_Qg7RR2YXfW;mGD zj9;#kr7=5C6kD>84xZ{}i=EE4pkmvDrd)XXFf(nS&XR>~zw*Dt690R|{Z%^uo`7)6 zA%jAV%(^TEN;d@QEiWK=xfVCx(adLUCY_l$ADN21IcJkO8irXB@deSv=0Db<867e) zB(*LumElwP6PopN`|tKTq_P!o^Su{IgSnA6#_X<*I^r5pEcP#tw-w#GH zHaj&q55Hw)&aTyElP6cDzY9d?r?Hj4v<1nb%x92Xrz?EzW#pgpT-U-28E^JnCr4OZ zSWh3c^Fd8`8cUt_WNNBxd4ko{cu@N*H1&=08dp070AL<4Tf%((+yO__0l3T9o;H|7 ze=qM(`B?+hpq$WZuANdX_lpFrpFPt&-Zp@uQx*4!xk7bKw5DzAjTODdtEnI9rngUJ zKmJv+a(FfPgln6KgYI-jDOCb3$j_t^7#wnmxPmP8AGIj28>%5-3pnKYgr36t5szCb zIZCEZ5C=63NU1SyZF9b*+W`-mmSc0#>#D4YqHYc&-4Xm<-OxLs9s*7ghRUDWq;9p0 z4OZ=#ix16k+Y+O`ofb_s^%S#)JsoZiIC!yTnNUVc?WS7!{6suj+<95wE#ZWfWiiEk zI6}~w<&)cGc)vQA2*DOn!?%9A=`DWDpbpV6bY~}BmnVWYNvvei?z?h0| zf8!Jlu8)M~Oa8QMfcw;Dxib_^n}a&kbr5sXJ%VMb0ocLpd0K~}T{F}lQvXcF-%s3F zX=dcvKb!INoOsQFP&U;3i(G=RVM5#JsORi~HtL>1C;Uc99{GhQG<#?eF?&Q zRR_ilUi;RUnj6s=sFKz9xppijwf7#}&$i7$m&3@(^S8F2NO?$}D&>`rB4jkNM34YL zj*SFq|EoGnXI$Fot3!Z$H=FEWy<7|+8`xMH9tbOWx9_rl8Gr(5uD>6-sNo3x)_d|! zV?y!Uq7W{3Pry)X{^-SgMoYWC15vXBUW8g|H@qE;S_?f$I3kCx5O!c7ZoMmf^&4NX zn+2{}eHH1hY6b>-C7o~bd)&-vO44|npRMxTp19uCj+V;zC04$i|Jsqpx zOPQaUes~Wd2PI*b%k@uIM&CilIQ_Pw#cAn>ZAlXsg(AYyVgReK^T7@7sctlleU$Zr ze;nKZnJ7sF>xS_t-0bv;T9!lfAG6^r+T`knD^QZ(lHaP0j*eECP}fq|(m~sw0-fHJ z>?Whm$AemLQys?D|EMBsiT|IJiu?iMm84l=`4E4~ZwX<~5der3zQDUmCD_lL{ap(Y z*zn21lp>C2dK1W0ol7yK>t@m!O4#BWq!m(5F~-D5T=`qFO9aiAQc?J#b%lWynKEaU zFMBTF-N59NWouQV+R&%!>Esh)u|mz{?(V(`ofi6pNSIf|Y6jy063tns52(XJmmg>$s#VkFnhlM6q6~qFH>vygK!Fjf-qC|&m?NvjjgcTk@@*Cy}jV5B#}$qGgTcDQ+}QhPhe$v*7I zeM@)jOLI3=B@^uThuo0&96R0-JAXZ#|3D+S1awzMK?ipc$^wG@E{T@fk z8m49LW!6Ebw8G)5tw>=k$<&Z;#B5x{Ila4i__gO>Dygh6i{|SOI_`fMQZ;}CX<*L^ zj^V|P8L@Gk>JrCAjo^l?evpC>>so&lPqc6o7K~vwEt2|M|97;Q+*lh~tN2FxlmN*78F{{8P;mWZZn`vL#Oj z4SB?YG`p#Bv(2sMoZ|wxLSvECo7zoXKpBq}=Fz@UyIEcD9P#4ms$esRfd$8K zl(~WjG8aJ>&h)~8P^@q>6%rQS7bY=O?oO+2pSwrLBQ4gg$OJ1LRkoYLB5#jCaU{S) z0{QKUmROhqlN)E~CbK{OE;hB6{Y~_Kpyc*RV>AaB$7@81*zeUqNb>2a*M$%JZ2x_e z8IyVD$Ae`1sqdE~tAw-iU3O!MW&IYvWvsHYHnU+W8j8}7KQWC)Qhn-klarE8Oxmgp ze!uZYy)#(TT)bq4XM0Kdd8RJT`-YQA1HHvuuY|z-)ANc}R56sx?5-ZzTF3H7leEpf z+go~ydCyB5^v{5iz{kB+|LU9LIY~ny@dod-+lr`i$Sp#*PH`<)L!U_RpE@nqpVtR7 z%j^ATpB95WaK?9XyKddDsZuHUHkVPg&^rjmmOSH3&=@~%j!)eb6T0amq{3ZMx@Fw^ zd*=XbX2uJZlt6pwdkQ8}J$c`68$A&tsH(uCY^^hzF?kvaa;FIj{GhshKNtnuY7aV` zhxmjY*|8z;V>c%Ey_q2je$ZJGJB{6>f*3JVPNqKr!b5gSZ0#kWznK4p#d*CV@3WTb zG>1mq|r$46{c=<=k>0_>LJ^L9tgr7{agprjqRBf`6dU)l2?>(_B#@4$Szkz4$x&|dAVdgAAL zb8U5^GxD^$qBu`-PIJ2Gjiu;iJ|DJgI&ZwSd**4=s4REs59k7X=Y#Q2DH{4WhVi@+ zkO#?)q4e*L`yT8V2o|mPC2ezaPzT82-z5}`W^Er?b#kR#G@Imwq6yNm5w5cm2gBc` z+$w3OsXBi>w|SQ4yovGo1e`AN{OL{6owMg z{7-lHHiQUwD$pLk_MwM7nanHU;;K!!=`&3j@z3Fvf2R%9rInpvx9(c6IBcpRFOttXl4Dd~ZaiU+Kx}Q3OqQzJcD@jqEeH zGm76>xIeqEd}&B5V0&Kp)Nkgcd_NsX2f7+238G!P;&G&v%Z^a#x`c2y`n&L^id*k_ z?OkoR9YxMjY!1d_p9hLjqO|)1+rJDV>~3!aoT8Ij**t#8rPdiaIvn~eYOY7s@7Y#- zlb0qb+}C;HdWCqkEXVC$$iz6$v+P>@0gkwL89-)he)FX^t}x28c6W8~-PMY+H)qu4 zoE^sMKKGp>2P!hkZYS;tURdB4=cNeS^#c zc0Nk!f|DZQtgG``+QQ_~Vm|<50I75`Bp!ctK zFy4N;GaaaM?@4!_h_6$&FT)tCpOUn3eLW-&xqbb@IkTL@$$4=}^e#Y9_}ER*r<^Nv zzCx>l+7tHYb4k@E5rhWdyKxv7wsyqAu7+gOo5&#yp@?1Qu#$97terTHu}2iD(R58@ zh`;RyZyBK{0vx_wV*kSeFx3+Z$0CuM>5g)(*K2c0_?`Fhrz79Voci7wOy?2lI|=J` z@+a>O+Z)|XWFl;^mg4fE*)n2f*zQ;MkFuhOt={(Y@6VkXwI27aja|+h3!-A$&R=3J zm2X|bgP)d-km1wm#t#OV9R~#qX2I;o4&Kc%i#1*XHM5@!LK&IEi)X31(P#SXHeUvK z+r7rr$K)Yw`QJ7XvUkSbz4yG?wf01>sLrp?$CeD3M4~`hUnEN48aWD{$8x|+m4Tmo z!trY;`dk66O8J!Xl)MXIjJ6c4)%nKE$3F94{+1WI^*2QphIlI+MTwK5F?$usfT|aE zmNH&SXK&`pJ(@531FWIe*g$M9lbr3>=sE+l_G98G z;>ljddP|<4>#X>#EUI!Xx0X`u!GkKsvb$=(U@jO7^M(DF=D`gM%YhD2%CPu-AU_fO zBG{&ze@<7FpG)_91$_YeGul zt=*5>^bRE=mmgcUjQwUE!R!{dntbilT^n zm*ZI6C(%93%-5{8YBpXP%9J<_0>i)ke-_o?rksyRGs^xkYG3G3jz$y6x4XAiBcIk? z!=b3oKZfLX^wDmS3&}se8a@)T51hd2HD78EYKeL3kdG$dahx)bjLW56ad0EZqhoBQ zSfT-ZDC_tAr=&p}whX)MMCQO&^b$8*;oIz{@Qt3Y!V9`SGWbOod1nq*-W_X{(fz0N zpIUS9bL2N`e>Z>D~Go^x3qV zCS07n)V53730G%L-o6qfZ|&1M_Ku82ePGe|tTWe*kBBwdEcRvrl^=qMNb~^0k>w41 zL$YrI*=;_`6U2idBSr}S+w`eFGp}G6Hc{BpbvP<)m8QBasMaKGV{a2m88B@1Fv2qz zOolA5$&`Z1DG`E*r5rFKD8GHR4Q|_3&J6BZI?o&QlLoeEYXz;qSDK+pE07q%uU4JQ zZazNAk4I$Uj@BSsWu1OEn`u2SH`lQ_US=J`FjR9mz9;dq+9G+pO;U;UvWD@h9%l9} z6<`63c)zP9Z5pyF1{TRa*Eer9&t+Z9BENWH*);9|p~aCR-}*HvhVXcooCg>bc)Mzb zH=m413tlh-6erF|s7oLdGl4ViT8EGh2^jS#DE&wwxH5R}oYvZ<;Hd{J2W>&2RDNS) zh4r+MS(wdRoPi5-nZZi3_Y}B&PeqbBl&v8M-Zw)2a}7i?B5!cBGmC4^w5*%z7$_wr ziI`+zeH_&>l~#4;H_S>>uh!r4l8vfO-XB=;dLLePv- zi^bk5DuLRk3i|WrcNJK3tl}JEFMQNn=oH)7-J%hE6D&|d18KV*RoRuYCI*aPJ-GY< zgrjQmWR9=Alq{)iKEZ61mIb4Kna>#rF(?*Kew(S49Jwe*QXYdj1@RA<`(%TwozvMk^4U5)sZfE0SE2VpVLCk2d_z@iqtGxcPciF{ld^Om`k))<9@=rnehH3QO}TS#sqfE^n7NV@jvi1^*)7o){sQ6 zoaAz_QeKrI>XCBU_*k=MvtlkSYWdhO0(364*HMbk+7VWb%8# zV#qUGIYXGs@Z|V;_6>T-FYkxB`dw@Nu#0sE$+%}}T*W}wZqyo#JAKdWQAdANSSi5A z+F+i8C%nM?V9{TlE9zm_;V(f*IiShDp*l$f)4{1*|DFGuIE z(g`@iN#e*g0qSPBODfk5kazr$i0Ar0#V24oVj_-b|1yZTnv0_RfnbyKUSJ5%MW}9O zUKpQjtGx-Ub5UNeM$$GObxM$n%y|~{)r{0*jnRrDTxK6 z#B+Oq3g86v!$k(~j{v@s!1$T?=oE*KI&@F>0Bypb13lTjFPgeUnz4~>#n0)9F`egm z{e0D^vbiw>YmMWuD863{Eix5`J})p^EMVK@FwKwR6v9Oz*8vbmrq`WBAFkFcsbV6j zwC1K6kyIshyGX7tY$UA%=u8H+!J1NSRn;a$19LD)I_t5WM0+!})}578q$^2-tO*Y% z8YIQEA|w0}j(zduY&O@t}JyabX9r4goIV+oY~LWtmNNV7P`vKk4WPAjB+!v8k-l@Z;YR zHYRJEIeBw$dT8sz|1lQ|CKFoy$qytRJC!y!G_hR?WG{tpI96*je2T_!52ov|;=Zss z@})P)dM-Wo@=?%8H{23U;0VsGg!Xq#rH|~m3FCwaO!Asvv7rg*yPbT7;UuzKYS1jV z++O8Y)7F&%Qg0o=VVUqW=H$F&V=y&TJ=ev|iaA{F3Sc=qh1*GX{u%?d`Sp8OWTq7E zV(*_`)C0EzPEE@ouy=L>#Dahya-h(<(BUKY5GnG$n24bih5!GYJOYKE@eG0Hi=_}P zY(|V1B{fO;KDV00nUdff^2S-c2fX(U7%O0d`zX;BRP&GZjRjvv-i>J>?ZTYSvm)f? zXj?7F=1imD{1)q|w(PL1@jLSGhn?T#8J}|5{!VqAt{VB!*@mar&qC;cT2b(+_25Fp zw5;)Lnl_MX$w;8mi{Mb4|4Q+#ugwGD=Y;qYO7io-2U<`KU^(Cl^9z=34PTyvo={6~ ztY55PqMox~Sjmym_09316BKc|j&3YutafesZGlH6j~rk+D5STNWcC2MG7+e^&KQnA zo4B{Hr?34>%>JLJ5e{{FQcc^qVhif6ZxRM0iDDEg683c;mohQ6aue74TV&Jhk2QN6 ze^`TraJtBGqE@lJxSE7@rSG1IQ{n#I!|~dI@NBl}%iMh`O<-cua@vZT4U(cldP>eT z=$dq4G16{BJ;y(Ab@r1sQo2K);u$rmFeFO9A_q587h3u28pU71Cuw|=d%pp19OLZd zTB@|Q*Y(Ctb6ozbnv3=D@n5;Hfq0P$uwjm~1?%U4GNSBL;U6LYnyg`231?bGT&DTcOtz8(^*vD=QQQiQKk zrRnh4ZmkKNh#`tWX9pSJdN+;xE?8!aOSJ1s%`bO<9zo==53q&8v%wjWLq>pFqCT1M8XE-W+wex^D4MG={;}E)s)x)CqW5iMLf{q$N|M_2 zbt!ARR=doGms;x#9i_i1U@O11VlBS3FpC-ZhG=4zz0PW$f`4KEKodi1QPH3~lAT{GKGfYuvK0#!Ai)#ETuZZ6)`m=4UDCjzkk{bw;{cL# zjMSPsB)1ApV9V1gynga>%o1BBZxPGS7SsJ9yequqb%zcpE znO|ohX*o|WEtaO$hAiH2UyFACF@Kz%mv!Hv8>HEs&{|a9tdA$z#ayq2%jM{(r zVG9pW)gM_YW+mEnifqrI{W#N;GL}u>dp3}sz~#J=A;`XT`$84L@;)e%LPEzM0KKd$ z?4NqVW+rmSYqDCvlBDs&mk}HJs>i`rby5&;=*$HOB(1IuXvOwecSp9(4sd^H{#K}h zSV{5U!818hRjfetueLLalh=b;-dK39A``2rCCijJR012;@h`WBGJW>BC)HzKL@%uT z<^w0rN{9mU-`_Zm+(OJCpWR^NS@MhcOm*~qp$1u)W4OaIwXDU@amvVe1gXna>4Z8_ z^k)}F9!d7smyyB%kH%0TPj>$gGU_1YNY2Y);*GB&a|@)at>;Gu>rA(&tLY_oNBtp& z!n&77s)8rXc56IcbSxFTXK#B>x2gi%$No}E{O6(*$#{fDzQhzkLcJ4M+*|)dKRiF< z1!-Px!!eLL+EU=0BaHw84GxwAz^PLZw-!<&Db@^Y=D*j`Koj^LQC0l+H&Tj;MtAh! zyrk*2I)&@l9DmL6on{Om6%5sKRg0VBzLwTq_7Bq*P#Mo9dBb&q55oo0nJVRP<*znk z?xR%|R#R5R%WrY z9vyv#HAn^yJb5nF>;HO3f8AB(=i)6aW4p1VuQJkMv$lTw>M?t@SsHb1}pMA7y@h*B8aj7B~M+HY?Gi$X-)ho81 zcRy+_rOEtf#6QO51;`m&{cR#-z|wF)trd{)@{ma-7c~;wU*mbXQGUUX1PYb_N)r1a z!GbLM)0oe%#rC1#X(-$+UzEC{%Ne1 z?`zk{YVRyj$u92tUtLH3m};pxOWz& zFNOsFQblx|Ao==TE`>;1-Q8?jZH_owEq7vGYHG&O%R|6{H4cursQ~P)T`=#Q@+w#9 zUu*k+zl;oHv>|JYEG#_xcK(EkpZ5;J`>7S5rB-my*Azi8liVn&rG-o*pxf$;w&;1k zfg24Nhw1_4)E=05#<&I~vVE8Hz1;)D7lqD9kH3uFIA#2g%uS%`F##z5K+Rx4wkMRG zqrq4l@;C6o0uKo|2ApO7c!`9#2Y`_?0c0L405`t`&|u}VP<)L%hwbs>R3_O}O%(iT z&TmJ-|ILX|dFTaDZ*jQLmq9!|^;nAx(O?^nSZ2B3Vu6D1b2>C)`!izT?0Tiy=*(Dw za$A?Nhc^|tXOlI}pr0)05hcPhC;a}kxo2FV^#MYBL+NKD{bK;zXud+vr2W?m{^EGa zWHs~lr{V9%;_EOV5hosp9oY8#KkiX~G@S3=URyO2Sl10;soF|Q5VP!6y|^O8CS$?P z4?`wUo@{aLmoouCOs8~U({TZB8wH-PKV0%oHjjqyzP})Ur}3vuMebk8f8;qbAHb8S z5CX5kZO3V|SI&r%xWoQ`EgpePJb{ZA?_tEZ02Qt<@$|~Q;O4(-1|VWnNI@fCkT{yw z%fg=aTqS%kx>oeUjNVJ!8QGzs`tfV|zF}bH3LxjB(pq`aSK%ZZw; zoe>HSO9USNOLXJ4MS*jAr}rTiALm78)!$dZjKj1~=E!)2r2n$=z9I0R51`G_P2(B~ z;^DBK)3jOyU-U<@1zdb*HZX@j!xMYIH`?AuPdflK`IJR(2hp1RQH097yr=Izk_ylW z$*zO#=Kdjo_&Cr7Ub@ta9vJnveoQ1|2u-BXbF#7ff1mn~1NxIc!cy1~GU-$-hLd{_0!1F@_|MEI`ljTOzg!?2AZXAciUq0*>CdKRI~~gZayzE)aqn^ zo*()^@2ftrp1Vt`>^aYJ1h24DZz|_xm>D~zzgz&Y%MA)}3 z{K^WTCtLo!PR0H|^0n6}NR^&h{~ulN9gp?@{f{HE$`+E9nas)vaT$@MkX3e3_R2-W z-jUTXlU1_!ya*W)*?W)dy|?_%rTKb)e&2t(dA)AN^LjiVkMlU^e(vXfzeiM%a4!ga zQ4O7<0!|Cs_Sc9#4lg=JOmC`S6mV4cLeUFe3XE70mrPWqKaO7REVR<=1_f%(>rQC| zShG7R1b)D<{~63zUt=881qzZ4C`R1iVyYxLrCR}Vj8!d&_mb?tnv8BzjILY6A}8aK z(Z!Tt5N1Fkan_Zk5e&h}WEeZ1{NLxq#$sFa^%F5?FcWh$ypNpiIQRV%^H&dCdJps# zJDZh`$7kY`jVr@=UL(Vf!ExDbt~)cvtUa-@0A-losDTxHcdv8q%g;FL7hT~;dEQ+v z$h>2x^f8*X9Owp>yx&1s+#dS*+{Ty?IzkX5Y#+ue7c!B3zIbX>KPQ>i-{<9`%zv_Q z8Ab+t&Bvihu^tOaJKz$)impNXgqe2*-6axNMjJj~Byv9hvSf)$b_TwIo*&MJxR z&Q8L%RF@Lyip{82t8)4G8`mYRpmfd%ZMuCeV~69@QRIPi2iJ`Uw3O^T|RFkDW^IwxgBbLlGsOC8Tahg^b}glHR??p`Zps2$c)?GKc^LYY`uJ~$x~IV zU{!1$B4I#iYB&!M<~4q&C=}Iy-&)6u-sgAh$ z5FcTa6oi;EW{*vsKr40-O3FdFXeUV;K?E&T(=uCjNg6BobWNuJFDwSJL2e8hz*?n` zv$gV!L(G8Hzd?o20E+j2;`g8bbQ5C(zsAW6ahf+q49q;~dru#WR_6Dy5HjuH$d~9Z zeSH)CTKt}4yhDiZPBVkvu^3tuhom4Zm@lWEG#KN(?Y>>XuN9>@gGufhoAw6d{YaTO zrRINM=${}CH7J*uf@+IFe_HOzX7`6g*mUq0@x{!`OC3~K8`@@I+g(-EAE|H)oEit; zrGfe0Tn{`?ryM_W_;X|Pc8S0L9E%&6eEHaZ$CUXWK>Z&$qed3i*4GO5bpJ9J`tOLu z?=3Gf{X8v6XWZZ(_u|vM{qg3>Aq3jo!F~|gU2k;Pzd01+{VA6n6!K`{-1_7(F!A`W zg7NwSn_}cR=+NI5m7LD_pH1`gn4*J5AjasO_;~netS#int_j*25HV&;kH#sc zeA6vyoK68lMc!3J=hqt}2tn*^E)2p^9$24gAFO^(&WdranpfHAf75`U+sF-~gh7?} zi%Ozu`l5s8FYyK-VaZB+53P8_h~*_23$VuLHC%cG7^BTCcXa@oTFK$~?zIY5u-ML7 z)f2z321~5Rm>@y^Mk`C-4gBj>eUrOU$hlb_?+o_;y%>L98fTS8u$SxIx&v8)=n9CJ z=zBH6Tczs6GK+y+f^0x#w)v{^>7TE!lBETVf`q{IXbbqEsECUXMM@)=^4f2DJ-H~L zWQvb4#X#}=yrdbicBJ&7G_i>R#84A0XAJk*yl=jowATN7m(6(6&2>HfT#IV6=0=wg z1QZvG6{|yTjwpjRSK6w|*`JRw#@dphQ$q5?i;wSxfj*g=;g*vE#!EW(4`jbqGM=?U zf&86>QhO8F7jT2G4sxMS&A`BKleRnHS1|i;mh9{L2tX70^&V16$B|FWT3{-syWFI# zK9U_htTCH^>@%*3;jhICK8b$&BG}%Z*;Lfx2!1j?8y_z{`Mcx=tXipXmWmDT{5fMJZYeAk z+t^Ii)Fr`qETTDNu7@+@!Tqek(6Y=An4TgPEJkby)iZAK+BenbF{}cp2 zQ$`AEOo$iCa*m=@Hn@elU1qi2^rBoh2y2gSD|A*&jtvzCnV6d+bhzP07zwuC%rS(r zh2>GJ?(eOZkFC^^;|NnR(7JfMGRBCFHrg};IW z?6d~Y2haVk-1rly;Q`0byFqSV8&BX`UR*aCiAkl6p-D6$G#Vi=f%KNCIU*T(< z*A21=;ZQI@z-6jKNA?u8RP=$<0d*V?lJ}6>#T{dES(0M?U;faq&9cwr`Y@11QqGQH zR4a#HhL&wopRRz`V(PSo2FjwAWwFjXvF+!gjf=X0%SADGi?waLai%E=m;LtSHmK%V@5KF%jSxBkZS z-+RCpuN2HnCGjeIs$(TR{HB{yCe>l7P6yUs{S}Z*Pr89b_Hib>dnA=r;jR2`4Fc7S zX;GI+<^h)?(F3Vt*>OWU&-Nx$qaePI2F*sH~D9 zXU59@05@l=bl)`ajRhdDE5uIl7f`Vs~q4NyL6$bLE@g{0;eQ{_}*L3qRkaF9Jzs4EM?X z&!IdzvyW#g&*P2W(~R;#OHK~GdHve+14#2`*nI!edFO_X!vEh592-i?*l}I;8w972 z^sHm8vM%hU4#zBn*k?I`tJYR^M_6S(-d8aLX zmCC8cp=VpHF#8*(ApTy}2gZdZKwSp$v*7x&nrbbedKzLhUMbJ{UpGO%7skr=GSR(; z`Zwnr2A+bPxcdbvNnd>Fo?N1ePlv;XW?CUVA83=LpFNNss6h|!;l*B*k30=^U;?ftm>H%Q#6 z-@_KWi7aKE)B3 zl`7mD@gN=m1DOdD5607H#2#l=t#v@dTd!nvdhu^4ip9bPAxBl&I#Me8@Db*)w1@~Z zdeIB`Vt9l9&@$c3@%aJ~9MnU4U<^6|AXVf-^3|}LSi$jo*OAh{UYn9OcKFv%;34+f zhs2YKR>+d;(JMRpQ5u=};0v1TlIXK$O6PX&b|Q8*E>68KfUH2{gbeT8$sux{e>&l3MRM1hy@xDQ7 z@1M`4f(?#_lZiK@XTxQ#b5MUFG)<7lP@yeH4(9&a02IP*@P2V5Az+@WtgBXx4;Ci< z$?6{~H#AIG43W8xFK8sV|Jf>r3K)f!Y{#<&awEpR++bEM z=kh$3g%peabvh_`++g;nhp z8smLZx$fZGUklcui=`NO$%YH8&u&QS%TmJKW*yZK8KGvLD-#fS$&=B*q^(21q>shC zeTVI5bgsLF<$L&Jx4Yb1I1_It7wr@%`{0wA1O>nGx z1l)NCwA^#If&Cox;itk^`XH2z(0Iy|0q@BA)|HLd%rQ%jQ=*H0=QHr$$x>5<{MpjJ zh-@+houo<6g=H32%O~+E>hsRclv=_;hx>sLivg^u@p-}@S z)|Jc&ay_|rlOri@8Njj`_eG)6=drhjjxruZBG<-(W)Dx>UHx^^IId&mk&;^VxVKal zB$!pxQ^&u68N1`k$H`BG2kXlUQ;RvYB(mr=Np64kJSOJN7lJ8?OD}`Y@d6<#v{(!j zwMN_4pOe&IU5hysGvAtSt#VrZ%FZ-EC=~*vOrPXUu5Prb8xXqo24Eg?RQ3fmX*H8N z(Lcx?d=_wz<$3(0f_57Q$D*+rYqq)P-u=lSWEf9kii}yiG>{31EKkS!^V+SlJ~@%C zbiwo0bDruOp+A?-{2A7X_yLeLkzD?a0AZ;lsw4|NES;lZi~d!yB>0Rez68Q;_@aPB zzinS=?Rp+RJd+-64n^{i5i zPi7SFrLjp2dh4sctw1mA>!=NM1OjRDe)L%0=X8<9ZVQt4V;U_Hf3~uh42Cl9y})fU z%4b=hz*H&CiZCcxnH21cP8;}GyxP3wvil0H&MgWTcp>Tw;0DtmCp0D-c!s7l?8>*&Bjf|Fn>*r`R zms9Jv03>!Sc zemm-4>8>q%1tVb>KpT8@m1%d6BQ;?wEe1{%{zhG8Vy*G{f?7)-RbQo(k9kzwo@C98 zvbaaoALbu?2t+q)G;}h=W(AXsN}FgMtK@qNupK40-LzJL6ITo~Fg!Od#p?LdAv=_l z^YFA9S@!vUqu%IL8u0)N&jf#^X-^&c`0h$VYcw@Bs`LoI@6S4Pex=$_&Yin(0bT@R0Co@=}!I<6s=Fjdj<;NssASY&j)pWoYM>sYlwf!yr&O-jS&wDLM zsCxV`az$7$dI|jPe?1c-pEOqS6&b)oOI_)=c;_o#-OG^OtMxpSme9{Otsm`Q7^vM4 zyZ&dh!53bV7|J|D2KXO+y7T+=2{3QdmKhBu{JG$UNcAT*+U9v5e2Nf8J2MzWZS>`v z-QN2yB#p}<6%4IoAEceuSgbUpgF?hS%QxpsF$awKFt+rw!_W+5Wu`N);% zU}m0G#`HfM;RrX(VRB^`#6HSnAIId9RQA5rN`mbBT!+=oi9eteguSlfUMQk3Y{{{k z4rt+321BkTtj)x$Rlvn%baRz~h3GkX>%-sq$ggL?)7*Yz$b@?~DD#SgYV~d0?j*g; zGP9l}16do~ArZ~r@X1e1QK=Jq`XT!z#-&_BDxMSX5GlK-cS2*Z8Fw}VlEnTlTQI^k ztOE^BvO0$oX;m|_;XSuhI79aF!+&QLluEI0bc7Im9{Yr3Ar$NKy1DEZ9BXkeK0x*) zEsmRyQ$hZdwf|iTQ$LKQ1OUpQqo;|7b9jx14;a@ej~EM{eV=aj@3!?tY+{p`G4|E5OlRHio!UiSm!V^uyhdg# zvnAiLA|Pb(?>AFWxdCEc0!_8!#C_-v15omuYzFn`Em<(0W46lu{!}1L$&J0Lb7nPF z@1P#7Y?1*o-}w{gTb=$zi6HF-z{QAl8nG=|6spaA+PS8hPTp*2gLSs_L^ zKd+uDzf?2Go0Z_oF6)A)3 z>YNZrS~6l4A8hsy!g#q^_j`Hr?joD}=nT8#5}D4w^q<%YJjM<_Ww|G2Qu*WeB1(Z_ z3tU7klRpvVXGFJUS5i?S!)650hx&tYEKz7O{LjMxDM5{i=nl#*nfA)lyneVK1_3z) zTJf`m{IF-!aXtg!1GRKhY(=IJ8nLdUP(43FTQotcRQHgJGwOE$L5E@i5=4^nyYQ;O zsoCTzG3)AXC?1~7Bzf~{h5dK$p25=$x9K~UNBcO4SN#>nd(HAYgJFMv(>RTrc@0zH zfUUnMbj9c_cSxQBkEknvPPEJB2Sg%|k^B4GE0!x`HIj^IF=-TJzc^NmkFlTg*tInL zxy#@Sf-qNn!JIqfDS&5c6)vies*M4cb;^8AP2}(UKtCJ0Ud1B0?oCA^=1!3cRan|^ z+TuUB3xO{}^^AMneRT2&v;g9JL1-WjOjnDRoR*$hf@zi|@GOXe7(xA`d=TVEbpS0J z1oOj6vT~ybda^i7D;6R@eq)FEu| z7iX#cfe4NQ9ETwmY*`yPSD&S&Vq zR2NQ^i9V0q{CmO?cd%@fYXQb@^Aoc!eCyBZrTP5nq_5@NAU9Rc^?#rQc%XcL403!$ z43%#VJju`aT}n_wf7hA=frS<=xG#UPR;l_l0gFgxq*!_jsp})H%_8LAPi8WxzXiT*zlv^v2@*dy)*EmRr zm+3ksf_O6VbJGRI^m=8EPugafmcH~qX=Vy|^~v`d<4a#f(LV>y)VBhvd9o{y!h@@Z zoHVD-&W;RnaSl{8++Bav;5t!K|fP0A6}kCe}M{4 zelYLM1<4cl2DaN5~cO)^VdaVcwAC$l_haV8y@Kb zah^`+KvFoU-w)0%1~C8Vt)^Qw4CPk)1>OO{0>lFXO8{XWgorr@{(Yw{@57b02ou)U zP!SWw01C4N3~9rM9^L{@nGzs(e%nYC#&{YiT}Li&ynWPUGuiukkLi8JQBGpYjM*oR zhV?yN4dkZ;P%XXJFjS_8W9xbU*7IkT?qgF!tqMaE_h?9b83~^AqLIO4!fAJ2zW7W{ z?v*8IfY+~m`%gnjNf`T^f}D1bK@4etY~iEgi=L-#Naaw?WXN$T^RElS}%;7`}bz_MYxgjxm}Z&|EkVf+o=DNuX?kWvE}GQ zQH9Mz5o3K}lO~h(^gu5`#GkzK4OzvUcV}l>0#@L(vuLP)7*VO`2Xbo?Q}TUdXN z6=DK^0KCQ|_ifPU<`@h&8a@X3d0fmoFnAq=)|~E+zv@{Za1-{-E#DhlLIKyp=neVQ z@}l*8cCE+||4}xk)Q`V>qdL4uBaMxiv1Ye%w(Rez1P)*%1`n=HNo3PTidTpviF+6c zxp&rs;IG=0Y=bNw(s)uN9x`4`1?g__ET(-wlNtDh;hN0y6{N#HazWbPJZTF8{e`#9 zYc>B~3MnxaFyTk~z~j3?)jU9tL|DOqwD)G@&7mnF{gx%%zT6})M$!}D5TcP1Yq${| zgqz#u0aqfj`GP(bpu|=gb?Up2v$)3%w&U_-&yCfU-iH4M*3M#*TgZHR z)Kie25FezyNXl=dU2T9Bxa};SYT4+O(e~@NBN|DHz6XjHpqA0JyD|W_EK={U(E0M9 z^+&Tvq>hu~#$_YBC!|z}Kn$VTDfJ~vlj)nCG zJ-<~9oGNZ1b4(NNJj^F#Jl@V2NBgG39*YfQ=Wu=y*HP7IcXLI{lq1eTidYdL>4z83 zVNZe7Iggq}amHup*mstjX;Jpi^}XrT(XpeXub?0O_v`<@3j`|%Uh^ooJ(Hfs{QLKtaJ~@j!BNn>cZ@j2EILx%vld6 z=eLJaTz9uFNUe>MQ;|K#S0hWdOM2-`?EhM`=boc}$<}-Ue9Tkdnd?e)hV!3&T<9;a zwO>-qrxU%sYFShBSkb878x@eESxn7;0kz?fNZ~Xy20+E$xz>&FmGY}2Vz`PDW6^5Ft zAwYtOi$)X}E9tN|H|x)5dX`wL6<*xs0?8nTNYvBLg3eBVsdJG_;L;_4qXhQBGwx?o zxL)45o!@%6SALiaDO}g!nN`@|4+KTq!J^Vlg?Z!{Bdm>p)n#12UylLLf>@zydHzBo z;<^1L8XRdygiQNJOSF7zB(blI_<6o~8&rvJXgSs#d3Rr%r&qy)gX;=6hNyQ}bH_Ke zBDKEmn0+gY`GK^g;NURF}YYdsYt+ z)ttNeroB**E>yT3GsydKu;)|7F#A+C<{5zern5OULfkNac;WEnL$n3An;6Nmf%Cy2 zcX9v$BkM-=MA4B+=g)uY5EZyW@krhT-f>3~mhE{TB+7~O7J<`^sEak~nYUcA-Ok`o-+RMHS(^3^UXYCl+RrL+ekY(f; z-RBlrYvBtWAyEi9zC7hPM~({RxYCl_UAV&T?E-<`zn6Sm77-H-Bb4GGU-;$#rWT$*>i_<6Hn2xqA*_{Q3@ zk639p%v?5EEKnC#AjLR$#-ZTfcN;>{qH~>7C{->mkz)E?m5reS=Xc0s0hJ3K_}7yWrdN@fVBto9hR=CPlRp^o-phP zNR>DgKUi;H0F6QU!YeL?Pf_?U5b&8v>atylU8ltg-V0*=-*=0Pi9>XO(AW6YXHKS8 zsk6H|N|aaEd(Q0g-fgFH7C%AexHb17BBf7*&<%RjDFU_Uy>@0HxK1oaYc?19L7H$kb>~s< zvS)=W>bY_h|9$U4xMN1o0UyudjfA7ag;D$yjOY~_zgvNeuzS@HyIsLhqYE2hd+`0U z`#&zUj3kN(oziJ#=$ab88vLr3r+@A7K!&P=P;r^#30+~rj2rA`1m4^J#-D?I8Hk$n zw0*kSGqP{VmOm`ndXJJ$BGc-!1QV%cSh}3XR5ad^No~5x$lW5Eo$1Z6|`NF zPHYrPIL|l>i82g+8nO50rptCMQ}R7wEmKBxT%1?T@&TXokQOkBsk{5KK-~ z2S53_0*KgcJTx^!@Ln}us>%nynwpwkkb$Bcdg8^`Br?aP(RxAbf`=R0a<;J>+?J0T zfm8V~*(Tyq+&J5nZicoOBYdX~l_<~Sc)!TIx4=|>{zI5;)v4JEHv&|TlDDm4?@;<+r=95kNF0wWJ&FcL)t%k3 zwM)6@yM5wfR;CoZvh4(250S1!=~QzaYp!{xhkIA`7!y^lnssOAs|BRrYoKB;qI<_T zL7RH_Lu8GRnbtaStmk6fqPX9$b+oHhxp|kbn)FQIsp%Hs(?9PBJVvFLIF8*3WtHBX z$fOyuwZnt*!?48`QHRC1qnDGK_?-a8jXudBK7f-Zun2`;F7zY@6gT_V*LJ5$7Eujq z{i@VeR(mkGTL9HwNAnm8qm!__91>XjsfJM+tYZSE9a&Itc}|_YkpmEDA4DLdYFP|7GA5Ez`lPkFm(&=SIoEN;9~Qd2_ALzc z__>5X7t?KwE0#R3F4!0Kdgc4Nmx;O})wJU^nP!nu!oc(MCB1S1hjphi!7f)uDVffr(NL(dehd>ZX64pbxY_|rJ9aD_~zqc_w}kvkUR0g z!F73g8wYhkleTIdyRCLgjIZ*yg*eMN<@j2Z%St&N&SdnAe%#?Dw9Pp=iMHncxiN%U zV)bRSIIp!_RTJxQLiZo-hEC(BjYoP!uXu=oWU7*%}Uxh@Lf|si0B;#Y!;U+Y_0^p*o-1z zr1{E6|NC#Fm(?%Lwd`AmG*x@Nz#wHN-!(ppu_`9#QXb=((Q=tU?Vv7(6TaJ{`qx-& zBTAosGTte*-cB&h=k%0VB?#S+p)~GzFFEbN+S$dHR!CQ(GXK$JxHp;oEgf=bpE}u3 zoZvo3-H6M_jc2niLI=VJi#s-_H@_bUbAPX$aW7z4s>KQG-UOD4DauS`qTrFrLZy#@ z`y1g)Jbh*X{#_J^VldoV0Hv}EUI<;M4K*sw%TRL-mKnP^8Z+ApZ;K>|UQ4jJ$o_p@ zXdU=yIS#{4-R~S%zn&;rum36%LG}A{ax7wL=pf&Kn$;6!V(FMxitS~^&;4-a?}ha` zci93Y-O#na`!?}WpD}j=&m94)3-gmgn;%{xak}mG-e&{xCPH2 z7mZ&uJkH#3M(s;IE~m}*vUhpi`_&P!-p-PL#a29Z`{rd<4*?^qb%=YjWqcrmO_f`S zcwOAly$>$G^YyM~Io>9J?}SN|s&XMGO};(`OTv>?Tj)PtI?9ON5^hJGv%TweaY~Ex zEi0ZYMWCqG-~A0MBXw%|bHEFGIFBzleWw*x(OK+|m`({h*+#1>i9LN^T{BI+<8lR^ za~gfS)dH4wgS+|ZPa91`a+goLIg%Q;m4R;zzJPUQ5ioiw2Y?qeL<%c8H1La`DiTXEPkfLbt zXsL+-`fY;dyy$$rM2x(g!1xs!wc17RA@G?v*LE&6fXe3pYJV^m+5>r}ohiLFRC;eS z>b<)XTwh#oGnMF6&6i1s|DVY7DDcXrrddZ)$a$ST2$MaL0%ill+=}hCrXt?pfZDo{ zx+#>J`294x8G3&Mr0AT~b1%~U-kOLJ7p&dVZ8X`Zxh(eRZl=(|WWZPvdPp&NrE%~b zDe!%16_|deHAlG(0-tJm@Y{4lud$*7KK6NU4vL)fNR2+5IG%HtZpkWQk}w=!VG1c$ z_~`X8bC~1V2bU^BKGzCTyi3N~&7s`7CVN{8g{Kt~L z|1d&>-mIU$kBw<}Um(!p@Qs@gH1E-e+`(2&z%lI7=ldWobZGoB+CFlx5@A5GK_l^W z-MIThKne*OcvW-(A4#2j5}b!1PWB801{Q#%Ba|*3M=G!|1@)s2-V~&2{N=X*!_LMh zXEVGTJq^RKc5~Z5_Lc@O9v-dQ(LaW_5HU2s9e(#IB7zXT#IY^djy1Yij9#0kvJ8G- z#Yd+WXr493V`)lTB#5+3&1|vh-o-Xwy+ zUE!dvXa&j3oE&j{VU;u?3xF;?Iw(3{-TFa+>e+1aM{T1QBaT2Mjv%y{w)#x-@T~z< z_n9Xlb5&iCesdXycP)j69dn&vO)^R%fG%2;Lf6_g(Y*)BNKpz)ieP*_gU9icIU2f8 zYH$#jZr!^V&#jqNp+;8>los@4N8&?dNy5lA_?~%mM>Mr$B2;T0D!Y6t-N&ER$dx%J zASbHNT6$VeEXMrL9z$<5B^4Y;91@f()VzHE)VxRO<15#cGuY?pWGrPdgY_vxqD$=i z<~_e!7WB-jF+Xf>olBPZR`7a3w4Iy$c5-}YvR?bFV46jz>6u=^wsf&5X0mRpoLj>* z3zHecMS%kTR&N_w6&B5LiO%HVTny8!FNp5?K7Rk=m6nrcugr(mSqlu1@e9OinMqVn zdA|o)KH%=#7Ox1}9bUz~sBofoPwsbM)IqsC*t`JL`KspGT^VAWs7ty* z-y%6RrsJ-QMjQkh76k6U6NJG9s@F=}(hF$Z3zNi4-4T+Sxk{!i0F{bHY5|ThgLKe# zGyvVby_26o$Wv6|C2=X<cVgakP9&8xRY;hbD1&lmiH1*lHr%HlP-7@x8((v%MeQ(e zneS6c+?gY4T&R!Y%_4}aKV59`Ii>{1e^P4<)i|o;Q?B&MN^ep^qqnz!$9!%KS>wlV zdEiBfm8_N;+6l9RvpnZZ<7R1lEt(|`OVPX_`^kuhcY(*pJ-t4cS>6YCZbZ6T@=G7F z4wq6ZPSy-l)(}O^(*j<$@%g08vPFI@E_?mMHw-9|xCyh2v!UL9s#(V1L#!x4iyTn# z*aD-NHBu|381lJ}WOC=E6#A3sb!2>q1%=CG&A{I~3U=)c>~*iW#U73Js|mIf^^|q* zmU^5Z6f3{Crw4dG1vAvy4RzL3TQVNUreWj!-jWcxB&o3T;(Aw7DNg$%UB^-9P&+sDyoO-uJZfW(i}mtTR${f!EjZ+dX)zjJr0dVp%h{iz zDO@^ylI@g%=y{y}Cb-hIvzWxi#Y+d>&nUqy%je1YfTL(sOO}aHQ3Hp_O9CwrW!)k@ zn73^Y6imZspd_7_1FC^Yt{F=xp1 zI|9aX;3wI+=tc`oblN174M8SU6&Li@jyJZs`_5oMhTk)2>e&)6JOW{VZR+nMHJ+!g0SqzUkO2(M$6etEs z_3~%qEagBkMg7^R7geC~#%^1u58J-Z{^^e;X{tI1y~SAtlg8Yq8>S96N>p`@H7AFS zy!1AG?b$M^#0MIxNz;psO4#f-VtB9T26jZ3Sd6=T>G`HN+5c|vnN*w`zx__Yv9@nj z{`=%Tk)@5YpCrUf-RjlO_cp!O8SQR8ZohCNpW(~?BwO1e~=r> zMy3k(<;6_)Tn>9@swOoj)|Qy%?W{*J>HGY-4e_9j=7;NV?2M8VbRGjJ=_G8J=wt%) zYUr4K<(}J8>~9(VP-*@d7$SRd*Xhw6vIVd>&cA)@N+()CQt0ws5*Zh(^({Lviv|Lc zSd_3${M^&4ltLX87_G~2Ml7Mi$Olp2>VTllX82JHhe2dm{~{0zt-zGRK~0n*^lJ+6 z@|!L6HX$3i#GSce^6UrEM|Xlfqx{Spa=(*MTjt>4;E|>UD6qyV$#%^X{HUP~mJOyz zQxD!e$$8PlP3hXje7F4}|H8-0+T9ap9Jd+s1Fyy`I89s`7I@*3?wZ+zJP0_`7kFm9 zE6byj-N+C? zjYWk{W4-v@3Fa6lS81veJIMxIK>%?kc5|o_FUZQz{@+5snnzZW^~Kx|va+h( zS}<=MqwV)6E?)?gNSFxazJ_;8Wa?#^o0Af2U`|(hGyi7IvtiVeE+2Qs^gbcNlXA~; z;~gl;bf4(Q!cOYSzu#OD{`Ms2rTAf198!vXUwcX2@@AC2PK%;TLdS>twhsz}!)#u6 z&qhhnYG~Vdoun7*QB<*(R&)!gYw_jjD&Jpi$mo;xA)-qIupM%|Oe|YaH}8F;p-Z!< zBK!G7IgikC`G%?HsPMtbF8d9oEEy(>1G?L5l0;i)$6}y7MYYJms~l|J^~5J17=CcT z-7##7GKIksLr=}ySQaiKP@ z`8fz9O5BLiSf?3}_vf*VyK@-9ZY!sD=RSUS--<~ z;c;{;iuwpdS6aosP#&+o8W_eb_4{nWW4hsC>IAFwNK&;^V7EpuqV)&SQYwNEo6evo z(W=QF5ZFvB)DuhWwtn|F68%(iK)G%aw~9COD>_6r^>T!qrkXR zWNm=TI1LPlYP(dE{(|(9kq<_WABZJhmA&6kyLIWN0g1pM(}()wrUVfj90^7nS2KvC zik{1D2X&=x%rqFNv7h^v$S33IGby;?)0?qdUG{0O&67u+=gxhGvK_TZp6hn}tJN1v z`tMLhzg{FxX$6`ObMm5ElfXhx|MpJ^bF*o$t_vFLARj<^x7ZMW# zAPv@uhCS(p%qKas_ zV@Id1?+q|!=oXoU6-}OOyLsZ1Xs6m{xw(6m{`-L#k+` z@hEX)Ld+JRe)YP~76de|Ov5mYJ*9ZZ75~Ma7bmjOaLc;ysr9zu(nD~sLH9+97~dW~ zOIS!c0KT%%ajC;u1!6U$r_f^5*5utT9E14+hsWY4r>*R*CDseI^swq~r(1F4#RoUQ z?WeQBs+W8=B5|kg!-(3^*7qxLbziNef0nj4pWydk z_SDV8phMtOtX;v5UrU1Aza7mlx)DO}xGcG~bInZyX%=r?58QkskeRdSnCKAD;}cF( z@)x&C;rue$=z~&IMUvz*pLFAR8&7+BJwnxO;v0xDwQGm*I@3EfwO@eHOcZ0aYw~0x zO+S;~d6YS8%w5UT<`&w^lpG%hqI?xA~Lx#259hU!3ZD3uEg$hp) z?d)`N=XpBgUk$l-2`>xM;FjL}#!P#yQ*u&3@~&6ec>BI7iaL>3B>%<(MLn)rf6d`W z*GkHR-HnSnGVRf-pA(U@?)~8UZH(5UbAL6kjHaP3@}XtY2F-L_Rg6e+5IOA>L)-AC z25^L&vQu6CIDHKZuO64kd+W|Udz|gDTmZ6UCDnUV*oU=q*I0DJ5@;?>&~dyuTk4CVr9_7nkitq2)Z{cTEr z_5Q4n!^BHr!`_LhFTZLv2V?;?#z;|0=lwP$1(}v-o2lst@8Z%DJyf6 z%-(7+xO5A$TOhxyhKyJIIA+=JKgm`2anWheTTGx%RgqPQn|+ixz1%)2(vN5d9+SZqaQBrN8o4Zcy-zkVz z40w>Y6A<2s4+~25GT-HwRx;e>Nl2WPMVFLlmha+H+K-GGLcedJttfZ5fI8$ub>(xm zx;R}I0HE6ck-y1n%YfW6$(m7M{0$tx*2eU@vQd1klU@xe6=Smg#B91H&IF4wB{Gg@ z-p(?9BqLKP4kI}dwWL}hY4B1u;PeN~+hNQpuUlbO%pov^^A%e7r1RW*+RVzzib?1S zFGXL=&M5G}tiZXKVbIu1Q*DFmE{2R+r{lKtlv$s~aDLJ$^-h0u?Msr@q=(E%;iQ&p zvlA0x?<}^Hl_WtP6hd%VeqiT3BTX|Jg2NXJ`(BCh?i=3xC4$axZ!fn;_s>3J{guYx zEo+pomv)~yhfZXVQW*q4C3+%Z@GAdsP$m`=DpiYW*{-mpzI;~U>YHt~h`WRGA9%lj zR-leUHCnsvgB>!2J2!E}*PXa*#*!(YGEVgQ*<*~T1ieAJq#e=vLI1;p@4VtWHUuw> zU2@wgekgr7ab?N~LmHDBE+)SN<7l|)2+G4#Cl%`v6UB=aVCRl zDsQNx4*I3`w)ON%PRe15)zJ(V$eT5{|rsQ*laPoC{xUDk=`fo+vxy6gsnW zD zA#%oH`r*_^oAv=g3UeBX*^f%dSGUg!-PX^PE}==W%=toLxnneTqi`@#r#~D^v?lvp z-pFAS&X%4|olJo~qWV_D%&K$oi+7o*Sx&0=N|Y>4H1Ry?jt+NdxT_xjsb#Wo>=r-h zSDq9aAR)3djsdA<@ouM&5-uH2z9$5U&o;3N+@zHHu{V5(S`!S=$mjDKLuMq;psAUI zfcIyVkgCzO+d0{{@5}&uO{a#CVX~z-z7lVCjP-7N@fTop7!d64Ca&ebsLUjYOqyBK z1zt_Nmk#CjblV62nE?$&reNliu0@nyKfZF{#kV|n?8ws-34O5%6(`2wb`%Z8e#=fG zXGBuU!{vbj40{j7pD14r24=97^RXVWKU)z4tCzB6Pz$C@^G2(DqRPTMa71+Mt}7}c zF^|7l3z+v~Et%_bOmQboBO6OKP7?KaE2yL0LH95PBbLNxkrO?FQlOr&L)p<%lUjPh zRmM`As+wYRd6ZbOTSo`aHG35R zgAScS1NBnR-4?VQdUCw*Hyh=KeX1xv>h-Xfrt7gc+N+6P8goy*=`c!sG8OBKmy2*a z4r2Z8DDLo}pAS-r;=Mc~43#bNHZtm||V;DBppG>T0G==>643Wz;GSj)X zcU%dN#Y8&iK-fMd+G*un9N}D~inZdYAn(n74VD!x@zIX&^8*cgJ7Ho|Zmub(j0$a) z>CFSx{@{snT(QeOky58WCz6y)F_@xZA3~QTe-sG%SF(Y+SJQCE#-K&v;N)a$aU!SH z^uUeJK`^vh{BST9evnfy$-SSuaA2$}wZ*OJ1I1e>pyZm5RJd7QY5k#`G!8rjqFX9k z&M5_(Xi87*4kpfBiVltT0DJ;18ME0w)hShicS(`HO}V!Hb_oc>HAxb>gi6-Wk3`j2 z&do2&S-a#*q=d(h1P;j^g=fSJ86$=YYRD?^)L)b-oM0L&qLRTBhFSujbq%Veq{R6w zUe_=g0yXP#E9)yM-pfl$TYP#>$fQbll;ScKk;fX25AtJ3ACyxA(p3PacHJ(ByJv9Mf8S2FC;%1k!XtEgLuLg z^WmJql+G6$uL!1hV*7{d0^V?Ibb*qn^q-`k;}aH25}`O1Op_0@CrxTgO4p>PTnYT& zI`7UTTKf>YzP0&6lhH4hET{Bcu>UzXBjJP(1HGe^wAl^vW(Px;tJsnre4>7KN9c9zUuGR{urn88| zmd?A$2Toi^`4|iXKz}83%m33q4VDVEk0jE|XSJ+_3uR_iB&mEI+r2Idc%4=4)1bW4 zk@LuA4t#SQsE&b(FlFHjp0k`;V|y>{nJ;e3QGHa6VD8aTIG#)2YP{i)K6yUcSkobN zCjNmT##IN`nVT0GC|XO4O<vzG$4aE)D2AbCpWNQw&nb3N51tr`6Y_S}-72;;o%BRCDq~DR)aY}MP*}*Q&1_ys zxkL2Nc_7?g%O7^$YeZVi5X(*7nZ5o2reF(TK(+hL_2uIjI0te;^a~Gft<9gm$f?2IT0o-#|No+=K=Nq@4-J8=p zJpC>c9)A(bAgfRI@xAH_@J$?8Mdi*yqrR!oQeX9enTLm`aaZ6b6}7;S5W}_0n?3j2 z?FheroEpF5&|%{AIdS3Ke0=RDotDK6yAP)c_SEH<2FP~Xn%K3f)Npa545uH9g^L@d zGyd(^h|R@b+QlDNC4>kx4ZAkyhwc-YB|UpnLVx(mNzgH^k;scwRgu|X=I)l#7Vj*< zq+itW_o)>jy{H65E#YSo2YWj~Z8zEq&U>Z=yf+_?Nage8jNT5-Sx_os?FqP{eq2{Z6Ch4l5VF z0o`caI%p*!PJOrtm#sFfz<)%vJ`-|(~}fNLHLH>q;k5o9Myc+!{F*~+i-rA z_d5y2!1{ndOgvHZ)1Yd#Ggy4i{;sY|Id%RB14IMsb3r?xvtUnENKsiQ-yVGn?FgB? z>+=q&5wSQa0_5c!HA!izIpEMwq8_d|L{1p)MKq=^dzJ6W_qSv%-MZVaf>-4uwO<-3 z*LiE-HX>buz1{tDP^oy+h;xz_336~utNAvnr#jQwel*Y~=FqU#M^^*ii=(67>xAQN zw6E08QM=8VwoVOGi9t*NORhD|Ic6H&Qgkg5*`YVUU9!mN+t#W${)+&F;dYiOc9uc}SCvtZ z=?AFK_P{&7N8k$PcPofP+W?3a?}|Z1fQ>EaLEIm2qS94m4=C}HFRT{ zO2AokN9RtvmCsKWVLUSeDVbNWG0*Ol!j_HeTB`y708i7ClnDvC!X*Jf9$1;!Y`f;cioqMrVk=5LXIE zyubUbJF8}NRdY;dF6vpUi0YSapUV^|r8|a-Ym~xy^g7kISxFSP28XbD5fAdy(-Nsv zmzfg|TJ|pMkC<#iy^Ex}R=#5#uVdGE$8xiU<+c$%((5Hao%yE2TnU};Y090E@pFOi zpEhcyswbo*&-&6&={=D(7L6&glvkC%zu|}MdVjU*Qp1C-nzkMMQ33`6BjbZ7tzE3< zCo&W5Kb^KLGSI%F@yYPv^%McCb{0G3k{gfTRi5598MxG4<9}Uvc%=t9vnjunnm7}` zHK|m1>1v$fJF#A!x6SjF<-@lYwg6$|0%lBr$jtj!Y0#&zgho10r=O;;n4%@K9uI*5 zZCyZn&gsmf#=qpXD&X&U+32J#0Sua`cf)vR-xwvWwikP#+R662$Yl%;!y+)AUh4#k zSJj~7kag8bv=BvcV-hN^sds%Br~r0xggD!jeOrn#+zI*M)7uN1p;)E)-IWC(m)ht& zF#Q3;G=qyUNUuRBO(_>I5Itv7VhZ4g!bShh^P0sn?;#J#E;>=F6@!riFk+c3p;5dCTQ@r0KX8lecOtWRo(G9*(4pyAXB4~Y#YoQe* z5R^yT?k;w`;E0nPEQG#9zJ%oebBP37VRdUi3YZy<0!mM%M%K*P2&>&3wM^uwoPz>R zsscKN88s@jyt2-kU54FRnliv|H?8EL(F1(K+=CBEWqASSDDwG6pi7L$qI6U? zMM9;F(2zZjl@=Xw?3rX!HrbL;v`{1~;@CUK3W=1JO;*U>d;hMN7Vq!p_fL-=#W}BW z-`9PO=ZIYKYVI@^;v*JPT9z8E!`qhB@H-9@>aVXjc6(n$NKAOIN#AY@2{ES5*zD02 znUcrdC#y4_*G}l!j#_c%cJ<|dT!S{`}0^jg?sCt7d3U? z+7*V{EmF1k81g9oWE<@oJVZxOUpb%1_fv@AS*X*JXnPK;c?<77yUFafVr~*kmExnQ zOrnlpxehJ&x0=gk?@ExF^W_*f+e~b{DvQ!|AEvldu8*OumdfybM2xSFT)JZIRUI*P zk4I3VzW;Fbj_~pY%{-Gw_jIy03`i-z5$n!rj|^%j8-Kj_^CE4j_=@NzU>7>Q4d>Y- z6dESuHuhv&bhgh4N5^$jbXz(uPWW)t6IBoo&d(a-BUFl8Tnm`!G_~pa=lNyqQ%3v) zdb-(icQ3C67QGjkc;ENE`%GsEt|$D_TFANO0!QUP7;jch^q?p})gnlH6FHxN%HO-u zH!>`wqDqC5TA@T8$PB9Is=YRi$lmoq@y%iUlX^iFGc&VL$4UGsHv@1Cg)6GqoFh}z zJx8x*db06k9dNM=6|%*J;cD+XN%Ms_aP)-HjlWQozdT5pr|lA_DNqw>KThNhFpKZRI zbMvza!|dl19cg^*1vSZ^JCZJrmrW*|H0ut%S@y=Y+jcmbvi@~WFj00W+EMMQW`tRc_!}eZcU(EC;%hZW9X4oN)*tKe z6~EEQHlU1FgSB8eW1*|I41TPzua$mOh8 z?;tdUgha;n+DIhvF8Uzjifp5fkHI{e23LP3XF)gD2QTcKX#yQC?)M}6SNq2;HOu$g z()4{1Uqw;jqR;mDNi|{n+bq$RkizDXs$E-KF>ENam;F(=x-e-xPv5k_W4)%CE5T)I ze~nY)jA=rwS%mEx#{!4fFe*Yc`Uh2V_oXs3?V)zaTf$q9dFjPy8X2@IPUf$(Q;od2-QDHV z%Z0ngM65Xz&81!Nu{rgcUE;UNL~aYt{m+^*$&`pV*M|tRakFfdu{YYpBH@pE*TC7E zo0*vh8U0;T)@vR5&*6@pGpM4rf2wUC4j|nYM98q{>q{UI=f6)O_s1O_zL`If)?}*H z)8bt6;gwFvM%Tq)qT(J;(r?7*Mwv%N(sgz&cR+DG)`Bj(ASZ@7d?R@DOOTH1a(Q!- zS|5(dI5b$Xp)+daxpt@1u*Bcm+Aq;vjDN)Wdc=8b{S7SR{IXJ%-*M4mksDOlj0UOB z`l0i$Jn4(r3(_q*g%+p!=8^~=iV3g!h@G0~F7Eag&3Y7Yy;kjl3ty5->YGugi$PPr zBaenV!KGo>O+lwW?LnZYoQ~ubf5};mg{VaE!`S+mrdQui*t^=#znVC7UQ>ea z;{?d*4qr``tb2(lmUzvR6NrTsAY_pNjY(h7B`%6-JcTxvn9FD06 zk$0-KLz5m(^H=%#SQ??MNs!*Kt9Z9DVH>42P_zkC%)FVd5&4T)dESUpTGUM=!63m& zz$G|nJ*`-;5Z|Z|0vAUZ-pIIOZ_^`$@08N>`V|4T4NNX`3LwOH!$CB30cKkrFwn73 z_mMnqvhq!W^_%$GlvIBIv#X`6Zz%^xayXZS59RS}aZr8@$nfrBrXvc}VX4{)%s#2j zQG-S_@C?KPN1i^9`|xm5`(lYcQ%cQep_f~5-^hN{5gL3Q1xNqYziVylbI94uJOFsw z`epO*h+T}udV6z<;%I4CY#pP~-qX+|9Nmy+@fzc`&CL*GZ#-}{S=B$8f&u6GBs?}l zymrGS%0GdDFP~=ui#>6O(pU2fjOWcwsrXc%Lq$5ZuHqeh7D4ak+r_Cvt5Z_vzTr`H z{mR-oT$VzvUNUb-2S5l#T?fBB4Xd7-r?Tt{>&<$7t*)pN?eSP>-ZYjpt^bx*i6ei~ z)hronGVH4%wYSrkP{`QRfTaahB&naU0{y~1=t zN*QqNy)Cg5ca?CO24&X)!I7JSsLKG(NDUO20utBGf*z`3>q1d4{V;(sC~tyD5gXcYf;v2H-&CqRIWUi8j4Ggr@XA4`@-DE zZNdaA{@oz3c<6QbI6Fb~lgbtyxA5UH)Pzx?Og6h}RHQU0!hGj8aR4I(W4vu1f*!Qj z3^;uL6R~*F`hrFae<9vnf&Z+DdI;W8VM!_(kb@Rl6EYvgksk7>*u^HPMtXh=GfO~2 zE!AL%<(%iKy)VAGHz7!O)3-S&AZKwPLUjpni|j#3b&wE`Qwrud@JuLznF1#kG7SMk__#91PG>&O^Bf z(7kr8$)#4zi|$-*wH4G!d&r&6x{O&AJWIo=7Op;TogFgbrnUY=)|5k`Q>2mK2>>^m z{3igAXI1i`bcFs&uODJl)Pbez!puJ&%YjyA7i6pl5z(n+*!8qY_oMw70dQ}aqkI98 zffEhk@Ly^!yl3B%?C&-nVM`aUez9Cj_R%3d+@+b^;`M53Wd-{)xP#Fa#=k=O)*Z;m zqB{@bfQM1j`B+;uBG5m8bs_0heiTo z9Gx4STTzM9%!TfyOen^LY_o4C*Z1cgiFx8l$mA4%%Qmh0<=HZ&ykmg66Tp9XV5=v( z19jJ(V;%-A|4~||IS^^{&}jtN-D|VdM4-(9ixT9nW2R>E4!5T3`ykreTe!Ov128o( z1Cjk4ka1{(=|FH8He>(aYy~Yw62Ibew1|DbBn^3L$$8{I(DKAHDH~?;xnI|Iyf*^E zVKCwwF$%iLkw0y!oSa*DZy_$shoX%R_*I`9wXOuUO2xJ5WXx6Poz&A>itMPcN0ANM zMZy=yRnfpJDH^@VdTuRh9(Uu?&6_tZ`0sxFV%}ZU*+?Uo6?f%mgv-LK!j+N4oIAae zTXGy`^`6W@oGLl*-wUYZ-0LcEv^Z>Am|;5_<;Q_?cZS%$0G;G~ThW=y;IxLn-F2qicj}( z?5?)#QOuc+z`n!3g2Nc_I4p z^-@L)%9w2}^2)LF^mGe6_rq2HA2{Y{jFj>hQwb)?`V3rMlrUElms}7B_PdkUCR^6s zavGIZ=mm5RK|d8g7!x2=HAli{z6pEOu8GekH!k366Q4896HpthMOy!}T2*W>qi8h) znGg>{^S)1yE%MuQJXuj*OB34XP)SBEyZ0Wni6Wb4OpUC94u)n653cB#u=yrD-Ik#aM73KhLy$&*!$zVyDLA;IT%tv{;ea`ZGD~`$hF^bBo8J zyp`PtG8S%drnzYNRj-++FpAt6n)y&ZsA+!p04irRYJGJvA4l{2q@2~HRKDGK5}?N{ zRQsTVl?2_ZX7H%s2RE7J-aFpE0X19>fMIzM(h?qon3(P&yr3m99<_0<+m_!x%bAnTki09bMCE@8B7RW zLUV>~rihw2r-bf$`{SHj8&)mYhrF=SFD)IP(!UFo_*Wb*kKlB*Z9+`HTEUf;_NAA^ zwvV>riL}r@XNpsOC)|)g`0N!W!o%K0bc{HjfReq`blXqDAxg6ETKM_$qD=!chd>T& zK>GXJkCP-~oNmi{%ffTXA?CAeziCR@9QFoSf4Jx2E;Ga%tiM*4Vm`QtN^HE=(8AyiC<3yArEw`o-%HL+Fu0(E->DPs4 zz)1F45P8F&uJzXacpPKKu*YT0kJ<(#9IGr~%{2R5MVwW3Bs1#@e&Lc#BsBeOcoal2e(|hZr1Zz=6dnS&<7+BH!)d zOjWtI$-SJTru=9N=<@fECk!6+O(troeJgm`s+w_bqGuV_VdI^-{QQZWH@=w3cbQ!d zdzK_Qlme4c5_>>lHgM?wmi0NU35~E)^ye6nF zcz)}@UI@Sm%{sv~;Qr?oA~zqIMWU2^#MFs;5o8eTKnMTLcsKTwiE_$d6|=oXclLWG z+SNa8uI;bR9qoZYkTDi~{|EwG0G=M=#&_8(nevw|O~rh-R*rqr@bxR{-&ON({lMSu zKzDRW;`e&`^FM5NcFpS-!u(8;Jzj}K}+IsLGo|2Li2wF)s|A%Dr#M_<2B|eePcKI1LhVYWI%3Vr4H|M?hscLEY|k{$1yfRLCw4MwxM)i7Jr zfRr0)@e>!3nUU}Os^1af*$Lb5kv|7%a<=JgU*tFV4(fI?@>~F z{Q=w`c=Ha)*s&cy{pa^&;Ce1Sy?3>hWyfNI`f{u@zr}f;3WGD&!)X?fBv~Acq(WHql)uvyPnVU>=;u{=KpN=UpImt zrUIbLN|$xO9~AAcn_Yl%hlgww}I89MyY3_xZMq{`&}GFT!g`a7+}$>|7bT#CDTi=8)Q!GC`M|vz1ZT^nd+2 z$%|tU7-NU3e`0o?3ZB%MC4Ep9R?fB1G6n9Qghi>0clZLI`+E1z1vR6i z3%e}`I%c_1074$z+|x$5^AZ34h*(Xy1NO~bJySccV2zx_Zv94{)xcUS(df4G=HFT) z@NkE>Pq4@9KX)d}9XVA2{ljDcVmHIU^SBO+>Gr_$Z>{|A3KfCAwc>3PlU378tB*1< zMRbVSE+y54TaVMyxAj}Zhd21i^ke3fjKNjPr5OZpS}H1irA;=`NnzP-awmU33&V>5a2_vu6z;q`zihOL32u3W3FY>J zy=?e)x~o*1T3GmQ|k9KjD~Z_ccN5v=f!!Lk;IS4rj3RG zA=W^j{q{EDitR7IfELo3mguCNuZB&A5aos>Bw&-KhX^#u$ks&d++4qJ7L$cMzT`!( z!ku5>_xJ-Sp>naXl#E*f*vP-yH8W<%^ZD}vUPyabu}(({oczz_uTda1cy8hkZG{Ka71$aQmopi6 zd_m+((j@J|cEli@Q!(xlqxILb&0vw4sF{~hUQt0edt85U=T7pZ15a?Cv9ITAvyf!f zZF5yequ8}D0sjM3zLE`V-`F)O$kMFIr^_JU<8hMuyr_H zyY>h{{M&Tdwi$%vS?HmRb6Za%mxMkG>*U6xZV|hGJa=Rnv0XyEwA28)gro(?MBd(B z-O4Is+g#vRjIMlzMi@N+i>z*w{Q8Uiiatp=aPHNo6FaU4KDCr^vT*TDK0~skH>x>Z zUsf0_%b~;Unh8a=DtK9z&Ys;70sbuqVjjpBdaB!YCIFbz#2^l?2L~C%P<}WLal(5J z{Hm{hUEH>vA2|hEk$U6ahogT_hpms7QP&04wgrR$3)5N9%>E3^+YprD(@j(I;x0|{ z3xgBlzYF>EH?%P&Jh#v;^8lLd5s$pm!##EBX=vyO-pSYBKNC3SZGf1M@X9{J`9D4d zKAHMHL}^dVZH7Oey!CD9vs9RDGGfuH7wq~_!Dr|PiZY#(+-$s$1 zzvGwwT;~fjk8`Z6QvyOepTEaQ2x%x8V)k@x#^ zfqaVD_4Z?N`4Q$F59En8vf$e4Wtq$&{cDD-kB;cFygZ-iwie^|yT!~Q@u_g}zUa2H z4=xp@r3(jhFwiR(VxYNc2aDm-dS{J z|3JT6&-TwBR>#l;Cr+vV)j|99EiVXnbyr^nzZXQqBDUwDp!Cky`ulzO6~j9Ev3b;r zXvf8&-|RcBk@FSO`_p`U&C~=@JLAcpp9P{YEN79fQwx+k-fyM72ZW_CLS_@-fGih@ z^8LNroe$9Q6kPh`X*H@H?-ck)$kRiVd*BHMI%o-Mc}%Xba&y<1fM`)e`Ky0uz^!M% z>_hnZ^Jj#ncU4ZVy7$@FUldlf6J%k-a{no*s6*YkHxOh3u&(?GJAGih)dB6pB#14& zBTSGVWFo#OkfLfwu9oi1FF`9Z&1&EZ(nuWx@@p={ec8@zP(N)4NYL<4uv@&_=otMN zF%0Q+vUZ~S0O4gE{8-Z<>yOnK2j1iuZ0cMf33glLkMnJH(_qmJ|I{Z!?jQY`icMwa zpzjV&B0SbgUw2%<(g@SYN~~s{)H^@$Jx&L)SxBZvlb}m2sK)w76YcjZWxa@Gi3@;} z!uJh>2>_tS_&d`PSQUbb{1gFRqs{QkHnaWZ55cvg#9KJ-dc=gXeY2Wj8@P3b-EOKC znSF%lb`YEP?U0Eq@{Y1ZrWzob^GTD^s;~!9EXdv_c&1O+PNM(45QJU zqoPi&3Gd#Rz*=5>E;rzTNF^>HzLZ~ob+zd{+?W5SVhin~a|_wFg16-otD+2F+YQ7Hc+cC%E1Pc$l; zdT@%|jiD*p1i0@=O)>ZT9zt=`oHy7)sm?l^(dKHf6}}C|2bXfcgQZ5NfVWsyu?dbm znp+Rd6NC|8R)z}kt*6VX=ne{ovn~Vi+k02 z!a`3iTB+IqW~C3$o{6r)4vXS-yIf0@XS{z1!W{=*!SoF|7j@3DX#kqNZ^5U%cU^Zv z^y`NIvntTWbQpV16QKwcUng}WqJlsq+X07br(jS`va|4=9(RU8FM3yJy9h)E#+aXb zV@;0csEcCA8lgle zGWih0{||7uA^l*bvkG#(ZrBz~&oNc+>8TsU!i`{AnOg#eQup}_Ab-m(#tXV{)y$X- zq(~TB42juZBtR3jj!^?wSr4<|DP_b$?!l?+Z;l)dsdtBYC8^!&H(1!bnTe0mLaT^t z!}x2ns-d9EyIbTWixBQdL1V8896Nq+U&4JkL<>%iW!dHhs5qOXJOMZ|Xv_&lz!~A3c zsCXUVdvz1hKqGY@S_}MhH&sDnWqm{2mnw`rC|a|OpXU#~^EWMtJ0k!zCo+YC) zh)XtfKO5JtUaa;Jv6+?+)NPnC8R?SgEQw#G6{WtCH&seHPUg1c#d#pf?*zV11*D3m ze&BZ}0eU`;TmL=Dq1$>p_hltUce1N6Wh9287mXx(%B;IEkAb;mIb0SX; z6->S|e3R~T)Tt7@REGHy84f5>yah%OaW;e5*4#Ss36fw?iiBm9t{E#et;kyqZ{HUXQg-UK>lms^UnCd3+K z#B2vLpqXm_E`*yP1&kySB}nK%SeK3Xt9Q&biGTN7+A%bTIjN!t6nbg^ATay-@@yRU z1?*jgCK{xfHEcyJsGwEvJXNwc_{EEU3-Y?WS%jN8xT{^w}u zf@?9=BAy2lq{WB3Ypp;6W<7p?#CmxyP&e-nDi{Rlg41yJJwXuTGKJCNQdHeTyr;sx zAHbhzf8+3DU!q!OT)1_OU|fEEqccCRSpQi#vg!C>iViA^+2Cm0j8LwA4*c${|5*th zWBcM64rQ}QJ$P?uyGfZ0QjmG|px%SJzA)%4%V?|Qpy_%53a1L-WHIbfO0fFizH2#~ zy?IL)79&jrr~>IO61&~oGZepw51^K0gzQ~JxtRNY6plW%a3M57sItv4B79&M$PpXx zf%zgrRvt&(bfEqIr3=`Eyk8LA<%OSNmhFgIb*F~m8^<{I{WHiR1*gn-sA)=iYpW`Q zxNAXvUlQCHpY4cJ?!j)+YOIQu0mSVzI9fjrOTMx?TgWS_N@X2yO{h2otdv=TM`gZ}dNB>=!{GTD=eNloPEyVAkE{s)eIP1BX}h!h^pZLu}>NHd{?z^m7o$NLXv?MOoTos zX|SUQNv*NV&EoBD3=KIJTL39u17o0g$hZ3lQfA>3gJmmFK>B`;wq?E>4JhZKeyuX7 zj%z)Xj7?Il5ARquE*V&R-!ltF#^0+6@n?J5O;ay;EB^}EtU5jMn9?(D#~-kEKRLd$ zcXq8wym2s-yJ|TO#R!pUj;BE+0<4?tTD0u*?h0`=IHTm*rk*M&mIuIVdM{iVU7hK+ z>DmFIZIu3`6+UMgkvmvdYB@hbCB$#OIMHbwaCRnp;&g+Sd7iPb-B=oE0{YO+cMes4 z63zkk%e-FltH#*Jq4?5zDY-AEq9(4(Jx*R<68C3Ld{S%?^sb-N2KRwxII@%ug&Brz zf2kOELZOfbLH(>*Bo_(;7$7Wa`vpi$Wji^;^9vw#QFtfAkYN2mSC_S2#$~J1@^1ejuKe z#NoBXEZvW{p?if3;swA_3vl1hAG+haAk<#|wbI3RLA^H^s`>Zm`w=NstR_&(^-f!X zCQ}4M>eT(v3Fq0>SlkJ`seCn0YKv=E&kUSZR--~2OMP-BPdqIEe)hBz&TI=e+jNz6 zA2$eXv}k}N;xjII{2ui?LZ+it)8Rd>c-)=&j09&dJvzD!#Qe>8nhaT&L zu;cLz=^OMHR~%v49t5eMxsx$dfBRV$))amlv8hSz>+37)^RIGWiB%3cX9AOQvdLgV z786JZY{?VXbD+`quPa`72tfx-V_1`Y*fRaip^v-1mNnJF{ zQzZHzqAH%esHFJMSTZ>z>o2>S1U=iLwVA7Qr6hrC-5($=>;%P$xY$>3t4{NG+B}D$ zB)fE>-8K~3{6VG;G0n3ieyEh8)4DY> zA~O!KIFh{_Sw*_50Q*21dp4aVMxmZePUE?VWMKz{dzefEX|^3q0`D zZHQ7xt~vnC!A@-q@|#>JV9F7Pc>LZQY`1`&WCzZPd-)@7t46&H(Q$2ite7kL4+Qe> zT=MwAf+l|QV_FQnxwjX}=m27fbpssYMiSoQC_LE^_yc!YNw$pkS zf29(n#Kxgw%mEHc-hj6Aw9F{<6*X$1H2!`kiv~yUSIPu_nC^*>&H>hoLDCaG z^#xpGl*>1}Vt~XUv;#!P&>{#GhPbk%v_C9m3cX%&#$ihL9&E`N^WeKXZtHisTCNFY zO8MG>TRS?ekv99-UPRX2cY|RZzlbKx^%5~rp38>VNC7xE6Yf2QRY)iBLh_)Kv}wC6 zv4o8XsGhPl5?sn!ZxA3BrdG}CeZY_e`fw9>zg<4%ov&FhV)*(lNUwjB@k%Lu;K_vY zVq1zbyg;n0gw=<mX`G)WNH&@@mh|l5@_A)ieG9YF32CD9|GaG%}KIbE5kF<{LaeQ4f zPEDxN5+JmRX%Y`_A+8;_*^vH~!ZQmKYR-QSpq$tHO=8~3N2?5o6~Su z(cEv(nYEr_IHQZsYCF86sp-fTIh)%f7>@t&b?mi#r+v-Kv&TD+#)rlbvIy}^4ced* zem7MgQZxS#)CxJV&0t6|I=;8S2$zNQJ||8zbl!q)6_!*-AW0+FqR56UW~u~0Zf|;7 zcrCuSdY@>-KEkOs!VI&_an`zY->KKS5LV@K_l*~aayS6mv}D5c7~LU$i`R*3({Q3` zKyz4=O&KCLvzTZgP%R4w6)|=P8yPAcpB@zZYnApOmVQNIsCTMQqK5h zrajXgtDyOf3ODw*r^4hWUHDB=Ec>1i>>9rGn1s+Nk8P&nqM|f$uO~Ino-;P&6fa0Q zzDe(A&0;3M#IkSLwgCj;*Jjsy&%X};YQ}RuGoqqJ?{>{sLF<}(w66zWO)iUu@rTjM zQN@_U%zosmn$#|Qs2mFwm!9sq0>e3Fz@y+Wd3{ReKsCwv{#`R47?xxF#mkQ&b@__S zNAicF{V9)H!LZ(W9b)ECL%9f$j5kz+gl)>-tqZ&TNe*@)F-T;P3)-crxgdOF|#O_$!j z`vAdQ^ik5}!ienKD-CyzIi3&MoE*uF{}xp=dogT%t^+bTa$bgD2gsRoT1-j{UdsQvd7^K245N;CKl9K4t+-Ov*qx`zg4J?6{H%VILV zdk$W0rw$+~2{d|-_6o$`;A)2qoHj8&%A*G2=*5VX##KmMW_Ar74-`4qyDA3x%L0Jz zJLd`{4+||AL49<4EJ~6KFtzUxq0OUs0hn~Sgn>TviYfKSB}o6rk}_*%Dv**R860bK z3MYoFTMXBcycRLQ3X;y!R{ZiB`g=KG&Lw)fPBLDKbG{8xn=P7tY}txPk3)f3Xn946gLf{3^{w3^vG}S)zf~&2qP0u#L zvdQw%!mwndwuCd5v@yEJUS3{4q1)@gR^s_hBl1(pCY8L1!X2jwI@z6wqPGR^5a6|> zH6SV@8h1xG9zGzAPGwJBrGElbuWX%I+HfCr#Z1K9SVo>S#-o#bg=BZ25Fhpp1Pd=7 zn3H6JEX-NEO5C%kVeKDbd;BiQJ>Da4n;j9l$ERsdRoSFHHQ>6OSD6X^+!UwIvR^lu z1hr_LkSMS!&(*D-AT2cN(X2?4FeJwEy5EBYy927ffys~|CRDSLE?*mse|w1J(ei|x zXk!g}KC_{cN79o)X5m%xrgcIEJ^`0il=&dw@hccSfmCAPN%cKQVVt6}@S4sfv*y;)rTq}$6E|#wS zPi5Eg^CekObfXt&>Up`Mi|ldNsU(|MERt+Z;6-z|58X=-hSRm8^cct?O}l#)?dBAS z8Jz31gHFOmp(=Kz(eMUo&?4|6PrXo4?3N1RQ#z0qpN1!-LutxtKv22n@442y>M*xF zQ^3POd|S!!MEfbla*1Vy18+sL+vo^MZuxxxRIGETrdB_dTh#TFuaDE9&-E(yANjZL zpoK9`WJ9dUyB77tLz0AkC@Bd+0yadK=o~ooAaRB|8q+|{H7&P0i)D@?Sv@+jO>*dX zTay)iyd3pL-9006RsTI4WeZUwzI)^@fb>i91Ip&lrwf#uE=m$phKIemnp0SMP-x=T zPn2Bz$S0(72gT(q&|ItD>&cVXPbnUJYqM^ZmDJ5B?2O#ijPaP!tM`I**U;Gk?Dxg9 z+_dyQ&oe6+PyEKKRmGbO?ylRvub6>zEO~Oa z-BLizMMnio>YW+mais8FjU_aI2IvXu@0$3@bLpv9E={&LJ&x1%eITwhEnT6cs)Ozb zGK65Ma6xi@m|DAj(K!z>@J`3LI2N5+-I_IBGWW>XEWT$F!6dumU?+L|+C8NXrAMlz z*9tgqRjfZwK=nY)$OzwoB1m(Z2A?XENbmNg|Im1(8J<4QdPsnVjU*~idUtfMW@(c{ zRJ5#W#1P;9BeD?{&R9#5bR!n5F26ld9pEn7(!<>5*F;A^5D z015Fb*#zns(#G#7a0)N|I^9qbf2{MPFV(v6?JQIT$5kVG>UlaP8YzkUOXe4_zHx_? z>ZGCu$X`AzS_JFhQ=6`9;N{-1_->fQHhUK75@6+{Q@Ms+8E6n9BO& zgzN9Fc#ha}L{e@-nNU%=x^=iI1whlK>h4di?Tenk)?MdJNX$U&nYrf46aXS&$v`5t4ehwP*yyoIKC#> z32pAY^zpgfMWxIr8>7w8(2E_QILLl^W6*7*B2bC}GX9RZVa-x&oF>0je_-{QL6V%5e+6IYNgFyM)9{&XiXs%JF=VY^bdneQ0kb&( ztAI~VMy)-L`LZ*q1o?dDoS@9=r4@~YswvqyRfA~K{nWQqE--iplekNJzefW7ts;1G zUpF5KN^P$QFP+_`^*B};LO!8NQf#T-h=~lbgp!q-O1p7=(0zP{d`aL?q$$S{o{DYL zNVMa=q5RZ1re!#k5IJ=*7d>PW1i8!XR0YC#!k&Kv=Blg1*WE^Fq-c4x$9e;i#uhS_ zxd+>6T%&s>SPP2I^fJUqdrc7Ay974$7Em58vL9rEvTL=R$F+Ad*8O2=1&B6-dS(;0 zD0zj{DY=xscw;_wyheC3OT!|syzB(ZZKz0+9mgF{{y>sqx

B&QWuiJml{^ME#7- zRIxiUdUY>~H{LDUSUY+$w#OF-8;%)g!sbsVw)CNl%s{kQx+C#MG_4CCt}Z&5qc`wQ zLFf%dMbi;W*}cQQ!RYq+L|>w0YL9^V6AV=_HKd4eoB(qSI~Y6duB)zaMfBi zaX1|W^VBg{9W}XLK08$-@ox;Qq_GRzY6MQz$sCov1=vd+0W&LK3mdgVp^rJBGhXRa6F2>k4*D@Ln^1p zW)j|xjMfmoTk$(j4il8IkI6CIm1!u?7%2&+={5$LLJ$4~lZC>)GLjJ|R-7+Sf>A+d zt=gd0Q#l$zY9e30!}m>2>Jy!*uvXu9XQ;~q2${U)+?D96I)NP*@DMC#Bos}=fy2xR>5~+D0jsNcWda-^K4+TbrvlaPPV~>YgF<6iF;aiTR54c zuCSx3jhur0P#*EoKAwzDfpv3Tuo-u~G*Wc9DDf1LQ^w;zE*jRnhPIBJ@Gar+MBJnP z{{EM7VXvTKD!x7OJ&#t$c;Lxn&b!`m2fjteO}VahYq1_hS#HTvV2A;Bgd+&g-LaZR zxFVuC>Le6D ze1(zL8`l-%dq^wh^Qnj|WcYwkx+H7SyG-Sd&*pcp*Q6A0IJu1jw&IxuRp}m~6quqf zk5Ur|u1%Fax1f51iKS$$1!Gf7RKg2c#U3e^mk2r1>&&#?qZtRXaVf<@wnmENn&`#m zMxJ_hy*YI`FGUJ2`ZbbOSc!!`7$x5m&PNl-2^HMTK@q(74A+`mh4P)P0S$8>aZ!>& z&@?o${}nh$wV%KeDflYJ%L^$aUM2~KCPpI-+)ps;&i9n7ATMR=bx?9r-(3)zsX35F zb5o%q$N-tpBKbS zm#bw{FQcs`6*%9yj9Jd;7Dg0uJrQ z@0JCJ^4CheNnQ52kU^>=E7yG;p%|yWkE*C2oD(Qwe|fix{oO~7yU=j<Qc9GcUz zXzgOJBA~^kM7s=T3}fJL^JrYz)hYGqaoJA+DitxY1)*J163<~{bgatOubYIvGK!F2 zXJ(8bl)%=5nMu!j1_&{UG&7CDSbZ!r!B78(=vJkHy9oU$Y+p_O_BV#UKv$=m`tz|e z&4KFLq+P;XcqfcXM#BBfU_TRjRplxD>d*_W3@%LAgJ*;s-nF%1R@**GF@A=DFM^G9=tC1WkMkY_8r&tq>MI&B2-H=nP3+EQqnyk>e zFtubIwJex^V2ld|MTU0!^=eDk2I{$omWbGukBYWKFL489XxH_Ur;yRr7I%;VB4_m^ zPTLBab<26O5u_dE-4EO!G$-PGSBO^vlG!yRy#vVcDWK1P`bp%IhqUG~Q+YL)<#y4` z(!ZEhZhMcv z%c?c5VwxY$0`em6gN4ml0&kO%hgaXOt;5k9)hHlQkhD5@v0B?1s zXm~^dDiN6=sVg14%n7@`ok7PlOFK6Z#P0FDN+nXiA$3T4k|K0Zd|!UJ5R*5$wCO2+ zM8P1ttS`;n;5$ypcTY25Ka>w!s`Q8|9TOo!&+(suMq9C!(rjf&&amu*UAy-z1^Lim zALM6Me6st~IYpl&84|X&v&-?xiy4fWEI`IhgVCe@);idcAH{(jOX;?w%8Ev+-Kq0$ zd~tqkUy~*S>)o?G*+Vp~d{s#5?Yu8|*V9~UiH_5iA+h}^uF~onUCW*n<#K=B8Jf2n zSsZih{m}@NWpa0dQ)KBm)HNevIrf;A3-C|077DRs-ke$D#8+=5CtUdoP*-z6$oU)z z)s%9R&oxNEM4R}nXppSqmoSgIG%co^j*tnmDI)={NfX_NS=qeq&6j;k{W!rh;|R9F z9b^|{_DB;N{0$43@%s>+EZt}PL1lOTwErH-Ym3u#GUGygndaoPv}BT=>*)2;d!PSV6F#bPd*u9+*gZ|yWEr`@ z`L=M!pRYDlRk%!^sIx}VnECQ)Q6zZmIdI3cJ)E52>GPCFjqY}boLk(B_k6Iu@b=0h zPUe`N0Gzi`w-XuhL!0clH_w-$Hqh^0?OH5YTZGJJG`3`ZLr6I&w%Pq2U<{&tKDzvi zqSVw6_n@yhIjp4Mj45kj)O2q&Irj=)FqJ3Py{I@*CvtLNy5Z&nt&6KRQA~8>-3gWy zD^}Ak!lLrcfPRYLR?@n>Ak@6I1YZVzxn)IgpIvu}b7za{1{y6sllV0)#g!B*WWx}5 zww}d=Tp@@r>qYD^s$>XjMDK9AHg2Xd^x{R8306|~_!($^J32ZJEH}rthonR*#y*n{ z;s+z53G3p~*VJb9S$rsEBU~`z0;mmwk~*nq|0?con3CH;Ik7}@g5CxZ2U)|(F{-}Y zxVTvMf)}3(-3kGw$d;hTPV%#brXR!#QmY)lT=n`K`g{Wnju%S|7@v1(ummB(Ygd92 zkq){Y(iF)pn&;x_T?h2$@@W6YNMdR`P~F#U*Z$4wnJ*AG@?28NP8E<%j7;Nrc3=1I z-JISF26UKsO$l?Zs4G4zHY-ohX3dN=7z>3%L|4@N_N$(Peku9J!JV}gH6?~zB1k~; z!odS856}-MMorT0u&QPxR@n&Ak2M9|>cyQqK=ME^UaC$H+O&LNVMTV>h(IBTg<60l z*T6tQH7YHRvtMj=>^#}k7qQeuj#HEHp%HG?pDj_1zb2 zj!8vu)bo?w-P9>{-=|=_7Oe#oTfW<04+;N#sqcLB4ly6E&Kjrz8o8~H>bRsS_dbDS zo*BjjJZ6v^aR zOR!?E;7z4r19OYcwmua6EInVh-d6-+<0pXLgsg~Ocz7{zh%^S7khHPBe1 zt`G5v4Mj=FW8c-$SWnlocGx?nw%p|?py&on++d>9+z`d4QfUQ8W-|GMI7@{yC-9ws zjc^HrIpxXkeE4$(lT2W+(Q2YK{O-(^=(ytDh4#^L!zR48Uy*ZO>cRf$S;V{mG0M6+ zXVv_#zym-k;Vy3xrB^&{_A^9b4sLAqD?>sqAuW9WcJ5``PU)! zHqSlfQp2+`T=pF&lpo@X)5>xnNQhe=q48c1isqn&l+L0I_5-|5ryZ0f$aJoS@_sILeeTVNU`ck7%P~@! zvmBw+QfYO;?y1jveCTYccprfByEr|JLSNxf->K~iM7H&|&>X1vS_FVV=Kd9AJ)xth zIHZTWp`+%x;yv;D)GtT_n{?!DmfC6RzuD8)pb~w7d zaeuQcT8_KkW`*qN+3C$X-t$(-;L>buX`1ief|)R=I*-8%lwG?@=9qMa#RTPQ2GuSk z_byN?_L()tD`;2CsL=aus9(ZYlN{#Xv#!9RwGs zgdyi2hZIue7Beu2dGeb=X9kcq23%4ZjCM>z7i1&?kg3HgVzrSAH{Pyh7;XRnk1Xki z5;nGD{?HmNLx2WB(lawN&ZzJPdEsiW6Vs=tBpKDavrSbPglytn`WU*?!1k(9iVbnG z35R8h5K52{Ug1m?r&y}PnybSOR75!yW?m9Ye7P}xzA;vbOUl|h(KsCGC@&<;B14_$2fJ_unKfFg7ze3U1i7W( zB)aza#|DcOw%h32+soh2>xeWKQO~f+%h1SGHvrs-axWimc0io#zR4*4Z+RnrGXInk z;7VU;>q4_P&egMMR(ADTdrXmAqUW)O;ul>ZT(Dw2{AlaE(e#!I*>TsBTBQlzMsIqy zitkvwPfilje{7^|M-Cc5&Se06e2K%Gmb&N?trW#{&+T*!CjCQK0Kct&?@HIroeYglsivrKf(c|;@G@fqe2_}@>kTW(}iZ+z+HozQm z?8eo}JU9tMLDDEg$~F~=I)XO`H?CUq3tLSf%WeI!V^@B{3z3HyT?9Y9nRk9KogW#veb8c6`?^ zBHRsh6BjjMeUoXua?Hg8U%q^qO;84JBAPp)DKd(0vw()Pa^uek;`fR+=84=0z`5QZ zJ|S!~)U(bs|2R4sMqXWR(KmFJyjQm_4$F$UBb|y1@Lb#uQiT_B>F_SCyx=5Iv=pKx zR0EHB(9StdOXN%T_(aFv(O=Q=_fXqIi58<{2(jJuA#9LrC>&LxaY}VG19uEZCgaA& zLdLoE^BijK1eaL7X8#s2Ti1!kkwPab#qMe|e1bm6k~}7sP)<^%Aoa)s^XRtQN&m@l zwVCNR5DPuq$*xYAm%W^OZx0MErOiuKWmH?Y6m%L+qGu(J!rLPtnwgO(BQw)q_5o(4G3=-uht(&Rp}c*7S78jPs*rf(+ZQqEg8N)<=0M6AU+IHWhY*;ttS`F#FEG{i6l&_j}-gzfHnx-rfjI2*gGD4TJ>%ImDMZ`EV0p0m#=M|M`pD`FjIJ;!%wtRCe732Dwc^?z3Bz zvPyC!%FIYu(Qn_O?r7Y;#uTj%r^N|#sNXUGs6GvEboH8Gm=mkCQtO z$ELNg^X)L-d5Exf5ux)OsUYP8*1js@Z^98CuhR;aEU5h!9C0 zI&rZSAr3Q}LmKtATDII{ds7fur!np+DGe{qz+#;(vxH+yWp{!~sIq;O^361F96b9wZi;*K6p0ExHJE0y!ZN;5&RZCv8+Wb5bWUxIn0LJR3kQUJ1Xy zM;Bq`JpWL!hFXBUTX>h>1;T|r>JEXxw!zP1Yst8XtC>-^qrk>Iaqo*M1IT5OEP)~P zNp)!b@{8s`wASqpz5O4qYzXFfPkFn#0MBj`5})^f{){bWHd_12vPBEMe;$e4K0NYd z7riQ$iBS*EDx&xEU8ZkY+!((ZA=)B~ngeS;zn*vZm-R8yeMIwJQ^7wT2A@=m zCek~?{o~BPI?|jP2Jpr7+V?SAS07XwRGdWNiC*Qgv8={a*>LyLukS18D37y%9G|Tg zp7A2emLZI{whsBCq(Eq#qIi}5G1&N|VKf$Xpx7~j9}gF(k_QSh~ z!%^Fk0Vw($$X5J(r`K9g#}YhWoIa0LF!B>g?r3J=%rQHyR8Sc(p~p|?`Om@CQ}Ce@>;RCtTLVY9xaKuVur); z;ThK%rysjPn9uI^beRZFK8?*fRfugPpMJ;x@Sg|4C+VUQNi2jl3*h%|2(P3eig16> z&zY~56KfQ-Yju1{)@Sdm4hWE+?rp9G#yxH0a)Mh0E}ZxP#i2rAfX#IQq?c{hQH6`yN<{{tIxa?B67F zqs%!N+tq7NY4A(Rt0C`{8bl*x)Be%y3-8)f>AJ0{!u!lk(35C9c>DVGqtKKtgszSE zOkZ*s-;NLsgzI4IVH*?yN0KVK_m=3|Z8?hqnj)_FB4KxVn&9Onw6>a8+I^BHNPe*0 z^btjCq{L}>*m7aAQW!{@wV5@5BS=dHbK)`Iw)+TJfK@RdSsg8(bZ)ft%`8^7-1Imo z2AacI8r3P}egdFBp@+hI-r_ zteOq4yX~)abn68H%^odvA!0&qc{SI25Ui_$Lppvjlg?K8GvAt3fpfVbmP8dmO0Ni- zS(%b4Sp@<*t}rOn^~-IkqyMPL7~>BwEiUje>0mehg4Ynl#q29L8b!T$HN$0Zg7aYw z+H2#xeQZZ+9Y~tMiO2V2pp5q@bHlfeyqhl1OSI@I`g0n4{w1)fqoFD?!hr`8h7&Ne zf2!U`2m&6Z+;r|?CyV|<`j)rwnK*68PNJZxo{7Pm*E#ltQ`bNewCfJMj+A!7MW2}Q zifGAT)s#mRR$j)kW?dmGZRAMAg7wuAef*y$_Oj6?N3k^}CFBp!boVYEv9R$@&x6Ke zBa){mi$rCF{|~7@X-Jc!p~*BhgN7h4UwnT0TW8;(U!|y$xl?SczQLwwF|>NEn=fAY z?QG%xGO&&hkid8PZvV?QZy!_&Q9#`(3uWG7WoQ@;HM2%&4-CElAh$bmV) zC7xC17H)P+IqS4P%&}b)%N@ZI8~g@F*5j$m?-}V5$Jvvl6 zY;I~)a&ik7CwKE1EBSWA`~2>Y_o9T;GYS;990BJ#yAMVo-Pp9+YQsSyh$hjdR8%Ov zc>Q`x;2AIrDtVnD!878za(v(K=G3bAoD#7t?SYtd)0UqbK3;Yfe=;`q_SpHUZ{H8= z%%AyKgc7j=`4y9vvdK4L0)&(#!o&lOM(sCj!V(-RThar;q+n-Qcca&?h1|yK42l9$ z=wh%@2y4yl-Tmeqa@HZ~wHXz1hcH~?ZeAMgdr~XS}q=ZVJ_f0iUgj4YM6aH9wOkl z;`&$QwMjDEhSw-+c`}XWf$cR6A1NA-DC38UKM>}BIx)r$9%2vC+?eAhtADza%j~VN z@1ly`m16F+pS?8oHlFa!PP-ggR-F)JJ2#6%D=f^C!4Z1zilE;=(pi)WDbY^4#%pH( zx?zC@dbO;S+@tKwLBVs$7#*)eoq4rF$)|N(Vl)TfTxpDP-P^8|iIXZBmVijv$N$@M z;tJpL=S%T&Xeg^VgTg`~)CMj6{i~!86bmbg05{E3ZmLG_p9>BNP!GC+NBAxHb8@yT ztd5;tmpxDNl68v2akbsT2jYc~ryk5Gl(^*MdR(1GSV4Jx^jb5A7YLy*_Z;QPSqCaB zoB&I?09B+{*RjgSH~#MnrQ-1%yXEV0ueFpw4fzR5xY?KhN0&oN$HSI`(BOc%$%-*? z7JkQ4271#9u`ToTSN*qu0$Z8Ga?9#(082x56>b880K!yybz^5e!1<0NQV@_>%v_a4 zyrLHSE!^Kt`LjL5G$e@go#i5pWxDX5h4=9t7WGn%yf z$(N12MR>L|j+C%iHG_4$sQ8KF&mRBzxF_h-XUibfe)Zvxny7Kpo$c!n2msrHRC2vtyfSDa1MAZoYr+b_qLD!!_EF`iOyz z{?&gS(H5%fy2FL|>J2a{ggN+0Z%nA(r^HC*?FB+HEWyIm-LYR4eB8VY%|2hXfFTC4 za`gJ%F2(=)a94?@eCvIQ>{{)3V9+59>z~=`qlBpy-=Pct7BE+N zP~<@-!}yf4jhc?|0qp7_wEK@k(4ctglg7yV%7?dspyK(2P5a4vlEsUPsjg$o3N64h zlM)lF&%gf(1GdWHtAbgkp@Q|VYl(?tLCJfssRph4>SYht&>+og z?(S>*R$mgz9+c*!86wezAW1KQ<~~s~6mFm7ItD2~dLlB3`c7{~K8 zeO%QuAt$CYRTiEvLPsfqddd0XX68cNlT!fJ{`Da<|In}bpN)Pdff{t&iM~G~)@v>P zxL*Av!}S3uaaBGk%Ahu%zr?q{YkCqEHdnPgXah7h_6MiH^lD*#-*NK7n}CJuh?s#g zo+@e3R$N>>e|9l2VD(*x^B=eV+o z$pY4T&(f8|`6rntnz2_fEyr9rLsZ+0n%fr>-fOCQPKLD&wD=k5Wq;5Dc+#{Ps!DAu z7ZyM#P&WwT$CZbWOX4(Q}2r1@v8M`zq8H(#O;Q=hcFe0PSpA{i7?XP;V?Bv z=^gv|GvC(i>r)2USCdZlk1Qn7`Pb*F`UVyN(|X>v5B@t{MW_+aP5e>2LB?xFJ&qBf zob+leuo*O_G|j=kpMX5!E(lR~jemT+;7yVyE@_hXVbx4jG?RTuQq6uy_)0NEB`8}) zqE4i{T@f>yl5m^oH35rYetC5D?jf5gu7M}1cqk-L$ysSd>!cO>FXmfDD#l46U@NKl zo9@(Hx*y; z=kT89CK|i+gW#R0xuAv}Yw53_19P5G#gV61^O#>laL!Uju5_ENNu*)vX&_@K;MTdi zzHpYzO+;oB1q^|x%I0njmBZA=R*-NTquUQXkBpq|_Ob&HJ@bZiy%Y=#be4~WYymoF z1I2@u4ZuCy{#|C404=lCMjrWR>H@grT-7#X<}?t8Q})V^y`A7L(p7$L%-yODqVv%* z!KRNa8yD4MIB1&v71H&5HwebaUOx_DPqpx3CA6|DIy0z>r(qX8NHSbHMkp z^BT1CA;}T@H53fa|6a?CDZbS<`}CFVi`l>WUBCSsPzK_?H#oD(%g8iBW1vqJ!<^yj za}9(b>NA25fYew^8Ht0flta=S>t(>;fplkTW*u4N(<2j5LeIN^lF$!h!MCP*mzFvY z^Q_5si2P*Pvrcvk*hv{Ir$u{>^FiopMitA+2nc~%U8=?l12*4b+jD<@UCg%(tc^UtaLskAh z6~~Wr;q3yAi_zA5pgOsiv!=`DgVx)#(M6BVOPJIYs znZ<3rl99USWALVV*D46z-%?3AwJ$cj3vJj&Z~o)&i$GpUiw&NGCbHWI!T#D00&-oBTy(`fng=dW7Z8??Ag)WMs}a%Y0R%|NiTnY+^IzoCqo_lA9Xc;8l zrt%?fcWOwcG-WqjhdofTI8y!V)d{7F} z!P$1M>rF*W%J@8}^c-|HMouT6C1W?WF`d)>v5z}!4A}!IoF4y5_E0(*{d@k&e{PMe z&x%Z&=^q%VH%y0|qDZpaUUKP-HfcAO(*@cy^JXGGykCaRMPfA!etI3#O#tOSF`uqC z*`^UFVd$(H&GOt?a|kB5jN9>(%p3Q8EesY*RlW%K7-f15=^nG#$-B0Re{`3xjH2RP zb=oGbWKu7*K~ZLV#dxiT%=fck=zuIC>UT#B(z?6!qWbZNp`bY)dB`JKFGB$(aAPXs z^uM?n7qKK4b7Hkai8$)i$fNn`gC`Kvssd=sIBX+6ag- zg1o^C(CC1?%j4hqWxqE;;4*$xL-N2X(AvrukYtby1d1^CkOU4X!>~Vt11kj%0{HO* zBM>luY*!@;YP^8zF-FNe{&V5ujd!87iM6aPNAzEyua&dtxCgcR@t%2+LB{gD$`Pmx z75VG=@@p;d(0{x#X;)&ikOtS)se(%^93J2*5q3(a&I{h(+O@}t8$)e(-=}b)1)08wH5@=yX0LWWCY!hXw5{dw`^AFRf`n&hcM?9s&GdaMHT z5inQwe%zBsu}sUk9$4k4!tnCq zwKT3fNUJMx#t%@l-}3!mLQbYHNNJk5ZM_f=hr$Zt*vG@VmDZqXFzwKmNN8&dGqKgO zVTOD1;h?o>2O@mc3HiI{J}IpJLdu~esReF& zNd&Ia{6T$wU-np%e^iE#l-|vK=klS8LAB&yZx1k5Ir9Be9sT=aXur|V%9S3wK2|ye z14*_w#YC*Lho<(xLOcKgxOR(zxHEo|6J&-a7w7k!UwuDd(OAx=njoz0%Wbrnhocqcl@jX8gnD9nK4LXcNT??@*R~vTA%ep8@~0V zCOEpP!Ft}@ZsU5UmcyNrzYixm4xHfP;3$I0SbffmnUk zCv8o|kgug#uF16%$^1f+2cjVP2UVoF%dJYpG|4$F8uA23*5pW#v>!{N&|26P>oY8^ zL4C@jJqG(yR9_l@w10R1l=4X~6f2Avgn8>M#|JMW8mTiRmq)7o{v2IR%CXkgiVjbs zI@@qOFO^_+n%`aydI9;P9-tNIx804N-{TN2J@;3dUN_N1{mkJLP{VCBnrl1k=DWv! zYnd)*&d@J}SSFB~%R$ifc~|@fpSR9L;UrZcD&e)N1r1JIeNArob5SkD|K-=Wcl|DM z(wDbS-1Y%**W!L#znd)+4s9%^y=n%2*FZv#Yp~vVmMcU>zCE?7{!Ok)Yl4D|ALUTH z7TAlSdS%cn>@Ao*{C$D;w#Dx4Bo8fCp2ia zv#XokSDxLSTR=T%ke=-yHA@+;ekCGDl}Xd=aG09;Ww}pizcA7f)bMJu5aHs z^4M*{J46AdbFtpRy*bF7>zZUvcbA7k6cBDth}NNHWlnH4j{osIdy4Ut(tpM`PTCk8 zMLk0LoVgmEdD}C=8iwcDe3xD1mQ3N_bldgx$J!8%j+kbTofx3PYEq{hurwxS1Qm`L zxy2I~5WEil0AQ!CYR0(z6LU3a;#(_u&%HZ^Oip;4q#EQKJv0~{#Sc(O;dIg)r(ZqP*>NEw$hcjgvDEja05?qD4giCvzHLd|y>4-(kq1S|aR< z$sV*U9b+wQBEh&$U1{QC6Ng{0is{gmkCuNz5$LMxCS`#WQF{Q@&aWT^aW|}O)7GP! z6AswUjRvGWYIvbs$ze~xQ{97+J_sXLCc>t`kJ^~h4e8-8J#2|FM;*~MnLo8~|Hl~O ztmAG@sNai2row4JX-q;-)*@x(GKna}G3xpN9K)ao!b7(A3t0db|> zQ-|*FgtDtyDeI_ukT1}?D_M$hM7BJ1EP!2NNQ@e1oR9fj0pSf?5pO;gWLF=6b#>Oae5O+I3_*~wPx0=?2a+ecd#%eK=9$@u*!QwE>0z zU;+TW<^-iYCZo7PbF&)fi-sZi6oZ8=TlGNx-uI&6RwIT${Tn;#GNYU4GSm?6V{VM5 ziYSLNTQp1>!l@^DUGXP9y*$qM-)UR^Te~?v=sHFREcmNPL<_MVwH^w(vdp<^fQ z>%F-j{QFk>Nl1aubFl3%gKmmtmIHM0!z%7U4Z6yZW3T)Ns_F}8vl;bzb}Mj2k9*jA zT@TB5Vdt9;Q`c!Kc)?8ULt9{=F@#()ir34cmw>bSBT(0)yP>M!Q6HdJXO5;$chHCg@7x?2G;Yw`7ofVpn<*J)rsLtems zRtt7vaWPX4YSm)137_7_^qTu!Z;CNV)G~YF-1Qp5`tzk)qZW2-5Qx$j;kqF>fi~x< z_w_BO1}_8xddQ+*@cVn@3Z*l`G=!EcZ=qFY3JK60QGY~d6rs3Y;ByKQE`-$oI283u z$NZ-sA}I}U7pn%6qxH5wc(VQB*B$)MQQyX>Ir%%RKb{39(44E=Pv}z!SKtgS9%Yw@ z)iMGAvKaIj8ud8dK-xGE(ox<7>Tz4PG%<}}9+KiUf+`b~waTpIEvc%e)|^8R+&c3#t1(IdPCJh9j_u#n0R-OQwF9-ySX-;(+J}0E^{lZ zoSWkN;bYBsJxl4XP1Yk*>r0%>1f+3LqH%NGLDIe5QvCILyx=5pE~wwxPEZ|6$O}KmLHQiT%5MR zJ-G?I4~zexABW8tjB$pM3RKrDV}IWbe%w6>-*<7yRK;9Ha>C9dXWXv@dTB4`Y*uTP^) zVq^Ak9*%b$g>>{MZZk|i3h#k}DpWDJI)x8OXG%`7E6|&HOeTDpHf;0YxD#yzv2#PH z=2*d8b5jU4B1^wy9pQ0G{a!KVtD+koIrn~~R-RKPp7mY_>-}nbBKop`S zF`2M#)3;6`*U4H^KWG$ZxN-}AHmUXx3Ys3NNAZJj$D@!!8@kvKgG_cC_|`6@@5yrV zX&51;AhNmuhvUJwll*zarQKWixZur$o>BwZdq1aVyI>xEGVXR9#_LwBk6C4OvM}U^ z!TQ1T)fumu3>LTztPk9}$TRE^0)Fg?guA4hik2BE)L*}t;&&>B{01KX$cA9K1pTdL zS-0Qv^B?`U#!$nB!kpE}@d9}fU*TgIV>qXRkaYLfAo|jY76;E9 zlYGV|eJb~-P6yUTBG*)>({Lb}+){{Dh|iH+l+SwsQYC(dKMNBF^VYd>m^U9I8E6jR zS4Z#U*bTw{dJNfN^>NKH5mRDB19iXHPl}VNr%#{uHL(=wiZOY%|A3^9N(Q8$MgICQ z#TN6`l*3fFt1Teem7vp()FRRnpyooH)A*m3vgrnmoO2qF`9kPLu;#`|LMBb>{Shy^ zh!W~_nF+<|=f>VETX?!mXAfBuNk!uH@Qmac!~P=uDNurXwxG8R7`|b101qNRVYmOHXr4xm3lra z`-5R2UbfC@uzJvZ1jr~G7Iqq|NSN4)yw$=Co9z+4u@QJR0=E%3d241}(LZM@KA&L& zUFgT*vT;kg@aGBZwsTAnuv3J42Hv?AZyo3rp#eR_A=luLXvdGqbIzt_u!ieO*V|gZ zfi4Q*S`YPSdeE`m7HCTrAo`eXG}N{?SyVi+Gj0+ zXOclwXh;;Yh? zGLGv^-AO;dug04GRuKeJ=pGBAQ}$G)8i*vQKOcbdcs%X`lzuSJK{BF&%dHje0ZWiL zYl`YoYLJG=gZ~5wDVXKF-N$C|p$6T^gahu287V*tSO#BS-ncT(jMXqwmARd2jgQofHGwE09Odq#PzdjVjgX%zr9yG{AxZM0mHQ8(E;-@yTlrPtu177NG0L5xp|rC(#oZC6STRpm#XuCxk1k_{jdN-8-kaQPoZrq zmS4yVkqw{Xy3I+TE5W_xMG0PY-ySL7{rBG9kV)cSN?nLQSzYKKRplUx@ez;L*OQ^0 zG;7oquV7UwFum0{&Vmt zw5ado$)-dTj&KcW;!lW*)CPlS@Y{+etji#qxd{!M#2T1%WA#Bpp1B{UJ62RDixHn| zw&UgZGX<=t&+-bycL5hkXD)`a>35v*xBCX@K>qf}fzI=8#cs8?I_v`F-*G

^`%)l^a!R57Flh5ha#N^3Q!ibrZu@lA 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≫S`$PW>gt4u*kaY)t*-^H&_#W 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

rkLD3v7>1@Q-wdz!8pn&blhw}>x@y! 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 literal 0 HcmV?d00001 diff --git a/media/images/tensorboard-histograms.png b/media/images/tensorboard-histograms.png new file mode 100644 index 0000000000000000000000000000000000000000..79c1d863dccdc792566d57623b31b2a892ef1d4d GIT binary patch literal 834319 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 K!98(0WSC86tWs+c2TM?0Q8 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%0DA$>1JamAy2H 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

+db!t}$D8Dk(927K@$oLPrRX6~oX| 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�F$V(1>e6b_(V+9<2R1fOvIGB`XMos|skrXvPbG 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�wo|zwhGla5iaa~8oknRNy3sGXVNk}yYjzO-Vseu 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 z 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

!o&Mb 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 literal 0 HcmV?d00001 diff --git a/media/images/tensorboard-scalar.png b/media/images/tensorboard-scalar.png new file mode 100644 index 0000000000000000000000000000000000000000..5919897646d92d3988a05fe4008483dba9cb5ae2 GIT binary patch literal 353432 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

Z3aCH@vvN}SH%#~6 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�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%0AbiPOLWpF9kwT+>?L>gNLNE8=#_B)8Wldo#x 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 z z6{{cn(}_({IA?YEp>|qX@e%p`y}JSH7^mC28C+NxutO~`isqKfO|kUF&t=VE zNM&b;c3UMq4{7qV4F|iHzAI?E4HNw^x;s2;KqBxuLP}nzWU1D+M^$fc{3#>!c6|n{ zQ5pKmdXYv*-+&ruA#tf~qRtoeFbbrz1S{^bem9Lmsm zv+xm-4sA~G%$HU*p$rQAgiA{OU2Z86zi+F{XLfmuyQ7_92?-|Ce*Rr*G)j(;z@KB|xgHaaIbc=XxTi+`Xt&yu{GpBjd`~&hK znBwRm(q;1$L^X%2tYMC?=@Bl$7OWfrLBdh@fsfE5hMCr8g*A))Ar?Ie`-4iWQr+!s zGJM1kIv5x~*||pEpQLd$$_bau5i{9UfVqJf$`kuXSd5&iWEyg4(=|>N4iNn2w-UemxUJ@`O%TMv>RaO|El-3(X zqSo(i1?9p_RgCHe67L(vSnJ?xy5!72H=1*)YOWYI4{XYG;0LsHc3RQ9@&b4wflHK> zCx2I7zIv>i4xe<(5Z1UF{)de>%m8kCzq-1 zu$<<-jO#Soelv%sg)if^T6c*x=XqVeC&UCX4}wNn{TOXM=SfHBKO>2swOy`{U-%J$ zR(p-Q+i0(`RGKXpbB2HP@C7h(ONaG0?;2f4g-SP1IP&Skd5~}(elV~LXm&>U_NugNpI?6Pj@ z4z#?OO~|X+ASg79y00vbHrmvg|H?=xE_j2vKC3TPE=pA2o5XIt`&#~P_?BRs^Rx|) zTyt&soKr)@PBeUkg)&`p$B=-ouKD%^g)DBsn#PZuN&BoPIEkov);#PZCyQPzD#tIA z#>1LQezrB1nGR8&hlgYJZ8Nu*TDEs(0QV`2{Q_qubeoiFbt)D3Q6IL7}G-#+R0j@Gc;Io%)tw*V~q zaJ5a~G_AU=exO!;(3K{dSMl?u>NZFazkV8Naes_5G!88qxzr{ls4UbbB}3nqd~^SdY?6W ze)Ztq&v>CWibU=F1^;KfFLc&kS$;-J+)I2rt=7w)&JC2D71A)*az5R-KfhN(QcwOe z@Q9K|rjerdTbOVL6723gxz?7}8Bh~@J7a!8UQIvu%a!h~(Qmx4q-oi)`}@zt$};)4 zrTz5^5ySi3_MdylnanC6G0`{kJbNXE)G0PG5@(~yJ~5wsg8~05y}3l?OonG#B;M?( z#oc)3x~&kKY8Gg9&r7ttYlx+9C#P0xV(YM5#B(-1quZX?tu-&xQu48YgO`~nztjrHnqs)Vc+M(iHhF$IxV{* z^3Iy03NQJ6z^~pKYlMo`jEmFF4eDz%6Se{N6k#I{~-`dO($vT4YO!v z^-e99Z)mx)N)Yh>YX0fs1P(dyL%Erk6(v@)#0!^Tj|%-*H|w~}w_tTsj6DJ_-aBk> zp4wU-{FyJ1C)0e~Dkc$ks}F~`Xh7_F7QD1p&Fr;~TDx%63i@1UMMWm_43@$rrbAZe zmAG(*NXXX3dW0b55}x6uqT-$TGXt6(6kyhWQ37Xn4)96$uCWxn{Z<7V5{_GM+6@bO zKdPUuqYEbP-fYIb^FQb#cb^TWCL%QOM{hO$BA5tzK=xRpbg^h$nl8C&{qTnOu&g-0 zL_8#J*}CUcD(Cii9W>4Appkag;AdJV_r9^+yk5VTu(r}4Z5}i@Z~#IOp-o`f{Z(v< zkmVov911&T&JXg`pF9ay{q`_oYUCxsf*c(_*{uPL7U^ll1R85qcE03r9DrKkwC0pO z??fWO!25I#wp^PiQ@if$%G*iC)k9mG5Pq|5P1u!pRVnG*4}ADdmKX+p;GK}|3A*5I z%6RTaaJ0B-?z4h3VEUqw5qV_C`J;{WbSvkcKr`Zk_~vo%&T{cLEw2=ob!E?!u!hbYwBWQgy(&C zJjYsQW=%iUtDdu!x-J7TcY}iRy_W~dwWi>QmAIqB)a=U?vg1MXI2HmS9uWQr0Md6x7J$ZNN5>%7Qbw7uZu+WgM(JqW#3BBO_lu^p* zXnf9785{ujRKx5?(}o|E+5=}&w{4Gi!n}kv#Rn7g0X++!@peMeYX97OrcC#JGLNHL z({8&SZ?G}6$6%C3UHa317m>8$WBSXC7WjXc)qlU z8c(mVy0C|uTCaccJK!`U{o+wu%96SQhhPWC@mMV`U_!I8ri!~v1@F!(r%GG1&bjye z5};42Cw`mln;48PEA59_Y_#I_Ku+)LFM>A7@DFVBOeCDysV)cRer6}2gCAWC<%#U{txoVdTIkd5^ z%>Xy};9e=DrVeGaRsa3hMe{%+CmESQu$)l)6Ii4#@Ilh=Ur=)OJ>*~UzX8O^4NcE)3!dYR;r)OB?;N`WpCLkkGB+WNW78 z%L2>#sd1%l$JDw&=<9WW6fBH0q0FTo|7uBH!7mJK=vLuscI|L? zW82@YtnOVJ5dDEEZ9NTd)O3D-pM11kHLyzOz9v_7ZWVZ~^QC}%N_XXSxLo<$t`x|0g zg0fXhnVJ(x&Sfj0ULcn5I4^~}L=0KSIlMD86%=u8{H&AFfC%c-6xwKvy7L$Pda@yRcX!uP@5 z%R;>W?P~Y2`ZMzlV-g0p-^?;O+s$ z>#(`Yt#HZd<{Vj_7M=KoW4dOel4aw~A!5f5I;Ts2bO9%)WUB^QwWqJ+tLoO21iIYk zoC9!`%Y5Oio;8F(>GnjxZ%4R54X$EdguEr|5gg8*Ezq>((;qM#y*HL$Lbd=}E{TKv zN@?_lz-Q7C>`mQq$qik3Axyi(kR$b?hS2vJFJSp{7$1$gDhxu@<4DMo(}E1|VckU0 z)BuAfK2f@Ru~U`#%ydcf;WP7zT*rPZZ%J_3k8puWBKQ6Oi@m>&s&ehx#$gK;QIQZ7 zB$NgLQ7K79K)O4n8|enYKzd7ugmiZ*THWR3%QJlT8$joGxE`^OgWRF5xQURA14GerBy( z*vN+;AMrCxrILg#`f~voFYk3~`mEnhy*C{wwU3yLh~n@QFdPv~Wj7n2DST7)f^9b@ zE?{}vq;$mySGkQjx!#m2=10?8XRf0IH6utRE*dFsEznWDAhXbuHc&JwQrMq2Z95^F zyJXXsIDpurl_7b3>B3dp3pGgzPIw^4aP~uA(|2~VD7PH%RQ8%Sv8zcc$%{|k5)KQcc;AL_PG_xFu@%0 z#KCu=Qs{(LN|2vBgC|+(mNpB;ykWLwVR2dEOOcbK-3c)|0Ulf&S|z3;MO8_W+*mI^ z$ZDu7y``_|Q(mz`nLz)|l)z~}oVYD&4yl$l;Qe#UtSvSqD z{;hx5x1V8oLrvCJF+5puY^^nG@X3Z#h|H*9GgMGQNHl=LWu+iy=zhk_ zJn3K&f=laEkF*=Hi*{u*6v>otpc10mg?@sQh8R4G|L|i{jJW#}dN}EiQ3myf|M1yA zm*W-%FZ>583EJ~>=P%vj{*OP_DY)JEkBt-_|EGKTef@v1&SSEhfB*5~zqmAf#Ptvr z;8iZAVDJCKrMfMf$upI zXGVcL?Aop9;5k>#Jd8hk-W89U+fk7R{bA{cKNr@fhppaE^nGZN8*#U`M8WVdVY0N= zy|gTtO^~sKBt6!+t59{sDq&UcW8LucBMUBV$SADGjc=t_0q@g zk1dG#f+Co;;%?rfHQ2=WODap-+ng$(oKB1K>?Y4$U{nGVtV5)>ee-MwQZk<(?=)xA zFrxo6D$<_kXl-j)J5qGCC=B%<$TfN7g?YD#6C<{KwdxtFyS3PrcFQCzK4G7YE%7}f z(vDX+y^{v49)+&@b3k1tn%3R>^QGd-uFADRC5obEj0PhE9%6`8D&5ggA z#dnbx^=jGXltw4fwX?YaYmq<<&wh>H)%aglbQPx236=Bj@ccy4t0J*rn|?`rYqw>A zZz@r4rgX)yFjn>+vdOUh#KHLDsF?*IJ)?hEkbmso^foZ0A(TQMkpPqULf zxgVZql(Rj4V)0G@&)4MpqtG8PgVNsLK$)ipOt4eK%1ZX@>U6bA=R)-=w^-waeErTL zCT~2(RK3A(o^W%n;iPcu0lwr1ZrsZd&`1@La*7OlhQpX}Q-ceWLMd^@wGoS$Q{*TV zD>~7HSL71)^S3&eCD|Jr_80aVO+Bu#ycCP|><}%O4P9UP8Gb`BvG~}9 zjp^pR%9G>4a3*7e0)y_Y==@^-zq9!Zh zFw);q`7UykPi%ti!c}b5U!VC2b6hW88G!tPYnA3bzYkLG^T^2jQ*-LAA1`1_p|R`m zA_tX{21YpdnX-`)3M>lQ)hgXy4DOgkQ18br-c)dAVo^aNtV&?wu|w%xh3Zt4-B$jaSKO zt2+a-HJF?aZKb4K>IrPVh=e_^B^Ujo7hzl&7D1@mhDKlZ3n78bK^WHCqTd~JCmIM= zGSM$E?6t1uIyuZ^G#TnE9I;<8*l-VFeEt2>!CF1h5=34WaVIM$$F1{SDVhh%rCA4E zudIgGw|dn|xh$rC=JaGJ4JJmI7|>*uncGUBx^wORx_B@hVXBOFA7GvW0_(o}CQf%9 zx4Pv_oFJ^r$|xK#FyWF_HsfU$laUGHI9SZq_5%>xkA8Zo!`tnI&@SaEB_jWxwUkqV!@fscpyIq!g{W0^QV%P zosgnCDyyJ)ALHyNC$kA;;(Eo-?x&)qD?@>`NipAsc2bwNW+WPC@rH< za963P@-7q~ww}q|)*rU&wHiz^35oT3D6Mu0xGprPpA@MPmBgT{ zL5keU-2Je$>NwxmB-JG4w0di6dWeN6?DEtkRa}ZbH9`GX;r$*GPBKm(C!L4*LXL=^ z--#Y@Zjn(>1YGiKWNBF>yP%JXv_4WB9wpQs`@&1PCLC!j?M+84 zKVMty&l5qtESM?22V*<*luU~9JgM@gcro~u(-gKpL%}#kve{&cgg`CxDIMe=?EbYa#)6?M|(5TEmI(@G((>X zT79#aQ;*O>UjnYe#gyxC^__9$(f0GlA2C@re<=#k2^y_oy~sxw^psftI4#r8W1pdh z-WFurQD$cm!D^8R(c#Rp1LVr58Y|hpd`6ebW41UZ=oxveVfSkmupol z?n8NXNZhaxV77l%2?R$;{JR(Awv-C5T+Af`xnsCW9zI(hG%3wsJ8o}U>PYb7*!}fx zd1x(Z?#nWiHTvl^pcm&e#2Pmm=6eFexUAD@)>cB8_QmCRFL6UHx}VgRvSBvXi!K)e zXOah16EGYFuumWLq%QfgEnh8UP=4JO^V}M8THX0e#-cbJ!u=xxe_+$`xZf;*+^B&_ zHNj^cD~}Q0cNo4eSDrZU9QXx&!d8i1fymGi%+WZ}yYOrjZ7C0wms!`S;2-_{O3HDm@y^ZG@NniUsDz9wp}G85wP@QCG&zdAmC5aD1}Od6 zG*Y_C%mj1Wl-94wYL**E&lA$HjwQ$Wnwt*NJfHAk9(hBnGJD>%>=JrG*H4teB@NKM<%mXh>xk8xKm=C@=n)Qgun~`W&?!9@Nw+m#FatD8zal@7^ z*L{*fQa?vh8%hs-FiX}A1b|bfMS}Pylk6_p>UAQ{AyxZ1GPdbZP30GUUxJA9dsQ7u zG*g#Yk9Q|TGG5Py&N@n_5j+#KtbnH^q#Jua^C1|Q#*PPtKbP>jq9lcLl*)@Td{s-~^2gy{n<~k|lGZOb22*TwW?mer7>{~X8?4pz? zL}bj#em@+8U!;?CF17CPUTYu-BMe)Q5NklUzZzlOuN|VIY=f@o>rWae9)m;MMfQrE zS4E9d|ApzwK?8xJuVQIiwQ0fAulN=21lICHwKNScc{7}LJxH2pi@p#*MOV5#681Pu zX@FU$5cR78Y)@5&^^*s&t?rK5@WyG~Sc>qMJiO8?NG`EMZ?Bi}nyZS3mL>Tmh3!Lt zt?BN5TZsj^1$m1YDucmoGF3Nz1l@ci&q3N2%^Wu`D%t#lml-USu6(qXlxtIwHX~-k zMYE2pO863TY*&aJv!S9xU$fGu%3P84AN=O-+e#VjlnQ(*$?R)2Scw(_yfgb$NnbPo z>GKs@Z?j8z?*q1Kkjy68*Po!v*u!()P+@+YUw|pq<;Q*ZJ^_kIE#^_jyp--Rc~nBd zaPjuz6vH58+@nNk$W+lQ-Re<#dhvS0SuKEfwKhuw-ADNC8A{B(u^*#KeRguyG7rnM!iF{z)v&>-Gcdhc(Yq zR}>61!8fyrl{E*$kidsD2@TG)r@vZ0JJ$Q{sXFH#c}0mj;?ZhkqNp!N(^(~F1{~d4 zj@B`irxPOPRI!i$B<3L&aHQjb{1r(O^w?=GAXKnlX&cKG`_eRhW^QNnZgtmB)e5hk zuU7hz3G$X$97MSK%3lJ<+gnDN7!A58DbVC>2*+Y;P-q8NoXOZ}gI-&`i^W`cUPu_< znQHJpxq+VGk za$I#4niLnJq@G8Y;2kY!&fO}VH^VBc)Zhr+Nt#-C(n;zgJR?*{G;gg3=UgVT)}-6y zO&88c&G|Zh-Ue=J!8(a{(>O4~CVeMDbp~rX1>LfF&_1Bcr^n_tnP2i$;B2fcm$WF$ z*!x)l*1gQkFzK#TA*qGo%T50)8^3z{4C=<7S#|cm1lQ`G4 z>9`#cUB0`42T2~zyvW)0Xz>$_;B(_oATZlz{`$?P@%$T)X3||wjx*6h;W#Y4 zvJpTo;@S7UKTo%GCB>fi=a(euzyNxM?lVq zF@xZvZs13K;p|0^m!x$+$ac84D@$#(;BxFUgFRBjknMzziA#5*-zcN7B|!y=_{|Ho zpKg2Qv{?G0oJvk zI{aRUDF}e@4)hWh;FE(4!#StNZPXLS5>7Zq_hxfV^-;0&7=2#olqY>yuWT$qAV(a_ zX}Tfg?P!AM==YbK_Q!`CVjEcWu}O2Kgs&F-5Gn!*dQOdxx0Ob&w#HedybmDSBv#$p zYEx3l&DU%HUVt5o^P~&KGyLI~$J(B>3b~|7sDyKfvcvTzy04mEw1wGCbfrJZ?3FFs zdAkucZPm6xZ!o>^B_=B+MFw6Ks3w+ffO}u6(7p7kELQee7o$fsgyl}&L{@v;hUrZMSPZLD<$2)hKgsId{ z2bqKHUxPgCm-R_3WDf(%W2z^cpMKWi&u3vP^wra;;KDE8IbSl)3_3nX#o>6#x_^F2 zQ1OQ!y(AWLHKLb%wftlKTvv8~h>{6w5x)oGTEh-qkx_p~2C}+NdSPmb#SEec8!+lE zgU&;YdH;BYJe|xagn@wUq5HHm^X;+yW2X1LN%$%AIy@ORj%&5JnGQJ3aa*ZVm&t6C zyHSRJs6ia@-K)ufMFqFuOU$xSSL)039)Uxj&q1D;vVjGvf@BKoe7SQaeYllMm?!K4 zR$)cM))7MUZH`&x+u;O|=+OgyXm9QZqF?SI-B566MI+c;)rLb{z;64Z zbU@%vv-D}k#>GR7#0mcWKR+fRqHr13^VF+cA_X+cbCnza)b*(EDJsy@45R2pDi#%f z4HQbmr6RQnT$iA2DcnOpsDx1B(~Y(rNA|Ze7u-A%Olw{UMhT%irsZ3~3kJ1BS*=J1 zi}d|V)3lTkFz)H-2b-N@!$~J0{`9d*^Wtc@)KCY@-!QB?E6pC7dZaE?@X|irFNL0_t`w9u06zT@*#98LyJg% z%WzJ!FZ(rym*FtNstwWDDaN&wNF^`>iW+OwXYiU=a`Xbdf!RdW6{4qPrkmh$72w3; zaCBX0xXHG7%ZzXjmB$0K>JZ2F5JyA9I7<M7I3J>B5`$?u_h;iiO}Z;rCDWi;Sv`8ss1^0b*Na)=eHW~}2-c(moF{E63jy?>|kVS8~X9dm0qc$FN#>%bhE|G#@{0Z#a zmTY*x>I<^BZ!c68%}?gWFT|4KlGO}3tdx_>kx~8_FeMm=*bkjatl{E3HILO)#!&}r z%==JD$^qxwl~bQyklE-(La-gqX#_>+m!Aw*2L5_8?m>azLV_J2`o6)W*G9~?HyI!@ za{}Ay-oy1iO+UthUu&z?=!2*fU)1CHe9Sw2xsGjn@r1+~{4N6dnKI{BC{;>xCx5`aJLI_0Yz>}YO=?{+COF_K z_Tn(z(O*t6*w3Je4@7Rkb(cN%Gdj>6z~5~^w}I~ul+}VuFY>s z9^??;i_YE8-dAGZ`1vFQ;GE2a8?;IX7Jwaq|We z@BL@Txw=$cj5$<7+<>6X;v|ybiriUk{GG@Uw zOb+@{3`!I@dnWl^cb}GEFk*rmh76kcj`@%~k)-u%#r<1U-~h~FEP&Mg;qAHvlCwGU zI-4_SKZorsL+w(glaaQWB-t4C&L!*GNyC=2dq~D>!Ph8)!)A0 z+Q`KtYWlFa#)Zcu2_l^gy}49EC}r_+sUXiUX+#rBnj z1KOe?%)DcWzLye-tovSfCq|n$Qkf|F5poPA^?HgHJZs=nw(6EKQKf$#rzk`JxP9h@Oi|7h4Y zi{_3?;6c~QXwxS8bUOk{RbfgbbydDUiSB-rDO3>>y|9#_-$Y||B00)=;z$gj)$UI| zuzdLChpj@6;VzmPuE@<2^n`YF?KynBkyF+@QgVlWYiXmEU|dSgtWTd^W z{>UJg(8GeqY;w;+k(#74Qf)!fhB84_a+tncCWcN24%w1GYXOx_z5c+23kKbj0N7Zm zwSZuuH`d2=f~>iij_)v-rOVU3@%)v0zc}Ial62T;W>yK|GI_rff;cJx2z9uZwy^Iz z5rJbW3PBJO193_vi?D3^h;K5h1NntB#vSnjRf`jKK6$8EsqR^{8AI?iVp8N%JX1Wo~=2)@E9V;%o zt78(Hd!E3Dz&VniNYFmM2xYB-;GwpC&pEerYi*afLZI$@sq0RY@E2gA2 z*jsP1%>fYCJWr+qwI1rC?B}TlwE{%ap`x2?rL&X6{#??#as(VAP?O$zxwJRdec{0@ zKrR-;lgWcYPy%znX4Fa7xrkh~=^jJrw|?tEW07V&`@2;p3aT_jRnH^|`gEh6gjLX} z!gy3JBay%90zs^FrNJbpRWE;~zza%J#wAuObqCYVE?u>V0vRu_hpw=X5+yCk_f=6aOkBrLv*{HnopXdLQAhnhC z;ugVNebO$loGic}Q?wAZ^nL>xPiH9jmP5=-#n;uPM z6pdW#aT>9k2`l7XSo2cEghct)A^RZZQ}5_V%Di4D!dM4@=R!`W{oU?iUEo%X7yEJ& zFJX5Fc))ESkp2!bJ5D2NpdjR9(U_Gx&5z!N?OGpCISS?I*YJd5FedBlCPs`Gt_B95 zL*j<|k)MrjT$rK-R%N8#F9TSWj$6cVR?+%A$=Ows5OOMx&%OIZ=jWU5fg;mr!L8gZ ztjN!i3pix!<%gE&+?(6+Y%ZA#GXre)2eCWMom<13jgAg;X|?TMHluk0)<3$pYlj~3 zJwTG~fgiqsDFkt9SWls`l9VA%LnEB#no>!kj0KZlFMWJLPOmpSkHfbho%<$6@2 zvYOOB9Lo`bhy`dfk|Pq$IjoS5m`_baLkQCB`JyB5!B6hbJ?P@mCn5;i4DQT-SbpfyDP}MZ=6BgRL(;ort4MO-YqEc{627ar9sIHn{5DnI}FJl^ipBEPLG z6kKx8l+)!{a!T9yx2+q>R4A0-JxsmI`%OZ?!a$O93d*>q6&(X?d0Gb&27^k1gFKFkg8c7{|6I$} z99Mn-+I6m=4Ek|npy2gLz2J{iM|+xX_Lpo0TFvu5EUW8QJsy8(Wst$2^4QlW{!(I_ zNLtkC$uxINIJY~F)zTN0VC#n1F?0G4&K7RW#EnPZuMhrwI0orG=dnGgN$THYU_K*9 zZ^6>VqxB!L0r0yl+2{0|xJ7U%Pbk_Ude1i1CIbw-Ja<5q3FnMR=8n+;H=t*6qG{y* znHpq@9B$Qw-+Sql4umxzi46jf7KsKKKBLTFEZrv-Oo%pGCep!G$5KZ5ieTE^H0nNY z$-xu#>N3|Lxmb#X>?uROW9VU-(7Q#gY>Q^i0V81$iHz?J19 z>aJdD6j84$b6Lu-pLv--F5!6)!_0bRM^7U|uQm=F9eogz{C?lfq%fT0x`7X`{vAK! zE3m6rxwSC<-0oX$ybDr^!e#|ZP@?z^9VR>G`lB3jwAlw!nMF8#NYJX%zB)m=D?LVW znMM2HGDMjjuCJB;aO>w>*+G#ojS<58FKtdd%xXB(-6wya?JgQf9T*6noLZ8yI?D>#y5KDm?>T!@J=YRL{7^qxji+we``@g*Vuxnk-mVDDZr(aF{nY+^Y2vbA{ z@4{``H^A%2ZXV}t{C)~-9&jV>%%|rm!)9uldX*D-`Z}Wkyi86YvQ5?tQ(J2k^lYE~+pz@Ohv`Zs zl~|0I0iC1dp-37mAdLU#c>cW+$_h|k)pA`nI{)8&)j#4eZ|~WKU;e$qzmymM=D$3V zN|-gj^Gg5W0nQc;Dbj4*N5?udaR2Xza2{l8f-e}?P-*9=Y#Dx6O{#NI}vC)i} zp|&*NZ!7A06#|Q^H!J?fD2Ov%V9Z7F1MapTGBqZShoC5$K9M(wLi#`?p$;X&vYMkf z*p~K$oIZ{^A2iqb;LBw4sk6e*L@LBf@9 zh8gYFC$+lML|Uzn4bUEb#`wS)Eu>Y{e;sL2T_1zc&4*nbvcGdZuqXzw#Moam4_gNK z++*zkB$`91_|0pr+I!BOxmM_sJ25L|8=?+SXG_FP?W-W`2p4UjNJY;E;P?Z5IhspQ zi=eTWTAuFDu_XPL+ediy$98e~?zk5SubA0@gI)r-w$a**jNxR|<-{1&Qt4JJBg3+) zcG{3PF|l5u0>M$i`HPq3ORblT291lXaH;l`=f1F77y&L|q5={pOI*IN^c4_J6oNRb z(HitfZkGpFEr; zE7jMy=kG2r6UHw;2Px3tGn-{2TBX8#DKU<2NR9sz!XxGwj@uKDM!@A<7HL*@wmP=oR>ox}T=G{=6ip8ce^S zorrk5YR3$nD5Z6ql*(TaHI*%0Mf<&YV=iBPKXD17hnsp|HN(w6iD{dEN2OqaMxi5p zfxm!9G zpjXuzo^1fKfYo)Q>~y^G61W6$6#$aYgER?ultFn$ie&GN7q_jxLN6tU2)cZ88Gvb0 z)FnRXO_9onF~`(k7I5bRe^a`6w3`0{9d}r&eDY~_k@Q<<^ z6V&!zpfKBP&C*adO{fg|`CDMjeSFE_g=1<+9q`|`icUGF2h=j##vP3)M4>!D>%$8GBxE*LM+^kpSa+X@04uv;|v*UxhM ztz5uuN-q_8i~NyHLRkWCTv`U-*zo$&#oVT$i#wu`&uWt;_T##|)mTb2L08vQ+~hC4 zv%S&E<(HhwZ4GpU-<^;q`bIbS;$*J?uo7%(GP@ZzKMdo1m>LZf=33I<-z#_-TXY_D zr$Nh$tQl&vnqi$jy03p5<}PlqSwC+Yz@&%cMC&A~-nF+Os}<0D+=p67u>q7j9qLigja0vP@y{9YmYeCq?M^rM@YsX( zCi-C_6d8M4(Ci+CTBj~h+=RkBKk%50?&L-BrPADB3`=T7N+qPjn^j|wpS`o2Ew6M>U4Ll1f3wX=@dCg@w&uFQhdC>P+A)WW}!sh@u&9eihKH&AW>a|BQw7Kc~1wW z$n~AQ4Ca?s6KV-?oG@g44*VID`3l=*zRnVwR&>rcJ{sJ+O#(H0lD0wGSt@V;?gmpb zj?_Z2Vdn2fh9I!+0TMAWbhR1R_s-^kMS3vs@sw!A8cU%Jqz(9;sR?a8tzC9 z&{}$ahoG4f8Ru4))DmFyHe1-}+ERh(7$)Tt+0{4G3R$e8i>88=29WXvC;nlnpNZZ7 zgj=6H#e-6R`b=iyFPRY#0WBZfr<)jKpHSVDZZAKOx0-H=G<5Fe36E;za4!0G$At<< z#_$nX(tIQjm)K`^xVvWAjalt^Cf5JQ^_v?CTB_vU1la@WIWg8in-M$yl;&l>-lW&v z|J>(sTRFCMvVSfcWb-6{fUbOhKJ7U)hT^Imu=KG#T&qtji}#LEwJn*6axe)BS;es6 zr2i*8~;qm~P5VM!C!L{vEJZoum6(Req`F`2TypWw&Z3h=A+)NuCAL_5?wRgTBp zg&T&f?=Ig+T_;3bT39RU73#}c_s=+zk+DPFe@;N(Uf$@Shb4>#;=^wjpL3`bO(Av% z<&rm8dk0(BPvcu^{+NylsTEh3TUeHJ9c0U{L~PbZ;$k}&^QaJ`v-Q_Tgv`xwyDMEz zVn$&5-YZf~#A@6-PT5vq$nJF#{dq^iEN;0xO|f*n4?* zOpc6KF{RAQZG+Fi1xD^~t@W>hOELO~-r~OQ$~Om%as6<@Shag84oBIQX`HO7>nqBi zLe;_+A?wo@GAWHQCaTrSu8eI1Q{4w$WA&`&yHLf=4!Vd8MJXgrT^OmE}k4UG_du@{OB(!aXcCdZWFami1Gfw_eTkzP$&34tc5B z*wzOcn7(&C+TSM_)2&ilMGG|i(}LM!d#h~z1e-rp!69_07L+Miv4u40d%ms70c17-Ag>^99?ky7ldLOM7B80wQ6P1^&Oc*0ipqr%gQilMf92{8d5&~BEOUdX zW3WDpdAEKgn16VHlxAemFVX9~)xkvhnmQt0qj zX76o3gyh=Dt?To)VUs3~j~>*XcfkivPS{~CA!LY1C4ZNYY~? zryqfx!v&7$b9491Qc$5zA^atF+zplo=na@u(D9{xS*P!~tYpvsV1U@tC~qOfG_LQwZtd&bEC$mP4!m2V#vPa5qspEycK0dzYV+ zT|UF0Ts5wd8je>-FEgW#YmWyzqB1kg_RHFt>dOpHgR4ZYhbc0gU`tDV$?CgGzOAV@ z$^;{{>he?Pq-Q172(Lg=p;eaj62uw^gj)OdtRG_T6W#pxnrP=54E~p5Ee$pD4YV5&uCoW^sQkGIP%XA#l+G!HWlmGU$-Iq2W~Mw)Gg3Z@7Belbkwhf>LBS6dBnv?O zb-5GDHR3SO{ljw;wXPPSyV4rHM4^(eMf2nEk1OSPo{Oluwe{1E!i3T)%Y1U2a_4td z@p}^65X!|gs1|s}1fxq*ss1w)ek5aa2Ox$1YyEnGeg9*E>_G$fU+@T1B`IOe3xY zzZ$}3h0wcG$$t)qzUqfY!J}LVg06V&gR;o&_1W@?*+kMUE1`h{I0=~1(;EXXXs_>^ zdZkjCGrl8G0f$1_S0*=d)UUa~sK7s&nJ&%?!MEw9C?>5B8lqb?h6mmDn#J!+by*j) ztG@@_`4d0H!v0GmItDe=01B@1FY@HtX)qua_6bkxZT(0)zQkFkCSgW@EMg+s5$h%^ zP?YX*vMV6(C^nl|r5;`dB_ENuRNCN}B#e)`IL8h-kP|j z+OgcW>PDt**yLHlazbN`O!Vp`b7 z^cak+&Cb-(a)wO9N*#S@6~5kRMfotua;?E9ENzG8@7Kvk!T(M?*!Z90Y2b)P=yCIH zuaW7aJut-R9|La8PXB@>YfSLW@=e%x$UcfnslAb9r#Xmh{?d{e5s(yVt@vozP@}bM znKK%T}SH-#n!kct>~D_q6LzsCs_;3Ghc(*fLD$V zWt#K7K3a)ZNgArhx`t_h)f}*(pHi2UlFsaC`jq`%6uADCEl?|SQ8iW?jZmmMXV*&7I=UKF_cu0c?K%d6*h)_bKH+7H1zl0IS+OJa2OE&wPLE+ZBOph@v<(lNcg zc~#z>>8-GIO4rFyO<#}XMA?PEses%iSEVi8>H(Z_o0zPey6yexNgL$2oF*o9K`!11 z$f~S*8NG5#Z>y(P&S~+Uj~{s~^`IUUJQ^TGMAMPz_<_V)ptcd;BVR~|M@G{oWAj2! zL9u`#=#+c4Twwj62x~^@7{t!@>wk18Tmz=!%bF`BzTWy{1eF{C^gLQ z%s&uSDW5_(1io>rms4}Pjq41FidFd<6t?iim)SnYxkBLF+4UmA)8E?aggqb@m*q%S z@o>*-aiw_TrcLw+QT^ZSZt>I$j1?$;P{5`(UyjQiFdfrJv_Y59w^n9C3XKQrgqN@C z${$#5r4-d6Wkbi7O9PDT4L6`(I^-(ezr$s}IjbJ(dU%x`>8H8HMNFZQKl;m8P0E8g zt&d^UGlPA>AY(aGVZjE+#UNLeuSEr`YK6Z?vMrDyj9j)|ZRH3chTTAe* z1yvA^^g?HnpA*2+RW@gbHc;`mlh;rQueDscfhXOpM$5eWeDm2ty5_Z!fFMxQpvZt! z5*84VWAEGW9>5lb9*HvFJBsykV=^8nwo0AygMHK+jqQk(jNVCP^g!0`a$X>?A2jO} zVQwC@KLbUPMf!+2Zx}whhl9M$?E#IwsStEoHvNux^*$nTuerP6 zzOzI0es|&!3=r358_y9h5{X^{G~{{()aO^p0sJJf=NU2&)Wvc&MW_2{+$JZbqPx0R z`PlN0@1AVwD(EYgg_x%<1vhJmD#oEk@SGm_8Y7~pWEi{JzrML+8#JaRlU~qU2G z4tJBnssyRFxziyBTnVGOlvnpUq-%Q$}(AT>}Az{gZ7MXJL`EU%Tt@^l})pX_Uj;H;`-APglCA zVIU*UTw>UrstvuS6P5reTz)hAyarMx4Zu$3A#;C`;a*HywR}Cz;NDBMe)Pqn#Z1HunRLtvLi=7L1g8uVK1Rx&@wZPp@WTWvTp*e{l&E8rJuT#gM8vx< zQ8RGL;1WUkIbL-$Nb4H_mg1J9A7dN%b@`=!X!JAhu|ywPVZ_FgqSVS7D9EFhfu;Va zV%|XZd<)Jo+BH^%u-?%1MRyS7Rhk>LK!rN;-Tx+xAM6}diz0P)7X@|V?YaB&am5U5*H$b z-XN|>5+|`}Ub<_%eyGIah+2TFpd3_}B8p;zm}!(!{X#gO7^#+7=ozZ;7!9y3>}@&P zgTt#z8}RZPrb5vUMqd%Mf?V~1PSEQ9_v*1m#iYlZGSETfDkzcdY|Vd;t>$Vhx$9hu zwpp7eRctYDqQy;TV|TGF8QXi;IKo|Ap_bHE|G13f`X6BqcRcs*iN$#5EBuoPqUznz zqt+MoPp7b>6CI4l01c$IoXz+-Ylv6rt2hRwp(BJ%Q&Q*F0Z6Hep4|79lj@njGHj|% za?dYSqi`b)|8DIfqHdk=P3UN|XC(&c)vZ_Ue6yFZ32 z<_8?@Dw=hd8*X|nk80ybr*2&>csWg$dYSh6!NQh5rt%_|iCy}aaVZzBSWO-m$K5h7 zIf{FEyuE9fZ;|yCmPg8V&ef=;8%B!KMkS+Q4{OS`n}t8o^<6Nh7-EEc)uHk6esvvF z_0pxnJUGlyGP+Kaf)|2cj8LGPqW{r%0YCP@Rk87$fOJ*#bivE9%Rr#6_)(X(A{FV_ zyK}BctUPLK+t3aIv2usvOisLN^jRr|;+@1WxK~N0Cmf%i-k^+!g8yPu8rUo7;D)rtF9BM02 zh0t-BQL@Z19D18IXyt(?CJ*w&SlpmZ2f!O>?TZ&43{UnJ$nDm-bOcc(i^EJ@iug|Y z+s_h2*3Q^_{X^R^^^Pb#8J$9I4U&$SS7k>88am>Y6O|m(;ns%E$MUv53{?Npb_MCdL@?Sr(H-d@|(jUc6RVWTHuNkhtgs()?|)J#wJ z+JBI8HfRyL2t5uf!XEDw&ZN!Hf{@M1g;~WMs|gMW!_ra)Lj5IFN7DC^Ap{ z1*l$LxZUl>|KO8kWZ|2!7gFRlsk~JVz(z`CsAi17olhxZr!d{Gy2|JfBC;ATiu-in zdbv#TxF-#H-ve@im^<~Dc7J@?HV(daCs;%(Frb`DPjlLoN%7c6Dq3Ag!-6`rR|i3ZZUiZf zBKlF1DVu;B^uee=FOtFnkasZCM{Gfvg#oZ%#_spbU#SLXp*5Wx?^O0A2;mwI6`M6K z++nj$w>uFXgqYHlRx$sTU4uX8Y=@F_IGf1>jx z|12a}WFt9PSw(%a2sRs&*i?*8;B}`eMv*YjfPNCMFwGSG9w)k>-Dp1(Y!c$nfEYZ8 zT#w)bvYP>!BUKIw#^jYCEa@L+Tk6Y+Lvn7@^_*d}cKymQGhU_483%1pQRn8eagjl{ zfkMK)8$s(wo%f)kH?Gtt!@#oTb7=fXyd@i?iYyAkyg{y^w3Gkd=`M z^YwG94wv1;sY(b@HGuk=A_XeQ^2bPOr4YDVxd#=p5KT?whM z-AqP(kK|NPFHW_s*TX@fj|^i6myu@DY5H;11WZ#t1Xn%C6jcY9{b7-DWpdkD=Hy^o zLdVtT_?(W#c_$ztkrZ7GWik#Iy4voI$cf03yf(vE;b&E`c&cIf$M@V?O35y`aFKcB zMOIMYcIT(fPf182NKs4EaY@uFdhZy0rQevqg5)h^O`PTsZ0`v>hVNn6f|y}3K0q|L zA%H?o>60pUXZa7Kl{jBK#zsJGRgL%X*1!|&hoqZZ7K+bEnx>BRpB+fgBK9iys5XzY zPbIUilNT6QQua@_6@g|<+Tkfl0 zFTHs39`jk^yLU(KZ4MONv$VIKg`Q)&gFoc3Q=+m_aO9HJg4ep(++)aQlNB{%qC@J# zx9_7POH#g{UqrI}Y75Vg>$sS83UV)vC7*QA$}opds3tXjSwnULkD)@%cB1~ituNJ+ zU8A4p1kFv=yr=c@@(Z^06D!dU=bu~bGFoxy`95C7gKltD558?v4JOg5X!di8tlU&@ z*p5CqobfHbcvJ`RV2WnJU0DuDhC@uoj$vQmB>D;#xp zxC{Jjx}Lz^$&#r{08q?3b=QQ+m4xjeX7|}2!nr0ZI@J1M%k;-K)VINW=%h)&DU2ue z(i{MA`dKY=}yUo zbVy5gcmM9C-}mbK?)~k3&iU_*@f%|;MO^Vbcg%avYhLr3h2Lj0Kb4Ohjn7tAfIPwD zUh1o3nR@2X#gV5@=|Y=M=@JH#h=#$vn5e#Ei*{GI#a?5W#Hp_$_0IUbw!ih6m|1KL zq#6ZEQfnvSPuZnCBmH|L$Ey<+;a&%&RL<>KVf``>KQOy|y7LBch2qE^gfB`-ppj@VU0=u>Bvz^1%qy(9_RcIVjK%+% zni^wbBIuYNU!ks8k;*t2S(o*||05>XwO}L4F2U}2UYSRa9z}|L9G#ufp|xo@O_Ek<8yxE>Sc+ zWzFB=ORP3Is>Kim;~Fll!7TVfPi zAVuoVlz;bbUilVirDo&YAJQ$>^uw_=BWMqFrI^tnCDh?+-aIldLEK%}*EpghhbCTUr((SE74+>bC0YU~wZnNS0i_V|UJ?y6f_8Jr zM49R)CA`XKhI_2vif*R!Ul%chC3cUM_Cd9Xouq*(3#y`Lh7TaO$n4WK5DC0Pxu^*F zaZ-Zo$;L`tqrQc1Rf@DJbOi`d+#|MP^+}j4RMMGOz&?zyNUlQ1zNoXy9L?jviI-5ax2KOWk{p`*j-A1ad2(Mnl#7yyD62ME694RifG;NQUK<) z8s6arx;+!Vz(Tf6F7oO`7|o6vkF@b{3G?JM&kk?$jNQC!UWK(%C#U$9c0}Hwcq1Q$ zilF4l#t}-{@uG{5=_+CBf%U_p>6YUDW+AAhvkQWQI@?Y7J^uq z!eC+k{DwyBpYFCaecFvy}DF8KKo=g-6ER>{^n;rX? z%F*2KxEVq)M)^N$vVIPbWqK(*Bi!*t$CVcEFo%)$t1aRdFd30@+GH~(8*tvKF>Du# zz4z8)-EMGB_Byol7QdLS+wEjM*gOX;$XiDg31K2TfOBFyYnXB`NtqQ-;dw&XBrQ%i z?y)51jB_7yxT~=T(ELkO?!zJ#NwFyi$|F|#PDI0I7chRIf=cybdvq_Y9AprJ^th<~ z1~G$4ifE`gYqotI>hgC?i$2Mv3VQdMjTuH0ErdFkp>(%8*w`slNuqH{Xaeyr@qLDG z+`HBVAMct@3*z_D;NJGIULtY*&Uaqc=k)!J0@sf%=bwpCJX^6r;efN~Kuv#HSKQmD zp)>C#e-I=Vv~G%rD~Ju@-K@#Q@k zy6&#id@&Yb9+T>B#=-~-8^MO;m~vJtmPb9FNvMA|sFmwrd#BO{!%q|m7c*wCjZ9IXOHwfs|C)|qN96n3Q?UzTwndDMdwV~lJL z(YhYS*l=i;*g!WrouT5*q{MBh`)Gd)?@Vz`jDKBhK4Ue&ajju z-p~1_hw-y)+fK8nQ#FLsqYI}emL9*f<+InTy~aDX(`=5xlaA5IjcMcKNbs6W{Fvsw zkb?_Ik^y+-?8%`SF7EZahO-gn#`Ayys&aEj>_M^Cy@!kH zoQ)xjj%iJ)sk3U~X`aKCVoJSs{D5+e`4t`T3QC_m9n&Z+OEGvq$tGJJ6FQff&lrX@f!B+B_f|ge z9}MTC%pwqnQWfg2#bOMOrh)k>8ek@)_&pW~i~5=?%9y zd+}vxp^zLU*^G1CqhDREketC#-XC#D$u91uEk@M4qDrxZT0Z2O=!x=P|&fyQzOJ*xe31e6Fq5nBQ5EhIY^1y|Gi#m=a`N^&*1P`XS`r4EDxlKq zU8AKbFIF==N5xdXi!l;T^02Z;(YRg+{UV`ijt^{qI3;by3)5G`_|K(%t|3-*cdg9D zRH44#lH*bFEJ@#v1CDh!X0f0g6+e(O6HkCc=X!nh^6-Jj zh%j4$+4v`KT8|@vPg+0TcDrz|Qso=R%9gsldx53|ID?J*PstbPyH9D_vt|L^`}Q;)?ArO=N&TAdAM6CnawY z>OM%=f`fam9863yfGNRBwAF;onMW%u;0~BA0ku- zca|jVQTL_f9S@U(JiEBtzCs^j2xI`HKFRiMqDi?$qaW1FD^_?<2)5mww?8D>_z_Pn z?3l$g27II$iX0(J(`3jmS9=Axm@57VA9H6P;WI)qSb81}idwDP_<t!7vg;DpMRdODrsZ2WDA%z-rWI)wtSx=Hch<{v{2BLOE~DQ_24z3; zgX?+XF93^I;K{3;%52To5!x=3_f{wnB037swL7H`Cma;PpxaQ0X{$*CRGVYz7Q}p} zS*TU$+sa^P;OB&j#VwHEkLFBFNMHrJ9fXb{tHP-d69LWLy;0^ZhmB#gYg#trtd^V_tS*CdZyJ%@?>Oy(YSZ3&j z)k|ED3IHIntTa{Ek8ZO^=gKWr--^0H6D9*ev`vWsNmX40=7u@pbFrq&lDn9llcQx_oGdAV`Jk_ zcZ@DJNUp0_aA;Sl7c^MI;qd#9YvRt+caA^;w}ma3-K7ij@y(YC+?dcGj^B)gRx+aI z0qvW&Eso&bqvkK*=v{=K7cbaNd#I-dE)C~vlXHF-=+aS+ZQs5T@CtkF&6_vt`Jj?Y6qK-3y}K{B#V{ah z)n$X?_%(w?IA$l3af;~a8#It#{~j4hxJLZlN=GLt%0)f!Wod{yE~BkhlfDpUpslSK zjqA&6Nar)N>{>IiBeSyxZ3w9)lj-YRw%2lqcVZ+S${2Cm{t$OaREO(TkhkGWS0t7) z`o`O?2v^rA^(2YRF(SdSxwu2nh2)PUp1)jp&4#Bf^@IbI-Awasr(WCnR^_x7@{ySB zo9_~qv7aE)uzqVe^_B;R$OV=-o8i{0X^-|Rwo^n*d=0Av{a7^xC}`aaG_C z-!wL{oVzLaMjd0P8yqz2`stS3IoP;r94Tq7_9WIz-BG1wFxy-tt5}&vd!`k^=Ubq< zj4QKgUki${#(s6N<@5MvAa5iAvE@|F=$C6K2i&`eSTjLPeY?;AC_nEd1INg3i^yaI z_hKOVlHOI}=it0V9YY7JvE_X83nF4maxGKjU8{}F@*2B2jeb1U>_Q{l6ycyd<4lApW@A#j7e5)N@_&`)E^ZBM;{ z#Y%E-6EfyLmFAIDw;6nbNx!3fZNpNQ) zgd7&tZHn_geiUKzv`pSXPdh1x58 z{T||su4av5Qsh4aJym_@NNfF|XY3E{k0xCpPx2y~CucBH!;?KgwF70Uzpg8^9$5Bx zy?Lw^X-MHKgbF(p{!N`>E8a9oLy?R!5j{-TedVM36j!t9T1EAT1KR91P$x>cwY-G1 zYRR0IPI*h}gHp)XPfScQQL{=lQWD&W*47#Ie111_B_{*PLu9hnkxg!{8_d0CtU z6fVA0Cs|cZw}69ZcYOMCIK!!x%rtHTaMM_ZBh!~?p+Bu14hZQ0EKufNI z7C$DMC}@|a!AM?N15U zBiscU`SNx^Zm}vtTeA^-?N>^Cq#nI9|JPK;ynHVbO23!sS4wb>)}jsA?MkN7C2t9y zz{v?zHH0;ueayg;ItG#Zt-c4EMu4D3p!!(&5>pvY&@BY?oSd2*S+I$y&AOAt#M1nB z6mE4F=Vxc%wFjZR3{Vp-X$Pc(JeLW8nd(^dOV*_)z9E;7K_ejr5>@X1{krJ zLY*Va4I(3<3V1pR8*R2Ue~8MH+kNOV(yEmQ{pSmuK4#}CSnGB2V`t15t}CZ41jO{N zn{OYhQj3>Qk|lh0z|MdBAnl@>)OG!zhuR ze3d0X$OUt?8}RxTp6jY!^1J($-MwbN>k5cg{LFdkOu8U1vv}LPM?2Ty=?;b>ynnc7 zd5=jxPH&b1l!Ek0B+a4V3O0OI&S9bQ@z5(sr^X(JkIsr1H9MKnwoMmU({T0i;_1k4 z0ohE)e)Dz(hl#b<^WjTBaZD+I`rHos7xL3l`w)RLEREAlRbQLlD*N`v<_*Y9#@pQA zm#L_)O&{Mxlm|Ib)uHSp7WnRAj@6b;zH$87^Pv)J#glYAYKPKjFDS2@u~Z_o%xcxW z_XU|T0@{W#{9L5#VmC~#RuCln5~)E#+ld`Ymovz_*ddTqTY4_V6!gAMmw5ca#K?my zcf(5gEwRU@@(=SGAvmfOmP)C3lVM9Kq1o_6f$NfoIsDfjFiIi}IlDr`DmS5-0R0nG za%&>Xok)gw7{Wb1*(pin5I$@BZ~-vLVeDeNiE#i^3^?4wF{o-b+!&AIlC_ybsOt|y zHp{rtsPKutuZ?ejgyQCN>a$^LEk5Q6N?m;93N+#%bdN;;sENjFC17eRWoPv9OsyPt@DH|s!$e>L`^s0p z2~4k_#Jusg`EhHS+8W~vdL7HfY}LgCGTw*eRhKWdjCINr)8Z{HE&N%1WskM-ZnLM$ z2ZC_C@R##?LEdpWAWP4Dk-2#m^Wq9zJznUKBW^8zIE`?6{I(c{=-hja3x0Sd3>8y(a=zw$D&VK0Xa)x93%T9sW! zlsq~D=h|Sd5JqwS@Ml%DVh<3ZBp7q6=-`QADqCqLWp@cRe**mwcWtq@@awyT;NXtDq6Y^%ii zl2gI6`m@QcuCcGCiB2&ZYnqVg$8r3N_w&pH`7h-w*Rc+(tR1Q_n}zMUqSh3~lZa}+ z_4K%?pDzm3zYU;rZ`YuGKz^sMZ=nGN&+&X+(F)y3!2q| z;Ac87_cqRJLGbRkKo=>rs8x>dnD0m_h#U--z{>%~M80Ri6@COd3<$ePihe=GmR~Y9 zwedn75`M)(kWb!Id19z-p7@y&?ENH%>%(m|puWcls9D;d7aFcTw6@M~qh8}Z+?v)M z^!0DkWe;r!xeiv4{tny;aGM8_MaMdL=hP=l^OLV^ivCrGYk1%9ut$qcR?Tz=R@ao_ zRy7Zq2Rc}l*H4QkNewo>Sc=ULEq30}d{SB}5>nmrKI-sdCTv+@y4Ge+FNi7eGjkTX zd1JHtnf1nr^BVa>k&C8D@68K!r{-3>X_Wf4J30;%7WEbb;fN*aD-FB}0^qWlvw_t} zVNfdZUG%^PK6<46sT63z^B119@%I74GI4y^DiCz>pxMpmxS6`kr5n_J`bvd23sfo; z;rr{GsjfM0OXxXYf~vO|P)j>x!IXKbZ8`9*ql0@oSiOvJZPI0>zXd(sO4%pVm7^5} z;cCc6f$b3F6ZP~WF>ok0(z+h&Oc8{$-Zhh6Yt~n;XUijUncBXWv!GP1b^mP+v7_Qu zj^-rEzOl>N@VDo}17n$oLM7wsp65UBPo*t-`*FG?u7g=(iuqU>KlQTV2v#GaY%<}a zW}%7~@SCk{C#-TWO2@By2QpV&mK z5oJtzV?T98KowQ$Qc0`c(!<`RYds(G=z_{t*vj|%omHz@xw*!mo|g(yr%BC)TbX84vVK{ z)V+C$MDV14~ULo>N3S~le3#%Ew>;I$-1DGSGi(T-grl= zMSI-STnj#odi9Y{V!y`PgrLwp55YFZm1-=FdO= z1Q!ZojO@?&rpjTu8j&YzPCg!IA7_?gH;@{;5kPcIlCS#dltBL1d`Rl@pui_6U&xZM zk&p|ayI|w1Zh!_~5|>RMe(E{b8}$?O{fUxjl7o9n*a|E18uQF`WB6CZKm+?hsCQO! zvI(%xZ*A|N(f&;5|MYbiX%WR34xgpvTuR-ssY1~xES?(V@nK@=nIZY~ZGx=m#|paJ zk8ZaiY&;ZX`MTrr2fq@!2)?cOb!R_AKdTTh9N%1;M@6kfhieFbE+!DZg1uV^F61a| zV_?zn8|&Mj5iKG{7ym?%(m>Y%K~^p%)pmRvLN1_y=%aN4n!KQ8JF;~Y&V@lbK?}4v zTe4_+&Y{Kh#(8pzm2-yx#mUk{oAOxvIs`D(hZ@WJ8X&efruk22v@zIal9Tzl__j0THJFAKwaVrup}Df%N18YLTYfi8}Q6uMpGqzdbOaNY|mr zKG+)9{`c4Z{xI0E!b{}vVebG9(f?O(YajxXxLqEB_WPs$w+jTXe6fMby!~RsC2j!` zFaJM&{NG#q$58#>S^MYWf&KquLDE#0l141RpCbb{Raka08;=w8{Q5B8WeG zm5>1@Vki~$;{*xBd1m4^6vdDKWk&Ko0K3yz+4xpg8noY8%i!s{?9Slg{%v&85w_mg z<~kY`J3RTBqHhCmag0{_KNbNBD+2*!FD*Jcx*Z6K%C~~{UreC5zPm=A@ohR_8FheP zd<0N)Kal#M?{2SQP7tt(0cD4Bz)42b&+qZX8HFwOBy--ocaO()TMx_JwBZdgD{9XJ zAXlCNq^=&uK#S9?CMuqQvMvTtgBt z<_2SHeSgow2uPCkms&gnS1CsWN1S@_81^V%U*r`)&8LCCluw^TY74*V2fH%Bf045> z@Zqt=$DXw)5fzfl(?>ma4piWn`A{;a8@w@a?D?J*q-qyw6OV<#0c|o!!3``fZfDJd zDpcR8q>_aP_3c2CrAr^EU7<{tzm!aw#=i(y7LdNukDxpq0M6t`zzOmdU7@Ld$NH=j zh!dcXtfJPultSsih`w;+} z2GG9Vc>@duMFV}1j_>Z1aNoP4D6Y@}*SekOhGK!ZThD4tcf4CX_ycjNo0s{T+O`3k z*iRjGF&?$+EMjBeJ8`PXH=fbsDuEh?@ny?o_pSSKR3H@^xnHi6urZLwrs*EOF%VOS z;xuA<#>cxUr3JsweAArhBJr>;t%nFj%{H#EH_}QfDhU0ucx#J*?t!egw>OHi#pu9} zRoD?tU5_8fn-@1O0?YVIUSCpc#SCwYn81CV`I4e&j`qfiNQ;d{&F$?b+kSp z)Wg$$FhyeW=8vQM=i$#2BCg=YJM{KVKMtI}_z!31_cr`_X6MCTL!-(&nkq8-$A8fG zW}!BDy>{)-(cqtU==vEm{nI4WtjYSvlKVQNpfTW$qkfZ!|Df=GWtg#uzALE~2@XPH$m=u4+u`5|2|Nfr?p-BW& zif%|Rt0}oh9BzzAFaNg>SO_Dyi3ihECSm{l1Rg(eW{6DD?ygAuXYKON|F2`=j_F^_ zkfWum=*GOg{o@DHKW`V|IsSa`u>d#c{Y_3Hrhi;1Y*>mW$Bg@cn&>&=eMKiU^OUI(Dkob{4YN| zegIrIMk%=ezcP@2eM5>9!OIG|37fb~r6KsDN0{4xdF$`1?&U+QjobP1@BTTnnhda9 zXaQRIm{X3Xv5*Gye^?txgzbEQabh$^sqg*IyQT5NGICm5>!3uVqN4Z-u>WJye*F{1 zh}a`hsm4veuj|((_f}#0?_Sq@22;QNAHNkme8*Z=+!aV0D^tuo2F<8vP#As`-+}D@%#r6x1&is&*t1E4Id%ZU62C2Q+|U1 zUm;JFZ{Hr8{Lk6^JvDl)NQd24#*HF>yYCkcsG^t4yz$TzQK9`plm(zR6SFy4-9dVH z|M*C*po1t}jJ15iJ+CZl3-aIoENN&D_(wbQ%lAqNF=>J?8^&xA?3gSubPzyjf9qYOi1u`M~is$F$4r>cDpe#R1 z)XM|z%#BJTh%}P)8r)FfKj?T1u-9GYe~p!+}Oc=W`@Dz}@8Mf%>nscHv_ct+rLC0-Z0WW4e|Vd>}` ztJ0kJ!-H~+Tk@)KR2>&2?Ex$yH^j{rLujMKVc}iuv=Tw5MACLVuTM09;Gevya^5-K zOEJSTD&3l|6wjy`{JSZHl}V&rgeSufTg2j;NG=K=nLogdvMm?2O5bK<_`Qfq@L_qi z+3e9sIx&Br!4zZ63FkHX%FQac$SkglLO0|}ULzO&Q5-WeB!OqaLTEKh%J2d3y9za& zjk`a%DSRmE=W#n2DxdEvR&Y9>fT+_hg77&S09ex-?1dync5{qxAW)U}OEftEoqA=i z#`X`ZnPP?Co_rRHGtD)9?v#A>ZZKbCivN1|)8FPw9GftuAsuaIum5lRw)ZJ2kPp2J zT-<{gIlCncHGWXGs^_-$?W&^IaMO?_CP}2a4M#>iJV_+Obwik`d%_JHz#fzzr2-Da zboW8-cN_uDiA?S7L)9-*{>P44X7IjZXf(5>_SAJ*W{de+)Au} z$M1gl?(X%aILKoen&^aS#~@zgzkSo+ObaXywaD-_7mXnnXn-UG>8_6gU`COIo4=W5 zTr+4QoZrCboGe-^&vb=^vCf*R)Gn|AYS=m)dg_=RmN+6p6Zjv7Z%%e;uF6n5RNTB- zm_9;!TjaNOr$NDDQ?F3Rg>EllISf}iq?TArEAU(0eH%sz`5Nl;L*fiR%~`Jl*by{< zA$9mQFE8&M#JXOtY+Ao$esNI{REIf76jNI)?e)}0YrC9$W^!!}p`L$MfBLHCaBO_H zsa_`r_+TA9J+YDfPe-k*-`Wpr_(TFVPxtN_i8%tyBQn~1@G_24Wf2?D0-9{nl~nK1 z@2STZN5<#td4G@f^9LXxqj_d*%0w)nOh>Gu`Y4~(0pZnm+A_r|7CMu%Ytp}a_bxIj zDt(%5GZHO_qJ3kwC0O;EuJtKG5`eS@xx&82^ThswYSM^J2?&)A6BE{GLythYT@)xE zfCGrp_t~{)VZp({#^2uGdkTVvkEfJWMgbmQ04S@C?wsz1fm+E{K@IYxLpxQ-5@PZZ zlv8cY*i&tVT;xU=*j3DOf)u#tTiBZ@o&DuD=N+07b-EJm5a4W8$mK&h`tSAj2=7Uf zL5=kMP^rSj4nu0LE@kXn$$X*_vc)wjG{+TNQ!?`>OIPesOw+3?t}-N3o^#sqf;-ki z7a_{?6}r^MsCQV^aw9=amv$KBkUsu6oE&W}d*C+`1}I~qNNiCc?pey<(ahK>Jby$B zYbzVajq;gt2mnTksL1``wiP*Ur00f;`WJ(bY^tf-JM}^jfOu{0()%FMe!ES>a8Y)b zt3BKvH?gh{?4zgp6Uwokm2+WOz~JW7kx||Pim&fKIL@xvH-|n0^u2NS?m3BOEZ}(F zQ1oZ{!{=aSPWUv)yl=lNf>}^HeeF>%v`yA-tv>688?4>B3;yz*emFtCzlU1O zhVPmJp5TWpEoN+OI3ea?fj+#*VmN0G?GOxPl$K4UGQwVK6xu!+8@ZaF>shE=(uo90 zKMh^2C0G~pOw9|<8x-}sZ?JfF!m8)fg0IZ|wn z4bgsW#VcLpw5X+^P&U6}8T{tWx7}P#U#T;@hL_%bnWt3E?i0t@R~*l@y@Cix$7PSX zUK3ZPhl#4-ik&|j9=E)63t^Cr+an~#@@plid}eicQF@42T9Nv-OU+e7lnMk)BJ$L~ zG_8?E&~=p*;ZicP#HJTX+DE_hxWwttwHm2`a(Up5ygF!aw#1rUJV+D(tc2lfO)mGz> z^Rwws$cGiynh_BM$}B6rcj_1(cqn|b z-qCvFtN>Vn`{ewU53k2-l1yNiKs*js8G!l+e9)5d9cMI(8m$s;G*dh70k##@Am?B) z4Fr00Ec!sZd5_vCfS+P4)fEHv;)rls=vYbw+g(E`b6e}-ND;zK)wq19eF2W%h_g)( z75Af+&&Bu!{kX-26OIF4GrB{={9|Vx3tUKnve)b370r}*O<{DnSBW2d8Z{J_Ccr7p z398%zWhQ1sO~XanItCQ$Qy4K#;mdt=lM)ku#uM%0$m%+HX~9Mmq7!;SbZ^hj7DnO^ z>2j@(*{6?2O_k>d#geR~n}ejOsD1Y1C(>pYu{oexz|-^S`Pip%(vfM?@>~u7t;>WR zge*_4v?f(;IZ^|?Rp;8GPm~?k-sNbBr;g;@zG)tFJ_yU|A-`8%&YK|(L)=AxDkXtacqyVj$Y7GK|Dn83zV@pY$G z3Rilaf(_;R0Xw_)L_(>BpBV)mLX(EQ%I4gqci*cCr#WQ`qek%w`gN%99^BWIakSC# z{E~@WKpD%j-D0UjQz1k1Ix-t$gWf%gsc8w~`@4r*9R>zVK_Cx#6cIo(ZKfMJXboMdCjQ!0)EXqF?13V}U5E=sc?G z^l&^p(lp7deT6<5;^O^u>Eu2TyZxMvOU{=5;OZ;q_v6$)mtl>}&ej_V89>}~PQam+ zjZExvJ#L9cZ@zuz?sgnNQJz2g6YcM!dFf0QqfG|X@S1QM$7Dv>H=5Mn)}L9w1_~_d zR9@@J+!!Qnq2u?vPvOb)$u45dL@KuHOMr*=(?86mHic`uOy^s;ujYzV2XyaATTfU+ z;8%60j0`ZDt*Ofq2VHDl4v5q0&F>nIZZQ{uR`e`AW!ZfiOd_YjxtcGc-gc*&uk>~m zmqoZZ>NstTsm89ZtjsgWLYA{$yQw*bWq4BaWTg~(!eDL_7>-S7eRr;Iy#Uq4GJ2-3 z)2Q@mG7Ag23J&-QH%G77FIqLnt_x47X)B3*;JWwr5$B zEWSd--MvmNwZph{CV*>#?p)Z;9@hBMS=dkKqwro=ZQy;6#LpVNUC4NGi7jlm;sg{k zadtLs9A4?G37NDTeo|M0UsH=)35U5w-|2H0eQv2-8|GD@#|6paUD$yda#e$49hRq< zC6fi765fn7PaF4cz%Y`wXoM{&v9{Eqq!Nzm3O8uOX|7ECJhEfTd|eCTmaY*6l4#5L zR%R%_+`3l$S7xRc9kEVZtxqR}_7LT`JRdJ-gA3-(wB3ytI#oaIW%yjx**9<=Mghg8 zbgFlxI-X5&xY?wIEhv;Zyr!4T&#Zmya+&x4WZQth^4B^^mB719KURA z>tnqlUodw|*DC+I)=cWWId8EFxRlfUP2m;=)z8ZYKB~@EVoI8z6#E|&-Q2f3igQs0Y2@1 zs~7}6S6VTlNBlvT+@nVe=h&CD0C(m76#8W!F2;DNJmq#KQn{NgHwd)~i}E?Dn_C%+ zcU-F7El%FJ{e4t3Kg~Aw_whM~3e$Eu`z#-4Tdg-MGo3kx)^JU`&;iP#wx8w@|9lIo{J{hA61S>V)Ihp4! zKxc=gc>)w>3HCOCh8quMtD0C@r=ezE)F$wKCiX)^g z4Z*?BG{R6gGe#K~0kuj159$z(TXxsZI`w`IN=W|Q z6=`d~VZ7!f{_ znwr`pJ3BkQtyf-ci}RMHN$)zG+Bj_x417`j(K66E?d(35KXp=28SQq%4WPCm*2&;g zt+`phMIbcubxx$GH(abMCa0k4$!4#!VF2!w$LWcwZYQ2t*DfYh*oA{{qkXTZS|z_` z*9JM5%KDj_rit`dU{@pH9QD0efa*FjPg+00X=aC^z;<_))~DW}<~iTx^~(JsY@=B1 zR^b(W)3L!V(74p*Z7`?kv-^o?NnBKXxG>uuq$Gdyk%Ghj8MNF%n5kp=Cc0vuWyB zXEh95in#3wKo4dP@9wYnx$?K;C+S9-l(uh0I&dIi`HJ{`r3@I@(j(eFmGViR$sg=@ zbu%o=X;(hSOaV@g)!se3PMYXqQ04Vb3$&w*W?Qgp$gqs`M-b^Q`WPh65 zzkt?XKhO{W0FscvylK0sNny9Un)BWa@ha0K$Z3%gmM*$osM9v{;SS48KZC4H;`+U~ zI&KqN0P@H&2{x6Q4??~VQ-0_dMZXzE`PFwB)eSGrL5r#3hqe+N7Jqq5d;>&>dhnO$ zq$DJ_VKPcvC`m}sNC(%A8ys#*2f*|K>6DT|`G>DMDooZG)X_fpK`?mg@9qztHwSrA zb{lTrL zmI!x770G%o(ELlT+&&Ncl9cnTdeosi$bZYd!OVEBl^0z zU4BEOFHtoGV6qBHHb`^{@cZW341@XUHiCa3FfUR2nIhg@eunY}qT-$oA%Pt3zQ0CW z)xsvOoBF2U#s1zrDL{7SI8RwyD6z13{*EA*7$DDBcC2QQK%eJ3Pu?9NaQV}t(}cjX zo2Zg#huPxp++!tqv=F-`d(cE30y@S84!Y0o{JH9Aya42$(ZiA6lM67O0BZNNq|z{v z!|#vlKJ1oy7OZ8r*#nSOx8u60TZ}H^ATL_d5sRAhad6BXSpIX!z}WS^#zcVhEbRXP z>0$gbG-+P_3pQeRj0;5Q8NwAJZU`iEs80KEl(yVNF0brtK#uw=EklM#%ivhS87YFK zjrub@j2Euk%n1R-5uhq?yK?b;!oprpU2bg0h>nNW=6RcleG4(^L*|=2Glf$-t2s8E zHq4t@ZNXH(ClhgHBv}3iadXzeZ0aU|fNn5hWc9iN^TlD&rLjPl1m(|_3Vt4=f+;zNmG?f^nuPnw z{2sdAPAnCdm3NLbh2SnR=4vuA9)=`hY>JZpn)v=+U|ykIg0WXvt@3 z_rqll!`5{g8A`9L`GtiRXgHD+D*r-BRG6yqfvwTOZRX1HP5Ol`(GCBhTyMk0UneUw0@AdG@K=#I9`P=W&Pt+D*NDS4iBpFiuzT217Fh$YJ=icXbWzgN_Nrc;f z_tmRJRJaTtwWz#x)rmP7k7I;<%^XL)a@3*6=?baQl6I@CfaP#$JOIH#Z4c* zA`0j468$oH0eV7fbs(Fgd%4RbwDds?j)2NaOH1pP29)X3ki*qEa6&tk|lPnJ-vMx^r@JQkR*OqYo4jQf<_Ek^t=` zmPPkm5m?Z`xV~i9Sq-7ZxaQE5X3qXgjCDG+jq66>VDoO=AD7fqRtTtI+jWL0A=3Y| z()=WHE7&?niW%m`(vSG#>c>i1p*w%ew-&y8S$|QIH#70)B+T^ZY2Lc_uL7ZimGbIV}ZxfYx!r@{*rg8jQ*d$n58_#!m((Pow%;nOwtA-P3Cc;%qACKIJX z&0r9m@=pVs2OzocoxUEw7aG1NG8grSJAU~?*e0?a%_9$u9NgsdRe9_1&r8J?IU^y5 zOWbqZ2n)K0>2JTw!>Qaw@b3*I-b$oiWE8)@K1ydTN_Q8R6BuF+ZQ-`iB~n3+SZ$%x z<>m~TaBJ_zu<0hW;BQ52VF5key9=x!X2;#fN_}=0Rq~ZKgHNokY>?a!*dCqvklkKp zf$&4s>Xv?P^dY^|!-*71Oqp*y7h2EpCAP+=icWNKU(zlhG}!8Me&h3#jW%n}O>pX=z7(&Ba(Q6&ZPyK{{a&%`zt4i+NL0XXVg-g= zYl5xogOD6h>;5!$Fj!TPDSz?^hzPURpBo$OfU+);J2SR|CZc!m-ZkoLYAMQF^y^L* zrw{ufVA`&R&5n=0v|boc0+|nw9QqRMWALO-wJO)NqnIe&)9tS>1N%Bc6Fa`Qd*eU82LEKV7D@5txv}v(jsp8&3Ws%qFKNf8HWP(U^lIm3 zgL@8cgdcW&`xbP#OEK-dW^{6L>CvXW*y12bE)p1c#Uq&Nd#FR3%GNQtaLw#$9Gk&o zo7qM^Bt6?kG$OLiIzsloS;(#Z-vKAAOoql;u4?0pUeK?D!vH^Ua9CD4583GcxBgH9 zk$YP>nhLa~A-w!pMpQ_2>sg;kMxWmyG-XuP6dExt1)Qdirvp`KBQHPV*Skn&RXw^} z@A+)Pf|bdmR@N;@#dA0NCdGDwk)l3e*uqE{@i+T=qWo50@rtzlK~aFIU`DSLvH6^h ztJ;4hz<}phhdo|Usq}8LvR?#QAdnOL^izhni8T_bX3+t4j0C26ysj4c2kkC$x zPrS|)sDxII+1<5gVPkH?O!dexRi$Q-56)-(i4buEgvoW|RSXm^($cc$ekagt!Zb*Lvs&;H4`UqZYss?s#*x-tLBgs6K+n8cx;l`1vCiDbfAwy z7pyua&1^bWdo|1ja=Fz6Xvv4=sy{l=Lj<($e)3rs5qp)My(O03K!>Ii@(7vzG0k9K zwKVpwA6ZQ5c@|j$d*YMdVFt|{R#zggE=T>ju+VnO#RAY5lxL~utUrH!(`kjaI&@s< z<6atF^Y!+7BNMsW)cTc&WAOf>sV@dCZN)MzHnOmh7jmmZE2?-|D_tGP%>Q#}RSw%`L8u&j+KsKy9`I#uG z5k}075h_yggzqAKUy9R4>#V<>JS>uu?-}d0xAuwmdvC@_@c3G?!cp0z_-5qeV^UO= zYb2W{Pw8v;zEYOnwZCqi zK|$TE8(&EZ^I<2-Lk{%=bEU%VV+zuH?B*I$d^*em^_z2Ab7ZXK6$Q)cy&6yB$UwUH zj{1r%1M9UsAq?BUgajL?H@TkPs~Ac>LvtDrAOo_^10Ii1CL1;uILv74|a_r z`6RE!`;}KPh@s3Q+W7&+%=R1RX!HI=;ffl1vkG-K)69)E5TzsTTf!jw#lprGE$T(+ z6aFAE=}ADG_6BHj<*1l#nR?+v=XMv@x*!T8BT?b5@7lmK^Xt3x;4f$lRG2O9?nae! z?3gxQOrS#Di|YYMPXcLy1O%lkHdUeYH6#U)6VCv^$75K|X#ZCT@@yEDh`TH)u|3+T zzAdQ_=yMZoJz0fT$sC4xeL>vKcb!W;6zO<)Tc_0_+=VykYfl_A05r zbRo#J6#dX>#noP}nuTlO^x0cgQ43eQU#igX3= zTZnthRIY<=B*DR!1O5My_10lkuFv4DIF5h2uPQ7cS}l0 zhje$x@8KNve7^7d57z~IUp#x?F|%gP%$h_dEi6owiiiN5cUL&cm*hp#JQ6lwSVw1K z?tu=6(HkB!HBj%IltBeQ-(q`24I+k(0NP9S`Y)prr3iu*>yo+6Hj8>>b5t_4$Bff- zlWU^b>GE3LOveEmh>j7}Gv$fL`?iy(qLlE%Iur>s=bZjAxnI7AN=8r#n=+fD`iiiX zCZ*I24WFr1X+mSUEhUbqj*Iz;P}k5#t`M)ky1%LKPw8z4mY*PGV7bc#p`yMf1bRqb z!EL-vGHf>8+8V({016WNYe%&i11Ob(xqGtaL*Yox9=C zkgU$z5GT%;-_u;VkpdU(`*fJCcbys@qTs&`vk5PDygeZELMovA#dsYIu}91eCL1&7 zzR+Iswa%sb{LPszE(HUTV!<-&Y?$_o3=B$a(PKc~d4uF_X_K>LR7v?#>;iIeZr2ge zk=Mh41m4)%k_Ix;!?n5{pmje#5iqHMhJR}{gb2Hvjbh@LFSnRbkWN|=p)ZceLP`A} z?*q7LX#w&K$eIhfPO`v-`s-qX58C6z+ztbDF+&e4(BTHr&%X&c!446)F~GLax?O5@ zF|$yK#{d;}f~}t4xt}k6uCM?%KXE~O7L&<<`tZF{5!Uy~&vl3qJL5&17MBhiLa)_Y zuEjg_ZJ`2Mxc2y)ju;6PMrJnfZY8JgcQ%_Ru#OVbAiDA_R#9>JRKDHWlC3TUOyLUP z55ajH*v*Q?^02Pv2h4qO|1x9+s=zkrM#iB!hO@4eSw#~e=sSG@Ut+@X9vQ<9irk$<68WrnkveV6;EtZe(jn{=oxD<`Aa@Stln(A_f^#-)VG8dQ9Md zqN)rT#=?;MxjMGwpMlC-!=j(nDxq?1!} zKAAJeZBh(le$ zQ*jf{o@cS-RH(r`^Z6ngVl7Nw*BLvZ?IO9#)|GmSS-iSfgIWB?XTxR#$#(krn7kp~ zb(^{-qpNu_pt6;bXnz%A9v2bnMtLcIVdG5H1N9TaN3&-8INoha3k-5~($pcR+0f4x zb6%e`G(m~H#Psd2Ua2m7lQtM$g^viW88U{ZWWT=3C5Hx8P83w}WwE5>a8tcckFj`s zpI6nhOuuXp$Wr);Tdt8RzS1eSe@-;*-GX2*C^++lu!aEsr#$IE4mF+g6g0z03&KuO zXO`^mH`Ifn?Ob95Tm$x{9bwJ5G&mLzplK7@Xn>tjZLaIo zfK;){-2)~7MC@`dOHKLX01&sI*4ck6$6>Bd>^RT?I5A^7_=mP66&f>gBWluQvw3?L z840;P6w*gbfksZ`W3Qm}nH>RLZ%G{wpl^T~kfP09GtneZwyHtdl*3bsifLsJr?%{| zK6jt}ZfopSzhgRW5KLimroU;XFjLVJu?loH;GOj*GhwQ*13hpoEVxxK4IH>aZF<5m zdLuYZnw)oYLF+HL)(J*ICV{Y1M)bRA&rJ+V1A@*#Jti}Y=1GL%@G&u0v(`+xp6#xZ zg6Xyavd20>6(3VPZvl$5`*Zn3!EE&BqZ@#tehz-#Heze|TgrUPoxOYPSt^q|yG! zJxY(4uL-3IS;O~kv+w0{i2g)SfMSdbKnqr1a(_Ps!sTjr5O#8zPPw$u_P*vg#L?*! z4_PX|PtHKYWD$1m+QXJtIiw|YZ>f?cT;prY3Le+Kmh=s+3Uuhew{}teWQmL*{}&iR zU_=zKCX}@9Ps4bLG@nogi$!w9dj;79TWYa)S?Odoo{AHk|GQX)bl^p@|Q@)H`C@=45+b)q+qXVWpXXm_VsCQ9q)=2i&3nOCmm8 zM4?pW@liswVY2$jh|8JOf)kRIlt4D_OVT3=1}}`{RLZPU&U@5QW|Y>pS z_S9E)X&Q~)oCv*g5_CsK7u%-Hc(WC1rJLwfdKmInFCPODxC(mG1x+}yMG(wkH80y& zot@P)Ar|r_G(H+(TyzVK_wwf+#R4VHkr-Je^t`#XPB|~l64bifm zKApT6tFUL*xfu6|OKx!Czp{M4@0373cXOF+^B>UyB~pEum8o55{6NT5elHzr(+>tv zsAxJ+1FCWlS-LJvW)XSx4#Cl?L&Rqkt|7d`r%W2un4#^r{wPvp_(V@pz5>ejv|LsO zkb9UfG0ZsBNYTW(VPoFV!jU^sg9dt;S-^N~gE&kgpV|%2D9a_5Mo}WeG+eRADa444 z;Mfz}g^#!=0s_F$({F`t7_ExvrS6rsKCkcx;%ar1>Z1ebT@>9Jgp_8Uc%s+=oj4Ur zTowk4hEfR=D2kSxOrbyw8n=UU7TQIP6%fHu8@|&O#Sc&CLRf`4#Ve$WpJSDNZB$0j zq1PkCdM!=u0wX>+9ADDxLR|vh8ZfFKMRUZr$oEGA<0{6=*4}=;EoRZK#Fue-TK&4D z{^9-`5aQvH4cZ+xWkj03IC%&ZXT7z7Gf%1HTHOug<&0wNo@59Wsji|cxth#1Hx;$u zLNiePa34mmSJkc@WrT9t`#}BK4CvqmhMeym0!0jL26M@hKu40^EHEPeb?=nlLQXZ})}p)0uCnuLtXMf-FN&@i`bn>pCXMz()eS zLS6_(T`ZAXc%!VB0o%twQxE3ROjg-zlwty4NH~k-7%BnRyU@Dqsm+_c^86h~!bB!R z7m0?5QQo^a{Nr#hJlbR5i>MhrPp!v?BTD5FNcjSJeN}ID90kppEtQI=lMAwU?Xb(0 z20EwE4@if$8>g-rahH7$H4tylRQ>?0XW3al{mW*kcvi=MI?`n21z^X3{_YsNt5zk} zJ-pfb4Q?gYv!UEFyhB!j&X!4p&WN|YLLk00;YJx4n8addPArx^J>{_Nb{4*ZRiZ(L z7`tc)6W=x|QS#$rjZNIukB!VQhj_w9-)_R|RLGALB?*Ymy-`@iPJ0QA{J&4&Qp@xc zG=#4oxYy&X2OoEU{l+vXoZtH^z4g3+(1|i^bmG{F_}QISC0gybVaw>2!QwD;I~znLL>DCx^NTR1?xi$glj0naXDyD5{4{Pz zr6vdwC#AOVwbvfkJCZj{@3B608DHXdCfXf!I44ay#`t_9FfN_gkkWt1ws>@MEU#jv z16%t#BmJ8ECJcqiQ9Y7;n|)^|cASlAq~si_D6Z6EBD@xIhs-ifXQ9qe`nsxJGm6U) z2XdN$*hHgku0nVr?XfG@<3>owMr}HY9?+!D3cyhQjceq}SWB_GyIX8YvOdJ>&&opDeaBSMj__ZEJ!w`kDG!3cWV(2km zE4Jb%$uSFwt5=;eRatd;az98r_1<0G`%KT=^=IKltCuy$AC1Fju%!8%-PSy!9TI&8 zOK<`*6~=|oEHTl3&ID=Y_m7Tmy>@E@ksMs-`o5osRCFLA2>Vthm2rp9zGTcVBz*z4 z3f&g3#@X-F=PlcDK%>K!M)bsg4|C3R+_bvMk5?HI2~!LS-pqbbG#%_6z|uT=v-sZb zt%q-+cG6D4^)bc3l1qeybKc9gK#~s%!Bm-%dbgd6CJKBdJPu;_lXkwzc|btQVhBZ= zIM$34HlUQ)a9y)w5TB@q}1TWZcAI#J;0 zDpW)AoH|=-!E--_@^|k>Rh-U(tR4&6*7qywP)@JrU#-p6??QCr_nN2lW9`mB&12YpqOHNLJoy+xQIgI$i{@^|6Y6#hyDD}*LC%!KJxjV@ z!3i1C>wtzW3Y?jb<|Xf9qh7KVF!pfpNK>ngJ4>BEZb%;N8pl1vr(Zm7O!K0;(W}6z z@>&*UEg7K_?kq?z=<(q7f?y`>7hmThSE2^eXy|x;c1$x4vm&4>R3I7A{J8BLiDrQ~ zv_NnfhrbT7hIm&pvoU?ezsnTJ<}F0B{JPfd4Gn%+l9&^=h}wY&DGx&J{RfH5BVvO`g>1^+r?980;bj|2)@{Hlkmcz=m%AJg%ykD8+(l>bZ<7a(P z|7D%BaNyqwS{CCtj!HkL5d`okeId>zHcWI9v#TZxE?$Ik7pZnDJkE9559lj!`$P*< z*p`#YHlt8#uXXpWe8WjwIu*2m!sp_MgwU@-4?(##Y>1Q?fN_k%!Je+qK7GaVBJw)@ z>9OEtFfk}<*vbbEWpY)bQ-w`>p{PpIDsov zx5?yVgV=!>2Hv}gQ)X3A2ICc?gfu4HAHbMwPR)CQyTOJ-_)$XEFAO9 z-tdLXUd!>pgYcEq;wJeP=8;0KpKbUl$V9NwE{hm#+$eXHRy_kLh+%egS$)law=Iu ze#~%c9_I-u6pp(Xc}+w4VgPK`d()_35G$f$2LUT5b`0?{a5`0LAWl=Ki?hwsb^yW> z!%XCy1K`4{fS57cA4LloMad!)L4l+t0Y|&?g)58r6BDMYN`;XK9xn76!Q>AGFkM4| zqgD;$G}8hI>56Y{jfa0VXs>bVfIHlXdji!EB6sm+{th#@1>M(nntLXk&=XWlVdkEV zs3o1wtpx)U4MCOlE#gEbH7S*TApnn|$$+w5(s#Sf%a$$fgN3$5{|BQzn-yAY$K>-~ zqwF^h$^9>ilWXXuYrvT3Lji1;-xy_8px*qEGX&zdNFkugNvxw^l7LskG=E?*SsG+TlyoC9Hc*!l-$<>7^ZI-;DTJa$y+7VTAUY~4j43dm| zeDCw#o^OrrPo#*DS|p{AIjj`rh>I7NJ?$v^d($X9GrQl=RVgeag@WGNp>h7SG(yET znD~xUlln46;99@LlJ>JT6fG+a*6u5^9K_Tu zTB34!|16~ZqQE4I+eP^OYPT$WX_X`%;HwC{~`+}=R@`3#u#JuJbm0AL35d?%O z+>laFMN-6Np}AWe3~Y<#O1YKQS85zXaRs8Ng%dq+3tMmO>9n45=r=s!6eaHrN13W( zzMZ>YdD45ye;1IaRsFG=I}`z(WD@A}R3IEteUCFt12FlgamELJnZL)NiCBeI81o26#McD>T~`m-;=7#&syaCp=@ zRh*1JZ4+bcz3%6w?Nf0fz^+U}_$^27hL=p8h+z7{lq($_A!?4n-APf{eV_Lt0u<4U z`u9v-Uw>%SCEsfBK6zGskB~%khD?-ldW%z~64pd`ZH#;|7{-lO<_x{|C3KS#RE&Fb zP&A>*WVI+qO7c2&N+c{wa;*!1FWlA5ESu;aEEKJ zum3j#*-P%5=XB<5zB++*=nz+Wf7@n}cga}eUno5?@n5!80FM|5Iq>QSXh{Lfxkrko zWG{*x@TP(|E8u&@h{EIHkJh!QOYsbnhNk;Y#H?({<%)a1y{@oOno`=D!PQ!`7bFtM zYYl5|EMLT_L6Xx&exB{~lHxytRiQ04Ail12dBLPI<5hkfCJQ9i&zlw}W-QRW4v+*% zrvTwxz9_u(RGKXXD4d*H$v40m9Zqb2#iLY{uX2PI6=W}DzR1iv&2Od^N=^OkERrJ9 z-=*=xKyZx-oz}G}>b#(Xz6SJAn3+aZ-E2pl+X^}$Y13^y)fwghWLim8S-vJyDA_qs zvCG3=!)~9xYpK=D9rFxDNs)09Q&^8@BD=LijQy}S_D=!8+$)HCxxguA<>7Dca+SsB z?C(t1%l=Qn!n2v^fU3@<^t=YMNOmvED?c78Ppk$?891 z1(X{t`V-e!Tx6~FGQI(ou%R9H&a=DIWS)e?Pea}tc9!LifP*qKP7h0i}D zXI-Xwpx`HJ$Q8;|LfjQkA4sg#>EOH*zCdur_8zsn5|gBY9H|>&CG1;rhZi^rT%|%v zy)N*XFEk* z!I*N!hPZEJ^U9l##Ic$CtabUb1{?P%&(WpD#YX5<7%+>|;-Td6J~I^e={1H^cCdmu zJ%{*wkwqd@V*#n|=|-4sJ)y=X#{nr_d)KX@9>og@n-?%JAjuXxy2uRaiJwHH`F7Uq z^P&(43R#QLlXqWgOno?JXitvjYP>n^Mlc@T-TZ)lDMYd{Nwl^QMP zCv@?zqqUHKyp9p=WOMTODYY7P)Q`q2SX*j=es#ZkJ-|SMBln?)&5l-vd2+PTxm8qC zAnMn-9{!RIS>F#mCc8Cp>0!A<=_YU5S6T1zfP%O9`lc0akeg(7wXcrU}A*j*O&df|sUe9m1G$GGN z@9tUv3Q$6~hUhmxWs{u@h>@QMQ>BpyP8pXIb$^JhlRxDF;}yeQcE;K4n{I z)47e-^x&VI?jFdz9u4`ira{t{02!!fd-v�kwTJ> zmaQJkZRYOvd26<)q>n{+4@3X6VWf(_5QMRAD#(-hKyi2QN-~99Cxw9_ zZqqr0%#(AOlbZ`ADk@6Fz#y)np;6BiGD+BAUgvpb^Yg$(coC{L3Ed0=w(MFZ*XxY_ zy-{nd($bR~dh{)P3G|(!x;KZG2-#HU`*A>9nRq4`KRyr&<6J-Yi}5MdL|MQDWKgJ_ zgiufmk_l^bcwO!*!o5c^Ps75(KrI5Ss$!Vwuvhgt?^o%|tg6dOnQ zWPe?jEU;YXRRM9Yr&NGx=j3xD%}axft*;1MEobO`+OrgGzXL_NYk;JRrhZ`aGH#`W zzLd8&A3h2!IpdE4(Xx-g2g0qnv0{hjk|QQAR_SB)_x$?T9H4I_f#OIe`3{}x*}U?D zr-!dx8|ZBbs`_tO|1O|FE&^janNoC#;4Q}MoQzwP?0#hT1_Pt+S8nk`CBe*$7X0KK zqBdz#cad|jCrNzQw+4Y{1G&K$75CTV?h~ltD?ghW#!b{wv7>i?jRpw^^L!i$EX@h# zGp}|=#v0@#p9zi~r8M`^up-^JhYwZb4^^FI&V6TmR%(;LDr|gqJcs9_$KpA4 zIT^`ZjLWYoWT zl7H#LNhrpb8R3C~bJA>@N+vB3yvr=Q_q6O#yszrl6(Fh>J&X50*Eum7w4@_*J=78-kH{A=@qnY18OC0GCX()4|;PHqXN{8 zgO1U;h~NqT>)2nKs^&n_LL0z1Ix5SZx#-p%_pat1^|(%`I3pLIQ_{hm!~^ zl2cOVs57wUN+E{jzr)yco3h1lngpLTPAUlPnt!ULZ_WO;{_vA(Mnw6IgV)vG%xHxl z^vTIdXk_HnlHP{bbf_pZ&j1>DA}K8mpUg$jvMNoQ7BGZE&@yUxB^Cwsjm;O2Sllyb zL(cp#l>fMye+{9gx&W`fq1+C_d{$+F&Pk!qyed&^2`JjofXK1P2j{=H3XsFU^EQ1O z=h5H#e0v!ye4*S_7(8C9KDpx#&85p4#dC%<3A(-{p~eLJRY7gAl%>(AY(99;V4 zpQGA^AhB7;zsU!+;~n$qJ_Hml0FXBUmM{k@lxMc zJQrW`G5|2fG7#mkWs%El+w<85`J|6a>;`y@QbV8)UtbuJ)t0P}-w9S1&1$3mb*E#^ zzML(og9-^H#pD|O;Q#sFRAXwOOGU~q`#I6ZVd<>OctJw0*CT(PiN*;+Iu1=U9LNCv z@{)9=lqv{m9Kw}g*Tu%7TAfv=3KiC+;8T2@OI*-jzwK1*J75wbiu~ghSR3gWZhht5 zUk{QcK!YfurggVHfDDSHd1B2JBrLTW9#;H!3#iZtfv3Sm|7urze*Q6{8?TKU!r3Z4 z=Zl$IqWdA^&N)xCOW7x03+2X}q|~)n4?oiWU+wB3HhR{xv$o(HWU;diQhvQ?x%?|4ZJ;0QR5(0vdz6`CK25Vd)u2l)}M1~vVK zt5sZC7k-9lUkA>gJH;i@j=te585uwbUV!FaDJ?|O?l%AP;`7Q@m-!Bq1Tzr^{6s9X ze%IgCU}3*^7_F7_*H95q0nbC}-YNqe0>V4$tY8y+>su6z^6%r!?oiW}Mwjqu8~-gD z91%n~#&iaxlU|XhirBZ)ts|ot@oRjF+Q7d{E|TjDg{L)XI-Xp`FmoZ#7p?YqCVBDs z9EGDz3(i)x!G_oL@0R_eIuI##6kbPKkr^2Z4MYQ%; zE?eI&=zq?ooeb#a=C0zytSitiPZ1Ut&SWtO2PjP9l8GS&P0fAd$7$AOXw_}RC-P~A zgND9aacYQ(ON)rj2{yPruZsPI{=uvgP;KeYsApckhe%%n{5>#ue)q?9@?UZ|6D zX=WBR%wpMXFv0g@Z`TSMu4-3xw-Mlc6>U|CZdzx1V*bCNum<|Oq(78-Y_t#!H9M*0@e;WP0U4Y$9xL4-a&{`7djG6CAcZp&;RK6$~6qO-~oK zM`@9C;B|m_fWaA#M$SXs6(+Tmcc$k25RTffzEEbs+FI8n#(u9eoe9Qhm3;iqslB8j z?ik6-%Oklc|N0f?xuR(XyGDZOL(h&=@Pg~I<=lFmFtYWB``LC)47;?Z#&MlVT94Nw z1swX4V?+-CC2b%$xYtJJO>*2krHyH#tN}jg5_=oPF!B z5`MkH8}d{oICj}srhw$RNB`$Wj#Yw|!jx26FGPT)wu0;{DG-gQ*C7pAKQvb@OV94`iLIw0?IU{ zq?qZOkF_K4Ig!|lS0b;Lo?yRk2Iq*{%*KWHZSh7DE>>00sXuk6+XV2BSS{4!sO!4F zRZ@z_(;7A=Ajyg<=46ufBvlGdL!@0wk%B3P@wZF)eS`c$(SO!jYe_r+m7_wsy2qo< zB-SMX)EJnUw^y|6o^`gU@g-HY=wO&k1kX)<^7T@Y^QGZOm)kcyPww!CPY;L*i?Cn5 zjY@FDHmlyPq&B-WEviq&v;mbW;Q$!!mt9Iu#umQpnArwoQG`br;8i%CwqtB7 zNqmM_$-H8GsdnOHr6ncd*S%y$SZ@5=39>aWP(r%KAOanb z*12L^B^W=A2Q-nl3*VAHFy1~fI9TN}09`~0l8Gp<051XC;aK;4eL>JhW|&*M40uqk zVCF`$%P%;7s+_X_!hbVXzlP|MzWv!Mrw#%?yiBGuO>O6m$QS`MoH7b9Fs%~9rloY} zsm{USHVdc{?pN)=d$=RI5w?4{m37k}F`UDCtFG-14-C9jNpsn47(SHCSfQe!F|`w~ zk|L;@Ku>~;A6!x7XRWn7Q2N=IKF$=mru%#e|8Xt?-0)Bk09)hh623qP%AddCNwmPq+%80 zR+ZKfJ9d7I_EHitAiQlC4t~EgLD4e%#>8nrz+UlVSriiD*?K(cjz8r{r~o|k>kDl9V;iy#px0TfK=kSVNH(Hv@x%LSkZK z;5t_DuMh0Sc|;RLWJ!Q|IZG19iN0gtNq>tdE`0rsk0*&)ktuB%1qHwXa^ zsFMYRvJ)-7vQH#cg5t;*!Xk^3q=>JC=S9HX9}XtV5s|Sy$C1eAG6RIZO$=cxOEI|;TX1u#Gr6&o30Hxf{-SRk zkwhM|;y0q4lM)D)l$1lU{&0-0Dj%!|kGV45=A*}Rx4?6Mu`y$Rte-6QjIrC`nmFaD6U~UlpcMb5veFu;n9blTNeY@5} zgYv}r!Hrj<2dDD51dTmfT0s+>ZGJV&5K79z^ry?O73WwlPxd0U-z492zNe29O!P zbGl<2jEG>^r;*FAlD#t+#6h0lRAnUKTGOmC$B+tg-4)Mi3OOFP;7GSQG^Cg|l5zzJ5LNk#=l9N2V|9(6g$ zf>mB*j+etXv|b%8m+LHx@nFKD5>7@1-4jtiwc%B&sHm8E6_l2WT9w!nWyM&MQcx)U zpmzMD1<(^3;%og?0E{4^A3RX@n5oi1s8r$=EWo@YH67L1+#8ZwGT(@M`imy<{7@p9 zbD4eUe*#z?=!lzP>84lqrq7;FQ=?r6w%~+o(X)>IX9bjNvej<1%tbd1;=dc0MF))^ zWk$D6`pK(bmU^K3Wyu1kWvz?j)o0T!!CJkx4`;&&+U`BbZYOy+edy~X>@i8+5AZT? zlpl1ix5T6HgR?CP5}zJ{W1+DP^!j_R882M)}T|H+k&T9a9k-%NkZtmcuFW`7xJE?^{J72tR-R+?vFG z!_Cf)1vvX{Ktm$lxzjypf$9{)ow-T&ZneY@XR6(`l^0Yy0ofl>*^wIKVYI3!BRNk| zLB`6eiahmWgQ|AygdtYI{~7U)pIJ-??j$tbv$_@J_C8izJ(7KTl^Xq*#>C>o`3wgtv z^=I0_zjmENA}ca>G{60+F47JErwIbKX#1Sui!?7p1uf;s^B+DiM{%wzbJujuyJuF0 zJxNnJ9^oXgZlCppa99KVL5VKf*el^-@pWZ`t zbZsk{e{)LlZzxqt8Izb8*5Y}}KF~X#&{B8*ZgP@ttc;7KAkM zP{8_6n?nC}Sz}6ov#C~zxOm=u`~ZOibt1DJ0!VfeAKKo>`>+4=@f+HK=?`7E7pcVZ zrR?gMKCMuu8Ju|y)N_pxkaq?@zLpB^SeSg@wWc3W;}h1({eLJc!0(r{BIpjRDYk)2G_%Af1FQ6R zz694tgaxyjV#{3ihOD0AbA|2(*=F6}XxLeUb$u+;^8d0SedGWeVz~Az{P`(ueKvtM;od;_TPu`{J*ZS7c5kFax;qrD+I2P!=dF=N zYT<#IWRFW6+3D4=%a@FW38vn`?| zERtF5qj&3hz^;`yqr$WE!StD9b;KnsZd;O%vFj6dgbA1H<5yZ;{E1#OD4zOgP56V2Gs=B8^|Z{7Vj4Y9-*=l^RR6C*S4KW=NmgAH$&^?cae%p${0c^6JXi@pUe~uqXHA zJfK2fJtLamuy`!OcgD!Vq*Q9je(l{;fad0;jEH;#Hv9}>k z{?X270tVnvc$I!AjZu&h>`hyXsHv#~o!{2m^K~cr&kCP`A7&IxA>sz<|FxL zThQ?E!T~E7Tjxdj?2^BGS)mxU^=ZBVoJ`;5aL2E+jNTtU?uvMqJtlSL9Tb;T+=S`e zcrBjA=L58>Bv})h;*q=rBdpT*2PdEKMIv!qN3vVdP5%Jh=T-1EfSxqf0r=sVqZ^C1 z2bl-jK!AUmA#m+LQK3!F0f~%=opOni-v0 zqdS16`naX%2ExEd(9{<c5<3lR?w&8qp5whqzEHa#E3fSdjOB{zr1E<3LDpOuDK z+HzQcmN2e}I6EJvO8~N+U=sqE*|Ur95Q#(m!|t-}@E3NRmDQOQsK16a%QqXEyx``# zN}tFDM6K%s>mpT`1s$4gE;vGB#%FQ(Cn>F z)8$H|_fvO6sVVfn*>ENjN?D{aSNjQZQ%A%Jlsh9F|#X?yW>JL9?gc0}AjU0wi& z#`gZ#GPq)eh{I;z?4pMk_+Re!UX&PiGubvn7H;WNTrVUS`+tXNaFl+4ZgRi8B|6Tu zaeKRWX=P#7e8v31_Hvu;m`4dfS$*9Gi$tcu&FnHvZGFM@F$8Qchf%s-!0W%C*B2xP z#1(HyFa0f7wVTjKj-Fs$TOwK$p1cvt7Fg}>*VRM#VLf?|)joB08>B^gZ_j%F*&{f7 zPn&fY^Ea+*CvL|VGcfQGJmFdAzGs@-`^A?*ybB z(`ReK6L-0O^3`tG0C|`4p6io7=;FZ(^zBK|(ykO8uOYF}WME-TD*k_qn)L&&Alv;r zJaxQu3Lj&dVXSKki!VXm-}{&@Cct+lmU+v<@%0I%)(^RjKPek=h_DUEcytNo%8xhZ z2vy@RTP#2Y`o8iqObK@82Cy}2zziW#6E!TJ;}zZtO**&j?7rwC)mK!fW5V*lob*E> z87rBb`RiYqHl62Z-XA}=waFb6pD1@1PU!L9ht7?pH8GivEQr;01)*oP8~8Qqq^`cD zxpYkaf^V00;`6`hf4>n@eTVMOxFuQkH|{!*ERp4$#{&bUZ+r znM3SDw7a_?At~vP#O-$It{fYKMpW-Er<~OTs!dz1Fu4>2!a#+GoxR2x=~}(35!r&9 z<@r!tZfJl#wVN+C zx!pF(%YW_UZ|xGg6&DvP&&Jsb&wNMHc9~@uYjTx8FsO@L69(6B`&?fb&#YvJ9ErAh zbEdDDRfJo=)erk9e!h;VFDD~>(O2H7tovm?-SGmeVCW8_vh5nOq$TxnN%xBMZ+2Ol<(-=+PCBa_75B2us|3(slEO@VMNKnyoT5?^2jo%?eqx=>t?{>;aX% zmGyXel|8}>)fw-$T#%&0q_@d%qbTB93`q%vWhl?_GJB76ffv&cY58@;loL()5C7};yrq?a!Ve1wf#)b{z zhe9^G*uywB#bEpA3ZN9sW0genmsda?&NlVu_z45Kk+HwrE8wiRWk7FOMZ&Gez(6g) z%;(18);}ohIL8-CqhHvFOzhpmiwG!hataDTe|9Bh<&>Iu1F%>W?zB-wX!B2t8jB9x zprD@qeu*Eo>LqhA8L>X;?3ocV=l{k zhVuDZ%miD$sQRHpUrFOOmYz4aGxq+!GYt?3p)Xk6oW7l96*b}#d0l_J6@EhiOm)Ze zIN$!7NBFK7HJmwP{XU;ithx(AQW4yCzo&PUZ9000&FdlZp!y7(cMRRTbzPmXC>=m{$|2Na@#X_Z(`a%ZiewhsA*^ft*_^9 z7MbscPESo40D3GWE$1s8 z0T$XL!~c}F0GY4HH>$-i@cylBaloghp;6S;Jv@q!ePdy1SqYT3h=_{TxK~-jx{$6G z`*f`FoQfx_KUCIsWq^*DGKPTD=C7qQ#GF{t^WOZdwYmodP%ngSVAG~ga?!2n;hXbF zo$%ffH#dK4VG+e+K0bYCJ$x|aPCgTuCeA!vp*S>>&P_5?2Sroccd>{m2aLR?qNkr8 zp>S_weP38qq@?G4C@3R?wEpClgW2!~*iM7V&8kIo#t2`EoRG_)TArG18dg287cgD7 z@2*q-Jq~CMpwsr*AEV!`YXg7|+74d`ubQ^Al+psV47<*Hlj8nmN>tu^C}7k*)?9#1 z>!5OehF{ZBN`QNdCn-x+xNYU7)}yZXv7bA~N%sj!jo{V$5d~r>2zZag6=Y@YFPAv= zEDIG_P)KC%q+_@)%C%3%p`3hoX6)Clb9FXES5ql;P6_6$_b`TIF;Tw7M^s)Wqlh)^A zS#~TpK2}y3=Tx>V47S6)0H`_an-6i8{s75p<_Qr`hB>{TZ3pw=XN88RggKDf0t0~+HorHLx7Q7Wb9wxW zSMcxLZ#HHWN`egrMs`Y(&y-^HvIw_1eDxl8x4s*dy#6I)iO|1gP_V^KTlkr=a21gv zReS?4dMCtkKr3W$hES+eHd+`Y^k3D5FWkEa$rL_o`k3To-%-rg`OQ1{1wjjoqFci} z`IRqX`FBNJ^R?D}Z}Vlkt45n62IA#~fDs4Pse>1KS>K2|b+#_cEeDXd1Oxo@IRKRy zRpCLSEFT|3F>2}QaAZ6-Gb@K5BmECC`QHGBW*i8UZ}a^~HoY`3*E!CC`K=f8+By(d zi3!Ia?r?aZ=bh)-ukb!rhud_oD(V7rX?V!kH#T-&b0%pzwA8qXTVI1ha1nNanyhU= z!Ca~?Wg*zpqDfXd5qbcV#1MpcVeYfsK(1GUbI~FhRq=t7YNk$mMhrPhLPBEf+id?` zaq}qdKeX?WB%ma^%OZR{in}@|4&xTM7i-W&3YaW{Xk5oI+>t}+r=*`5agcUp_xP7g z`C^)`vqXQqh7fvzQrEWyk3HUGz6UEhDzfe*)`Cl5{6zMbW)QdQpsmIZgJD?oGf z$J1?#=b8Py^%aRa@ApfZgoG}28}%W8ln0VQ&0<8D*UL|>o#hNoFy)U2oODB#N6sDI z}*Eoo8dRm|yf+Yn08`c-qnrVt(%hs-~V(_FxO@RW*no!wCRWZ86K5$1nCcB7R%% z^W<&aZ#Mu#NMyS&^M+ZZoag+FFu!zLg!Xz012wh(QC;jEsqn63M|_pmOd1QRY>X#%Toi@vEd(3+YI|q4qBrWSrlMzfwooxAWe^~-M!<232+14 z0j}qVBPkwSm~^)wEN#Zp*{>xU50G-))^TcEhn_apwTDFB{D{vbCP3js$*hOAq+cke zg1nAf7y>TxVMR1I7ps!T0`;gH;pxx?KG2h)(8sW0PRtWjx zu=P8Xg+%C&d~RJue7fIis^40g*YpAdQYqh5g4g;cuaer7mt8YTjMu?UF1+N&h8@MD zY@DBJjNZ}rFNa|1fql769!QL46^MFc^W8Qe2;GSX3Pf*LXgY$IPNopImK}IL^ifRy z`f2eHYY@IaUVzU?s5=#P9jUj+W?f1zJ{NWsQ{lxr7$PGit9>?G=H(UZUG1soM8|)L zqo=q26T5|B!ds93XOba5yQU?ggACXHoNcMxeLcZ4=bM>GAW08j8~*7RDJrFyl-{~Z zd~1bM3BV(8O}7nS()(byGy;Tx>D*@tY3Yljt=#yiz5vwkUANA7Oh((pPp9o4gAku! zt9l~*AXA@Wu&;4}h_4FKO?Cal;$^VBPVyv?$@nk1qkW!z{y(@1-He#Ht2+6$lK#LT zP;xZdw$$LwiH~%A>}mHK*P#u7?yiX1)2kj!g85}9nT`985)*xj4b;BMa!VU)SFqkp zU?;d=*E5k-?x)(?KSFQm9{?pVj0W0cc<8Sw(|ui+9x4V7ru9e!QOLw13fk&B?txK> zDp`_mf{|G+Asrn8C>f59x9UHALPsLtsut9XtQH8~DJ&~fTMkFHdRHv%dETR?igMI0 zNVVLgfjp`-sh@Niz&%dZ3%c|5W}HnK5qOIuM?oV9$P2Dk=}Jta47?f#YA^fUP1Z?2 zW00T8s;MQi(Y64m`XR>f|Izi9QB`i;->@Lv-6<*3NGPc&ASH-|bR$T2w}3P#oeI+3 z-4fE>B`Mt<&)O>Jx&QC`#c|FU8{J&jT64|$tMxG~?DJt;yUTrMW(C4Eozl-O;JS(5 z#J(;?xDM55eOQ2QU!)MOgCH@hrh8a5bX4b8SnKcC93Wwn%~~UMH;lC_upb>-*f`J? zChl$hGq3KXYrdmx-f-HNS>JuPM9C`AkEf3dj^L#(qudVq)9v>@teAt;;)m7;_Lr^} ziO?oY6gsWd=*#Q2*g)1LR&{O@t&L^f`RHaA25?3)%+M??)}q$Wo{~g9@;{J8f~@93 zYj?%kcVdf~gW}zSv%0;vp1duaf@|kp7Z;w%-s9u7m%@sQ^72&t{7kFwK;tiyyH+HV zTni(~wyR95`EGW;09_FA2osxlqY4l-=G!v^nvZT(n0=36q8n4JNDS0iXsiGbZKt(0 zb!xv9QJ>vDx}{t)oYt+tE~Fn>5*RpaxfpQtAEMm2!LTGDW|$!pO`zSWX6Z1;&ughXY;w<{;F zy}Mg@dxk%bbG(QK|D&{kY&M6crl9lbw*h^?Lw2v74?r=Q64zd6}D?~qpogq3`bh((Li<6%*{a~&{RlvQ|bR*#qTEU#dU`kj~;+~Kr zEcyzrCz$B%hp~HDCCi*DM2EeTA$A6Y!&T~S@mB9m|B)BELkA&b)QjfS!ZqoJ9OWO3 zD16>a+P~bt)umDt!2o6=1)7Z!GQb7!9`%;bd;>tvz?lb#%O#a6EO{4}8a}191H=vO|gI&uPe9tOeqw>6j}tl`n_m(}k*$ zqIIw__;>lD7Y^T)*K*2ds8wdDO*SRm9tFDqzw6&^b7um8Lm=Z^-e4l@;p33NHinm< z*)3<<;Ui3Ln3!aKU|_*}@kH$~N%5jO0);FOwNs0jZ>B!*765(b(@_3E0ZeCn@dA2| zeQ0WK&1M!e4su>2)%$sZKLoE&aYohmol?`&zl3~$y^&+1tuliaEk%oaVSyb?%qw1= zAonuCyTu!Z@1hTzHS;lhi-ct0U8f^FA)ioiahzd=tlmYa4I|E~3=rtxapq`kgUX)=Xb#$+=`rRA~okK_!m)c5hFm}Fz8QKw%c^U7R{eW^o z9S$!I8-3^>{qbA%23@;`3A+lUP|`1*{gi&j}YXnc)LA{{TQGh2ZF#Ac&3w zui>6tgPaAzas_q!4rA#9fuJtwBE{bawudyWjH041=erT_p>@!yXdkW(|8acag0WaZ z!RNVPPJ}PUu-=^kXrJ2b(|Ka!P414_kuz+-4$%Wuqm~vW8VQe#TPfx8yWiuo&E4;L zru09(d{Fy6$cZam&TT8EO*h-L3kfoRUX^WutBfp7Kolb76aH?KmU|{q?(JWmE z3W54yX1{JK z)Fo78WqJ7v=zn}n+(aMpv9Un`0kKJc9u0!-T*DQUBkBXWSbCtSVQ>BFbS=$Oe~z+MJ850* zPh^$#-(A{`TtT{P{w=+6lV{I6cU<19VzU+Hi(y^4DnthThvEV#76xk!K$6@S=&s=< zlp{^=?y2dGf8>xoobRk!x+zrzx55AZLa2&tNT(6%)%fas%3@;T<+=@!?ghwI3=#erh zGqKzhD|-)wI8W1plx(-AGW8f%$BXG+y?PZm28)A_FU&6b%T$rC?y~`A>F`?N9;!!4 zfy#@qk?SgX?_#*L!;Tdlk|H2~aB7F;kg~C{8QBNhgUcrg3XzRDKo{fz2b~seuS8Pl zcRG%makk>TdEU_=UMeBzE`{pim+>$f^o+Lz#IryYB z(7Pe_A%7`?6r>QuheAszlx@LEa^x<|-JSs0MSMV*U1T7XT{BC z0na^I4>D(H7T(KJ-^qa)EBf`j-11D|WRxTusiVT+l)kOae)ANxi$j?XkiquCaWY6nN@aH;OsP8=f13?Xq~mI!+3ti0fPmQRULy zy|;#pUo~N_z+JcL3>zcDmBf1`zcLT zur3IW#|oFgN+U)VlY!^+9mF5m9CP$-LK0J_bs%J$D2Jb-2oECE_b9w(H6+>F!ZdU~g2g$m?-o4@_H`!2u@wQ6))@qp75 zEdTo~{a35I0G6(GdQc;cyMrl1T|sqZz-{z08jf+9`tM_GU_)xh9~_CFuga|$KAHcY zjlcm-TYRLZx0#H%qr6$=zoix@dpX~!sn17>e6yi^u)&&{M~(z!7VQir&Tghj{^%zO<0fgdfw#Q%>ne&=OxnK|0$qv z>E}u(Wbl)a1}iu)ovt_wboJI5UYLs>HgQ{b-g1lXY>@XExX_{ih!Ro?nQ}W~qdG^8 zas$LIzw1q7{q4V%53I|QAopB#nOtW~rkBM3v+cW)?Kc=S9ou1)s+K4KQLaU7AHM~Q z#iy3Sj$eFJAv7Vyj9}fquoNs>UIhE>@AJ%EqgMdk#a%z5ZzPTE@>x(^W4I;oAjL)= z#`sdC0ca4W%XC+3Cccud{w4T+@AE$JPxrIZd?iriUp=2^etd2>YWP?endU>;AXidyl%iD4Om_1^>%v6 zJay{e`kv^pgz_xtxYz10qvP%6KDz!5+@Jc?=sV<8w^$H~mP`v>^VRtZpq|q>K%h_> zPn2{Bnzei&<+V*ND^uX5m6eqh+3>9IuD072k(bAvB4fdNCm|aZ3fE#My5Tp7QLP_V zpD0cG4rkg5>PLLR+BWYrKJVUxTA3U43H!cA|g2Gg3B`ONW$%V zXJ_ex&SD*il6pGRD=scBqo!uEn3r5sgynR!0ih@WlCcy0Q!_6wnl<;Ox zLaO70QiHJ%j6+Mj)guP=Q;wP*A`@Rw&{*@Y!98}6SG( zB6!_KO?fzpu9;T-|@i za}5Zokj4NH4veNs{SR&{%X$m}ZEr@;S04Q}(>FcQY!9V;5*HR17XWTT)0}JYc(U$e z1zY)(_6fR`F)Q7P#B{839a8VG|qeqWaV{KkB}K zY1F%lY#{*~5j6bL7{TSW_#+IIoz;`UFeoxoH)YvdzfBamhKMqIcyNW0W zbtrnHqNc!t-P=FbIxX5R(EcWllld?^MI@-9!XkxDyG2GRm+AcDlPk?j$DfwY7rXax za5lW;o*$-Xu*?IR)dx6Y6f~kACcYZ|X+3|wJ!)j4RD1?+-M#T;f)#F|jXb^X!t^45 zB@;yX;dhgT1Euh*^Dk-R;;Mur(BX}D@g8hY(XK)BN$NfK6DYXb-j1+-RBZ8kTmlvj zGAKgR=cdozzgo1i&9D(3R~H>ZyilRUI@2kiq>K@x=4o1O6FIxbja6F5^V(fh^XC9+ zL=Xz5%yCCHq~0-kscRkvCypG_w5(^ROim45QDw4Nnsz**bzwg{#CqWpM!X#c%y5tW zKh>QC2OPAmjs|R3JUkR=TiT@RD>8dGnJzU2>8L!=uy+(98|9+&C*8U#6&vHbh~XdO z{64*fS`eH|7m4`}hmfOfw_+elr{O{F|Km3lCL@1chmydyV4Ir$^@n1Vs`ti*`ULsH zw{J8`HTHqE&3D5$IPiQ+qy0aY z5t(E|C|o|1%^Cb2+@!U&3S`^li^?~C)dyUz_*oxs9JLfR;4HyZZ%dIY6?ujA!l+b6 zTu%>JNBy5>64}~_OGsRrgwyk<90?D6dZDpM`{7v$aQgc{|LGMtJu+m$nyU^ir@8Wq zUG_(zP%VYIp|7+A`Qlla0F1!>{?9>1^F2!wQLgO{dP8hdE-sv&>FrgYF59gPGUDDrs^=PcQv|nuzB}1hJ8s_)#`A2cXjGq zK5Mb=>X03r5BjPOOJBuaaN5SItEKY{X1L#{B?E@ZXsqD)^jG~GC?sKaJ%)D)&EFIDEJ_coviKiV43zxPXgtknrZ6ROf7F} z)x5$Bh#>(6kD!#?5||UlUWEEzfI&XmgqXC~ z2d2ELJrOYqKa^3doE)V>@y@dT*R}ES0?LuWQ&W6y1wJS%KVCr@C}s!+wTc7nMaAV& z4A2u8>>LbQUCJ-==j7zXHijNe<0p#?&naQ;+hrKl zs#4)izcgBlM4{l|N1Q};vOZWzatp>gSkX{2`*DJ(v)gbtBvX=~W=&ZzJ{M@`;Li>_ zGZjA;hcRjfzi?-A%3zML?waY&$mG=5RHY_=a1``+aHP0^{UZGsU*Yg{!pfW_OW^DQ z-;(H+v=#F?LE(xjRK~pOEyaz%0(G@b^1A|<(jTo2KX{uI#iZhsno50GVh{oWK%Q!* zAvhFGWnAv?<0gfLd4QK_o{Ba>>%gGya~?*CLBxw@GwCW+S*%c=khAb|xZAfm5XFN6 zifp>tj(Y=x$&w1Ju18UeX*HMuQ!SAT6x@r%yh(w5bcXf1V&TU+DMwG@X{@|eXDy}L z4*`JHsJurt>J1^I#kj~2OFo2za37rNF3#&IJI*j(7_&(yI=||Rl8U#6zS@hz-)$3| z#wppNmbW`xvw^59f<__&MI9!~bPl4!CL9sT)XFwgrr6exgGSI*={HX<_E~lZlM>UJ zW(u@8d{D_Z^6z=Pl1`VXMTc4bv6sL63Zq_7}WuQA6JNT09BV)jSwxDaeCz|X_n zG@Fp^{uBqa=h^94CdynP;+(nx+?oh2dn=}*@kCkQa7?Ch@+sL1h<^V-gA5o;Scm4d zbwKk{hP9JLCpi85Y=d-UM%0w3blA00?a%NlinuXWNo8RZ`j6_ZOt{_%T=czw*&2MAi3+< z-0ZRsY8Ze(wha44Iec-=jMBK7Hl@ z=xh!>^y4<>o8})f*Mi2o>w_U{4AaDlF(5@Qf-)v+ae)9e*gJcLwY@pN>Cdqv)CMsa zE`&g-fS>aA5Yj|?>SiTLdreLEXJ?1eQZ%OmeCz#CF2qnM`hN|Dl$Mr`RLXiI!r5p;+_3ohmQB(U*E8w)yEh%t}= zs^~tL_;+DzI3tXlU*OJRhI-04e%qx9ax)&k`)jYfRc@H~8}Ve0&9l%Ano13qBx(Gf zP^|xs+b+q$mQ45ju#ry)Xd${k-LHXqi3=L;#*TjAV^<$11l)WxqFZqRZZ<7FcM zbqD60Nf}z!B?}4as>tE~#~#S8Dwq@eT330Kb(FLY(ad(_i~hKq?Bkth_VPxCRJi}^ z3mnFOO~GBf)CwthU6JpEXEYZ1d;OlzL@g?bx%FnPeXg6r&;J0V?NlCzz07YSgn^7e+Y2BAb9kLPQin&O=L z^Tn8yxJDbjP7C%}aJSJot@1btuQgAlZX`Czp(~*Y1%vM^r>5DrZH*!MwAB0Wr=qt9 zz6NLk+uu1&A1xJ?upT#($w`)wmw9yL230r|6&qW>`DkhH%l|*ep8{hgEntm<#$cJ= zN(BFwo*`YhO@_jI1_8V#kSf_T^F-{=_= zbWWVE$!+JkNt?deqFQj~CLg9gb#|`NGQ)#~Yima}Ntr&_t1_D3;6{-L&go@-l~5$Q z95t(_k6q_qy+~w;qFbcl4eAdTPX5gIlZAWvD|%yIXT#|G!IEv4=cf9^hc6r|6PNUD zEiH?*dg&g80LjpPJIJkq$!tGlf+DNikej!z^BurDy`Eh^yvNV4hP;Qc#5u1Z>Ld5D zi%;ZAP(?C`PgS-e0oxcIpwBh#y4yRr9Y3^QbUp=m)$8R2s`2hD0T)sW{O%q3h1U@zIf-raoxuf*{n5s}6C6mxMi!j|m`sYzf&A~)S>2!pfdD==qbDyEF5dXcHVsY$u842V+VAhvs&_780=jk@PL;Us zefpyNKM=}W4bXO$)mAI9BiOpTOqvkXz6|WJX8{`Fn9VhDvyB`M&fTa8Cw3Sv|qEkku03CP}`W23U z4k81sscBA@>G*G(pCEWX&wSjS=QlP7Bt~NOa#9y z>aZU1LxpQ?15Pl9h|~vK-Ha+F*$_H2B90fN9W{vyeT_f-grEJ;Yxqh(=8I0rs`WLr z^q)51-fN+O*(A#mr6rH}lo)wZ>G&i~`(qiw{`R>+ezY&l+!98LNq-=htt(!fdt z2@3Wr2_d0z+2|DqwbBF4vv%9U6?08i^Tf)!QzvXnWgEQ4hXrx7hw7n(d{}J48ks z6~&Z`O5W%WDvbAozkgQ`TO5dfOWO)iv_kfXfU@11KBEg_iV;nuN6Q~6;{5Zm5&Vjy zi3c)rYF7w=BG;B;VgG}VIG`N+PVE`oirrOdEZMjl7c zaJPY1zx?ul_%Hfo?9dGmP8@(^5|W!pYkpDxF7*|(51+U5?E+JHKZ~- zmyUPZdJ}yE=ZPyEz4^{}4j0XFt?tw^Gp3RkXCHjWQ z^ay9c5%Ii6>n#}4q^Nni7on8F-n_K5*+&$UDd3f8JJAu%cS`McR2Ers6~Gdy{Zp}% zq8VB|?ACxZ$MIHf@-QPXzgO@YsYlR_sLJ|090fb9B$QirrlHj|Bv1AL^&5OGm%F*@O2TMWej ztT7j{epiLUy1tfH7@nrZG65@Dk*VcGt!O~LL}L6kYrJ%Ni8lC@yM|ZWJ*sO|Z zbaqDtmw+S%n!|Q(DeB6{?c!3yevKuhDG%CS_&z5mXT^CQJOxyJ{l!x6>z#a<`%a~l zmotw0q&0h^qq|`I$4oiG%&7s2Kl{tl@)8PcID44EA7_5}Cv0=gTyGh>4Bs#$FQ8WJ zhoI!&e?kV}=s964OgGvBuV1?p^fFNM(ON?cToCF7uxAy=+akc+Xye32_qCY|NXKuX zx^%42`B!kLM195-A{i9yIi2nvm#mHl2#1S0BJGnUN{j^Tx|)4+!40+`VH4c6jxX$k zrfn`tA!!h;pusbWnwY$vnO=ebm>!vb2yX8vcir)^8ixmXHD@T&d=`9I*w~t-$`E4` z-@#68JJ6f!86lSrL#&VdPBxINrjp)bEP{JUn7&zE=Eu`+@X`XO&q}xYlj9~!43W!B zr+vVcw6M9INI0vnp}Baw5byid&M7OsP8QY7Jlk1ncq9EQ85RIbeXU@Ae5<2r3Zh#O zsG#yi-vxHO35sQz^+?ZA8m$;hn$GywUzIF$f^6@I;teSHDxZ-|t&{i%f`8+V+@a^G zcAAip&E+^^MyVf6{`jWhGc@<*i#7!KRkip=BQ;XLI1o^3Ov!#BF8931o$qK&V+Rb` zQ?GHE(}mI@99BtPr`hCO;bZtwkdmv9KK=BT|vfa<5#Ik zI5tKbD*pG|Ht;|L+0U~i>%_c9cD#y22r~lOMsvwa zPRXOUf&t}eSYOdE@c_5_pNaw~@)Q%*N_kLGx?q4_G52}@xn0A-LP`FIvU$2w+S5O# z70CGB;0L|dsc&VZs8m#Blba7D9{=cVtZRfq$fkD=IIQAK+FOHESix$J?ryBF69Brr zXv?!j+Hyr8X7VL-g^tSFAff%3`K0#87c5Br53A0y4eAIau)+M95Lx)gd(9k6&qG)~TRr^_(Djwqn-L*&I7V zx@Lj#w{3;ACj>8r>db?IQ{qUk=xBVqjhRQ$H8`U`y&;x=$UZ^)S9${Y?GhxD#Zfyg z*K?0GLHr^lI4Nc8(rMep+kX#fW2zEc9h(6*&2kvxkY+;>hUA%w~fDehmEWJS4$f zKRpZE?hw!=!FE<9Y0cCyl!OSmGBYIB!sfjhr3}q-KCTLRe)dXT9qnTW%%k1|RR~$? zH2qrf!K~tXg_vNfU^vYS*8|n>-@gylwXJqaCd!!LL+c#0yA_CF@rRX-hex zp{0eht>)LROk`Lj3R}1bm1kk$T*)(HDv4LA`pg|nl**WPmUTh}Xa~8z25GeQb5Uj)|gQP3;UcPg& zj66Usmo?QmCD4+Pr@wJqMj zv3{4?2S^ExG<4~6TZ`CjQthmcnO34m@DT?-Ce!odJ7`4K0q5p)J)MNR@4<6uzJse{ z@Fxh<%Sby0VS1DPoN zzJAKO?a_P7yB33KQbrsJ(gv>&L_P0;K)bK!aW$4|9oQFygoGyNCHA{$LJkEztebpu z>FrJDly>0?6 z2S4Q^;?hvlzu57R5^y+DyPjN$#+(1JfJpV(ECyf>et!IL#tsehiP*)pey^c#%NWWM zyZF)bSLfWvX}MD*Qqt03`R}wgRe}! zcM%?MBH);MQPy&MzPXgW{KmVJqonGj+)%UZ)I$DP{*=9Jsr<{LPbo}}n9Qdc5YhOC z=?x-vsL-}c7zK2t7AdMr7`8%BF#v|9$?-eTz=Kmgb`)$|bOac`;$1%Q>=1WC>)Lnw zoir95!ys-Eq0Z|pTjOfTGIWRT#zHu&LHLB*lzt&fRTB*#f|&GA`fjpN2?D(a*<`D< zhe6C9%>359@hN9wg{Ce>vQp}cKS`P(Sb+20RRikitbYK@BlI>hr`G|K`@5d+336e~ z#0o@oK=X`_gd8v=?=K;~yPjV^pUrYS<%j0B2?BR4+BT2xb4M7jN$r7{4nAkLbb#ki zL$kw_T{LLECd*hyUH5B#2t{@!^=|I;6j`aQ?1G5ycU~>{_R0V>c*}3icD$1GNU84P z*o7>BozCDcNC@P}Q7I>r&tstZ_6D8AwM8qMUGE{Oo7(r`^bdgjYFrS4GT7Fg0YQ*ft#Y1cBX7d-srF#{P*QT7p3-Q=*C1iN+c# zWEeWmLQnMA&mYay;PYj;EqX$}2x51>*<4q^Ue~;176~M%dug(o>70Il)`|;vj&e3r zn#Xxm26KOTdTdo7zvjndRo8Ft3Ha*TrtjwzR zn7Zq(NK^DD5$0cLEdbn=pEQgiP0rCy$Wn0IJz%ciAXh3`&32hsf0tkPzIxjc!I#t# zgUoqHns0xD>O0S;^dEyS@#cR7#0%9|0|5 z0W8*H8+l+B^kt#Y*jr zhVY~gKP-KLs8IJ0ExRmSxTSKFrY?SDyO;7c7cXJNk?yU%xe=Q*%zyzrwxI?M>}_H_?{3R8@7i&v44A|wmP1|OO|-; ztxsNb{fK)yII~Ss0a~c%ImoFUVkGal|AOadDxv*Bp_9e&^nO@Wx!V5Y9+~83*iR^A z9(&q{bTv%N9`N41mN(J45M;<71|^ap+EKSLgO8s;9heBNkAmjqZ}qmx39zoGdO!n< z4T^K&sFUl;=JD`n`6dk>+l{vy<+C!XZquq8Q*Q|B#1hnN&(KwEhEXe)Cpv*_g`hAV z7es~BA-AuXmC_5BM#BgBeC^p8^SDs`Bxs51#dnkttMZ37d#=Ft`dyVJh z+1F69HsZPmxyGq(*T#~HUzP-~FC^lvdVU_7Mn&MPB6w)B-kEKUh*fiP(tWr5uNw)& z1$w!z8Pl%OB;%xh9W#R-(WdWkq}i|jEUb_3hONSRtKmT&b@>H_uog;=cJ!KG$Nn94 zz|L;lOXU14yR*p3(S?N&{2xUU*TJUKull&F(fK&Za%KwII&V!?_tIz*hP@aMtBQU8G^0luoedlw_ zHN2-y<%r8&T{@F^&QDjC#92i&KtyV4WANhyX;s%#SbCOhciq*{BF#pFimj@8&J&_H z=1qugKaOV=xU0}WM9DPlr(JRvhjq^C+zyhgn1AEVgshPWbg+ln8Zq(a<`omkJ{|Ot z0Bc^zBd6b5+ysp|_9Z9LQ^OYyrxA3-&f_J9qEB2wM^JcpUq zMO8ThF`wsxT}&oMHQaprbws!-V`At?@R7EFWkV)q8Xm>?LRe8mCDmzT9V3A7V z+`|iLS7o93xN-(I2AWaGh|q6m3?YvUT-KQRXa|cH8K#K*886M!2S(N1!GByfRYgKi zpYnksmxm@g4HAX(j6tIV0)SE2Y@<2gn*~lw{G=2FxTAzipJf#M(GB)FgHGmco&4*Z zN&y3^w3kU)M|wX8l6IHtuYxWvpl#?QK@nnI%6P%^15|&P>Eu*)5}SrAR-zzrg%Hb{ zqlw8At)DLuPVV{z*=UayH1e!()C*nhw>c!j=ciQV5;xY z#a_gor5Dy>|B1|}?s53he{_7{C+@+b*wShDRzOAMPiG_U?Jy*D4`ZRwlXt|t6?heV zgWCGQotUv8P2X9X;*v%jj(5FUUaK*vwS+>$B*#7b)F|4!FUL-|%gko5hNV^-%eh9ojI~=O!@6{QY%7wl9oXd%*_|W^Xp; z7sdTWzWJVRokw(?On3-UF=LB9!Yre=hYsu$Fr}i#@qj} zw%(pWB@4k%axOv`oi)b=(9@cWT9QBv&(aV!kk+thA8ou_S4%hj+Pl*1kNaRvVU#y1 zD#~}MGitOtr&v+kUDCv&QnhMR6vUPTahHselAoui=LECO%&ho9xr-Cp0N<7j@m>7~ z3iu3A5=(9kxiGvxOO2;0FkP3FBgsE@q;{Haj1>xZ+PC*us?02|NkXB-T3~O0|x;RpMX5zY0%0)M}zct$mgY zu7*WYU>rsB?O#Q%2!%GG2a~3z?K?A8#~;Yu7Z1HGKCVm0KXyZ=;&y$ zgjOn%*qSq52{*4X$or})^QB(r;1aly1}QhY9I?`N5piL@**AMMY-WOGbGpW%I5v}l zg9E#xqr-8-lbu?gjoRwjt5;Y>MMYpOJPM(9@{O0X6!=-%&dKz~VX-RGkRJ~S)sEl% z`hy>@V`AQ%2Lm79*Y)!3=P$$4$?0o@6(I@1q_Zlz#=|Q)1e~poXzC|qUVOZmR&xio z@}cz_;V%AQ5k%C^B!D$h%eblD(VM<0Ju`=PdRp>?=(ouL)llpS9e zJiF^{riQnkCIdNmrZFskZUnJr0=sopxebI78qf|-q|W_1%B=L zq0pGl-xUJX`(Eyi%ifQyFtl4qNej7;SIipf_0*p6Ke(a6{BY(HPQ*TDX*qjbd!hf0>L3>o`|hHw^_Ow5LsK}(?1a7UnUk{%1cEI_DF#VeVeFTiabuKOx* z{QSQSQXecV=mye0C9)o`k@ue(E&XiNEJbc4vTI@gb>GXMY7Q#hIkP4yCnlRti2s<( z(qxEvMkE66%}4Hm0T|N|3zw5!^1B2}9a)&eLP0ZHQ%I+4V^+jFqK%a=&o%B7_6I^{ ziMI(c93kH>kNJsW^Lgiw&v*MSuA2!B;$PWeuH5h2f^PiIKE$XIm~7CCzu($o%6ind z!b-G>)=qkp6(!{H7GK7bZ=)?9@jNVD9Jzb@nRve z`-56ZG;q|IQ6}1VFMTBgYBU!1);1^vY*px}q6b|tUQYn}&Cxz9oBZ<=N|NREW%~+Q)S`K79#+H;2zMx90e6TeUm;`?=5{iihwt)i#8K68_Q6B)T4m734frKu1 zT1o8P^??k(4-?wMU)w(7PRNcnDgS-v$UiJ4I8fZ7)l?gzLy@xg7ByS&JHNiqaJ)7= z;mY0m@pMDrU+vk1NJI1|xXuPyOk#8#V-KfYc+A6`o42AF;_lE(onGbNP%tkHocdO~ zb6z3yU!!J(^z~UzoCR_&bx4cYoff`EB?(zthWiLZ3omz9W4;u;yq8zA2M1EN?orj! zahXm9UU))-nQI)3qhFRmP@0e^0^m;T1f$*+*%26{jiJQ_uW5>w_?`bv5XD)|fo?s~ zZ6UE_1nVA?ek#o{Z9NDc({7iP^{W+uI4a7mb`$b-`;ed`wH7q53<;cx6%EUl-xS>$ zaXoL2=U4rw1lj`Wm9VeD(|T8z-7b!hhZB|`JG_(JPOBPi&JMQ&=n|a~*gr`~_rTfI zZfpp!#t{q9P^YxfM8&6H0aI*tBWX;n6Xm1l#3%!E(v`pgMS)>mJ(s_~RHM7iIu`Hl z)EmmQ*@v_B*Ciq&1P`5-=rYH*`^v^ou(#;_XS_~xw_%NX_!W&S%&dj~$N=g49z**O zRPQ~yU_ar?@m{Z`6DCGgQ2hL3Tm{2w)tV=mm*w@}Fn?P_bH7MtS6VUsV2``!*@8i^ zc0+pNVt#GyVdrcWDaTrE=dR?vZu~$mI7WR0k|JXe5z!Krf_!I;Z+DU>bp)M$UUVR68 z?wIpJnfbpRs4{gjT3qy}G_+ByMA?_@Kga8x?~0h&1eA5+{~0L0$TpA!C1@vs!jeaa zkz>(ZyUGN^za_JxXO9Q)Pm3G;6Vfjx6GF4U4shAa+*!#LP5wfC;J;>ejqLUUDxOXQ z(cydO-@bnc7Xi)-c)_z&a$}-wQbE)7xx&7ewK+Dzntj1?ldv_fs!I9z@;(cT@8qV! zxmK~E@8)0!B_d~WP7X>$M1+w>jk;Mz-QY`t99HV%JGRD1oWpx<>`EA3;fto9AJK|CvwmU`7 zgajNsIlDJn3*gS}`hlpE6Z_gaT+!#%hnM)&3}{fipwMm;0Vcy@(6ls&rRxJRYA&Qwh4 zmzS5hs-z7x=v^|Hur@v)Ux8-yF6c1Vx{WFgb61LhBc4;~xhbtUt4E^0OT&{@g$h)- zB)Xvu(?^1HyfV5r#^PC&I~U*(u2w5qEY)#wa56>%VMJCd z#deYpo}W=eJ#b{UG<~6=t*xzDsB|!e3kqi`3+=}jcH13?jhz+%B6nfmRBXEwa#XyW z2;M#y76h2A*Gte}Z#}_jA$hDO*LG_)g>2%7iVan>ln4xjd|3jnFZRO$2B5mlhqS^7 z=kQkZ7EE_%2#t-MNPPy{VvrsY{_$g+YB@(f1>rrTfGPJuCpYT#_b~Qif(Jl5*d}7? zC$4dTH|Nn}kx}-o;p()rG#y{km4$tjNknt)^z&nW>2@h~L<)eK4_qGJy9$q>U}KX7 zuQP5dyjIjyY5megvIwZXSbn`wC^9SzTvRuW#fhjcQY`EAC7f8A6tLGF6;r1pMnObnqyc74aroe*H1TCEkd^ip*F z1?f}LEw)zkH9~~v6%{hHYu3=sGYs z7#10s2G-Vu3NK^8f$&+%%02EGnrwfVnN{!`=Q$BhJj-*cJ$`;h>1MEDTfKGuiuYLn z%*@ZriuO`6)aI_$Q+|nwyzL7<$5DfGfbhED@0<^@jJgmj7?tT2v>E*eOcL^_#bs@w z&3H4f-5YaP&arHHsSd!u>L*oc!5lYp@2{B-riE;eew_mr+o0k^A{fUxCj;BIm4y~q`bPJ)(b3TCv=*4x_Gp491`SpTg;aUx31o5vRqHxi5d5LgVK(PpValid@PaVcIVC4L^7CL8SDY9TaXNXR&hD40w zIN&)dsIo#H^FnSI`hAK$7861|@QY!^4qhmEi3#^^D#PBC?1H!4R;IZ^<>o_>&GjtZ zolStSV1q2}TTJrL)Z=oR9sI?=9Mvik^m1O`i=!}b8>6&G@+55UMAE|qj^kMkj=!T; zEFQR73_kK|2OH$h6F&d;jc3jslYrM22f#&W#gz`%di3}2e?#uAA35mx#Cb%{h9Z|H zIg~?;0J8%!aDd2Yw$N}v-)20y@h+>**=qpQJu5cd>_XC;ejZSlmyioes-o(hI4NFJ ztJ()e;Q%TNrBun$Noy##;pgkDN34B1@JzAJlKV$bHEwHai46ZO6#4tecEMmJn3s?e zm4EuOC4?W#hkIMNPcGL~<`U)V!UW(vT#~hC+s)D^uYNxm_d1x^W0Tyvvz8IiB&$86 zDBwW9syU3EQT8QI{RasQLUyh`apJo=DUKFcAW*gJs08i;T!{#w5cC-hcaS_rd@N`V z53W;LAeN1MoPZ{o=xqOSo&UP&UHj^=T=5J@MmHanD%WWb_2Aho!3K8(aRHDJLY-tD zas(&&?Dq=F?GweEZWObGCiY{Wb7I`Nx30v9clzzAhXQu!yfR6f1`ItA`ng^*luQfF zbG>G=$1HR^<<50U6!o}O{#4<7_J7r*7XskU!lX@2vMu-|EH+XXp& zlr+y@xKvk5#`BQv?a$o}SqSFcYO8VJ9$_}xDIYfa<`;I(S)q!@sChdRw;Ezw& zPcL1k?3?-G9Y!*F&Q_^}4+j!EK87?U3{R;E?fT-)ergjIxAxJBwWAbi}zO(N*mq!0y*Z02|3uf!C9k=AEcE zk#?)JEXU7b{oT-9xbOaRXQN(z{C1|Dc1?;2dPmb8J%%E8Vek!8?koR-1Zb;nlcU2u1mNElT}~BctFOR3jTAP};)Nd}n}Bx6%xqNh zMqL2lzykdAZs(FejVZlmX=C&lYR_Qa`^s(BZjlfhWnSLbpvncwry~f+&RH z{Fw(mKEg-^W)7p52H_W)8l|%kgnvlCAOxTtg-`1B)e1r}(|$+vN3qgS@bmx z{{;oON?|4hh%oPKw|~-bed9qmn9fxd2GE17PCfdli6U@G7iYHUCZC&JG8GIXRa z?xp3M2~7HN#L;?kFSBX?;J0|kFK+7*IOQ^MLM0u+h{F@ij}J#PM^#fH=z^Q5QTMD* z1zWxQ54TK5VM(r_hqxS|7*O{s9w8>KeZE*0;=yl8h|+ zv^{A4;=KEfTPkmK3<)AHxUxL!5R;VjQ(^)fAsosEzN|*Mc0+@4&V`Fj1~?c63udo` zh4(>D*rvk35lBS?&wuy6xg@Wmi+{lue%AoX>@w%(7}1vh-}Ay9T9#Rp9r$rkf_Zoh z)G~kO@ZqegAJAqAUPnO|$5o`TL8veEY^#={k)I?$?Aa?(j|tj(u$x_BiQNydM~c zfhcOYx~8lswE_o}*wSKvp)rBzJtW91UH$(WyUMUAx2`QCA|MTdbPGs|0@5u4Dy5X9 zba%H%NK1#(-QA5eNJuwQBkj=r?NRZZ^Zxqy=XD7TGyBZb%Lc)L;&RNQ7i<9 z(-!nBP3IzCIy-&F)(~$^Jr_E8HyIfpGGVittx12znUA_9B~Yg7ONOlA{7v|I3c>#Z z;;L8WqE&cU9?9cNNUo=#T@GbR5smUtP$iNTM_ULSsd$T3lToM>$2|1p`7 zhm-(V>$BZALg@vzH-Brm${RrdAWC>RPC~_^u3iIxhZ`_<0dnSeniI1-cwR>|GXQq8 z#cxk~p8CD{xb;j(BB@a&Wea#SzeFebF~^U-7q!(%_a(1acNSC~&$5A9M2C4BMkGwK zd(P-|^n>^iSi7|>iU{ZZBTuvQpO$9op~(g^oN)mLtF7#&B%2X3OKYQ*Pj1Zo%jQHV z1`qI~Kqp2mEB7v5?~W*va42!&$~?tta)%!Ty}|Pu_Wul@pbc&Z^=Akv5$x{tc?()J z__kQh++sV}%*(mXK?DwIcOoMr$9Q$6+=`@ROC2L0Y#8WmIm_oZ+O6lk*&Qf7`w zFCRI@&$FZZWJz*qzk>c`9V&^gKLh7<4i#x~zLVPZ#RHF{-Nx9`mx#=za>-xHbmGXT&(3(%X z;3d({b`LFVX-=E=o@Yuas&E=9k~H7*+axI8hHs^;BAVomlr+z>wQyag%QifJ zrKFVS7Pk4wnLjC=+?q)@mga}|Wd1-AA?W_)fE|NABz!|8Gy{%ECoL-jYX)e^o%ORi zwekD3dl7T+G_<|Fy-^#f(Azpdn7a-*!lJZ}@}U`k^|U4W;syGrmlp!<%;RD}H9>}n zFb#}NWRv^Blh-Xp(fM%wrswFqE7nxf*|%{m!pHFlW0cr0f8XGbQJ{MXF@`*lO#s`1 zjZzb46zd#WNh7z5qZsL5G|y12*}RH@E5?LK)96UPMpCbAI-$aROUl~&XHJ&J7qhDV z!h+l*hpWrUFpAK;qFQW+%RT(`tfRsFqq#cr#iMy8o%8qJa&j6eED^+A^UNpD8%l~) zxJ~t!yDr$&2y<5=Wbm~+f>s44Z@0w!F%&K~Cp}52|1UoU4u? z4sFpYu9PN)O=Im+Ls>k#)e!<8-R-vOE`GI1DF2K|?^F+4>V^F){ZP~jIdh(#VBWk@ zRKGUt-0|u6`@)4zHF3;bs|U)<`ju+LuuG~PCub&DBTc6W2}_fiDQ+ zlJ(N?HcQ9Ec}yd03#$U3O>V9ff6|P3m3gRlbuUND4NU$-FSxhWAQ{{VCmSu!kdPf? z5sWLkTh42892+(+<=$t%t}cL=X2C@b3JGUm>3=BM98<^n{a`hpGU!W)toE(n2wJj{ z*K#Dyimx!r>3+AVwH`=3OU-ZM(mN??V&p1dzQ?bx8^Kz)n_3pNsKjpdgLXVyG#8DG zPsr#E13VtW%lnkki=1mIhfY&SUl|FzW^v>d_i^&gpWgS5(f=0-{I{>wNA^f?24Fl-tsF~hwy?ydk~nzfej4Q!dn{UeZXsXjL#pMcjjAT zkFqlP83Zp0J_r!F;_Bxd;5=Kft{I^_KX4{Vrw%_6G4JcO8Z<$|G-^VeO3%n(m<*2R za*bMDuzyF`jYu8mkAs6_>!L1ww&EHN-a1WO9AygN^Nee)wy$hlM%~Rpxl`uMgi}u2 zDGV{&cNOrtnjKrR(n^5qamp*;0Fy$M?e!LM_Jp%g$!c}E(d?is7=61@tH_@=#vndQF9~%uGR8KKWZ+AJRG4C1W`YXj+(X0yEy(-dfzhDNFG|% z^DwJmF0X1TaD}@twzbut&3TNDKVBoB)BtM;8%1$7wNK_2_&(&gH7Nz-2^#E7fqbv$ z3f@$`{N|@+N20|>C7X%(X`ehGH&pYzMcadZZoSikI}_-_PcoB2*OS@LKf>PEt9OT` zjW1Drj-a~$%Dw%RoDF&Jp%41T^Ge_pYa~U+Y^a#)16A&iL!gv;_7zB`_FZ2*3k%Q< z4!eO_(|GXf?RCjlBXDM7{}hkt1U<2+tlr@GruZiD5zOi5=c@Tm-{1s5;s3C0G&?d- z&hDxyUAlVyQvyTa(vfoPA}$S4qjq%h7A6TV>bESJ*M-_{NJbSIf>kfPUNUG^wgM;x zu_vm}dYbcnJiKb3xAQK1vU~kcv)FLQc0s7!IZFpVv>xK`5*T&XRG|^IK{pNskY~t$ z9e=UlU(M55fbBPNm&AE+xKiMC&sy=F*{`p<{%8&8N{voOZ{$iwxfevuEcPZm81h#;-VVz zZBBFDF&R4_f|}?qvNoM(BKn{iTJskIm=Zrs2vbL`H2eY2&B_mD3r`k@{nd}FEZ*;I zT#1d8U8Bujr?&zErFK0+1q0U-J=FT~ViM;>(XqaEK|g?04=fJ_$fLruPUbMQ$Ndb_ z(M)Za(jLHQoOM}l!u2bSL1&}>YL9!y#zA6fF4`fmmIOP z+=hzi`@qG`sG@nyfzTugCY?VQp^ycHBvsr(f+=8%F-K_+28$o1mV8sM*Bh;0Fg>aG zfPn#pL()7M?EJ*V#p&tkWv>(%mlUc@P>{4#4oKg&cF0Cv#1OufttMFWNoR}}=(^X1 z;g_afHyFa^h zxZx5}y|%XI*D*G>ac>Q{gSaV5DR51XM)52PS~E)vE?1@dkDGiHfO4Rp%*FRs2-;2I z&Df2LR&P~K9yFd;%_}bUvVw#xf}}K+%U)K-NSjJ!QbqAHt)o7Dy(dxIv){1Di_nyY z#0Uj1DQ0+%%=_Z)T>U z%WD6dNHkjM-BaR$QS~oQsO2@De8R{laskiZ_=R{6VF%_8XhA@nYcRQLc3oy1~KF?+~zJ6>M%6Cp<-lT&8 zc+HuO_WHoI06NNh6ZizR6>EE&}WQlhJsa4mVk5CZ#NBy~N zo&VX%?NfoZRRc*5y;)XJ!Sp98u0Uf8R}O=VujL^@N2+gt|ANLDrPqU%m6i42&4w34 z8q-(N=bVV=Y>IVZ)pq=ETRE|cza&$X5J2iI{C$~?E#=LzB*|$8MT8+yP-v$&2*8^q z3!FNd@NHDyL|ch^%@2&e zh6AJ*vd^@&vCXS575kpJs~S4uJAtrk9P>CA(!wTl7W4Q$hl3B&IYrEj(N|!+uO{c3 zv8=!u=_X#QU^$<)g7{7#!ij5-II-`_44`n(C~Leo51bd9EQxu){*UkS1;iwBAPI23 z-(0oMR)A{NT5Gp4^vcuERpOPLT*^t1%DnF*mm`rvoF{$2=g?MJ!s{!YmTcoA&ik3I zoR^Nrdt+_n_-g9YQ|lIjx}Flue=PVtS>Rie-Zp&x;IBPB#-)$ol;`Kq#dhWz;4p9@ z1=kCZpk2WEBGGWnL~yf5!6!U}f`j8Ozw^GK;Cilg@-U)K4(D{>V%N8i9~&GP#%YU1 z-P2i}`7t1@2r@W$LwQQ99D5>Xq(NiT5iMGtGm!&bU9v?xW7F1WW|C9nXh@@ny(NP> zAj<<{w#?uT?;d6r?dwKOM2ZOcXuuC!zIZ)n0G?Ylz?}j(t$LCSj@Woqz`0q|UJ}=m z747JO)0zf6QPx&w!#9d?Tu5GHK!M$5eBd3xLUK2m;e9%Q2Yu&q68CJ9&1xY^2ph$6Nbh=8q|SvcetHxpMJ~pebeQDvN>6 z{iP5i)4O&mMn;4oNlvB_8_Y@&KLZlMitdAI(98@vA)OmXf65R!(CC`(H82cc0xmR1GyDlVWdsQhQl}K-AISn| zkfRrnxsw3QbTDxXv>1F_)Ch)Pqydfdp5#~RhC|_(WZg)#2)5QNk~d<=0{Qsww_tBw zkWI%cTBFh6N`iK%aDcAney!@q0lINDo46^n?${C=14{jQTeGw_neN!-;JYXj6A4s1 zqHCXQc)mVa!dqr&p#*srPtG>Kef$(Y0@Yvc?vo&|lj;9nCP|3jvGMc!dLHZRM`9eO zBEV_;HcFQzbERY%eC0*Vd7fOOdt1#y5Un%l&e7>3^V@blb$^_i%j=q5cADl4?<+WE zOO%?Sk&HBTS9V*z13_x$X&Vg(V|6`OX5kNYyON)dFNuI@$_Djb#PEnOVHA^d=Dz81 zl^HTe`FfkdBI^_epj!F;eGCT!Jq32q*2QDC!20>{MKeG{U!#sE>~Ty#G{E>yFi(X2 z^$&`yDgho6ag^q*>SR@v{Vw@Z^R9t8JQOyfC&fQlVMqE2YB3NqS_)yZ!?c%59hdfP zRobr&xe_&-6dP^l{Hp`E-v^O?y(S8KDmLfpnwaGC9XBsMv4$dDkxl#4n#eAmK6q(>G!y@g!l`T zq`PZttqr^APxLkN6E2HW{@^$v_+e-%GW;iyo+zdSuKp93z=Sg0Zg#!w)=~Ny6~t~` zmt9I7?Xu}ZW0zt4?!k#qR4N>_8~%yXj;r4dp`mC9jFTJ*E@-@aC3kiLbPDkz2lR5uxs^XJnt}5->@8%FmHtyKygQs#Y=9B)G9$<@rS9Ux9oAY9wFWH&rZ&$#COKwE5+2KCgx#G0H`@aPoO1Rc>eNU zfN+A0hy`FjR*Qzrn6aC5)Tw92T#qXBvQ0uxD%|Ex7Xq<;_h+m+Kj9nfgcT&&PkrcVg58XaQCa}eX73Q) z_;#B~T`Fc@=N;-o<+;Y11y4>+fNzW0P3Z$Uby-;~V?z~{xb3qtyMSH3=Gk|mBW*h1nkY{aqU-OpLkw3C_w@4)16 z?3sxomn`yg-g&V4-L`mHryIKnVy?S(M?tIA?g9+u`A!{cME5s1UTY6^^5cf1L}=@l};W<5P8MfUJH8bnaN4DBF|Ti;F@{N)C~K}th~}$rQCC&~U+2Q!+u59HoW*}Ve3SST zgC6s9x79~-egYKPkHi7Pm<{9vKLSaJPiBW3?|GN733vB=9L62J!0@~X%}8n6m^h@% zm3S#KXsommv@O;A_Gxn5xV52Ze{9$irP~MJC7c&-ABFtg_&ejRj;HnRb_?BQ2FvWw zVS*E*9~JW~(EbTYvyMPRXrQgqY0Gd4#6`f%&Xl+Mm)IoNQ}Z2f% zMyD(RJ=q^2$#1}67WH1OUh}94^5$J$4o!AxzjvdrEicX3H2Dd2n+kP2oCZi)R zKb<*0k7Tc?~m{*CGitFm@Q*m?Gh`XRi5>PA4L3HGa&S%5r0P|a$g;6L}CP@Sk z(Q;J|&v`l9v?`lpz%A}~ry zN_O@14A;ItsJw9l-&;~l_?3;)$c6@Fn`Sy#?aG-Yyh4KgLAQ%%J?lozGfxS#-Qc+^ z#U3kvUu}JWJxET!@xXf65LkQx#uY!5*G(-&tyoiN4Uwz?xv| z3e2e6Vfg2jZ)w4Duco^LK#{`QDUE(|hNTf|UJ!Mm=H!{(=miXKYK#st6}F>Mq_>h! zjmBMMfV2fE678FCQq`U8;=o^5YqAo2mOSVxnZ@(xM43AoQ879;Nb%lIBh&{>ocXpyG7se^=#MOyWAq?`0MWrm4bxVEDcK+ zwgbZbV!R3KeAfN~u!rhA{gioCczLqsj7HM@aJ6pOsiW~JUO;LTh`tRzfLFtPdM&nAEFC|ynIY_gqe2zm z9;I#hQYXF~cNx+W$TbxDSqKo-KQB-equ@c;A;K2u^?5N=P&xU9Q3a-(m^V5}i*EbA z{$1#P9S=ELt>Q0$TuyaZZW6g^H&s3~EH^)ugiSU=$&fz!cvvo@`MMpTx<%vC*$EJc z5d|54wF$9)FyaA&0#@TOV8QzZh>LJUMBKY~A~TQA>_L(bvLBhf>=$b| zyO9T97Lu0{>x}8SRZNK8Ml*&%s!^sp&h|lADK3P!H}jWnAMCJV(@GRJac}XYc``u# z(rQWA&;9Yd+fj8yj15eU>#8Ih(+f|2?jap9B9Q$hO2K;;=mSV*(53%Huifs-N-`{i zS9CU-H9;>MA1+NzgmEF#+LgmpR1<}+jc>)unqe!9i`K6f(<8nbmnHyD)}WfIxxr;; zAaKJgEp=Y>x=rTYq9ruHDNsCZ)-_vy3&iaS z(g>W*aMS~bsiU=`gUtFsLI*rR%FGaGSH5CY`A>uc6c6wwnuk3QnY=rj>khMI>1cKQ z(nDB0mWd|rC!&?XmMI|!E5ye4p=gwURy(OLwPvb^ln<8(nAgWC{es%RwE@WQC=ts(vkkSVi7DDX&uurKhbF*b(XBPg8fxI#;r)x znL-bKe=YHn%Eok0QCj2cn!UvU$b5$*tBoMhgyKh}3TT@~`99LqASK)cEo~OYzp10O z^`5RjHqU!2ibMDxPz_Q;tv{RLk9-q^fjZAs#W@%O8;WjVc)4(W(w7P|p zR+eik3{VU<8$2mH3X#l!dMQd9OD4dPLXO>OgkDhCf!5S7srra_;rbFOpl?PaEAa1r zA(#9R!DeuN;yX*#^LM=GZ^l#fe`LisPGfLKw~+obD8T<{TRnu6(#iDnuxP8+{>ipQ zzSrHW58t{r(6ks6T7EC$(H+jQ8l^mtftsFZSLivsN?vRMpgXYzwSU#MEM~wZel4UzI#E&S``fZ zbu9x^g-406d`+E@=j@tB%4ik;@D`^u!2N1w(Z?^Ftc}oAw5TUnE7o!IXeHlsW6N*! z+1jqTsxK*G8qAjJugu`rZyGH248k?~w8n8K&9-B2x+>ezJ&~PHIwaGtW5jj>BQf`1E6eK_#lVbPN&WKO-WNtHMbxqC zMSzdPE9=~-GY!fbcy)XW6ygm<8{o16 zfBy$p;l=?rZ?`=mE{I6x=Lo`~E;8Z-v8c`_hx_bUvhw2v6OYI_SDvgsk7d8@GinKL znm?Z#{1P{m7b0wIj~%`l-J(OJHhM9+v1_J0xnTXDR0A-%B0uBAl)l0)4v9xzGa7H@ zv2IQDsmp@!R;8W~nT#d@{n}gZ>jP~D@P^RJ@D+Oo*-+24S~aJD?E>d$F^ed)ZYrac z716>bL*DbA+w;3`pFb0Z?`#-$I&y#Pw8mKdO9TpkZHb;2&_@(HKGF}B&Eg48?o=iN zzOwAW<+t5JwN#aVGBSQ$1IZztIAUg&Uvfk%x^OnU6tuSUNbyS!?}FTDSX3Pr{p<&! zp^z!#Yr~B4IM15?%06`P$Pyv+ZZE1VcXL;<<5ymEDRA_r+1-a8+>mmH#_td$>;G88 zCVc*OAn~TcK;zJq+u>hs8z~B$sIDyMQCU(u+tu6K23zUfP~3RiSX#NuFn3zzy-Vc<+6gN=V+*`sUIdPALV6yk7*HRL)fJ@Q4IJG2mZinKg6n$#fmh9c&axdG z5}W8C4~1hPI#b+i9kfPc!1I_Ps%QosU;rt4EjYAg5-Qq;bDIy)UtDXc25}I4(JIA) zi&C03P?aypl;2HhVE~_q=j%utQ0gOV6CP!C6g3oj(XwYhEmUt>e6;}P0-=VEvm-;; zjMwT*a3z?=W=ule1Od6kL0w98Zq?X{UF*i`76ci-SQz}wSSheM`o5t*ZMIob~ zm61Wo&)@J!o@?@c_Y|ef(QiePvGqlVB61`_8=N&%yorjy zaFaWFiNRd9Q!CrscKugf71WdXAh8Z3ZcJzLzrrO*Kwuzc9CdhjIH0g*^a_BGtx4Wr zhoVTl(5R+y<^Q2u`c-M3BBWuDl}HGeI>RY%UZ`fP<$x6YK(pa?NE|_4Tevh5W|s_G z^5K2GA7?^E&-GN3JT!TiD76!QeK!Y!oBQ7IXo&ph%gYmkknpD`4xg-hQ0$^NXH9_^ z!gYVhK)K4CKUeK_kH?hD!Y(yN8(6byv)!ZO#79FaS+2`C-v4%`eRfE?>)7y2vGEC! zQ?q+4_ntD%{rh6|zIW>ogOFRZk4KpsNo$J73WDC90N&))7|DUC`N0u+Ta%fnSP{v$ z0Y5SRzgZ!_CpDl6vVG7N@IK2;vC)z9etPbbuZyC45u(}}Lt7csNO}Z@V%-QG+7e4+ zMBKsQ1(xNVe;qYBCavOaBKsEtI?`GdIY&3Tc9*urEn45m2-%IE$+T&xAoVUh%$1TQ z>>xn^B7hnhEw!I_!=ehtq?0QV1FyM%@$j&SRVlmh18bYA@37uWuf|E0GrWbLQ+XC( zRYU;Bs{yz|Bu{{n8i9O3V2}OsVh3~gcnOn!N$8D8L$sA;QO)XoTj>`qga(NLrg~TS zf#Oag*z^!=;*_o;n$05;`Hvcw>*TOav zx%#VsSzt8!>lTGKQy^~U{cVT$W}^%K-gd_=fcM)xEcEsdY*_$7q0JJnfV|j zZ$4e+Zlp@mDdhi9K(V$UNYtRkSl+9^^F|wbTiNQqPY7p0f(&~+N{SY8n2sRqm2#9_ zQ2R8tLTsRx9XHz&AELURXBN+QyK5fac)EEW1V;co2PgE_iCwVT07?gm9xJE2s5r;@GgGcl>t|hGybM4>L{@@e@MqBQRV7C78)>^m69e#1;x+HaB zGMfdJ%Hqlg`)?BIUnM<88~wM&0x(?_nq$iil<#`eKJBm94w8QVuplOWD2*}->{`Tv zVJg$HO_J*E$*z9eQA{p+JqBifT3B#L0iOoe7M`~USMJ9s`eav1_2)2RxHG|%gL2$A zGiWHy)kkv@a7ERkCC~co*8?s!A7BqCPbykt@1qA~Z6D}f7JUvro-NYU+~59;&<$yo zZ}Q|$<~vc$LhKD#9}#QGAHS)&O@3hiB{C5mH1?x)K~euY{NR90qdc23I1y2G|5O%9 z5lVU6*#164n)(j^haQ3*Pltoj!P4aL7Exd8|MciWF$93FHNuSZoY`w+wNH4R%4S}h z4OI5g;oVT6&0v-e1>&#tqSy z(*xo+GwDel8X+Jlhm$8V;M0g$uu@c-EPA7kNGj11pi3?oy2!MX5w((&Oxv*3 z-oJwwg_&{rd76r6J=Pwh@8ZzAWi?2-<3F-!+2jkvWobjOE08OBgy|)+W#F)r)FkAd zPmSrfHap~o8u&DITh8w8 zGR{>9=Je_v<1>VBO~;1SnmCHB@Y;9Tn|N$^dcF9iQS&;)^+)3}ZE~}b>Bs9@k03R;YGO5wI;~ZdPM>$Y>E^BPMT=cedZya3o4i{nIO)CU(w=fPZ21#7 zETUQkR>}kWn=s6*#dfP1Cx1c@J{s@a|I;e}1cpB5V2Yoo_BF{di!(SG-#y=NQg17x z7bX*4@w=V{e|M$XnxNW~lo)(f^fP;iNtA))3`jUR9xJmIjp&S{ePrwT;coo0s{TTf zUO2}k8)a4Jih_R9$=APAs|rN<*_J411M2ScB!Smk2g4bHOZ^@f#3v`W*b@5Ju^1IX z;@?w;JYf=9iOq?y>g~T0Bd499p-#)vuR%Lwze=GizVcrzR%Hg@?j*I=-uRx6VYwTd z!f@Bgp3RZ1^UcEj|nylj;2_Db(cZTmq|C#B}AX}Y8U zEj>asZJm&D^_ah73O(jDBc{y-Ab0ksPBgmlx?f#5+yiiM!91bT6d*NZtF*VbE7!2Y z_QVWtkv<0|WT~~aMD9)Gpu^%Zv}$`XQ)|bVo144v({aIaMDUeMThX?f^fDhKkV5sY zh=8v(V>L08$Q1NF)DczDX4Iu*6lmoMX6(#eY?Cp?uD0-+B0-45s_Z>`L9F#)Y2iVf zn`tl}Z?xIBk6U*pMjb?(Lz9PIoxw29)aB*h0UM-Lz!mJip*f?yWf)8v6BWg9)D6QX zCl3t>@C|)!vYA&K~9 z7$~-~>oNfs24TRAE`$7SCkK&_U3>Z`^zobwUqVp!)zUF5#LbmCs&*=hewa3`IF69T z82$*{r&c|s>U`?pR??pGcCf{=@Ct>)$PK&ha?M%BWo>F_@#UtMr=614$ALu8j71GeRQ3k1V{HTB6!9a28}4I!+`( l?-XYtuhCHEQCzq}cu3ja|1mqj><0Lf6n`mJD5CZ5{{Z*)O~L>G literal 0 HcmV?d00001 From 97c46f383cbc469e4f312df5440bae6dcd76bdd4 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 23 May 2020 17:20:50 +0800 Subject: [PATCH 017/562] implement external efield in fix/dplr --- source/lmp/fix_dplr.cpp | 31 ++++++++++++++++++++++++++++++- source/lmp/fix_dplr.h | 1 + 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/source/lmp/fix_dplr.cpp b/source/lmp/fix_dplr.cpp index c0f0bb930c..1119383129 100644 --- a/source/lmp/fix_dplr.cpp +++ b/source/lmp/fix_dplr.cpp @@ -34,7 +34,7 @@ is_key (const string& input) FixDPLR::FixDPLR(LAMMPS *lmp, int narg, char **arg) - :Fix(lmp, narg, arg) + :Fix(lmp, narg, arg), efield(3, 0.0) { virial_flag = 1; @@ -54,6 +54,13 @@ FixDPLR::FixDPLR(LAMMPS *lmp, int narg, char **arg) model = string(arg[iarg+1]); iarg += 2; } + if (string(arg[iarg]) == string("efield")) { + if (iarg+3 > narg) error->all(FLERR,"Illegal fix adapt command, efield should be provided 3 float numbers"); + efield[0] = atof(arg[iarg+1]); + efield[1] = atof(arg[iarg+2]); + efield[2] = atof(arg[iarg+3]); + iarg += 4; + } if (string(arg[iarg]) == string("type_associate")) { int iend = iarg+1; while (iend < narg && (! is_key(arg[iend]) )) { @@ -347,6 +354,7 @@ void FixDPLR::post_force(int vflag) int nall = nlocal + nghost; vector dcoord(nall*3, 0.0), dbox(9, 0.0), dfele(nlocal*3, 0.0); vector dtype(nall, 0); + // set values for dcoord, dbox, dfele { int *type = atom->type; for (int ii = 0; ii < nall; ++ii){ @@ -366,9 +374,30 @@ void FixDPLR::post_force(int vflag) } } assert(dfele_.size() == nlocal * 3); + // revise force according to efield for (int ii = 0; ii < nlocal*3; ++ii){ dfele[ii] = dfele_[ii]; } + // revise force and virial according to efield + double * q = atom->q; + imageint *image = atom->image; + double unwrap[3]; + double v[6]; + for (int ii = 0; ii < nlocal; ++ii){ + for (int dd = 0; dd < 3; ++dd){ + dfele[ii*3+dd] += q[ii] * efield[dd]; + } + domain->unmap(x[ii],image[ii],unwrap); + if (evflag) { + v[0] = q[ii] * efield[0] *unwrap[0]; + v[1] = q[ii] * efield[1] *unwrap[1]; + v[2] = q[ii] * efield[2] *unwrap[2]; + v[3] = q[ii] * efield[0] *unwrap[1]; + v[4] = q[ii] * efield[0] *unwrap[2]; + v[5] = q[ii] * efield[1] *unwrap[2]; + v_tally(ii, v); + } + } } // lmp nlist NeighList * list = pair_nnp->list; diff --git a/source/lmp/fix_dplr.h b/source/lmp/fix_dplr.h index edc9204874..094b0aa3e1 100644 --- a/source/lmp/fix_dplr.h +++ b/source/lmp/fix_dplr.h @@ -45,6 +45,7 @@ namespace LAMMPS_NS { map bk_type_asso; vector dipole_recd; vector dfcorr_buff; + vector efield; void get_valid_pairs(vector >& pairs); }; } From 62ecff64dd82a20e2ea979cbb86c5905e765530f Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 30 Dec 2020 15:59:50 +0800 Subject: [PATCH 018/562] refactorize the embedding net --- source/train/DescrptSeA.py | 135 ++++------------------------------ source/train/DescrptSeAEbd.py | 41 +++-------- source/train/DescrptSeR.py | 41 +++-------- source/train/Network.py | 71 ++++++++++++++++++ 4 files changed, 108 insertions(+), 180 deletions(-) diff --git a/source/train/DescrptSeA.py b/source/train/DescrptSeA.py index 08b8623a43..3fed6db202 100644 --- a/source/train/DescrptSeA.py +++ b/source/train/DescrptSeA.py @@ -5,6 +5,7 @@ from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module from deepmd.env import default_tf_session_config +from deepmd.Network import embedding_net class DescrptSeA (): def __init__ (self, jdata): @@ -362,40 +363,22 @@ def _filter(self, [-1, self.sel_a[type_i]* 4] ) start_index += self.sel_a[type_i] shape_i = inputs_i.get_shape().as_list() - # with (natom x nei_type_i) x 4 + # with (natom x nei_type_i) x 4 inputs_reshape = tf.reshape(inputs_i, [-1, 4]) + # with (natom x nei_type_i) x 1 xyz_scatter = tf.reshape(tf.slice(inputs_reshape, [0,0],[-1,1]),[-1,1]) + # with (natom x nei_type_i) x out_size if (type_input, type_i) not in self.exclude_types: - for ii in range(1, len(outputs_size)): - w = tf.get_variable('matrix_'+str(ii)+'_'+str(type_i), - [outputs_size[ii - 1], outputs_size[ii]], - self.filter_precision, - tf.random_normal_initializer(stddev=stddev/np.sqrt(outputs_size[ii]+outputs_size[ii-1]), seed = seed), - trainable = trainable) - b = tf.get_variable('bias_'+str(ii)+'_'+str(type_i), - [1, outputs_size[ii]], - self.filter_precision, - tf.random_normal_initializer(stddev=stddev, mean = bavg, seed = seed), - trainable = trainable) - hidden = tf.reshape(activation_fn(tf.matmul(xyz_scatter, w) + b), [-1, outputs_size[ii]]) - if self.filter_resnet_dt : - idt = tf.get_variable('idt_'+str(ii)+'_'+str(type_i), - [1, outputs_size[ii]], - self.filter_precision, - tf.random_normal_initializer(stddev=0.001, mean = 1.0, seed = seed), - trainable = trainable) - if outputs_size[ii] == outputs_size[ii-1]: - if self.filter_resnet_dt : - xyz_scatter += hidden * idt - else : - xyz_scatter += hidden - elif outputs_size[ii] == outputs_size[ii-1] * 2: - if self.filter_resnet_dt : - xyz_scatter = tf.concat([xyz_scatter,xyz_scatter], 1) + hidden * idt - else : - xyz_scatter = tf.concat([xyz_scatter,xyz_scatter], 1) + hidden - else: - xyz_scatter = hidden + xyz_scatter = embedding_net(xyz_scatter, + self.filter_neuron, + self.filter_precision, + activation_fn = activation_fn, + resnet_dt = self.filter_resnet_dt, + name_suffix = "_"+str(type_i), + stddev = stddev, + bavg = bavg, + seed = seed, + trainable = trainable) else: w = tf.zeros((outputs_size[0], outputs_size[-1]), dtype=global_tf_float_precision) xyz_scatter = tf.matmul(xyz_scatter, w) @@ -429,93 +412,3 @@ def _filter(self, return result, qmat - def _filter_type_ext(self, - inputs, - natoms, - activation_fn=tf.nn.tanh, - stddev=1.0, - bavg=0.0, - name='linear', - reuse=None, - seed=None, - trainable = True): - # natom x (nei x 4) - outputs_size = [1] + self.filter_neuron - outputs_size_2 = self.n_axis_neuron - with tf.variable_scope(name, reuse=reuse): - start_index = 0 - result_all = [] - xyz_scatter_1_all = [] - xyz_scatter_2_all = [] - for type_i in range(self.ntypes): - # cut-out inputs - # with natom x (nei_type_i x 4) - inputs_i = tf.slice (inputs, - [ 0, start_index* 4], - [-1, self.sel_a[type_i]* 4] ) - start_index += self.sel_a[type_i] - shape_i = inputs_i.get_shape().as_list() - # with (natom x nei_type_i) x 4 - inputs_reshape = tf.reshape(inputs_i, [-1, 4]) - xyz_scatter = tf.reshape(tf.slice(inputs_reshape, [0,0],[-1,1]),[-1,1]) - for ii in range(1, len(outputs_size)): - w = tf.get_variable('matrix_'+str(ii)+'_'+str(type_i), - [outputs_size[ii - 1], outputs_size[ii]], - self.filter_precision, - tf.random_normal_initializer(stddev=stddev/np.sqrt(outputs_size[ii]+outputs_size[ii-1]), seed = seed), - trainable = trainable) - b = tf.get_variable('bias_'+str(ii)+'_'+str(type_i), - [1, outputs_size[ii]], - self.filter_precision, - tf.random_normal_initializer(stddev=stddev, mean = bavg, seed = seed), - trainable = trainable) - hidden = tf.reshape(activation_fn(tf.matmul(xyz_scatter, w) + b), [-1, outputs_size[ii]]) - if self.filter_resnet_dt : - idt = tf.get_variable('idt_'+str(ii)+'_'+str(type_i), - [1, outputs_size[ii]], - self.filter_precision, - tf.random_normal_initializer(stddev=0.001, mean = 1.0, seed = seed), - trainable = trainable) - if outputs_size[ii] == outputs_size[ii-1]: - if self.filter_resnet_dt : - xyz_scatter += hidden * idt - else : - xyz_scatter += hidden - elif outputs_size[ii] == outputs_size[ii-1] * 2: - if self.filter_resnet_dt : - xyz_scatter = tf.concat([xyz_scatter,xyz_scatter], 1) + hidden * idt - else : - xyz_scatter = tf.concat([xyz_scatter,xyz_scatter], 1) + hidden - else: - xyz_scatter = hidden - # natom x nei_type_i x out_size - xyz_scatter = tf.reshape(xyz_scatter, (-1, shape_i[1]//4, outputs_size[-1])) - # natom x nei_type_i x 4 - inputs_i_reshape = tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]) - # natom x 4 x outputs_size - xyz_scatter_1 = tf.matmul(inputs_i_reshape, xyz_scatter, transpose_a = True) - xyz_scatter_1 = xyz_scatter_1 * (4.0 / shape_i[1]) - # natom x 4 x outputs_size_2 - xyz_scatter_2 = tf.slice(xyz_scatter_1, [0,0,0],[-1,-1,outputs_size_2]) - xyz_scatter_1_all.append(xyz_scatter_1) - xyz_scatter_2_all.append(xyz_scatter_2) - - # for type_i in range(self.ntypes): - # for type_j in range(type_i, self.ntypes): - # # natom x outputs_size x outputs_size_2 - # result = tf.matmul(xyz_scatter_1_all[type_i], xyz_scatter_2_all[type_j], transpose_a = True) - # # natom x (outputs_size x outputs_size_2) - # result = tf.reshape(result, [-1, outputs_size_2 * outputs_size[-1]]) - # result_all.append(tf.identity(result)) - xyz_scatter_2_coll = tf.concat(xyz_scatter_2_all, axis = 2) - for type_i in range(self.ntypes) : - # natom x outputs_size x (outputs_size_2 x ntypes) - result = tf.matmul(xyz_scatter_1_all[type_i], xyz_scatter_2_coll, transpose_a = True) - # natom x (outputs_size x outputs_size_2 x ntypes) - result = tf.reshape(result, [-1, outputs_size_2 * self.ntypes * outputs_size[-1]]) - result_all.append(tf.identity(result)) - - # natom x (ntypes x outputs_size x outputs_size_2 x ntypes) - result_all = tf.concat(result_all, axis = 1) - - return result_all diff --git a/source/train/DescrptSeAEbd.py b/source/train/DescrptSeAEbd.py index 0d432b9bc0..bff7452576 100644 --- a/source/train/DescrptSeAEbd.py +++ b/source/train/DescrptSeAEbd.py @@ -7,6 +7,7 @@ from deepmd.env import op_module from deepmd.env import default_tf_session_config from deepmd.DescrptSeA import DescrptSeA +from deepmd.Network import embedding_net class DescrptSeAEbd (DescrptSeA): def __init__ (self, jdata): @@ -105,36 +106,18 @@ def _embedding_net(self, shape_i = inputs_i.get_shape().as_list() # with (natom x nei) x 4 inputs_reshape = tf.reshape(inputs_i, [-1, 4]) + # with (natom x nei) x 1 xyz_scatter = tf.reshape(tf.slice(inputs_reshape, [0,0],[-1,1]),[-1,1]) - for ii in range(1, len(outputs_size)): - w = tf.get_variable('matrix_'+str(ii), - [outputs_size[ii - 1], outputs_size[ii]], - self.filter_precision, - tf.random_normal_initializer(stddev=stddev/np.sqrt(outputs_size[ii]+outputs_size[ii-1]), seed = seed), - trainable = trainable) - b = tf.get_variable('bias_'+str(ii), - [1, outputs_size[ii]], - self.filter_precision, - tf.random_normal_initializer(stddev=stddev, mean = bavg, seed = seed), - trainable = trainable) - if self.filter_resnet_dt : - idt = tf.get_variable('idt_'+str(ii), - [1, outputs_size[ii]], - self.filter_precision, - tf.random_normal_initializer(stddev=0.001, mean = 1.0, seed = seed), - trainable = trainable) - if outputs_size[ii] == outputs_size[ii-1]: - if self.filter_resnet_dt : - xyz_scatter += activation_fn(tf.matmul(xyz_scatter, w) + b) * idt - else : - xyz_scatter += activation_fn(tf.matmul(xyz_scatter, w) + b) - elif outputs_size[ii] == outputs_size[ii-1] * 2: - if self.filter_resnet_dt : - xyz_scatter = tf.concat([xyz_scatter,xyz_scatter], 1) + activation_fn(tf.matmul(xyz_scatter, w) + b) * idt - else : - xyz_scatter = tf.concat([xyz_scatter,xyz_scatter], 1) + activation_fn(tf.matmul(xyz_scatter, w) + b) - else: - xyz_scatter = activation_fn(tf.matmul(xyz_scatter, w) + b) + # with (natom x nei) x out_size + xyz_scatter = embedding_net(xyz_scatter, + self.filter_neuron, + self.filter_precision, + activation_fn = activation_fn, + resnet_dt = self.filter_resnet_dt, + stddev = stddev, + bavg = bavg, + seed = seed, + trainable = trainable) # natom x nei x out_size xyz_scatter = tf.reshape(xyz_scatter, (-1, shape_i[1]//4, outputs_size[-1])) xyz_scatter_total.append(xyz_scatter) diff --git a/source/train/DescrptSeR.py b/source/train/DescrptSeR.py index 451eef0f30..7e799ba7c7 100644 --- a/source/train/DescrptSeR.py +++ b/source/train/DescrptSeR.py @@ -5,6 +5,7 @@ from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module from deepmd.env import default_tf_session_config +from deepmd.Network import embedding_net class DescrptSeR (): def __init__ (self, jdata): @@ -309,36 +310,16 @@ def _filter_r(self, # with (natom x nei_type_i) x 1 xyz_scatter = tf.reshape(inputs_i, [-1, 1]) if (type_input, type_i) not in self.exclude_types: - for ii in range(1, len(outputs_size)): - w = tf.get_variable('matrix_'+str(ii)+'_'+str(type_i), - [outputs_size[ii - 1], outputs_size[ii]], - self.filter_precision, - tf.random_normal_initializer(stddev=stddev/np.sqrt(outputs_size[ii]+outputs_size[ii-1]), seed = seed), - trainable = trainable) - b = tf.get_variable('bias_'+str(ii)+'_'+str(type_i), - [1, outputs_size[ii]], - self.filter_precision, - tf.random_normal_initializer(stddev=stddev, mean = bavg, seed = seed), - trainable = trainable) - hidden = tf.reshape(activation_fn(tf.matmul(xyz_scatter, w) + b), [-1, outputs_size[ii]]) - if self.filter_resnet_dt : - idt = tf.get_variable('idt_'+str(ii)+'_'+str(type_i), - [1, outputs_size[ii]], - self.filter_precision, - tf.random_normal_initializer(stddev=0.001, mean = 1.0, seed = seed), - trainable = trainable) - if outputs_size[ii] == outputs_size[ii-1]: - if self.filter_resnet_dt : - xyz_scatter += hidden * idt - else : - xyz_scatter += hidden - elif outputs_size[ii] == outputs_size[ii-1] * 2: - if self.filter_resnet_dt : - xyz_scatter = tf.concat([xyz_scatter,xyz_scatter], 1) + hidden * idt - else : - xyz_scatter = tf.concat([xyz_scatter,xyz_scatter], 1) + hidden - else: - xyz_scatter = hidden + xyz_scatter = embedding_net(xyz_scatter, + self.filter_neuron, + self.filter_precision, + activation_fn = activation_fn, + resnet_dt = self.filter_resnet_dt, + name_suffix = "_"+str(type_i), + stddev = stddev, + bavg = bavg, + seed = seed, + trainable = trainable) else: w = tf.zeros((outputs_size[0], outputs_size[-1]), dtype=global_tf_float_precision) xyz_scatter = tf.matmul(xyz_scatter, w) diff --git a/source/train/Network.py b/source/train/Network.py index 1afa83bd1c..7685b8d215 100644 --- a/source/train/Network.py +++ b/source/train/Network.py @@ -50,3 +50,74 @@ def one_layer(inputs, # return self._batch_norm(hidden, name=name+'_normalization', reuse=reuse) else: return hidden + + + +def embedding_net(xx, + network_size, + precision, + activation_fn = tf.nn.tanh, + resnet_dt = False, + name_suffix = '', + stddev = 1.0, + bavg = 0.0, + seed = None, + trainable = True): + """ + Parameters + ---------- + xx : Tensor + Input tensor of shape [-1,1] + network_size: list of int + Size of the embedding network. For example [16,32,64] + precision: + Precision of network weights. For example, tf.float64 + activation_fn: + Activation function + resnet_dt: boolean + Using time-step in the ResNet construction + name_suffix: str + The name suffix append to each variable. + stddev: float + Standard deviation of initializing network parameters + bavg: float + Mean of network intial bias + seed: int + Random seed for initializing network parameters + trainable: boolean + If the netowk is trainable + """ + outputs_size = [1] + network_size + + for ii in range(1, len(outputs_size)): + w = tf.get_variable('matrix_'+str(ii)+name_suffix, + [outputs_size[ii - 1], outputs_size[ii]], + precision, + tf.random_normal_initializer(stddev=stddev/np.sqrt(outputs_size[ii]+outputs_size[ii-1]), seed = seed), + trainable = trainable) + b = tf.get_variable('bias_'+str(ii)+name_suffix, + [1, outputs_size[ii]], + precision, + tf.random_normal_initializer(stddev=stddev, mean = bavg, seed = seed), + trainable = trainable) + hidden = tf.reshape(activation_fn(tf.matmul(xx, w) + b), [-1, outputs_size[ii]]) + if resnet_dt : + idt = tf.get_variable('idt_'+str(ii)+name_suffix, + [1, outputs_size[ii]], + precision, + tf.random_normal_initializer(stddev=0.001, mean = 1.0, seed = seed), + trainable = trainable) + if outputs_size[ii] == outputs_size[ii-1]: + if resnet_dt : + xx += hidden * idt + else : + xx += hidden + elif outputs_size[ii] == outputs_size[ii-1] * 2: + if resnet_dt : + xx = tf.concat([xx,xx], 1) + hidden * idt + else : + xx = tf.concat([xx,xx], 1) + hidden + else: + xx = hidden + + return xx From c2c32c98041dd5d14f71e3040683947faee98c24 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 30 Dec 2020 17:16:30 +0800 Subject: [PATCH 019/562] first implementation of 3-body embedding --- source/train/DescrptSeAT.py | 394 ++++++++++++++++++++++++++++++++++++ source/train/Trainer.py | 3 + source/train/argcheck.py | 1 + 3 files changed, 398 insertions(+) create mode 100644 source/train/DescrptSeAT.py diff --git a/source/train/DescrptSeAT.py b/source/train/DescrptSeAT.py new file mode 100644 index 0000000000..b2b1d738d0 --- /dev/null +++ b/source/train/DescrptSeAT.py @@ -0,0 +1,394 @@ +import numpy as np +from deepmd.env import tf +from deepmd.common import ClassArg, get_activation_func, get_precision +from deepmd.RunOptions import global_tf_float_precision +from deepmd.RunOptions import global_np_float_precision +from deepmd.env import op_module +from deepmd.env import default_tf_session_config +from deepmd.Network import embedding_net + +class DescrptSeAT (): + def __init__ (self, jdata): + args = ClassArg()\ + .add('sel', list, must = True) \ + .add('rcut', float, default = 6.0) \ + .add('rcut_smth',float, default = 0.5) \ + .add('neuron', list, default = [10, 20, 40]) \ + .add('axis_neuron', int, default = 4, alias = 'n_axis_neuron') \ + .add('resnet_dt',bool, default = False) \ + .add('trainable',bool, default = True) \ + .add('seed', int) \ + .add('type_one_side', bool, default = False) \ + .add('exclude_types', list, default = []) \ + .add('set_davg_zero', bool, default = False) \ + .add('activation_function', str, default = 'tanh') \ + .add('precision', str, default = "default") + class_data = args.parse(jdata) + self.sel_a = class_data['sel'] + self.rcut_r = class_data['rcut'] + self.rcut_r_smth = class_data['rcut_smth'] + self.filter_neuron = class_data['neuron'] + self.n_axis_neuron = class_data['axis_neuron'] + self.filter_resnet_dt = class_data['resnet_dt'] + self.seed = class_data['seed'] + self.trainable = class_data['trainable'] + self.filter_activation_fn = get_activation_func(class_data['activation_function']) + self.filter_precision = get_precision(class_data['precision']) + exclude_types = class_data['exclude_types'] + self.exclude_types = set() + for tt in exclude_types: + assert(len(tt) == 2) + self.exclude_types.add((tt[0], tt[1])) + self.exclude_types.add((tt[1], tt[0])) + self.set_davg_zero = class_data['set_davg_zero'] + self.type_one_side = class_data['type_one_side'] + if self.type_one_side and len(exclude_types) != 0: + raise RuntimeError('"type_one_side" is not compatible with "exclude_types"') + + # descrpt config + self.sel_r = [ 0 for ii in range(len(self.sel_a)) ] + self.ntypes = len(self.sel_a) + assert(self.ntypes == len(self.sel_r)) + self.rcut_a = -1 + # numb of neighbors and numb of descrptors + self.nnei_a = np.cumsum(self.sel_a)[-1] + self.nnei_r = np.cumsum(self.sel_r)[-1] + self.nnei = self.nnei_a + self.nnei_r + self.ndescrpt_a = self.nnei_a * 4 + self.ndescrpt_r = self.nnei_r * 1 + self.ndescrpt = self.ndescrpt_a + self.ndescrpt_r + self.useBN = False + self.dstd = None + self.davg = None + + self.place_holders = {} + avg_zero = np.zeros([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) + std_ones = np.ones ([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) + sub_graph = tf.Graph() + with sub_graph.as_default(): + name_pfx = 'd_sea_' + for ii in ['coord', 'box']: + self.place_holders[ii] = tf.placeholder(global_np_float_precision, [None, None], name = name_pfx+'t_'+ii) + self.place_holders['type'] = tf.placeholder(tf.int32, [None, None], name=name_pfx+'t_type') + self.place_holders['natoms_vec'] = tf.placeholder(tf.int32, [self.ntypes+2], name=name_pfx+'t_natoms') + self.place_holders['default_mesh'] = tf.placeholder(tf.int32, [None], name=name_pfx+'t_mesh') + self.stat_descrpt, descrpt_deriv, rij, nlist \ + = op_module.descrpt_se_a(self.place_holders['coord'], + self.place_holders['type'], + self.place_holders['natoms_vec'], + self.place_holders['box'], + self.place_holders['default_mesh'], + tf.constant(avg_zero), + tf.constant(std_ones), + rcut_a = self.rcut_a, + rcut_r = self.rcut_r, + rcut_r_smth = self.rcut_r_smth, + sel_a = self.sel_a, + sel_r = self.sel_r) + self.sub_sess = tf.Session(graph = sub_graph, config=default_tf_session_config) + + + def get_rcut (self) : + return self.rcut_r + + def get_ntypes (self) : + return self.ntypes + + def get_dim_out (self) : + return self.filter_neuron[-1] + + def get_dim_rot_mat_1 (self) : + return self.filter_neuron[-1] + + def get_nlist (self) : + return self.nlist, self.rij, self.sel_a, self.sel_r + + def compute_input_stats (self, + data_coord, + data_box, + data_atype, + natoms_vec, + mesh, + input_dict) : + all_davg = [] + all_dstd = [] + if True: + sumr = [] + suma = [] + sumn = [] + sumr2 = [] + suma2 = [] + for cc,bb,tt,nn,mm in zip(data_coord,data_box,data_atype,natoms_vec,mesh) : + sysr,sysr2,sysa,sysa2,sysn \ + = self._compute_dstats_sys_smth(cc,bb,tt,nn,mm) + sumr.append(sysr) + suma.append(sysa) + sumn.append(sysn) + sumr2.append(sysr2) + suma2.append(sysa2) + sumr = np.sum(sumr, axis = 0) + suma = np.sum(suma, axis = 0) + sumn = np.sum(sumn, axis = 0) + sumr2 = np.sum(sumr2, axis = 0) + suma2 = np.sum(suma2, axis = 0) + for type_i in range(self.ntypes) : + davgunit = [sumr[type_i]/sumn[type_i], 0, 0, 0] + dstdunit = [self._compute_std(sumr2[type_i], sumr[type_i], sumn[type_i]), + self._compute_std(suma2[type_i], suma[type_i], sumn[type_i]), + self._compute_std(suma2[type_i], suma[type_i], sumn[type_i]), + self._compute_std(suma2[type_i], suma[type_i], sumn[type_i]) + ] + davg = np.tile(davgunit, self.ndescrpt // 4) + dstd = np.tile(dstdunit, self.ndescrpt // 4) + all_davg.append(davg) + all_dstd.append(dstd) + + if not self.set_davg_zero: + self.davg = np.array(all_davg) + self.dstd = np.array(all_dstd) + + + def build (self, + coord_, + atype_, + natoms, + box_, + mesh, + input_dict, + suffix = '', + reuse = None): + davg = self.davg + dstd = self.dstd + with tf.variable_scope('descrpt_attr' + suffix, reuse = reuse) : + if davg is None: + davg = np.zeros([self.ntypes, self.ndescrpt]) + if dstd is None: + dstd = np.ones ([self.ntypes, self.ndescrpt]) + t_rcut = tf.constant(np.max([self.rcut_r, self.rcut_a]), + name = 'rcut', + dtype = global_tf_float_precision) + t_ntypes = tf.constant(self.ntypes, + name = 'ntypes', + dtype = tf.int32) + t_ndescrpt = tf.constant(self.ndescrpt, + name = 'ndescrpt', + dtype = tf.int32) + t_sel = tf.constant(self.sel_a, + name = 'sel', + dtype = tf.int32) + self.t_avg = tf.get_variable('t_avg', + davg.shape, + dtype = global_tf_float_precision, + trainable = False, + initializer = tf.constant_initializer(davg)) + self.t_std = tf.get_variable('t_std', + dstd.shape, + dtype = global_tf_float_precision, + trainable = False, + initializer = tf.constant_initializer(dstd)) + + coord = tf.reshape (coord_, [-1, natoms[1] * 3]) + box = tf.reshape (box_, [-1, 9]) + atype = tf.reshape (atype_, [-1, natoms[1]]) + + self.descrpt, self.descrpt_deriv, self.rij, self.nlist \ + = op_module.descrpt_se_a (coord, + atype, + natoms, + box, + mesh, + self.t_avg, + self.t_std, + rcut_a = self.rcut_a, + rcut_r = self.rcut_r, + rcut_r_smth = self.rcut_r_smth, + sel_a = self.sel_a, + sel_r = self.sel_r) + + self.descrpt_reshape = tf.reshape(self.descrpt, [-1, self.ndescrpt]) + self.descrpt_reshape = tf.identity(self.descrpt_reshape, name = 'o_rmat') + self.descrpt_deriv = tf.identity(self.descrpt_deriv, name = 'o_rmat_deriv') + self.rij = tf.identity(self.rij, name = 'o_rij') + self.nlist = tf.identity(self.nlist, name = 'o_nlist') + + self.dout, self.qmat = self._pass_filter(self.descrpt_reshape, + atype, + natoms, + input_dict, + suffix = suffix, + reuse = reuse, + trainable = self.trainable) + + return self.dout + + + def get_rot_mat(self) : + return self.qmat + + + def prod_force_virial(self, atom_ener, natoms) : + [net_deriv] = tf.gradients (atom_ener, self.descrpt_reshape) + net_deriv_reshape = tf.reshape (net_deriv, [-1, natoms[0] * self.ndescrpt]) + force \ + = op_module.prod_force_se_a (net_deriv_reshape, + self.descrpt_deriv, + self.nlist, + natoms, + n_a_sel = self.nnei_a, + n_r_sel = self.nnei_r) + virial, atom_virial \ + = op_module.prod_virial_se_a (net_deriv_reshape, + self.descrpt_deriv, + self.rij, + self.nlist, + natoms, + n_a_sel = self.nnei_a, + n_r_sel = self.nnei_r) + return force, virial, atom_virial + + + def _pass_filter(self, + inputs, + atype, + natoms, + input_dict, + reuse = None, + suffix = '', + trainable = True) : + start_index = 0 + inputs = tf.reshape(inputs, [-1, self.ndescrpt * natoms[0]]) + output = [] + output_qmat = [] + inputs_i = inputs + inputs_i = tf.reshape(inputs_i, [-1, self.ndescrpt]) + type_i = -1 + layer, qmat = self._filter(tf.cast(inputs_i, self.filter_precision), type_i, name='filter_type_all'+suffix, natoms=natoms, reuse=reuse, seed = self.seed, trainable = trainable, activation_fn = self.filter_activation_fn) + layer = tf.reshape(layer, [tf.shape(inputs)[0], natoms[0] * self.get_dim_out()]) + # qmat = tf.reshape(qmat, [tf.shape(inputs)[0], natoms[0] * self.get_dim_rot_mat_1() * 3]) + output.append(layer) + # output_qmat.append(qmat) + output = tf.concat(output, axis = 1) + # output_qmat = tf.concat(output_qmat, axis = 1) + return output, None + + + def _compute_dstats_sys_smth (self, + data_coord, + data_box, + data_atype, + natoms_vec, + mesh) : + dd_all \ + = self.sub_sess.run(self.stat_descrpt, + feed_dict = { + self.place_holders['coord']: data_coord, + self.place_holders['type']: data_atype, + self.place_holders['natoms_vec']: natoms_vec, + self.place_holders['box']: data_box, + self.place_holders['default_mesh']: mesh, + }) + natoms = natoms_vec + dd_all = np.reshape(dd_all, [-1, self.ndescrpt * natoms[0]]) + start_index = 0 + sysr = [] + sysa = [] + sysn = [] + sysr2 = [] + sysa2 = [] + for type_i in range(self.ntypes): + end_index = start_index + self.ndescrpt * natoms[2+type_i] + dd = dd_all[:, start_index:end_index] + dd = np.reshape(dd, [-1, self.ndescrpt]) + start_index = end_index + # compute + dd = np.reshape (dd, [-1, 4]) + ddr = dd[:,:1] + dda = dd[:,1:] + sumr = np.sum(ddr) + suma = np.sum(dda) / 3. + sumn = dd.shape[0] + sumr2 = np.sum(np.multiply(ddr, ddr)) + suma2 = np.sum(np.multiply(dda, dda)) / 3. + sysr.append(sumr) + sysa.append(suma) + sysn.append(sumn) + sysr2.append(sumr2) + sysa2.append(suma2) + return sysr, sysr2, sysa, sysa2, sysn + + + def _compute_std (self,sumv2, sumv, sumn) : + val = np.sqrt(sumv2/sumn - np.multiply(sumv/sumn, sumv/sumn)) + if np.abs(val) < 1e-2: + val = 1e-2 + return val + + + def _filter(self, + inputs, + type_input, + natoms, + activation_fn=tf.nn.tanh, + stddev=1.0, + bavg=0.0, + name='linear', + reuse=None, + seed=None, + trainable = True): + # natom x (nei x 4) + shape = inputs.get_shape().as_list() + outputs_size = [1] + self.filter_neuron + outputs_size_2 = self.n_axis_neuron + with tf.variable_scope(name, reuse=reuse): + start_index_i = 0 + result = None + for type_i in range(self.ntypes): + # cut-out inputs + # with natom x (nei_type_i x 4) + inputs_i = tf.slice (inputs, + [ 0, start_index_i *4], + [-1, self.sel_a[type_i] *4] ) + start_index_i += self.sel_a[type_i] + nei_type_i = self.sel_a[type_i] + shape_i = inputs_i.get_shape().as_list() + assert(shape_i[1] == nei_type_i * 4) + # with natom x nei_type_i x 4 + env_i = tf.reshape(inputs_i, [-1, nei_type_i, 4]) + start_index_j = 0 + for type_j in range(self.ntypes): + # with natom x (nei_type_j x 4) + inputs_j = tf.slice (inputs, + [ 0, start_index_j *4], + [-1, self.sel_a[type_j] *4] ) + start_index_j += self.sel_a[type_j] + nei_type_j = self.sel_a[type_j] + shape_j = inputs_j.get_shape().as_list() + assert(shape_j[1] == nei_type_j * 4) + # with natom x nei_type_j x 4 + env_j = tf.reshape(inputs_j, [-1, nei_type_j, 4]) + # with natom x nei_type_i x nei_type_j + env_ij = tf.einsum('ijm,ikm->ijk', env_i, env_j) / 4.0 + # with (natom x nei_type_i x nei_type_j) + ebd_env_ij = tf.reshape(env_ij, [-1, 1]) + # with (natom x nei_type_i x nei_type_j) x out_size + ebd_env_ij = embedding_net(ebd_env_ij, + self.filter_neuron, + self.filter_precision, + activation_fn = activation_fn, + resnet_dt = self.filter_resnet_dt, + name_suffix = f"_{type_i}_{type_j}", + stddev = stddev, + bavg = bavg, + seed = seed, + trainable = trainable) + # with (natom x nei_type_i x nei_type_j) x out_size + ebd_env_ij = tf.reshape(ebd_env_ij, [-1, nei_type_i, nei_type_j, outputs_size[-1]]) + res_ij = tf.einsum('ijk,ijkm->im', env_ij, ebd_env_ij) + res_ij = res_ij * (1.0 / float(nei_type_i) / float(nei_type_j)) + if result is None: + result = res_ij + else: + result += res_ij + + return result, None + diff --git a/source/train/Trainer.py b/source/train/Trainer.py index 82d1dcf81e..ffeb9251bf 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -10,6 +10,7 @@ from deepmd.Fitting import EnerFitting, WFCFitting, PolarFittingLocFrame, PolarFittingSeA, GlobalPolarFittingSeA, DipoleFittingSeA from deepmd.DescrptLocFrame import DescrptLocFrame from deepmd.DescrptSeA import DescrptSeA +from deepmd.DescrptSeAT import DescrptSeAT from deepmd.DescrptSeAEbd import DescrptSeAEbd from deepmd.DescrptSeAEf import DescrptSeAEf from deepmd.DescrptSeR import DescrptSeR @@ -62,6 +63,8 @@ def _init_param(self, jdata): self.descrpt = DescrptLocFrame(descrpt_param) elif descrpt_type == 'se_a' : self.descrpt = DescrptSeA(descrpt_param) + elif descrpt_type == 'se_at' : + self.descrpt = DescrptSeAT(descrpt_param) elif descrpt_type == 'se_a_ebd' : self.descrpt = DescrptSeAEbd(descrpt_param) elif descrpt_type == 'se_a_ef' : diff --git a/source/train/argcheck.py b/source/train/argcheck.py index a6a8146ff4..7146a1bd4e 100644 --- a/source/train/argcheck.py +++ b/source/train/argcheck.py @@ -136,6 +136,7 @@ def descrpt_variant_type_args(): return Variant("type", [ Argument("loc_frame", dict, descrpt_local_frame_args()), Argument("se_a", dict, descrpt_se_a_args()), + Argument("se_at", dict, descrpt_se_a_args()), Argument("se_a_ebd", dict, descrpt_se_a_ebd_args()), Argument("se_r", dict, descrpt_se_r_args()), Argument("se_ar", dict, descrpt_se_ar_args()) From 6718206f73c26d795cab02cc260860b12f45ec8c Mon Sep 17 00:00:00 2001 From: Han Wang Date: Thu, 31 Dec 2020 08:01:57 +0800 Subject: [PATCH 020/562] consistent indent, fix bug --- source/train/DescrptSeAT.py | 99 ++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 50 deletions(-) diff --git a/source/train/DescrptSeAT.py b/source/train/DescrptSeAT.py index b2b1d738d0..b90d086ae5 100644 --- a/source/train/DescrptSeAT.py +++ b/source/train/DescrptSeAT.py @@ -340,55 +340,54 @@ def _filter(self, outputs_size = [1] + self.filter_neuron outputs_size_2 = self.n_axis_neuron with tf.variable_scope(name, reuse=reuse): - start_index_i = 0 - result = None - for type_i in range(self.ntypes): - # cut-out inputs - # with natom x (nei_type_i x 4) - inputs_i = tf.slice (inputs, - [ 0, start_index_i *4], - [-1, self.sel_a[type_i] *4] ) - start_index_i += self.sel_a[type_i] - nei_type_i = self.sel_a[type_i] - shape_i = inputs_i.get_shape().as_list() - assert(shape_i[1] == nei_type_i * 4) - # with natom x nei_type_i x 4 - env_i = tf.reshape(inputs_i, [-1, nei_type_i, 4]) - start_index_j = 0 - for type_j in range(self.ntypes): - # with natom x (nei_type_j x 4) - inputs_j = tf.slice (inputs, - [ 0, start_index_j *4], - [-1, self.sel_a[type_j] *4] ) - start_index_j += self.sel_a[type_j] - nei_type_j = self.sel_a[type_j] - shape_j = inputs_j.get_shape().as_list() - assert(shape_j[1] == nei_type_j * 4) - # with natom x nei_type_j x 4 - env_j = tf.reshape(inputs_j, [-1, nei_type_j, 4]) - # with natom x nei_type_i x nei_type_j - env_ij = tf.einsum('ijm,ikm->ijk', env_i, env_j) / 4.0 - # with (natom x nei_type_i x nei_type_j) - ebd_env_ij = tf.reshape(env_ij, [-1, 1]) - # with (natom x nei_type_i x nei_type_j) x out_size - ebd_env_ij = embedding_net(ebd_env_ij, - self.filter_neuron, - self.filter_precision, - activation_fn = activation_fn, - resnet_dt = self.filter_resnet_dt, - name_suffix = f"_{type_i}_{type_j}", - stddev = stddev, - bavg = bavg, - seed = seed, - trainable = trainable) - # with (natom x nei_type_i x nei_type_j) x out_size - ebd_env_ij = tf.reshape(ebd_env_ij, [-1, nei_type_i, nei_type_j, outputs_size[-1]]) - res_ij = tf.einsum('ijk,ijkm->im', env_ij, ebd_env_ij) - res_ij = res_ij * (1.0 / float(nei_type_i) / float(nei_type_j)) - if result is None: - result = res_ij - else: - result += res_ij - + start_index_i = 0 + result = None + for type_i in range(self.ntypes): + # cut-out inputs + # with natom x (nei_type_i x 4) + inputs_i = tf.slice (inputs, + [ 0, start_index_i *4], + [-1, self.sel_a[type_i] *4] ) + start_index_i += self.sel_a[type_i] + nei_type_i = self.sel_a[type_i] + shape_i = inputs_i.get_shape().as_list() + assert(shape_i[1] == nei_type_i * 4) + # with natom x nei_type_i x 4 + env_i = tf.reshape(inputs_i, [-1, nei_type_i, 4]) + start_index_j = 0 + for type_j in range(self.ntypes): + # with natom x (nei_type_j x 4) + inputs_j = tf.slice (inputs, + [ 0, start_index_j *4], + [-1, self.sel_a[type_j] *4] ) + start_index_j += self.sel_a[type_j] + nei_type_j = self.sel_a[type_j] + shape_j = inputs_j.get_shape().as_list() + assert(shape_j[1] == nei_type_j * 4) + # with natom x nei_type_j x 4 + env_j = tf.reshape(inputs_j, [-1, nei_type_j, 4]) + # with natom x nei_type_i x nei_type_j + env_ij = tf.einsum('ijm,ikm->ijk', env_i, env_j) / 4.0 + # with (natom x nei_type_i x nei_type_j) + ebd_env_ij = tf.reshape(env_ij, [-1, 1]) + # with (natom x nei_type_i x nei_type_j) x out_size + ebd_env_ij = embedding_net(ebd_env_ij, + self.filter_neuron, + self.filter_precision, + activation_fn = activation_fn, + resnet_dt = self.filter_resnet_dt, + name_suffix = f"_{type_i}_{type_j}", + stddev = stddev, + bavg = bavg, + seed = seed, + trainable = trainable) + # with (natom x nei_type_i x nei_type_j) x out_size + ebd_env_ij = tf.reshape(ebd_env_ij, [-1, nei_type_i, nei_type_j, outputs_size[-1]]) + res_ij = tf.einsum('ijk,ijkm->im', env_ij, ebd_env_ij) + res_ij = res_ij * (1.0 / float(nei_type_i) / float(nei_type_j)) + if result is None: + result = res_ij + else: + result += res_ij return result, None From 86cec4c98cea7316c168fe870ee015a67c813548 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Thu, 31 Dec 2020 09:21:59 +0800 Subject: [PATCH 021/562] clean up the code --- source/train/DescrptSeAT.py | 29 +++++++++++------------------ source/train/argcheck.py | 31 ++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/source/train/DescrptSeAT.py b/source/train/DescrptSeAT.py index b90d086ae5..fb5bc4efeb 100644 --- a/source/train/DescrptSeAT.py +++ b/source/train/DescrptSeAT.py @@ -14,11 +14,9 @@ def __init__ (self, jdata): .add('rcut', float, default = 6.0) \ .add('rcut_smth',float, default = 0.5) \ .add('neuron', list, default = [10, 20, 40]) \ - .add('axis_neuron', int, default = 4, alias = 'n_axis_neuron') \ .add('resnet_dt',bool, default = False) \ .add('trainable',bool, default = True) \ .add('seed', int) \ - .add('type_one_side', bool, default = False) \ .add('exclude_types', list, default = []) \ .add('set_davg_zero', bool, default = False) \ .add('activation_function', str, default = 'tanh') \ @@ -28,7 +26,6 @@ def __init__ (self, jdata): self.rcut_r = class_data['rcut'] self.rcut_r_smth = class_data['rcut_smth'] self.filter_neuron = class_data['neuron'] - self.n_axis_neuron = class_data['axis_neuron'] self.filter_resnet_dt = class_data['resnet_dt'] self.seed = class_data['seed'] self.trainable = class_data['trainable'] @@ -41,9 +38,6 @@ def __init__ (self, jdata): self.exclude_types.add((tt[0], tt[1])) self.exclude_types.add((tt[1], tt[0])) self.set_davg_zero = class_data['set_davg_zero'] - self.type_one_side = class_data['type_one_side'] - if self.type_one_side and len(exclude_types) != 0: - raise RuntimeError('"type_one_side" is not compatible with "exclude_types"') # descrpt config self.sel_r = [ 0 for ii in range(len(self.sel_a)) ] @@ -325,20 +319,19 @@ def _compute_std (self,sumv2, sumv, sumn) : def _filter(self, - inputs, - type_input, - natoms, - activation_fn=tf.nn.tanh, - stddev=1.0, - bavg=0.0, - name='linear', - reuse=None, - seed=None, + inputs, + type_input, + natoms, + activation_fn=tf.nn.tanh, + stddev=1.0, + bavg=0.0, + name='linear', + reuse=None, + seed=None, trainable = True): # natom x (nei x 4) shape = inputs.get_shape().as_list() outputs_size = [1] + self.filter_neuron - outputs_size_2 = self.n_axis_neuron with tf.variable_scope(name, reuse=reuse): start_index_i = 0 result = None @@ -381,13 +374,13 @@ def _filter(self, bavg = bavg, seed = seed, trainable = trainable) - # with (natom x nei_type_i x nei_type_j) x out_size + # with natom x nei_type_i x nei_type_j x out_size ebd_env_ij = tf.reshape(ebd_env_ij, [-1, nei_type_i, nei_type_j, outputs_size[-1]]) res_ij = tf.einsum('ijk,ijkm->im', env_ij, ebd_env_ij) res_ij = res_ij * (1.0 / float(nei_type_i) / float(nei_type_j)) if result is None: result = res_ij else: - result += res_ij + result += res_ij return result, None diff --git a/source/train/argcheck.py b/source/train/argcheck.py index 7146a1bd4e..694bb52171 100644 --- a/source/train/argcheck.py +++ b/source/train/argcheck.py @@ -72,6 +72,35 @@ def descrpt_se_a_args(): ] +def descrpt_se_a_args(): + doc_sel = 'A list of integers. The length of the list should be the same as the number of atom types in the system. `sel[i]` gives the selected number of type-i neighbors. `sel[i]` is recommended to be larger than the maximally possible number of type-i neighbors in the cut-off radius.' + doc_rcut = 'The cut-off radius.' + doc_rcut_smth = 'Where to start smoothing. For example the 1/r term is smoothed from `rcut` to `rcut_smth`' + doc_neuron = 'Number of neurons in each hidden layers of the embedding net. When two layers are of the same size or one layer is twice as large as the previous layer, a skip connection is built.' + doc_activation_function = f'The activation function in the embedding net. Supported activation functions are {list_to_doc(activation_fn_dict.keys())}' + doc_resnet_dt = 'Whether to use a "Timestep" in the skip connection' + doc_precision = f'The precision of the embedding net parameters, supported options are {supported_precision()}' + doc_trainable = 'If the parameters in the embedding net is trainable' + doc_seed = 'Random seed for parameter initialization' + doc_exclude_types = 'The Excluded types' + doc_set_davg_zero = 'Set the normalization average to zero. This option should be set when `atom_ener` in the energy fitting is used' + + return [ + Argument("sel", list, optional = False, doc = doc_sel), + Argument("rcut", float, optional = True, default = 6.0, doc = doc_rcut), + Argument("rcut_smth", float, optional = True, default = 0.5, doc = doc_rcut_smth), + Argument("neuron", list, optional = True, default = [10,20,40], doc = doc_neuron), + Argument("activation_function", str, optional = True, default = 'tanh', doc = doc_activation_function), + Argument("resnet_dt", bool, optional = True, default = False, doc = doc_resnet_dt), + Argument("precision", str, optional = True, default = "float64", doc = doc_precision), + Argument("trainable", bool, optional = True, default = True, doc = doc_trainable), + Argument("seed", [int,None], optional = True, doc = doc_seed), + Argument("exclude_types", list, optional = True, default = [], doc = doc_exclude_types), + Argument("set_davg_zero", bool, optional = True, default = False, doc = doc_set_davg_zero) + ] + + + def descrpt_se_a_ebd_args(): doc_type_nchanl = 'number of channels for type embedding' doc_type_nlayer = 'number of hidden layers of type embedding net' @@ -136,7 +165,7 @@ def descrpt_variant_type_args(): return Variant("type", [ Argument("loc_frame", dict, descrpt_local_frame_args()), Argument("se_a", dict, descrpt_se_a_args()), - Argument("se_at", dict, descrpt_se_a_args()), + Argument("se_at", dict, descrpt_se_at_args()), Argument("se_a_ebd", dict, descrpt_se_a_ebd_args()), Argument("se_r", dict, descrpt_se_r_args()), Argument("se_ar", dict, descrpt_se_ar_args()) From 9cc60ceba1deeb79abea2732273e9f7b33329ab1 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Thu, 31 Dec 2020 09:53:18 +0800 Subject: [PATCH 022/562] fix bug. improved angle embedding --- source/train/DescrptSeAT.py | 9 +++++++-- source/train/argcheck.py | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/source/train/DescrptSeAT.py b/source/train/DescrptSeAT.py index fb5bc4efeb..b73c9eca1e 100644 --- a/source/train/DescrptSeAT.py +++ b/source/train/DescrptSeAT.py @@ -347,8 +347,10 @@ def _filter(self, assert(shape_i[1] == nei_type_i * 4) # with natom x nei_type_i x 4 env_i = tf.reshape(inputs_i, [-1, nei_type_i, 4]) + # with natom x nei_type_i x 3 + env_i = tf.slice(env_i, [0, 0, 1], [-1, -1, -1]) start_index_j = 0 - for type_j in range(self.ntypes): + for type_j in range(type_i, self.ntypes): # with natom x (nei_type_j x 4) inputs_j = tf.slice (inputs, [ 0, start_index_j *4], @@ -359,8 +361,10 @@ def _filter(self, assert(shape_j[1] == nei_type_j * 4) # with natom x nei_type_j x 4 env_j = tf.reshape(inputs_j, [-1, nei_type_j, 4]) + # with natom x nei_type_i x 3 + env_j = tf.slice(env_j, [0, 0, 1], [-1, -1, -1]) # with natom x nei_type_i x nei_type_j - env_ij = tf.einsum('ijm,ikm->ijk', env_i, env_j) / 4.0 + env_ij = tf.einsum('ijm,ikm->ijk', env_i, env_j) # with (natom x nei_type_i x nei_type_j) ebd_env_ij = tf.reshape(env_ij, [-1, 1]) # with (natom x nei_type_i x nei_type_j) x out_size @@ -376,6 +380,7 @@ def _filter(self, trainable = trainable) # with natom x nei_type_i x nei_type_j x out_size ebd_env_ij = tf.reshape(ebd_env_ij, [-1, nei_type_i, nei_type_j, outputs_size[-1]]) + # with natom x out_size res_ij = tf.einsum('ijk,ijkm->im', env_ij, ebd_env_ij) res_ij = res_ij * (1.0 / float(nei_type_i) / float(nei_type_j)) if result is None: diff --git a/source/train/argcheck.py b/source/train/argcheck.py index 694bb52171..510567bf4e 100644 --- a/source/train/argcheck.py +++ b/source/train/argcheck.py @@ -72,7 +72,7 @@ def descrpt_se_a_args(): ] -def descrpt_se_a_args(): +def descrpt_se_at_args(): doc_sel = 'A list of integers. The length of the list should be the same as the number of atom types in the system. `sel[i]` gives the selected number of type-i neighbors. `sel[i]` is recommended to be larger than the maximally possible number of type-i neighbors in the cut-off radius.' doc_rcut = 'The cut-off radius.' doc_rcut_smth = 'Where to start smoothing. For example the 1/r term is smoothed from `rcut` to `rcut_smth`' From 573e6b3ca11c762b0c684f3404f31bc2d84082ce Mon Sep 17 00:00:00 2001 From: Han Wang Date: Thu, 31 Dec 2020 11:01:45 +0800 Subject: [PATCH 023/562] implement hybrid descrpt --- source/train/DescrptHybrid.py | 104 ++++++++++++++++++++++++++++++++++ source/train/Trainer.py | 3 + source/train/argcheck.py | 11 +++- 3 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 source/train/DescrptHybrid.py diff --git a/source/train/DescrptHybrid.py b/source/train/DescrptHybrid.py new file mode 100644 index 0000000000..e0544ad344 --- /dev/null +++ b/source/train/DescrptHybrid.py @@ -0,0 +1,104 @@ +import numpy as np +from deepmd.env import tf +from deepmd.common import ClassArg +from deepmd.env import op_module +from deepmd.DescrptLocFrame import DescrptLocFrame +from deepmd.DescrptSeA import DescrptSeA +from deepmd.DescrptSeAT import DescrptSeAT +from deepmd.DescrptSeAEbd import DescrptSeAEbd +from deepmd.DescrptSeAEf import DescrptSeAEf +from deepmd.DescrptSeR import DescrptSeR + +class DescrptHybrid (): + def __init__ (self, jdata): + args = ClassArg()\ + .add('list', list, must = True) + class_data = args.parse(jdata) + dict_list = class_data['list'] + self.numb_descrpt = len(dict_list) + self.descrpt_list = [] + self.descrpt_type = [] + for ii in dict_list: + this_type = ii.get('type') + if this_type == 'loc_frame': + this_descrpt = DescrptLocFrame(ii) + elif this_type == 'se_a' : + this_descrpt = DescrptSeA(ii) + elif this_type == 'se_at' : + this_descrpt = DescrptSeAT(ii) + elif this_type == 'se_a_ebd' : + this_descrpt = DescrptSeAEbd(ii) + elif this_type == 'se_a_ef' : + this_descrpt = DescrptSeAEf(ii) + elif this_type == 'se_r' : + this_descrpt = DescrptSeR(ii) + else : + raise RuntimeError('unknow model type ' + this_type) + self.descrpt_list.append(this_descrpt) + self.descrpt_type.append(this_type) + for ii in range(1, self.numb_descrpt): + assert(self.descrpt_list[ii].get_ntypes() == + self.descrpt_list[ 0].get_ntypes()), \ + f'number of atom types in {ii}th descrptor does not match others' + + + def get_rcut (self) : + all_rcut = [ii.get_rcut() for ii in self.descrpt_list] + return np.max(all_rcut) + + + def get_ntypes (self) : + return self.descrpt_list[0].get_ntypes() + + + def get_dim_out (self) : + all_dim_out = [ii.get_dim_out() for ii in self.descrpt_list] + return sum(all_dim_out) + + + def get_nlist_i(self, ii): + return self.descrpt_list[ii].nlist, self.descrpt_list[ii].rij, self.descrpt_list[ii].sel_a, self.descrpt_list[ii].sel_r + + + def compute_input_stats (self, + data_coord, + data_box, + data_atype, + natoms_vec, + mesh, + input_dict) : + for ii in self.descrpt_list: + ii.compute_input_stats(data_coord, data_box, data_atype, natoms_vec, mesh, input_dict) + + + def build (self, + coord_, + atype_, + natoms, + box, + mesh, + input_dict, + suffix = '', + reuse = None): + all_dout = [] + for tt,ii in zip(self.descrpt_type,self.descrpt_list): + dout = ii.build(coord_, atype_, natoms, box, mesh, input_dict, suffix=suffix+f'_{tt}', reuse=reuse) + dout = tf.reshape(dout, [-1, ii.get_dim_out()]) + all_dout.append(dout) + dout = tf.concat(all_dout, axis = 1) + dout = tf.reshape(dout, [-1, natoms[0] * self.get_dim_out()]) + return dout + + + def prod_force_virial(self, atom_ener, natoms) : + for idx,ii in enumerate(self.descrpt_list): + ff, vv, av = ii.prod_force_virial(atom_ener, natoms) + if idx == 0: + force = ff + virial = vv + atom_virial = av + else: + force += ff + virial += vv + atom_virial += av + return force, virial, atom_virial diff --git a/source/train/Trainer.py b/source/train/Trainer.py index ffeb9251bf..8a86f4871e 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -15,6 +15,7 @@ from deepmd.DescrptSeAEf import DescrptSeAEf from deepmd.DescrptSeR import DescrptSeR from deepmd.DescrptSeAR import DescrptSeAR +from deepmd.DescrptHybrid import DescrptHybrid from deepmd.Model import Model, WFCModel, DipoleModel, PolarModel, GlobalPolarModel from deepmd.Loss import EnerStdLoss, EnerDipoleLoss, TensorLoss from deepmd.LearningRate import LearningRateExp @@ -73,6 +74,8 @@ def _init_param(self, jdata): self.descrpt = DescrptSeR(descrpt_param) elif descrpt_type == 'se_ar' : self.descrpt = DescrptSeAR(descrpt_param) + elif descrpt_type == 'hybrid' : + self.descrpt = DescrptHybrid(descrpt_param) else : raise RuntimeError('unknow model type ' + descrpt_type) diff --git a/source/train/argcheck.py b/source/train/argcheck.py index 510567bf4e..9840611944 100644 --- a/source/train/argcheck.py +++ b/source/train/argcheck.py @@ -155,6 +155,14 @@ def descrpt_se_ar_args(): ] +def descrpt_hybrid_args(): + doc_list = f'A list of descriptor definitions' + + return [ + Argument("list", list, optional = False, doc = doc_list) + ] + + def descrpt_variant_type_args(): doc_descrpt_type = 'The type of the descritpor. Valid types are `loc_frame`, `se_a`, `se_r` and `se_ar`. \n\n\ - `loc_frame`: Defines a local frame at each atom, and the compute the descriptor as local coordinates under this frame.\n\n\ @@ -168,7 +176,8 @@ def descrpt_variant_type_args(): Argument("se_at", dict, descrpt_se_at_args()), Argument("se_a_ebd", dict, descrpt_se_a_ebd_args()), Argument("se_r", dict, descrpt_se_r_args()), - Argument("se_ar", dict, descrpt_se_ar_args()) + Argument("se_ar", dict, descrpt_se_ar_args()), + Argument("hybrid", dict, descrpt_hybrid_args()) ], doc = doc_descrpt_type) From d2c1153c579eeff970acadf5770a4157a2b7f0dc Mon Sep 17 00:00:00 2001 From: Han Wang Date: Thu, 31 Dec 2020 19:28:31 +0800 Subject: [PATCH 024/562] add unittest for embedding net --- source/tests/test_embedding_net.py | 110 +++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 source/tests/test_embedding_net.py diff --git a/source/tests/test_embedding_net.py b/source/tests/test_embedding_net.py new file mode 100644 index 0000000000..faa2e62055 --- /dev/null +++ b/source/tests/test_embedding_net.py @@ -0,0 +1,110 @@ +import os,sys +import numpy as np +import unittest + +from deepmd.env import tf +from tensorflow.python.framework import ops + +from deepmd.Network import embedding_net + +from deepmd.RunOptions import global_tf_float_precision +from deepmd.RunOptions import global_np_float_precision +from deepmd.RunOptions import global_ener_float_precision + +class Inter(unittest.TestCase): + def setUp (self) : + self.sess = tf.Session() + self.inputs = tf.constant([ 0., 1., 2.], dtype = tf.float64) + self.ndata = 3 + self.inputs = tf.reshape(self.inputs, [-1, 1]) + self.places = 6 + + def test_enlarger_net(self): + network_size = [3, 4] + out = embedding_net(self.inputs, + network_size, + tf.float64, + name_suffix = 'enlarger_net', + seed = 1) + self.sess.run(tf.global_variables_initializer()) + myout = self.sess.run(out) + refout = [[-0.1482171, -0.14177827, -0.76181204, 0.21266767], + [-0.27800543, -0.08974353, -0.78784335, 0.3485518 ], + [-0.36744368, -0.06285603, -0.80749876, 0.4347974 ]] + for ii in range(self.ndata): + for jj in range(network_size[-1]): + self.assertAlmostEqual(refout[ii][jj], myout[ii][jj], places = self.places) + + + def test_enlarger_net_1(self): + network_size = [4, 4] + out = embedding_net(self.inputs, + network_size, + tf.float64, + name_suffix = 'enlarger_net_1', + seed = 1) + self.sess.run(tf.global_variables_initializer()) + myout = self.sess.run(out) + refout = [[ 0.10842905, -0.61623145, -1.46738788, -0.01921788], + [ 0.09376136, -0.75526936, -1.64995884, 0.01076112], + [ 0.1033177, -0.8911794, -1.75530172, 0.00653156]] + for ii in range(self.ndata): + for jj in range(network_size[-1]): + self.assertAlmostEqual(refout[ii][jj], myout[ii][jj], places = self.places) + + def test_enlarger_net_1_idt(self): + network_size = [4, 4] + out = embedding_net(self.inputs, + network_size, + tf.float64, + name_suffix = 'enlarger_net_1_idt', + resnet_dt = True, + seed = 1) + self.sess.run(tf.global_variables_initializer()) + myout = self.sess.run(out) + refout = [[ 0.10839754, -0.6161336, -1.46673253, -0.01927138], + [ 0.09370214, -0.75516888, -1.64927868, 0.01067603], + [ 0.10323835, -0.89107102, -1.75460243, 0.00642493]] + for ii in range(self.ndata): + for jj in range(network_size[-1]): + self.assertAlmostEqual(refout[ii][jj], myout[ii][jj], places = self.places) + + def test_enlarger_net_2(self): + network_size = [2, 4] + out = embedding_net(self.inputs, + network_size, + tf.float64, + name_suffix = 'enlarger_net_2', + seed = 1) + self.sess.run(tf.global_variables_initializer()) + myout = self.sess.run(out) + refout = [[ 0.24023149, -0.66311811, -0.50951819, -0.36873654], + [ 2.00858313, -0.05971232, 0.52272395, -0.12604478], + [ 3.39365063, 0.63492697, 1.5780069, 0.46445682]] + for ii in range(self.ndata): + for jj in range(network_size[-1]): + self.assertAlmostEqual(refout[ii][jj], myout[ii][jj], places = self.places) + + + def test_enlarger_net_2(self): + network_size = [2, 4] + out = embedding_net(self.inputs, + network_size, + tf.float64, + name_suffix = 'enlarger_net_2_idt', + resnet_dt = True, + seed = 1) + self.sess.run(tf.global_variables_initializer()) + myout = self.sess.run(out) + refout = [[ 0.2403889, -0.66290763, -0.50883586, -0.36869913], + [ 2.00891479, -0.05936574, 0.52351633, -0.12579749], + [ 3.3940202, 0.63538459, 1.57887697, 0.46486689]] + for ii in range(self.ndata): + for jj in range(network_size[-1]): + self.assertAlmostEqual(refout[ii][jj], myout[ii][jj], places = self.places) + + + + +if __name__ == '__main__': + unittest.main() From 98b2c92182b858dcf1bc68a8d097eb25346ebb58 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 1 Jan 2021 17:10:53 +0800 Subject: [PATCH 025/562] add doc for short-range tabulated interaction --- doc/train-input-auto.rst | 36 ++++++++++++++++++++++++++++++++++++ source/train/argcheck.py | 9 +++++++++ 2 files changed, 45 insertions(+) diff --git a/doc/train-input-auto.rst b/doc/train-input-auto.rst index 5f3cc77cdf..957edff293 100644 --- a/doc/train-input-auto.rst +++ b/doc/train-input-auto.rst @@ -23,6 +23,42 @@ model: The model determines the normalization from the statistics of the data. This key specifies the number of `frames` in each `system` used for statistics. + .. raw:: html + + + use_srtab: + | type: ``str``, optional + | argument path: ``model/use_srtab`` + + The table for the short-range pairwise interaction added on top of DP. The table is a text data file with (N_t + 1) * N_t / 2 + 1 columes. The first colume is the distance between atoms. The second to the last columes are energies for pairs of certain types. For example we have two atom types, 0 and 1. The columes from 2nd to 4th are for 0-0, 0-1 and 1-1 correspondingly. + + .. raw:: html + + + smin_alpha: + | type: ``float``, optional + | argument path: ``model/smin_alpha`` + + The short-range tabulated interaction will be swithed according to the distance of the nearest neighbor. This distance is calculated by softmin. This parameter is the decaying parameter in the softmin. It is only required when `use_srtab` is provided. + + .. raw:: html + + + sw_rmin: + | type: ``float``, optional + | argument path: ``model/sw_rmin`` + + The lower boundary of the interpolation between short-range tabulated interaction and DP. It is only required when `use_srtab` is provided. + + .. raw:: html + + + sw_rmax: + | type: ``float``, optional + | argument path: ``model/sw_rmax`` + + The upper boundary of the interpolation between short-range tabulated interaction and DP. It is only required when `use_srtab` is provided. + .. raw:: html diff --git a/source/train/argcheck.py b/source/train/argcheck.py index a6a8146ff4..943a23b4b2 100644 --- a/source/train/argcheck.py +++ b/source/train/argcheck.py @@ -236,9 +236,18 @@ def model_args (): doc_data_stat_nbatch = 'The model determines the normalization from the statistics of the data. This key specifies the number of `frames` in each `system` used for statistics.' doc_descrpt = 'The descriptor of atomic environment.' doc_fitting = 'The fitting of physical properties.' + doc_use_srtab = 'The table for the short-range pairwise interaction added on top of DP. The table is a text data file with (N_t + 1) * N_t / 2 + 1 columes. The first colume is the distance between atoms. The second to the last columes are energies for pairs of certain types. For example we have two atom types, 0 and 1. The columes from 2nd to 4th are for 0-0, 0-1 and 1-1 correspondingly.' + doc_smin_alpha = 'The short-range tabulated interaction will be swithed according to the distance of the nearest neighbor. This distance is calculated by softmin. This parameter is the decaying parameter in the softmin. It is only required when `use_srtab` is provided.' + doc_sw_rmin = 'The lower boundary of the interpolation between short-range tabulated interaction and DP. It is only required when `use_srtab` is provided.' + doc_sw_rmax = 'The upper boundary of the interpolation between short-range tabulated interaction and DP. It is only required when `use_srtab` is provided.' + ca = Argument("model", dict, [Argument("type_map", list, optional = True, doc = doc_type_map), Argument("data_stat_nbatch", int, optional = True, default = 10, doc = doc_data_stat_nbatch), + Argument("use_srtab", str, optional = True, doc = doc_use_srtab), + Argument("smin_alpha", float, optional = True, doc = doc_smin_alpha), + Argument("sw_rmin", float, optional = True, doc = doc_sw_rmin), + Argument("sw_rmax", float, optional = True, doc = doc_sw_rmax), Argument("descriptor", dict, [], [descrpt_variant_type_args()], doc = doc_descrpt), Argument("fitting_net", dict, [], [fitting_variant_type_args()], doc = doc_fitting) ]) From c4c199d3490252b0c7c32d3806f46464be73a860 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 4 Jan 2021 19:19:18 +0800 Subject: [PATCH 026/562] fix bug of missing model attribute in hybrid descriptor --- source/train/DescrptHybrid.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/train/DescrptHybrid.py b/source/train/DescrptHybrid.py index e0544ad344..c41d3d75a1 100644 --- a/source/train/DescrptHybrid.py +++ b/source/train/DescrptHybrid.py @@ -2,6 +2,8 @@ from deepmd.env import tf from deepmd.common import ClassArg from deepmd.env import op_module +from deepmd.RunOptions import global_tf_float_precision +from deepmd.RunOptions import global_np_float_precision from deepmd.DescrptLocFrame import DescrptLocFrame from deepmd.DescrptSeA import DescrptSeA from deepmd.DescrptSeAT import DescrptSeAT @@ -80,6 +82,13 @@ def build (self, input_dict, suffix = '', reuse = None): + with tf.variable_scope('descrpt_attr' + suffix, reuse = reuse) : + t_rcut = tf.constant(self.get_rcut(), + name = 'rcut', + dtype = global_tf_float_precision) + t_ntypes = tf.constant(self.get_ntypes(), + name = 'ntypes', + dtype = tf.int32) all_dout = [] for tt,ii in zip(self.descrpt_type,self.descrpt_list): dout = ii.build(coord_, atype_, natoms, box, mesh, input_dict, suffix=suffix+f'_{tt}', reuse=reuse) From 933c193c7be39247bda0ef32856f8f6aa2573eac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Mon, 4 Jan 2021 17:34:25 +0100 Subject: [PATCH 027/562] small changes to minimize PR diff --- README.md | 9 ++--- {media => doc}/images/l2_energy_loss.png | Bin {media => doc}/images/l2_force_loss.png | Bin {media => doc}/images/l2_loss.png | Bin .../images/tensorboard-distribution.png | Bin {media => doc}/images/tensorboard-graph.png | Bin .../images/tensorboard-histograms.png | Bin {media => doc}/images/tensorboard-scalar.png | Bin doc/index.rst | 1 + {media/docs => doc}/install-tf.1.12.md | 0 {media/docs => doc}/install-tf.1.14-gpu.md | 0 {media/docs => doc}/install-tf.1.14.md | 0 {media/docs => doc}/install-tf.1.8.md | 0 .../docs => doc}/lammps-pair-style-deepmd.md | 0 .../tensorboard.md | 31 ++++++++++-------- doc/use-deepmd-kit.md | 6 ++++ examples/water/train/water_se_a.json | 4 +-- source/train/Trainer.py | 2 +- 18 files changed, 33 insertions(+), 20 deletions(-) rename {media => doc}/images/l2_energy_loss.png (100%) rename {media => doc}/images/l2_force_loss.png (100%) rename {media => doc}/images/l2_loss.png (100%) rename {media => doc}/images/tensorboard-distribution.png (100%) rename {media => doc}/images/tensorboard-graph.png (100%) rename {media => doc}/images/tensorboard-histograms.png (100%) rename {media => doc}/images/tensorboard-scalar.png (100%) rename {media/docs => doc}/install-tf.1.12.md (100%) rename {media/docs => doc}/install-tf.1.14-gpu.md (100%) rename {media/docs => doc}/install-tf.1.14.md (100%) rename {media/docs => doc}/install-tf.1.8.md (100%) rename {media/docs => doc}/lammps-pair-style-deepmd.md (100%) rename media/docs/dp-tensorboard-tutorial.md => doc/tensorboard.md (67%) diff --git a/README.md b/README.md index 778277ffe9..7f9b02b628 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ DeePMD-kit is a package written in Python/C++, designed to minimize the effort r For more information, check the [documentation](https://deepmd.readthedocs.io/). ## Highlighted features -* **interfaced with TensorFlow**, one of the most popular deep learning frameworks, making the training process highly automatic and efficient. +* **interfaced with TensorFlow**, one of the most popular deep learning frameworks, making the training process highly automatic and efficient, in addition Tensorboard can be used to visualize training procedure. * **interfaced with high-performance classical MD and quantum (path-integral) MD packages**, i.e., LAMMPS and i-PI, respectively. * **implements the Deep Potential series models**, which have been successfully applied to finite and extended systems including organic molecules, metals, semiconductors, and insulators, etc. * **implements MPI and GPU supports**, makes it highly efficient for high performance parallel and distributed computing. @@ -78,9 +78,10 @@ The typical procedure of using DeePMD-kit includes 5 steps 1. [Prepare data](doc/use-deepmd-kit.md#prepare-data) 2. [Train a model](doc/use-deepmd-kit.md#train-a-model) -3. [Freeze the model](doc/use-deepmd-kit.md#freeze-a-model) -4. [Test the model](doc/use-deepmd-kit.md#test-a-model) -5. [Inference the model in python](doc/use-deepmd-kit.md#model-inference) or using the model in other molecular simulation packages like [LAMMPS](doc/use-deepmd-kit.md#run-md-with-lammps), [i-PI](doc/use-deepmd-kit.md#run-path-integral-md-with-i-pi) or [ASE](doc/use-deepmd-kit.md#use-deep-potential-with-ase). +3. [Analyze training with Tensorboard](doc/tensorboard.md) +4. [Freeze the model](doc/use-deepmd-kit.md#freeze-a-model) +5. [Test the model](doc/use-deepmd-kit.md#test-a-model) +6. [Inference the model in python](doc/use-deepmd-kit.md#model-inference) or using the model in other molecular simulation packages like [LAMMPS](doc/use-deepmd-kit.md#run-md-with-lammps), [i-PI](doc/use-deepmd-kit.md#run-path-integral-md-with-i-pi) or [ASE](doc/use-deepmd-kit.md#use-deep-potential-with-ase). A quick-start on using DeePMD-kit can be found [here](doc/use-deepmd-kit.md). diff --git a/media/images/l2_energy_loss.png b/doc/images/l2_energy_loss.png similarity index 100% rename from media/images/l2_energy_loss.png rename to doc/images/l2_energy_loss.png diff --git a/media/images/l2_force_loss.png b/doc/images/l2_force_loss.png similarity index 100% rename from media/images/l2_force_loss.png rename to doc/images/l2_force_loss.png diff --git a/media/images/l2_loss.png b/doc/images/l2_loss.png similarity index 100% rename from media/images/l2_loss.png rename to doc/images/l2_loss.png diff --git a/media/images/tensorboard-distribution.png b/doc/images/tensorboard-distribution.png similarity index 100% rename from media/images/tensorboard-distribution.png rename to doc/images/tensorboard-distribution.png diff --git a/media/images/tensorboard-graph.png b/doc/images/tensorboard-graph.png similarity index 100% rename from media/images/tensorboard-graph.png rename to doc/images/tensorboard-graph.png diff --git a/media/images/tensorboard-histograms.png b/doc/images/tensorboard-histograms.png similarity index 100% rename from media/images/tensorboard-histograms.png rename to doc/images/tensorboard-histograms.png diff --git a/media/images/tensorboard-scalar.png b/doc/images/tensorboard-scalar.png similarity index 100% rename from media/images/tensorboard-scalar.png rename to doc/images/tensorboard-scalar.png diff --git a/doc/index.rst b/doc/index.rst index 13c0c45b7d..9969d8372d 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -15,6 +15,7 @@ DeePMD-kit's documentation use-deepmd-kit train-input lammps-pair-style-deepmd + tensorboard api diff --git a/media/docs/install-tf.1.12.md b/doc/install-tf.1.12.md similarity index 100% rename from media/docs/install-tf.1.12.md rename to doc/install-tf.1.12.md diff --git a/media/docs/install-tf.1.14-gpu.md b/doc/install-tf.1.14-gpu.md similarity index 100% rename from media/docs/install-tf.1.14-gpu.md rename to doc/install-tf.1.14-gpu.md diff --git a/media/docs/install-tf.1.14.md b/doc/install-tf.1.14.md similarity index 100% rename from media/docs/install-tf.1.14.md rename to doc/install-tf.1.14.md diff --git a/media/docs/install-tf.1.8.md b/doc/install-tf.1.8.md similarity index 100% rename from media/docs/install-tf.1.8.md rename to doc/install-tf.1.8.md diff --git a/media/docs/lammps-pair-style-deepmd.md b/doc/lammps-pair-style-deepmd.md similarity index 100% rename from media/docs/lammps-pair-style-deepmd.md rename to doc/lammps-pair-style-deepmd.md diff --git a/media/docs/dp-tensorboard-tutorial.md b/doc/tensorboard.md similarity index 67% rename from media/docs/dp-tensorboard-tutorial.md rename to doc/tensorboard.md index 81d7d0eaa7..a9814c33a0 100644 --- a/media/docs/dp-tensorboard-tutorial.md +++ b/doc/tensorboard.md @@ -1,6 +1,8 @@ -# DeePMD-kit TensorBoard tutorial +# DeePMD-kit TensorBoard usage -TensorBoard provides the visualization and tooling needed for machine learning experimentation. A full instruction of tensorboard can be found [here](https://tensorflow.google.cn/tensorboard). +TensorBoard provides the visualization and tooling needed for machine learning +experimentation. A full instruction of tensorboard can be found +[here](https://tensorflow.google.cn/tensorboard). ## Highlighted features @@ -14,9 +16,11 @@ DeePMD-kit can now use most of the interesting features enabled by tensorboard! -## How to use +## How to use Tensorboard with DeePMD-kit -Before running TensorBoard, make sure you have generated summary data in a log directory by modifying the the input script, set "tensorboard" true will enable the tensorboard data analysis. eg. **water_se_a.json**. +Before running TensorBoard, make sure you have generated summary data in a log +directory by modifying the the input script, set "tensorboard" true in training +subsection will enable the tensorboard data analysis. eg. **water_se_a.json**. ```json "training" : { @@ -45,7 +49,8 @@ Before running TensorBoard, make sure you have generated summary data in a log d } ``` -Once you have event files, run TensorBoard and provide the log directory. This should print that TensorBoard has started. Next, connect to http://tensorboard_server_ip:6006. +Once you have event files, run TensorBoard and provide the log directory. This +should print that TensorBoard has started. Next, connect to http://tensorboard_server_ip:6006. TensorBoard requires a logdir to read logs from. For info on configuring TensorBoard, run tensorboard --help. One can easily change the log name with "tensorboard_log_file". @@ -58,24 +63,24 @@ tensorboard --logdir path/to/logs ### Tracking and visualizing loss metrics(red:train, blue:test) -![ALT](/media/images/l2_loss.png "l2 loss") +![ALT](./images/l2_loss.png "l2 loss") -![ALT](/media/images/l2_energy_loss.png "l2 energy loss") +![ALT](./images/l2_energy_loss.png "l2 energy loss") -![ALT](/media/images/l2_force_loss.png "l2 force loss") +![ALT](./images/l2_force_loss.png "l2 force loss") ### Visualizing deepmd-kit model graph -![ALT](/media/images/tensorboard-graph.png "deepmd-kit graph") +![ALT](./images/tensorboard-graph.png "deepmd-kit graph") ### Viewing histograms of weights, biases, or other tensors as they change over time -![ALT](/media/images/tensorboard-histograms.png "deepmd-kit histograms") +![ALT](./images/tensorboard-histograms.png "deepmd-kit histograms") -![ALT](/media/images/tensorboard-distribution.png "deepmd-kit distribution") +![ALT](./images/tensorboard-distribution.png "deepmd-kit distribution") -### Viewing summaries of trainable viriables -![ALT](/media/images/tensorboard-scalar.png "deepmd-kit scalar") +### Viewing summaries of trainable variables +![ALT](./images/tensorboard-scalar.png "deepmd-kit scalar") ## Atention diff --git a/doc/use-deepmd-kit.md b/doc/use-deepmd-kit.md index cbf7a91cbc..657a738336 100644 --- a/doc/use-deepmd-kit.md +++ b/doc/use-deepmd-kit.md @@ -222,6 +222,12 @@ export TF_INTER_OP_PARALLELISM_THREADS=2 dp train input.json ``` +### Training analysis with Tensorboard + +If enbled in json/yaml input file DeePMD-kit will create log files which can be +used to analyze training procedure with Tensorboard. For a short tutorial +please read this [document](doc/tensorboard.md) + ## Freeze a model The trained neural network is extracted from a checkpoint and dumped into a database. This process is called "freezing" a model. The idea and part of our code are from [Morgan](https://blog.metaflow.fr/tensorflow-how-to-freeze-a-model-and-serve-it-with-a-python-api-d4f3596b3adc). To freeze a model, typically one does diff --git a/examples/water/train/water_se_a.json b/examples/water/train/water_se_a.json index 969081b56f..31e9d18479 100644 --- a/examples/water/train/water_se_a.json +++ b/examples/water/train/water_se_a.json @@ -4,10 +4,10 @@ "type_map": ["O", "H"], "descriptor" :{ "type": "se_a", - "sel": [48, 96], + "sel": [46, 92], "rcut_smth": 5.80, "rcut": 6.00, - "neuron": [24, 48, 96], + "neuron": [25, 50, 100], "resnet_dt": false, "axis_neuron": 16, "seed": 1, diff --git a/source/train/Trainer.py b/source/train/Trainer.py index 6c7a258a68..7b0f18b7e1 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -528,4 +528,4 @@ def test_on_the_fly (self, print_str += " %8.1e\n" % current_lr fp.write(print_str) - fp.flush () \ No newline at end of file + fp.flush () From b10dbaa624f2721cdd1fae578ecb79a224ccacc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Mon, 4 Jan 2021 20:35:47 +0100 Subject: [PATCH 028/562] added ommited tf summaries in some of the descriptors --- doc/use-deepmd-kit.md | 2 +- source/train/DescrptLocFrame.py | 2 ++ source/train/DescrptSeAEbd.py | 1 + source/train/DescrptSeAEf.py | 9 +++++++++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/doc/use-deepmd-kit.md b/doc/use-deepmd-kit.md index 657a738336..724171576c 100644 --- a/doc/use-deepmd-kit.md +++ b/doc/use-deepmd-kit.md @@ -226,7 +226,7 @@ dp train input.json If enbled in json/yaml input file DeePMD-kit will create log files which can be used to analyze training procedure with Tensorboard. For a short tutorial -please read this [document](doc/tensorboard.md) +please read this [document](doc/tensorboard.md). ## Freeze a model diff --git a/source/train/DescrptLocFrame.py b/source/train/DescrptLocFrame.py index fc436aa27e..831847bf03 100644 --- a/source/train/DescrptLocFrame.py +++ b/source/train/DescrptLocFrame.py @@ -157,6 +157,8 @@ def build (self, axis_rule = self.axis_rule) self.descrpt = tf.reshape(self.descrpt, [-1, self.ndescrpt]) tf.summary.histogram('descrpt', self.descrpt) + tf.summary.histogram('rij', self.rij) + tf.summary.histogram('nlist', self.nlist) return self.descrpt diff --git a/source/train/DescrptSeAEbd.py b/source/train/DescrptSeAEbd.py index 0d432b9bc0..8fdf343e13 100644 --- a/source/train/DescrptSeAEbd.py +++ b/source/train/DescrptSeAEbd.py @@ -43,6 +43,7 @@ def build (self, trainable = False, initializer = tf.constant_initializer(nei_type)) self.dout = DescrptSeA.build(self, coord_, atype_, natoms, box_, mesh, input_dict, suffix = suffix, reuse = reuse) + tf.summary.histogram('embedding_net_output', self.dout) return self.dout diff --git a/source/train/DescrptSeAEf.py b/source/train/DescrptSeAEf.py index b30706d21e..b94373270e 100644 --- a/source/train/DescrptSeAEf.py +++ b/source/train/DescrptSeAEf.py @@ -63,6 +63,9 @@ def build (self, self.dout = tf.concat([self.dout_vert, self.dout_para], axis = 1) self.dout = tf.reshape(self.dout, [nframes, natoms[0] * self.get_dim_out()]) self.qmat = self.descrpt_vert.qmat + self.descrpt_para.qmat + + tf.summary.histogram('embedding_net_output', self.dout) + return self.dout def prod_force_virial(self, atom_ener, natoms) : @@ -264,7 +267,13 @@ def build (self, self.rij = tf.identity(self.rij, name = 'o_rij') self.nlist = tf.identity(self.nlist, name = 'o_nlist') + # only used when tensorboard was set as true + tf.summary.histogram('descrpt', self.descrpt) + tf.summary.histogram('rij', self.rij) + tf.summary.histogram('nlist', self.nlist) + self.dout, self.qmat = self._pass_filter(self.descrpt_reshape, atype, natoms, input_dict, suffix = suffix, reuse = reuse, trainable = self.trainable) + tf.summary.histogram('embedding_net_output', self.dout) return self.dout From a03b6852a8ea3261c5e42da5ef061e0030d59a8e Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 6 Jan 2021 10:37:25 +0800 Subject: [PATCH 029/562] update the doc for descriptor type --- doc/train-input-auto.rst | 282 ++++++++++++++++++++++++++++----------- source/train/Trainer.py | 4 +- source/train/argcheck.py | 27 ++-- 3 files changed, 224 insertions(+), 89 deletions(-) diff --git a/doc/train-input-auto.rst b/doc/train-input-auto.rst index 5f3cc77cdf..067b1144ea 100644 --- a/doc/train-input-auto.rst +++ b/doc/train-input-auto.rst @@ -42,7 +42,7 @@ model: | type: ``str`` (flag key) | argument path: ``model/descriptor/type`` - The type of the descritpor. Valid types are `loc_frame`, `se_a`, `se_r` and `se_ar`. + The type of the descritpor. Valid types are `loc_frame <#model/descriptor[loc_frame]>`__, `se_a <#model/descriptor[se_a]>`__, `se_r <#model/descriptor[se_r]>`__, `se_a_3be <#model/descriptor[se_a_3be]>`__, `se_a_tpe <#model/descriptor[se_a_tpe]>`__, ``hybrid <#model/descriptor[hybrid]>`__`. - `loc_frame`: Defines a local frame at each atom, and the compute the descriptor as local coordinates under this frame. @@ -50,7 +50,13 @@ model: - `se_r`: Used by the smooth edition of Deep Potential. Only the distance between atoms is used to construct the descriptor. - - `se_ar`: A hybrid of `se_a` and `se_r`. Typically `se_a` has a smaller cut-off while the `se_r` has a larger cut-off. + - `se_a_t`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Three-body embedding will be used by this descriptor. + + - `se_a_ebd`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Type embedding will be used by this descriptor. + + - `hybrid`: Concatenate of a list of descriptors as a new descriptor. + + - `se_ar`: A hybrid of `se_a` and `se_r`. Typically `se_a` has a smaller cut-off while the `se_r` has a larger cut-off. Deprecated, use `hybrid` instead. .. raw:: html @@ -232,267 +238,387 @@ model: .. raw:: html - - When *type* is set to ``se_a_ebd``: + + When *type* is set to ``se_r``: .. raw:: html - + sel: | type: ``list`` - | argument path: ``model/descriptor[se_a_ebd]/sel`` + | argument path: ``model/descriptor[se_r]/sel`` A list of integers. The length of the list should be the same as the number of atom types in the system. `sel[i]` gives the selected number of type-i neighbors. `sel[i]` is recommended to be larger than the maximally possible number of type-i neighbors in the cut-off radius. .. raw:: html - + rcut: | type: ``float``, optional, default: ``6.0`` - | argument path: ``model/descriptor[se_a_ebd]/rcut`` + | argument path: ``model/descriptor[se_r]/rcut`` The cut-off radius. .. raw:: html - + rcut_smth: | type: ``float``, optional, default: ``0.5`` - | argument path: ``model/descriptor[se_a_ebd]/rcut_smth`` + | argument path: ``model/descriptor[se_r]/rcut_smth`` Where to start smoothing. For example the 1/r term is smoothed from `rcut` to `rcut_smth` .. raw:: html - + neuron: | type: ``list``, optional, default: ``[10, 20, 40]`` - | argument path: ``model/descriptor[se_a_ebd]/neuron`` + | argument path: ``model/descriptor[se_r]/neuron`` Number of neurons in each hidden layers of the embedding net. When two layers are of the same size or one layer is twice as large as the previous layer, a skip connection is built. .. raw:: html - - axis_neuron: - | type: ``int``, optional, default: ``4`` - | argument path: ``model/descriptor[se_a_ebd]/axis_neuron`` - - Size of the submatrix of G (embedding matrix). - - .. raw:: html - - + activation_function: | type: ``str``, optional, default: ``tanh`` - | argument path: ``model/descriptor[se_a_ebd]/activation_function`` + | argument path: ``model/descriptor[se_r]/activation_function`` The activation function in the embedding net. Supported activation functions are "relu", "relu6", "softplus", "sigmoid", "tanh", "gelu". .. raw:: html - + resnet_dt: | type: ``bool``, optional, default: ``False`` - | argument path: ``model/descriptor[se_a_ebd]/resnet_dt`` + | argument path: ``model/descriptor[se_r]/resnet_dt`` Whether to use a "Timestep" in the skip connection .. raw:: html - + type_one_side: | type: ``bool``, optional, default: ``False`` - | argument path: ``model/descriptor[se_a_ebd]/type_one_side`` + | argument path: ``model/descriptor[se_r]/type_one_side`` Try to build N_types embedding nets. Otherwise, building N_types^2 embedding nets .. raw:: html - + precision: | type: ``str``, optional, default: ``float64`` - | argument path: ``model/descriptor[se_a_ebd]/precision`` + | argument path: ``model/descriptor[se_r]/precision`` The precision of the embedding net parameters, supported options are "float64", "float32", "float16". .. raw:: html - + trainable: | type: ``bool``, optional, default: ``True`` - | argument path: ``model/descriptor[se_a_ebd]/trainable`` + | argument path: ``model/descriptor[se_r]/trainable`` If the parameters in the embedding net is trainable .. raw:: html - + seed: | type: ``int`` | ``NoneType``, optional - | argument path: ``model/descriptor[se_a_ebd]/seed`` + | argument path: ``model/descriptor[se_r]/seed`` Random seed for parameter initialization .. raw:: html - + exclude_types: | type: ``list``, optional, default: ``[]`` - | argument path: ``model/descriptor[se_a_ebd]/exclude_types`` + | argument path: ``model/descriptor[se_r]/exclude_types`` The Excluded types .. raw:: html - + set_davg_zero: | type: ``bool``, optional, default: ``False`` - | argument path: ``model/descriptor[se_a_ebd]/set_davg_zero`` + | argument path: ``model/descriptor[se_r]/set_davg_zero`` Set the normalization average to zero. This option should be set when `atom_ener` in the energy fitting is used + .. raw:: html - - type_nchanl: - | type: ``int``, optional, default: ``4`` - | argument path: ``model/descriptor[se_a_ebd]/type_nchanl`` + + When *type* is set to ``se_a_3be``: - number of channels for type embedding + .. raw:: html + + + sel: + | type: ``list`` + | argument path: ``model/descriptor[se_a_3be]/sel`` + + A list of integers. The length of the list should be the same as the number of atom types in the system. `sel[i]` gives the selected number of type-i neighbors. `sel[i]` is recommended to be larger than the maximally possible number of type-i neighbors in the cut-off radius. .. raw:: html - - type_nlayer: - | type: ``int``, optional, default: ``2`` - | argument path: ``model/descriptor[se_a_ebd]/type_nlayer`` + + rcut: + | type: ``float``, optional, default: ``6.0`` + | argument path: ``model/descriptor[se_a_3be]/rcut`` - number of hidden layers of type embedding net + The cut-off radius. .. raw:: html - - numb_aparam: - | type: ``int``, optional, default: ``0`` - | argument path: ``model/descriptor[se_a_ebd]/numb_aparam`` + + rcut_smth: + | type: ``float``, optional, default: ``0.5`` + | argument path: ``model/descriptor[se_a_3be]/rcut_smth`` - dimension of atomic parameter. if set to a value > 0, the atomic parameters are embedded. + Where to start smoothing. For example the 1/r term is smoothed from `rcut` to `rcut_smth` + + .. raw:: html + + neuron: + | type: ``list``, optional, default: ``[10, 20, 40]`` + | argument path: ``model/descriptor[se_a_3be]/neuron`` + + Number of neurons in each hidden layers of the embedding net. When two layers are of the same size or one layer is twice as large as the previous layer, a skip connection is built. .. raw:: html - - When *type* is set to ``se_r``: + + activation_function: + | type: ``str``, optional, default: ``tanh`` + | argument path: ``model/descriptor[se_a_3be]/activation_function`` + + The activation function in the embedding net. Supported activation functions are "relu", "relu6", "softplus", "sigmoid", "tanh", "gelu". .. raw:: html - + + resnet_dt: + | type: ``bool``, optional, default: ``False`` + | argument path: ``model/descriptor[se_a_3be]/resnet_dt`` + + Whether to use a "Timestep" in the skip connection + + .. raw:: html + + + precision: + | type: ``str``, optional, default: ``float64`` + | argument path: ``model/descriptor[se_a_3be]/precision`` + + The precision of the embedding net parameters, supported options are "float64", "float32", "float16". + + .. raw:: html + + + trainable: + | type: ``bool``, optional, default: ``True`` + | argument path: ``model/descriptor[se_a_3be]/trainable`` + + If the parameters in the embedding net is trainable + + .. raw:: html + + + seed: + | type: ``int`` | ``NoneType``, optional + | argument path: ``model/descriptor[se_a_3be]/seed`` + + Random seed for parameter initialization + + .. raw:: html + + + exclude_types: + | type: ``list``, optional, default: ``[]`` + | argument path: ``model/descriptor[se_a_3be]/exclude_types`` + + The Excluded types + + .. raw:: html + + + set_davg_zero: + | type: ``bool``, optional, default: ``False`` + | argument path: ``model/descriptor[se_a_3be]/set_davg_zero`` + + Set the normalization average to zero. This option should be set when `atom_ener` in the energy fitting is used + + + .. raw:: html + + + When *type* is set to ``se_a_tpe``: + + .. raw:: html + + sel: | type: ``list`` - | argument path: ``model/descriptor[se_r]/sel`` + | argument path: ``model/descriptor[se_a_tpe]/sel`` A list of integers. The length of the list should be the same as the number of atom types in the system. `sel[i]` gives the selected number of type-i neighbors. `sel[i]` is recommended to be larger than the maximally possible number of type-i neighbors in the cut-off radius. .. raw:: html - + rcut: | type: ``float``, optional, default: ``6.0`` - | argument path: ``model/descriptor[se_r]/rcut`` + | argument path: ``model/descriptor[se_a_tpe]/rcut`` The cut-off radius. .. raw:: html - + rcut_smth: | type: ``float``, optional, default: ``0.5`` - | argument path: ``model/descriptor[se_r]/rcut_smth`` + | argument path: ``model/descriptor[se_a_tpe]/rcut_smth`` Where to start smoothing. For example the 1/r term is smoothed from `rcut` to `rcut_smth` .. raw:: html - + neuron: | type: ``list``, optional, default: ``[10, 20, 40]`` - | argument path: ``model/descriptor[se_r]/neuron`` + | argument path: ``model/descriptor[se_a_tpe]/neuron`` Number of neurons in each hidden layers of the embedding net. When two layers are of the same size or one layer is twice as large as the previous layer, a skip connection is built. .. raw:: html - + + axis_neuron: + | type: ``int``, optional, default: ``4`` + | argument path: ``model/descriptor[se_a_tpe]/axis_neuron`` + + Size of the submatrix of G (embedding matrix). + + .. raw:: html + + activation_function: | type: ``str``, optional, default: ``tanh`` - | argument path: ``model/descriptor[se_r]/activation_function`` + | argument path: ``model/descriptor[se_a_tpe]/activation_function`` The activation function in the embedding net. Supported activation functions are "relu", "relu6", "softplus", "sigmoid", "tanh", "gelu". .. raw:: html - + resnet_dt: | type: ``bool``, optional, default: ``False`` - | argument path: ``model/descriptor[se_r]/resnet_dt`` + | argument path: ``model/descriptor[se_a_tpe]/resnet_dt`` Whether to use a "Timestep" in the skip connection .. raw:: html - + type_one_side: | type: ``bool``, optional, default: ``False`` - | argument path: ``model/descriptor[se_r]/type_one_side`` + | argument path: ``model/descriptor[se_a_tpe]/type_one_side`` Try to build N_types embedding nets. Otherwise, building N_types^2 embedding nets .. raw:: html - + precision: | type: ``str``, optional, default: ``float64`` - | argument path: ``model/descriptor[se_r]/precision`` + | argument path: ``model/descriptor[se_a_tpe]/precision`` The precision of the embedding net parameters, supported options are "float64", "float32", "float16". .. raw:: html - + trainable: | type: ``bool``, optional, default: ``True`` - | argument path: ``model/descriptor[se_r]/trainable`` + | argument path: ``model/descriptor[se_a_tpe]/trainable`` If the parameters in the embedding net is trainable .. raw:: html - + seed: | type: ``int`` | ``NoneType``, optional - | argument path: ``model/descriptor[se_r]/seed`` + | argument path: ``model/descriptor[se_a_tpe]/seed`` Random seed for parameter initialization .. raw:: html - + exclude_types: | type: ``list``, optional, default: ``[]`` - | argument path: ``model/descriptor[se_r]/exclude_types`` + | argument path: ``model/descriptor[se_a_tpe]/exclude_types`` The Excluded types .. raw:: html - + set_davg_zero: | type: ``bool``, optional, default: ``False`` - | argument path: ``model/descriptor[se_r]/set_davg_zero`` + | argument path: ``model/descriptor[se_a_tpe]/set_davg_zero`` Set the normalization average to zero. This option should be set when `atom_ener` in the energy fitting is used + .. raw:: html + + + type_nchanl: + | type: ``int``, optional, default: ``4`` + | argument path: ``model/descriptor[se_a_tpe]/type_nchanl`` + + number of channels for type embedding + + .. raw:: html + + + type_nlayer: + | type: ``int``, optional, default: ``2`` + | argument path: ``model/descriptor[se_a_tpe]/type_nlayer`` + + number of hidden layers of type embedding net + + .. raw:: html + + + numb_aparam: + | type: ``int``, optional, default: ``0`` + | argument path: ``model/descriptor[se_a_tpe]/numb_aparam`` + + dimension of atomic parameter. if set to a value > 0, the atomic parameters are embedded. + + + .. raw:: html + + + When *type* is set to ``hybrid``: + + .. raw:: html + + + list: + | type: ``list`` + | argument path: ``model/descriptor[hybrid]/list`` + + A list of descriptor definitions + .. raw:: html diff --git a/source/train/Trainer.py b/source/train/Trainer.py index 8a86f4871e..d6ba2ada5d 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -64,9 +64,9 @@ def _init_param(self, jdata): self.descrpt = DescrptLocFrame(descrpt_param) elif descrpt_type == 'se_a' : self.descrpt = DescrptSeA(descrpt_param) - elif descrpt_type == 'se_at' : + elif descrpt_type == 'se_a_3be' or descrpt_type == 'se_at' : self.descrpt = DescrptSeAT(descrpt_param) - elif descrpt_type == 'se_a_ebd' : + elif descrpt_type == 'se_a_tpe' or descrpt_type == 'se_a_ebd' : self.descrpt = DescrptSeAEbd(descrpt_param) elif descrpt_type == 'se_a_ef' : self.descrpt = DescrptSeAEf(descrpt_param) diff --git a/source/train/argcheck.py b/source/train/argcheck.py index 9840611944..a7dc884010 100644 --- a/source/train/argcheck.py +++ b/source/train/argcheck.py @@ -164,20 +164,29 @@ def descrpt_hybrid_args(): def descrpt_variant_type_args(): - doc_descrpt_type = 'The type of the descritpor. Valid types are `loc_frame`, `se_a`, `se_r` and `se_ar`. \n\n\ + link_lf = make_link('loc_frame', 'model/descriptor[loc_frame]') + link_se_a = make_link('se_a', 'model/descriptor[se_a]') + link_se_r = make_link('se_r', 'model/descriptor[se_r]') + link_se_a_3be = make_link('se_a_3be', 'model/descriptor[se_a_3be]') + link_se_a_tpe = make_link('se_a_tpe', 'model/descriptor[se_a_tpe]') + link_hybrid = make_link('hybrid', 'model/descriptor[hybrid]') + doc_descrpt_type = f'The type of the descritpor. Valid types are {link_lf}, {link_se_a}, {link_se_r}, {link_se_a_3be}, {link_se_a_tpe}, `{link_hybrid}`. \n\n\ - `loc_frame`: Defines a local frame at each atom, and the compute the descriptor as local coordinates under this frame.\n\n\ - `se_a`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor.\n\n\ - `se_r`: Used by the smooth edition of Deep Potential. Only the distance between atoms is used to construct the descriptor.\n\n\ -- `se_ar`: A hybrid of `se_a` and `se_r`. Typically `se_a` has a smaller cut-off while the `se_r` has a larger cut-off.' +- `se_a_t`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Three-body embedding will be used by this descriptor.\n\n\ +- `se_a_ebd`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Type embedding will be used by this descriptor.\n\n\ +- `hybrid`: Concatenate of a list of descriptors as a new descriptor.\n\n\ +- `se_ar`: A hybrid of `se_a` and `se_r`. Typically `se_a` has a smaller cut-off while the `se_r` has a larger cut-off. Deprecated, use `hybrid` instead.' return Variant("type", [ - Argument("loc_frame", dict, descrpt_local_frame_args()), - Argument("se_a", dict, descrpt_se_a_args()), - Argument("se_at", dict, descrpt_se_at_args()), - Argument("se_a_ebd", dict, descrpt_se_a_ebd_args()), - Argument("se_r", dict, descrpt_se_r_args()), - Argument("se_ar", dict, descrpt_se_ar_args()), - Argument("hybrid", dict, descrpt_hybrid_args()) + Argument("loc_frame", dict, doc = descrpt_local_frame_args()), + Argument("se_a", dict, doc = descrpt_se_a_args()), + Argument("se_r", dict, doc = descrpt_se_r_args()), + Argument("se_a_3be", dict, doc = descrpt_se_at_args(), alias = ['se_at']), + Argument("se_a_tpe", dict, doc = descrpt_se_a_ebd_args(), alias = ['se_a_ebd']), + Argument("hybrid", dict, doc = descrpt_hybrid_args()), + Argument("se_ar", dict, doc = descrpt_se_ar_args()), ], doc = doc_descrpt_type) From 4d9de4936870073490eb97a333c6829b02fb9dfc Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 6 Jan 2021 11:23:15 +0800 Subject: [PATCH 030/562] fix bugs in argcheck --- doc/train-input-auto.rst | 2 +- source/train/argcheck.py | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/train-input-auto.rst b/doc/train-input-auto.rst index 1e54615a4e..43a7f1bc66 100644 --- a/doc/train-input-auto.rst +++ b/doc/train-input-auto.rst @@ -78,7 +78,7 @@ model: | type: ``str`` (flag key) | argument path: ``model/descriptor/type`` - The type of the descritpor. Valid types are `loc_frame <#model/descriptor[loc_frame]>`__, `se_a <#model/descriptor[se_a]>`__, `se_r <#model/descriptor[se_r]>`__, `se_a_3be <#model/descriptor[se_a_3be]>`__, `se_a_tpe <#model/descriptor[se_a_tpe]>`__, ``hybrid <#model/descriptor[hybrid]>`__`. + The type of the descritpor. Valid types are `loc_frame <#model/descriptor[loc_frame]>`__, `se_a <#model/descriptor[se_a]>`__, `se_r <#model/descriptor[se_r]>`__, `se_a_3be <#model/descriptor[se_a_3be]>`__, `se_a_tpe <#model/descriptor[se_a_tpe]>`__, `hybrid <#model/descriptor[hybrid]>`__. - `loc_frame`: Defines a local frame at each atom, and the compute the descriptor as local coordinates under this frame. diff --git a/source/train/argcheck.py b/source/train/argcheck.py index fe563645f0..1c76da43bc 100644 --- a/source/train/argcheck.py +++ b/source/train/argcheck.py @@ -72,7 +72,7 @@ def descrpt_se_a_args(): ] -def descrpt_se_at_args(): +def descrpt_se_a_3be_args(): doc_sel = 'A list of integers. The length of the list should be the same as the number of atom types in the system. `sel[i]` gives the selected number of type-i neighbors. `sel[i]` is recommended to be larger than the maximally possible number of type-i neighbors in the cut-off radius.' doc_rcut = 'The cut-off radius.' doc_rcut_smth = 'Where to start smoothing. For example the 1/r term is smoothed from `rcut` to `rcut_smth`' @@ -101,7 +101,7 @@ def descrpt_se_at_args(): -def descrpt_se_a_ebd_args(): +def descrpt_se_a_tpe_args(): doc_type_nchanl = 'number of channels for type embedding' doc_type_nlayer = 'number of hidden layers of type embedding net' doc_numb_aparam = 'dimension of atomic parameter. if set to a value > 0, the atomic parameters are embedded.' @@ -170,7 +170,7 @@ def descrpt_variant_type_args(): link_se_a_3be = make_link('se_a_3be', 'model/descriptor[se_a_3be]') link_se_a_tpe = make_link('se_a_tpe', 'model/descriptor[se_a_tpe]') link_hybrid = make_link('hybrid', 'model/descriptor[hybrid]') - doc_descrpt_type = f'The type of the descritpor. Valid types are {link_lf}, {link_se_a}, {link_se_r}, {link_se_a_3be}, {link_se_a_tpe}, `{link_hybrid}`. \n\n\ + doc_descrpt_type = f'The type of the descritpor. Valid types are {link_lf}, {link_se_a}, {link_se_r}, {link_se_a_3be}, {link_se_a_tpe}, {link_hybrid}. \n\n\ - `loc_frame`: Defines a local frame at each atom, and the compute the descriptor as local coordinates under this frame.\n\n\ - `se_a`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor.\n\n\ - `se_r`: Used by the smooth edition of Deep Potential. Only the distance between atoms is used to construct the descriptor.\n\n\ @@ -180,13 +180,13 @@ def descrpt_variant_type_args(): - `se_ar`: A hybrid of `se_a` and `se_r`. Typically `se_a` has a smaller cut-off while the `se_r` has a larger cut-off. Deprecated, use `hybrid` instead.' return Variant("type", [ - Argument("loc_frame", dict, doc = descrpt_local_frame_args()), - Argument("se_a", dict, doc = descrpt_se_a_args()), - Argument("se_r", dict, doc = descrpt_se_r_args()), - Argument("se_a_3be", dict, doc = descrpt_se_at_args(), alias = ['se_at']), - Argument("se_a_tpe", dict, doc = descrpt_se_a_ebd_args(), alias = ['se_a_ebd']), - Argument("hybrid", dict, doc = descrpt_hybrid_args()), - Argument("se_ar", dict, doc = descrpt_se_ar_args()), + Argument("loc_frame", dict, descrpt_local_frame_args()), + Argument("se_a", dict, descrpt_se_a_args()), + Argument("se_r", dict, descrpt_se_r_args()), + Argument("se_a_3be", dict, descrpt_se_a_3be_args(), alias = ['se_at']), + Argument("se_a_tpe", dict, descrpt_se_a_tpe_args(), alias = ['se_a_ebd']), + Argument("hybrid", dict, descrpt_hybrid_args()), + Argument("se_ar", dict, descrpt_se_ar_args()), ], doc = doc_descrpt_type) From 21c8e1f18e4f4c3428c92ef69f066dd2e0b6b5ce Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 6 Jan 2021 11:25:22 +0800 Subject: [PATCH 031/562] fix typos --- doc/train-input-auto.rst | 4 ++-- source/train/argcheck.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/train-input-auto.rst b/doc/train-input-auto.rst index 43a7f1bc66..aa85750cbc 100644 --- a/doc/train-input-auto.rst +++ b/doc/train-input-auto.rst @@ -86,9 +86,9 @@ model: - `se_r`: Used by the smooth edition of Deep Potential. Only the distance between atoms is used to construct the descriptor. - - `se_a_t`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Three-body embedding will be used by this descriptor. + - `se_a_3be`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Three-body embedding will be used by this descriptor. - - `se_a_ebd`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Type embedding will be used by this descriptor. + - `se_a_tpe`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Type embedding will be used by this descriptor. - `hybrid`: Concatenate of a list of descriptors as a new descriptor. diff --git a/source/train/argcheck.py b/source/train/argcheck.py index 1c76da43bc..01f536e9ec 100644 --- a/source/train/argcheck.py +++ b/source/train/argcheck.py @@ -174,8 +174,8 @@ def descrpt_variant_type_args(): - `loc_frame`: Defines a local frame at each atom, and the compute the descriptor as local coordinates under this frame.\n\n\ - `se_a`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor.\n\n\ - `se_r`: Used by the smooth edition of Deep Potential. Only the distance between atoms is used to construct the descriptor.\n\n\ -- `se_a_t`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Three-body embedding will be used by this descriptor.\n\n\ -- `se_a_ebd`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Type embedding will be used by this descriptor.\n\n\ +- `se_a_3be`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Three-body embedding will be used by this descriptor.\n\n\ +- `se_a_tpe`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Type embedding will be used by this descriptor.\n\n\ - `hybrid`: Concatenate of a list of descriptors as a new descriptor.\n\n\ - `se_ar`: A hybrid of `se_a` and `se_r`. Typically `se_a` has a smaller cut-off while the `se_r` has a larger cut-off. Deprecated, use `hybrid` instead.' From bb77c1a9fcd377bd6d0aea90a27a6f0256f5c537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 7 Jan 2021 12:35:28 +0100 Subject: [PATCH 032/562] reworked TB logdir clean system --- doc/tensorboard.md | 4 ++-- examples/water/train/water_se_a.json | 2 +- source/train/DescrptSeA.py | 21 ++++++++++++++++++++- source/train/Trainer.py | 15 ++++++--------- source/train/common.py | 16 ---------------- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/doc/tensorboard.md b/doc/tensorboard.md index a9814c33a0..fdc2b00760 100644 --- a/doc/tensorboard.md +++ b/doc/tensorboard.md @@ -42,7 +42,7 @@ subsection will enable the tensorboard data analysis. eg. **water_se_a.json**. "disp_training":true, "time_training":true, "tensorboard": true, - "tensorboard_log_file":"log", + "tensorboard_log_dir":"log", "profiling": false, "profiling_file":"timeline.json", "_comment": "that's all" @@ -53,7 +53,7 @@ Once you have event files, run TensorBoard and provide the log directory. This should print that TensorBoard has started. Next, connect to http://tensorboard_server_ip:6006. TensorBoard requires a logdir to read logs from. For info on configuring TensorBoard, run tensorboard --help. -One can easily change the log name with "tensorboard_log_file". +One can easily change the log name with "tensorboard_log_dir". ```bash tensorboard --logdir path/to/logs diff --git a/examples/water/train/water_se_a.json b/examples/water/train/water_se_a.json index 31e9d18479..368170a77f 100644 --- a/examples/water/train/water_se_a.json +++ b/examples/water/train/water_se_a.json @@ -60,7 +60,7 @@ "disp_training":true, "time_training":true, "tensorboard": false, - "tensorboard_log_file":"log", + "tensorboard_log_dir":"log", "profiling": false, "profiling_file":"timeline.json", "_comment": "that's all" diff --git a/source/train/DescrptSeA.py b/source/train/DescrptSeA.py index e5f89ac545..35daf6af8a 100644 --- a/source/train/DescrptSeA.py +++ b/source/train/DescrptSeA.py @@ -6,8 +6,27 @@ from deepmd.env import op_module from deepmd.env import default_tf_session_config +from typing_extensions import TypedDict, List + +JDATA = TypedDict("JDATA", { + 'sel': List[int], + 'rcut': float, + 'rcut_smth': float, + 'neuron': List[int], + 'axis_neuron': int, + 'resnet_dt': bool, + 'trainable': bool, + 'seed': int, + 'type_one_side': bool, + 'exclude_types': list, + 'set_davg_zero': bool, + 'activation_function': str, + 'precision': str +}) + + class DescrptSeA (): - def __init__ (self, jdata): + def __init__ (self, jdata: JDATA): args = ClassArg()\ .add('sel', list, must = True) \ .add('rcut', float, default = 6.0) \ diff --git a/source/train/Trainer.py b/source/train/Trainer.py index 7b0f18b7e1..0e1a648aa9 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -32,7 +32,7 @@ import deepmd._soft_min_virial_grad import deepmd._gelu -from deepmd.common import j_must_have, ClassArg, delete_file_folder +from deepmd.common import j_must_have, ClassArg def _is_subdir(path, directory): path = os.path.realpath(path) @@ -187,7 +187,7 @@ def _init_param(self, jdata): .add('profiling', bool, default = False)\ .add('profiling_file',str, default = 'timeline.json')\ .add('tensorboard', bool, default = False)\ - .add('tensorboard_log_file',str, default = 'log')\ + .add('tensorboard_log_dir',str, default = 'log')\ .add('sys_probs', list )\ .add('auto_prob_style', str, default = "prob_sys_size") tr_data = tr_args.parse(training_param) @@ -202,7 +202,7 @@ def _init_param(self, jdata): self.profiling = tr_data['profiling'] self.profiling_file = tr_data['profiling_file'] self.tensorboard = tr_data['tensorboard'] - self.tensorboard_log_file = tr_data['tensorboard_log_file'] + self.tensorboard_log_dir = tr_data['tensorboard_log_dir'] self.sys_probs = tr_data['sys_probs'] self.auto_prob_style = tr_data['auto_prob_style'] self.useBN = False @@ -410,12 +410,9 @@ def train (self, # set tensorboard execution environment if self.tensorboard : summary_merged_op = tf.summary.merge_all() - if os.path.exists(self.tensorboard_log_file + '/train'): - delete_file_folder(self.tensorboard_log_file + '/train') - if os.path.exists(self.tensorboard_log_file + '/test'): - delete_file_folder (self.tensorboard_log_file + '/test') - tb_train_writer = tf.summary.FileWriter(self.tensorboard_log_file + '/train', self.sess.graph) - tb_test_writer = tf.summary.FileWriter(self.tensorboard_log_file + '/test') + shutil.rmtree(self.tensorboard_log_dir) + tb_train_writer = tf.summary.FileWriter(self.tensorboard_log_dir + '/train', self.sess.graph) + tb_test_writer = tf.summary.FileWriter(self.tensorboard_log_dir + '/test') else: tb_train_writer = None tb_test_writer = None diff --git a/source/train/common.py b/source/train/common.py index b1142051e1..3695bfaf32 100644 --- a/source/train/common.py +++ b/source/train/common.py @@ -209,22 +209,6 @@ def get_precision(precision): else: raise RuntimeError("%d is not a valid precision" % precision) -def delete_file_folder(src): - '''delete files and folders''' - if os.path.isfile(src): - try: - os.remove(src) - except: - pass - elif os.path.isdir(src): - for item in os.listdir(src): - itemsrc=os.path.join(src,item) - delete_file_folder(itemsrc) - try: - os.rmdir(src) - except: - pass - def variable_summaries(var, name): """Attach a lot of summaries to a Tensor (for TensorBoard visualization).""" with tf.name_scope(name): From 868503822caed9e56f6667965324f9ec4b941862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 7 Jan 2021 13:48:13 +0100 Subject: [PATCH 033/562] remove forgotten experimental tweaks --- source/train/DescrptSeA.py | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/source/train/DescrptSeA.py b/source/train/DescrptSeA.py index af5dc427d5..4bd6cfea43 100644 --- a/source/train/DescrptSeA.py +++ b/source/train/DescrptSeA.py @@ -7,27 +7,9 @@ from deepmd.env import default_tf_session_config from deepmd.Network import embedding_net -from typing_extensions import TypedDict, List - -JDATA = TypedDict("JDATA", { - 'sel': List[int], - 'rcut': float, - 'rcut_smth': float, - 'neuron': List[int], - 'axis_neuron': int, - 'resnet_dt': bool, - 'trainable': bool, - 'seed': int, - 'type_one_side': bool, - 'exclude_types': list, - 'set_davg_zero': bool, - 'activation_function': str, - 'precision': str -}) - class DescrptSeA (): - def __init__ (self, jdata: JDATA): + def __init__ (self, jdata): args = ClassArg()\ .add('sel', list, must = True) \ .add('rcut', float, default = 6.0) \ From f5c67af0d99e9e5af35695b3b3e89524facfe427 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 11 Jan 2021 09:06:17 +0800 Subject: [PATCH 034/562] first working version --- source/CMakeLists.txt | 1 + source/api/CMakeLists.txt | 8 + .../DescrptSeA.py => api/descrpt_se_a.py} | 236 ++++++++++++++---- .../descrpt_se_a_ebd.py} | 6 +- .../descrpt_se_a_ef.py} | 2 +- .../DescrptSeAT.py => api/descrpt_se_a_t.py} | 2 +- .../DescrptSeAR.py => api/descrpt_se_ar.py} | 4 +- .../DescrptSeR.py => api/descrpt_se_r.py} | 2 +- source/{train/Network.py => api/network.py} | 0 source/train/DescrptHybrid.py | 12 +- source/train/Fitting.py | 4 +- source/train/Model.py | 6 +- source/train/Trainer.py | 17 +- source/train/argcheck.py | 18 +- source/train/common.py | 30 ++- 15 files changed, 247 insertions(+), 101 deletions(-) create mode 100644 source/api/CMakeLists.txt rename source/{train/DescrptSeA.py => api/descrpt_se_a.py} (72%) rename source/{train/DescrptSeAEbd.py => api/descrpt_se_a_ebd.py} (99%) rename source/{train/DescrptSeAEf.py => api/descrpt_se_a_ef.py} (99%) rename source/{train/DescrptSeAT.py => api/descrpt_se_a_t.py} (99%) rename source/{train/DescrptSeAR.py => api/descrpt_se_ar.py} (97%) rename source/{train/DescrptSeR.py => api/descrpt_se_r.py} (99%) rename source/{train/Network.py => api/network.py} (100%) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index dc35ee5dc0..086c3d4584 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -201,6 +201,7 @@ include_directories(${CMAKE_BINARY_DIR}/lib/) add_subdirectory (op/) if (BUILD_PY_IF) add_subdirectory (train/) + add_subdirectory (api/) add_subdirectory (scripts/) add_subdirectory (tests/) endif (BUILD_PY_IF) diff --git a/source/api/CMakeLists.txt b/source/api/CMakeLists.txt new file mode 100644 index 0000000000..9ccf6dd716 --- /dev/null +++ b/source/api/CMakeLists.txt @@ -0,0 +1,8 @@ +# train + +file(GLOB LIB_PY descrpt_*.py network.py) + +install( + FILES ${LIB_PY} + DESTINATION deepmd +) diff --git a/source/train/DescrptSeA.py b/source/api/descrpt_se_a.py similarity index 72% rename from source/train/DescrptSeA.py rename to source/api/descrpt_se_a.py index 4bd6cfea43..551ff8aa12 100644 --- a/source/train/DescrptSeA.py +++ b/source/api/descrpt_se_a.py @@ -1,48 +1,81 @@ import numpy as np +from typing import Tuple, List + from deepmd.env import tf -from deepmd.common import ClassArg, get_activation_func, get_precision +from deepmd.common import ClassArg, get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter +from deepmd.argcheck import list_to_doc from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module from deepmd.env import default_tf_session_config -from deepmd.Network import embedding_net +from deepmd.network import embedding_net class DescrptSeA (): - def __init__ (self, jdata): - args = ClassArg()\ - .add('sel', list, must = True) \ - .add('rcut', float, default = 6.0) \ - .add('rcut_smth',float, default = 0.5) \ - .add('neuron', list, default = [10, 20, 40]) \ - .add('axis_neuron', int, default = 4, alias = 'n_axis_neuron') \ - .add('resnet_dt',bool, default = False) \ - .add('trainable',bool, default = True) \ - .add('seed', int) \ - .add('type_one_side', bool, default = False) \ - .add('exclude_types', list, default = []) \ - .add('set_davg_zero', bool, default = False) \ - .add('activation_function', str, default = 'tanh') \ - .add('precision', str, default = "default") - class_data = args.parse(jdata) - self.sel_a = class_data['sel'] - self.rcut_r = class_data['rcut'] - self.rcut_r_smth = class_data['rcut_smth'] - self.filter_neuron = class_data['neuron'] - self.n_axis_neuron = class_data['axis_neuron'] - self.filter_resnet_dt = class_data['resnet_dt'] - self.seed = class_data['seed'] - self.trainable = class_data['trainable'] - self.filter_activation_fn = get_activation_func(class_data['activation_function']) - self.filter_precision = get_precision(class_data['precision']) - exclude_types = class_data['exclude_types'] + @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + def __init__ (self, + rcut: float, + rcut_smth: float, + sel: List[str], + neuron: List[int], + axis_neuron: int, + resnet_dt: bool = False, + trainable: bool = True, + seed: int = 1, + type_one_side: bool = True, + exclude_types: List[int] = [], + set_davg_zero: bool = False, + activation_function: str = 'tanh', + precision: str = 'default' + ) -> None: + """ + Constructor + + Parameters + ---------- + rcut + The cut-off radius + rcut_smth + From where the environment matrix should be smoothed + sel : list[str] + sel[i] specifies the maxmum number of type i atoms in the cut-off radius + neuron : list[int] + Number of neurons in each hidden layers of the embedding net + axis_neuron + Number of the axis neuron (number of columns of the sub-matrix of the embedding matrix) + resnet_dt + Time-step `dt` in the resnet construction: + y = x + dt * \phi (Wx + b) + trainable + If the weights of embedding net are trainable. + seed + Random seed for initializing the network parameters. + type_one_side + Try to build N_types embedding nets. Otherwise, building N_types^2 embedding nets + exclude_types : list[int] + The Excluded types + activation_function + The activation function in the embedding net. Supported options are {0} + precision + The precision of the embedding net parameters. Supported options are {1} + """ + self.sel_a = sel + self.rcut_r = rcut + self.rcut_r_smth = rcut_smth + self.filter_neuron = neuron + self.n_axis_neuron = axis_neuron + self.filter_resnet_dt = resnet_dt + self.seed = seed + self.trainable = trainable + self.filter_activation_fn = get_activation_func(activation_function) + self.filter_precision = get_precision(precision) self.exclude_types = set() for tt in exclude_types: assert(len(tt) == 2) self.exclude_types.add((tt[0], tt[1])) self.exclude_types.add((tt[1], tt[0])) - self.set_davg_zero = class_data['set_davg_zero'] - self.type_one_side = class_data['type_one_side'] + self.set_davg_zero = set_davg_zero + self.type_one_side = type_one_side if self.type_one_side and len(exclude_types) != 0: raise RuntimeError('"type_one_side" is not compatible with "exclude_types"') @@ -89,28 +122,70 @@ def __init__ (self, jdata): self.sub_sess = tf.Session(graph = sub_graph, config=default_tf_session_config) - def get_rcut (self) : + def get_rcut (self) -> float: + """ + Returns the cut-off radisu + """ return self.rcut_r - def get_ntypes (self) : + def get_ntypes (self) -> int: + """ + Returns the number of atom types + """ return self.ntypes - def get_dim_out (self) : + def get_dim_out (self) -> int: + """ + Returns the output dimension of this descriptor + """ return self.filter_neuron[-1] * self.n_axis_neuron - def get_dim_rot_mat_1 (self) : + def get_dim_rot_mat_1 (self) -> int: + """ + Returns the first dimension of the rotation matrix. The rotation is of shape dim_1 x 3 + """ return self.filter_neuron[-1] - def get_nlist (self) : + def get_nlist (self) -> Tuple[tf.Tensor, tf.Tensor, List[int], List[int]]: + """ + Returns + ------- + nlist + Neighbor list + rij + The relative distance between the neighbor and the center atom. + sel_a + The number of neighbors with full information + sel_r + The number of neighbors with only radial information + """ return self.nlist, self.rij, self.sel_a, self.sel_r def compute_input_stats (self, - data_coord, - data_box, - data_atype, - natoms_vec, - mesh, - input_dict) : + data_coord : list, + data_box : list, + data_atype : list, + natoms_vec : list, + mesh : list, + input_dict : dict) -> None : + """ + Compute the statisitcs (avg and std) of the training data. The input will be normalized by the statistics. + + Parameters + ---------- + data_coord + The coordinates. Can be generated by deepmd.model.make_stat_input + data_box + The box. Can be generated by deepmd.model.make_stat_input + data_atype + The atom types. Can be generated by deepmd.model.make_stat_input + natoms_vec + The vector for the number of atoms of the system and different types of atoms. Can be generated by deepmd.model.make_stat_input + mesh + The mesh for neighbor searching. Can be generated by deepmd.model.make_stat_input + input_dict + Dictionary for additional input + """ all_davg = [] all_dstd = [] if True: @@ -150,14 +225,44 @@ def compute_input_stats (self, def build (self, - coord_, - atype_, - natoms, - box_, - mesh, - input_dict, - suffix = '', - reuse = None): + coord_ : tf.Tensor, + atype_ : tf.Tensor, + natoms : tf.Tensor, + box_ : tf.Tensor, + mesh : tf.Tensor, + input_dict : dict, + suffix : str = '', + reuse : bool = None) -> tf.Tensor: + """ + Build the computational graph for the descriptor + + Parameters + ---------- + coord_ + The coordinate of atoms + atype_ + The type of atoms + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + mesh + For historical reasons, only the length of the Tensor matters. + if size of mesh == 6, pbc is assumed. + if size of mesh == 0, no-pbc is assumed. + input_dict + Dictionary for additional inputs + suffix + Name suffix to identify this descriptor + reuse + The weights in the networks should be reused when get the variable. + + Returns + ------- + descriptor + The output descriptor + """ davg = self.davg dstd = self.dstd with tf.variable_scope('descrpt_attr' + suffix, reuse = reuse) : @@ -229,11 +334,38 @@ def build (self, return self.dout - def get_rot_mat(self) : + def get_rot_mat(self) -> tf.Tensor: + """ + Get rotational matrix + """ return self.qmat - def prod_force_virial(self, atom_ener, natoms) : + def prod_force_virial(self, + atom_ener : tf.Tensor, + natoms : tf.Tensor + ) -> Tuple[tf.Tensor, tf.Tensor, tf.Tensor]: + """ + Compute force and virial + + Parameters + ---------- + atom_ener + The atomic energy + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + Return + ------ + force + The force on atoms + virial + The total virial + atom_virial + The atomic virial + """ [net_deriv] = tf.gradients (atom_ener, self.descrpt_reshape) tf.summary.histogram('net_derivative', net_deriv) net_deriv_reshape = tf.reshape (net_deriv, [-1, natoms[0] * self.ndescrpt]) diff --git a/source/train/DescrptSeAEbd.py b/source/api/descrpt_se_a_ebd.py similarity index 99% rename from source/train/DescrptSeAEbd.py rename to source/api/descrpt_se_a_ebd.py index f8f9fce3f9..01a32c3ac3 100644 --- a/source/train/DescrptSeAEbd.py +++ b/source/api/descrpt_se_a_ebd.py @@ -1,13 +1,13 @@ import numpy as np from deepmd.env import tf from deepmd.common import ClassArg, get_activation_func, get_precision, add_data_requirement -from deepmd.Network import one_layer +from deepmd.network import one_layer from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module from deepmd.env import default_tf_session_config -from deepmd.DescrptSeA import DescrptSeA -from deepmd.Network import embedding_net +from deepmd.descrpt_se_a import DescrptSeA +from deepmd.network import embedding_net class DescrptSeAEbd (DescrptSeA): def __init__ (self, jdata): diff --git a/source/train/DescrptSeAEf.py b/source/api/descrpt_se_a_ef.py similarity index 99% rename from source/train/DescrptSeAEf.py rename to source/api/descrpt_se_a_ef.py index b94373270e..6c8681b28f 100644 --- a/source/train/DescrptSeAEf.py +++ b/source/api/descrpt_se_a_ef.py @@ -5,7 +5,7 @@ from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module from deepmd.env import default_tf_session_config -from deepmd.DescrptSeA import DescrptSeA +from deepmd.descrpt_se_a import DescrptSeA class DescrptSeAEf (): def __init__(self, jdata): diff --git a/source/train/DescrptSeAT.py b/source/api/descrpt_se_a_t.py similarity index 99% rename from source/train/DescrptSeAT.py rename to source/api/descrpt_se_a_t.py index b73c9eca1e..3cb54b26e2 100644 --- a/source/train/DescrptSeAT.py +++ b/source/api/descrpt_se_a_t.py @@ -5,7 +5,7 @@ from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module from deepmd.env import default_tf_session_config -from deepmd.Network import embedding_net +from deepmd.network import embedding_net class DescrptSeAT (): def __init__ (self, jdata): diff --git a/source/train/DescrptSeAR.py b/source/api/descrpt_se_ar.py similarity index 97% rename from source/train/DescrptSeAR.py rename to source/api/descrpt_se_ar.py index 086d027963..615073b0a8 100644 --- a/source/train/DescrptSeAR.py +++ b/source/api/descrpt_se_ar.py @@ -2,8 +2,8 @@ from deepmd.env import tf from deepmd.common import ClassArg -from deepmd.DescrptSeA import DescrptSeA -from deepmd.DescrptSeR import DescrptSeR +from deepmd.descrpt_se_a import DescrptSeA +from deepmd.descrpt_se_r import DescrptSeR from deepmd.env import op_module class DescrptSeAR (): diff --git a/source/train/DescrptSeR.py b/source/api/descrpt_se_r.py similarity index 99% rename from source/train/DescrptSeR.py rename to source/api/descrpt_se_r.py index 8ffffe9c46..218a81fb60 100644 --- a/source/train/DescrptSeR.py +++ b/source/api/descrpt_se_r.py @@ -5,7 +5,7 @@ from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module from deepmd.env import default_tf_session_config -from deepmd.Network import embedding_net +from deepmd.network import embedding_net class DescrptSeR (): def __init__ (self, jdata): diff --git a/source/train/Network.py b/source/api/network.py similarity index 100% rename from source/train/Network.py rename to source/api/network.py diff --git a/source/train/DescrptHybrid.py b/source/train/DescrptHybrid.py index c41d3d75a1..9df7026bbd 100644 --- a/source/train/DescrptHybrid.py +++ b/source/train/DescrptHybrid.py @@ -5,11 +5,11 @@ from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.DescrptLocFrame import DescrptLocFrame -from deepmd.DescrptSeA import DescrptSeA -from deepmd.DescrptSeAT import DescrptSeAT -from deepmd.DescrptSeAEbd import DescrptSeAEbd -from deepmd.DescrptSeAEf import DescrptSeAEf -from deepmd.DescrptSeR import DescrptSeR +from deepmd.descrpt_se_a import DescrptSeA +from deepmd.descrpt_se_a_t import DescrptSeAT +from deepmd.descrpt_se_a_ebd import DescrptSeAEbd +from deepmd.descrpt_se_a_ef import DescrptSeAEf +from deepmd.descrpt_se_r import DescrptSeR class DescrptHybrid (): def __init__ (self, jdata): @@ -25,7 +25,7 @@ def __init__ (self, jdata): if this_type == 'loc_frame': this_descrpt = DescrptLocFrame(ii) elif this_type == 'se_a' : - this_descrpt = DescrptSeA(ii) + this_descrpt = DescrptSeA(**ii) elif this_type == 'se_at' : this_descrpt = DescrptSeAT(ii) elif this_type == 'se_a_ebd' : diff --git a/source/train/Fitting.py b/source/train/Fitting.py index d968a22df5..5e433bdb18 100644 --- a/source/train/Fitting.py +++ b/source/train/Fitting.py @@ -3,9 +3,9 @@ from deepmd.env import tf from deepmd.common import ClassArg, add_data_requirement, get_activation_func, get_precision -from deepmd.Network import one_layer +from deepmd.network import one_layer from deepmd.DescrptLocFrame import DescrptLocFrame -from deepmd.DescrptSeA import DescrptSeA +from deepmd.descrpt_se_a import DescrptSeA from deepmd.RunOptions import global_cvt_2_tf_float from deepmd.RunOptions import global_tf_float_precision diff --git a/source/train/Model.py b/source/train/Model.py index af7eb77e35..707ebbea01 100644 --- a/source/train/Model.py +++ b/source/train/Model.py @@ -20,7 +20,7 @@ def _make_all_stat_ref(data, nbatches): return all_stat -def make_all_stat(data, nbatches, merge_sys = True): +def make_stat_input(data, nbatches, merge_sys = True): """ pack data for statistics Parameters @@ -110,7 +110,7 @@ def get_type_map (self) : return self.type_map def data_stat(self, data): - all_stat = make_all_stat(data, self.data_stat_nbatch, merge_sys = False) + all_stat = make_stat_input(data, self.data_stat_nbatch, merge_sys = False) m_all_stat = merge_sys_stat(all_stat) self._compute_input_stat(m_all_stat, protection = self.data_stat_protect) self._compute_output_stat(all_stat) @@ -297,7 +297,7 @@ def get_out_size (self) : return self.fitting.get_out_size() def data_stat(self, data): - all_stat = make_all_stat(data, self.data_stat_nbatch, merge_sys = False) + all_stat = make_stat_input(data, self.data_stat_nbatch, merge_sys = False) m_all_stat = merge_sys_stat(all_stat) self._compute_input_stat (m_all_stat, protection = self.data_stat_protect) self._compute_output_stat(all_stat) diff --git a/source/train/Trainer.py b/source/train/Trainer.py index a6c1335350..df0435cd79 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -9,12 +9,12 @@ from deepmd.RunOptions import global_ener_float_precision from deepmd.Fitting import EnerFitting, WFCFitting, PolarFittingLocFrame, PolarFittingSeA, GlobalPolarFittingSeA, DipoleFittingSeA from deepmd.DescrptLocFrame import DescrptLocFrame -from deepmd.DescrptSeA import DescrptSeA -from deepmd.DescrptSeAT import DescrptSeAT -from deepmd.DescrptSeAEbd import DescrptSeAEbd -from deepmd.DescrptSeAEf import DescrptSeAEf -from deepmd.DescrptSeR import DescrptSeR -from deepmd.DescrptSeAR import DescrptSeAR +from deepmd.descrpt_se_a import DescrptSeA +from deepmd.descrpt_se_a_t import DescrptSeAT +from deepmd.descrpt_se_a_ebd import DescrptSeAEbd +from deepmd.descrpt_se_a_ef import DescrptSeAEf +from deepmd.descrpt_se_r import DescrptSeR +from deepmd.descrpt_se_ar import DescrptSeAR from deepmd.DescrptHybrid import DescrptHybrid from deepmd.Model import Model, WFCModel, DipoleModel, PolarModel, GlobalPolarModel from deepmd.Loss import EnerStdLoss, EnerDipoleLoss, TensorLoss @@ -60,10 +60,11 @@ def _init_param(self, jdata): # descriptor descrpt_type = j_must_have(descrpt_param, 'type') + descrpt_param.pop('type',None) if descrpt_type == 'loc_frame': self.descrpt = DescrptLocFrame(descrpt_param) - elif descrpt_type == 'se_a' : - self.descrpt = DescrptSeA(descrpt_param) + elif descrpt_type == 'se_a' : + self.descrpt = DescrptSeA(**descrpt_param) elif descrpt_type == 'se_a_3be' or descrpt_type == 'se_at' : self.descrpt = DescrptSeAT(descrpt_param) elif descrpt_type == 'se_a_tpe' or descrpt_type == 'se_a_ebd' : diff --git a/source/train/argcheck.py b/source/train/argcheck.py index 01f536e9ec..643b973ae3 100644 --- a/source/train/argcheck.py +++ b/source/train/argcheck.py @@ -1,5 +1,5 @@ from dargs import Argument, Variant -from deepmd.common import activation_fn_dict +from deepmd.common import activation_fn_dict, precision_dict def list_to_doc (xx): items = [] @@ -12,10 +12,6 @@ def list_to_doc (xx): return ''.join(items) -def supported_precision() : - return list_to_doc(['float64', 'float32', 'float16']) - - def make_link(content, ref_key) : return f'`{content} <#{ref_key}>`__' @@ -49,7 +45,7 @@ def descrpt_se_a_args(): doc_activation_function = f'The activation function in the embedding net. Supported activation functions are {list_to_doc(activation_fn_dict.keys())}' doc_resnet_dt = 'Whether to use a "Timestep" in the skip connection' doc_type_one_side = 'Try to build N_types embedding nets. Otherwise, building N_types^2 embedding nets' - doc_precision = f'The precision of the embedding net parameters, supported options are {supported_precision()}' + doc_precision = f'The precision of the embedding net parameters, supported options are {list_to_doc(precision_dict.keys())}' doc_trainable = 'If the parameters in the embedding net is trainable' doc_seed = 'Random seed for parameter initialization' doc_exclude_types = 'The Excluded types' @@ -79,7 +75,7 @@ def descrpt_se_a_3be_args(): doc_neuron = 'Number of neurons in each hidden layers of the embedding net. When two layers are of the same size or one layer is twice as large as the previous layer, a skip connection is built.' doc_activation_function = f'The activation function in the embedding net. Supported activation functions are {list_to_doc(activation_fn_dict.keys())}' doc_resnet_dt = 'Whether to use a "Timestep" in the skip connection' - doc_precision = f'The precision of the embedding net parameters, supported options are {supported_precision()}' + doc_precision = f'The precision of the embedding net parameters, supported options are {list_to_doc(precision_dict.keys())}' doc_trainable = 'If the parameters in the embedding net is trainable' doc_seed = 'Random seed for parameter initialization' doc_exclude_types = 'The Excluded types' @@ -121,7 +117,7 @@ def descrpt_se_r_args(): doc_activation_function = f'The activation function in the embedding net. Supported activation functions are {list_to_doc(activation_fn_dict.keys())}' doc_resnet_dt = 'Whether to use a "Timestep" in the skip connection' doc_type_one_side = 'Try to build N_types embedding nets. Otherwise, building N_types^2 embedding nets' - doc_precision = f'The precision of the embedding net parameters, supported options are {supported_precision()}' + doc_precision = f'The precision of the embedding net parameters, supported options are {list_to_doc(precision_dict.keys())}' doc_trainable = 'If the parameters in the embedding net is trainable' doc_seed = 'Random seed for parameter initialization' doc_exclude_types = 'The Excluded types' @@ -195,7 +191,7 @@ def fitting_ener(): doc_numb_aparam = 'The dimension of the atomic parameter. If set to >0, file `aparam.npy` should be included to provided the input aparams.' doc_neuron = 'The number of neurons in each hidden layers of the fitting net. When two hidden layers are of the same size, a skip connection is built.' doc_activation_function = f'The activation function in the fitting net. Supported activation functions are {list_to_doc(activation_fn_dict.keys())}' - doc_precision = f'The precision of the fitting net parameters, supported options are {supported_precision()}' + doc_precision = f'The precision of the fitting net parameters, supported options are {list_to_doc(precision_dict.keys())}' doc_resnet_dt = 'Whether to use a "Timestep" in the skip connection' doc_trainable = 'Whether the parameters in the fitting net are trainable. This option can be\n\n\ - bool: True if all parameters of the fitting net are trainable, False otherwise.\n\n\ @@ -222,7 +218,7 @@ def fitting_polar(): doc_neuron = 'The number of neurons in each hidden layers of the fitting net. When two hidden layers are of the same size, a skip connection is built.' doc_activation_function = f'The activation function in the fitting net. Supported activation functions are {list_to_doc(activation_fn_dict.keys())}' doc_resnet_dt = 'Whether to use a "Timestep" in the skip connection' - doc_precision = f'The precision of the fitting net parameters, supported options are {supported_precision()}' + doc_precision = f'The precision of the fitting net parameters, supported options are {list_to_doc(precision_dict.keys())}' doc_scale = 'The output of the fitting net (polarizability matrix) will be scaled by ``scale``' doc_diag_shift = 'The diagonal part of the polarizability matrix will be shifted by ``diag_shift``. The shift operation is carried out after ``scale``.' doc_fit_diag = 'Fit the diagonal part of the rotational invariant polarizability matrix, which will be converted to normal polarizability matrix by contracting with the rotation matrix.' @@ -250,7 +246,7 @@ def fitting_dipole(): doc_neuron = 'The number of neurons in each hidden layers of the fitting net. When two hidden layers are of the same size, a skip connection is built.' doc_activation_function = f'The activation function in the fitting net. Supported activation functions are {list_to_doc(activation_fn_dict.keys())}' doc_resnet_dt = 'Whether to use a "Timestep" in the skip connection' - doc_precision = f'The precision of the fitting net parameters, supported options are {supported_precision()}' + doc_precision = f'The precision of the fitting net parameters, supported options are {list_to_doc(precision_dict.keys())}' doc_sel_type = 'The atom types for which the atomic dipole will be provided. If not set, all types will be selected.' doc_seed = 'Random seed for parameter initialization of the fitting net' return [ diff --git a/source/train/common.py b/source/train/common.py index 97b524b8d0..cad4110ac5 100644 --- a/source/train/common.py +++ b/source/train/common.py @@ -22,6 +22,7 @@ def gelu(x): return op_module.gelu(x) data_requirement = {} + activation_fn_dict = { "relu": tf.nn.relu, "relu6": tf.nn.relu6, @@ -30,6 +31,14 @@ def gelu(x): "tanh": tf.nn.tanh, "gelu": gelu } + +precision_dict = { + "default": global_tf_float_precision, + "float16": tf.float16, + "float32": tf.float32, + "float64": tf.float64, +} + def add_data_requirement(key, ndof, atomic = False, @@ -190,6 +199,11 @@ def get_activation_func(activation_fn): raise RuntimeError(activation_fn+" is not a valid activation function") return activation_fn_dict[activation_fn] +def get_precision(precision): + if precision not in precision_dict: + raise RuntimeError(precision+" is not a valid precision") + return precision_dict[precision] + def expand_sys_str(root_dir): matches = [] for root, dirnames, filenames in os.walk(root_dir, followlinks=True): @@ -197,14 +211,8 @@ def expand_sys_str(root_dir): matches.append(root) return matches -def get_precision(precision): - if precision == "default": - return global_tf_float_precision - elif precision == "float16": - return tf.float16 - elif precision == "float32": - return tf.float32 - elif precision == "float64": - return tf.float64 - else: - raise RuntimeError("%d is not a valid precision" % precision) +def docstring_parameter(*sub): + def dec(obj): + obj.__doc__ = obj.__doc__.format(*sub) + return obj + return dec From fe6ea1fc7cf16467385b72434cf6336dd01aea00 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 12 Jan 2021 10:06:48 +0800 Subject: [PATCH 035/562] fixed bug in dipole fitting --- source/api/CMakeLists.txt | 2 +- source/api/descrpt_se_a.py | 10 +- source/{train/Fitting.py => api/fitting.py} | 534 ++++++++++++++++---- source/train/CMakeLists.txt | 2 +- source/train/Model.py | 2 +- source/train/Trainer.py | 26 +- 6 files changed, 463 insertions(+), 113 deletions(-) rename source/{train/Fitting.py => api/fitting.py} (62%) diff --git a/source/api/CMakeLists.txt b/source/api/CMakeLists.txt index 9ccf6dd716..816c3b1612 100644 --- a/source/api/CMakeLists.txt +++ b/source/api/CMakeLists.txt @@ -1,6 +1,6 @@ # train -file(GLOB LIB_PY descrpt_*.py network.py) +file(GLOB LIB_PY descrpt_*.py network.py fitting.py) install( FILES ${LIB_PY} diff --git a/source/api/descrpt_se_a.py b/source/api/descrpt_se_a.py index 551ff8aa12..d5be3ca1a1 100644 --- a/source/api/descrpt_se_a.py +++ b/source/api/descrpt_se_a.py @@ -17,8 +17,8 @@ def __init__ (self, rcut: float, rcut_smth: float, sel: List[str], - neuron: List[int], - axis_neuron: int, + neuron: List[int] = [24,48,96], + axis_neuron: int = 8, resnet_dt: bool = False, trainable: bool = True, seed: int = 1, @@ -230,9 +230,9 @@ def build (self, natoms : tf.Tensor, box_ : tf.Tensor, mesh : tf.Tensor, - input_dict : dict, - suffix : str = '', - reuse : bool = None) -> tf.Tensor: + input_dict : dict, + reuse : bool = None, + suffix : str = '') -> tf.Tensor: """ Build the computational graph for the descriptor diff --git a/source/train/Fitting.py b/source/api/fitting.py similarity index 62% rename from source/train/Fitting.py rename to source/api/fitting.py index 5e433bdb18..563dfda770 100644 --- a/source/train/Fitting.py +++ b/source/api/fitting.py @@ -1,8 +1,10 @@ import warnings import numpy as np +from typing import Tuple, List from deepmd.env import tf -from deepmd.common import ClassArg, add_data_requirement, get_activation_func, get_precision +from deepmd.common import ClassArg, add_data_requirement, get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter +from deepmd.argcheck import list_to_doc from deepmd.network import one_layer from deepmd.DescrptLocFrame import DescrptLocFrame from deepmd.descrpt_se_a import DescrptSeA @@ -11,38 +13,84 @@ from deepmd.RunOptions import global_tf_float_precision class EnerFitting (): - def __init__ (self, jdata, descrpt): + @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + def __init__ (self, + descrpt : tf.Tensor, + neuron : List[int] = [120,120,120], + resnet_dt : bool = True, + numb_fparam : int = 0, + numb_aparam : int = 0, + rcond : float = 1e-3, + tot_ener_zero : bool = False, + trainable : List[bool] = [True,True,True,True], + seed : int = 1, + atom_ener : List[float] = [], + activation_function : str = 'tanh', + precision : str = 'default' + ) -> None: + """ + Constructor + + Parameters + ---------- + descrpt + The descrptor + neuron + Number of neurons in each hidden layer of the fitting net + resnet_dt + Time-step `dt` in the resnet construction: + y = x + dt * \phi (Wx + b) + numb_fparam + Number of frame parameter + numb_aparam + Number of atomic parameter + rcond + The condition number for the regression of atomic energy. + tot_ener_zero + Force the total energy to zero. Useful for the charge fitting. + trainable + If the weights of fitting net are trainable. + Suppose that we have N_l hidden layers in the fitting net, + this list is of length N_l + 1, specifying if the hidden layers and the output layer are trainable. + seed + Random seed for initializing the network parameters. + atom_ener + Specifying atomic energy contribution in vacuum. The `set_davg_zero` key in the descrptor should be set. + activation_function + The activation function in the embedding net. Supported options are {0} + precision + The precision of the embedding net parameters. Supported options are {1} + """ # model param self.ntypes = descrpt.get_ntypes() self.dim_descrpt = descrpt.get_dim_out() - args = ClassArg()\ - .add('numb_fparam', int, default = 0)\ - .add('numb_aparam', int, default = 0)\ - .add('neuron', list, default = [120,120,120], alias = 'n_neuron')\ - .add('resnet_dt', bool, default = True)\ - .add('rcond', float, default = 1e-3) \ - .add('tot_ener_zero', bool, default = False) \ - .add('seed', int) \ - .add('atom_ener', list, default = [])\ - .add("activation_function", str, default = "tanh")\ - .add("precision", str, default = "default")\ - .add("trainable", [list, bool], default = True) - class_data = args.parse(jdata) - self.numb_fparam = class_data['numb_fparam'] - self.numb_aparam = class_data['numb_aparam'] - self.n_neuron = class_data['neuron'] - self.resnet_dt = class_data['resnet_dt'] - self.rcond = class_data['rcond'] - self.seed = class_data['seed'] - self.tot_ener_zero = class_data['tot_ener_zero'] - self.fitting_activation_fn = get_activation_func(class_data["activation_function"]) - self.fitting_precision = get_precision(class_data['precision']) - self.trainable = class_data['trainable'] + # args = ClassArg()\ + # .add('numb_fparam', int, default = 0)\ + # .add('numb_aparam', int, default = 0)\ + # .add('neuron', list, default = [120,120,120], alias = 'n_neuron')\ + # .add('resnet_dt', bool, default = True)\ + # .add('rcond', float, default = 1e-3) \ + # .add('tot_ener_zero', bool, default = False) \ + # .add('seed', int) \ + # .add('atom_ener', list, default = [])\ + # .add("activation_function", str, default = "tanh")\ + # .add("precision", str, default = "default")\ + # .add("trainable", [list, bool], default = True) + self.numb_fparam = numb_fparam + self.numb_aparam = numb_aparam + self.n_neuron = neuron + self.resnet_dt = resnet_dt + self.rcond = rcond + self.seed = seed + self.tot_ener_zero = tot_ener_zero + self.fitting_activation_fn = get_activation_func(activation_function) + self.fitting_precision = get_precision(precision) + self.trainable = trainable if type(self.trainable) is bool: self.trainable = [self.trainable] * (len(self.n_neuron)+1) assert(len(self.trainable) == len(self.n_neuron) + 1), 'length of trainable should be that of n_neuron + 1' self.atom_ener = [] - for at, ae in enumerate(class_data['atom_ener']): + for at, ae in enumerate(atom_ener): if ae is not None: self.atom_ener.append(tf.constant(ae, global_tf_float_precision, name = "atom_%d_ener" % at)) else: @@ -61,13 +109,31 @@ def __init__ (self, jdata, descrpt): self.aparam_std = None self.aparam_inv_std = None - def get_numb_fparam(self) : + def get_numb_fparam(self) -> int: + """ + Get the number of frame parameters + """ return self.numb_fparam - def get_numb_aparam(self) : + def get_numb_aparam(self) -> int: + """ + Get the number of atomic parameters + """ return self.numb_fparam - def compute_output_stats(self, all_stat): + def compute_output_stats(self, + all_stat: dict + ) -> None: + """ + Compute the ouput statistics + + Parameters + ---------- + all_stat + must have the following components: + all_stat['energy'] of shape n_sys x n_batch x n_frame + can be prepared by model.make_stat_input + """ self.bias_atom_e = self._compute_output_stats(all_stat, rcond = self.rcond) @classmethod @@ -93,7 +159,20 @@ def _compute_output_stats(self, all_stat, rcond = 1e-3): = np.linalg.lstsq(sys_tynatom, sys_ener, rcond = rcond) return energy_shift - def compute_input_stats(self, all_stat, protection): + def compute_input_stats(self, + all_stat : dict, + protection : float = 1e-2) -> None: + """ + Compute the input statistics + + Parameters: + all_stat + if numb_fparam > 0 must have all_stat['fparam'] + if numb_aparam > 0 must have all_stat['aparam'] + can be prepared by model.make_stat_input + protection + Divided-by-zero protection + """ # stat fparam if self.numb_fparam > 0: cat_data = np.concatenate(all_stat['fparam'], axis = 0) @@ -130,11 +209,37 @@ def _compute_std (self, sumv2, sumv, sumn) : def build (self, - inputs, - input_dict, - natoms, - reuse = None, - suffix = '') : + inputs : tf.Tensor, + natoms : tf.Tensor, + input_dict : dict = {}, + reuse : bool = None, + suffix : str = '') -> tf.Tensor: + """ + Build the computational graph for fitting net + + Parameters + ---------- + inputs + The input descriptor + input_dict + Additional dict for inputs. + if numb_fparam > 0, should have input_dict['fparam'] + if numb_aparam > 0, should have input_dict['aparam'] + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + reuse + The weights in the networks should be reused when get the variable. + suffix + Name suffix to identify this descriptor + + Return + ------ + ener + The system energy + """ bias_atom_e = self.bias_atom_e if self.numb_fparam > 0 and ( self.fparam_avg is None or self.fparam_inv_std is None ): raise RuntimeError('No data stat result. one should do data statisitic, before build') @@ -256,7 +361,10 @@ def build (self, class WFCFitting () : - def __init__ (self, jdata, descrpt) : + """ + Fitting Wannier function centers (WFCs) with local frame descriptor. Not supported anymore. + """ + def __init__ (self, jdata, descrpt): if not isinstance(descrpt, DescrptLocFrame) : raise RuntimeError('WFC only supports DescrptLocFrame') self.ntypes = descrpt.get_ntypes() @@ -341,6 +449,9 @@ def build (self, class PolarFittingLocFrame () : + """ + Fitting polarizability with local frame descriptor. not supported anymore. + """ def __init__ (self, jdata, descrpt) : if not isinstance(descrpt, DescrptLocFrame) : raise RuntimeError('PolarFittingLocFrame only supports DescrptLocFrame') @@ -423,31 +534,79 @@ def build (self, class PolarFittingSeA () : - def __init__ (self, jdata, descrpt) : + """ + Fit the atomic polarizability with descriptor se_a + """ + @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + def __init__ (self, + descrpt : tf.Tensor, + neuron : List[int] = [120,120,120], + resnet_dt : bool = True, + sel_type : List[int] = None, + fit_diag : bool = True, + scale : List[float] = None, + diag_shift : List[float] = None, + seed : int = 1, + activation_function : str = 'tanh', + precision : str = 'default' + ) -> None: + """ + Constructor + + Parameters + ---------- + descrpt : tf.Tensor + The descrptor + neuron : List[int] + Number of neurons in each hidden layer of the fitting net + resnet_dt : bool + Time-step `dt` in the resnet construction: + y = x + dt * \phi (Wx + b) + sel_type : List[int] + The atom types selected to have an atomic polarizability prediction. If is None, all atoms are selected. + fit_diag : bool + Fit the diagonal part of the rotational invariant polarizability matrix, which will be converted to normal polarizability matrix by contracting with the rotation matrix. + scale : List[float] + The output of the fitting net (polarizability matrix) for type i atom will be scaled by scale[i] + diag_shift : List[float] + The diagonal part of the polarizability matrix of type i will be shifted by diag_shift[i]. The shift operation is carried out after scale. + seed : int + Random seed for initializing the network parameters. + activation_function : str + The activation function in the embedding net. Supported options are {0} + precision : str + The precision of the embedding net parameters. Supported options are {1} + """ if not isinstance(descrpt, DescrptSeA) : raise RuntimeError('PolarFittingSeA only supports DescrptSeA') self.ntypes = descrpt.get_ntypes() self.dim_descrpt = descrpt.get_dim_out() - args = ClassArg()\ - .add('neuron', list, default = [120,120,120], alias = 'n_neuron')\ - .add('resnet_dt', bool, default = True)\ - .add('fit_diag', bool, default = True)\ - .add('diag_shift', [list,float], default = [0.0 for ii in range(self.ntypes)])\ - .add('scale', [list,float], default = [1.0 for ii in range(self.ntypes)])\ - .add('sel_type', [list,int], default = [ii for ii in range(self.ntypes)], alias = 'pol_type')\ - .add('seed', int)\ - .add("activation_function", str , default = "tanh")\ - .add('precision', str, default = "default") - class_data = args.parse(jdata) - self.n_neuron = class_data['neuron'] - self.resnet_dt = class_data['resnet_dt'] - self.sel_type = class_data['sel_type'] - self.fit_diag = class_data['fit_diag'] - self.seed = class_data['seed'] - self.diag_shift = class_data['diag_shift'] - self.scale = class_data['scale'] - self.fitting_activation_fn = get_activation_func(class_data["activation_function"]) - self.fitting_precision = get_precision(class_data['precision']) + # args = ClassArg()\ + # .add('neuron', list, default = [120,120,120], alias = 'n_neuron')\ + # .add('resnet_dt', bool, default = True)\ + # .add('fit_diag', bool, default = True)\ + # .add('diag_shift', [list,float], default = [0.0 for ii in range(self.ntypes)])\ + # .add('scale', [list,float], default = [1.0 for ii in range(self.ntypes)])\ + # .add('sel_type', [list,int], default = [ii for ii in range(self.ntypes)], alias = 'pol_type')\ + # .add('seed', int)\ + # .add("activation_function", str , default = "tanh")\ + # .add('precision', str, default = "default") + # class_data = args.parse(jdata) + self.n_neuron = neuron + self.resnet_dt = resnet_dt + self.sel_type = sel_type + self.fit_diag = fit_diag + self.seed = seed + self.diag_shift = diag_shift + self.scale = scale + self.fitting_activation_fn = get_activation_func(activation_function) + self.fitting_precision = get_precision(precision) + if self.sel_type is None: + self.sel_type = [ii for ii in range(self.ntypes)] + if self.scale is None: + self.scale = [1.0 for ii in range(self.ntypes)] + if self.diag_shift is None: + self.diag_shift = [0.0 for ii in range(self.ntypes)] if type(self.sel_type) is not list: self.sel_type = [self.sel_type] if type(self.diag_shift) is not list: @@ -458,13 +617,31 @@ def __init__ (self, jdata, descrpt) : self.dim_rot_mat = self.dim_rot_mat_1 * 3 self.useBN = False - def get_sel_type(self): + def get_sel_type(self) -> List[int]: + """ + Get selected atom types + """ return self.sel_type - def get_out_size(self): + def get_out_size(self) -> int: + """ + Get the output size. Should be 9 + """ return 9 - def compute_input_stats(self, all_stat, protection = 1e-2): + def compute_input_stats(self, + all_stat, + protection = 1e-2): + """ + Compute the input statistics + + Parameters: + all_stat + Dictionary of inputs. + can be prepared by model.make_stat_input + protection + Divided-by-zero protection + """ if not ('polarizability' in all_stat.keys()): self.avgeig = np.zeros([9]) warnings.warn('no polarizability data, cannot do data stat. use zeros as guess') @@ -482,11 +659,35 @@ def compute_input_stats(self, all_stat, protection = 1e-2): self.avgeig = np.average(all_tmp, axis = 0) def build (self, - input_d, - rot_mat, - natoms, - reuse = None, - suffix = '') : + input_d : tf.Tensor, + rot_mat : tf.Tensor, + natoms : tf.Tensor, + reuse : bool = None, + suffix : str = '') : + """ + Build the computational graph for fitting net + + Parameters + ---------- + input_d + The input descriptor + rot_mat + The rotation matrix from the descriptor. + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + reuse + The weights in the networks should be reused when get the variable. + suffix + Name suffix to identify this descriptor + + Return + ------ + atomic_polar + The atomic polarizability + """ start_index = 0 inputs = tf.cast(tf.reshape(input_d, [-1, self.dim_descrpt * natoms[0]]), self.fitting_precision) rot_mat = tf.reshape(rot_mat, [-1, self.dim_rot_mat * natoms[0]]) @@ -556,17 +757,74 @@ def build (self, class GlobalPolarFittingSeA () : - def __init__ (self, jdata, descrpt) : + """ + Fit the system polarizability with descriptor se_a + """ + @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + def __init__ (self, + descrpt : tf.Tensor, + neuron : List[int] = [120,120,120], + resnet_dt : bool = True, + sel_type : List[int] = None, + fit_diag : bool = True, + scale : List[float] = None, + diag_shift : List[float] = None, + seed : int = 1, + activation_function : str = 'tanh', + precision : str = 'default' + ) -> None: + """ + Constructor + + Parameters + ---------- + descrpt : tf.Tensor + The descrptor + neuron : List[int] + Number of neurons in each hidden layer of the fitting net + resnet_dt : bool + Time-step `dt` in the resnet construction: + y = x + dt * \phi (Wx + b) + sel_type : List[int] + The atom types selected to have an atomic polarizability prediction + fit_diag : bool + Fit the diagonal part of the rotational invariant polarizability matrix, which will be converted to normal polarizability matrix by contracting with the rotation matrix. + scale : List[float] + The output of the fitting net (polarizability matrix) for type i atom will be scaled by scale[i] + diag_shift : List[float] + The diagonal part of the polarizability matrix of type i will be shifted by diag_shift[i]. The shift operation is carried out after scale. + seed : int + Random seed for initializing the network parameters. + activation_function : str + The activation function in the embedding net. Supported options are {0} + precision : str + The precision of the embedding net parameters. Supported options are {1} + """ if not isinstance(descrpt, DescrptSeA) : raise RuntimeError('GlobalPolarFittingSeA only supports DescrptSeA') self.ntypes = descrpt.get_ntypes() self.dim_descrpt = descrpt.get_dim_out() - self.polar_fitting = PolarFittingSeA(jdata, descrpt) - - def get_sel_type(self): + self.polar_fitting = PolarFittingSeA(descrpt, + neuron, + resnet_dt, + sel_type, + fit_diag, + scale, + diag_shift, + seed, + activation_function, + precision) + + def get_sel_type(self) -> int: + """ + Get selected atom types + """ return self.polar_fitting.get_sel_type() - def get_out_size(self): + def get_out_size(self) -> int: + """ + Get the output size. Should be 9 + """ return self.polar_fitting.get_out_size() def build (self, @@ -574,7 +832,31 @@ def build (self, rot_mat, natoms, reuse = None, - suffix = '') : + suffix = '') -> tf.Tensor: + """ + Build the computational graph for fitting net + + Parameters + ---------- + input_d + The input descriptor + rot_mat + The rotation matrix from the descriptor. + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + reuse + The weights in the networks should be reused when get the variable. + suffix + Name suffix to identify this descriptor + + Return + ------ + polar + The system polarizability + """ inputs = tf.reshape(input_d, [-1, self.dim_descrpt * natoms[0]]) outs = self.polar_fitting.build(input_d, rot_mat, natoms, reuse, suffix) # nframes x natoms x 9 @@ -585,41 +867,107 @@ def build (self, class DipoleFittingSeA () : - def __init__ (self, jdata, descrpt) : + """ + Fit the atomic dipole with descriptor se_a + """ + @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + def __init__ (self, + descrpt : tf.Tensor, + neuron : List[int] = [120,120,120], + resnet_dt : bool = True, + sel_type : List[int] = None, + seed : int = 1, + activation_function : str = 'tanh', + precision : str = 'default' + ) : + """ + Constructor + + Parameters + ---------- + descrpt : tf.Tensor + The descrptor + neuron : List[int] + Number of neurons in each hidden layer of the fitting net + resnet_dt : bool + Time-step `dt` in the resnet construction: + y = x + dt * \phi (Wx + b) + sel_type : List[int] + The atom types selected to have an atomic dipole prediction. If is None, all atoms are selected. + seed : int + Random seed for initializing the network parameters. + activation_function : str + The activation function in the embedding net. Supported options are {0} + precision : str + The precision of the embedding net parameters. Supported options are {1} + """ if not isinstance(descrpt, DescrptSeA) : raise RuntimeError('DipoleFittingSeA only supports DescrptSeA') self.ntypes = descrpt.get_ntypes() self.dim_descrpt = descrpt.get_dim_out() - args = ClassArg()\ - .add('neuron', list, default = [120,120,120], alias = 'n_neuron')\ - .add('resnet_dt', bool, default = True)\ - .add('sel_type', [list,int], default = [ii for ii in range(self.ntypes)], alias = 'dipole_type')\ - .add('seed', int)\ - .add("activation_function", str, default = "tanh")\ - .add('precision', str, default = "default") - class_data = args.parse(jdata) - self.n_neuron = class_data['neuron'] - self.resnet_dt = class_data['resnet_dt'] - self.sel_type = class_data['sel_type'] - self.seed = class_data['seed'] - self.fitting_activation_fn = get_activation_func(class_data["activation_function"]) - self.fitting_precision = get_precision(class_data['precision']) + # args = ClassArg()\ + # .add('neuron', list, default = [120,120,120], alias = 'n_neuron')\ + # .add('resnet_dt', bool, default = True)\ + # .add('sel_type', [list,int], default = [ii for ii in range(self.ntypes)], alias = 'dipole_type')\ + # .add('seed', int)\ + # .add("activation_function", str, default = "tanh")\ + # .add('precision', str, default = "default") + # class_data = args.parse(jdata) + self.n_neuron = neuron + self.resnet_dt = resnet_dt + self.sel_type = sel_type + if self.sel_type is None: + self.sel_type = [ii for ii in range(self.ntypes)] + self.sel_type = sel_type + self.seed = seed + self.fitting_activation_fn = get_activation_func(activation_function) + self.fitting_precision = get_precision(precision) self.dim_rot_mat_1 = descrpt.get_dim_rot_mat_1() self.dim_rot_mat = self.dim_rot_mat_1 * 3 self.useBN = False - def get_sel_type(self): + def get_sel_type(self) -> int: + """ + Get selected type + """ return self.sel_type - def get_out_size(self): + def get_out_size(self) -> int: + """ + Get the output size. Should be 3 + """ return 3 def build (self, - input_d, - rot_mat, - natoms, - reuse = None, - suffix = '') : + input_d : tf.Tensor, + rot_mat : tf.Tensor, + natoms : tf.Tensor, + reuse : bool = None, + suffix : str = '') -> tf.Tensor: + """ + Build the computational graph for fitting net + + Parameters + ---------- + input_d + The input descriptor + rot_mat + The rotation matrix from the descriptor. + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + reuse + The weights in the networks should be reused when get the variable. + suffix + Name suffix to identify this descriptor + + Return + ------ + dipole + The atomic dipole. + """ start_index = 0 inputs = tf.cast(tf.reshape(input_d, [-1, self.dim_descrpt * natoms[0]]), self.fitting_precision) rot_mat = tf.reshape(rot_mat, [-1, self.dim_rot_mat * natoms[0]]) diff --git a/source/train/CMakeLists.txt b/source/train/CMakeLists.txt index 34363a6826..4a567abb9d 100644 --- a/source/train/CMakeLists.txt +++ b/source/train/CMakeLists.txt @@ -2,7 +2,7 @@ configure_file("RunOptions.py.in" "${CMAKE_CURRENT_BINARY_DIR}/RunOptions.py" @ONLY) -file(GLOB LIB_PY main.py common.py env.py compat.py calculator.py Network.py Deep*.py Data.py DataSystem.py Model*.py Descrpt*.py Fitting.py Loss.py LearningRate.py Trainer.py TabInter.py EwaldRecp.py DataModifier.py ${CMAKE_CURRENT_BINARY_DIR}/RunOptions.py transform.py argcheck.py doc.py) +file(GLOB LIB_PY main.py common.py env.py compat.py calculator.py Network.py Deep*.py Data.py DataSystem.py Model*.py Descrpt*.py Loss.py LearningRate.py Trainer.py TabInter.py EwaldRecp.py DataModifier.py ${CMAKE_CURRENT_BINARY_DIR}/RunOptions.py transform.py argcheck.py doc.py) file(GLOB CLS_PY Local.py Slurm.py) diff --git a/source/train/Model.py b/source/train/Model.py index 707ebbea01..b8d171eb09 100644 --- a/source/train/Model.py +++ b/source/train/Model.py @@ -180,8 +180,8 @@ def build (self, nnei_r = np.cumsum(sel_r)[-1] atom_ener = self.fitting.build (dout, - input_dict, natoms, + input_dict, reuse = reuse, suffix = suffix) diff --git a/source/train/Trainer.py b/source/train/Trainer.py index df0435cd79..e31bcabf9f 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -7,7 +7,7 @@ from deepmd.env import default_tf_session_config from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_ener_float_precision -from deepmd.Fitting import EnerFitting, WFCFitting, PolarFittingLocFrame, PolarFittingSeA, GlobalPolarFittingSeA, DipoleFittingSeA +from deepmd.fitting import EnerFitting, WFCFitting, PolarFittingLocFrame, PolarFittingSeA, GlobalPolarFittingSeA, DipoleFittingSeA from deepmd.DescrptLocFrame import DescrptLocFrame from deepmd.descrpt_se_a import DescrptSeA from deepmd.descrpt_se_a_t import DescrptSeAT @@ -85,25 +85,27 @@ def _init_param(self, jdata): fitting_type = fitting_param['type'] except: fitting_type = 'ener' + fitting_param.pop('type', None) + fitting_param['descrpt'] = self.descrpt if fitting_type == 'ener': - self.fitting = EnerFitting(fitting_param, self.descrpt) - elif fitting_type == 'wfc': - self.fitting = WFCFitting(fitting_param, self.descrpt) + self.fitting = EnerFitting(**fitting_param) + # elif fitting_type == 'wfc': + # self.fitting = WFCFitting(fitting_param, self.descrpt) elif fitting_type == 'dipole': if descrpt_type == 'se_a': - self.fitting = DipoleFittingSeA(fitting_param, self.descrpt) + self.fitting = DipoleFittingSeA(**fitting_param) else : raise RuntimeError('fitting dipole only supports descrptors: se_a') elif fitting_type == 'polar': - if descrpt_type == 'loc_frame': - self.fitting = PolarFittingLocFrame(fitting_param, self.descrpt) - elif descrpt_type == 'se_a': - self.fitting = PolarFittingSeA(fitting_param, self.descrpt) + # if descrpt_type == 'loc_frame': + # self.fitting = PolarFittingLocFrame(fitting_param, self.descrpt) + if descrpt_type == 'se_a': + self.fitting = PolarFittingSeA(**fitting_param) else : raise RuntimeError('fitting polar only supports descrptors: loc_frame and se_a') elif fitting_type == 'global_polar': if descrpt_type == 'se_a': - self.fitting = GlobalPolarFittingSeA(fitting_param, self.descrpt) + self.fitting = GlobalPolarFittingSeA(**fitting_param) else : raise RuntimeError('fitting global_polar only supports descrptors: loc_frame and se_a') else : @@ -113,8 +115,8 @@ def _init_param(self, jdata): # infer model type by fitting_type if fitting_type == Model.model_type: self.model = Model(model_param, self.descrpt, self.fitting) - elif fitting_type == 'wfc': - self.model = WFCModel(model_param, self.descrpt, self.fitting) + # elif fitting_type == 'wfc': + # self.model = WFCModel(model_param, self.descrpt, self.fitting) elif fitting_type == 'dipole': self.model = DipoleModel(model_param, self.descrpt, self.fitting) elif fitting_type == 'polar': From 5e10aa9105fd1bbd01e4d6228c8aacf351c5e5ff Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 12 Jan 2021 10:07:38 +0800 Subject: [PATCH 036/562] fix bug of compulsory key `loss` --- source/train/argcheck.py | 1 + 1 file changed, 1 insertion(+) diff --git a/source/train/argcheck.py b/source/train/argcheck.py index 643b973ae3..c7d6fae16c 100644 --- a/source/train/argcheck.py +++ b/source/train/argcheck.py @@ -356,6 +356,7 @@ def loss_args(): doc_loss = 'The definition of loss function. The type of the loss depends on the type of the fitting. For fitting type `ener`, the prefactors before energy, force, virial and atomic energy losses may be provided. For fitting type `dipole`, `polar` and `global_polar`, the loss may be an empty `dict` or unset.' ca = Argument('loss', dict, [], [loss_variant_type_args()], + optional = True, doc = doc_loss) return ca From dfa519463d170b2896979955dc73d708fa05ff0b Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 12 Jan 2021 10:07:38 +0800 Subject: [PATCH 037/562] fix bug of compulsory key `loss` --- source/train/argcheck.py | 1 + 1 file changed, 1 insertion(+) diff --git a/source/train/argcheck.py b/source/train/argcheck.py index 01f536e9ec..05a8096f15 100644 --- a/source/train/argcheck.py +++ b/source/train/argcheck.py @@ -360,6 +360,7 @@ def loss_args(): doc_loss = 'The definition of loss function. The type of the loss depends on the type of the fitting. For fitting type `ener`, the prefactors before energy, force, virial and atomic energy losses may be provided. For fitting type `dipole`, `polar` and `global_polar`, the loss may be an empty `dict` or unset.' ca = Argument('loss', dict, [], [loss_variant_type_args()], + optional = True, doc = doc_loss) return ca From 00d6fbef0647e9a1f3cacbdae413c74254e7b75e Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 12 Jan 2021 10:39:02 +0800 Subject: [PATCH 038/562] fix bug of compulsory lable requirement --- source/train/Loss.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/train/Loss.py b/source/train/Loss.py index f476b6146d..df81672ab0 100644 --- a/source/train/Loss.py +++ b/source/train/Loss.py @@ -40,11 +40,11 @@ def __init__ (self, jdata, **kwarg) : self.has_ae = (self.start_pref_ae != 0 or self.limit_pref_ae != 0) self.has_pf = (self.start_pref_pf != 0 or self.limit_pref_pf != 0) # data required - add_data_requirement('energy', 1, atomic=False, must=self.has_e, high_prec=True) - add_data_requirement('force', 3, atomic=True, must=self.has_f, high_prec=False) - add_data_requirement('virial', 9, atomic=False, must=self.has_v, high_prec=False) - add_data_requirement('atom_ener', 1, atomic=True, must=self.has_ae, high_prec=False) - add_data_requirement('atom_pref', 1, atomic=True, must=self.has_pf, high_prec=False, repeat=3) + add_data_requirement('energy', 1, atomic=False, must=False, high_prec=True) + add_data_requirement('force', 3, atomic=True, must=False, high_prec=False) + add_data_requirement('virial', 9, atomic=False, must=False, high_prec=False) + add_data_requirement('atom_ener', 1, atomic=True, must=False, high_prec=False) + add_data_requirement('atom_pref', 1, atomic=True, must=False, high_prec=False, repeat=3) def build (self, learning_rate, From abea60376730506f2c1e44cec3b708d87ebac35a Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 12 Jan 2021 10:39:02 +0800 Subject: [PATCH 039/562] fix bug of compulsory lable requirement --- source/train/Loss.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/train/Loss.py b/source/train/Loss.py index f476b6146d..df81672ab0 100644 --- a/source/train/Loss.py +++ b/source/train/Loss.py @@ -40,11 +40,11 @@ def __init__ (self, jdata, **kwarg) : self.has_ae = (self.start_pref_ae != 0 or self.limit_pref_ae != 0) self.has_pf = (self.start_pref_pf != 0 or self.limit_pref_pf != 0) # data required - add_data_requirement('energy', 1, atomic=False, must=self.has_e, high_prec=True) - add_data_requirement('force', 3, atomic=True, must=self.has_f, high_prec=False) - add_data_requirement('virial', 9, atomic=False, must=self.has_v, high_prec=False) - add_data_requirement('atom_ener', 1, atomic=True, must=self.has_ae, high_prec=False) - add_data_requirement('atom_pref', 1, atomic=True, must=self.has_pf, high_prec=False, repeat=3) + add_data_requirement('energy', 1, atomic=False, must=False, high_prec=True) + add_data_requirement('force', 3, atomic=True, must=False, high_prec=False) + add_data_requirement('virial', 9, atomic=False, must=False, high_prec=False) + add_data_requirement('atom_ener', 1, atomic=True, must=False, high_prec=False) + add_data_requirement('atom_pref', 1, atomic=True, must=False, high_prec=False, repeat=3) def build (self, learning_rate, From 28d72335ac181bcf9bbee0a0757dc9af49bd1148 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 12 Jan 2021 17:11:20 +0800 Subject: [PATCH 040/562] fix bugs --- source/api/descrpt_se_a_ef.py | 84 ++++++++++++++++------ source/api/descrpt_se_ar.py | 2 +- source/api/fitting.py | 4 +- source/tests/data_modifier/dipole.json | 8 +-- source/tests/polar_se_a.json | 8 +-- source/tests/test_data_modifier_shuffle.py | 4 +- source/tests/test_descrpt_se_ar.py | 2 +- source/tests/test_descrpt_sea_ef_rot.py | 8 +-- source/tests/test_embedding_net.py | 2 +- source/tests/test_fitting_stat.py | 18 +++-- source/tests/test_gen_stat_data.py | 10 +-- source/tests/test_model_loc_frame.py | 6 +- source/tests/test_model_se_a.py | 12 ++-- source/tests/test_model_se_a_aparam.py | 10 +-- source/tests/test_model_se_a_fparam.py | 12 ++-- source/tests/test_model_se_a_srtab.py | 12 ++-- source/tests/test_model_se_r.py | 8 ++- source/tests/test_polar_se_a.py | 11 +-- source/tests/test_wfc.py | 2 +- 19 files changed, 145 insertions(+), 78 deletions(-) diff --git a/source/api/descrpt_se_a_ef.py b/source/api/descrpt_se_a_ef.py index 6c8681b28f..e463e47be8 100644 --- a/source/api/descrpt_se_a_ef.py +++ b/source/api/descrpt_se_a_ef.py @@ -1,4 +1,6 @@ import numpy as np +from typing import Tuple, List + from deepmd.env import tf from deepmd.common import ClassArg, add_data_requirement from deepmd.RunOptions import global_tf_float_precision @@ -9,8 +11,8 @@ class DescrptSeAEf (): def __init__(self, jdata): - self.descrpt_para = DescrptSeAEfLower(jdata, op_module.descrpt_se_a_ef_para) - self.descrpt_vert = DescrptSeAEfLower(jdata, op_module.descrpt_se_a_ef_vert) + self.descrpt_para = DescrptSeAEfLower(op_module.descrpt_se_a_ef_para, **jdata) + self.descrpt_vert = DescrptSeAEfLower(op_module.descrpt_se_a_ef_vert, **jdata) def get_rcut (self) : return self.descrpt_vert.rcut_r @@ -80,26 +82,64 @@ def prod_force_virial(self, atom_ener, natoms) : class DescrptSeAEfLower (DescrptSeA): - def __init__ (self, jdata, op): - DescrptSeA.__init__(self, jdata) - args = ClassArg()\ - .add('sel', list, must = True) \ - .add('rcut', float, default = 6.0) \ - .add('rcut_smth',float, default = 5.5) \ - .add('neuron', list, default = [10, 20, 40]) \ - .add('axis_neuron', int, default = 4, alias = 'n_axis_neuron') \ - .add('resnet_dt',bool, default = False) \ - .add('trainable',bool, default = True) \ - .add('seed', int) - class_data = args.parse(jdata) - self.sel_a = class_data['sel'] - self.rcut_r = class_data['rcut'] - self.rcut_r_smth = class_data['rcut_smth'] - self.filter_neuron = class_data['neuron'] - self.n_axis_neuron = class_data['axis_neuron'] - self.filter_resnet_dt = class_data['resnet_dt'] - self.seed = class_data['seed'] - self.trainable = class_data['trainable'] + def __init__ (self, + op, + rcut: float, + rcut_smth: float, + sel: List[str], + neuron: List[int] = [24,48,96], + axis_neuron: int = 8, + resnet_dt: bool = False, + trainable: bool = True, + seed: int = 1, + type_one_side: bool = True, + exclude_types: List[int] = [], + set_davg_zero: bool = False, + activation_function: str = 'tanh', + precision: str = 'default' + ) -> None: + DescrptSeA.__init__(self, + rcut, + rcut_smth, + sel, + neuron, + axis_neuron, + resnet_dt, + trainable, + seed, + type_one_side, + exclude_types, + set_davg_zero, + activation_function, + precision + ) + # DescrptSeA.__init__(self, **jdata) + # args = ClassArg()\ + # .add('sel', list, must = True) \ + # .add('rcut', float, default = 6.0) \ + # .add('rcut_smth',float, default = 5.5) \ + # .add('neuron', list, default = [10, 20, 40]) \ + # .add('axis_neuron', int, default = 4, alias = 'n_axis_neuron') \ + # .add('resnet_dt',bool, default = False) \ + # .add('trainable',bool, default = True) \ + # .add('seed', int) + # class_data = args.parse(jdata) + # self.sel_a = class_data['sel'] + # self.rcut_r = class_data['rcut'] + # self.rcut_r_smth = class_data['rcut_smth'] + # self.filter_neuron = class_data['neuron'] + # self.n_axis_neuron = class_data['axis_neuron'] + # self.filter_resnet_dt = class_data['resnet_dt'] + # self.seed = class_data['seed'] + # self.trainable = class_data['trainable'] + self.sel_a = sel + self.rcut_r = rcut + self.rcut_r_smth = rcut_smth + self.filter_neuron = neuron + self.n_axis_neuron = axis_neuron + self.filter_resnet_dt = resnet_dt + self.seed = seed + self.trainable = trainable self.op = op # descrpt config diff --git a/source/api/descrpt_se_ar.py b/source/api/descrpt_se_ar.py index 615073b0a8..66bd3c5cd5 100644 --- a/source/api/descrpt_se_ar.py +++ b/source/api/descrpt_se_ar.py @@ -14,7 +14,7 @@ def __init__ (self, jdata): class_data = args.parse(jdata) self.param_a = class_data['a'] self.param_r = class_data['r'] - self.descrpt_a = DescrptSeA(self.param_a) + self.descrpt_a = DescrptSeA(**self.param_a) self.descrpt_r = DescrptSeR(self.param_r) assert(self.descrpt_a.get_ntypes() == self.descrpt_r.get_ntypes()) self.davg = None diff --git a/source/api/fitting.py b/source/api/fitting.py index 563dfda770..24dc6bd07b 100644 --- a/source/api/fitting.py +++ b/source/api/fitting.py @@ -22,7 +22,7 @@ def __init__ (self, numb_aparam : int = 0, rcond : float = 1e-3, tot_ener_zero : bool = False, - trainable : List[bool] = [True,True,True,True], + trainable : List[bool] = None, seed : int = 1, atom_ener : List[float] = [], activation_function : str = 'tanh', @@ -86,6 +86,8 @@ def __init__ (self, self.fitting_activation_fn = get_activation_func(activation_function) self.fitting_precision = get_precision(precision) self.trainable = trainable + if self.trainable is None: + self.trainable = [True for ii in range(len(self.n_neuron) + 1)] if type(self.trainable) is bool: self.trainable = [self.trainable] * (len(self.n_neuron)+1) assert(len(self.trainable) == len(self.n_neuron) + 1), 'length of trainable should be that of n_neuron + 1' diff --git a/source/tests/data_modifier/dipole.json b/source/tests/data_modifier/dipole.json index 283ebe161b..9cf93d93f1 100644 --- a/source/tests/data_modifier/dipole.json +++ b/source/tests/data_modifier/dipole.json @@ -11,16 +11,14 @@ "neuron": [25, 50, 100], "resnet_dt": false, "axis_neuron": 6, - "seed": 1, - "_comment": " that's all" + "seed": 1 }, "fitting_net": { "type": "dipole", - "dipole_type": [0], + "sel_type": [0], "neuron": [100, 100, 100], "resnet_dt": true, - "seed": 1, - "_comment": " that's all" + "seed": 1 }, "_comment": " that's all" }, diff --git a/source/tests/polar_se_a.json b/source/tests/polar_se_a.json index 1c4694636e..2e1a1ee62d 100644 --- a/source/tests/polar_se_a.json +++ b/source/tests/polar_se_a.json @@ -12,17 +12,15 @@ "neuron": [25, 50, 100], "resnet_dt": false, "axis_neuron": 16, - "seed": 1, - "_comment": " that's all" + "seed": 1 }, "fitting_net": { "type": "polar", - "pol_type": [0], + "sel_type": [0], "fit_diag": false, "neuron": [100, 100, 100], "resnet_dt": true, - "seed": 1, - "_comment": " that's all" + "seed": 1 }, "_comment": " that's all" }, diff --git a/source/tests/test_data_modifier_shuffle.py b/source/tests/test_data_modifier_shuffle.py index 91b69fd936..f41424ffde 100644 --- a/source/tests/test_data_modifier_shuffle.py +++ b/source/tests/test_data_modifier_shuffle.py @@ -99,7 +99,7 @@ def _setUp_data(self): self.natoms = len(self.atom_types0) self.nframes = 1 scale = 10.0 - self.sel_type = jdata['model']['fitting_net']['dipole_type'] + self.sel_type = jdata['model']['fitting_net']['sel_type'] self.nsel = 0 for ii in self.sel_type: self.nsel += np.sum(self.atom_types0 == ii) @@ -144,7 +144,7 @@ def _setUp_jdata(self): }, "fitting_net": { "type": "dipole", - "dipole_type": [1, 3], + "sel_type": [1, 3], "neuron": [10], "resnet_dt": True, "seed": 1, diff --git a/source/tests/test_descrpt_se_ar.py b/source/tests/test_descrpt_se_ar.py index a7042f7f1b..e5ac11ab71 100644 --- a/source/tests/test_descrpt_se_ar.py +++ b/source/tests/test_descrpt_se_ar.py @@ -19,7 +19,7 @@ from common import virial_dw_test from common import Data -from deepmd.DescrptSeAR import DescrptSeAR +from deepmd.descrpt_se_ar import DescrptSeAR from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision diff --git a/source/tests/test_descrpt_sea_ef_rot.py b/source/tests/test_descrpt_sea_ef_rot.py index 8d2b0234fd..5aa931ba5d 100644 --- a/source/tests/test_descrpt_sea_ef_rot.py +++ b/source/tests/test_descrpt_sea_ef_rot.py @@ -9,8 +9,8 @@ from deepmd.RunOptions import global_ener_float_precision from deepmd.env import op_module -from deepmd.DescrptSeA import DescrptSeA -from deepmd.DescrptSeAEf import DescrptSeAEfLower +from deepmd.descrpt_se_a import DescrptSeA +from deepmd.descrpt_se_a_ef import DescrptSeAEfLower class TestEfRot(unittest.TestCase): def setUp(self): @@ -60,9 +60,9 @@ def build_efv(self, efield = self._normalize_3d(efield) efield = tf.reshape(efield, [-1, tnatoms[0] * 3]) if op != op_module.descrpt_se_a : - descrpt = DescrptSeAEfLower({'sel':self.sel_a}, op) + descrpt = DescrptSeAEfLower(op, **{'sel':self.sel_a, 'rcut': 6, 'rcut_smth' : 5.5}) else: - descrpt = DescrptSeA({'sel':self.sel_a}) + descrpt = DescrptSeA(**{'sel':self.sel_a, 'rcut': 6, 'rcut_smth' : 0.5}) dout = descrpt.build(dcoord, dtype, tnatoms, diff --git a/source/tests/test_embedding_net.py b/source/tests/test_embedding_net.py index faa2e62055..732470d408 100644 --- a/source/tests/test_embedding_net.py +++ b/source/tests/test_embedding_net.py @@ -5,7 +5,7 @@ from deepmd.env import tf from tensorflow.python.framework import ops -from deepmd.Network import embedding_net +from deepmd.network import embedding_net from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision diff --git a/source/tests/test_fitting_stat.py b/source/tests/test_fitting_stat.py index 1e9c48b30b..7a49e11282 100644 --- a/source/tests/test_fitting_stat.py +++ b/source/tests/test_fitting_stat.py @@ -3,8 +3,8 @@ import unittest from collections import defaultdict -from deepmd.DescrptSeA import DescrptSeA -from deepmd.Fitting import EnerFitting +from deepmd.descrpt_se_a import DescrptSeA +from deepmd.fitting import EnerFitting from deepmd.common import j_loader input_json = 'water_se_a_afparam.json' @@ -60,8 +60,18 @@ class TestEnerFittingStat (unittest.TestCase) : def test (self) : jdata = j_loader(input_json) jdata = jdata['model'] - descrpt = DescrptSeA(jdata['descriptor']) - fitting = EnerFitting(jdata['fitting_net'], descrpt) + # descrpt = DescrptSeA(jdata['descriptor']) + # fitting = EnerFitting(jdata['fitting_net'], descrpt) + descrpt = DescrptSeA(6.0, + 5.8, + [46, 92], + neuron = [25, 50, 100], + axis_neuron = 16) + fitting = EnerFitting(descrpt, + neuron = [240, 240, 240], + resnet_dt = True, + numb_fparam = 2, + numb_aparam = 2) avgs = [0, 10] stds = [2, 0.4] sys_natoms = [10, 100] diff --git a/source/tests/test_gen_stat_data.py b/source/tests/test_gen_stat_data.py index 852915bd12..68b3019965 100644 --- a/source/tests/test_gen_stat_data.py +++ b/source/tests/test_gen_stat_data.py @@ -4,8 +4,8 @@ import dpdata from deepmd.DataSystem import DeepmdDataSystem -from deepmd.Fitting import EnerFitting -from deepmd.Model import make_all_stat, merge_sys_stat, _make_all_stat_ref +from deepmd.fitting import EnerFitting +from deepmd.Model import make_stat_input, merge_sys_stat, _make_all_stat_ref def gen_sys(nframes, atom_types): natoms = len(atom_types) @@ -66,9 +66,9 @@ def test_merge_all_stat(self): data2.add('force', 3, atomic = True, must = True) np.random.seed(0) - all_stat_0 = make_all_stat(data0, 10, merge_sys = False) + all_stat_0 = make_stat_input(data0, 10, merge_sys = False) np.random.seed(0) - all_stat_1 = make_all_stat(data1, 10, merge_sys = True) + all_stat_1 = make_stat_input(data1, 10, merge_sys = True) all_stat_2 = merge_sys_stat(all_stat_0) np.random.seed(0) all_stat_3 = _make_all_stat_ref(data2, 10) @@ -116,7 +116,7 @@ def test_ener_shift(self): 1.0) data.add('energy', 1, must = True) ener_shift0 = data.compute_energy_shift(rcond = 1) - all_stat = make_all_stat(data, 4, merge_sys = False) + all_stat = make_stat_input(data, 4, merge_sys = False) ener_shift1 = EnerFitting._compute_output_stats(all_stat, rcond = 1) for ii in range(len(ener_shift0)): self.assertAlmostEqual(ener_shift0[ii], ener_shift1[ii]) diff --git a/source/tests/test_model_loc_frame.py b/source/tests/test_model_loc_frame.py index e79e59de1a..921501fc76 100644 --- a/source/tests/test_model_loc_frame.py +++ b/source/tests/test_model_loc_frame.py @@ -6,7 +6,7 @@ from deepmd.RunOptions import RunOptions from deepmd.DataSystem import DataSystem from deepmd.DescrptLocFrame import DescrptLocFrame -from deepmd.Fitting import EnerFitting +from deepmd.fitting import EnerFitting from deepmd.Model import Model from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader @@ -38,7 +38,9 @@ def test_model(self): numb_test = 1 descrpt = DescrptLocFrame(jdata['model']['descriptor']) - fitting = EnerFitting(jdata['model']['fitting_net'], descrpt) + fitting = EnerFitting(descrpt, + neuron = [240, 120, 60, 30, 10], + seed = 1) model = Model(jdata['model'], descrpt, fitting) # model._compute_dstats([test_data['coord']], [test_data['box']], [test_data['type']], [test_data['natoms_vec']], [test_data['default_mesh']]) diff --git a/source/tests/test_model_se_a.py b/source/tests/test_model_se_a.py index 2d32d89e45..59c96fa35c 100644 --- a/source/tests/test_model_se_a.py +++ b/source/tests/test_model_se_a.py @@ -6,8 +6,8 @@ from deepmd.RunOptions import RunOptions from deepmd.DataSystem import DataSystem -from deepmd.DescrptSeA import DescrptSeA -from deepmd.Fitting import EnerFitting +from deepmd.descrpt_se_a import DescrptSeA +from deepmd.fitting import EnerFitting from deepmd.Model import Model from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader @@ -37,9 +37,11 @@ def test_model(self): test_data = data.get_test () numb_test = 1 - - descrpt = DescrptSeA(jdata['model']['descriptor']) - fitting = EnerFitting(jdata['model']['fitting_net'], descrpt) + + jdata['model']['descriptor'].pop('type', None) + descrpt = DescrptSeA(**jdata['model']['descriptor']) + jdata['model']['fitting_net']['descrpt'] = descrpt + fitting = EnerFitting(**jdata['model']['fitting_net']) model = Model(jdata['model'], descrpt, fitting) # model._compute_dstats([test_data['coord']], [test_data['box']], [test_data['type']], [test_data['natoms_vec']], [test_data['default_mesh']]) diff --git a/source/tests/test_model_se_a_aparam.py b/source/tests/test_model_se_a_aparam.py index f22629ca19..23edf54215 100644 --- a/source/tests/test_model_se_a_aparam.py +++ b/source/tests/test_model_se_a_aparam.py @@ -5,8 +5,8 @@ from deepmd.RunOptions import RunOptions from deepmd.DataSystem import DataSystem -from deepmd.DescrptSeA import DescrptSeA -from deepmd.Fitting import EnerFitting +from deepmd.descrpt_se_a import DescrptSeA +from deepmd.fitting import EnerFitting from deepmd.Model import Model from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader @@ -38,8 +38,10 @@ def test_model(self): test_data['aparam'] = np.load('system/set.000/aparam.npy') numb_test = 1 - descrpt = DescrptSeA(jdata['model']['descriptor']) - fitting = EnerFitting(jdata['model']['fitting_net'], descrpt) + jdata['model']['descriptor'].pop('type', None) + descrpt = DescrptSeA(**jdata['model']['descriptor']) + jdata['model']['fitting_net']['descrpt'] = descrpt + fitting = EnerFitting(**jdata['model']['fitting_net']) model = Model(jdata['model'], descrpt, fitting) # model._compute_dstats([test_data['coord']], [test_data['box']], [test_data['type']], [test_data['natoms_vec']], [test_data['default_mesh']]) diff --git a/source/tests/test_model_se_a_fparam.py b/source/tests/test_model_se_a_fparam.py index 7c5ca2dfc6..4125c911fb 100644 --- a/source/tests/test_model_se_a_fparam.py +++ b/source/tests/test_model_se_a_fparam.py @@ -5,8 +5,8 @@ from deepmd.RunOptions import RunOptions from deepmd.DataSystem import DataSystem -from deepmd.DescrptSeA import DescrptSeA -from deepmd.Fitting import EnerFitting +from deepmd.descrpt_se_a import DescrptSeA +from deepmd.fitting import EnerFitting from deepmd.Model import Model from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader @@ -37,8 +37,12 @@ def test_model(self): test_data = data.get_test () numb_test = 1 - descrpt = DescrptSeA(jdata['model']['descriptor']) - fitting = EnerFitting(jdata['model']['fitting_net'], descrpt) + jdata['model']['descriptor'].pop('type', None) + descrpt = DescrptSeA(**jdata['model']['descriptor']) + jdata['model']['fitting_net']['descrpt'] = descrpt + fitting = EnerFitting(**jdata['model']['fitting_net']) + # descrpt = DescrptSeA(jdata['model']['descriptor']) + # fitting = EnerFitting(jdata['model']['fitting_net'], descrpt) model = Model(jdata['model'], descrpt, fitting) # model._compute_dstats([test_data['coord']], [test_data['box']], [test_data['type']], [test_data['natoms_vec']], [test_data['default_mesh']]) diff --git a/source/tests/test_model_se_a_srtab.py b/source/tests/test_model_se_a_srtab.py index 2eeda45b50..2389421ec3 100644 --- a/source/tests/test_model_se_a_srtab.py +++ b/source/tests/test_model_se_a_srtab.py @@ -5,8 +5,8 @@ from deepmd.RunOptions import RunOptions from deepmd.DataSystem import DataSystem -from deepmd.DescrptSeA import DescrptSeA -from deepmd.Fitting import EnerFitting +from deepmd.descrpt_se_a import DescrptSeA +from deepmd.fitting import EnerFitting from deepmd.Model import Model from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader @@ -47,8 +47,12 @@ def test_model(self): test_data = data.get_test () numb_test = 1 - descrpt = DescrptSeA(jdata['model']['descriptor']) - fitting = EnerFitting(jdata['model']['fitting_net'], descrpt) + jdata['model']['descriptor'].pop('type', None) + descrpt = DescrptSeA(**jdata['model']['descriptor']) + jdata['model']['fitting_net']['descrpt'] = descrpt + fitting = EnerFitting(**jdata['model']['fitting_net']) + # descrpt = DescrptSeA(jdata['model']['descriptor']) + # fitting = EnerFitting(jdata['model']['fitting_net'], descrpt) model = Model(jdata['model'], descrpt, fitting) # model._compute_dstats([test_data['coord']], [test_data['box']], [test_data['type']], [test_data['natoms_vec']], [test_data['default_mesh']]) diff --git a/source/tests/test_model_se_r.py b/source/tests/test_model_se_r.py index 32e3276760..1bf16cde6c 100644 --- a/source/tests/test_model_se_r.py +++ b/source/tests/test_model_se_r.py @@ -5,8 +5,8 @@ from deepmd.RunOptions import RunOptions from deepmd.DataSystem import DataSystem -from deepmd.DescrptSeR import DescrptSeR -from deepmd.Fitting import EnerFitting +from deepmd.descrpt_se_r import DescrptSeR +from deepmd.fitting import EnerFitting from deepmd.Model import Model from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader @@ -38,7 +38,9 @@ def test_model(self): numb_test = 1 descrpt = DescrptSeR(jdata['model']['descriptor']) - fitting = EnerFitting(jdata['model']['fitting_net'], descrpt) + jdata['model']['fitting_net']['descrpt'] = descrpt + fitting = EnerFitting(**jdata['model']['fitting_net']) + # fitting = EnerFitting(jdata['model']['fitting_net'], descrpt) model = Model(jdata['model'], descrpt, fitting) # model._compute_dstats([test_data['coord']], [test_data['box']], [test_data['type']], [test_data['natoms_vec']], [test_data['default_mesh']]) diff --git a/source/tests/test_polar_se_a.py b/source/tests/test_polar_se_a.py index ad2168dcb5..0ce8873836 100644 --- a/source/tests/test_polar_se_a.py +++ b/source/tests/test_polar_se_a.py @@ -5,8 +5,8 @@ from deepmd.RunOptions import RunOptions from deepmd.DataSystem import DataSystem -from deepmd.DescrptSeA import DescrptSeA -from deepmd.Fitting import PolarFittingSeA +from deepmd.descrpt_se_a import DescrptSeA +from deepmd.fitting import PolarFittingSeA from deepmd.Model import PolarModel from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader @@ -37,8 +37,11 @@ def test_model(self): test_data = data.get_test () numb_test = 1 - descrpt = DescrptSeA(jdata['model']['descriptor']) - fitting = PolarFittingSeA(jdata['model']['fitting_net'], descrpt) + jdata['model']['descriptor'].pop('type', None) + jdata['model']['fitting_net'].pop('type', None) + descrpt = DescrptSeA(**jdata['model']['descriptor']) + jdata['model']['fitting_net']['descrpt'] = descrpt + fitting = PolarFittingSeA(**jdata['model']['fitting_net']) model = PolarModel(jdata['model'], descrpt, fitting) # model._compute_dstats([test_data['coord']], [test_data['box']], [test_data['type']], [test_data['natoms_vec']], [test_data['default_mesh']]) diff --git a/source/tests/test_wfc.py b/source/tests/test_wfc.py index 876f4dba0a..ddef429eda 100644 --- a/source/tests/test_wfc.py +++ b/source/tests/test_wfc.py @@ -6,7 +6,7 @@ from deepmd.RunOptions import RunOptions from deepmd.DataSystem import DataSystem from deepmd.DescrptLocFrame import DescrptLocFrame -from deepmd.Fitting import WFCFitting +from deepmd.fitting import WFCFitting from deepmd.Model import WFCModel from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader From 7e534be15448fafbca82b6b71b540dde81edb373 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 13 Jan 2021 08:21:18 -0500 Subject: [PATCH 041/562] add the instruction to install tf 2.3 --- doc/install-tf.2.3.md | 111 ++++++++++++++++++++++++++++++++++++++++++ doc/install.md | 18 ++++--- 2 files changed, 122 insertions(+), 7 deletions(-) create mode 100644 doc/install-tf.2.3.md diff --git a/doc/install-tf.2.3.md b/doc/install-tf.2.3.md new file mode 100644 index 0000000000..6971da151c --- /dev/null +++ b/doc/install-tf.2.3.md @@ -0,0 +1,111 @@ +# Install TensorFlow's C++ interface +The tensorflow's C++ interface will be compiled from the source code. Firstly one installs bazel. The bazel version 3.1.0 should be used. A full instruction of bazel installation can be found [here](https://docs.bazel.build/versions/master/install.html). +```bash +cd /some/workspace +wget https://github.com/bazelbuild/bazel/releases/download/3.1.0/bazel-3.1.0-installer-linux-x86_64.sh +chmod +x bazel-3.1.0-installer-linux-x86_64.sh +./bazel-3.1.0-installer-linux-x86_64.sh --prefix /some/workspace/bazel +export PATH=/some/workspace/bazel/bin:$PATH +``` + +Firstly get the source code of the tensorflow +```bash +git clone https://github.com/tensorflow/tensorflow tensorflow -b v2.3.0 --depth=1 +cd tensorflow +./configure +``` + +You will answer a list of questions that help configure the building of tensorflow. You may want to answer the question like the following. If you do not want to add CUDA support, please answer no. + +``` +Please specify the location of python. [Default is xxx]: + +Found possible Python library paths: + xxx +Please input the desired Python library path to use. Default is [xxx] + +Do you wish to build TensorFlow with OpenCL SYCL support? [y/N]: +No OpenCL SYCL support will be enabled for TensorFlow. + +Do you wish to build TensorFlow with ROCm support? [y/N]: +No ROCm support will be enabled for TensorFlow. + +Do you wish to build TensorFlow with CUDA support? [y/N]: y +CUDA support will be enabled for TensorFlow. + +Do you wish to build TensorFlow with TensorRT support? [y/N]: +No TensorRT support will be enabled for TensorFlow. + +Found CUDA 10.2 in: + /usr/local/cuda/lib64 + /usr/local/cuda/include +Found cuDNN 7 in: + /usr/local/cuda/lib64 + /usr/local/cuda/include + +Please specify a list of comma-separated CUDA compute capabilities you want to build with. +You can find the compute capability of your device at: https://developer.nvidia.com/cuda-gpus. +Please note that each additional compute capability significantly increases your build time and binary size, and that TensorFlow only supports compute capabilities >= 3.5 [Default is: 7.5,7.5]: + +Do you want to use clang as CUDA compiler? [y/N]: +nvcc will be used as CUDA compiler. + +Please specify which gcc should be used by nvcc as the host compiler. [Default is /usr/bin/gcc]: + +Please specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is -march=native -Wno-sign-compare]: + +Would you like to interactively configure ./WORKSPACE for Android builds? [y/N]: +Not configuring the WORKSPACE for Android builds. + +Preconfigured Bazel build configs. You can use any of the below by adding "--config=<>" to your build command. See .bazelrc for more details. + --config=mkl # Build with MKL support. + --config=monolithic # Config for mostly static monolithic build. + --config=ngraph # Build with Intel nGraph support. + --config=numa # Build with NUMA support. + --config=dynamic_kernels # (Experimental) Build kernels into separate shared objects. + --config=v2 # Build TensorFlow 2.x instead of 1.x. +Preconfigured Bazel build configs to DISABLE default on features: + --config=noaws # Disable AWS S3 filesystem support. + --config=nogcp # Disable GCP support. + --config=nohdfs # Disable HDFS support. + --config=nonccl # Disable NVIDIA NCCL support. +Configuration finished +``` + +The library path for Python should be set accordingly. + +Now build the shared library of tensorflow: +```bash +bazel build -c opt --verbose_failures //tensorflow:libtensorflow_cc.so +``` +You may want to add options `--copt=-msse4.2`, `--copt=-mavx`, `--copt=-mavx2` and `--copt=-mfma` to enable SSE4.2, AVX, AVX2 and FMA SIMD accelerations, respectively. It is noted that these options should be chosen according to the CPU architecture. If the RAM becomes an issue of your machine, you may limit the RAM usage by using `--local_resources 2048,.5,1.0`. + +Now I assume you want to install tensorflow in directory `$tensorflow_root`. Create the directory if it does not exists +```bash +mkdir -p $tensorflow_root +``` +Now, copy the libraries to the tensorflow's installation directory: +```bash +mkdir -p $tensorflow_root/lib +cp -d bazel-bin/tensorflow/libtensorflow_cc.so* $tensorflow_root/lib/ +cp -d bazel-bin/tensorflow/libtensorflow_framework.so* $tensorflow_root/lib/ +cp -d $tensorflow_root/lib/libtensorflow_framework.so.2 $tensorflow_root/lib/libtensorflow_framework.so +``` +Then copy the headers +```bash +mkdir -p $tensorflow_root/include/tensorflow +rsync -avzh --exclude '_virtual_includes/' --include '*/' --include '*.h' --include '*.inc' --exclude '*' bazel-bin/ $tensorflow_root/include/ +rsync -avzh --include '*/' --include '*.h' --include '*.inc' --exclude '*' tensorflow/cc $tensorflow_root/include/tensorflow/ +rsync -avzh --include '*/' --include '*.h' --include '*.inc' --exclude '*' tensorflow/core $tensorflow_root/include/tensorflow/ +rsync -avzh --include '*/' --include '*' --exclude '*.cc' third_party/ $tensorflow_root/include/third_party/ +rsync -avzh --include '*/' --include '*' --exclude '*.txt' bazel-tensorflow/external/eigen_archive/Eigen/ $tensorflow_root/include/Eigen/ +rsync -avzh --include '*/' --include '*' --exclude '*.txt' bazel-tensorflow/external/eigen_archive/unsupported/ $tensorflow_root/include/unsupported/ +rsync -avzh --include '*/' --include '*.h' --include '*.inc' --exclude '*' bazel-tensorflow/external/com_google_protobuf/src/google/ $tensorflow_root/include/google/ +rsync -avzh --include '*/' --include '*.h' --include '*.inc' --exclude '*' bazel-tensorflow/external/com_google_absl/absl/ $tensorflow_root/include/absl/ +``` + +# Troubleshooting +```bash +git: unknown command -C ... +``` +This may be your git version issue, because low version of git does not support this command. Upgrading your git maybe helpful. diff --git a/doc/install.md b/doc/install.md index 5e00d3275a..4715121db3 100644 --- a/doc/install.md +++ b/doc/install.md @@ -41,12 +41,12 @@ A docker for installing the DeePMD-kit is available [here](https://github.com/or To pull the CPU version: ```bash -docker pull ghcr.io/deepmodeling/deepmd-kit:1.2.2_cpu +docker pull ghcr.io/deepmodeling/deepmd-kit:1.3.1_cpu ``` To pull the GPU version: ```bash -docker pull ghcr.io/deepmodeling/deepmd-kit:1.2.2_cuda10.1_gpu +docker pull ghcr.io/deepmodeling/deepmd-kit:1.3.1_cuda10.1_gpu ``` ## Install the python interface @@ -126,7 +126,7 @@ gcc --version The C++ interface of DeePMD-kit was tested with compiler gcc >= 4.8. It is noticed that the I-Pi support is only compiled with gcc >= 4.9. -First the C++ interface of Tensorflow should be installed. It is noted that the version of Tensorflow should be in consistent with the python interface. We assume that you have followed our instruction and installed tensorflow python interface 1.14.0 with, then you may follow [the instruction for CPU](install-tf.1.14.md) to install the corresponding C++ interface (CPU only). If one wants GPU supports, he/she should follow [the instruction for GPU](install-tf.1.14-gpu.md) to install the C++ interface. +First the C++ interface of Tensorflow should be installed. It is noted that the version of Tensorflow should be in consistent with the python interface. You may follow [the instruction](install-tf.2.3.md) to install the corresponding C++ interface. ### Install the DeePMD-kit's C++ interface @@ -175,14 +175,15 @@ DeePMD-kit provide module for running MD simulation with LAMMPS. Now make the De cd $deepmd_source_dir/source/build make lammps ``` -DeePMD-kit will generate a module called `USER-DEEPMD` in the `build` directory. Now download your favorite LAMMPS code, and uncompress it (I assume that you have downloaded the tar `lammps-stable.tar.gz`) +DeePMD-kit will generate a module called `USER-DEEPMD` in the `build` directory. Now download the latest LAMMPS code, and uncompress it: ```bash cd /some/workspace -tar xf lammps-stable.tar.gz +wget https://github.com/lammps/lammps/archive/stable_29Oct2020.tar.gz +tar xf stable_29Oct2020.tar.gz ``` -The source code of LAMMPS is stored in directory, for example `lammps-31Mar17`. Now go into the LAMMPS code and copy the DeePMD-kit module like this +The source code of LAMMPS is stored in directory `lammps-stable_29Oct2020`. Now go into the LAMMPS code and copy the DeePMD-kit module like this ```bash -cd lammps-31Mar17/src/ +cd lammps-stable_29Oct2020/src/ cp -r $deepmd_source_dir/source/build/USER-DEEPMD . ``` Now build LAMMPS @@ -193,6 +194,9 @@ make mpi -j4 The option `-j4` means using 4 processes in parallel. You may want to use a different number according to your hardware. If everything works fine, you will end up with an executable `lmp_mpi`. +```bash +./lmp_mpi -h +``` The DeePMD-kit module can be removed from LAMMPS source code by ```bash From 7ad746f221357b0b4c74c1e64b27ec7ad9c8a12e Mon Sep 17 00:00:00 2001 From: Han Wang Date: Thu, 14 Jan 2021 07:40:24 +0800 Subject: [PATCH 042/562] fix most of the descriptors --- source/api/descrpt_se_a.py | 14 +- source/api/descrpt_se_a_ebd.py | 139 ++++++++++++++++--- source/api/descrpt_se_a_ef.py | 233 ++++++++++++++++++++++++++++---- source/api/descrpt_se_a_t.py | 228 +++++++++++++++++++++++-------- source/api/descrpt_se_ar.py | 2 +- source/api/descrpt_se_r.py | 213 ++++++++++++++++++++++++----- source/api/fitting.py | 3 +- source/tests/test_model_se_r.py | 3 +- source/train/DescrptHybrid.py | 10 +- source/train/Trainer.py | 8 +- source/train/argcheck.py | 2 - 11 files changed, 699 insertions(+), 156 deletions(-) diff --git a/source/api/descrpt_se_a.py b/source/api/descrpt_se_a.py index d5be3ca1a1..235774de9f 100644 --- a/source/api/descrpt_se_a.py +++ b/source/api/descrpt_se_a.py @@ -2,7 +2,7 @@ from typing import Tuple, List from deepmd.env import tf -from deepmd.common import ClassArg, get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter +from deepmd.common import get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter from deepmd.argcheck import list_to_doc from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision @@ -54,6 +54,8 @@ def __init__ (self, Try to build N_types embedding nets. Otherwise, building N_types^2 embedding nets exclude_types : list[int] The Excluded types + set_davg_zero + Set the shift of embedding net input to zero. activation_function The activation function in the embedding net. Supported options are {0} precision @@ -167,7 +169,8 @@ def compute_input_stats (self, data_atype : list, natoms_vec : list, mesh : list, - input_dict : dict) -> None : + input_dict : dict + ) -> None : """ Compute the statisitcs (avg and std) of the training data. The input will be normalized by the statistics. @@ -232,7 +235,8 @@ def build (self, mesh : tf.Tensor, input_dict : dict, reuse : bool = None, - suffix : str = '') -> tf.Tensor: + suffix : str = '' + ) -> tf.Tensor: """ Build the computational graph for the descriptor @@ -253,10 +257,10 @@ def build (self, if size of mesh == 0, no-pbc is assumed. input_dict Dictionary for additional inputs - suffix - Name suffix to identify this descriptor reuse The weights in the networks should be reused when get the variable. + suffix + Name suffix to identify this descriptor Returns ------- diff --git a/source/api/descrpt_se_a_ebd.py b/source/api/descrpt_se_a_ebd.py index 01a32c3ac3..b627f2664f 100644 --- a/source/api/descrpt_se_a_ebd.py +++ b/source/api/descrpt_se_a_ebd.py @@ -1,4 +1,6 @@ import numpy as np +from typing import Tuple, List + from deepmd.env import tf from deepmd.common import ClassArg, get_activation_func, get_precision, add_data_requirement from deepmd.network import one_layer @@ -10,31 +12,128 @@ from deepmd.network import embedding_net class DescrptSeAEbd (DescrptSeA): - def __init__ (self, jdata): - DescrptSeA.__init__(self, jdata) - args = ClassArg()\ - .add('type_nchanl', int, default = 4) \ - .add('type_nlayer', int, default = 2) \ - .add('type_one_side', bool, default = True) \ - .add('numb_aparam', int, default = 0) - class_data = args.parse(jdata) - self.type_nchanl = class_data['type_nchanl'] - self.type_nlayer = class_data['type_nlayer'] - self.type_one_side = class_data['type_one_side'] - self.numb_aparam = class_data['numb_aparam'] + def __init__ (self, + rcut: float, + rcut_smth: float, + sel: List[str], + neuron: List[int] = [24,48,96], + axis_neuron: int = 8, + resnet_dt: bool = False, + trainable: bool = True, + seed: int = 1, + type_one_side: bool = True, + type_nchanl : int = 2, + type_nlayer : int = 1, + numb_aparam : int = 0, + set_davg_zero: bool = False, + activation_function: str = 'tanh', + precision: str = 'default' + ) -> None: + """ + Constructor + + Parameters + ---------- + rcut + The cut-off radius + rcut_smth + From where the environment matrix should be smoothed + sel : list[str] + sel[i] specifies the maxmum number of type i atoms in the cut-off radius + neuron : list[int] + Number of neurons in each hidden layers of the embedding net + axis_neuron + Number of the axis neuron (number of columns of the sub-matrix of the embedding matrix) + resnet_dt + Time-step `dt` in the resnet construction: + y = x + dt * \phi (Wx + b) + trainable + If the weights of embedding net are trainable. + seed + Random seed for initializing the network parameters. + type_one_side + Try to build N_types embedding nets. Otherwise, building N_types^2 embedding nets + type_nchanl + Number of channels for type representation + type_nlayer + Number of hidden layers for the type embedding net (skip connected). + numb_aparam + Number of atomic parameters. If >0 it will be embedded with atom types. + set_davg_zero + Set the shift of embedding net input to zero. + activation_function + The activation function in the embedding net. Supported options are {0} + precision + The precision of the embedding net parameters. Supported options are {1} + """ + # args = ClassArg()\ + # .add('type_nchanl', int, default = 4) \ + # .add('type_nlayer', int, default = 2) \ + # .add('type_one_side', bool, default = True) \ + # .add('numb_aparam', int, default = 0) + # class_data = args.parse(jdata) + DescrptSeA.__init__(self, + rcut, + rcut_smth, + sel, + neuron = neuron, + axis_neuron = axis_neuron, + resnet_dt = resnet_dt, + trainable = trainable, + seed = seed, + type_one_side = type_one_side, + set_davg_zero = set_davg_zero, + activation_function = activation_function, + precision = precision + ) + self.type_nchanl = type_nchanl + self.type_nlayer = type_nlayer + self.type_one_side = type_one_side + self.numb_aparam = numb_aparam if self.numb_aparam > 0: add_data_requirement('aparam', 3, atomic=True, must=True, high_prec=False) def build (self, - coord_, - atype_, - natoms, - box_, - mesh, - input_dict, - suffix = '', - reuse = None): + coord_ : tf.Tensor, + atype_ : tf.Tensor, + natoms : tf.Tensor, + box_ : tf.Tensor, + mesh : tf.Tensor, + input_dict : dict, + reuse : bool = None, + suffix : str = '' + ) -> tf.Tensor: + """ + Build the computational graph for the descriptor + + Parameters + ---------- + coord_ + The coordinate of atoms + atype_ + The type of atoms + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + mesh + For historical reasons, only the length of the Tensor matters. + if size of mesh == 6, pbc is assumed. + if size of mesh == 0, no-pbc is assumed. + input_dict + Dictionary for additional inputs + reuse + The weights in the networks should be reused when get the variable. + suffix + Name suffix to identify this descriptor + + Returns + ------- + descriptor + The output descriptor + """ nei_type = np.array([]) for ii in range(self.ntypes): nei_type = np.append(nei_type, ii * np.ones(self.sel_a[ii])) diff --git a/source/api/descrpt_se_a_ef.py b/source/api/descrpt_se_a_ef.py index e463e47be8..49a0263fbc 100644 --- a/source/api/descrpt_se_a_ef.py +++ b/source/api/descrpt_se_a_ef.py @@ -2,7 +2,8 @@ from typing import Tuple, List from deepmd.env import tf -from deepmd.common import ClassArg, add_data_requirement +from deepmd.common import add_data_requirement,get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter +from deepmd.argcheck import list_to_doc from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module @@ -10,27 +11,132 @@ from deepmd.descrpt_se_a import DescrptSeA class DescrptSeAEf (): - def __init__(self, jdata): - self.descrpt_para = DescrptSeAEfLower(op_module.descrpt_se_a_ef_para, **jdata) - self.descrpt_vert = DescrptSeAEfLower(op_module.descrpt_se_a_ef_vert, **jdata) + @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + def __init__(self, + rcut: float, + rcut_smth: float, + sel: List[str], + neuron: List[int] = [24,48,96], + axis_neuron: int = 8, + resnet_dt: bool = False, + trainable: bool = True, + seed: int = 1, + type_one_side: bool = True, + exclude_types: List[int] = [], + set_davg_zero: bool = False, + activation_function: str = 'tanh', + precision: str = 'default' + ) -> None: + """ + Constructor + + Parameters + ---------- + rcut + The cut-off radius + rcut_smth + From where the environment matrix should be smoothed + sel : list[str] + sel[i] specifies the maxmum number of type i atoms in the cut-off radius + neuron : list[int] + Number of neurons in each hidden layers of the embedding net + axis_neuron + Number of the axis neuron (number of columns of the sub-matrix of the embedding matrix) + resnet_dt + Time-step `dt` in the resnet construction: + y = x + dt * \phi (Wx + b) + trainable + If the weights of embedding net are trainable. + seed + Random seed for initializing the network parameters. + type_one_side + Try to build N_types embedding nets. Otherwise, building N_types^2 embedding nets + exclude_types : list[int] + The Excluded types + set_davg_zero + Set the shift of embedding net input to zero. + activation_function + The activation function in the embedding net. Supported options are {0} + precision + The precision of the embedding net parameters. Supported options are {1} + """ + self.descrpt_para = DescrptSeAEfLower( + op_module.descrpt_se_a_ef_para, + rcut, + rcut_smth, + sel, + neuron, + axis_neuron, + resnet_dt, + trainable, + seed, + type_one_side, + exclude_types, + set_davg_zero, + activation_function, + precision, + ) + self.descrpt_vert = DescrptSeAEfLower( + op_module.descrpt_se_a_ef_vert, + rcut, + rcut_smth, + sel, + neuron, + axis_neuron, + resnet_dt, + trainable, + seed, + type_one_side, + exclude_types, + set_davg_zero, + activation_function, + precision, + ) - def get_rcut (self) : + def get_rcut (self) -> float: + """ + Returns the cut-off radisu + """ return self.descrpt_vert.rcut_r - def get_ntypes (self) : + def get_ntypes (self) -> int: + """ + Returns the number of atom types + """ return self.descrpt_vert.ntypes - def get_dim_out (self) : + def get_dim_out (self) -> int: + """ + Returns the output dimension of this descriptor + """ return self.descrpt_vert.get_dim_out() + self.descrpt_para.get_dim_out() - def get_dim_rot_mat_1 (self) : + def get_dim_rot_mat_1 (self) -> int: + """ + Returns the first dimension of the rotation matrix. The rotation is of shape dim_1 x 3 + """ return self.descrpt_vert.filter_neuron[-1] - def get_rot_mat(self) : + def get_rot_mat(self) -> tf.Tensor: + """ + Get rotational matrix + """ return self.qmat - def get_nlist (self) : + def get_nlist (self) -> Tuple[tf.Tensor, tf.Tensor, List[int], List[int]]: + """ + Returns + ------- + nlist + Neighbor list + rij + The relative distance between the neighbor and the center atom. + sel_a + The number of neighbors with full information + sel_r + The number of neighbors with only radial information + """ return \ self.descrpt_vert.nlist, \ self.descrpt_vert.rij, \ @@ -38,24 +144,74 @@ def get_nlist (self) : self.descrpt_vert.sel_r def compute_input_stats (self, - data_coord, - data_box, - data_atype, - natoms_vec, - mesh, - input_dict) : + data_coord : list, + data_box : list, + data_atype : list, + natoms_vec : list, + mesh : list, + input_dict : dict + ) -> None : + """ + Compute the statisitcs (avg and std) of the training data. The input will be normalized by the statistics. + + Parameters + ---------- + data_coord + The coordinates. Can be generated by deepmd.model.make_stat_input + data_box + The box. Can be generated by deepmd.model.make_stat_input + data_atype + The atom types. Can be generated by deepmd.model.make_stat_input + natoms_vec + The vector for the number of atoms of the system and different types of atoms. Can be generated by deepmd.model.make_stat_input + mesh + The mesh for neighbor searching. Can be generated by deepmd.model.make_stat_input + input_dict + Dictionary for additional input + """ self.descrpt_vert.compute_input_stats(data_coord, data_box, data_atype, natoms_vec, mesh, input_dict) self.descrpt_para.compute_input_stats(data_coord, data_box, data_atype, natoms_vec, mesh, input_dict) def build (self, - coord_, - atype_, - natoms, - box_, - mesh, - input_dict, - suffix = '', - reuse = None): + coord_ : tf.Tensor, + atype_ : tf.Tensor, + natoms : tf.Tensor, + box_ : tf.Tensor, + mesh : tf.Tensor, + input_dict : dict, + reuse : bool = None, + suffix : str = '' + ) -> tf.Tensor: + """ + Build the computational graph for the descriptor + + Parameters + ---------- + coord_ + The coordinate of atoms + atype_ + The type of atoms + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + mesh + For historical reasons, only the length of the Tensor matters. + if size of mesh == 6, pbc is assumed. + if size of mesh == 0, no-pbc is assumed. + input_dict + Dictionary for additional inputs. Should have 'efield'. + reuse + The weights in the networks should be reused when get the variable. + suffix + Name suffix to identify this descriptor + + Returns + ------- + descriptor + The output descriptor + """ self.dout_vert = self.descrpt_vert.build(coord_, atype_, natoms, box_, mesh, input_dict) self.dout_para = self.descrpt_para.build(coord_, atype_, natoms, box_, mesh, input_dict, reuse = True) coord = tf.reshape(coord_, [-1, natoms[1] * 3]) @@ -70,7 +226,31 @@ def build (self, return self.dout - def prod_force_virial(self, atom_ener, natoms) : + def prod_force_virial(self, + atom_ener : tf.Tensor, + natoms : tf.Tensor + ) -> Tuple[tf.Tensor, tf.Tensor, tf.Tensor]: + """ + Compute force and virial + + Parameters + ---------- + atom_ener + The atomic energy + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + Return + ------ + force + The force on atoms + virial + The total virial + atom_virial + The atomic virial + """ f_vert, v_vert, av_vert \ = self.descrpt_vert.prod_force_virial(atom_ener, natoms) f_para, v_para, av_para \ @@ -82,6 +262,9 @@ def prod_force_virial(self, atom_ener, natoms) : class DescrptSeAEfLower (DescrptSeA): + """ + Helper class for implementing DescrptSeAEf + """ def __init__ (self, op, rcut: float, diff --git a/source/api/descrpt_se_a_t.py b/source/api/descrpt_se_a_t.py index 3cb54b26e2..eaf1f54170 100644 --- a/source/api/descrpt_se_a_t.py +++ b/source/api/descrpt_se_a_t.py @@ -1,6 +1,9 @@ import numpy as np +from typing import Tuple, List + from deepmd.env import tf -from deepmd.common import ClassArg, get_activation_func, get_precision +from deepmd.common import get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter +from deepmd.argcheck import list_to_doc from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module @@ -8,36 +11,61 @@ from deepmd.network import embedding_net class DescrptSeAT (): - def __init__ (self, jdata): - args = ClassArg()\ - .add('sel', list, must = True) \ - .add('rcut', float, default = 6.0) \ - .add('rcut_smth',float, default = 0.5) \ - .add('neuron', list, default = [10, 20, 40]) \ - .add('resnet_dt',bool, default = False) \ - .add('trainable',bool, default = True) \ - .add('seed', int) \ - .add('exclude_types', list, default = []) \ - .add('set_davg_zero', bool, default = False) \ - .add('activation_function', str, default = 'tanh') \ - .add('precision', str, default = "default") - class_data = args.parse(jdata) - self.sel_a = class_data['sel'] - self.rcut_r = class_data['rcut'] - self.rcut_r_smth = class_data['rcut_smth'] - self.filter_neuron = class_data['neuron'] - self.filter_resnet_dt = class_data['resnet_dt'] - self.seed = class_data['seed'] - self.trainable = class_data['trainable'] - self.filter_activation_fn = get_activation_func(class_data['activation_function']) - self.filter_precision = get_precision(class_data['precision']) - exclude_types = class_data['exclude_types'] - self.exclude_types = set() - for tt in exclude_types: - assert(len(tt) == 2) - self.exclude_types.add((tt[0], tt[1])) - self.exclude_types.add((tt[1], tt[0])) - self.set_davg_zero = class_data['set_davg_zero'] + @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + def __init__ (self, + rcut: float, + rcut_smth: float, + sel: List[str], + neuron: List[int] = [24,48,96], + resnet_dt: bool = False, + trainable: bool = True, + seed: int = 1, + set_davg_zero: bool = False, + activation_function: str = 'tanh', + precision: str = 'default' + ) -> None: + """ + Constructor + + Parameters + ---------- + rcut + The cut-off radius + rcut_smth + From where the environment matrix should be smoothed + sel : list[str] + sel[i] specifies the maxmum number of type i atoms in the cut-off radius + neuron : list[int] + Number of neurons in each hidden layers of the embedding net + resnet_dt + Time-step `dt` in the resnet construction: + y = x + dt * \phi (Wx + b) + trainable + If the weights of embedding net are trainable. + seed + Random seed for initializing the network parameters. + set_davg_zero + Set the shift of embedding net input to zero. + activation_function + The activation function in the embedding net. Supported options are {0} + precision + The precision of the embedding net parameters. Supported options are {1} + """ + self.sel_a = sel + self.rcut_r = rcut + self.rcut_r_smth = rcut_smth + self.filter_neuron = neuron + self.filter_resnet_dt = resnet_dt + self.seed = seed + self.trainable = trainable + self.filter_activation_fn = get_activation_func(activation_function) + self.filter_precision = get_precision(precision) + # self.exclude_types = set() + # for tt in exclude_types: + # assert(len(tt) == 2) + # self.exclude_types.add((tt[0], tt[1])) + # self.exclude_types.add((tt[1], tt[0])) + self.set_davg_zero = set_davg_zero # descrpt config self.sel_r = [ 0 for ii in range(len(self.sel_a)) ] @@ -82,28 +110,65 @@ def __init__ (self, jdata): self.sub_sess = tf.Session(graph = sub_graph, config=default_tf_session_config) - def get_rcut (self) : + def get_rcut (self) -> float: + """ + Returns the cut-off radisu + """ return self.rcut_r - def get_ntypes (self) : + def get_ntypes (self) -> int: + """ + Returns the number of atom types + """ return self.ntypes - def get_dim_out (self) : - return self.filter_neuron[-1] - - def get_dim_rot_mat_1 (self) : + def get_dim_out (self) -> int: + """ + Returns the output dimension of this descriptor + """ return self.filter_neuron[-1] - def get_nlist (self) : + def get_nlist (self) -> Tuple[tf.Tensor, tf.Tensor, List[int], List[int]]: + """ + Returns + ------- + nlist + Neighbor list + rij + The relative distance between the neighbor and the center atom. + sel_a + The number of neighbors with full information + sel_r + The number of neighbors with only radial information + """ return self.nlist, self.rij, self.sel_a, self.sel_r def compute_input_stats (self, - data_coord, - data_box, - data_atype, - natoms_vec, - mesh, - input_dict) : + data_coord : list, + data_box : list, + data_atype : list, + natoms_vec : list, + mesh : list, + input_dict : dict + ) -> None : + """ + Compute the statisitcs (avg and std) of the training data. The input will be normalized by the statistics. + + Parameters + ---------- + data_coord + The coordinates. Can be generated by deepmd.model.make_stat_input + data_box + The box. Can be generated by deepmd.model.make_stat_input + data_atype + The atom types. Can be generated by deepmd.model.make_stat_input + natoms_vec + The vector for the number of atoms of the system and different types of atoms. Can be generated by deepmd.model.make_stat_input + mesh + The mesh for neighbor searching. Can be generated by deepmd.model.make_stat_input + input_dict + Dictionary for additional input + """ all_davg = [] all_dstd = [] if True: @@ -143,14 +208,45 @@ def compute_input_stats (self, def build (self, - coord_, - atype_, - natoms, - box_, - mesh, - input_dict, - suffix = '', - reuse = None): + coord_ : tf.Tensor, + atype_ : tf.Tensor, + natoms : tf.Tensor, + box_ : tf.Tensor, + mesh : tf.Tensor, + input_dict : dict, + reuse : bool = None, + suffix : str = '' + ) -> tf.Tensor: + """ + Build the computational graph for the descriptor + + Parameters + ---------- + coord_ + The coordinate of atoms + atype_ + The type of atoms + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + mesh + For historical reasons, only the length of the Tensor matters. + if size of mesh == 6, pbc is assumed. + if size of mesh == 0, no-pbc is assumed. + input_dict + Dictionary for additional inputs + reuse + The weights in the networks should be reused when get the variable. + suffix + Name suffix to identify this descriptor + + Returns + ------- + descriptor + The output descriptor + """ davg = self.davg dstd = self.dstd with tf.variable_scope('descrpt_attr' + suffix, reuse = reuse) : @@ -215,12 +311,32 @@ def build (self, return self.dout - - def get_rot_mat(self) : - return self.qmat + def prod_force_virial(self, + atom_ener : tf.Tensor, + natoms : tf.Tensor + ) -> Tuple[tf.Tensor, tf.Tensor, tf.Tensor]: + """ + Compute force and virial - def prod_force_virial(self, atom_ener, natoms) : + Parameters + ---------- + atom_ener + The atomic energy + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + Return + ------ + force + The force on atoms + virial + The total virial + atom_virial + The atomic virial + """ [net_deriv] = tf.gradients (atom_ener, self.descrpt_reshape) net_deriv_reshape = tf.reshape (net_deriv, [-1, natoms[0] * self.ndescrpt]) force \ diff --git a/source/api/descrpt_se_ar.py b/source/api/descrpt_se_ar.py index 66bd3c5cd5..935110a1a0 100644 --- a/source/api/descrpt_se_ar.py +++ b/source/api/descrpt_se_ar.py @@ -15,7 +15,7 @@ def __init__ (self, jdata): self.param_a = class_data['a'] self.param_r = class_data['r'] self.descrpt_a = DescrptSeA(**self.param_a) - self.descrpt_r = DescrptSeR(self.param_r) + self.descrpt_r = DescrptSeR(**self.param_r) assert(self.descrpt_a.get_ntypes() == self.descrpt_r.get_ntypes()) self.davg = None self.dstd = None diff --git a/source/api/descrpt_se_r.py b/source/api/descrpt_se_r.py index 218a81fb60..ad2f5b5051 100644 --- a/source/api/descrpt_se_r.py +++ b/source/api/descrpt_se_r.py @@ -1,6 +1,9 @@ import numpy as np +from typing import Tuple, List + from deepmd.env import tf -from deepmd.common import ClassArg, get_activation_func, get_precision +from deepmd.common import get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter +from deepmd.argcheck import list_to_doc from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module @@ -8,38 +11,80 @@ from deepmd.network import embedding_net class DescrptSeR (): - def __init__ (self, jdata): - args = ClassArg()\ - .add('sel', list, must = True) \ - .add('rcut', float, default = 6.0) \ - .add('rcut_smth',float, default = 0.5) \ - .add('neuron', list, default = [10, 20, 40]) \ - .add('resnet_dt',bool, default = False) \ - .add('trainable',bool, default = True) \ - .add('seed', int) \ - .add('type_one_side', bool, default = False) \ - .add('exclude_types', list, default = []) \ - .add('set_davg_zero', bool, default = False) \ - .add("activation_function", str, default = "tanh") \ - .add("precision", str, default = "default") - class_data = args.parse(jdata) - self.sel_r = class_data['sel'] - self.rcut = class_data['rcut'] - self.rcut_smth = class_data['rcut_smth'] - self.filter_neuron = class_data['neuron'] - self.filter_resnet_dt = class_data['resnet_dt'] - self.seed = class_data['seed'] - self.trainable = class_data['trainable'] - self.filter_activation_fn = get_activation_func(class_data["activation_function"]) - self.filter_precision = get_precision(class_data['precision']) - exclude_types = class_data['exclude_types'] + @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + def __init__ (self, + rcut: float, + rcut_smth: float, + sel: List[str], + neuron: List[int] = [24,48,96], + resnet_dt: bool = False, + trainable: bool = True, + seed: int = 1, + type_one_side: bool = True, + exclude_types: List[int] = [], + set_davg_zero: bool = False, + activation_function: str = 'tanh', + precision: str = 'default'): + """ + Constructor + + Parameters + ---------- + rcut + The cut-off radius + rcut_smth + From where the environment matrix should be smoothed + sel : list[str] + sel[i] specifies the maxmum number of type i atoms in the cut-off radius + neuron : list[int] + Number of neurons in each hidden layers of the embedding net + resnet_dt + Time-step `dt` in the resnet construction: + y = x + dt * \phi (Wx + b) + trainable + If the weights of embedding net are trainable. + seed + Random seed for initializing the network parameters. + type_one_side + Try to build N_types embedding nets. Otherwise, building N_types^2 embedding nets + exclude_types : list[int] + The Excluded types + activation_function + The activation function in the embedding net. Supported options are {0} + precision + The precision of the embedding net parameters. Supported options are {1} + """ + # args = ClassArg()\ + # .add('sel', list, must = True) \ + # .add('rcut', float, default = 6.0) \ + # .add('rcut_smth',float, default = 0.5) \ + # .add('neuron', list, default = [10, 20, 40]) \ + # .add('resnet_dt',bool, default = False) \ + # .add('trainable',bool, default = True) \ + # .add('seed', int) \ + # .add('type_one_side', bool, default = False) \ + # .add('exclude_types', list, default = []) \ + # .add('set_davg_zero', bool, default = False) \ + # .add("activation_function", str, default = "tanh") \ + # .add("precision", str, default = "default") + # class_data = args.parse(jdata) + self.sel_r = sel + self.rcut = rcut + self.rcut_smth = rcut_smth + self.filter_neuron = neuron + self.filter_resnet_dt = resnet_dt + self.seed = seed + self.trainable = trainable + self.filter_activation_fn = get_activation_func(activation_function) + self.filter_precision = get_precision(precision) + exclude_types = exclude_types self.exclude_types = set() for tt in exclude_types: assert(len(tt) == 2) self.exclude_types.add((tt[0], tt[1])) self.exclude_types.add((tt[1], tt[0])) - self.set_davg_zero = class_data['set_davg_zero'] - self.type_one_side = class_data['type_one_side'] + self.set_davg_zero = set_davg_zero + self.type_one_side = type_one_side # descrpt config self.sel_a = [ 0 for ii in range(len(self.sel_r)) ] @@ -81,15 +126,36 @@ def __init__ (self, jdata): def get_rcut (self) : + """ + Returns the cut-off radisu + """ return self.rcut def get_ntypes (self) : + """ + Returns the number of atom types + """ return self.ntypes def get_dim_out (self) : + """ + Returns the output dimension of this descriptor + """ return self.filter_neuron[-1] def get_nlist (self) : + """ + Returns + ------- + nlist + Neighbor list + rij + The relative distance between the neighbor and the center atom. + sel_a + The number of neighbors with full information + sel_r + The number of neighbors with only radial information + """ return self.nlist, self.rij, self.sel_a, self.sel_r def compute_input_stats (self, @@ -99,6 +165,24 @@ def compute_input_stats (self, natoms_vec, mesh, input_dict) : + """ + Compute the statisitcs (avg and std) of the training data. The input will be normalized by the statistics. + + Parameters + ---------- + data_coord + The coordinates. Can be generated by deepmd.model.make_stat_input + data_box + The box. Can be generated by deepmd.model.make_stat_input + data_atype + The atom types. Can be generated by deepmd.model.make_stat_input + natoms_vec + The vector for the number of atoms of the system and different types of atoms. Can be generated by deepmd.model.make_stat_input + mesh + The mesh for neighbor searching. Can be generated by deepmd.model.make_stat_input + input_dict + Dictionary for additional input + """ all_davg = [] all_dstd = [] sumr = [] @@ -127,14 +211,45 @@ def compute_input_stats (self, def build (self, - coord_, - atype_, - natoms, - box_, - mesh, - input_dict, - suffix = '', - reuse = None): + coord_ : tf.Tensor, + atype_ : tf.Tensor, + natoms : tf.Tensor, + box_ : tf.Tensor, + mesh : tf.Tensor, + input_dict : dict, + reuse : bool = None, + suffix : str = '' + ) -> tf.Tensor: + """ + Build the computational graph for the descriptor + + Parameters + ---------- + coord_ + The coordinate of atoms + atype_ + The type of atoms + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + mesh + For historical reasons, only the length of the Tensor matters. + if size of mesh == 6, pbc is assumed. + if size of mesh == 0, no-pbc is assumed. + input_dict + Dictionary for additional inputs + reuse + The weights in the networks should be reused when get the variable. + suffix + Name suffix to identify this descriptor + + Returns + ------- + descriptor + The output descriptor + """ davg = self.davg dstd = self.dstd with tf.variable_scope('descrpt_attr' + suffix, reuse = reuse) : @@ -198,7 +313,31 @@ def build (self, return self.dout - def prod_force_virial(self, atom_ener, natoms) : + def prod_force_virial(self, + atom_ener : tf.Tensor, + natoms : tf.Tensor + ) -> Tuple[tf.Tensor, tf.Tensor, tf.Tensor]: + """ + Compute force and virial + + Parameters + ---------- + atom_ener + The atomic energy + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + Return + ------ + force + The force on atoms + virial + The total virial + atom_virial + The atomic virial + """ [net_deriv] = tf.gradients (atom_ener, self.descrpt_reshape) tf.summary.histogram('net_derivative', net_deriv) net_deriv_reshape = tf.reshape (net_deriv, [-1, natoms[0] * self.ndescrpt]) diff --git a/source/api/fitting.py b/source/api/fitting.py index 24dc6bd07b..9e27ae5ed0 100644 --- a/source/api/fitting.py +++ b/source/api/fitting.py @@ -215,7 +215,8 @@ def build (self, natoms : tf.Tensor, input_dict : dict = {}, reuse : bool = None, - suffix : str = '') -> tf.Tensor: + suffix : str = '' + ) -> tf.Tensor: """ Build the computational graph for fitting net diff --git a/source/tests/test_model_se_r.py b/source/tests/test_model_se_r.py index 1bf16cde6c..fa0a594199 100644 --- a/source/tests/test_model_se_r.py +++ b/source/tests/test_model_se_r.py @@ -37,7 +37,8 @@ def test_model(self): test_data = data.get_test () numb_test = 1 - descrpt = DescrptSeR(jdata['model']['descriptor']) + jdata['model']['descriptor'].pop('type', None) + descrpt = DescrptSeR(**jdata['model']['descriptor']) jdata['model']['fitting_net']['descrpt'] = descrpt fitting = EnerFitting(**jdata['model']['fitting_net']) # fitting = EnerFitting(jdata['model']['fitting_net'], descrpt) diff --git a/source/train/DescrptHybrid.py b/source/train/DescrptHybrid.py index 9df7026bbd..4126959d98 100644 --- a/source/train/DescrptHybrid.py +++ b/source/train/DescrptHybrid.py @@ -22,18 +22,20 @@ def __init__ (self, jdata): self.descrpt_type = [] for ii in dict_list: this_type = ii.get('type') + ii.pop('type', None) + ii.pop('_comment', None) if this_type == 'loc_frame': this_descrpt = DescrptLocFrame(ii) elif this_type == 'se_a' : this_descrpt = DescrptSeA(**ii) elif this_type == 'se_at' : - this_descrpt = DescrptSeAT(ii) + this_descrpt = DescrptSeAT(**ii) elif this_type == 'se_a_ebd' : - this_descrpt = DescrptSeAEbd(ii) + this_descrpt = DescrptSeAEbd(**ii) elif this_type == 'se_a_ef' : - this_descrpt = DescrptSeAEf(ii) + this_descrpt = DescrptSeAEf(**ii) elif this_type == 'se_r' : - this_descrpt = DescrptSeR(ii) + this_descrpt = DescrptSeR(**ii) else : raise RuntimeError('unknow model type ' + this_type) self.descrpt_list.append(this_descrpt) diff --git a/source/train/Trainer.py b/source/train/Trainer.py index e31bcabf9f..3d6af33141 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -66,13 +66,13 @@ def _init_param(self, jdata): elif descrpt_type == 'se_a' : self.descrpt = DescrptSeA(**descrpt_param) elif descrpt_type == 'se_a_3be' or descrpt_type == 'se_at' : - self.descrpt = DescrptSeAT(descrpt_param) + self.descrpt = DescrptSeAT(**descrpt_param) elif descrpt_type == 'se_a_tpe' or descrpt_type == 'se_a_ebd' : - self.descrpt = DescrptSeAEbd(descrpt_param) + self.descrpt = DescrptSeAEbd(**descrpt_param) elif descrpt_type == 'se_a_ef' : - self.descrpt = DescrptSeAEf(descrpt_param) + self.descrpt = DescrptSeAEf(**descrpt_param) elif descrpt_type == 'se_r' : - self.descrpt = DescrptSeR(descrpt_param) + self.descrpt = DescrptSeR(**descrpt_param) elif descrpt_type == 'se_ar' : self.descrpt = DescrptSeAR(descrpt_param) elif descrpt_type == 'hybrid' : diff --git a/source/train/argcheck.py b/source/train/argcheck.py index c7d6fae16c..74cf886fa6 100644 --- a/source/train/argcheck.py +++ b/source/train/argcheck.py @@ -78,7 +78,6 @@ def descrpt_se_a_3be_args(): doc_precision = f'The precision of the embedding net parameters, supported options are {list_to_doc(precision_dict.keys())}' doc_trainable = 'If the parameters in the embedding net is trainable' doc_seed = 'Random seed for parameter initialization' - doc_exclude_types = 'The Excluded types' doc_set_davg_zero = 'Set the normalization average to zero. This option should be set when `atom_ener` in the energy fitting is used' return [ @@ -91,7 +90,6 @@ def descrpt_se_a_3be_args(): Argument("precision", str, optional = True, default = "float64", doc = doc_precision), Argument("trainable", bool, optional = True, default = True, doc = doc_trainable), Argument("seed", [int,None], optional = True, doc = doc_seed), - Argument("exclude_types", list, optional = True, default = [], doc = doc_exclude_types), Argument("set_davg_zero", bool, optional = True, default = False, doc = doc_set_davg_zero) ] From 1cac7cf8545f06eb4969859690c9ab75824bda39 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Thu, 14 Jan 2021 08:26:23 -0500 Subject: [PATCH 043/562] Update install.md --- doc/install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install.md b/doc/install.md index 4715121db3..ebbf7c2989 100644 --- a/doc/install.md +++ b/doc/install.md @@ -175,7 +175,7 @@ DeePMD-kit provide module for running MD simulation with LAMMPS. Now make the De cd $deepmd_source_dir/source/build make lammps ``` -DeePMD-kit will generate a module called `USER-DEEPMD` in the `build` directory. Now download the latest LAMMPS code, and uncompress it: +DeePMD-kit will generate a module called `USER-DEEPMD` in the `build` directory. Now download the LAMMPS code (`29Oct2020` or later), and uncompress it: ```bash cd /some/workspace wget https://github.com/lammps/lammps/archive/stable_29Oct2020.tar.gz From a9ff2b65551584ef43e38834aed58c583451ab9a Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 15 Jan 2021 23:04:18 +0800 Subject: [PATCH 044/562] add descrpt hybrid and loc_frame --- source/api/descrpt_hybrid.py | 209 ++++++++++++++++++ .../descrpt_loc_frame.py} | 192 +++++++++++++--- source/api/descrpt_se_a.py | 2 +- source/api/descrpt_se_ar.py | 7 +- source/api/fitting.py | 2 +- source/tests/test_descrpt_nonsmth.py | 2 +- source/tests/test_descrpt_se_r.py | 2 +- source/tests/test_descrpt_sea_ef.py | 2 +- source/tests/test_descrpt_sea_ef_para.py | 2 +- source/tests/test_descrpt_sea_ef_vert.py | 2 +- source/tests/test_descrpt_smooth.py | 2 +- source/tests/test_model_loc_frame.py | 6 +- source/tests/test_tab_nonsmth.py | 2 +- source/tests/test_tab_smooth.py | 2 +- source/tests/test_wfc.py | 6 +- source/train/DataModifier.py | 4 +- source/train/DescrptHybrid.py | 115 ---------- source/train/Trainer.py | 64 ++++-- 18 files changed, 436 insertions(+), 187 deletions(-) create mode 100644 source/api/descrpt_hybrid.py rename source/{train/DescrptLocFrame.py => api/descrpt_loc_frame.py} (58%) delete mode 100644 source/train/DescrptHybrid.py diff --git a/source/api/descrpt_hybrid.py b/source/api/descrpt_hybrid.py new file mode 100644 index 0000000000..64993cc6d1 --- /dev/null +++ b/source/api/descrpt_hybrid.py @@ -0,0 +1,209 @@ +import numpy as np +from typing import Tuple, List + +from deepmd.env import tf +from deepmd.common import ClassArg +from deepmd.env import op_module +from deepmd.RunOptions import global_tf_float_precision +from deepmd.RunOptions import global_np_float_precision +from deepmd.descrpt_loc_frame import DescrptLocFrame +from deepmd.descrpt_se_a import DescrptSeA +from deepmd.descrpt_se_a_t import DescrptSeAT +from deepmd.descrpt_se_a_ebd import DescrptSeAEbd +from deepmd.descrpt_se_a_ef import DescrptSeAEf +from deepmd.descrpt_se_r import DescrptSeR + +class DescrptHybrid (): + def __init__ (self, + descrpt_list : list + ) -> None : + """ + Constructor + + Parameters + ---------- + descrpt_list : list + Build a descriptor from the concatenation of the list of descriptors. + """ + if descrpt_list == [] or descrpt_list is None: + raise RuntimeError('cannot build descriptor from an empty list of descriptors.') + # args = ClassArg()\ + # .add('list', list, must = True) + # class_data = args.parse(jdata) + # dict_list = class_data['list'] + self.descrpt_list = descrpt_list + self.numb_descrpt = len(self.descrpt_list) + for ii in range(1, self.numb_descrpt): + assert(self.descrpt_list[ii].get_ntypes() == + self.descrpt_list[ 0].get_ntypes()), \ + f'number of atom types in {ii}th descrptor does not match others' + + + def get_rcut (self) -> float: + """ + Returns the cut-off radius + """ + all_rcut = [ii.get_rcut() for ii in self.descrpt_list] + return np.max(all_rcut) + + + def get_ntypes (self) -> int: + """ + Returns the number of atom types + """ + return self.descrpt_list[0].get_ntypes() + + + def get_dim_out (self) -> int: + """ + Returns the output dimension of this descriptor + """ + all_dim_out = [ii.get_dim_out() for ii in self.descrpt_list] + return sum(all_dim_out) + + + def get_nlist_i(self, + ii : int + ) -> Tuple[tf.Tensor, tf.Tensor, List[int], List[int]]: + """ + Parameters + ---------- + ii : int + Get the neighbor information of the ii-th descriptor + Returns + ------- + nlist + Neighbor list + rij + The relative distance between the neighbor and the center atom. + sel_a + The number of neighbors with full information + sel_r + The number of neighbors with only radial information + """ + return self.descrpt_list[ii].nlist, self.descrpt_list[ii].rij, self.descrpt_list[ii].sel_a, self.descrpt_list[ii].sel_r + + + def compute_input_stats (self, + data_coord : list, + data_box : list, + data_atype : list, + natoms_vec : list, + mesh : list, + input_dict : dict + ) -> None : + """ + Compute the statisitcs (avg and std) of the training data. The input will be normalized by the statistics. + + Parameters + ---------- + data_coord + The coordinates. Can be generated by deepmd.model.make_stat_input + data_box + The box. Can be generated by deepmd.model.make_stat_input + data_atype + The atom types. Can be generated by deepmd.model.make_stat_input + natoms_vec + The vector for the number of atoms of the system and different types of atoms. Can be generated by deepmd.model.make_stat_input + mesh + The mesh for neighbor searching. Can be generated by deepmd.model.make_stat_input + input_dict + Dictionary for additional input + """ + for ii in self.descrpt_list: + ii.compute_input_stats(data_coord, data_box, data_atype, natoms_vec, mesh, input_dict) + + + def build (self, + coord_ : tf.Tensor, + atype_ : tf.Tensor, + natoms : tf.Tensor, + box_ : tf.Tensor, + mesh : tf.Tensor, + input_dict : dict, + reuse : bool = None, + suffix : str = '' + ) -> tf.Tensor: + """ + Build the computational graph for the descriptor + + Parameters + ---------- + coord_ + The coordinate of atoms + atype_ + The type of atoms + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + mesh + For historical reasons, only the length of the Tensor matters. + if size of mesh == 6, pbc is assumed. + if size of mesh == 0, no-pbc is assumed. + input_dict + Dictionary for additional inputs + reuse + The weights in the networks should be reused when get the variable. + suffix + Name suffix to identify this descriptor + + Returns + ------- + descriptor + The output descriptor + """ + with tf.variable_scope('descrpt_attr' + suffix, reuse = reuse) : + t_rcut = tf.constant(self.get_rcut(), + name = 'rcut', + dtype = global_tf_float_precision) + t_ntypes = tf.constant(self.get_ntypes(), + name = 'ntypes', + dtype = tf.int32) + all_dout = [] + for idx,ii in enumerate(self.descrpt_list): + dout = ii.build(coord_, atype_, natoms, box_, mesh, input_dict, suffix=suffix+f'_{idx}', reuse=reuse) + dout = tf.reshape(dout, [-1, ii.get_dim_out()]) + all_dout.append(dout) + dout = tf.concat(all_dout, axis = 1) + dout = tf.reshape(dout, [-1, natoms[0] * self.get_dim_out()]) + return dout + + + def prod_force_virial(self, + atom_ener : tf.Tensor, + natoms : tf.Tensor + ) -> Tuple[tf.Tensor, tf.Tensor, tf.Tensor]: + """ + Compute force and virial + + Parameters + ---------- + atom_ener + The atomic energy + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + Return + ------ + force + The force on atoms + virial + The total virial + atom_virial + The atomic virial + """ + for idx,ii in enumerate(self.descrpt_list): + ff, vv, av = ii.prod_force_virial(atom_ener, natoms) + if idx == 0: + force = ff + virial = vv + atom_virial = av + else: + force += ff + virial += vv + atom_virial += av + return force, virial, atom_virial diff --git a/source/train/DescrptLocFrame.py b/source/api/descrpt_loc_frame.py similarity index 58% rename from source/train/DescrptLocFrame.py rename to source/api/descrpt_loc_frame.py index e7a4d5c1ad..f841004e98 100644 --- a/source/train/DescrptLocFrame.py +++ b/source/api/descrpt_loc_frame.py @@ -1,23 +1,53 @@ import numpy as np +from typing import Tuple, List + from deepmd.env import tf -from deepmd.common import ClassArg from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module from deepmd.env import default_tf_session_config class DescrptLocFrame () : - def __init__(self, jdata): - args = ClassArg()\ - .add('sel_a', list, must = True) \ - .add('sel_r', list, must = True) \ - .add('rcut', float, default = 6.0) \ - .add('axis_rule',list, must = True) - class_data = args.parse(jdata) - self.sel_a = class_data['sel_a'] - self.sel_r = class_data['sel_r'] - self.axis_rule = class_data['axis_rule'] - self.rcut_r = class_data['rcut'] + def __init__(self, + rcut: float, + sel_a : List[int], + sel_r : List[int], + axis_rule : List[int] + ) -> None: + """ + Constructor + + Parameters + rcut + The cut-off radius + sel_a : list[str] + The length of the list should be the same as the number of atom types in the system. + `sel_a[i]` gives the selected number of type-i neighbors. + The full relative coordinates of the neighbors are used by the descriptor. + sel_r : list[str] + The length of the list should be the same as the number of atom types in the system. + `sel_r[i]` gives the selected number of type-i neighbors. + Only relative distance of the neighbors are used by the descriptor. + sel_a[i] + sel_r[i] is recommended to be larger than the maximally possible number of type-i neighbors in the cut-off radius. + axis_rule: list[int] + The length should be 6 times of the number of types. + - axis_rule[i*6+0]: class of the atom defining the first axis of type-i atom. 0 for neighbors with full coordinates and 1 for neighbors only with relative distance.\n\n\ + - axis_rule[i*6+1]: type of the atom defining the first axis of type-i atom.\n\n\ + - axis_rule[i*6+2]: index of the axis atom defining the first axis. Note that the neighbors with the same class and type are sorted according to their relative distance.\n\n\ + - axis_rule[i*6+3]: class of the atom defining the first axis of type-i atom. 0 for neighbors with full coordinates and 1 for neighbors only with relative distance.\n\n\ + - axis_rule[i*6+4]: type of the atom defining the second axis of type-i atom.\n\n\ + - axis_rule[i*6+5]: class of the atom defining the second axis of type-i atom. 0 for neighbors with full coordinates and 1 for neighbors only with relative distance. + """ + # args = ClassArg()\ + # .add('sel_a', list, must = True) \ + # .add('sel_r', list, must = True) \ + # .add('rcut', float, default = 6.0) \ + # .add('axis_rule',list, must = True) + # class_data = args.parse(jdata) + self.sel_a = sel_a + self.sel_r = sel_r + self.axis_rule = axis_rule + self.rcut_r = rcut # ntypes and rcut_a === -1 self.ntypes = len(self.sel_a) assert(self.ntypes == len(self.sel_r)) @@ -59,25 +89,65 @@ def __init__(self, jdata): self.sub_sess = tf.Session(graph = sub_graph, config=default_tf_session_config) - def get_rcut (self) : + def get_rcut (self) -> float: + """ + Returns the cut-off radisu + """ return self.rcut_r - def get_ntypes (self) : + def get_ntypes (self) -> int: + """ + Returns the number of atom types + """ return self.ntypes - def get_dim_out (self) : + def get_dim_out (self) -> int: + """ + Returns the output dimension of this descriptor + """ return self.ndescrpt - def get_nlist (self) : + def get_nlist (self) -> Tuple[tf.Tensor, tf.Tensor, List[int], List[int]]: + """ + Returns + ------- + nlist + Neighbor list + rij + The relative distance between the neighbor and the center atom. + sel_a + The number of neighbors with full information + sel_r + The number of neighbors with only radial information + """ return self.nlist, self.rij, self.sel_a, self.sel_r def compute_input_stats (self, - data_coord, - data_box, - data_atype, - natoms_vec, - mesh, - input_dict) : + data_coord : list, + data_box : list, + data_atype : list, + natoms_vec : list, + mesh : list, + input_dict : dict + ) -> None : + """ + Compute the statisitcs (avg and std) of the training data. The input will be normalized by the statistics. + + Parameters + ---------- + data_coord + The coordinates. Can be generated by deepmd.model.make_stat_input + data_box + The box. Can be generated by deepmd.model.make_stat_input + data_atype + The atom types. Can be generated by deepmd.model.make_stat_input + natoms_vec + The vector for the number of atoms of the system and different types of atoms. Can be generated by deepmd.model.make_stat_input + mesh + The mesh for neighbor searching. Can be generated by deepmd.model.make_stat_input + input_dict + Dictionary for additional input + """ all_davg = [] all_dstd = [] if True: @@ -106,14 +176,45 @@ def compute_input_stats (self, def build (self, - coord_, - atype_, - natoms, - box_, - mesh, - input_dict, - suffix = '', - reuse = None): + coord_ : tf.Tensor, + atype_ : tf.Tensor, + natoms : tf.Tensor, + box_ : tf.Tensor, + mesh : tf.Tensor, + input_dict : dict, + reuse : bool = None, + suffix : str = '' + ) -> tf.Tensor: + """ + Build the computational graph for the descriptor + + Parameters + ---------- + coord_ + The coordinate of atoms + atype_ + The type of atoms + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + mesh + For historical reasons, only the length of the Tensor matters. + if size of mesh == 6, pbc is assumed. + if size of mesh == 0, no-pbc is assumed. + input_dict + Dictionary for additional inputs + reuse + The weights in the networks should be reused when get the variable. + suffix + Name suffix to identify this descriptor + + Returns + ------- + descriptor + The output descriptor + """ davg = self.davg dstd = self.dstd with tf.variable_scope('descrpt_attr' + suffix, reuse = reuse) : @@ -162,10 +263,37 @@ def build (self, return self.descrpt - def get_rot_mat(self) : + def get_rot_mat(self) -> tf.Tensor: + """ + Get rotational matrix + """ return self.rot_mat - def prod_force_virial(self, atom_ener, natoms) : + def prod_force_virial(self, + atom_ener : tf.Tensor, + natoms : tf.Tensor + ) -> Tuple[tf.Tensor, tf.Tensor, tf.Tensor]: + """ + Compute force and virial + + Parameters + ---------- + atom_ener + The atomic energy + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + Return + ------ + force + The force on atoms + virial + The total virial + atom_virial + The atomic virial + """ [net_deriv] = tf.gradients (atom_ener, self.descrpt) tf.summary.histogram('net_derivative', net_deriv) net_deriv_reshape = tf.reshape (net_deriv, [-1, natoms[0] * self.ndescrpt]) diff --git a/source/api/descrpt_se_a.py b/source/api/descrpt_se_a.py index 235774de9f..60ca39b98a 100644 --- a/source/api/descrpt_se_a.py +++ b/source/api/descrpt_se_a.py @@ -126,7 +126,7 @@ def __init__ (self, def get_rcut (self) -> float: """ - Returns the cut-off radisu + Returns the cut-off radius """ return self.rcut_r diff --git a/source/api/descrpt_se_ar.py b/source/api/descrpt_se_ar.py index 935110a1a0..25cf1a9727 100644 --- a/source/api/descrpt_se_ar.py +++ b/source/api/descrpt_se_ar.py @@ -40,9 +40,10 @@ def compute_input_stats (self, data_box, data_atype, natoms_vec, - mesh) : - self.descrpt_a.compute_input_stats(data_coord, data_box, data_atype, natoms_vec, mesh) - self.descrpt_r.compute_input_stats(data_coord, data_box, data_atype, natoms_vec, mesh) + mesh, + input_dict) : + self.descrpt_a.compute_input_stats(data_coord, data_box, data_atype, natoms_vec, mesh, input_dict) + self.descrpt_r.compute_input_stats(data_coord, data_box, data_atype, natoms_vec, mesh, input_dict) self.davg = [self.descrpt_a.davg, self.descrpt_r.davg] self.dstd = [self.descrpt_a.dstd, self.descrpt_r.dstd] diff --git a/source/api/fitting.py b/source/api/fitting.py index 9e27ae5ed0..4d42d1849d 100644 --- a/source/api/fitting.py +++ b/source/api/fitting.py @@ -6,7 +6,7 @@ from deepmd.common import ClassArg, add_data_requirement, get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter from deepmd.argcheck import list_to_doc from deepmd.network import one_layer -from deepmd.DescrptLocFrame import DescrptLocFrame +from deepmd.descrpt_loc_frame import DescrptLocFrame from deepmd.descrpt_se_a import DescrptSeA from deepmd.RunOptions import global_cvt_2_tf_float diff --git a/source/tests/test_descrpt_nonsmth.py b/source/tests/test_descrpt_nonsmth.py index 450e30295d..f4a17be554 100644 --- a/source/tests/test_descrpt_nonsmth.py +++ b/source/tests/test_descrpt_nonsmth.py @@ -17,7 +17,7 @@ from common import virial_dw_test from common import Data -from deepmd.DescrptLocFrame import op_module +from deepmd.descrpt_loc_frame import op_module from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision diff --git a/source/tests/test_descrpt_se_r.py b/source/tests/test_descrpt_se_r.py index f1ab40ac52..9f8cea7969 100644 --- a/source/tests/test_descrpt_se_r.py +++ b/source/tests/test_descrpt_se_r.py @@ -19,7 +19,7 @@ from common import virial_dw_test from common import Data -from deepmd.DescrptLocFrame import op_module +from deepmd.descrpt_loc_frame import op_module from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision diff --git a/source/tests/test_descrpt_sea_ef.py b/source/tests/test_descrpt_sea_ef.py index 8537bf30f0..4a1e19aa2e 100644 --- a/source/tests/test_descrpt_sea_ef.py +++ b/source/tests/test_descrpt_sea_ef.py @@ -19,7 +19,7 @@ from common import virial_dw_test from common import Data -from deepmd.DescrptLocFrame import op_module +from deepmd.descrpt_loc_frame import op_module from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision diff --git a/source/tests/test_descrpt_sea_ef_para.py b/source/tests/test_descrpt_sea_ef_para.py index 3ae3549406..ec893ca1ee 100644 --- a/source/tests/test_descrpt_sea_ef_para.py +++ b/source/tests/test_descrpt_sea_ef_para.py @@ -19,7 +19,7 @@ from common import virial_dw_test from common import Data -from deepmd.DescrptLocFrame import op_module +from deepmd.descrpt_loc_frame import op_module from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision diff --git a/source/tests/test_descrpt_sea_ef_vert.py b/source/tests/test_descrpt_sea_ef_vert.py index efea0da716..4066670e88 100644 --- a/source/tests/test_descrpt_sea_ef_vert.py +++ b/source/tests/test_descrpt_sea_ef_vert.py @@ -19,7 +19,7 @@ from common import virial_dw_test from common import Data -from deepmd.DescrptLocFrame import op_module +from deepmd.descrpt_loc_frame import op_module from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision diff --git a/source/tests/test_descrpt_smooth.py b/source/tests/test_descrpt_smooth.py index 4b8183fb68..7b169c4704 100644 --- a/source/tests/test_descrpt_smooth.py +++ b/source/tests/test_descrpt_smooth.py @@ -19,7 +19,7 @@ from common import virial_dw_test from common import Data -from deepmd.DescrptLocFrame import op_module +from deepmd.descrpt_loc_frame import op_module from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision diff --git a/source/tests/test_model_loc_frame.py b/source/tests/test_model_loc_frame.py index 921501fc76..4c12c4a732 100644 --- a/source/tests/test_model_loc_frame.py +++ b/source/tests/test_model_loc_frame.py @@ -5,7 +5,7 @@ from deepmd.RunOptions import RunOptions from deepmd.DataSystem import DataSystem -from deepmd.DescrptLocFrame import DescrptLocFrame +from deepmd.descrpt_loc_frame import DescrptLocFrame from deepmd.fitting import EnerFitting from deepmd.Model import Model from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader @@ -37,7 +37,9 @@ def test_model(self): test_data = data.get_test () numb_test = 1 - descrpt = DescrptLocFrame(jdata['model']['descriptor']) + jdata['model']['descriptor'].pop('type', None) + jdata['model']['descriptor'].pop('_comment', None) + descrpt = DescrptLocFrame(**jdata['model']['descriptor']) fitting = EnerFitting(descrpt, neuron = [240, 120, 60, 30, 10], seed = 1) diff --git a/source/tests/test_tab_nonsmth.py b/source/tests/test_tab_nonsmth.py index 007d41cd63..748839ddda 100644 --- a/source/tests/test_tab_nonsmth.py +++ b/source/tests/test_tab_nonsmth.py @@ -21,7 +21,7 @@ from common import Data from test_descrpt_nonsmth import Inter -from deepmd.DescrptLocFrame import op_module +from deepmd.descrpt_loc_frame import op_module def _make_tab(ntype) : xx = np.arange(0,9,0.001) diff --git a/source/tests/test_tab_smooth.py b/source/tests/test_tab_smooth.py index 6d34aa06d1..d2f29b6b1a 100644 --- a/source/tests/test_tab_smooth.py +++ b/source/tests/test_tab_smooth.py @@ -21,7 +21,7 @@ from common import Data from test_descrpt_smooth import Inter -from deepmd.DescrptLocFrame import op_module +from deepmd.descrpt_loc_frame import op_module def _make_tab(ntype) : xx = np.arange(0,9,0.001) diff --git a/source/tests/test_wfc.py b/source/tests/test_wfc.py index ddef429eda..a03cfa2262 100644 --- a/source/tests/test_wfc.py +++ b/source/tests/test_wfc.py @@ -5,7 +5,7 @@ from deepmd.RunOptions import RunOptions from deepmd.DataSystem import DataSystem -from deepmd.DescrptLocFrame import DescrptLocFrame +from deepmd.descrpt_loc_frame import DescrptLocFrame from deepmd.fitting import WFCFitting from deepmd.Model import WFCModel from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader @@ -37,7 +37,9 @@ def test_model(self): test_data = data.get_test () numb_test = 1 - descrpt = DescrptLocFrame(jdata['model']['descriptor']) + jdata['model']['descriptor'].pop('type', None) + jdata['model']['descriptor'].pop('_comment', None) + descrpt = DescrptLocFrame(**jdata['model']['descriptor']) fitting = WFCFitting(jdata['model']['fitting_net'], descrpt) model = WFCModel(jdata['model'], descrpt, fitting) diff --git a/source/train/DataModifier.py b/source/train/DataModifier.py index 0afa5f1c4d..bcc5a6083b 100644 --- a/source/train/DataModifier.py +++ b/source/train/DataModifier.py @@ -227,7 +227,7 @@ def eval(self, coord, box, atype, eval_fv = True): corr_v = [] corr_av = [] for ii in range(0,nframes,batch_size): - f, v, av = self.eval_fv(coord[ii:ii+batch_size], box[ii:ii+batch_size], atype, ext_f[ii:ii+batch_size]) + f, v, av = self._eval_fv(coord[ii:ii+batch_size], box[ii:ii+batch_size], atype, ext_f[ii:ii+batch_size]) corr_f.append(f) corr_v.append(v) corr_av.append(av) @@ -257,7 +257,7 @@ def eval(self, coord, box, atype, eval_fv = True): return tot_e, tot_f, tot_v - def eval_fv(self, coords, cells, atom_types, ext_f) : + def _eval_fv(self, coords, cells, atom_types, ext_f) : # reshape the inputs cells = np.reshape(cells, [-1, 9]) nframes = cells.shape[0] diff --git a/source/train/DescrptHybrid.py b/source/train/DescrptHybrid.py deleted file mode 100644 index 4126959d98..0000000000 --- a/source/train/DescrptHybrid.py +++ /dev/null @@ -1,115 +0,0 @@ -import numpy as np -from deepmd.env import tf -from deepmd.common import ClassArg -from deepmd.env import op_module -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision -from deepmd.DescrptLocFrame import DescrptLocFrame -from deepmd.descrpt_se_a import DescrptSeA -from deepmd.descrpt_se_a_t import DescrptSeAT -from deepmd.descrpt_se_a_ebd import DescrptSeAEbd -from deepmd.descrpt_se_a_ef import DescrptSeAEf -from deepmd.descrpt_se_r import DescrptSeR - -class DescrptHybrid (): - def __init__ (self, jdata): - args = ClassArg()\ - .add('list', list, must = True) - class_data = args.parse(jdata) - dict_list = class_data['list'] - self.numb_descrpt = len(dict_list) - self.descrpt_list = [] - self.descrpt_type = [] - for ii in dict_list: - this_type = ii.get('type') - ii.pop('type', None) - ii.pop('_comment', None) - if this_type == 'loc_frame': - this_descrpt = DescrptLocFrame(ii) - elif this_type == 'se_a' : - this_descrpt = DescrptSeA(**ii) - elif this_type == 'se_at' : - this_descrpt = DescrptSeAT(**ii) - elif this_type == 'se_a_ebd' : - this_descrpt = DescrptSeAEbd(**ii) - elif this_type == 'se_a_ef' : - this_descrpt = DescrptSeAEf(**ii) - elif this_type == 'se_r' : - this_descrpt = DescrptSeR(**ii) - else : - raise RuntimeError('unknow model type ' + this_type) - self.descrpt_list.append(this_descrpt) - self.descrpt_type.append(this_type) - for ii in range(1, self.numb_descrpt): - assert(self.descrpt_list[ii].get_ntypes() == - self.descrpt_list[ 0].get_ntypes()), \ - f'number of atom types in {ii}th descrptor does not match others' - - - def get_rcut (self) : - all_rcut = [ii.get_rcut() for ii in self.descrpt_list] - return np.max(all_rcut) - - - def get_ntypes (self) : - return self.descrpt_list[0].get_ntypes() - - - def get_dim_out (self) : - all_dim_out = [ii.get_dim_out() for ii in self.descrpt_list] - return sum(all_dim_out) - - - def get_nlist_i(self, ii): - return self.descrpt_list[ii].nlist, self.descrpt_list[ii].rij, self.descrpt_list[ii].sel_a, self.descrpt_list[ii].sel_r - - - def compute_input_stats (self, - data_coord, - data_box, - data_atype, - natoms_vec, - mesh, - input_dict) : - for ii in self.descrpt_list: - ii.compute_input_stats(data_coord, data_box, data_atype, natoms_vec, mesh, input_dict) - - - def build (self, - coord_, - atype_, - natoms, - box, - mesh, - input_dict, - suffix = '', - reuse = None): - with tf.variable_scope('descrpt_attr' + suffix, reuse = reuse) : - t_rcut = tf.constant(self.get_rcut(), - name = 'rcut', - dtype = global_tf_float_precision) - t_ntypes = tf.constant(self.get_ntypes(), - name = 'ntypes', - dtype = tf.int32) - all_dout = [] - for tt,ii in zip(self.descrpt_type,self.descrpt_list): - dout = ii.build(coord_, atype_, natoms, box, mesh, input_dict, suffix=suffix+f'_{tt}', reuse=reuse) - dout = tf.reshape(dout, [-1, ii.get_dim_out()]) - all_dout.append(dout) - dout = tf.concat(all_dout, axis = 1) - dout = tf.reshape(dout, [-1, natoms[0] * self.get_dim_out()]) - return dout - - - def prod_force_virial(self, atom_ener, natoms) : - for idx,ii in enumerate(self.descrpt_list): - ff, vv, av = ii.prod_force_virial(atom_ener, natoms) - if idx == 0: - force = ff - virial = vv - atom_virial = av - else: - force += ff - virial += vv - atom_virial += av - return force, virial, atom_virial diff --git a/source/train/Trainer.py b/source/train/Trainer.py index 3d6af33141..e930289c59 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -8,14 +8,14 @@ from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_ener_float_precision from deepmd.fitting import EnerFitting, WFCFitting, PolarFittingLocFrame, PolarFittingSeA, GlobalPolarFittingSeA, DipoleFittingSeA -from deepmd.DescrptLocFrame import DescrptLocFrame +from deepmd.descrpt_loc_frame import DescrptLocFrame from deepmd.descrpt_se_a import DescrptSeA from deepmd.descrpt_se_a_t import DescrptSeAT from deepmd.descrpt_se_a_ebd import DescrptSeAEbd from deepmd.descrpt_se_a_ef import DescrptSeAEf from deepmd.descrpt_se_r import DescrptSeR from deepmd.descrpt_se_ar import DescrptSeAR -from deepmd.DescrptHybrid import DescrptHybrid +from deepmd.descrpt_hybrid import DescrptHybrid from deepmd.Model import Model, WFCModel, DipoleModel, PolarModel, GlobalPolarModel from deepmd.Loss import EnerStdLoss, EnerDipoleLoss, TensorLoss from deepmd.LearningRate import LearningRateExp @@ -44,6 +44,36 @@ def _is_subdir(path, directory): relative = os.path.relpath(path, directory) + os.sep return not relative.startswith(os.pardir + os.sep) +def _generate_descrpt_from_param_dict(descrpt_param): + try: + descrpt_type = descrpt_param['type'] + except KeyError: + raise KeyError('the type of descriptor should be set by `type`') + descrpt_param.pop('type', None) + to_pop = [] + for kk in descrpt_param: + if kk[0] == '_': + to_pop.append(kk) + for kk in to_pop: + descrpt_param.pop(kk, None) + if descrpt_type == 'loc_frame': + descrpt = DescrptLocFrame(**descrpt_param) + elif descrpt_type == 'se_a' : + descrpt = DescrptSeA(**descrpt_param) + elif descrpt_type == 'se_a_3be' or descrpt_type == 'se_at' : + descrpt = DescrptSeAT(**descrpt_param) + elif descrpt_type == 'se_a_tpe' or descrpt_type == 'se_a_ebd' : + descrpt = DescrptSeAEbd(**descrpt_param) + elif descrpt_type == 'se_a_ef' : + descrpt = DescrptSeAEf(**descrpt_param) + elif descrpt_type == 'se_r' : + descrpt = DescrptSeR(**descrpt_param) + elif descrpt_type == 'se_ar' : + descrpt = DescrptSeAR(descrpt_param) + else : + raise RuntimeError('unknow model type ' + descrpt_type) + return descrpt + class NNPTrainer (object): def __init__(self, @@ -59,26 +89,18 @@ def _init_param(self, jdata): fitting_param = j_must_have(model_param, 'fitting_net') # descriptor - descrpt_type = j_must_have(descrpt_param, 'type') - descrpt_param.pop('type',None) - if descrpt_type == 'loc_frame': - self.descrpt = DescrptLocFrame(descrpt_param) - elif descrpt_type == 'se_a' : - self.descrpt = DescrptSeA(**descrpt_param) - elif descrpt_type == 'se_a_3be' or descrpt_type == 'se_at' : - self.descrpt = DescrptSeAT(**descrpt_param) - elif descrpt_type == 'se_a_tpe' or descrpt_type == 'se_a_ebd' : - self.descrpt = DescrptSeAEbd(**descrpt_param) - elif descrpt_type == 'se_a_ef' : - self.descrpt = DescrptSeAEf(**descrpt_param) - elif descrpt_type == 'se_r' : - self.descrpt = DescrptSeR(**descrpt_param) - elif descrpt_type == 'se_ar' : - self.descrpt = DescrptSeAR(descrpt_param) - elif descrpt_type == 'hybrid' : - self.descrpt = DescrptHybrid(descrpt_param) + try: + descrpt_type = descrpt_param['type'] + except KeyError: + raise KeyError('the type of descriptor should be set by `type`') + + if descrpt_type != 'hybrid': + self.descrpt = _generate_descrpt_from_param_dict(descrpt_param) else : - raise RuntimeError('unknow model type ' + descrpt_type) + descrpt_list = [] + for ii in descrpt_param.get('list', []): + descrpt_list.append(_generate_descrpt_from_param_dict(ii)) + self.descrpt = DescrptHybrid(descrpt_list) # fitting net try: From afd4122cc9130f3b919d62096e6b46ef6216c805 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 16 Jan 2021 16:55:48 +0800 Subject: [PATCH 045/562] add python inference --- deepmd/__init__.py | 12 +- doc/use-deepmd-kit.md | 4 +- source/api/CMakeLists.txt | 2 +- source/api/deep_dipole.py | 25 +++++ .../{train/DeepEval.py => api/deep_eval.py} | 82 +++++++++++--- source/api/deep_polar.py | 68 ++++++++++++ source/{train/DeepPot.py => api/deep_pot.py} | 104 +++++++++++++++--- source/{train/DeepWFC.py => api/deep_wfc.py} | 2 +- source/train/DataModifier.py | 4 +- source/train/DeepDipole.py | 11 -- source/train/DeepPolar.py | 22 ---- 11 files changed, 264 insertions(+), 72 deletions(-) create mode 100644 source/api/deep_dipole.py rename source/{train/DeepEval.py => api/deep_eval.py} (76%) create mode 100644 source/api/deep_polar.py rename source/{train/DeepPot.py => api/deep_pot.py} (76%) rename source/{train/DeepWFC.py => api/deep_wfc.py} (86%) delete mode 100644 source/train/DeepDipole.py delete mode 100644 source/train/DeepPolar.py diff --git a/deepmd/__init__.py b/deepmd/__init__.py index 231145b989..5ead16e4c9 100644 --- a/deepmd/__init__.py +++ b/deepmd/__init__.py @@ -1,10 +1,10 @@ from .env import set_mkl -from .DeepEval import DeepEval -from .DeepPot import DeepPot -from .DeepDipole import DeepDipole -from .DeepPolar import DeepPolar -from .DeepPolar import DeepGlobalPolar -from .DeepWFC import DeepWFC +from .deep_eval import DeepEval +from .deep_pot import DeepPot +from .deep_dipole import DeepDipole +from .deep_polar import DeepPolar +from .deep_polar import DeepGlobalPolar +from .deep_wfc import DeepWFC set_mkl() diff --git a/doc/use-deepmd-kit.md b/doc/use-deepmd-kit.md index 724171576c..df942a4994 100644 --- a/doc/use-deepmd-kit.md +++ b/doc/use-deepmd-kit.md @@ -273,9 +273,9 @@ optional arguments: ## Model inference One may use the python interface of DeePMD-kit for model inference, an example is given as follows ```python -import deepmd.DeepPot as DP +from deepmd import DeepPot import numpy as np -dp = DP('graph.pb') +dp = DeepPot('graph.pb') coord = np.array([[1,0,0], [0,0,1.5], [1,0,3]]).reshape([1, -1]) cell = np.diag(10 * np.ones(3)).reshape([1, -1]) atype = [1,0,1] diff --git a/source/api/CMakeLists.txt b/source/api/CMakeLists.txt index 816c3b1612..6f5a659ab9 100644 --- a/source/api/CMakeLists.txt +++ b/source/api/CMakeLists.txt @@ -1,6 +1,6 @@ # train -file(GLOB LIB_PY descrpt_*.py network.py fitting.py) +file(GLOB LIB_PY descrpt_*.py deep_*.py network.py fitting.py) install( FILES ${LIB_PY} diff --git a/source/api/deep_dipole.py b/source/api/deep_dipole.py new file mode 100644 index 0000000000..9e582383b7 --- /dev/null +++ b/source/api/deep_dipole.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 + +from typing import Tuple, List +from deepmd.deep_eval import DeepTensor + +class DeepDipole (DeepTensor) : + def __init__(self, + model_file : str, + load_prefix : str = 'load', + default_tf_graph : bool = False + ) -> None: + """ + Constructor + + Parameters + ---------- + model_file : str + The name of the frozen model file. + load_prefix: str + The prefix in the load computational graph + default_tf_graph : bool + If uses the default tf graph, otherwise build a new tf graph for evaluation + """ + DeepTensor.__init__(self, model_file, 'dipole', 3, load_prefix = load_prefix, default_tf_graph = default_tf_graph) + diff --git a/source/train/DeepEval.py b/source/api/deep_eval.py similarity index 76% rename from source/train/DeepEval.py rename to source/api/deep_eval.py index 3a6e5624bc..695a5fd8a8 100644 --- a/source/train/DeepEval.py +++ b/source/api/deep_eval.py @@ -2,6 +2,7 @@ import platform import os import numpy as np +from typing import Tuple, List from deepmd.env import tf from deepmd.env import default_tf_session_config @@ -100,11 +101,28 @@ class DeepTensor(DeepEval) : Evaluates a tensor model """ def __init__(self, - model_file, - variable_name, - variable_dof, - load_prefix = 'load', - default_tf_graph = False) : + model_file : str, + variable_name : str, + variable_dof : int, + load_prefix : str = 'load', + default_tf_graph : bool = False + ) -> None : + """ + Constructor + + Parameters + ---------- + model_file : str + The name of the frozen model file. + variable_name : str + The name of the variable to evaluate. + variable_dof : + The DOF of the variable to evaluate. + load_prefix: str + The prefix in the load computational graph + default_tf_graph : bool + If uses the default tf graph, otherwise build a new tf graph for evaluation + """ DeepEval.__init__(self, model_file, load_prefix = load_prefix, default_tf_graph = default_tf_graph) # self.model_file = model_file # self.graph = self.load_graph (self.model_file) @@ -128,23 +146,61 @@ def __init__(self, [self.ntypes, self.rcut, self.tmap, self.tselt] = self.sess.run([self.t_ntypes, self.t_rcut, self.t_tmap, self.t_sel_type]) self.tmap = self.tmap.decode('UTF-8').split() - def get_ntypes(self) : + def get_ntypes(self) -> int: + """ + Get the number of atom types of this model + """ return self.ntypes - def get_rcut(self) : + def get_rcut(self) -> float: + """ + Get the cut-off radius of this model + """ return self.rcut - def get_type_map(self): + def get_type_map(self) -> List[int]: + """ + Get the type map (element name of the atom types) of this model + """ return self.tmap - def get_sel_type(self): + def get_sel_type(self) -> List[int]: + """ + Get the selected atom types of this model + """ return self.tselt def eval(self, - coords, - cells, - atom_types, - atomic = True) : + coords : np.array, + cells : np.array, + atom_types : List[int], + atomic : bool = True + ) -> np.array: + """ + Evaluate the model + + Parameters + ---------- + coords + The coordinates of atoms. + The array should be of size nframes x natoms x 3 + cells + The cell of the region. + If None then non-PBC is assumed, otherwise using PBC. + The array should be of size nframes x 9 + atom_types + The atom types + The list should contain natoms ints + atomic + Calculate the atomic energy and virial + + Returns + ------- + tensor + The returned tensor + If atomic == False then of size nframes x variable_dof + else of size nframes x natoms x variable_dof + """ # standarize the shape of inputs coords = np.array(coords) cells = np.array(cells) diff --git a/source/api/deep_polar.py b/source/api/deep_polar.py new file mode 100644 index 0000000000..f84689974f --- /dev/null +++ b/source/api/deep_polar.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 + +import numpy as np +from typing import Tuple, List +from deepmd.deep_eval import DeepTensor + +class DeepPolar (DeepTensor) : + def __init__(self, + model_file : str, + default_tf_graph : bool = False + ) -> None: + """ + Constructor + + Parameters + ---------- + model_file : str + The name of the frozen model file. + default_tf_graph : bool + If uses the default tf graph, otherwise build a new tf graph for evaluation + """ + DeepTensor.__init__(self, model_file, 'polar', 9, default_tf_graph = default_tf_graph) + + +class DeepGlobalPolar (DeepTensor) : + def __init__(self, + model_file : str, + default_tf_graph : bool = False + ) -> None: + """ + Constructor + + Parameters + ---------- + model_file : str + The name of the frozen model file. + default_tf_graph : bool + If uses the default tf graph, otherwise build a new tf graph for evaluation + """ + DeepTensor.__init__(self, model_file, 'global_polar', 9, default_tf_graph = default_tf_graph) + + def eval(self, + coords : np.array, + cells : np.array, + atom_types : List[int], + ) -> np.array: + """ + Evaluate the model + + Parameters + ---------- + coords + The coordinates of atoms. + The array should be of size nframes x natoms x 3 + cells + The cell of the region. + If None then non-PBC is assumed, otherwise using PBC. + The array should be of size nframes x 9 + atom_types + The atom types + The list should contain natoms ints + + Returns + ------- + polar + The system polarizability + """ + return DeepTensor.eval(self, coords, cells, atom_types, atomic = False) diff --git a/source/train/DeepPot.py b/source/api/deep_pot.py similarity index 76% rename from source/train/DeepPot.py rename to source/api/deep_pot.py index 7f90e85943..3f553b2131 100644 --- a/source/train/DeepPot.py +++ b/source/api/deep_pot.py @@ -1,16 +1,29 @@ #!/usr/bin/env python3 import numpy as np +from typing import Tuple, List + from deepmd.env import tf from deepmd.env import default_tf_session_config from deepmd.common import make_default_mesh -from deepmd.DeepEval import DeepEval +from deepmd.deep_eval import DeepEval from deepmd.DataModifier import DipoleChargeModifier class DeepPot (DeepEval) : def __init__(self, - model_file, - default_tf_graph = False) : + model_file : str, + default_tf_graph : bool = False + ) -> None: + """ + Constructor + + Parameters + ---------- + model_file : str + The name of the frozen model file. + default_tf_graph : bool + If uses the default tf graph, otherwise build a new tf graph for evaluation + """ DeepEval.__init__(self, model_file, default_tf_graph = default_tf_graph) # self.model_file = model_file # self.graph = self.load_graph (self.model_file) @@ -74,29 +87,90 @@ def __init__(self, self.dm = DipoleChargeModifier(mdl_name, mdl_charge_map, sys_charge_map, ewald_h = ewald_h, ewald_beta = ewald_beta) - def get_ntypes(self) : + def get_ntypes(self) -> int: + """ + Get the number of atom types of this DP + """ return self.ntypes - def get_rcut(self) : + def get_rcut(self) -> float: + """ + Get the cut-off radius of this DP + """ return self.rcut - def get_dim_fparam(self) : + def get_dim_fparam(self) -> int: + """ + Get the number (dimension) of frame parameters of this DP + """ return self.dfparam - def get_dim_aparam(self) : + def get_dim_aparam(self) -> int: + """ + Get the number (dimension) of atomic parameters of this DP + """ return self.daparam - def get_type_map(self): + def get_type_map(self) -> List[int]: + """ + Get the type map (element name of the atom types) of this DP + """ return self.tmap def eval(self, - coords, - cells, - atom_types, - fparam = None, - aparam = None, - atomic = False, - efield = None) : + coords : np.array, + cells : np.array, + atom_types : List[int], + fparam : np.array = None, + aparam : np.array = None, + atomic : bool = False, + efield : np.array = None + ) : + """ + Evaluate the energy, force and virial by using this DP. + + Parameters + ---------- + coords + The coordinates of atoms. + The array should be of size nframes x natoms x 3 + cells + The cell of the region. + If None then non-PBC is assumed, otherwise using PBC. + The array should be of size nframes x 9 + atom_types + The atom types + The list should contain natoms ints + fparam + The frame parameter. + The array can be of size : + - nframes x dim_fparam. + - dim_fparam. Then all frames are assumed to be provided with the same fparam. + aparam + The atomic parameter + The array can be of size : + - nframes x natoms x dim_aparam. + - natoms x dim_aparam. Then all frames are assumed to be provided with the same aparam. + - dim_aparam. Then all frames and atoms are provided with the same aparam. + atomic + Calculate the atomic energy and virial + efield + The external field on atoms. + The array should be of size nframes x natoms x 3 + + Returns + ------- + energy + The system energy. + force + The force on each atom + virial + The virial + atom_energy + The atomic energy. Only returned when atomic == True + atom_virial + The atomic virial. Only returned when atomic == True + """ if atomic : if self.modifier_type is not None: raise RuntimeError('modifier does not support atomic modification') diff --git a/source/train/DeepWFC.py b/source/api/deep_wfc.py similarity index 86% rename from source/train/DeepWFC.py rename to source/api/deep_wfc.py index 0fff8947da..183757ca71 100644 --- a/source/train/DeepWFC.py +++ b/source/api/deep_wfc.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -from deepmd.DeepEval import DeepTensor +from deepmd.deep_eval import DeepTensor class DeepWFC (DeepTensor) : def __init__(self, diff --git a/source/train/DataModifier.py b/source/train/DataModifier.py index bcc5a6083b..c36b01bf1f 100644 --- a/source/train/DataModifier.py +++ b/source/train/DataModifier.py @@ -1,6 +1,8 @@ import os import numpy as np -from deepmd.DeepDipole import DeepDipole +from typing import Tuple, List + +from deepmd.deep_dipole import DeepDipole from deepmd.env import tf from deepmd.common import select_idx_map, make_default_mesh from deepmd.EwaldRecp import EwaldRecp diff --git a/source/train/DeepDipole.py b/source/train/DeepDipole.py deleted file mode 100644 index 1183486624..0000000000 --- a/source/train/DeepDipole.py +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env python3 - -from deepmd.DeepEval import DeepTensor - -class DeepDipole (DeepTensor) : - def __init__(self, - model_file, - load_prefix = 'load', - default_tf_graph = False) : - DeepTensor.__init__(self, model_file, 'dipole', 3, load_prefix = load_prefix, default_tf_graph = default_tf_graph) - diff --git a/source/train/DeepPolar.py b/source/train/DeepPolar.py deleted file mode 100644 index 705eacfe62..0000000000 --- a/source/train/DeepPolar.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python3 - -from deepmd.DeepEval import DeepTensor - -class DeepPolar (DeepTensor) : - def __init__(self, - model_file, - default_tf_graph = False) : - DeepTensor.__init__(self, model_file, 'polar', 9, default_tf_graph = default_tf_graph) - - -class DeepGlobalPolar (DeepTensor) : - def __init__(self, - model_file, - default_tf_graph = False) : - DeepTensor.__init__(self, model_file, 'global_polar', 9, default_tf_graph = default_tf_graph) - - def eval(self, - coords, - cells, - atom_types) : - return DeepTensor.eval(self, coords, cells, atom_types, atomic = False) From cf4407947c5353fc1bd61ea3e0c7da3375cb5293 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 16 Jan 2021 21:07:41 +0800 Subject: [PATCH 046/562] add loss, learning rate, tabulated interaction, data modifier --- source/api/CMakeLists.txt | 2 +- .../DataModifier.py => api/data_modifier.py} | 69 ++++++++++++-- source/api/deep_eval.py | 79 ++++++++++++++- source/api/deep_pot.py | 2 +- .../{train/EwaldRecp.py => api/ewald_recp.py} | 43 ++++++++- source/api/learning_rate.py | 95 +++++++++++++++++++ source/{train/Loss.py => api/loss.py} | 66 +++++++------ .../{train/TabInter.py => api/tab_inter.py} | 39 +++++++- source/tests/data_modifier/dipole.json | 2 +- source/tests/test_data_modifier.py | 4 +- source/tests/test_data_modifier_shuffle.py | 7 +- source/tests/test_ewald.py | 4 +- source/tests/test_tab_nonsmth.py | 2 +- source/tests/test_tab_smooth.py | 2 +- source/train/LearningRate.py | 39 -------- source/train/Model.py | 2 +- source/train/Trainer.py | 14 ++- source/train/train.py | 2 +- 18 files changed, 370 insertions(+), 103 deletions(-) rename source/{train/DataModifier.py => api/data_modifier.py} (90%) rename source/{train/EwaldRecp.py => api/ewald_recp.py} (71%) create mode 100644 source/api/learning_rate.py rename source/{train/Loss.py => api/loss.py} (91%) rename source/{train/TabInter.py => api/tab_inter.py} (57%) delete mode 100644 source/train/LearningRate.py diff --git a/source/api/CMakeLists.txt b/source/api/CMakeLists.txt index 6f5a659ab9..e09171fa4d 100644 --- a/source/api/CMakeLists.txt +++ b/source/api/CMakeLists.txt @@ -1,6 +1,6 @@ # train -file(GLOB LIB_PY descrpt_*.py deep_*.py network.py fitting.py) +file(GLOB LIB_PY descrpt_*.py deep_*.py network.py fitting.py learning_rate.py loss.py tab_inter.py data_modifier.py ewald_recp.py) install( FILES ${LIB_PY} diff --git a/source/train/DataModifier.py b/source/api/data_modifier.py similarity index 90% rename from source/train/DataModifier.py rename to source/api/data_modifier.py index c36b01bf1f..b562d0dd2d 100644 --- a/source/train/DataModifier.py +++ b/source/api/data_modifier.py @@ -5,7 +5,7 @@ from deepmd.deep_dipole import DeepDipole from deepmd.env import tf from deepmd.common import select_idx_map, make_default_mesh -from deepmd.EwaldRecp import EwaldRecp +from deepmd.ewald_recp import EwaldRecp from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.RunOptions import global_ener_float_precision @@ -16,11 +16,28 @@ class DipoleChargeModifier(DeepDipole): def __init__(self, - model_name, - model_charge_map, - sys_charge_map, - ewald_h = 1, - ewald_beta = 1): + model_name : str, + model_charge_map : List[float], + sys_charge_map : List[float], + ewald_h : float = 1, + ewald_beta : float = 1 + ) -> None: + """ + Constructor + + Parameters + ---------- + model_name + The model file for the DeepDipole model + model_charge_map + Gives the amount of charge for the wfcc + sys_charge_map + Gives the amount of charge for the real atoms + ewald_h + Grid spacing of the reciprocal part of Ewald sum. Unit: A + ewald_beta + Splitting parameter of the Ewald sum. Unit: A^{-1} + """ # the dipole model is loaded with prefix 'dipole_charge' self.modifier_prefix = 'dipole_charge' # init dipole model @@ -51,7 +68,11 @@ def __init__(self, self.force = None self.ntypes = len(self.sel_a) - def build_fv_graph(self): + + def build_fv_graph(self) -> tf.Tensor: + """ + Build the computational graph for the force and virial inference. + """ with tf.variable_scope('modifier_attr') : t_mdl_name = tf.constant(self.model_name, name = 'mdl_name', @@ -74,6 +95,7 @@ def build_fv_graph(self): with self.graph.as_default(): return self._build_fv_graph_inner() + def _build_fv_graph_inner(self): self.t_ef = tf.placeholder(global_tf_float_precision, [None], name = 't_ef') nf = 10 @@ -184,7 +206,35 @@ def _slice_descrpt_deriv(self, deriv): return tf.concat(coll, axis = 1) - def eval(self, coord, box, atype, eval_fv = True): + def eval(self, + coord : np.array, + box : np.array, + atype : np.array, + eval_fv : bool = True + ) -> Tuple[np.array, np.array, np.array]: + """ + Evaluate the modification + + Parameters + ---------- + coord + The coordinates of atoms + box + The simulation region. PBC is assumed + atype + The atom types + eval_fv + Evaluate force and virial + + Returns + ------- + tot_e + The energy modification + tot_f + The force modification + tot_v + The virial modification + """ coord, atype, imap = self.sort_input(coord, atype) natoms = coord.shape[1] // 3 nframes = coord.shape[0] @@ -323,7 +373,8 @@ def _extend_system(self, coord, box, atype, charge): return all_coord, all_charge, dipole - def modify_data(self, data): + def modify_data(self, + data) -> None: if 'find_energy' not in data and 'find_force' not in data and 'find_virial' not in data: return diff --git a/source/api/deep_eval.py b/source/api/deep_eval.py index 695a5fd8a8..f80e59c9b8 100644 --- a/source/api/deep_eval.py +++ b/source/api/deep_eval.py @@ -58,7 +58,41 @@ def _load_graph(self, return graph - def sort_input(self, coord, atom_type, sel_atoms = None) : + def sort_input(self, + coord : np.array, + atom_type : np.array, + sel_atoms : List[int] = None + ) : + """ + Sort atoms in the system according their types. + + Parameters + ---------- + coord + The coordinates of atoms. + Should be of shape [nframes, natoms, 3] + atom_type + The type of atoms + Should be of shape [natoms] + sel_atom + The selected atoms by type + + Returns + ------- + coord_out + The coordinates after sorting + atom_type_out + The atom types after sorting + idx_map + The index mapping from the input to the output. + For example coord_out = coord[:,idx_map,:] + sel_atom_type + Only output if sel_atoms is not None + The sorted selected atom types + sel_idx_map + Only output if sel_atoms is not None + The index mapping from the selected atoms to sorted selected atoms. + """ if sel_atoms is not None: selection = [False] * np.size(atom_type) for ii in sel_atoms: @@ -80,13 +114,52 @@ def sort_input(self, coord, atom_type, sel_atoms = None) : else: return coord, atom_type, idx_map - def reverse_map(self, vec, imap): + + def reverse_map(self, + vec : np.array, + imap : List[int] + ) -> np.array: + """ + Reverse mapping of a vector according to the index map + + Parameters + ---------- + vec + Input vector. Be of shape [nframes, natoms, -1] + imap + Index map. Be of shape [natoms] + + Returns + ------- + vec_out + Reverse mapped vector. + """ ret = np.zeros(vec.shape) for idx,ii in enumerate(imap) : ret[:,ii,:] = vec[:,idx,:] return ret - def make_natoms_vec(self, atom_types) : + + def make_natoms_vec(self, + atom_types : np.array + ) -> np.array : + """ + Make the natom vector used by deepmd-kit + + Parameters + ---------- + atom_types + The type of atoms + + Returns + ------- + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + + """ natoms_vec = np.zeros (self.ntypes+2).astype(int) natoms = atom_types.size natoms_vec[0] = natoms diff --git a/source/api/deep_pot.py b/source/api/deep_pot.py index 3f553b2131..ed8999a442 100644 --- a/source/api/deep_pot.py +++ b/source/api/deep_pot.py @@ -7,7 +7,7 @@ from deepmd.env import default_tf_session_config from deepmd.common import make_default_mesh from deepmd.deep_eval import DeepEval -from deepmd.DataModifier import DipoleChargeModifier +from deepmd.data_modifier import DipoleChargeModifier class DeepPot (DeepEval) : def __init__(self, diff --git a/source/train/EwaldRecp.py b/source/api/ewald_recp.py similarity index 71% rename from source/train/EwaldRecp.py rename to source/api/ewald_recp.py index 2517669454..300ae539e1 100644 --- a/source/train/EwaldRecp.py +++ b/source/api/ewald_recp.py @@ -1,4 +1,6 @@ import numpy as np +from typing import Tuple, List + from deepmd.env import tf from deepmd.common import ClassArg from deepmd.RunOptions import global_tf_float_precision @@ -10,9 +12,22 @@ from deepmd.env import default_tf_session_config class EwaldRecp () : + """ + Evaluate the reciprocal part of the Ewald sum + """ def __init__(self, hh, beta): + """ + Constructor + + Parameters + ---------- + hh + Grid spacing of the reciprocal part of Ewald sum. Unit: A + beta + Splitting parameter of the Ewald sum. Unit: A^{-1} + """ self.hh = hh self.beta = beta with tf.Graph().as_default() as graph: @@ -29,9 +44,31 @@ def __init__(self, self.sess = tf.Session(graph=graph, config=default_tf_session_config) def eval(self, - coord, - charge, - box) : + coord : np.array, + charge : np.array, + box : np.array + ) -> Tuple[np.array, np.array, np.array] : + """ + Evaluate + + Parameters + ---------- + coord + The coordinates of atoms + charge + The atomic charge + box + The simulation region. PBC is assumed + + Returns + ------- + e + The energy + f + The force + v + The virial + """ coord = np.array(coord) charge = np.array(charge) box = np.array(box) diff --git a/source/api/learning_rate.py b/source/api/learning_rate.py new file mode 100644 index 0000000000..572f317a92 --- /dev/null +++ b/source/api/learning_rate.py @@ -0,0 +1,95 @@ +import numpy as np +from deepmd.env import tf +from deepmd.common import ClassArg + +class LearningRateExp (object) : + """ + The exponentially decaying learning rate. + + The learning rate at step t is given by + + lr(t) = start_lr * decay_rate ^ ( t / decay_steps ) + """ + def __init__ (self, + start_lr : float, + stop_lr : float = 5e-8, + decay_steps : int = 5000, + decay_rate : float = 0.95 + ) -> None : + """ + Constructor + + Parameters + ---------- + start_lr + Starting learning rate + stop_lr + Stop learning rate + decay_steps + Learning rate decay every this number of steps + decay_rate + The decay rate. + If `stop_step` is provided in `build`, then it will be determined automatically and overwritten. + """ + # args = ClassArg()\ + # .add('decay_steps', int, must = False)\ + # .add('decay_rate', float, must = False)\ + # .add('start_lr', float, must = True)\ + # .add('stop_lr', float, must = False) + # self.cd = args.parse(jdata) + self.cd = {} + self.cd['start_lr'] = start_lr + self.cd['stop_lr'] = stop_lr + self.cd['decay_steps'] = decay_steps + self.cd['decay_rate'] = decay_rate + self.start_lr_ = self.cd['start_lr'] + + def build(self, + global_step : tf.Tensor, + stop_step : int = None + ) -> tf.Tensor : + """ + Build the learning rate + + Parameters + ---------- + global_step + The tf Tensor prividing the global training step + stop_step + The stop step. If provided, the decay_rate will be determined automatically and overwritten. + + Returns + ------- + learning_rate + The learning rate + """ + if stop_step is None: + self.decay_steps_ = self.cd['decay_steps'] if self.cd['decay_steps'] is not None else 5000 + self.decay_rate_ = self.cd['decay_rate'] if self.cd['decay_rate'] is not None else 0.95 + else: + self.stop_lr_ = self.cd['stop_lr'] if self.cd['stop_lr'] is not None else 5e-8 + default_ds = 100 if stop_step // 10 > 100 else stop_step // 100 + 1 + self.decay_steps_ = self.cd['decay_steps'] if self.cd['decay_steps'] is not None else default_ds + if self.decay_steps_ >= stop_step: + self.decay_steps_ = default_ds + self.decay_rate_ = np.exp(np.log(self.stop_lr_ / self.start_lr_) / (stop_step / self.decay_steps_)) + + return tf.train.exponential_decay(self.start_lr_, + global_step, + self.decay_steps_, + self.decay_rate_, + staircase=True) + def start_lr(self) -> float: + """ + Get the start lr + """ + return self.start_lr_ + + def value (self, + step : int + ) -> float: + """ + Get the lr at a certain step + """ + return self.start_lr_ * np.power (self.decay_rate_, (step // self.decay_steps_)) + diff --git a/source/train/Loss.py b/source/api/loss.py similarity index 91% rename from source/train/Loss.py rename to source/api/loss.py index df81672ab0..edabd338b8 100644 --- a/source/train/Loss.py +++ b/source/api/loss.py @@ -8,32 +8,35 @@ class EnerStdLoss () : - def __init__ (self, jdata, **kwarg) : - self.starter_learning_rate = kwarg['starter_learning_rate'] - args = ClassArg()\ - .add('start_pref_e', float, default = 0.02)\ - .add('limit_pref_e', float, default = 1.00)\ - .add('start_pref_f', float, default = 1000)\ - .add('limit_pref_f', float, default = 1.00)\ - .add('start_pref_v', float, default = 0)\ - .add('limit_pref_v', float, default = 0)\ - .add('start_pref_ae', float, default = 0)\ - .add('limit_pref_ae', float, default = 0)\ - .add('start_pref_pf', float, default = 0)\ - .add('limit_pref_pf', float, default = 0)\ - .add('relative_f', float) - class_data = args.parse(jdata) - self.start_pref_e = class_data['start_pref_e'] - self.limit_pref_e = class_data['limit_pref_e'] - self.start_pref_f = class_data['start_pref_f'] - self.limit_pref_f = class_data['limit_pref_f'] - self.start_pref_v = class_data['start_pref_v'] - self.limit_pref_v = class_data['limit_pref_v'] - self.start_pref_ae = class_data['start_pref_ae'] - self.limit_pref_ae = class_data['limit_pref_ae'] - self.start_pref_pf = class_data['start_pref_pf'] - self.limit_pref_pf = class_data['limit_pref_pf'] - self.relative_f = class_data['relative_f'] + """ + Standard loss function for DP models + """ + def __init__ (self, + starter_learning_rate : float, + start_pref_e : float = 0.02, + limit_pref_e : float = 1.00, + start_pref_f : float = 1000, + limit_pref_f : float = 1.00, + start_pref_v : float = 0, + limit_pref_v : float = 0, + start_pref_ae : float = 0, + limit_pref_ae : float = 0, + start_pref_pf : float = 0, + limit_pref_pf : float = 0, + relative_f : float = None + ) -> None: + self.starter_learning_rate = starter_learning_rate + self.start_pref_e = start_pref_e + self.limit_pref_e = limit_pref_e + self.start_pref_f = start_pref_f + self.limit_pref_f = limit_pref_f + self.start_pref_v = start_pref_v + self.limit_pref_v = limit_pref_v + self.start_pref_ae = start_pref_ae + self.limit_pref_ae = limit_pref_ae + self.start_pref_pf = start_pref_pf + self.limit_pref_pf = limit_pref_pf + self.relative_f = relative_f self.has_e = (self.start_pref_e != 0 or self.limit_pref_e != 0) self.has_f = (self.start_pref_f != 0 or self.limit_pref_f != 0) self.has_v = (self.start_pref_v != 0 or self.limit_pref_v != 0) @@ -196,7 +199,13 @@ def print_on_training(self, class EnerDipoleLoss () : - def __init__ (self, jdata, **kwarg) : + def __init__ (self, + starter_learning_rate : float, + start_pref_e : float = 0.1, + limit_pref_e : float = 1.0, + start_pref_ed : float = 1.0, + limit_pref_ed : float = 1.0 + ) -> None : self.starter_learning_rate = kwarg['starter_learning_rate'] args = ClassArg()\ .add('start_pref_e', float, must = True, default = 0.1) \ @@ -315,6 +324,9 @@ def print_on_training(self, class TensorLoss () : + """ + Loss function for tensorial properties. + """ def __init__ (self, jdata, **kwarg) : try: model = kwarg['model'] diff --git a/source/train/TabInter.py b/source/api/tab_inter.py similarity index 57% rename from source/train/TabInter.py rename to source/api/tab_inter.py index 99190e1191..1a028a6820 100644 --- a/source/train/TabInter.py +++ b/source/api/tab_inter.py @@ -1,15 +1,45 @@ #!/usr/bin/env python3 import numpy as np +from typing import Tuple, List + from scipy.interpolate import CubicSpline class TabInter (object): def __init__(self, - filename): + filename : str + ) -> None: + """ + Constructor + + Parameters + ---------- + filename + File name for the short-range tabulated potential. + The table is a text data file with (N_t + 1) * N_t / 2 + 1 columes. + The first colume is the distance between atoms. + The second to the last columes are energies for pairs of certain types. + For example we have two atom types, 0 and 1. + The columes from 2nd to 4th are for 0-0, 0-1 and 1-1 correspondingly. + """ self.reinit(filename) def reinit(self, - filename): + filename : str + ) -> None: + """ + Initialize the tabulated interaction + + Parameters + ---------- + filename + File name for the short-range tabulated potential. + The table is a text data file with (N_t + 1) * N_t / 2 + 1 columes. + The first colume is the distance between atoms. + The second to the last columes are energies for pairs of certain types. + For example we have two atom types, 0 and 1. + The columes from 2nd to 4th are for 0-0, 0-1 and 1-1 correspondingly. + """ self.vdata = np.loadtxt(filename) self.rmin = self.vdata[0][0] self.hh = self.vdata[1][0] - self.vdata[0][0] @@ -22,7 +52,10 @@ def reinit(self, self.tab_info = np.array([self.rmin, self.hh, self.nspline, self.ntypes]) self.tab_data = self._make_data() - def get(self) : + def get(self) -> Tuple[np.array, np.array]: + """ + Get the serialized table. + """ return self.tab_info, self.tab_data def _make_data(self) : diff --git a/source/tests/data_modifier/dipole.json b/source/tests/data_modifier/dipole.json index 9cf93d93f1..f53be905de 100644 --- a/source/tests/data_modifier/dipole.json +++ b/source/tests/data_modifier/dipole.json @@ -26,8 +26,8 @@ "learning_rate" :{ "type": "exp", "start_lr": 0.01, + "stop_lr": 1e-8, "decay_steps": 5000, - "decay_rate": 0.95, "_comment": "that's all" }, diff --git a/source/tests/test_data_modifier.py b/source/tests/test_data_modifier.py index f71e31377d..a88415e505 100644 --- a/source/tests/test_data_modifier.py +++ b/source/tests/test_data_modifier.py @@ -10,8 +10,8 @@ from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.RunOptions import global_ener_float_precision -from deepmd.EwaldRecp import EwaldRecp -from deepmd.DataModifier import DipoleChargeModifier +from deepmd.ewald_recp import EwaldRecp +from deepmd.data_modifier import DipoleChargeModifier from common import Data diff --git a/source/tests/test_data_modifier_shuffle.py b/source/tests/test_data_modifier_shuffle.py index f41424ffde..cf4a3757a3 100644 --- a/source/tests/test_data_modifier_shuffle.py +++ b/source/tests/test_data_modifier_shuffle.py @@ -11,9 +11,9 @@ from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.RunOptions import global_ener_float_precision -from deepmd.EwaldRecp import EwaldRecp -from deepmd.DataModifier import DipoleChargeModifier -from deepmd.DeepDipole import DeepDipole +from deepmd.ewald_recp import EwaldRecp +from deepmd.data_modifier import DipoleChargeModifier +from deepmd.deep_dipole import DeepDipole from common import Data @@ -153,6 +153,7 @@ def _setUp_jdata(self): "learning_rate" :{ "type": "exp", "start_lr": 0.01, + "stop_lr": 1e-8, "decay_steps": 5000, "decay_rate": 0.95, }, diff --git a/source/tests/test_ewald.py b/source/tests/test_ewald.py index 4131cfa4df..cf2d543c2f 100644 --- a/source/tests/test_ewald.py +++ b/source/tests/test_ewald.py @@ -6,8 +6,8 @@ from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.RunOptions import global_ener_float_precision -from deepmd.EwaldRecp import op_module -from deepmd.EwaldRecp import EwaldRecp +from deepmd.ewald_recp import op_module +from deepmd.ewald_recp import EwaldRecp if global_np_float_precision == np.float32 : global_default_fv_hh = 1e-2 diff --git a/source/tests/test_tab_nonsmth.py b/source/tests/test_tab_nonsmth.py index 748839ddda..4393a7e2d6 100644 --- a/source/tests/test_tab_nonsmth.py +++ b/source/tests/test_tab_nonsmth.py @@ -12,7 +12,7 @@ import deepmd._prod_virial_se_a_grad import deepmd._soft_min_force_grad import deepmd._soft_min_virial_grad -from deepmd.TabInter import TabInter +from deepmd.tab_inter import TabInter from common import force_test from common import virial_test diff --git a/source/tests/test_tab_smooth.py b/source/tests/test_tab_smooth.py index d2f29b6b1a..aa6bbc7170 100644 --- a/source/tests/test_tab_smooth.py +++ b/source/tests/test_tab_smooth.py @@ -12,7 +12,7 @@ import deepmd._prod_virial_se_a_grad import deepmd._soft_min_force_grad import deepmd._soft_min_virial_grad -from deepmd.TabInter import TabInter +from deepmd.tab_inter import TabInter from common import force_test from common import virial_test diff --git a/source/train/LearningRate.py b/source/train/LearningRate.py deleted file mode 100644 index fe66e52516..0000000000 --- a/source/train/LearningRate.py +++ /dev/null @@ -1,39 +0,0 @@ -import numpy as np -from deepmd.env import tf -from deepmd.common import ClassArg - -class LearningRateExp (object) : - def __init__ (self, - jdata) : - args = ClassArg()\ - .add('decay_steps', int, must = False)\ - .add('decay_rate', float, must = False)\ - .add('start_lr', float, must = True)\ - .add('stop_lr', float, must = False) - self.cd = args.parse(jdata) - self.start_lr_ = self.cd['start_lr'] - - def build(self, global_step, stop_batch = None) : - if stop_batch is None: - self.decay_steps_ = self.cd['decay_steps'] if self.cd['decay_steps'] is not None else 5000 - self.decay_rate_ = self.cd['decay_rate'] if self.cd['decay_rate'] is not None else 0.95 - else: - self.stop_lr_ = self.cd['stop_lr'] if self.cd['stop_lr'] is not None else 5e-8 - default_ds = 100 if stop_batch // 10 > 100 else stop_batch // 100 + 1 - self.decay_steps_ = self.cd['decay_steps'] if self.cd['decay_steps'] is not None else default_ds - if self.decay_steps_ >= stop_batch: - self.decay_steps_ = default_ds - self.decay_rate_ = np.exp(np.log(self.stop_lr_ / self.start_lr_) / (stop_batch / self.decay_steps_)) - - return tf.train.exponential_decay(self.start_lr_, - global_step, - self.decay_steps_, - self.decay_rate_, - staircase=True) - def start_lr(self) : - return self.start_lr_ - - def value (self, - batch) : - return self.start_lr_ * np.power (self.decay_rate_, (batch // self.decay_steps_)) - diff --git a/source/train/Model.py b/source/train/Model.py index b8d171eb09..d810a806ef 100644 --- a/source/train/Model.py +++ b/source/train/Model.py @@ -1,7 +1,7 @@ import numpy as np from deepmd.env import tf from collections import defaultdict -from deepmd.TabInter import TabInter +from deepmd.tab_inter import TabInter from deepmd.common import ClassArg from deepmd.RunOptions import global_cvt_2_ener_float diff --git a/source/train/Trainer.py b/source/train/Trainer.py index e930289c59..c3be9a0ebe 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -17,8 +17,8 @@ from deepmd.descrpt_se_ar import DescrptSeAR from deepmd.descrpt_hybrid import DescrptHybrid from deepmd.Model import Model, WFCModel, DipoleModel, PolarModel, GlobalPolarModel -from deepmd.Loss import EnerStdLoss, EnerDipoleLoss, TensorLoss -from deepmd.LearningRate import LearningRateExp +from deepmd.loss import EnerStdLoss, EnerDipoleLoss, TensorLoss +from deepmd.learning_rate import LearningRateExp from tensorflow.python.client import timeline from deepmd.env import op_module @@ -155,7 +155,9 @@ def _init_param(self, jdata): except: lr_type = 'exp' if lr_type == 'exp': - self.lr = LearningRateExp(lr_param) + self.lr = LearningRateExp(lr_param['start_lr'], + lr_param['stop_lr'], + lr_param['decay_steps']) else : raise RuntimeError('unknown learning_rate type ' + lr_type) @@ -169,10 +171,12 @@ def _init_param(self, jdata): loss_type = 'ener' if fitting_type == 'ener': + loss_param.pop('type', None) + loss_param['starter_learning_rate'] = self.lr.start_lr() if loss_type == 'ener': - self.loss = EnerStdLoss(loss_param, starter_learning_rate = self.lr.start_lr()) + self.loss = EnerStdLoss(**loss_param) elif loss_type == 'ener_dipole': - self.loss = EnerDipoleLoss(loss_param, starter_learning_rate = self.lr.start_lr()) + self.loss = EnerDipoleLoss(**loss_param) else: raise RuntimeError('unknow loss type') elif fitting_type == 'wfc': diff --git a/source/train/train.py b/source/train/train.py index e7978361b2..2b57026139 100755 --- a/source/train/train.py +++ b/source/train/train.py @@ -11,7 +11,7 @@ from deepmd.DataSystem import DeepmdDataSystem from deepmd.Trainer import NNPTrainer from deepmd.common import data_requirement, expand_sys_str, j_loader -from deepmd.DataModifier import DipoleChargeModifier +from deepmd.data_modifier import DipoleChargeModifier from deepmd.argcheck import normalize def create_done_queue(cluster_spec, task_index): From 1590613454d64425795a91986307cbb6a34a91bc Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 17 Jan 2021 15:34:35 +0800 Subject: [PATCH 047/562] add data and data_system --- source/api/CMakeLists.txt | 2 +- source/{train/Data.py => api/data.py} | 182 +++++++++++++++--- source/api/data_modifier.py | 20 +- .../DataSystem.py => api/data_system.py} | 172 ++++++++++++++--- source/tests/test_data_modifier.py | 2 +- source/tests/test_data_modifier_shuffle.py | 2 +- source/tests/test_deepmd_data.py | 2 +- source/tests/test_deepmd_data_sys.py | 2 +- source/tests/test_gen_stat_data.py | 2 +- source/tests/test_model_loc_frame.py | 2 +- source/tests/test_model_se_a.py | 2 +- source/tests/test_model_se_a_aparam.py | 2 +- source/tests/test_model_se_a_fparam.py | 2 +- source/tests/test_model_se_a_srtab.py | 2 +- source/tests/test_model_se_r.py | 2 +- source/tests/test_polar_se_a.py | 2 +- source/tests/test_wfc.py | 2 +- source/train/test.py | 2 +- source/train/train.py | 2 +- 19 files changed, 335 insertions(+), 71 deletions(-) rename source/{train/Data.py => api/data.py} (83%) rename source/{train/DataSystem.py => api/data_system.py} (83%) diff --git a/source/api/CMakeLists.txt b/source/api/CMakeLists.txt index e09171fa4d..8cd7f3cb5b 100644 --- a/source/api/CMakeLists.txt +++ b/source/api/CMakeLists.txt @@ -1,6 +1,6 @@ # train -file(GLOB LIB_PY descrpt_*.py deep_*.py network.py fitting.py learning_rate.py loss.py tab_inter.py data_modifier.py ewald_recp.py) +file(GLOB LIB_PY descrpt_*.py deep_*.py network.py fitting.py learning_rate.py loss.py tab_inter.py ewald_recp.py data_modifier.py data.py data_system.py) install( FILES ${LIB_PY} diff --git a/source/train/Data.py b/source/api/data.py similarity index 83% rename from source/train/Data.py rename to source/api/data.py index b38839a546..d2565afe46 100644 --- a/source/train/Data.py +++ b/source/api/data.py @@ -4,16 +4,38 @@ import glob import numpy as np import os.path +from typing import Tuple, List + from deepmd.RunOptions import global_np_float_precision from deepmd.RunOptions import global_ener_float_precision class DeepmdData() : + """ + Class for a data system. + It loads data from hard disk, and mantains the data as a `data_dict` + """ def __init__ (self, - sys_path, - set_prefix = 'set', - shuffle_test = True, - type_map = None, + sys_path : str, + set_prefix : str = 'set', + shuffle_test : bool = True, + type_map : List[str] = None, modifier = None) : + """ + Constructor + + Parameters + ---------- + sys_path + Path to the data system + set_prefix + Prefix for the directories of different sets + shuffle_test + If the test data are shuffled + type_map + Gives the name of different atom types + modifier + Data modifier that has the method `modify_data` + """ self.dirs = glob.glob (os.path.join(sys_path, set_prefix + ".*")) self.dirs.sort() # load atom type @@ -52,13 +74,37 @@ def __init__ (self, def add(self, - key, - ndof, - atomic = False, - must = False, - high_prec = False, - type_sel = None, - repeat = 1) : + key : str, + ndof : int, + atomic : bool = False, + must : bool = False, + high_prec : bool = False, + type_sel : List[int] = None, + repeat : int = 1 + ) : + """ + Add a data item that to be loaded + + Parameters + ---------- + key + The key of the item. The corresponding data is stored in `sys_path/set.*/key.npy` + ndof + The number of dof + atomic + The item is an atomic property. + If False, the size of the data should be nframes x ndof + If True, the size of data should be nframes x natoms x ndof + must + The data file `sys_path/set.*/key.npy` must exist. + If must is False and the data file does not exist, the `data_dict[find_key]` is set to 0.0 + high_prec + Load the data and store in float64, otherwise in float32 + type_sel + Select certain type of atoms + repeat + The data will be repeated `repeat` times. + """ self.data_dict[key] = {'ndof': ndof, 'atomic': atomic, 'must': must, @@ -71,8 +117,19 @@ def add(self, def reduce(self, - key_out, - key_in) : + key_out : str, + key_in : str + ) : + """ + Generate a new item from the reduction of another atom + + Parameters + ---------- + key_out + The name of the reduced item + key_in + The name of the data item to be reduced + """ assert (key_in in self.data_dict), 'cannot find input key' assert (self.data_dict[key_in]['atomic']), 'reduced property should be atomic' assert (not(key_out in self.data_dict)), 'output key should not have been added' @@ -88,10 +145,16 @@ def reduce(self, } return self - def get_data_dict(self): + def get_data_dict(self) -> dict: + """ + Get the `data_dict` + """ return self.data_dict - def check_batch_size (self, batch_size) : + def check_batch_size (self, batch_size) : + """ + Check if the system can get a batch of data with `batch_size` frames. + """ for ii in self.train_dirs : if self.data_dict['coord']['high_prec'] : tmpe = np.load(os.path.join(ii, "coord.npy")).astype(global_ener_float_precision) @@ -104,6 +167,9 @@ def check_batch_size (self, batch_size) : return None def check_test_size (self, test_size) : + """ + Check if the system can get a test dataset with `test_size` frames. + """ if self.data_dict['coord']['high_prec'] : tmpe = np.load(os.path.join(self.test_dir, "coord.npy")).astype(global_ener_float_precision) else: @@ -115,7 +181,17 @@ def check_test_size (self, test_size) : else : return None - def get_batch(self, batch_size) : + def get_batch(self, + batch_size : int + ) -> dict : + """ + Get a batch of data with `batch_size` frames. The frames are randomly picked from the data system. + + Parameters + ---------- + batch_size + size of the batch + """ if hasattr(self, 'batch_set') : set_size = self.batch_set["coord"].shape[0] else : @@ -134,7 +210,17 @@ def get_batch(self, batch_size) : ret = self._get_subdata(self.batch_set, idx) return ret - def get_test (self, ntests = -1) : + def get_test (self, + ntests : int = -1 + ) -> dict: + """ + Get the test data with `ntests` frames. + + Parameters + ---------- + ntests + Size of the test data set. If `ntests` is -1, all test data will be get. + """ if not hasattr(self, 'test_set') : self._load_test_set(self.test_dir, self.shuffle_test) if ntests == -1: @@ -148,44 +234,89 @@ def get_test (self, ntests = -1) : self.modifier.modify_data(ret) return ret - def get_ntypes(self) : + def get_ntypes(self) -> int: + """ + Number of atom types in the system + """ if self.type_map is not None: return len(self.type_map) else: return max(self.get_atom_type()) + 1 - def get_type_map(self) : + def get_type_map(self) -> List[str]: + """ + Get the type map + """ return self.type_map - def get_atom_type(self) : + def get_atom_type(self) -> List[int]: + """ + Get atom types + """ return self.atom_type - def get_numb_set (self) : + def get_numb_set (self) -> int: + """ + Get number of training sets + """ return len (self.train_dirs) - def get_numb_batch (self, batch_size, set_idx) : + def get_numb_batch (self, + batch_size : int, + set_idx : int + ) -> int: + """ + Get the number of batches in a set. + """ data = self._load_set(self.train_dirs[set_idx]) ret = data["coord"].shape[0] // batch_size if ret == 0: ret = 1 return ret - def get_sys_numb_batch (self, batch_size) : + def get_sys_numb_batch (self, + batch_size : int + ) -> int: + """ + Get the number of batches in the data system. + """ ret = 0 for ii in range(len(self.train_dirs)) : ret += self.get_numb_batch(batch_size, ii) return ret def get_natoms (self) : + """ + Get number of atoms + """ return len(self.atom_type) - def get_natoms_vec (self, ntypes) : + def get_natoms_vec (self, + ntypes : int) : + """ + Get number of atoms and number of atoms in different types + + Parameters + ---------- + ntypes + Number of types (may be larger than the actual number of types in the system). + + Returns + ------- + natoms + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + """ natoms, natoms_vec = self._get_natoms_2 (ntypes) tmp = [natoms, natoms] tmp = np.append (tmp, natoms_vec) return tmp.astype(np.int32) def avg(self, key) : + """ + Return the average value of an item. + """ if key not in self.data_dict.keys() : raise RuntimeError('key %s has not been added' % key) info = self.data_dict[key] @@ -370,6 +501,9 @@ def _check_pbc(self, sys_path): class DataSets (object): + """ + Outdated class for one data system. Not maintained anymore. + """ def __init__ (self, sys_path, set_prefix, diff --git a/source/api/data_modifier.py b/source/api/data_modifier.py index b562d0dd2d..3718a32447 100644 --- a/source/api/data_modifier.py +++ b/source/api/data_modifier.py @@ -374,7 +374,25 @@ def _extend_system(self, coord, box, atype, charge): def modify_data(self, - data) -> None: + data : dict) -> None: + """ + Modify data. + + Parameters + ---------- + data + Internal data of DeepmdData. + Be a dict, has the following keys + - coord coordinates + - box simulation box + - type atom types + - find_energy tells if data has energy + - find_force tells if data has force + - find_virial tells if data has virial + - energy energy + - force force + - virial virial + """ if 'find_energy' not in data and 'find_force' not in data and 'find_virial' not in data: return diff --git a/source/train/DataSystem.py b/source/api/data_system.py similarity index 83% rename from source/train/DataSystem.py rename to source/api/data_system.py index 5aa866d550..8c14d0d213 100644 --- a/source/train/DataSystem.py +++ b/source/api/data_system.py @@ -4,20 +4,48 @@ import collections import warnings import numpy as np -from deepmd.Data import DataSets -from deepmd.Data import DeepmdData +from typing import Tuple, List + +from deepmd.data import DataSets +from deepmd.data import DeepmdData class DeepmdDataSystem() : + """ + Class for manipulating many data systems. + It is implemented with the help of DeepmdData + """ def __init__ (self, - systems, - batch_size, - test_size, - rcut, - set_prefix = 'set', - shuffle_test = True, - type_map = None, + systems : List[str], + batch_size : int, + test_size : int, + rcut : float, + set_prefix : str = 'set', + shuffle_test : bool = True, + type_map : List[str] = None, modifier = None) : + """ + Constructor + + Parameters + ---------- + systems + Specifying the paths to systems + batch_size + The batch size + test_size + The size of test data + rcut + The cut-off radius + set_prefix + Prefix for the directories of different sets + shuffle_test + If the test data are shuffled + type_map + Gives the name of different atom types + modifier + Data modifier that has the method `modify_data` + """ # init data self.rcut = rcut self.system_dirs = systems @@ -143,7 +171,22 @@ def compute_energy_shift(self, rcond = 1e-3, key = 'energy') : return energy_shift - def add_dict(self, adict) : + def add_dict(self, + adict : dict + ) -> None: + """ + Add items to the data system by a `dict`. + `adict` should have items like + adict[key] = { + 'ndof': ndof, + 'atomic': atomic, + 'must': must, + 'high_prec': high_prec, + 'type_sel': type_sel, + 'repeat': repeat, + } + For the explaination of the keys see `add` + """ for kk in adict : self.add(kk, adict[kk]['ndof'], @@ -154,24 +197,59 @@ def add_dict(self, adict) : repeat=adict[kk]['repeat']) def add(self, - key, - ndof, - atomic = False, - must = False, - high_prec = False, - type_sel = None, - repeat = 1) : + key : str, + ndof : int, + atomic : bool = False, + must : bool = False, + high_prec : bool = False, + type_sel : List[int] = None, + repeat : int = 1 + ) : + """ + Add a data item that to be loaded + + Parameters + ---------- + key + The key of the item. The corresponding data is stored in `sys_path/set.*/key.npy` + ndof + The number of dof + atomic + The item is an atomic property. + If False, the size of the data should be nframes x ndof + If True, the size of data should be nframes x natoms x ndof + must + The data file `sys_path/set.*/key.npy` must exist. + If must is False and the data file does not exist, the `data_dict[find_key]` is set to 0.0 + high_prec + Load the data and store in float64, otherwise in float32 + type_sel + Select certain type of atoms + repeat + The data will be repeated `repeat` times. + """ for ii in self.data_systems: ii.add(key, ndof, atomic=atomic, must=must, high_prec=high_prec, repeat=repeat, type_sel=type_sel) def reduce(self, key_out, key_in) : + """ + Generate a new item from the reduction of another atom + + Parameters + ---------- + key_out + The name of the reduced item + key_in + The name of the data item to be reduced + """ for ii in self.data_systems: ii.reduce(key_out, k_in) - def get_data_dict(self) : - return self.data_systems[0].get_data_dict() + def get_data_dict(self, + ii : int = 0) -> dict: + return self.data_systems[ii].get_data_dict() def _get_sys_probs(self, @@ -196,7 +274,7 @@ def get_batch (self, sys_probs = None, auto_prob_style = "prob_sys_size") : """ - Get a batch of data from the data system + Get a batch of data from the data systems Parameters ---------- @@ -232,9 +310,20 @@ def get_batch (self, # ! altered by Marián Rynik def get_test (self, - sys_idx = None, - n_test = -1) : + sys_idx : int = None, + n_test : int = -1 + ) : + """ + Get test data from the the data systems. + Parameters + ---------- + sys_idx + The test dat of system with index `sys_idx` will be returned. + If is None, the currently selected system will be returned. + n_test + Number of test data. If set to -1 all test data will be get. + """ if not hasattr(self, 'default_mesh') : self._make_default_mesh() if not hasattr(self, 'test_data') : @@ -252,29 +341,49 @@ def get_test (self, return test_system_data def get_sys_ntest(self, sys_idx=None): - """Get number of tests for the currently selected system, - or one defined by sys_idx.""" + """ + Get number of tests for the currently selected system, + or one defined by sys_idx. + """ if sys_idx is not None : return self.test_size[sys_idx] else : return self.test_size[self.pick_idx] - def get_type_map(self): + def get_type_map(self) -> List[str]: + """ + Get the type map + """ return self.type_map - def get_nbatches (self) : + def get_nbatches (self) -> int: + """ + Get the total number of batches + """ return self.nbatches - def get_ntypes (self) : + def get_ntypes (self) -> int: + """ + Get the number of types + """ return self.sys_ntypes - def get_nsystems (self) : + def get_nsystems (self) -> int: + """ + Get the number of data systems + """ return self.nsystems - def get_sys (self, idx) : + def get_sys (self, idx : int) -> DeepmdData: + """ + Get a certain data system + """ return self.data_systems[idx] - def get_batch_size(self) : + def get_batch_size(self) -> int: + """ + Get the batch size + """ return self.batch_size def _format_name_length(self, name, width) : @@ -378,6 +487,9 @@ def _prob_sys_size_ext(self, keywords): class DataSystem (object) : + """ + Outdated class for the data systems. Not maintained anymore. + """ def __init__ (self, systems, set_prefix, diff --git a/source/tests/test_data_modifier.py b/source/tests/test_data_modifier.py index a88415e505..ed1ab78b71 100644 --- a/source/tests/test_data_modifier.py +++ b/source/tests/test_data_modifier.py @@ -6,7 +6,7 @@ from deepmd.common import j_must_have, data_requirement, j_loader from deepmd.RunOptions import RunOptions from deepmd.Trainer import NNPTrainer -from deepmd.DataSystem import DeepmdDataSystem +from deepmd.data_system import DeepmdDataSystem from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.RunOptions import global_ener_float_precision diff --git a/source/tests/test_data_modifier_shuffle.py b/source/tests/test_data_modifier_shuffle.py index cf4a3757a3..4851df648b 100644 --- a/source/tests/test_data_modifier_shuffle.py +++ b/source/tests/test_data_modifier_shuffle.py @@ -7,7 +7,7 @@ from deepmd.common import j_must_have, data_requirement from deepmd.RunOptions import RunOptions from deepmd.Trainer import NNPTrainer -from deepmd.DataSystem import DeepmdDataSystem +from deepmd.data_system import DeepmdDataSystem from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.RunOptions import global_ener_float_precision diff --git a/source/tests/test_deepmd_data.py b/source/tests/test_deepmd_data.py index 005ab26893..d82155ce71 100644 --- a/source/tests/test_deepmd_data.py +++ b/source/tests/test_deepmd_data.py @@ -2,7 +2,7 @@ import numpy as np import unittest -from deepmd.Data import DeepmdData +from deepmd.data import DeepmdData from deepmd.RunOptions import global_np_float_precision if global_np_float_precision == np.float32 : diff --git a/source/tests/test_deepmd_data_sys.py b/source/tests/test_deepmd_data_sys.py index 4cbf2af1b7..a2e85a7765 100644 --- a/source/tests/test_deepmd_data_sys.py +++ b/source/tests/test_deepmd_data_sys.py @@ -2,7 +2,7 @@ import numpy as np import unittest -from deepmd.DataSystem import DeepmdDataSystem +from deepmd.data_system import DeepmdDataSystem from deepmd.RunOptions import global_np_float_precision if global_np_float_precision == np.float32 : diff --git a/source/tests/test_gen_stat_data.py b/source/tests/test_gen_stat_data.py index 68b3019965..612b47a3fe 100644 --- a/source/tests/test_gen_stat_data.py +++ b/source/tests/test_gen_stat_data.py @@ -3,7 +3,7 @@ import unittest import dpdata -from deepmd.DataSystem import DeepmdDataSystem +from deepmd.data_system import DeepmdDataSystem from deepmd.fitting import EnerFitting from deepmd.Model import make_stat_input, merge_sys_stat, _make_all_stat_ref diff --git a/source/tests/test_model_loc_frame.py b/source/tests/test_model_loc_frame.py index 4c12c4a732..cd5fdb2067 100644 --- a/source/tests/test_model_loc_frame.py +++ b/source/tests/test_model_loc_frame.py @@ -4,7 +4,7 @@ from common import Data,gen_data from deepmd.RunOptions import RunOptions -from deepmd.DataSystem import DataSystem +from deepmd.data_system import DataSystem from deepmd.descrpt_loc_frame import DescrptLocFrame from deepmd.fitting import EnerFitting from deepmd.Model import Model diff --git a/source/tests/test_model_se_a.py b/source/tests/test_model_se_a.py index 59c96fa35c..6bb80ba0b7 100644 --- a/source/tests/test_model_se_a.py +++ b/source/tests/test_model_se_a.py @@ -5,7 +5,7 @@ from common import Data,gen_data from deepmd.RunOptions import RunOptions -from deepmd.DataSystem import DataSystem +from deepmd.data_system import DataSystem from deepmd.descrpt_se_a import DescrptSeA from deepmd.fitting import EnerFitting from deepmd.Model import Model diff --git a/source/tests/test_model_se_a_aparam.py b/source/tests/test_model_se_a_aparam.py index 23edf54215..0582024542 100644 --- a/source/tests/test_model_se_a_aparam.py +++ b/source/tests/test_model_se_a_aparam.py @@ -4,7 +4,7 @@ from common import Data,gen_data from deepmd.RunOptions import RunOptions -from deepmd.DataSystem import DataSystem +from deepmd.data_system import DataSystem from deepmd.descrpt_se_a import DescrptSeA from deepmd.fitting import EnerFitting from deepmd.Model import Model diff --git a/source/tests/test_model_se_a_fparam.py b/source/tests/test_model_se_a_fparam.py index 4125c911fb..642bcf4071 100644 --- a/source/tests/test_model_se_a_fparam.py +++ b/source/tests/test_model_se_a_fparam.py @@ -4,7 +4,7 @@ from common import Data,gen_data from deepmd.RunOptions import RunOptions -from deepmd.DataSystem import DataSystem +from deepmd.data_system import DataSystem from deepmd.descrpt_se_a import DescrptSeA from deepmd.fitting import EnerFitting from deepmd.Model import Model diff --git a/source/tests/test_model_se_a_srtab.py b/source/tests/test_model_se_a_srtab.py index 2389421ec3..338df18a6c 100644 --- a/source/tests/test_model_se_a_srtab.py +++ b/source/tests/test_model_se_a_srtab.py @@ -4,7 +4,7 @@ from common import Data,gen_data from deepmd.RunOptions import RunOptions -from deepmd.DataSystem import DataSystem +from deepmd.data_system import DataSystem from deepmd.descrpt_se_a import DescrptSeA from deepmd.fitting import EnerFitting from deepmd.Model import Model diff --git a/source/tests/test_model_se_r.py b/source/tests/test_model_se_r.py index fa0a594199..8aa6e6a383 100644 --- a/source/tests/test_model_se_r.py +++ b/source/tests/test_model_se_r.py @@ -4,7 +4,7 @@ from common import Data,gen_data from deepmd.RunOptions import RunOptions -from deepmd.DataSystem import DataSystem +from deepmd.data_system import DataSystem from deepmd.descrpt_se_r import DescrptSeR from deepmd.fitting import EnerFitting from deepmd.Model import Model diff --git a/source/tests/test_polar_se_a.py b/source/tests/test_polar_se_a.py index 0ce8873836..de2625ac9c 100644 --- a/source/tests/test_polar_se_a.py +++ b/source/tests/test_polar_se_a.py @@ -4,7 +4,7 @@ from common import Data,gen_data from deepmd.RunOptions import RunOptions -from deepmd.DataSystem import DataSystem +from deepmd.data_system import DataSystem from deepmd.descrpt_se_a import DescrptSeA from deepmd.fitting import PolarFittingSeA from deepmd.Model import PolarModel diff --git a/source/tests/test_wfc.py b/source/tests/test_wfc.py index a03cfa2262..b567a7717f 100644 --- a/source/tests/test_wfc.py +++ b/source/tests/test_wfc.py @@ -4,7 +4,7 @@ from common import Data,gen_data from deepmd.RunOptions import RunOptions -from deepmd.DataSystem import DataSystem +from deepmd.data_system import DataSystem from deepmd.descrpt_loc_frame import DescrptLocFrame from deepmd.fitting import WFCFitting from deepmd.Model import WFCModel diff --git a/source/train/test.py b/source/train/test.py index a4e7a2aa7b..c4fa7476f2 100644 --- a/source/train/test.py +++ b/source/train/test.py @@ -6,7 +6,7 @@ import argparse import numpy as np -from deepmd.Data import DeepmdData +from deepmd.data import DeepmdData from deepmd.common import expand_sys_str from deepmd import DeepEval from deepmd import DeepPot diff --git a/source/train/train.py b/source/train/train.py index 2b57026139..4307695cfe 100755 --- a/source/train/train.py +++ b/source/train/train.py @@ -8,7 +8,7 @@ from deepmd.env import tf from deepmd.compat import convert_input_v0_v1 from deepmd.RunOptions import RunOptions -from deepmd.DataSystem import DeepmdDataSystem +from deepmd.data_system import DeepmdDataSystem from deepmd.Trainer import NNPTrainer from deepmd.common import data_requirement, expand_sys_str, j_loader from deepmd.data_modifier import DipoleChargeModifier From 2a8500cb719dfb2ff688e210bd7ceea7a181c5a9 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 17 Jan 2021 17:55:38 +0800 Subject: [PATCH 048/562] install the package in a pythonic way --- deepmd/__init__.py | 18 +- deepmd/descriptor/__init__.py | 9 + .../descriptor/hybrid.py | 19 +- .../descriptor/loc_frame.py | 0 .../descriptor/se_a.py | 2 +- .../descriptor/se_a_ebd.py | 6 +- .../descriptor/se_a_ef.py | 2 +- .../descriptor/se_a_t.py | 2 +- .../descriptor/se_ar.py | 4 +- .../descriptor/se_r.py | 2 +- deepmd/fit/__init__.py | 6 + deepmd/fit/dipole.py | 158 +++ deepmd/fit/ener.py | 368 ++++++ deepmd/fit/polar.py | 432 +++++++ deepmd/fit/wfc.py | 98 ++ deepmd/infer/__init__.py | 0 {source/api => deepmd/infer}/data_modifier.py | 4 +- {source/api => deepmd/infer}/deep_dipole.py | 2 +- {source/api => deepmd/infer}/deep_eval.py | 0 {source/api => deepmd/infer}/deep_polar.py | 2 +- {source/api => deepmd/infer}/deep_pot.py | 4 +- {source/api => deepmd/infer}/deep_wfc.py | 2 +- {source/api => deepmd/infer}/ewald_recp.py | 0 deepmd/loss/__init__.py | 4 + source/api/loss.py => deepmd/loss/ener.py | 86 -- deepmd/loss/tensor.py | 91 ++ deepmd/utils/__init__.py | 8 + {source/api => deepmd/utils}/data.py | 0 {source/api => deepmd/utils}/data_system.py | 4 +- {source/api => deepmd/utils}/learning_rate.py | 0 {source/api => deepmd/utils}/network.py | 0 {source/api => deepmd/utils}/tab_inter.py | 0 setup.py | 8 +- source/api/CMakeLists.txt | 8 - source/api/fitting.py | 1016 ----------------- source/tests/test_data_modifier.py | 6 +- source/tests/test_data_modifier_shuffle.py | 8 +- source/tests/test_deepmd_data.py | 2 +- source/tests/test_deepmd_data_sys.py | 2 +- source/tests/test_descrpt_nonsmth.py | 2 +- source/tests/test_descrpt_se_ar.py | 2 +- source/tests/test_descrpt_se_r.py | 2 +- source/tests/test_descrpt_sea_ef.py | 2 +- source/tests/test_descrpt_sea_ef_para.py | 2 +- source/tests/test_descrpt_sea_ef_rot.py | 4 +- source/tests/test_descrpt_sea_ef_vert.py | 2 +- source/tests/test_descrpt_smooth.py | 2 +- source/tests/test_embedding_net.py | 2 +- source/tests/test_ewald.py | 4 +- source/tests/test_fitting_stat.py | 4 +- source/tests/test_gen_stat_data.py | 4 +- source/tests/test_model_loc_frame.py | 6 +- source/tests/test_model_se_a.py | 6 +- source/tests/test_model_se_a_aparam.py | 6 +- source/tests/test_model_se_a_fparam.py | 6 +- source/tests/test_model_se_a_srtab.py | 6 +- source/tests/test_model_se_r.py | 6 +- source/tests/test_polar_se_a.py | 6 +- source/tests/test_tab_nonsmth.py | 4 +- source/tests/test_tab_smooth.py | 4 +- source/tests/test_wfc.py | 6 +- source/train/Model.py | 2 +- source/train/Trainer.py | 20 +- source/train/test.py | 2 +- source/train/train.py | 4 +- 65 files changed, 1291 insertions(+), 1208 deletions(-) create mode 100644 deepmd/descriptor/__init__.py rename source/api/descrpt_hybrid.py => deepmd/descriptor/hybrid.py (93%) rename source/api/descrpt_loc_frame.py => deepmd/descriptor/loc_frame.py (100%) rename source/api/descrpt_se_a.py => deepmd/descriptor/se_a.py (99%) rename source/api/descrpt_se_a_ebd.py => deepmd/descriptor/se_a_ebd.py (99%) rename source/api/descrpt_se_a_ef.py => deepmd/descriptor/se_a_ef.py (99%) rename source/api/descrpt_se_a_t.py => deepmd/descriptor/se_a_t.py (99%) rename source/api/descrpt_se_ar.py => deepmd/descriptor/se_ar.py (97%) rename source/api/descrpt_se_r.py => deepmd/descriptor/se_r.py (99%) create mode 100644 deepmd/fit/__init__.py create mode 100644 deepmd/fit/dipole.py create mode 100644 deepmd/fit/ener.py create mode 100644 deepmd/fit/polar.py create mode 100644 deepmd/fit/wfc.py create mode 100644 deepmd/infer/__init__.py rename {source/api => deepmd/infer}/data_modifier.py (99%) rename {source/api => deepmd/infer}/deep_dipole.py (94%) rename {source/api => deepmd/infer}/deep_eval.py (100%) rename {source/api => deepmd/infer}/deep_polar.py (97%) rename {source/api => deepmd/infer}/deep_pot.py (99%) rename {source/api => deepmd/infer}/deep_wfc.py (84%) rename {source/api => deepmd/infer}/ewald_recp.py (100%) create mode 100644 deepmd/loss/__init__.py rename source/api/loss.py => deepmd/loss/ener.py (84%) create mode 100644 deepmd/loss/tensor.py create mode 100644 deepmd/utils/__init__.py rename {source/api => deepmd/utils}/data.py (100%) rename {source/api => deepmd/utils}/data_system.py (99%) rename {source/api => deepmd/utils}/learning_rate.py (100%) rename {source/api => deepmd/utils}/network.py (100%) rename {source/api => deepmd/utils}/tab_inter.py (100%) delete mode 100644 source/api/CMakeLists.txt delete mode 100644 source/api/fitting.py diff --git a/deepmd/__init__.py b/deepmd/__init__.py index 5ead16e4c9..a856bfe13d 100644 --- a/deepmd/__init__.py +++ b/deepmd/__init__.py @@ -1,10 +1,16 @@ +from . import descriptor +from . import fit +from . import loss +from . import utils +import deepmd.utils.network as network +from .infer.deep_eval import DeepEval +from .infer.deep_pot import DeepPot +from .infer.deep_dipole import DeepDipole +from .infer.deep_polar import DeepPolar +from .infer.deep_polar import DeepGlobalPolar +from .infer.deep_wfc import DeepWFC +from .infer.data_modifier import DipoleChargeModifier from .env import set_mkl -from .deep_eval import DeepEval -from .deep_pot import DeepPot -from .deep_dipole import DeepDipole -from .deep_polar import DeepPolar -from .deep_polar import DeepGlobalPolar -from .deep_wfc import DeepWFC set_mkl() diff --git a/deepmd/descriptor/__init__.py b/deepmd/descriptor/__init__.py new file mode 100644 index 0000000000..b08ca170f1 --- /dev/null +++ b/deepmd/descriptor/__init__.py @@ -0,0 +1,9 @@ +from .hybrid import DescrptHybrid +from .se_a import DescrptSeA +from .se_r import DescrptSeR +from .se_ar import DescrptSeAR +from .se_a_t import DescrptSeAT +from .se_a_ebd import DescrptSeAEbd +from .se_a_ef import DescrptSeAEf +from .se_a_ef import DescrptSeAEfLower +from .loc_frame import DescrptLocFrame diff --git a/source/api/descrpt_hybrid.py b/deepmd/descriptor/hybrid.py similarity index 93% rename from source/api/descrpt_hybrid.py rename to deepmd/descriptor/hybrid.py index 64993cc6d1..f16db2a280 100644 --- a/source/api/descrpt_hybrid.py +++ b/deepmd/descriptor/hybrid.py @@ -6,12 +6,19 @@ from deepmd.env import op_module from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision -from deepmd.descrpt_loc_frame import DescrptLocFrame -from deepmd.descrpt_se_a import DescrptSeA -from deepmd.descrpt_se_a_t import DescrptSeAT -from deepmd.descrpt_se_a_ebd import DescrptSeAEbd -from deepmd.descrpt_se_a_ef import DescrptSeAEf -from deepmd.descrpt_se_r import DescrptSeR +# from deepmd.descriptor import DescrptLocFrame +# from deepmd.descriptor import DescrptSeA +# from deepmd.descriptor import DescrptSeAT +# from deepmd.descriptor import DescrptSeAEbd +# from deepmd.descriptor import DescrptSeAEf +# from deepmd.descriptor import DescrptSeR +from .se_a import DescrptSeA +from .se_r import DescrptSeR +from .se_ar import DescrptSeAR +from .se_a_t import DescrptSeAT +from .se_a_ebd import DescrptSeAEbd +from .se_a_ef import DescrptSeAEf +from .loc_frame import DescrptLocFrame class DescrptHybrid (): def __init__ (self, diff --git a/source/api/descrpt_loc_frame.py b/deepmd/descriptor/loc_frame.py similarity index 100% rename from source/api/descrpt_loc_frame.py rename to deepmd/descriptor/loc_frame.py diff --git a/source/api/descrpt_se_a.py b/deepmd/descriptor/se_a.py similarity index 99% rename from source/api/descrpt_se_a.py rename to deepmd/descriptor/se_a.py index 60ca39b98a..884f024357 100644 --- a/source/api/descrpt_se_a.py +++ b/deepmd/descriptor/se_a.py @@ -8,7 +8,7 @@ from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module from deepmd.env import default_tf_session_config -from deepmd.network import embedding_net +from deepmd.utils.network import embedding_net class DescrptSeA (): diff --git a/source/api/descrpt_se_a_ebd.py b/deepmd/descriptor/se_a_ebd.py similarity index 99% rename from source/api/descrpt_se_a_ebd.py rename to deepmd/descriptor/se_a_ebd.py index b627f2664f..5d3838f476 100644 --- a/source/api/descrpt_se_a_ebd.py +++ b/deepmd/descriptor/se_a_ebd.py @@ -3,13 +3,13 @@ from deepmd.env import tf from deepmd.common import ClassArg, get_activation_func, get_precision, add_data_requirement -from deepmd.network import one_layer +from deepmd.utils.network import one_layer from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module from deepmd.env import default_tf_session_config -from deepmd.descrpt_se_a import DescrptSeA -from deepmd.network import embedding_net +from deepmd.utils.network import embedding_net +from .se_a import DescrptSeA class DescrptSeAEbd (DescrptSeA): def __init__ (self, diff --git a/source/api/descrpt_se_a_ef.py b/deepmd/descriptor/se_a_ef.py similarity index 99% rename from source/api/descrpt_se_a_ef.py rename to deepmd/descriptor/se_a_ef.py index 49a0263fbc..a58b465f6e 100644 --- a/source/api/descrpt_se_a_ef.py +++ b/deepmd/descriptor/se_a_ef.py @@ -8,7 +8,7 @@ from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module from deepmd.env import default_tf_session_config -from deepmd.descrpt_se_a import DescrptSeA +from .se_a import DescrptSeA class DescrptSeAEf (): @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) diff --git a/source/api/descrpt_se_a_t.py b/deepmd/descriptor/se_a_t.py similarity index 99% rename from source/api/descrpt_se_a_t.py rename to deepmd/descriptor/se_a_t.py index eaf1f54170..1639edbe5c 100644 --- a/source/api/descrpt_se_a_t.py +++ b/deepmd/descriptor/se_a_t.py @@ -8,7 +8,7 @@ from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module from deepmd.env import default_tf_session_config -from deepmd.network import embedding_net +from deepmd.utils.network import embedding_net class DescrptSeAT (): @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) diff --git a/source/api/descrpt_se_ar.py b/deepmd/descriptor/se_ar.py similarity index 97% rename from source/api/descrpt_se_ar.py rename to deepmd/descriptor/se_ar.py index 25cf1a9727..8ded2c5849 100644 --- a/source/api/descrpt_se_ar.py +++ b/deepmd/descriptor/se_ar.py @@ -2,8 +2,8 @@ from deepmd.env import tf from deepmd.common import ClassArg -from deepmd.descrpt_se_a import DescrptSeA -from deepmd.descrpt_se_r import DescrptSeR +from .se_a import DescrptSeA +from .se_r import DescrptSeR from deepmd.env import op_module class DescrptSeAR (): diff --git a/source/api/descrpt_se_r.py b/deepmd/descriptor/se_r.py similarity index 99% rename from source/api/descrpt_se_r.py rename to deepmd/descriptor/se_r.py index ad2f5b5051..353a531d3d 100644 --- a/source/api/descrpt_se_r.py +++ b/deepmd/descriptor/se_r.py @@ -8,7 +8,7 @@ from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module from deepmd.env import default_tf_session_config -from deepmd.network import embedding_net +from deepmd.utils.network import embedding_net class DescrptSeR (): @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) diff --git a/deepmd/fit/__init__.py b/deepmd/fit/__init__.py new file mode 100644 index 0000000000..71d582e8ca --- /dev/null +++ b/deepmd/fit/__init__.py @@ -0,0 +1,6 @@ +from .ener import EnerFitting +from .wfc import WFCFitting +from .dipole import DipoleFittingSeA +from .polar import PolarFittingSeA +from .polar import GlobalPolarFittingSeA +from .polar import PolarFittingLocFrame diff --git a/deepmd/fit/dipole.py b/deepmd/fit/dipole.py new file mode 100644 index 0000000000..de3b34626e --- /dev/null +++ b/deepmd/fit/dipole.py @@ -0,0 +1,158 @@ +import warnings +import numpy as np +from typing import Tuple, List + +from deepmd.env import tf +from deepmd.common import add_data_requirement, get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter +from deepmd.argcheck import list_to_doc +from deepmd.utils.network import one_layer +from deepmd.descriptor import DescrptSeA + +from deepmd.RunOptions import global_cvt_2_tf_float +from deepmd.RunOptions import global_tf_float_precision + +class DipoleFittingSeA () : + """ + Fit the atomic dipole with descriptor se_a + """ + @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + def __init__ (self, + descrpt : tf.Tensor, + neuron : List[int] = [120,120,120], + resnet_dt : bool = True, + sel_type : List[int] = None, + seed : int = 1, + activation_function : str = 'tanh', + precision : str = 'default' + ) : + """ + Constructor + + Parameters + ---------- + descrpt : tf.Tensor + The descrptor + neuron : List[int] + Number of neurons in each hidden layer of the fitting net + resnet_dt : bool + Time-step `dt` in the resnet construction: + y = x + dt * \phi (Wx + b) + sel_type : List[int] + The atom types selected to have an atomic dipole prediction. If is None, all atoms are selected. + seed : int + Random seed for initializing the network parameters. + activation_function : str + The activation function in the embedding net. Supported options are {0} + precision : str + The precision of the embedding net parameters. Supported options are {1} + """ + if not isinstance(descrpt, DescrptSeA) : + raise RuntimeError('DipoleFittingSeA only supports DescrptSeA') + self.ntypes = descrpt.get_ntypes() + self.dim_descrpt = descrpt.get_dim_out() + # args = ClassArg()\ + # .add('neuron', list, default = [120,120,120], alias = 'n_neuron')\ + # .add('resnet_dt', bool, default = True)\ + # .add('sel_type', [list,int], default = [ii for ii in range(self.ntypes)], alias = 'dipole_type')\ + # .add('seed', int)\ + # .add("activation_function", str, default = "tanh")\ + # .add('precision', str, default = "default") + # class_data = args.parse(jdata) + self.n_neuron = neuron + self.resnet_dt = resnet_dt + self.sel_type = sel_type + if self.sel_type is None: + self.sel_type = [ii for ii in range(self.ntypes)] + self.sel_type = sel_type + self.seed = seed + self.fitting_activation_fn = get_activation_func(activation_function) + self.fitting_precision = get_precision(precision) + self.dim_rot_mat_1 = descrpt.get_dim_rot_mat_1() + self.dim_rot_mat = self.dim_rot_mat_1 * 3 + self.useBN = False + + def get_sel_type(self) -> int: + """ + Get selected type + """ + return self.sel_type + + def get_out_size(self) -> int: + """ + Get the output size. Should be 3 + """ + return 3 + + def build (self, + input_d : tf.Tensor, + rot_mat : tf.Tensor, + natoms : tf.Tensor, + reuse : bool = None, + suffix : str = '') -> tf.Tensor: + """ + Build the computational graph for fitting net + + Parameters + ---------- + input_d + The input descriptor + rot_mat + The rotation matrix from the descriptor. + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + reuse + The weights in the networks should be reused when get the variable. + suffix + Name suffix to identify this descriptor + + Return + ------ + dipole + The atomic dipole. + """ + start_index = 0 + inputs = tf.cast(tf.reshape(input_d, [-1, self.dim_descrpt * natoms[0]]), self.fitting_precision) + rot_mat = tf.reshape(rot_mat, [-1, self.dim_rot_mat * natoms[0]]) + + count = 0 + for type_i in range(self.ntypes): + # cut-out inputs + inputs_i = tf.slice (inputs, + [ 0, start_index* self.dim_descrpt], + [-1, natoms[2+type_i]* self.dim_descrpt] ) + inputs_i = tf.reshape(inputs_i, [-1, self.dim_descrpt]) + rot_mat_i = tf.slice (rot_mat, + [ 0, start_index* self.dim_rot_mat], + [-1, natoms[2+type_i]* self.dim_rot_mat] ) + rot_mat_i = tf.reshape(rot_mat_i, [-1, self.dim_rot_mat_1, 3]) + start_index += natoms[2+type_i] + if not type_i in self.sel_type : + continue + layer = inputs_i + for ii in range(0,len(self.n_neuron)) : + if ii >= 1 and self.n_neuron[ii] == self.n_neuron[ii-1] : + layer+= one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, use_timestep = self.resnet_dt, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision) + else : + layer = one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision) + # (nframes x natoms) x naxis + final_layer = one_layer(layer, self.dim_rot_mat_1, activation_fn = None, name='final_layer_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, precision = self.fitting_precision) + # (nframes x natoms) x 1 * naxis + final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0] * natoms[2+type_i], 1, self.dim_rot_mat_1]) + # (nframes x natoms) x 1 x 3(coord) + final_layer = tf.matmul(final_layer, rot_mat_i) + # nframes x natoms x 3 + final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0], natoms[2+type_i], 3]) + + # concat the results + if count == 0: + outs = final_layer + else: + outs = tf.concat([outs, final_layer], axis = 1) + count += 1 + + tf.summary.histogram('fitting_net_output', outs) + return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) + # return tf.reshape(outs, [tf.shape(inputs)[0] * natoms[0] * 3 // 3]) diff --git a/deepmd/fit/ener.py b/deepmd/fit/ener.py new file mode 100644 index 0000000000..34f9cc08be --- /dev/null +++ b/deepmd/fit/ener.py @@ -0,0 +1,368 @@ +import warnings +import numpy as np +from typing import Tuple, List + +from deepmd.env import tf +from deepmd.common import ClassArg, add_data_requirement, get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter +from deepmd.argcheck import list_to_doc +from deepmd.utils.network import one_layer +from deepmd.descriptor import DescrptLocFrame +from deepmd.descriptor import DescrptSeA + +from deepmd.RunOptions import global_cvt_2_tf_float +from deepmd.RunOptions import global_tf_float_precision + +class EnerFitting (): + @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + def __init__ (self, + descrpt : tf.Tensor, + neuron : List[int] = [120,120,120], + resnet_dt : bool = True, + numb_fparam : int = 0, + numb_aparam : int = 0, + rcond : float = 1e-3, + tot_ener_zero : bool = False, + trainable : List[bool] = None, + seed : int = 1, + atom_ener : List[float] = [], + activation_function : str = 'tanh', + precision : str = 'default' + ) -> None: + """ + Constructor + + Parameters + ---------- + descrpt + The descrptor + neuron + Number of neurons in each hidden layer of the fitting net + resnet_dt + Time-step `dt` in the resnet construction: + y = x + dt * \phi (Wx + b) + numb_fparam + Number of frame parameter + numb_aparam + Number of atomic parameter + rcond + The condition number for the regression of atomic energy. + tot_ener_zero + Force the total energy to zero. Useful for the charge fitting. + trainable + If the weights of fitting net are trainable. + Suppose that we have N_l hidden layers in the fitting net, + this list is of length N_l + 1, specifying if the hidden layers and the output layer are trainable. + seed + Random seed for initializing the network parameters. + atom_ener + Specifying atomic energy contribution in vacuum. The `set_davg_zero` key in the descrptor should be set. + activation_function + The activation function in the embedding net. Supported options are {0} + precision + The precision of the embedding net parameters. Supported options are {1} + """ + # model param + self.ntypes = descrpt.get_ntypes() + self.dim_descrpt = descrpt.get_dim_out() + # args = ClassArg()\ + # .add('numb_fparam', int, default = 0)\ + # .add('numb_aparam', int, default = 0)\ + # .add('neuron', list, default = [120,120,120], alias = 'n_neuron')\ + # .add('resnet_dt', bool, default = True)\ + # .add('rcond', float, default = 1e-3) \ + # .add('tot_ener_zero', bool, default = False) \ + # .add('seed', int) \ + # .add('atom_ener', list, default = [])\ + # .add("activation_function", str, default = "tanh")\ + # .add("precision", str, default = "default")\ + # .add("trainable", [list, bool], default = True) + self.numb_fparam = numb_fparam + self.numb_aparam = numb_aparam + self.n_neuron = neuron + self.resnet_dt = resnet_dt + self.rcond = rcond + self.seed = seed + self.tot_ener_zero = tot_ener_zero + self.fitting_activation_fn = get_activation_func(activation_function) + self.fitting_precision = get_precision(precision) + self.trainable = trainable + if self.trainable is None: + self.trainable = [True for ii in range(len(self.n_neuron) + 1)] + if type(self.trainable) is bool: + self.trainable = [self.trainable] * (len(self.n_neuron)+1) + assert(len(self.trainable) == len(self.n_neuron) + 1), 'length of trainable should be that of n_neuron + 1' + self.atom_ener = [] + for at, ae in enumerate(atom_ener): + if ae is not None: + self.atom_ener.append(tf.constant(ae, global_tf_float_precision, name = "atom_%d_ener" % at)) + else: + self.atom_ener.append(None) + self.useBN = False + self.bias_atom_e = None + # data requirement + if self.numb_fparam > 0 : + add_data_requirement('fparam', self.numb_fparam, atomic=False, must=True, high_prec=False) + self.fparam_avg = None + self.fparam_std = None + self.fparam_inv_std = None + if self.numb_aparam > 0: + add_data_requirement('aparam', self.numb_aparam, atomic=True, must=True, high_prec=False) + self.aparam_avg = None + self.aparam_std = None + self.aparam_inv_std = None + + def get_numb_fparam(self) -> int: + """ + Get the number of frame parameters + """ + return self.numb_fparam + + def get_numb_aparam(self) -> int: + """ + Get the number of atomic parameters + """ + return self.numb_fparam + + def compute_output_stats(self, + all_stat: dict + ) -> None: + """ + Compute the ouput statistics + + Parameters + ---------- + all_stat + must have the following components: + all_stat['energy'] of shape n_sys x n_batch x n_frame + can be prepared by model.make_stat_input + """ + self.bias_atom_e = self._compute_output_stats(all_stat, rcond = self.rcond) + + @classmethod + def _compute_output_stats(self, all_stat, rcond = 1e-3): + data = all_stat['energy'] + # data[sys_idx][batch_idx][frame_idx] + sys_ener = np.array([]) + for ss in range(len(data)): + sys_data = [] + for ii in range(len(data[ss])): + for jj in range(len(data[ss][ii])): + sys_data.append(data[ss][ii][jj]) + sys_data = np.concatenate(sys_data) + sys_ener = np.append(sys_ener, np.average(sys_data)) + data = all_stat['natoms_vec'] + sys_tynatom = np.array([]) + nsys = len(data) + for ss in range(len(data)): + sys_tynatom = np.append(sys_tynatom, data[ss][0].astype(np.float64)) + sys_tynatom = np.reshape(sys_tynatom, [nsys,-1]) + sys_tynatom = sys_tynatom[:,2:] + energy_shift,resd,rank,s_value \ + = np.linalg.lstsq(sys_tynatom, sys_ener, rcond = rcond) + return energy_shift + + def compute_input_stats(self, + all_stat : dict, + protection : float = 1e-2) -> None: + """ + Compute the input statistics + + Parameters: + all_stat + if numb_fparam > 0 must have all_stat['fparam'] + if numb_aparam > 0 must have all_stat['aparam'] + can be prepared by model.make_stat_input + protection + Divided-by-zero protection + """ + # stat fparam + if self.numb_fparam > 0: + cat_data = np.concatenate(all_stat['fparam'], axis = 0) + cat_data = np.reshape(cat_data, [-1, self.numb_fparam]) + self.fparam_avg = np.average(cat_data, axis = 0) + self.fparam_std = np.std(cat_data, axis = 0) + for ii in range(self.fparam_std.size): + if self.fparam_std[ii] < protection: + self.fparam_std[ii] = protection + self.fparam_inv_std = 1./self.fparam_std + # stat aparam + if self.numb_aparam > 0: + sys_sumv = [] + sys_sumv2 = [] + sys_sumn = [] + for ss_ in all_stat['aparam'] : + ss = np.reshape(ss_, [-1, self.numb_aparam]) + sys_sumv.append(np.sum(ss, axis = 0)) + sys_sumv2.append(np.sum(np.multiply(ss, ss), axis = 0)) + sys_sumn.append(ss.shape[0]) + sumv = np.sum(sys_sumv, axis = 0) + sumv2 = np.sum(sys_sumv2, axis = 0) + sumn = np.sum(sys_sumn) + self.aparam_avg = (sumv)/sumn + self.aparam_std = self._compute_std(sumv2, sumv, sumn) + for ii in range(self.aparam_std.size): + if self.aparam_std[ii] < protection: + self.aparam_std[ii] = protection + self.aparam_inv_std = 1./self.aparam_std + + + def _compute_std (self, sumv2, sumv, sumn) : + return np.sqrt(sumv2/sumn - np.multiply(sumv/sumn, sumv/sumn)) + + + def build (self, + inputs : tf.Tensor, + natoms : tf.Tensor, + input_dict : dict = {}, + reuse : bool = None, + suffix : str = '' + ) -> tf.Tensor: + """ + Build the computational graph for fitting net + + Parameters + ---------- + inputs + The input descriptor + input_dict + Additional dict for inputs. + if numb_fparam > 0, should have input_dict['fparam'] + if numb_aparam > 0, should have input_dict['aparam'] + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + reuse + The weights in the networks should be reused when get the variable. + suffix + Name suffix to identify this descriptor + + Return + ------ + ener + The system energy + """ + bias_atom_e = self.bias_atom_e + if self.numb_fparam > 0 and ( self.fparam_avg is None or self.fparam_inv_std is None ): + raise RuntimeError('No data stat result. one should do data statisitic, before build') + if self.numb_aparam > 0 and ( self.aparam_avg is None or self.aparam_inv_std is None ): + raise RuntimeError('No data stat result. one should do data statisitic, before build') + + with tf.variable_scope('fitting_attr' + suffix, reuse = reuse) : + t_dfparam = tf.constant(self.numb_fparam, + name = 'dfparam', + dtype = tf.int32) + t_daparam = tf.constant(self.numb_aparam, + name = 'daparam', + dtype = tf.int32) + if self.numb_fparam > 0: + t_fparam_avg = tf.get_variable('t_fparam_avg', + self.numb_fparam, + dtype = global_tf_float_precision, + trainable = False, + initializer = tf.constant_initializer(self.fparam_avg)) + t_fparam_istd = tf.get_variable('t_fparam_istd', + self.numb_fparam, + dtype = global_tf_float_precision, + trainable = False, + initializer = tf.constant_initializer(self.fparam_inv_std)) + if self.numb_aparam > 0: + t_aparam_avg = tf.get_variable('t_aparam_avg', + self.numb_aparam, + dtype = global_tf_float_precision, + trainable = False, + initializer = tf.constant_initializer(self.aparam_avg)) + t_aparam_istd = tf.get_variable('t_aparam_istd', + self.numb_aparam, + dtype = global_tf_float_precision, + trainable = False, + initializer = tf.constant_initializer(self.aparam_inv_std)) + + start_index = 0 + inputs = tf.cast(tf.reshape(inputs, [-1, self.dim_descrpt * natoms[0]]), self.fitting_precision) + + if bias_atom_e is not None : + assert(len(bias_atom_e) == self.ntypes) + + if self.numb_fparam > 0 : + fparam = input_dict['fparam'] + fparam = tf.reshape(fparam, [-1, self.numb_fparam]) + fparam = (fparam - t_fparam_avg) * t_fparam_istd + if self.numb_aparam > 0 : + aparam = input_dict['aparam'] + aparam = tf.reshape(aparam, [-1, self.numb_aparam]) + aparam = (aparam - t_aparam_avg) * t_aparam_istd + aparam = tf.reshape(aparam, [-1, self.numb_aparam * natoms[0]]) + + for type_i in range(self.ntypes): + # cut-out inputs + inputs_i = tf.slice (inputs, + [ 0, start_index* self.dim_descrpt], + [-1, natoms[2+type_i]* self.dim_descrpt] ) + inputs_i = tf.reshape(inputs_i, [-1, self.dim_descrpt]) + layer = inputs_i + if self.numb_fparam > 0 : + ext_fparam = tf.tile(fparam, [1, natoms[2+type_i]]) + ext_fparam = tf.reshape(ext_fparam, [-1, self.numb_fparam]) + ext_fparam = tf.cast(ext_fparam,self.fitting_precision) + layer = tf.concat([layer, ext_fparam], axis = 1) + if self.numb_aparam > 0 : + ext_aparam = tf.slice(aparam, + [ 0, start_index * self.numb_aparam], + [-1, natoms[2+type_i] * self.numb_aparam]) + ext_aparam = tf.reshape(ext_aparam, [-1, self.numb_aparam]) + ext_aparam = tf.cast(ext_aparam,self.fitting_precision) + layer = tf.concat([layer, ext_aparam], axis = 1) + start_index += natoms[2+type_i] + + if bias_atom_e is None : + type_bias_ae = 0.0 + else : + type_bias_ae = bias_atom_e[type_i] + + for ii in range(0,len(self.n_neuron)) : + if ii >= 1 and self.n_neuron[ii] == self.n_neuron[ii-1] : + layer+= one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, use_timestep = self.resnet_dt, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision, trainable = self.trainable[ii]) + else : + layer = one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision, trainable = self.trainable[ii]) + final_layer = one_layer(layer, 1, activation_fn = None, bavg = type_bias_ae, name='final_layer_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, precision = self.fitting_precision, trainable = self.trainable[-1]) + + if type_i < len(self.atom_ener) and self.atom_ener[type_i] is not None: + inputs_zero = tf.zeros_like(inputs_i, dtype=global_tf_float_precision) + layer = inputs_zero + if self.numb_fparam > 0 : + layer = tf.concat([layer, ext_fparam], axis = 1) + if self.numb_aparam > 0 : + layer = tf.concat([layer, ext_aparam], axis = 1) + for ii in range(0,len(self.n_neuron)) : + if ii >= 1 and self.n_neuron[ii] == self.n_neuron[ii-1] : + layer+= one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=True, seed = self.seed, use_timestep = self.resnet_dt, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision, trainable = self.trainable[ii]) + else : + layer = one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=True, seed = self.seed, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision, trainable = self.trainable[ii]) + zero_layer = one_layer(layer, 1, activation_fn = None, bavg = type_bias_ae, name='final_layer_type_'+str(type_i)+suffix, reuse=True, seed = self.seed, precision = self.fitting_precision, trainable = self.trainable[-1]) + final_layer += self.atom_ener[type_i] - zero_layer + + final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0], natoms[2+type_i]]) + + # concat the results + if type_i == 0: + outs = final_layer + else: + outs = tf.concat([outs, final_layer], axis = 1) + + if self.tot_ener_zero: + force_tot_ener = 0.0 + outs = tf.reshape(outs, [-1, natoms[0]]) + outs_mean = tf.reshape(tf.reduce_mean(outs, axis = 1), [-1, 1]) + outs_mean = outs_mean - tf.ones_like(outs_mean, dtype = global_tf_float_precision) * (force_tot_ener/global_cvt_2_tf_float(natoms[0])) + outs = outs - outs_mean + outs = tf.reshape(outs, [-1]) + + tf.summary.histogram('fitting_net_output', outs) + return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) + + + + + diff --git a/deepmd/fit/polar.py b/deepmd/fit/polar.py new file mode 100644 index 0000000000..f466195fc8 --- /dev/null +++ b/deepmd/fit/polar.py @@ -0,0 +1,432 @@ +import warnings +import numpy as np +from typing import Tuple, List + +from deepmd.env import tf +from deepmd.common import add_data_requirement, get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter +from deepmd.argcheck import list_to_doc +from deepmd.utils.network import one_layer +from deepmd.descriptor import DescrptLocFrame +from deepmd.descriptor import DescrptSeA + +from deepmd.RunOptions import global_cvt_2_tf_float +from deepmd.RunOptions import global_tf_float_precision + + +class PolarFittingLocFrame () : + """ + Fitting polarizability with local frame descriptor. not supported anymore. + """ + def __init__ (self, jdata, descrpt) : + if not isinstance(descrpt, DescrptLocFrame) : + raise RuntimeError('PolarFittingLocFrame only supports DescrptLocFrame') + self.ntypes = descrpt.get_ntypes() + self.dim_descrpt = descrpt.get_dim_out() + args = ClassArg()\ + .add('neuron', list, default = [120,120,120], alias = 'n_neuron')\ + .add('resnet_dt', bool, default = True)\ + .add('sel_type', [list,int], default = [ii for ii in range(self.ntypes)], alias = 'pol_type')\ + .add('seed', int)\ + .add("activation_function", str, default = "tanh")\ + .add('precision', str, default = "default") + class_data = args.parse(jdata) + self.n_neuron = class_data['neuron'] + self.resnet_dt = class_data['resnet_dt'] + self.sel_type = class_data['sel_type'] + self.seed = class_data['seed'] + self.fitting_activation_fn = get_activation_func(class_data["activation_function"]) + self.fitting_precision = get_precision(class_data['precision']) + self.useBN = False + + def get_sel_type(self): + return self.sel_type + + def get_out_size(self): + return 9 + + def build (self, + input_d, + rot_mat, + natoms, + reuse = None, + suffix = '') : + start_index = 0 + inputs = tf.cast(tf.reshape(input_d, [-1, self.dim_descrpt * natoms[0]]), self.fitting_precision) + rot_mat = tf.reshape(rot_mat, [-1, 9 * natoms[0]]) + + count = 0 + for type_i in range(self.ntypes): + # cut-out inputs + inputs_i = tf.slice (inputs, + [ 0, start_index* self.dim_descrpt], + [-1, natoms[2+type_i]* self.dim_descrpt] ) + inputs_i = tf.reshape(inputs_i, [-1, self.dim_descrpt]) + rot_mat_i = tf.slice (rot_mat, + [ 0, start_index* 9], + [-1, natoms[2+type_i]* 9] ) + rot_mat_i = tf.reshape(rot_mat_i, [-1, 3, 3]) + start_index += natoms[2+type_i] + if not type_i in self.sel_type : + continue + layer = inputs_i + for ii in range(0,len(self.n_neuron)) : + if ii >= 1 and self.n_neuron[ii] == self.n_neuron[ii-1] : + layer+= one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, use_timestep = self.resnet_dt, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision) + else : + layer = one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision) + # (nframes x natoms) x 9 + final_layer = one_layer(layer, 9, activation_fn = None, name='final_layer_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, precision = self.fitting_precision) + # (nframes x natoms) x 3 x 3 + final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0] * natoms[2+type_i], 3, 3]) + # (nframes x natoms) x 3 x 3 + final_layer = final_layer + tf.transpose(final_layer, perm = [0,2,1]) + # (nframes x natoms) x 3 x 3(coord) + final_layer = tf.matmul(final_layer, rot_mat_i) + # (nframes x natoms) x 3(coord) x 3(coord) + final_layer = tf.matmul(rot_mat_i, final_layer, transpose_a = True) + # nframes x natoms x 3 x 3 + final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0], natoms[2+type_i], 3, 3]) + + # concat the results + if count == 0: + outs = final_layer + else: + outs = tf.concat([outs, final_layer], axis = 1) + count += 1 + + tf.summary.histogram('fitting_net_output', outs) + return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) + + +class PolarFittingSeA () : + """ + Fit the atomic polarizability with descriptor se_a + """ + @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + def __init__ (self, + descrpt : tf.Tensor, + neuron : List[int] = [120,120,120], + resnet_dt : bool = True, + sel_type : List[int] = None, + fit_diag : bool = True, + scale : List[float] = None, + diag_shift : List[float] = None, + seed : int = 1, + activation_function : str = 'tanh', + precision : str = 'default' + ) -> None: + """ + Constructor + + Parameters + ---------- + descrpt : tf.Tensor + The descrptor + neuron : List[int] + Number of neurons in each hidden layer of the fitting net + resnet_dt : bool + Time-step `dt` in the resnet construction: + y = x + dt * \phi (Wx + b) + sel_type : List[int] + The atom types selected to have an atomic polarizability prediction. If is None, all atoms are selected. + fit_diag : bool + Fit the diagonal part of the rotational invariant polarizability matrix, which will be converted to normal polarizability matrix by contracting with the rotation matrix. + scale : List[float] + The output of the fitting net (polarizability matrix) for type i atom will be scaled by scale[i] + diag_shift : List[float] + The diagonal part of the polarizability matrix of type i will be shifted by diag_shift[i]. The shift operation is carried out after scale. + seed : int + Random seed for initializing the network parameters. + activation_function : str + The activation function in the embedding net. Supported options are {0} + precision : str + The precision of the embedding net parameters. Supported options are {1} + """ + if not isinstance(descrpt, DescrptSeA) : + raise RuntimeError('PolarFittingSeA only supports DescrptSeA') + self.ntypes = descrpt.get_ntypes() + self.dim_descrpt = descrpt.get_dim_out() + # args = ClassArg()\ + # .add('neuron', list, default = [120,120,120], alias = 'n_neuron')\ + # .add('resnet_dt', bool, default = True)\ + # .add('fit_diag', bool, default = True)\ + # .add('diag_shift', [list,float], default = [0.0 for ii in range(self.ntypes)])\ + # .add('scale', [list,float], default = [1.0 for ii in range(self.ntypes)])\ + # .add('sel_type', [list,int], default = [ii for ii in range(self.ntypes)], alias = 'pol_type')\ + # .add('seed', int)\ + # .add("activation_function", str , default = "tanh")\ + # .add('precision', str, default = "default") + # class_data = args.parse(jdata) + self.n_neuron = neuron + self.resnet_dt = resnet_dt + self.sel_type = sel_type + self.fit_diag = fit_diag + self.seed = seed + self.diag_shift = diag_shift + self.scale = scale + self.fitting_activation_fn = get_activation_func(activation_function) + self.fitting_precision = get_precision(precision) + if self.sel_type is None: + self.sel_type = [ii for ii in range(self.ntypes)] + if self.scale is None: + self.scale = [1.0 for ii in range(self.ntypes)] + if self.diag_shift is None: + self.diag_shift = [0.0 for ii in range(self.ntypes)] + if type(self.sel_type) is not list: + self.sel_type = [self.sel_type] + if type(self.diag_shift) is not list: + self.diag_shift = [self.diag_shift] + if type(self.scale) is not list: + self.scale = [self.scale] + self.dim_rot_mat_1 = descrpt.get_dim_rot_mat_1() + self.dim_rot_mat = self.dim_rot_mat_1 * 3 + self.useBN = False + + def get_sel_type(self) -> List[int]: + """ + Get selected atom types + """ + return self.sel_type + + def get_out_size(self) -> int: + """ + Get the output size. Should be 9 + """ + return 9 + + def compute_input_stats(self, + all_stat, + protection = 1e-2): + """ + Compute the input statistics + + Parameters: + all_stat + Dictionary of inputs. + can be prepared by model.make_stat_input + protection + Divided-by-zero protection + """ + if not ('polarizability' in all_stat.keys()): + self.avgeig = np.zeros([9]) + warnings.warn('no polarizability data, cannot do data stat. use zeros as guess') + return + data = all_stat['polarizability'] + all_tmp = [] + for ss in range(len(data)): + tmp = np.concatenate(data[ss], axis = 0) + tmp = np.reshape(tmp, [-1, 3, 3]) + tmp,_ = np.linalg.eig(tmp) + tmp = np.absolute(tmp) + tmp = np.sort(tmp, axis = 1) + all_tmp.append(tmp) + all_tmp = np.concatenate(all_tmp, axis = 1) + self.avgeig = np.average(all_tmp, axis = 0) + + def build (self, + input_d : tf.Tensor, + rot_mat : tf.Tensor, + natoms : tf.Tensor, + reuse : bool = None, + suffix : str = '') : + """ + Build the computational graph for fitting net + + Parameters + ---------- + input_d + The input descriptor + rot_mat + The rotation matrix from the descriptor. + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + reuse + The weights in the networks should be reused when get the variable. + suffix + Name suffix to identify this descriptor + + Return + ------ + atomic_polar + The atomic polarizability + """ + start_index = 0 + inputs = tf.cast(tf.reshape(input_d, [-1, self.dim_descrpt * natoms[0]]), self.fitting_precision) + rot_mat = tf.reshape(rot_mat, [-1, self.dim_rot_mat * natoms[0]]) + + count = 0 + for type_i in range(self.ntypes): + # cut-out inputs + inputs_i = tf.slice (inputs, + [ 0, start_index* self.dim_descrpt], + [-1, natoms[2+type_i]* self.dim_descrpt] ) + inputs_i = tf.reshape(inputs_i, [-1, self.dim_descrpt]) + rot_mat_i = tf.slice (rot_mat, + [ 0, start_index* self.dim_rot_mat], + [-1, natoms[2+type_i]* self.dim_rot_mat] ) + rot_mat_i = tf.reshape(rot_mat_i, [-1, self.dim_rot_mat_1, 3]) + start_index += natoms[2+type_i] + if not type_i in self.sel_type : + continue + layer = inputs_i + for ii in range(0,len(self.n_neuron)) : + if ii >= 1 and self.n_neuron[ii] == self.n_neuron[ii-1] : + layer+= one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, use_timestep = self.resnet_dt, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision) + else : + layer = one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision) + if self.fit_diag : + bavg = np.zeros(self.dim_rot_mat_1) + # bavg[0] = self.avgeig[0] + # bavg[1] = self.avgeig[1] + # bavg[2] = self.avgeig[2] + # (nframes x natoms) x naxis + final_layer = one_layer(layer, self.dim_rot_mat_1, activation_fn = None, name='final_layer_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, bavg = bavg, precision = self.fitting_precision) + # (nframes x natoms) x naxis + final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0] * natoms[2+type_i], self.dim_rot_mat_1]) + # (nframes x natoms) x naxis x naxis + final_layer = tf.matrix_diag(final_layer) + else : + bavg = np.zeros(self.dim_rot_mat_1*self.dim_rot_mat_1) + # bavg[0*self.dim_rot_mat_1+0] = self.avgeig[0] + # bavg[1*self.dim_rot_mat_1+1] = self.avgeig[1] + # bavg[2*self.dim_rot_mat_1+2] = self.avgeig[2] + # (nframes x natoms) x (naxis x naxis) + final_layer = one_layer(layer, self.dim_rot_mat_1*self.dim_rot_mat_1, activation_fn = None, name='final_layer_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, bavg = bavg, precision = self.fitting_precision) + # (nframes x natoms) x naxis x naxis + final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0] * natoms[2+type_i], self.dim_rot_mat_1, self.dim_rot_mat_1]) + # (nframes x natoms) x naxis x naxis + final_layer = final_layer + tf.transpose(final_layer, perm = [0,2,1]) + # (nframes x natoms) x naxis x 3(coord) + final_layer = tf.matmul(final_layer, rot_mat_i) + # (nframes x natoms) x 3(coord) x 3(coord) + final_layer = tf.matmul(rot_mat_i, final_layer, transpose_a = True) + # nframes x natoms x 3 x 3 + final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0], natoms[2+type_i], 3, 3]) + # shift and scale + sel_type_idx = self.sel_type.index(type_i) + final_layer = final_layer * self.scale[sel_type_idx] + final_layer = final_layer + self.diag_shift[sel_type_idx] * tf.eye(3, batch_shape=[tf.shape(inputs)[0], natoms[2+type_i]], dtype = global_tf_float_precision) + + # concat the results + if count == 0: + outs = final_layer + else: + outs = tf.concat([outs, final_layer], axis = 1) + count += 1 + + tf.summary.histogram('fitting_net_output', outs) + return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) + + +class GlobalPolarFittingSeA () : + """ + Fit the system polarizability with descriptor se_a + """ + @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + def __init__ (self, + descrpt : tf.Tensor, + neuron : List[int] = [120,120,120], + resnet_dt : bool = True, + sel_type : List[int] = None, + fit_diag : bool = True, + scale : List[float] = None, + diag_shift : List[float] = None, + seed : int = 1, + activation_function : str = 'tanh', + precision : str = 'default' + ) -> None: + """ + Constructor + + Parameters + ---------- + descrpt : tf.Tensor + The descrptor + neuron : List[int] + Number of neurons in each hidden layer of the fitting net + resnet_dt : bool + Time-step `dt` in the resnet construction: + y = x + dt * \phi (Wx + b) + sel_type : List[int] + The atom types selected to have an atomic polarizability prediction + fit_diag : bool + Fit the diagonal part of the rotational invariant polarizability matrix, which will be converted to normal polarizability matrix by contracting with the rotation matrix. + scale : List[float] + The output of the fitting net (polarizability matrix) for type i atom will be scaled by scale[i] + diag_shift : List[float] + The diagonal part of the polarizability matrix of type i will be shifted by diag_shift[i]. The shift operation is carried out after scale. + seed : int + Random seed for initializing the network parameters. + activation_function : str + The activation function in the embedding net. Supported options are {0} + precision : str + The precision of the embedding net parameters. Supported options are {1} + """ + if not isinstance(descrpt, DescrptSeA) : + raise RuntimeError('GlobalPolarFittingSeA only supports DescrptSeA') + self.ntypes = descrpt.get_ntypes() + self.dim_descrpt = descrpt.get_dim_out() + self.polar_fitting = PolarFittingSeA(descrpt, + neuron, + resnet_dt, + sel_type, + fit_diag, + scale, + diag_shift, + seed, + activation_function, + precision) + + def get_sel_type(self) -> int: + """ + Get selected atom types + """ + return self.polar_fitting.get_sel_type() + + def get_out_size(self) -> int: + """ + Get the output size. Should be 9 + """ + return self.polar_fitting.get_out_size() + + def build (self, + input_d, + rot_mat, + natoms, + reuse = None, + suffix = '') -> tf.Tensor: + """ + Build the computational graph for fitting net + + Parameters + ---------- + input_d + The input descriptor + rot_mat + The rotation matrix from the descriptor. + natoms + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: number of local atoms + natoms[1]: total number of atoms held by this processor + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms + reuse + The weights in the networks should be reused when get the variable. + suffix + Name suffix to identify this descriptor + + Return + ------ + polar + The system polarizability + """ + inputs = tf.reshape(input_d, [-1, self.dim_descrpt * natoms[0]]) + outs = self.polar_fitting.build(input_d, rot_mat, natoms, reuse, suffix) + # nframes x natoms x 9 + outs = tf.reshape(outs, [tf.shape(inputs)[0], -1, 9]) + outs = tf.reduce_sum(outs, axis = 1) + tf.summary.histogram('fitting_net_output', outs) + return tf.reshape(outs, [-1]) + diff --git a/deepmd/fit/wfc.py b/deepmd/fit/wfc.py new file mode 100644 index 0000000000..786677b0dc --- /dev/null +++ b/deepmd/fit/wfc.py @@ -0,0 +1,98 @@ +import warnings +import numpy as np +from typing import Tuple, List + +from deepmd.env import tf +from deepmd.common import ClassArg, add_data_requirement, get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter +from deepmd.argcheck import list_to_doc +from deepmd.utils.network import one_layer +from deepmd.descriptor import DescrptLocFrame + +from deepmd.RunOptions import global_cvt_2_tf_float +from deepmd.RunOptions import global_tf_float_precision + +class WFCFitting () : + """ + Fitting Wannier function centers (WFCs) with local frame descriptor. Not supported anymore. + """ + def __init__ (self, jdata, descrpt): + if not isinstance(descrpt, DescrptLocFrame) : + raise RuntimeError('WFC only supports DescrptLocFrame') + self.ntypes = descrpt.get_ntypes() + self.dim_descrpt = descrpt.get_dim_out() + args = ClassArg()\ + .add('neuron', list, default = [120,120,120], alias = 'n_neuron')\ + .add('resnet_dt', bool, default = True)\ + .add('wfc_numb', int, must = True)\ + .add('sel_type', [list,int], default = [ii for ii in range(self.ntypes)], alias = 'wfc_type')\ + .add('seed', int)\ + .add("activation_function", str, default = "tanh")\ + .add('precision', str, default = "default") + class_data = args.parse(jdata) + self.n_neuron = class_data['neuron'] + self.resnet_dt = class_data['resnet_dt'] + self.wfc_numb = class_data['wfc_numb'] + self.sel_type = class_data['sel_type'] + self.seed = class_data['seed'] + self.fitting_activation_fn = get_activation_func(class_data["activation_function"]) + self.fitting_precision = get_precision(class_data['precision']) + self.useBN = False + + + def get_sel_type(self): + return self.sel_type + + def get_wfc_numb(self): + return self.wfc_numb + + def get_out_size(self): + return self.wfc_numb * 3 + + def build (self, + input_d, + rot_mat, + natoms, + reuse = None, + suffix = '') : + start_index = 0 + inputs = tf.cast(tf.reshape(input_d, [-1, self.dim_descrpt * natoms[0]]), self.fitting_precision) + rot_mat = tf.reshape(rot_mat, [-1, 9 * natoms[0]]) + + count = 0 + for type_i in range(self.ntypes): + # cut-out inputs + inputs_i = tf.slice (inputs, + [ 0, start_index* self.dim_descrpt], + [-1, natoms[2+type_i]* self.dim_descrpt] ) + inputs_i = tf.reshape(inputs_i, [-1, self.dim_descrpt]) + rot_mat_i = tf.slice (rot_mat, + [ 0, start_index* 9], + [-1, natoms[2+type_i]* 9] ) + rot_mat_i = tf.reshape(rot_mat_i, [-1, 3, 3]) + start_index += natoms[2+type_i] + if not type_i in self.sel_type : + continue + layer = inputs_i + for ii in range(0,len(self.n_neuron)) : + if ii >= 1 and self.n_neuron[ii] == self.n_neuron[ii-1] : + layer+= one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, use_timestep = self.resnet_dt, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision) + else : + layer = one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision) + # (nframes x natoms) x (nwfc x 3) + final_layer = one_layer(layer, self.wfc_numb * 3, activation_fn = None, name='final_layer_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, precision = self.fitting_precision) + # (nframes x natoms) x nwfc(wc) x 3(coord_local) + final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0] * natoms[2+type_i], self.wfc_numb, 3]) + # (nframes x natoms) x nwfc(wc) x 3(coord) + final_layer = tf.matmul(final_layer, rot_mat_i) + # nframes x natoms x nwfc(wc) x 3(coord_local) + final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0], natoms[2+type_i], self.wfc_numb, 3]) + + # concat the results + if count == 0: + outs = final_layer + else: + outs = tf.concat([outs, final_layer], axis = 1) + count += 1 + + tf.summary.histogram('fitting_net_output', outs) + return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) diff --git a/deepmd/infer/__init__.py b/deepmd/infer/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/source/api/data_modifier.py b/deepmd/infer/data_modifier.py similarity index 99% rename from source/api/data_modifier.py rename to deepmd/infer/data_modifier.py index 3718a32447..3c02454379 100644 --- a/source/api/data_modifier.py +++ b/deepmd/infer/data_modifier.py @@ -2,10 +2,10 @@ import numpy as np from typing import Tuple, List -from deepmd.deep_dipole import DeepDipole +from deepmd.infer.deep_dipole import DeepDipole +from deepmd.infer.ewald_recp import EwaldRecp from deepmd.env import tf from deepmd.common import select_idx_map, make_default_mesh -from deepmd.ewald_recp import EwaldRecp from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.RunOptions import global_ener_float_precision diff --git a/source/api/deep_dipole.py b/deepmd/infer/deep_dipole.py similarity index 94% rename from source/api/deep_dipole.py rename to deepmd/infer/deep_dipole.py index 9e582383b7..078306eadc 100644 --- a/source/api/deep_dipole.py +++ b/deepmd/infer/deep_dipole.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 from typing import Tuple, List -from deepmd.deep_eval import DeepTensor +from deepmd.infer.deep_eval import DeepTensor class DeepDipole (DeepTensor) : def __init__(self, diff --git a/source/api/deep_eval.py b/deepmd/infer/deep_eval.py similarity index 100% rename from source/api/deep_eval.py rename to deepmd/infer/deep_eval.py diff --git a/source/api/deep_polar.py b/deepmd/infer/deep_polar.py similarity index 97% rename from source/api/deep_polar.py rename to deepmd/infer/deep_polar.py index f84689974f..e9cb54fa77 100644 --- a/source/api/deep_polar.py +++ b/deepmd/infer/deep_polar.py @@ -2,7 +2,7 @@ import numpy as np from typing import Tuple, List -from deepmd.deep_eval import DeepTensor +from deepmd.infer.deep_eval import DeepTensor class DeepPolar (DeepTensor) : def __init__(self, diff --git a/source/api/deep_pot.py b/deepmd/infer/deep_pot.py similarity index 99% rename from source/api/deep_pot.py rename to deepmd/infer/deep_pot.py index ed8999a442..b051a66a5f 100644 --- a/source/api/deep_pot.py +++ b/deepmd/infer/deep_pot.py @@ -6,8 +6,8 @@ from deepmd.env import tf from deepmd.env import default_tf_session_config from deepmd.common import make_default_mesh -from deepmd.deep_eval import DeepEval -from deepmd.data_modifier import DipoleChargeModifier +from deepmd.infer.data_modifier import DipoleChargeModifier +from deepmd.infer.deep_eval import DeepEval class DeepPot (DeepEval) : def __init__(self, diff --git a/source/api/deep_wfc.py b/deepmd/infer/deep_wfc.py similarity index 84% rename from source/api/deep_wfc.py rename to deepmd/infer/deep_wfc.py index 183757ca71..98f443a027 100644 --- a/source/api/deep_wfc.py +++ b/deepmd/infer/deep_wfc.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -from deepmd.deep_eval import DeepTensor +from deepmd.infer.deep_eval import DeepTensor class DeepWFC (DeepTensor) : def __init__(self, diff --git a/source/api/ewald_recp.py b/deepmd/infer/ewald_recp.py similarity index 100% rename from source/api/ewald_recp.py rename to deepmd/infer/ewald_recp.py diff --git a/deepmd/loss/__init__.py b/deepmd/loss/__init__.py new file mode 100644 index 0000000000..94655dd734 --- /dev/null +++ b/deepmd/loss/__init__.py @@ -0,0 +1,4 @@ +from .ener import EnerStdLoss +from .ener import EnerDipoleLoss +from .tensor import TensorLoss + diff --git a/source/api/loss.py b/deepmd/loss/ener.py similarity index 84% rename from source/api/loss.py rename to deepmd/loss/ener.py index edabd338b8..2f628502d7 100644 --- a/source/api/loss.py +++ b/deepmd/loss/ener.py @@ -5,8 +5,6 @@ from deepmd.RunOptions import global_cvt_2_tf_float from deepmd.RunOptions import global_cvt_2_ener_float - - class EnerStdLoss () : """ Standard loss function for DP models @@ -323,88 +321,4 @@ def print_on_training(self, return print_str -class TensorLoss () : - """ - Loss function for tensorial properties. - """ - def __init__ (self, jdata, **kwarg) : - try: - model = kwarg['model'] - type_sel = model.get_sel_type() - except : - type_sel = None - self.tensor_name = kwarg['tensor_name'] - self.tensor_size = kwarg['tensor_size'] - self.label_name = kwarg['label_name'] - self.atomic = kwarg.get('atomic', True) - if jdata is not None: - self.scale = jdata.get('scale', 1.0) - else: - self.scale = 1.0 - # data required - add_data_requirement(self.label_name, - self.tensor_size, - atomic=self.atomic, - must=True, - high_prec=False, - type_sel = type_sel) - - def build (self, - learning_rate, - natoms, - model_dict, - label_dict, - suffix): - polar_hat = label_dict[self.label_name] - polar = model_dict[self.tensor_name] - l2_loss = tf.reduce_mean( tf.square(self.scale*(polar - polar_hat)), name='l2_'+suffix) - more_loss = {'nonorm': l2_loss} - if not self.atomic : - atom_norm = 1./ global_cvt_2_tf_float(natoms[0]) - l2_loss = l2_loss * atom_norm - self.l2_l = l2_loss - self.l2_more = more_loss['nonorm'] - - self.l2_loss_summary = tf.summary.scalar('l2_loss', tf.sqrt(l2_loss)) - return l2_loss, more_loss - - @staticmethod - def print_header(): - prop_fmt = ' %9s %9s' - print_str = '' - print_str += prop_fmt % ('l2_tst', 'l2_trn') - return print_str - - def print_on_training(self, - tb_writer, - cur_batch, - sess, - natoms, - feed_dict_test, - feed_dict_batch) : - - run_data = [self.l2_l] - - # first train data - error_train = sess.run(run_data, feed_dict=feed_dict_batch) - - # than test data, if tensorboard log writter is present, commpute summary - # and write tensorboard logs - if tb_writer: - summary_merged_op = tf.summary.merge([self.l2_loss_summary]) - run_data.insert(0, summary_merged_op) - - test_out = sess.run(run_data, feed_dict=feed_dict_test) - - if tb_writer: - summary = test_out.pop(0) - tb_writer.add_summary(summary, cur_batch) - - error_test = test_out[0] - - print_str = "" - prop_fmt = " %9.2e %9.2e" - print_str += prop_fmt % (np.sqrt(error_test), np.sqrt(error_train)) - - return print_str diff --git a/deepmd/loss/tensor.py b/deepmd/loss/tensor.py new file mode 100644 index 0000000000..0b360a0d83 --- /dev/null +++ b/deepmd/loss/tensor.py @@ -0,0 +1,91 @@ +import numpy as np +from deepmd.env import tf +from deepmd.common import ClassArg, add_data_requirement + +from deepmd.RunOptions import global_cvt_2_tf_float +from deepmd.RunOptions import global_cvt_2_ener_float + +class TensorLoss () : + """ + Loss function for tensorial properties. + """ + def __init__ (self, jdata, **kwarg) : + try: + model = kwarg['model'] + type_sel = model.get_sel_type() + except : + type_sel = None + self.tensor_name = kwarg['tensor_name'] + self.tensor_size = kwarg['tensor_size'] + self.label_name = kwarg['label_name'] + self.atomic = kwarg.get('atomic', True) + if jdata is not None: + self.scale = jdata.get('scale', 1.0) + else: + self.scale = 1.0 + # data required + add_data_requirement(self.label_name, + self.tensor_size, + atomic=self.atomic, + must=True, + high_prec=False, + type_sel = type_sel) + + def build (self, + learning_rate, + natoms, + model_dict, + label_dict, + suffix): + polar_hat = label_dict[self.label_name] + polar = model_dict[self.tensor_name] + l2_loss = tf.reduce_mean( tf.square(self.scale*(polar - polar_hat)), name='l2_'+suffix) + more_loss = {'nonorm': l2_loss} + if not self.atomic : + atom_norm = 1./ global_cvt_2_tf_float(natoms[0]) + l2_loss = l2_loss * atom_norm + self.l2_l = l2_loss + self.l2_more = more_loss['nonorm'] + + self.l2_loss_summary = tf.summary.scalar('l2_loss', tf.sqrt(l2_loss)) + return l2_loss, more_loss + + @staticmethod + def print_header(): + prop_fmt = ' %9s %9s' + print_str = '' + print_str += prop_fmt % ('l2_tst', 'l2_trn') + return print_str + + def print_on_training(self, + tb_writer, + cur_batch, + sess, + natoms, + feed_dict_test, + feed_dict_batch) : + + run_data = [self.l2_l] + + # first train data + error_train = sess.run(run_data, feed_dict=feed_dict_batch) + + # than test data, if tensorboard log writter is present, commpute summary + # and write tensorboard logs + if tb_writer: + summary_merged_op = tf.summary.merge([self.l2_loss_summary]) + run_data.insert(0, summary_merged_op) + + test_out = sess.run(run_data, feed_dict=feed_dict_test) + + if tb_writer: + summary = test_out.pop(0) + tb_writer.add_summary(summary, cur_batch) + + error_test = test_out[0] + + print_str = "" + prop_fmt = " %9.2e %9.2e" + print_str += prop_fmt % (np.sqrt(error_test), np.sqrt(error_train)) + + return print_str diff --git a/deepmd/utils/__init__.py b/deepmd/utils/__init__.py new file mode 100644 index 0000000000..610df6529d --- /dev/null +++ b/deepmd/utils/__init__.py @@ -0,0 +1,8 @@ +# +from .data import DeepmdData +from .data_system import DeepmdDataSystem +# out-of-dated +from .data import DataSets +from .data_system import DataSystem +from .tab_inter import TabInter +from .learning_rate import LearningRateExp diff --git a/source/api/data.py b/deepmd/utils/data.py similarity index 100% rename from source/api/data.py rename to deepmd/utils/data.py diff --git a/source/api/data_system.py b/deepmd/utils/data_system.py similarity index 99% rename from source/api/data_system.py rename to deepmd/utils/data_system.py index 8c14d0d213..af4daf3db9 100644 --- a/source/api/data_system.py +++ b/deepmd/utils/data_system.py @@ -6,8 +6,8 @@ import numpy as np from typing import Tuple, List -from deepmd.data import DataSets -from deepmd.data import DeepmdData +from deepmd.utils.data import DataSets +from deepmd.utils.data import DeepmdData class DeepmdDataSystem() : diff --git a/source/api/learning_rate.py b/deepmd/utils/learning_rate.py similarity index 100% rename from source/api/learning_rate.py rename to deepmd/utils/learning_rate.py diff --git a/source/api/network.py b/deepmd/utils/network.py similarity index 100% rename from source/api/network.py rename to deepmd/utils/network.py diff --git a/source/api/tab_inter.py b/deepmd/utils/tab_inter.py similarity index 100% rename from source/api/tab_inter.py rename to deepmd/utils/tab_inter.py diff --git a/setup.py b/setup.py index 885022d196..b7b104d33c 100644 --- a/setup.py +++ b/setup.py @@ -63,7 +63,13 @@ long_description=readme, long_description_content_type="text/markdown", url="https://github.com/deepmodeling/deepmd-kit", - packages=['deepmd'], + packages=['deepmd', + 'deepmd/descriptor', + 'deepmd/fit', + 'deepmd/infer', + 'deepmd/loss', + 'deepmd/utils', + ], python_requires=">=3.6", classifiers=[ "Programming Language :: Python :: 3.6", diff --git a/source/api/CMakeLists.txt b/source/api/CMakeLists.txt deleted file mode 100644 index 8cd7f3cb5b..0000000000 --- a/source/api/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# train - -file(GLOB LIB_PY descrpt_*.py deep_*.py network.py fitting.py learning_rate.py loss.py tab_inter.py ewald_recp.py data_modifier.py data.py data_system.py) - -install( - FILES ${LIB_PY} - DESTINATION deepmd -) diff --git a/source/api/fitting.py b/source/api/fitting.py deleted file mode 100644 index 4d42d1849d..0000000000 --- a/source/api/fitting.py +++ /dev/null @@ -1,1016 +0,0 @@ -import warnings -import numpy as np -from typing import Tuple, List - -from deepmd.env import tf -from deepmd.common import ClassArg, add_data_requirement, get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter -from deepmd.argcheck import list_to_doc -from deepmd.network import one_layer -from deepmd.descrpt_loc_frame import DescrptLocFrame -from deepmd.descrpt_se_a import DescrptSeA - -from deepmd.RunOptions import global_cvt_2_tf_float -from deepmd.RunOptions import global_tf_float_precision - -class EnerFitting (): - @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) - def __init__ (self, - descrpt : tf.Tensor, - neuron : List[int] = [120,120,120], - resnet_dt : bool = True, - numb_fparam : int = 0, - numb_aparam : int = 0, - rcond : float = 1e-3, - tot_ener_zero : bool = False, - trainable : List[bool] = None, - seed : int = 1, - atom_ener : List[float] = [], - activation_function : str = 'tanh', - precision : str = 'default' - ) -> None: - """ - Constructor - - Parameters - ---------- - descrpt - The descrptor - neuron - Number of neurons in each hidden layer of the fitting net - resnet_dt - Time-step `dt` in the resnet construction: - y = x + dt * \phi (Wx + b) - numb_fparam - Number of frame parameter - numb_aparam - Number of atomic parameter - rcond - The condition number for the regression of atomic energy. - tot_ener_zero - Force the total energy to zero. Useful for the charge fitting. - trainable - If the weights of fitting net are trainable. - Suppose that we have N_l hidden layers in the fitting net, - this list is of length N_l + 1, specifying if the hidden layers and the output layer are trainable. - seed - Random seed for initializing the network parameters. - atom_ener - Specifying atomic energy contribution in vacuum. The `set_davg_zero` key in the descrptor should be set. - activation_function - The activation function in the embedding net. Supported options are {0} - precision - The precision of the embedding net parameters. Supported options are {1} - """ - # model param - self.ntypes = descrpt.get_ntypes() - self.dim_descrpt = descrpt.get_dim_out() - # args = ClassArg()\ - # .add('numb_fparam', int, default = 0)\ - # .add('numb_aparam', int, default = 0)\ - # .add('neuron', list, default = [120,120,120], alias = 'n_neuron')\ - # .add('resnet_dt', bool, default = True)\ - # .add('rcond', float, default = 1e-3) \ - # .add('tot_ener_zero', bool, default = False) \ - # .add('seed', int) \ - # .add('atom_ener', list, default = [])\ - # .add("activation_function", str, default = "tanh")\ - # .add("precision", str, default = "default")\ - # .add("trainable", [list, bool], default = True) - self.numb_fparam = numb_fparam - self.numb_aparam = numb_aparam - self.n_neuron = neuron - self.resnet_dt = resnet_dt - self.rcond = rcond - self.seed = seed - self.tot_ener_zero = tot_ener_zero - self.fitting_activation_fn = get_activation_func(activation_function) - self.fitting_precision = get_precision(precision) - self.trainable = trainable - if self.trainable is None: - self.trainable = [True for ii in range(len(self.n_neuron) + 1)] - if type(self.trainable) is bool: - self.trainable = [self.trainable] * (len(self.n_neuron)+1) - assert(len(self.trainable) == len(self.n_neuron) + 1), 'length of trainable should be that of n_neuron + 1' - self.atom_ener = [] - for at, ae in enumerate(atom_ener): - if ae is not None: - self.atom_ener.append(tf.constant(ae, global_tf_float_precision, name = "atom_%d_ener" % at)) - else: - self.atom_ener.append(None) - self.useBN = False - self.bias_atom_e = None - # data requirement - if self.numb_fparam > 0 : - add_data_requirement('fparam', self.numb_fparam, atomic=False, must=True, high_prec=False) - self.fparam_avg = None - self.fparam_std = None - self.fparam_inv_std = None - if self.numb_aparam > 0: - add_data_requirement('aparam', self.numb_aparam, atomic=True, must=True, high_prec=False) - self.aparam_avg = None - self.aparam_std = None - self.aparam_inv_std = None - - def get_numb_fparam(self) -> int: - """ - Get the number of frame parameters - """ - return self.numb_fparam - - def get_numb_aparam(self) -> int: - """ - Get the number of atomic parameters - """ - return self.numb_fparam - - def compute_output_stats(self, - all_stat: dict - ) -> None: - """ - Compute the ouput statistics - - Parameters - ---------- - all_stat - must have the following components: - all_stat['energy'] of shape n_sys x n_batch x n_frame - can be prepared by model.make_stat_input - """ - self.bias_atom_e = self._compute_output_stats(all_stat, rcond = self.rcond) - - @classmethod - def _compute_output_stats(self, all_stat, rcond = 1e-3): - data = all_stat['energy'] - # data[sys_idx][batch_idx][frame_idx] - sys_ener = np.array([]) - for ss in range(len(data)): - sys_data = [] - for ii in range(len(data[ss])): - for jj in range(len(data[ss][ii])): - sys_data.append(data[ss][ii][jj]) - sys_data = np.concatenate(sys_data) - sys_ener = np.append(sys_ener, np.average(sys_data)) - data = all_stat['natoms_vec'] - sys_tynatom = np.array([]) - nsys = len(data) - for ss in range(len(data)): - sys_tynatom = np.append(sys_tynatom, data[ss][0].astype(np.float64)) - sys_tynatom = np.reshape(sys_tynatom, [nsys,-1]) - sys_tynatom = sys_tynatom[:,2:] - energy_shift,resd,rank,s_value \ - = np.linalg.lstsq(sys_tynatom, sys_ener, rcond = rcond) - return energy_shift - - def compute_input_stats(self, - all_stat : dict, - protection : float = 1e-2) -> None: - """ - Compute the input statistics - - Parameters: - all_stat - if numb_fparam > 0 must have all_stat['fparam'] - if numb_aparam > 0 must have all_stat['aparam'] - can be prepared by model.make_stat_input - protection - Divided-by-zero protection - """ - # stat fparam - if self.numb_fparam > 0: - cat_data = np.concatenate(all_stat['fparam'], axis = 0) - cat_data = np.reshape(cat_data, [-1, self.numb_fparam]) - self.fparam_avg = np.average(cat_data, axis = 0) - self.fparam_std = np.std(cat_data, axis = 0) - for ii in range(self.fparam_std.size): - if self.fparam_std[ii] < protection: - self.fparam_std[ii] = protection - self.fparam_inv_std = 1./self.fparam_std - # stat aparam - if self.numb_aparam > 0: - sys_sumv = [] - sys_sumv2 = [] - sys_sumn = [] - for ss_ in all_stat['aparam'] : - ss = np.reshape(ss_, [-1, self.numb_aparam]) - sys_sumv.append(np.sum(ss, axis = 0)) - sys_sumv2.append(np.sum(np.multiply(ss, ss), axis = 0)) - sys_sumn.append(ss.shape[0]) - sumv = np.sum(sys_sumv, axis = 0) - sumv2 = np.sum(sys_sumv2, axis = 0) - sumn = np.sum(sys_sumn) - self.aparam_avg = (sumv)/sumn - self.aparam_std = self._compute_std(sumv2, sumv, sumn) - for ii in range(self.aparam_std.size): - if self.aparam_std[ii] < protection: - self.aparam_std[ii] = protection - self.aparam_inv_std = 1./self.aparam_std - - - def _compute_std (self, sumv2, sumv, sumn) : - return np.sqrt(sumv2/sumn - np.multiply(sumv/sumn, sumv/sumn)) - - - def build (self, - inputs : tf.Tensor, - natoms : tf.Tensor, - input_dict : dict = {}, - reuse : bool = None, - suffix : str = '' - ) -> tf.Tensor: - """ - Build the computational graph for fitting net - - Parameters - ---------- - inputs - The input descriptor - input_dict - Additional dict for inputs. - if numb_fparam > 0, should have input_dict['fparam'] - if numb_aparam > 0, should have input_dict['aparam'] - natoms - The number of atoms. This tensor has the length of Ntypes + 2 - natoms[0]: number of local atoms - natoms[1]: total number of atoms held by this processor - natoms[i]: 2 <= i < Ntypes+2, number of type i atoms - reuse - The weights in the networks should be reused when get the variable. - suffix - Name suffix to identify this descriptor - - Return - ------ - ener - The system energy - """ - bias_atom_e = self.bias_atom_e - if self.numb_fparam > 0 and ( self.fparam_avg is None or self.fparam_inv_std is None ): - raise RuntimeError('No data stat result. one should do data statisitic, before build') - if self.numb_aparam > 0 and ( self.aparam_avg is None or self.aparam_inv_std is None ): - raise RuntimeError('No data stat result. one should do data statisitic, before build') - - with tf.variable_scope('fitting_attr' + suffix, reuse = reuse) : - t_dfparam = tf.constant(self.numb_fparam, - name = 'dfparam', - dtype = tf.int32) - t_daparam = tf.constant(self.numb_aparam, - name = 'daparam', - dtype = tf.int32) - if self.numb_fparam > 0: - t_fparam_avg = tf.get_variable('t_fparam_avg', - self.numb_fparam, - dtype = global_tf_float_precision, - trainable = False, - initializer = tf.constant_initializer(self.fparam_avg)) - t_fparam_istd = tf.get_variable('t_fparam_istd', - self.numb_fparam, - dtype = global_tf_float_precision, - trainable = False, - initializer = tf.constant_initializer(self.fparam_inv_std)) - if self.numb_aparam > 0: - t_aparam_avg = tf.get_variable('t_aparam_avg', - self.numb_aparam, - dtype = global_tf_float_precision, - trainable = False, - initializer = tf.constant_initializer(self.aparam_avg)) - t_aparam_istd = tf.get_variable('t_aparam_istd', - self.numb_aparam, - dtype = global_tf_float_precision, - trainable = False, - initializer = tf.constant_initializer(self.aparam_inv_std)) - - start_index = 0 - inputs = tf.cast(tf.reshape(inputs, [-1, self.dim_descrpt * natoms[0]]), self.fitting_precision) - - if bias_atom_e is not None : - assert(len(bias_atom_e) == self.ntypes) - - if self.numb_fparam > 0 : - fparam = input_dict['fparam'] - fparam = tf.reshape(fparam, [-1, self.numb_fparam]) - fparam = (fparam - t_fparam_avg) * t_fparam_istd - if self.numb_aparam > 0 : - aparam = input_dict['aparam'] - aparam = tf.reshape(aparam, [-1, self.numb_aparam]) - aparam = (aparam - t_aparam_avg) * t_aparam_istd - aparam = tf.reshape(aparam, [-1, self.numb_aparam * natoms[0]]) - - for type_i in range(self.ntypes): - # cut-out inputs - inputs_i = tf.slice (inputs, - [ 0, start_index* self.dim_descrpt], - [-1, natoms[2+type_i]* self.dim_descrpt] ) - inputs_i = tf.reshape(inputs_i, [-1, self.dim_descrpt]) - layer = inputs_i - if self.numb_fparam > 0 : - ext_fparam = tf.tile(fparam, [1, natoms[2+type_i]]) - ext_fparam = tf.reshape(ext_fparam, [-1, self.numb_fparam]) - ext_fparam = tf.cast(ext_fparam,self.fitting_precision) - layer = tf.concat([layer, ext_fparam], axis = 1) - if self.numb_aparam > 0 : - ext_aparam = tf.slice(aparam, - [ 0, start_index * self.numb_aparam], - [-1, natoms[2+type_i] * self.numb_aparam]) - ext_aparam = tf.reshape(ext_aparam, [-1, self.numb_aparam]) - ext_aparam = tf.cast(ext_aparam,self.fitting_precision) - layer = tf.concat([layer, ext_aparam], axis = 1) - start_index += natoms[2+type_i] - - if bias_atom_e is None : - type_bias_ae = 0.0 - else : - type_bias_ae = bias_atom_e[type_i] - - for ii in range(0,len(self.n_neuron)) : - if ii >= 1 and self.n_neuron[ii] == self.n_neuron[ii-1] : - layer+= one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, use_timestep = self.resnet_dt, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision, trainable = self.trainable[ii]) - else : - layer = one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision, trainable = self.trainable[ii]) - final_layer = one_layer(layer, 1, activation_fn = None, bavg = type_bias_ae, name='final_layer_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, precision = self.fitting_precision, trainable = self.trainable[-1]) - - if type_i < len(self.atom_ener) and self.atom_ener[type_i] is not None: - inputs_zero = tf.zeros_like(inputs_i, dtype=global_tf_float_precision) - layer = inputs_zero - if self.numb_fparam > 0 : - layer = tf.concat([layer, ext_fparam], axis = 1) - if self.numb_aparam > 0 : - layer = tf.concat([layer, ext_aparam], axis = 1) - for ii in range(0,len(self.n_neuron)) : - if ii >= 1 and self.n_neuron[ii] == self.n_neuron[ii-1] : - layer+= one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=True, seed = self.seed, use_timestep = self.resnet_dt, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision, trainable = self.trainable[ii]) - else : - layer = one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=True, seed = self.seed, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision, trainable = self.trainable[ii]) - zero_layer = one_layer(layer, 1, activation_fn = None, bavg = type_bias_ae, name='final_layer_type_'+str(type_i)+suffix, reuse=True, seed = self.seed, precision = self.fitting_precision, trainable = self.trainable[-1]) - final_layer += self.atom_ener[type_i] - zero_layer - - final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0], natoms[2+type_i]]) - - # concat the results - if type_i == 0: - outs = final_layer - else: - outs = tf.concat([outs, final_layer], axis = 1) - - if self.tot_ener_zero: - force_tot_ener = 0.0 - outs = tf.reshape(outs, [-1, natoms[0]]) - outs_mean = tf.reshape(tf.reduce_mean(outs, axis = 1), [-1, 1]) - outs_mean = outs_mean - tf.ones_like(outs_mean, dtype = global_tf_float_precision) * (force_tot_ener/global_cvt_2_tf_float(natoms[0])) - outs = outs - outs_mean - outs = tf.reshape(outs, [-1]) - - tf.summary.histogram('fitting_net_output', outs) - return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) - - -class WFCFitting () : - """ - Fitting Wannier function centers (WFCs) with local frame descriptor. Not supported anymore. - """ - def __init__ (self, jdata, descrpt): - if not isinstance(descrpt, DescrptLocFrame) : - raise RuntimeError('WFC only supports DescrptLocFrame') - self.ntypes = descrpt.get_ntypes() - self.dim_descrpt = descrpt.get_dim_out() - args = ClassArg()\ - .add('neuron', list, default = [120,120,120], alias = 'n_neuron')\ - .add('resnet_dt', bool, default = True)\ - .add('wfc_numb', int, must = True)\ - .add('sel_type', [list,int], default = [ii for ii in range(self.ntypes)], alias = 'wfc_type')\ - .add('seed', int)\ - .add("activation_function", str, default = "tanh")\ - .add('precision', str, default = "default") - class_data = args.parse(jdata) - self.n_neuron = class_data['neuron'] - self.resnet_dt = class_data['resnet_dt'] - self.wfc_numb = class_data['wfc_numb'] - self.sel_type = class_data['sel_type'] - self.seed = class_data['seed'] - self.fitting_activation_fn = get_activation_func(class_data["activation_function"]) - self.fitting_precision = get_precision(class_data['precision']) - self.useBN = False - - - def get_sel_type(self): - return self.sel_type - - def get_wfc_numb(self): - return self.wfc_numb - - def get_out_size(self): - return self.wfc_numb * 3 - - def build (self, - input_d, - rot_mat, - natoms, - reuse = None, - suffix = '') : - start_index = 0 - inputs = tf.cast(tf.reshape(input_d, [-1, self.dim_descrpt * natoms[0]]), self.fitting_precision) - rot_mat = tf.reshape(rot_mat, [-1, 9 * natoms[0]]) - - count = 0 - for type_i in range(self.ntypes): - # cut-out inputs - inputs_i = tf.slice (inputs, - [ 0, start_index* self.dim_descrpt], - [-1, natoms[2+type_i]* self.dim_descrpt] ) - inputs_i = tf.reshape(inputs_i, [-1, self.dim_descrpt]) - rot_mat_i = tf.slice (rot_mat, - [ 0, start_index* 9], - [-1, natoms[2+type_i]* 9] ) - rot_mat_i = tf.reshape(rot_mat_i, [-1, 3, 3]) - start_index += natoms[2+type_i] - if not type_i in self.sel_type : - continue - layer = inputs_i - for ii in range(0,len(self.n_neuron)) : - if ii >= 1 and self.n_neuron[ii] == self.n_neuron[ii-1] : - layer+= one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, use_timestep = self.resnet_dt, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision) - else : - layer = one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision) - # (nframes x natoms) x (nwfc x 3) - final_layer = one_layer(layer, self.wfc_numb * 3, activation_fn = None, name='final_layer_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, precision = self.fitting_precision) - # (nframes x natoms) x nwfc(wc) x 3(coord_local) - final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0] * natoms[2+type_i], self.wfc_numb, 3]) - # (nframes x natoms) x nwfc(wc) x 3(coord) - final_layer = tf.matmul(final_layer, rot_mat_i) - # nframes x natoms x nwfc(wc) x 3(coord_local) - final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0], natoms[2+type_i], self.wfc_numb, 3]) - - # concat the results - if count == 0: - outs = final_layer - else: - outs = tf.concat([outs, final_layer], axis = 1) - count += 1 - - tf.summary.histogram('fitting_net_output', outs) - return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) - - - -class PolarFittingLocFrame () : - """ - Fitting polarizability with local frame descriptor. not supported anymore. - """ - def __init__ (self, jdata, descrpt) : - if not isinstance(descrpt, DescrptLocFrame) : - raise RuntimeError('PolarFittingLocFrame only supports DescrptLocFrame') - self.ntypes = descrpt.get_ntypes() - self.dim_descrpt = descrpt.get_dim_out() - args = ClassArg()\ - .add('neuron', list, default = [120,120,120], alias = 'n_neuron')\ - .add('resnet_dt', bool, default = True)\ - .add('sel_type', [list,int], default = [ii for ii in range(self.ntypes)], alias = 'pol_type')\ - .add('seed', int)\ - .add("activation_function", str, default = "tanh")\ - .add('precision', str, default = "default") - class_data = args.parse(jdata) - self.n_neuron = class_data['neuron'] - self.resnet_dt = class_data['resnet_dt'] - self.sel_type = class_data['sel_type'] - self.seed = class_data['seed'] - self.fitting_activation_fn = get_activation_func(class_data["activation_function"]) - self.fitting_precision = get_precision(class_data['precision']) - self.useBN = False - - def get_sel_type(self): - return self.sel_type - - def get_out_size(self): - return 9 - - def build (self, - input_d, - rot_mat, - natoms, - reuse = None, - suffix = '') : - start_index = 0 - inputs = tf.cast(tf.reshape(input_d, [-1, self.dim_descrpt * natoms[0]]), self.fitting_precision) - rot_mat = tf.reshape(rot_mat, [-1, 9 * natoms[0]]) - - count = 0 - for type_i in range(self.ntypes): - # cut-out inputs - inputs_i = tf.slice (inputs, - [ 0, start_index* self.dim_descrpt], - [-1, natoms[2+type_i]* self.dim_descrpt] ) - inputs_i = tf.reshape(inputs_i, [-1, self.dim_descrpt]) - rot_mat_i = tf.slice (rot_mat, - [ 0, start_index* 9], - [-1, natoms[2+type_i]* 9] ) - rot_mat_i = tf.reshape(rot_mat_i, [-1, 3, 3]) - start_index += natoms[2+type_i] - if not type_i in self.sel_type : - continue - layer = inputs_i - for ii in range(0,len(self.n_neuron)) : - if ii >= 1 and self.n_neuron[ii] == self.n_neuron[ii-1] : - layer+= one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, use_timestep = self.resnet_dt, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision) - else : - layer = one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision) - # (nframes x natoms) x 9 - final_layer = one_layer(layer, 9, activation_fn = None, name='final_layer_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, precision = self.fitting_precision) - # (nframes x natoms) x 3 x 3 - final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0] * natoms[2+type_i], 3, 3]) - # (nframes x natoms) x 3 x 3 - final_layer = final_layer + tf.transpose(final_layer, perm = [0,2,1]) - # (nframes x natoms) x 3 x 3(coord) - final_layer = tf.matmul(final_layer, rot_mat_i) - # (nframes x natoms) x 3(coord) x 3(coord) - final_layer = tf.matmul(rot_mat_i, final_layer, transpose_a = True) - # nframes x natoms x 3 x 3 - final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0], natoms[2+type_i], 3, 3]) - - # concat the results - if count == 0: - outs = final_layer - else: - outs = tf.concat([outs, final_layer], axis = 1) - count += 1 - - tf.summary.histogram('fitting_net_output', outs) - return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) - - -class PolarFittingSeA () : - """ - Fit the atomic polarizability with descriptor se_a - """ - @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) - def __init__ (self, - descrpt : tf.Tensor, - neuron : List[int] = [120,120,120], - resnet_dt : bool = True, - sel_type : List[int] = None, - fit_diag : bool = True, - scale : List[float] = None, - diag_shift : List[float] = None, - seed : int = 1, - activation_function : str = 'tanh', - precision : str = 'default' - ) -> None: - """ - Constructor - - Parameters - ---------- - descrpt : tf.Tensor - The descrptor - neuron : List[int] - Number of neurons in each hidden layer of the fitting net - resnet_dt : bool - Time-step `dt` in the resnet construction: - y = x + dt * \phi (Wx + b) - sel_type : List[int] - The atom types selected to have an atomic polarizability prediction. If is None, all atoms are selected. - fit_diag : bool - Fit the diagonal part of the rotational invariant polarizability matrix, which will be converted to normal polarizability matrix by contracting with the rotation matrix. - scale : List[float] - The output of the fitting net (polarizability matrix) for type i atom will be scaled by scale[i] - diag_shift : List[float] - The diagonal part of the polarizability matrix of type i will be shifted by diag_shift[i]. The shift operation is carried out after scale. - seed : int - Random seed for initializing the network parameters. - activation_function : str - The activation function in the embedding net. Supported options are {0} - precision : str - The precision of the embedding net parameters. Supported options are {1} - """ - if not isinstance(descrpt, DescrptSeA) : - raise RuntimeError('PolarFittingSeA only supports DescrptSeA') - self.ntypes = descrpt.get_ntypes() - self.dim_descrpt = descrpt.get_dim_out() - # args = ClassArg()\ - # .add('neuron', list, default = [120,120,120], alias = 'n_neuron')\ - # .add('resnet_dt', bool, default = True)\ - # .add('fit_diag', bool, default = True)\ - # .add('diag_shift', [list,float], default = [0.0 for ii in range(self.ntypes)])\ - # .add('scale', [list,float], default = [1.0 for ii in range(self.ntypes)])\ - # .add('sel_type', [list,int], default = [ii for ii in range(self.ntypes)], alias = 'pol_type')\ - # .add('seed', int)\ - # .add("activation_function", str , default = "tanh")\ - # .add('precision', str, default = "default") - # class_data = args.parse(jdata) - self.n_neuron = neuron - self.resnet_dt = resnet_dt - self.sel_type = sel_type - self.fit_diag = fit_diag - self.seed = seed - self.diag_shift = diag_shift - self.scale = scale - self.fitting_activation_fn = get_activation_func(activation_function) - self.fitting_precision = get_precision(precision) - if self.sel_type is None: - self.sel_type = [ii for ii in range(self.ntypes)] - if self.scale is None: - self.scale = [1.0 for ii in range(self.ntypes)] - if self.diag_shift is None: - self.diag_shift = [0.0 for ii in range(self.ntypes)] - if type(self.sel_type) is not list: - self.sel_type = [self.sel_type] - if type(self.diag_shift) is not list: - self.diag_shift = [self.diag_shift] - if type(self.scale) is not list: - self.scale = [self.scale] - self.dim_rot_mat_1 = descrpt.get_dim_rot_mat_1() - self.dim_rot_mat = self.dim_rot_mat_1 * 3 - self.useBN = False - - def get_sel_type(self) -> List[int]: - """ - Get selected atom types - """ - return self.sel_type - - def get_out_size(self) -> int: - """ - Get the output size. Should be 9 - """ - return 9 - - def compute_input_stats(self, - all_stat, - protection = 1e-2): - """ - Compute the input statistics - - Parameters: - all_stat - Dictionary of inputs. - can be prepared by model.make_stat_input - protection - Divided-by-zero protection - """ - if not ('polarizability' in all_stat.keys()): - self.avgeig = np.zeros([9]) - warnings.warn('no polarizability data, cannot do data stat. use zeros as guess') - return - data = all_stat['polarizability'] - all_tmp = [] - for ss in range(len(data)): - tmp = np.concatenate(data[ss], axis = 0) - tmp = np.reshape(tmp, [-1, 3, 3]) - tmp,_ = np.linalg.eig(tmp) - tmp = np.absolute(tmp) - tmp = np.sort(tmp, axis = 1) - all_tmp.append(tmp) - all_tmp = np.concatenate(all_tmp, axis = 1) - self.avgeig = np.average(all_tmp, axis = 0) - - def build (self, - input_d : tf.Tensor, - rot_mat : tf.Tensor, - natoms : tf.Tensor, - reuse : bool = None, - suffix : str = '') : - """ - Build the computational graph for fitting net - - Parameters - ---------- - input_d - The input descriptor - rot_mat - The rotation matrix from the descriptor. - natoms - The number of atoms. This tensor has the length of Ntypes + 2 - natoms[0]: number of local atoms - natoms[1]: total number of atoms held by this processor - natoms[i]: 2 <= i < Ntypes+2, number of type i atoms - reuse - The weights in the networks should be reused when get the variable. - suffix - Name suffix to identify this descriptor - - Return - ------ - atomic_polar - The atomic polarizability - """ - start_index = 0 - inputs = tf.cast(tf.reshape(input_d, [-1, self.dim_descrpt * natoms[0]]), self.fitting_precision) - rot_mat = tf.reshape(rot_mat, [-1, self.dim_rot_mat * natoms[0]]) - - count = 0 - for type_i in range(self.ntypes): - # cut-out inputs - inputs_i = tf.slice (inputs, - [ 0, start_index* self.dim_descrpt], - [-1, natoms[2+type_i]* self.dim_descrpt] ) - inputs_i = tf.reshape(inputs_i, [-1, self.dim_descrpt]) - rot_mat_i = tf.slice (rot_mat, - [ 0, start_index* self.dim_rot_mat], - [-1, natoms[2+type_i]* self.dim_rot_mat] ) - rot_mat_i = tf.reshape(rot_mat_i, [-1, self.dim_rot_mat_1, 3]) - start_index += natoms[2+type_i] - if not type_i in self.sel_type : - continue - layer = inputs_i - for ii in range(0,len(self.n_neuron)) : - if ii >= 1 and self.n_neuron[ii] == self.n_neuron[ii-1] : - layer+= one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, use_timestep = self.resnet_dt, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision) - else : - layer = one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision) - if self.fit_diag : - bavg = np.zeros(self.dim_rot_mat_1) - # bavg[0] = self.avgeig[0] - # bavg[1] = self.avgeig[1] - # bavg[2] = self.avgeig[2] - # (nframes x natoms) x naxis - final_layer = one_layer(layer, self.dim_rot_mat_1, activation_fn = None, name='final_layer_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, bavg = bavg, precision = self.fitting_precision) - # (nframes x natoms) x naxis - final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0] * natoms[2+type_i], self.dim_rot_mat_1]) - # (nframes x natoms) x naxis x naxis - final_layer = tf.matrix_diag(final_layer) - else : - bavg = np.zeros(self.dim_rot_mat_1*self.dim_rot_mat_1) - # bavg[0*self.dim_rot_mat_1+0] = self.avgeig[0] - # bavg[1*self.dim_rot_mat_1+1] = self.avgeig[1] - # bavg[2*self.dim_rot_mat_1+2] = self.avgeig[2] - # (nframes x natoms) x (naxis x naxis) - final_layer = one_layer(layer, self.dim_rot_mat_1*self.dim_rot_mat_1, activation_fn = None, name='final_layer_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, bavg = bavg, precision = self.fitting_precision) - # (nframes x natoms) x naxis x naxis - final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0] * natoms[2+type_i], self.dim_rot_mat_1, self.dim_rot_mat_1]) - # (nframes x natoms) x naxis x naxis - final_layer = final_layer + tf.transpose(final_layer, perm = [0,2,1]) - # (nframes x natoms) x naxis x 3(coord) - final_layer = tf.matmul(final_layer, rot_mat_i) - # (nframes x natoms) x 3(coord) x 3(coord) - final_layer = tf.matmul(rot_mat_i, final_layer, transpose_a = True) - # nframes x natoms x 3 x 3 - final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0], natoms[2+type_i], 3, 3]) - # shift and scale - sel_type_idx = self.sel_type.index(type_i) - final_layer = final_layer * self.scale[sel_type_idx] - final_layer = final_layer + self.diag_shift[sel_type_idx] * tf.eye(3, batch_shape=[tf.shape(inputs)[0], natoms[2+type_i]], dtype = global_tf_float_precision) - - # concat the results - if count == 0: - outs = final_layer - else: - outs = tf.concat([outs, final_layer], axis = 1) - count += 1 - - tf.summary.histogram('fitting_net_output', outs) - return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) - - -class GlobalPolarFittingSeA () : - """ - Fit the system polarizability with descriptor se_a - """ - @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) - def __init__ (self, - descrpt : tf.Tensor, - neuron : List[int] = [120,120,120], - resnet_dt : bool = True, - sel_type : List[int] = None, - fit_diag : bool = True, - scale : List[float] = None, - diag_shift : List[float] = None, - seed : int = 1, - activation_function : str = 'tanh', - precision : str = 'default' - ) -> None: - """ - Constructor - - Parameters - ---------- - descrpt : tf.Tensor - The descrptor - neuron : List[int] - Number of neurons in each hidden layer of the fitting net - resnet_dt : bool - Time-step `dt` in the resnet construction: - y = x + dt * \phi (Wx + b) - sel_type : List[int] - The atom types selected to have an atomic polarizability prediction - fit_diag : bool - Fit the diagonal part of the rotational invariant polarizability matrix, which will be converted to normal polarizability matrix by contracting with the rotation matrix. - scale : List[float] - The output of the fitting net (polarizability matrix) for type i atom will be scaled by scale[i] - diag_shift : List[float] - The diagonal part of the polarizability matrix of type i will be shifted by diag_shift[i]. The shift operation is carried out after scale. - seed : int - Random seed for initializing the network parameters. - activation_function : str - The activation function in the embedding net. Supported options are {0} - precision : str - The precision of the embedding net parameters. Supported options are {1} - """ - if not isinstance(descrpt, DescrptSeA) : - raise RuntimeError('GlobalPolarFittingSeA only supports DescrptSeA') - self.ntypes = descrpt.get_ntypes() - self.dim_descrpt = descrpt.get_dim_out() - self.polar_fitting = PolarFittingSeA(descrpt, - neuron, - resnet_dt, - sel_type, - fit_diag, - scale, - diag_shift, - seed, - activation_function, - precision) - - def get_sel_type(self) -> int: - """ - Get selected atom types - """ - return self.polar_fitting.get_sel_type() - - def get_out_size(self) -> int: - """ - Get the output size. Should be 9 - """ - return self.polar_fitting.get_out_size() - - def build (self, - input_d, - rot_mat, - natoms, - reuse = None, - suffix = '') -> tf.Tensor: - """ - Build the computational graph for fitting net - - Parameters - ---------- - input_d - The input descriptor - rot_mat - The rotation matrix from the descriptor. - natoms - The number of atoms. This tensor has the length of Ntypes + 2 - natoms[0]: number of local atoms - natoms[1]: total number of atoms held by this processor - natoms[i]: 2 <= i < Ntypes+2, number of type i atoms - reuse - The weights in the networks should be reused when get the variable. - suffix - Name suffix to identify this descriptor - - Return - ------ - polar - The system polarizability - """ - inputs = tf.reshape(input_d, [-1, self.dim_descrpt * natoms[0]]) - outs = self.polar_fitting.build(input_d, rot_mat, natoms, reuse, suffix) - # nframes x natoms x 9 - outs = tf.reshape(outs, [tf.shape(inputs)[0], -1, 9]) - outs = tf.reduce_sum(outs, axis = 1) - tf.summary.histogram('fitting_net_output', outs) - return tf.reshape(outs, [-1]) - - -class DipoleFittingSeA () : - """ - Fit the atomic dipole with descriptor se_a - """ - @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) - def __init__ (self, - descrpt : tf.Tensor, - neuron : List[int] = [120,120,120], - resnet_dt : bool = True, - sel_type : List[int] = None, - seed : int = 1, - activation_function : str = 'tanh', - precision : str = 'default' - ) : - """ - Constructor - - Parameters - ---------- - descrpt : tf.Tensor - The descrptor - neuron : List[int] - Number of neurons in each hidden layer of the fitting net - resnet_dt : bool - Time-step `dt` in the resnet construction: - y = x + dt * \phi (Wx + b) - sel_type : List[int] - The atom types selected to have an atomic dipole prediction. If is None, all atoms are selected. - seed : int - Random seed for initializing the network parameters. - activation_function : str - The activation function in the embedding net. Supported options are {0} - precision : str - The precision of the embedding net parameters. Supported options are {1} - """ - if not isinstance(descrpt, DescrptSeA) : - raise RuntimeError('DipoleFittingSeA only supports DescrptSeA') - self.ntypes = descrpt.get_ntypes() - self.dim_descrpt = descrpt.get_dim_out() - # args = ClassArg()\ - # .add('neuron', list, default = [120,120,120], alias = 'n_neuron')\ - # .add('resnet_dt', bool, default = True)\ - # .add('sel_type', [list,int], default = [ii for ii in range(self.ntypes)], alias = 'dipole_type')\ - # .add('seed', int)\ - # .add("activation_function", str, default = "tanh")\ - # .add('precision', str, default = "default") - # class_data = args.parse(jdata) - self.n_neuron = neuron - self.resnet_dt = resnet_dt - self.sel_type = sel_type - if self.sel_type is None: - self.sel_type = [ii for ii in range(self.ntypes)] - self.sel_type = sel_type - self.seed = seed - self.fitting_activation_fn = get_activation_func(activation_function) - self.fitting_precision = get_precision(precision) - self.dim_rot_mat_1 = descrpt.get_dim_rot_mat_1() - self.dim_rot_mat = self.dim_rot_mat_1 * 3 - self.useBN = False - - def get_sel_type(self) -> int: - """ - Get selected type - """ - return self.sel_type - - def get_out_size(self) -> int: - """ - Get the output size. Should be 3 - """ - return 3 - - def build (self, - input_d : tf.Tensor, - rot_mat : tf.Tensor, - natoms : tf.Tensor, - reuse : bool = None, - suffix : str = '') -> tf.Tensor: - """ - Build the computational graph for fitting net - - Parameters - ---------- - input_d - The input descriptor - rot_mat - The rotation matrix from the descriptor. - natoms - The number of atoms. This tensor has the length of Ntypes + 2 - natoms[0]: number of local atoms - natoms[1]: total number of atoms held by this processor - natoms[i]: 2 <= i < Ntypes+2, number of type i atoms - reuse - The weights in the networks should be reused when get the variable. - suffix - Name suffix to identify this descriptor - - Return - ------ - dipole - The atomic dipole. - """ - start_index = 0 - inputs = tf.cast(tf.reshape(input_d, [-1, self.dim_descrpt * natoms[0]]), self.fitting_precision) - rot_mat = tf.reshape(rot_mat, [-1, self.dim_rot_mat * natoms[0]]) - - count = 0 - for type_i in range(self.ntypes): - # cut-out inputs - inputs_i = tf.slice (inputs, - [ 0, start_index* self.dim_descrpt], - [-1, natoms[2+type_i]* self.dim_descrpt] ) - inputs_i = tf.reshape(inputs_i, [-1, self.dim_descrpt]) - rot_mat_i = tf.slice (rot_mat, - [ 0, start_index* self.dim_rot_mat], - [-1, natoms[2+type_i]* self.dim_rot_mat] ) - rot_mat_i = tf.reshape(rot_mat_i, [-1, self.dim_rot_mat_1, 3]) - start_index += natoms[2+type_i] - if not type_i in self.sel_type : - continue - layer = inputs_i - for ii in range(0,len(self.n_neuron)) : - if ii >= 1 and self.n_neuron[ii] == self.n_neuron[ii-1] : - layer+= one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, use_timestep = self.resnet_dt, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision) - else : - layer = one_layer(layer, self.n_neuron[ii], name='layer_'+str(ii)+'_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, activation_fn = self.fitting_activation_fn, precision = self.fitting_precision) - # (nframes x natoms) x naxis - final_layer = one_layer(layer, self.dim_rot_mat_1, activation_fn = None, name='final_layer_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, precision = self.fitting_precision) - # (nframes x natoms) x 1 * naxis - final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0] * natoms[2+type_i], 1, self.dim_rot_mat_1]) - # (nframes x natoms) x 1 x 3(coord) - final_layer = tf.matmul(final_layer, rot_mat_i) - # nframes x natoms x 3 - final_layer = tf.reshape(final_layer, [tf.shape(inputs)[0], natoms[2+type_i], 3]) - - # concat the results - if count == 0: - outs = final_layer - else: - outs = tf.concat([outs, final_layer], axis = 1) - count += 1 - - tf.summary.histogram('fitting_net_output', outs) - return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) - # return tf.reshape(outs, [tf.shape(inputs)[0] * natoms[0] * 3 // 3]) diff --git a/source/tests/test_data_modifier.py b/source/tests/test_data_modifier.py index ed1ab78b71..c0091bc21c 100644 --- a/source/tests/test_data_modifier.py +++ b/source/tests/test_data_modifier.py @@ -6,12 +6,12 @@ from deepmd.common import j_must_have, data_requirement, j_loader from deepmd.RunOptions import RunOptions from deepmd.Trainer import NNPTrainer -from deepmd.data_system import DeepmdDataSystem +from deepmd.utils.data_system import DeepmdDataSystem from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.RunOptions import global_ener_float_precision -from deepmd.ewald_recp import EwaldRecp -from deepmd.data_modifier import DipoleChargeModifier +from deepmd.infer.ewald_recp import EwaldRecp +from deepmd.infer.data_modifier import DipoleChargeModifier from common import Data diff --git a/source/tests/test_data_modifier_shuffle.py b/source/tests/test_data_modifier_shuffle.py index 4851df648b..691589cfb4 100644 --- a/source/tests/test_data_modifier_shuffle.py +++ b/source/tests/test_data_modifier_shuffle.py @@ -7,13 +7,13 @@ from deepmd.common import j_must_have, data_requirement from deepmd.RunOptions import RunOptions from deepmd.Trainer import NNPTrainer -from deepmd.data_system import DeepmdDataSystem +from deepmd.utils.data_system import DeepmdDataSystem from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.RunOptions import global_ener_float_precision -from deepmd.ewald_recp import EwaldRecp -from deepmd.data_modifier import DipoleChargeModifier -from deepmd.deep_dipole import DeepDipole +from deepmd.infer.ewald_recp import EwaldRecp +from deepmd.infer.data_modifier import DipoleChargeModifier +from deepmd.infer.deep_dipole import DeepDipole from common import Data diff --git a/source/tests/test_deepmd_data.py b/source/tests/test_deepmd_data.py index d82155ce71..18a27630e3 100644 --- a/source/tests/test_deepmd_data.py +++ b/source/tests/test_deepmd_data.py @@ -2,7 +2,7 @@ import numpy as np import unittest -from deepmd.data import DeepmdData +from deepmd.utils.data import DeepmdData from deepmd.RunOptions import global_np_float_precision if global_np_float_precision == np.float32 : diff --git a/source/tests/test_deepmd_data_sys.py b/source/tests/test_deepmd_data_sys.py index a2e85a7765..4a706ba870 100644 --- a/source/tests/test_deepmd_data_sys.py +++ b/source/tests/test_deepmd_data_sys.py @@ -2,7 +2,7 @@ import numpy as np import unittest -from deepmd.data_system import DeepmdDataSystem +from deepmd.utils.data_system import DeepmdDataSystem from deepmd.RunOptions import global_np_float_precision if global_np_float_precision == np.float32 : diff --git a/source/tests/test_descrpt_nonsmth.py b/source/tests/test_descrpt_nonsmth.py index f4a17be554..dbed5b3757 100644 --- a/source/tests/test_descrpt_nonsmth.py +++ b/source/tests/test_descrpt_nonsmth.py @@ -17,7 +17,7 @@ from common import virial_dw_test from common import Data -from deepmd.descrpt_loc_frame import op_module +from deepmd.env import op_module from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision diff --git a/source/tests/test_descrpt_se_ar.py b/source/tests/test_descrpt_se_ar.py index e5ac11ab71..ce4edad316 100644 --- a/source/tests/test_descrpt_se_ar.py +++ b/source/tests/test_descrpt_se_ar.py @@ -19,7 +19,7 @@ from common import virial_dw_test from common import Data -from deepmd.descrpt_se_ar import DescrptSeAR +from deepmd.descriptor import DescrptSeAR from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision diff --git a/source/tests/test_descrpt_se_r.py b/source/tests/test_descrpt_se_r.py index 9f8cea7969..07e652e06d 100644 --- a/source/tests/test_descrpt_se_r.py +++ b/source/tests/test_descrpt_se_r.py @@ -19,7 +19,7 @@ from common import virial_dw_test from common import Data -from deepmd.descrpt_loc_frame import op_module +from deepmd.env import op_module from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision diff --git a/source/tests/test_descrpt_sea_ef.py b/source/tests/test_descrpt_sea_ef.py index 4a1e19aa2e..ee963e22e1 100644 --- a/source/tests/test_descrpt_sea_ef.py +++ b/source/tests/test_descrpt_sea_ef.py @@ -19,7 +19,7 @@ from common import virial_dw_test from common import Data -from deepmd.descrpt_loc_frame import op_module +from deepmd.env import op_module from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision diff --git a/source/tests/test_descrpt_sea_ef_para.py b/source/tests/test_descrpt_sea_ef_para.py index ec893ca1ee..6057599d10 100644 --- a/source/tests/test_descrpt_sea_ef_para.py +++ b/source/tests/test_descrpt_sea_ef_para.py @@ -19,7 +19,7 @@ from common import virial_dw_test from common import Data -from deepmd.descrpt_loc_frame import op_module +from deepmd.env import op_module from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision diff --git a/source/tests/test_descrpt_sea_ef_rot.py b/source/tests/test_descrpt_sea_ef_rot.py index 5aa931ba5d..461485150d 100644 --- a/source/tests/test_descrpt_sea_ef_rot.py +++ b/source/tests/test_descrpt_sea_ef_rot.py @@ -9,8 +9,8 @@ from deepmd.RunOptions import global_ener_float_precision from deepmd.env import op_module -from deepmd.descrpt_se_a import DescrptSeA -from deepmd.descrpt_se_a_ef import DescrptSeAEfLower +from deepmd.descriptor import DescrptSeA +from deepmd.descriptor import DescrptSeAEfLower class TestEfRot(unittest.TestCase): def setUp(self): diff --git a/source/tests/test_descrpt_sea_ef_vert.py b/source/tests/test_descrpt_sea_ef_vert.py index 4066670e88..062c4ac424 100644 --- a/source/tests/test_descrpt_sea_ef_vert.py +++ b/source/tests/test_descrpt_sea_ef_vert.py @@ -19,7 +19,7 @@ from common import virial_dw_test from common import Data -from deepmd.descrpt_loc_frame import op_module +from deepmd.env import op_module from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision diff --git a/source/tests/test_descrpt_smooth.py b/source/tests/test_descrpt_smooth.py index 7b169c4704..2ebe049bd4 100644 --- a/source/tests/test_descrpt_smooth.py +++ b/source/tests/test_descrpt_smooth.py @@ -19,7 +19,7 @@ from common import virial_dw_test from common import Data -from deepmd.descrpt_loc_frame import op_module +from deepmd.env import op_module from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision diff --git a/source/tests/test_embedding_net.py b/source/tests/test_embedding_net.py index 732470d408..3a1a15c42e 100644 --- a/source/tests/test_embedding_net.py +++ b/source/tests/test_embedding_net.py @@ -5,7 +5,7 @@ from deepmd.env import tf from tensorflow.python.framework import ops -from deepmd.network import embedding_net +from deepmd.utils.network import embedding_net from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision diff --git a/source/tests/test_ewald.py b/source/tests/test_ewald.py index cf2d543c2f..b8fc0731b8 100644 --- a/source/tests/test_ewald.py +++ b/source/tests/test_ewald.py @@ -6,8 +6,8 @@ from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.RunOptions import global_ener_float_precision -from deepmd.ewald_recp import op_module -from deepmd.ewald_recp import EwaldRecp +from deepmd.infer.ewald_recp import op_module +from deepmd.infer.ewald_recp import EwaldRecp if global_np_float_precision == np.float32 : global_default_fv_hh = 1e-2 diff --git a/source/tests/test_fitting_stat.py b/source/tests/test_fitting_stat.py index 7a49e11282..b56e72cc88 100644 --- a/source/tests/test_fitting_stat.py +++ b/source/tests/test_fitting_stat.py @@ -3,8 +3,8 @@ import unittest from collections import defaultdict -from deepmd.descrpt_se_a import DescrptSeA -from deepmd.fitting import EnerFitting +from deepmd.descriptor import DescrptSeA +from deepmd.fit import EnerFitting from deepmd.common import j_loader input_json = 'water_se_a_afparam.json' diff --git a/source/tests/test_gen_stat_data.py b/source/tests/test_gen_stat_data.py index 612b47a3fe..1dd9300ea4 100644 --- a/source/tests/test_gen_stat_data.py +++ b/source/tests/test_gen_stat_data.py @@ -3,8 +3,8 @@ import unittest import dpdata -from deepmd.data_system import DeepmdDataSystem -from deepmd.fitting import EnerFitting +from deepmd.utils.data_system import DeepmdDataSystem +from deepmd.fit import EnerFitting from deepmd.Model import make_stat_input, merge_sys_stat, _make_all_stat_ref def gen_sys(nframes, atom_types): diff --git a/source/tests/test_model_loc_frame.py b/source/tests/test_model_loc_frame.py index cd5fdb2067..b91fc1a2c7 100644 --- a/source/tests/test_model_loc_frame.py +++ b/source/tests/test_model_loc_frame.py @@ -4,9 +4,9 @@ from common import Data,gen_data from deepmd.RunOptions import RunOptions -from deepmd.data_system import DataSystem -from deepmd.descrpt_loc_frame import DescrptLocFrame -from deepmd.fitting import EnerFitting +from deepmd.utils.data_system import DataSystem +from deepmd.descriptor import DescrptLocFrame +from deepmd.fit import EnerFitting from deepmd.Model import Model from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader diff --git a/source/tests/test_model_se_a.py b/source/tests/test_model_se_a.py index 6bb80ba0b7..59e17b97fa 100644 --- a/source/tests/test_model_se_a.py +++ b/source/tests/test_model_se_a.py @@ -5,9 +5,9 @@ from common import Data,gen_data from deepmd.RunOptions import RunOptions -from deepmd.data_system import DataSystem -from deepmd.descrpt_se_a import DescrptSeA -from deepmd.fitting import EnerFitting +from deepmd.utils.data_system import DataSystem +from deepmd.descriptor import DescrptSeA +from deepmd.fit import EnerFitting from deepmd.Model import Model from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader diff --git a/source/tests/test_model_se_a_aparam.py b/source/tests/test_model_se_a_aparam.py index 0582024542..3ba2b60500 100644 --- a/source/tests/test_model_se_a_aparam.py +++ b/source/tests/test_model_se_a_aparam.py @@ -4,9 +4,9 @@ from common import Data,gen_data from deepmd.RunOptions import RunOptions -from deepmd.data_system import DataSystem -from deepmd.descrpt_se_a import DescrptSeA -from deepmd.fitting import EnerFitting +from deepmd.utils.data_system import DataSystem +from deepmd.descriptor import DescrptSeA +from deepmd.fit import EnerFitting from deepmd.Model import Model from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader diff --git a/source/tests/test_model_se_a_fparam.py b/source/tests/test_model_se_a_fparam.py index 642bcf4071..143f818d45 100644 --- a/source/tests/test_model_se_a_fparam.py +++ b/source/tests/test_model_se_a_fparam.py @@ -4,9 +4,9 @@ from common import Data,gen_data from deepmd.RunOptions import RunOptions -from deepmd.data_system import DataSystem -from deepmd.descrpt_se_a import DescrptSeA -from deepmd.fitting import EnerFitting +from deepmd.utils.data_system import DataSystem +from deepmd.descriptor import DescrptSeA +from deepmd.fit import EnerFitting from deepmd.Model import Model from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader diff --git a/source/tests/test_model_se_a_srtab.py b/source/tests/test_model_se_a_srtab.py index 338df18a6c..fd2ff980e4 100644 --- a/source/tests/test_model_se_a_srtab.py +++ b/source/tests/test_model_se_a_srtab.py @@ -4,9 +4,9 @@ from common import Data,gen_data from deepmd.RunOptions import RunOptions -from deepmd.data_system import DataSystem -from deepmd.descrpt_se_a import DescrptSeA -from deepmd.fitting import EnerFitting +from deepmd.utils.data_system import DataSystem +from deepmd.descriptor import DescrptSeA +from deepmd.fit import EnerFitting from deepmd.Model import Model from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader diff --git a/source/tests/test_model_se_r.py b/source/tests/test_model_se_r.py index 8aa6e6a383..dbc3d79c93 100644 --- a/source/tests/test_model_se_r.py +++ b/source/tests/test_model_se_r.py @@ -4,9 +4,9 @@ from common import Data,gen_data from deepmd.RunOptions import RunOptions -from deepmd.data_system import DataSystem -from deepmd.descrpt_se_r import DescrptSeR -from deepmd.fitting import EnerFitting +from deepmd.utils.data_system import DataSystem +from deepmd.descriptor import DescrptSeR +from deepmd.fit import EnerFitting from deepmd.Model import Model from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader diff --git a/source/tests/test_polar_se_a.py b/source/tests/test_polar_se_a.py index de2625ac9c..bb6068449e 100644 --- a/source/tests/test_polar_se_a.py +++ b/source/tests/test_polar_se_a.py @@ -4,9 +4,9 @@ from common import Data,gen_data from deepmd.RunOptions import RunOptions -from deepmd.data_system import DataSystem -from deepmd.descrpt_se_a import DescrptSeA -from deepmd.fitting import PolarFittingSeA +from deepmd.utils.data_system import DataSystem +from deepmd.descriptor import DescrptSeA +from deepmd.fit import PolarFittingSeA from deepmd.Model import PolarModel from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader diff --git a/source/tests/test_tab_nonsmth.py b/source/tests/test_tab_nonsmth.py index 4393a7e2d6..c626b7d634 100644 --- a/source/tests/test_tab_nonsmth.py +++ b/source/tests/test_tab_nonsmth.py @@ -12,7 +12,7 @@ import deepmd._prod_virial_se_a_grad import deepmd._soft_min_force_grad import deepmd._soft_min_virial_grad -from deepmd.tab_inter import TabInter +from deepmd.utils.tab_inter import TabInter from common import force_test from common import virial_test @@ -21,7 +21,7 @@ from common import Data from test_descrpt_nonsmth import Inter -from deepmd.descrpt_loc_frame import op_module +from deepmd.env import op_module def _make_tab(ntype) : xx = np.arange(0,9,0.001) diff --git a/source/tests/test_tab_smooth.py b/source/tests/test_tab_smooth.py index aa6bbc7170..ccb14bb09b 100644 --- a/source/tests/test_tab_smooth.py +++ b/source/tests/test_tab_smooth.py @@ -12,7 +12,7 @@ import deepmd._prod_virial_se_a_grad import deepmd._soft_min_force_grad import deepmd._soft_min_virial_grad -from deepmd.tab_inter import TabInter +from deepmd.utils.tab_inter import TabInter from common import force_test from common import virial_test @@ -21,7 +21,7 @@ from common import Data from test_descrpt_smooth import Inter -from deepmd.descrpt_loc_frame import op_module +from deepmd.env import op_module def _make_tab(ntype) : xx = np.arange(0,9,0.001) diff --git a/source/tests/test_wfc.py b/source/tests/test_wfc.py index b567a7717f..81b912ca58 100644 --- a/source/tests/test_wfc.py +++ b/source/tests/test_wfc.py @@ -4,9 +4,9 @@ from common import Data,gen_data from deepmd.RunOptions import RunOptions -from deepmd.data_system import DataSystem -from deepmd.descrpt_loc_frame import DescrptLocFrame -from deepmd.fitting import WFCFitting +from deepmd.utils.data_system import DataSystem +from deepmd.descriptor import DescrptLocFrame +from deepmd.fit import WFCFitting from deepmd.Model import WFCModel from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader diff --git a/source/train/Model.py b/source/train/Model.py index d810a806ef..9c9cd7ddff 100644 --- a/source/train/Model.py +++ b/source/train/Model.py @@ -1,7 +1,7 @@ import numpy as np from deepmd.env import tf from collections import defaultdict -from deepmd.tab_inter import TabInter +from deepmd.utils.tab_inter import TabInter from deepmd.common import ClassArg from deepmd.RunOptions import global_cvt_2_ener_float diff --git a/source/train/Trainer.py b/source/train/Trainer.py index c3be9a0ebe..765a25d206 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -7,18 +7,18 @@ from deepmd.env import default_tf_session_config from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_ener_float_precision -from deepmd.fitting import EnerFitting, WFCFitting, PolarFittingLocFrame, PolarFittingSeA, GlobalPolarFittingSeA, DipoleFittingSeA -from deepmd.descrpt_loc_frame import DescrptLocFrame -from deepmd.descrpt_se_a import DescrptSeA -from deepmd.descrpt_se_a_t import DescrptSeAT -from deepmd.descrpt_se_a_ebd import DescrptSeAEbd -from deepmd.descrpt_se_a_ef import DescrptSeAEf -from deepmd.descrpt_se_r import DescrptSeR -from deepmd.descrpt_se_ar import DescrptSeAR -from deepmd.descrpt_hybrid import DescrptHybrid +from deepmd.fit import EnerFitting, WFCFitting, PolarFittingLocFrame, PolarFittingSeA, GlobalPolarFittingSeA, DipoleFittingSeA +from deepmd.descriptor import DescrptLocFrame +from deepmd.descriptor import DescrptSeA +from deepmd.descriptor import DescrptSeAT +from deepmd.descriptor import DescrptSeAEbd +from deepmd.descriptor import DescrptSeAEf +from deepmd.descriptor import DescrptSeR +from deepmd.descriptor import DescrptSeAR +from deepmd.descriptor import DescrptHybrid from deepmd.Model import Model, WFCModel, DipoleModel, PolarModel, GlobalPolarModel from deepmd.loss import EnerStdLoss, EnerDipoleLoss, TensorLoss -from deepmd.learning_rate import LearningRateExp +from deepmd.utils.learning_rate import LearningRateExp from tensorflow.python.client import timeline from deepmd.env import op_module diff --git a/source/train/test.py b/source/train/test.py index c4fa7476f2..b8c5e450cc 100644 --- a/source/train/test.py +++ b/source/train/test.py @@ -6,7 +6,7 @@ import argparse import numpy as np -from deepmd.data import DeepmdData +from deepmd.utils.data import DeepmdData from deepmd.common import expand_sys_str from deepmd import DeepEval from deepmd import DeepPot diff --git a/source/train/train.py b/source/train/train.py index 4307695cfe..3184ab6250 100755 --- a/source/train/train.py +++ b/source/train/train.py @@ -8,10 +8,10 @@ from deepmd.env import tf from deepmd.compat import convert_input_v0_v1 from deepmd.RunOptions import RunOptions -from deepmd.data_system import DeepmdDataSystem +from deepmd.utils.data_system import DeepmdDataSystem from deepmd.Trainer import NNPTrainer from deepmd.common import data_requirement, expand_sys_str, j_loader -from deepmd.data_modifier import DipoleChargeModifier +from deepmd.infer.data_modifier import DipoleChargeModifier from deepmd.argcheck import normalize def create_done_queue(cluster_spec, task_index): From 2d3cb2b161ba2e784a5d759ded36ccb6816a1079 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 17 Jan 2021 18:21:54 +0800 Subject: [PATCH 049/562] fix bug: removed folder api --- {source/train => deepmd}/env.py | 0 source/CMakeLists.txt | 1 - 2 files changed, 1 deletion(-) rename {source/train => deepmd}/env.py (100%) diff --git a/source/train/env.py b/deepmd/env.py similarity index 100% rename from source/train/env.py rename to deepmd/env.py diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 086c3d4584..dc35ee5dc0 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -201,7 +201,6 @@ include_directories(${CMAKE_BINARY_DIR}/lib/) add_subdirectory (op/) if (BUILD_PY_IF) add_subdirectory (train/) - add_subdirectory (api/) add_subdirectory (scripts/) add_subdirectory (tests/) endif (BUILD_PY_IF) From e86cf20b4a9ad6ae629ec16c566ed3b086cb4b75 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 17 Jan 2021 18:53:03 +0800 Subject: [PATCH 050/562] move common, env, compat to deepmd and deepmd/utils --- {source/train => deepmd}/common.py | 0 deepmd/descriptor/se_a.py | 2 +- deepmd/descriptor/se_a_ef.py | 2 +- deepmd/descriptor/se_a_t.py | 2 +- deepmd/descriptor/se_r.py | 2 +- deepmd/fit/dipole.py | 2 +- deepmd/fit/ener.py | 2 +- deepmd/fit/polar.py | 2 +- deepmd/fit/wfc.py | 2 +- {source/train => deepmd/utils}/argcheck.py | 0 {source/train => deepmd/utils}/compat.py | 0 source/tests/test_compat_input.py | 2 +- source/train/CMakeLists.txt | 2 +- source/train/doc.py | 2 +- source/train/train.py | 8 ++++---- 15 files changed, 15 insertions(+), 15 deletions(-) rename {source/train => deepmd}/common.py (100%) rename {source/train => deepmd/utils}/argcheck.py (100%) rename {source/train => deepmd/utils}/compat.py (100%) diff --git a/source/train/common.py b/deepmd/common.py similarity index 100% rename from source/train/common.py rename to deepmd/common.py diff --git a/deepmd/descriptor/se_a.py b/deepmd/descriptor/se_a.py index 884f024357..410cf0d9b4 100644 --- a/deepmd/descriptor/se_a.py +++ b/deepmd/descriptor/se_a.py @@ -3,7 +3,7 @@ from deepmd.env import tf from deepmd.common import get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter -from deepmd.argcheck import list_to_doc +from deepmd.utils.argcheck import list_to_doc from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module diff --git a/deepmd/descriptor/se_a_ef.py b/deepmd/descriptor/se_a_ef.py index a58b465f6e..fd05669cbb 100644 --- a/deepmd/descriptor/se_a_ef.py +++ b/deepmd/descriptor/se_a_ef.py @@ -3,7 +3,7 @@ from deepmd.env import tf from deepmd.common import add_data_requirement,get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter -from deepmd.argcheck import list_to_doc +from deepmd.utils.argcheck import list_to_doc from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module diff --git a/deepmd/descriptor/se_a_t.py b/deepmd/descriptor/se_a_t.py index 1639edbe5c..64732b496f 100644 --- a/deepmd/descriptor/se_a_t.py +++ b/deepmd/descriptor/se_a_t.py @@ -3,7 +3,7 @@ from deepmd.env import tf from deepmd.common import get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter -from deepmd.argcheck import list_to_doc +from deepmd.utils.argcheck import list_to_doc from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module diff --git a/deepmd/descriptor/se_r.py b/deepmd/descriptor/se_r.py index 353a531d3d..2eab2afe09 100644 --- a/deepmd/descriptor/se_r.py +++ b/deepmd/descriptor/se_r.py @@ -3,7 +3,7 @@ from deepmd.env import tf from deepmd.common import get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter -from deepmd.argcheck import list_to_doc +from deepmd.utils.argcheck import list_to_doc from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module diff --git a/deepmd/fit/dipole.py b/deepmd/fit/dipole.py index de3b34626e..85bc1065f1 100644 --- a/deepmd/fit/dipole.py +++ b/deepmd/fit/dipole.py @@ -4,7 +4,7 @@ from deepmd.env import tf from deepmd.common import add_data_requirement, get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter -from deepmd.argcheck import list_to_doc +from deepmd.utils.argcheck import list_to_doc from deepmd.utils.network import one_layer from deepmd.descriptor import DescrptSeA diff --git a/deepmd/fit/ener.py b/deepmd/fit/ener.py index 34f9cc08be..5c766f729b 100644 --- a/deepmd/fit/ener.py +++ b/deepmd/fit/ener.py @@ -4,7 +4,7 @@ from deepmd.env import tf from deepmd.common import ClassArg, add_data_requirement, get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter -from deepmd.argcheck import list_to_doc +from deepmd.utils.argcheck import list_to_doc from deepmd.utils.network import one_layer from deepmd.descriptor import DescrptLocFrame from deepmd.descriptor import DescrptSeA diff --git a/deepmd/fit/polar.py b/deepmd/fit/polar.py index f466195fc8..c93aa43d1b 100644 --- a/deepmd/fit/polar.py +++ b/deepmd/fit/polar.py @@ -4,7 +4,7 @@ from deepmd.env import tf from deepmd.common import add_data_requirement, get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter -from deepmd.argcheck import list_to_doc +from deepmd.utils.argcheck import list_to_doc from deepmd.utils.network import one_layer from deepmd.descriptor import DescrptLocFrame from deepmd.descriptor import DescrptSeA diff --git a/deepmd/fit/wfc.py b/deepmd/fit/wfc.py index 786677b0dc..88f63a366e 100644 --- a/deepmd/fit/wfc.py +++ b/deepmd/fit/wfc.py @@ -4,7 +4,7 @@ from deepmd.env import tf from deepmd.common import ClassArg, add_data_requirement, get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter -from deepmd.argcheck import list_to_doc +from deepmd.utils.argcheck import list_to_doc from deepmd.utils.network import one_layer from deepmd.descriptor import DescrptLocFrame diff --git a/source/train/argcheck.py b/deepmd/utils/argcheck.py similarity index 100% rename from source/train/argcheck.py rename to deepmd/utils/argcheck.py diff --git a/source/train/compat.py b/deepmd/utils/compat.py similarity index 100% rename from source/train/compat.py rename to deepmd/utils/compat.py diff --git a/source/tests/test_compat_input.py b/source/tests/test_compat_input.py index c0a29283dd..a7c2c7f083 100644 --- a/source/tests/test_compat_input.py +++ b/source/tests/test_compat_input.py @@ -2,7 +2,7 @@ import numpy as np import unittest -from deepmd.compat import convert_input_v0_v1 +from deepmd.utils.compat import convert_input_v0_v1 from deepmd.common import j_loader class TestConvertInput (unittest.TestCase) : diff --git a/source/train/CMakeLists.txt b/source/train/CMakeLists.txt index 4a567abb9d..818b2f4225 100644 --- a/source/train/CMakeLists.txt +++ b/source/train/CMakeLists.txt @@ -2,7 +2,7 @@ configure_file("RunOptions.py.in" "${CMAKE_CURRENT_BINARY_DIR}/RunOptions.py" @ONLY) -file(GLOB LIB_PY main.py common.py env.py compat.py calculator.py Network.py Deep*.py Data.py DataSystem.py Model*.py Descrpt*.py Loss.py LearningRate.py Trainer.py TabInter.py EwaldRecp.py DataModifier.py ${CMAKE_CURRENT_BINARY_DIR}/RunOptions.py transform.py argcheck.py doc.py) +file(GLOB LIB_PY main.py calculator.py Model*.py Trainer.py ${CMAKE_CURRENT_BINARY_DIR}/RunOptions.py transform.py doc.py) file(GLOB CLS_PY Local.py Slurm.py) diff --git a/source/train/doc.py b/source/train/doc.py index 599f64e247..4973361b0f 100644 --- a/source/train/doc.py +++ b/source/train/doc.py @@ -1,4 +1,4 @@ -from deepmd.argcheck import gen_doc +from deepmd.utils.argcheck import gen_doc def doc_train_input(args): doc_str = gen_doc(make_anchor=True) diff --git a/source/train/train.py b/source/train/train.py index 3184ab6250..a1702998d9 100755 --- a/source/train/train.py +++ b/source/train/train.py @@ -6,13 +6,13 @@ import json import numpy as np from deepmd.env import tf -from deepmd.compat import convert_input_v0_v1 +from deepmd.common import data_requirement, expand_sys_str, j_loader from deepmd.RunOptions import RunOptions -from deepmd.utils.data_system import DeepmdDataSystem from deepmd.Trainer import NNPTrainer -from deepmd.common import data_requirement, expand_sys_str, j_loader from deepmd.infer.data_modifier import DipoleChargeModifier -from deepmd.argcheck import normalize +from deepmd.utils.data_system import DeepmdDataSystem +from deepmd.utils.compat import convert_input_v0_v1 +from deepmd.utils.argcheck import normalize def create_done_queue(cluster_spec, task_index): with tf.device("/job:ps/task:%d" % (task_index)): From 028d04ae1c1882a56dffe67e97344c65975b7c86 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 19 Jan 2021 07:32:57 +0800 Subject: [PATCH 051/562] avoid `using namespace std` in all c++ code --- source/ipi/driver.cc | 62 ++-- source/ipi/include/Convert.h | 20 +- source/ipi/include/XyzFileManager.h | 12 +- source/ipi/src/Convert.cc | 16 +- source/ipi/src/XyzFileManager.cc | 30 +- source/lib/include/ComputeDescriptor.h | 332 ++++++++++----------- source/lib/include/DataModifier.h | 42 +-- source/lib/include/DeepTensor.h | 52 ++-- source/lib/include/Ewald.h | 26 +- source/lib/include/MathUtilities.h | 10 +- source/lib/include/MathUtilities_Impl.h | 10 +- source/lib/include/NNPAtomMap.h | 26 +- source/lib/include/NNPInter.h | 184 ++++++------ source/lib/include/NeighborList.h | 84 +++--- source/lib/include/RandomGenerator.h | 23 ++ source/lib/include/SimulationRegion.h | 6 +- source/lib/include/SimulationRegion_Impl.h | 10 +- source/lib/include/common.h | 88 +++--- source/lib/include/version.h.in | 2 +- source/lib/src/DataModifier.cc | 56 ++-- source/lib/src/DeepTensor.cc | 50 ++-- source/lib/src/NNPAtomMap.cc | 18 +- source/lib/src/NNPInter.cc | 246 +++++++-------- source/lib/src/NeighborList.cpp | 236 +++++++-------- source/lib/src/common.cc | 114 +++---- source/op/descrpt.cc | 130 ++++---- source/op/descrpt_se_a.cc | 68 ++--- source/op/descrpt_se_a_ef.cc | 70 ++--- source/op/descrpt_se_a_ef_para.cc | 70 ++--- source/op/descrpt_se_a_ef_vert.cc | 70 ++--- source/op/descrpt_se_a_multi_device.cc | 14 +- source/op/descrpt_se_r.cc | 68 ++--- source/op/descrpt_se_r_multi_device.cc | 16 +- source/op/ewald_recp.cc | 14 +- source/op/map_aparam.cc | 2 +- source/op/prod_force.cc | 4 +- source/op/prod_force_grad.cc | 4 +- source/op/prod_force_se_a.cc | 2 +- source/op/prod_force_se_a_grad.cc | 4 +- source/op/prod_force_se_r.cc | 2 +- source/op/prod_force_se_r_grad.cc | 4 +- source/op/prod_virial.cc | 2 +- source/op/prod_virial_grad.cc | 4 +- source/op/prod_virial_se_a.cc | 2 +- source/op/prod_virial_se_a_grad.cc | 4 +- source/op/prod_virial_se_r.cc | 2 +- source/op/prod_virial_se_r_grad.cc | 4 +- source/op/soft_min.cc | 18 +- source/op/soft_min_force.cc | 6 +- source/op/soft_min_force_grad.cc | 4 +- source/op/soft_min_virial.cc | 2 +- source/op/soft_min_virial_grad.cc | 4 +- source/op/tab_inter.cc | 22 +- 53 files changed, 1197 insertions(+), 1174 deletions(-) create mode 100644 source/lib/include/RandomGenerator.h diff --git a/source/ipi/driver.cc b/source/ipi/driver.cc index 3830ca8a8d..91a54504ea 100644 --- a/source/ipi/driver.cc +++ b/source/ipi/driver.cc @@ -10,7 +10,7 @@ using json = nlohmann::json; -using namespace std; +// using namespace std; // bohr -> angstrom const double cvt_len = 0.52917721; @@ -38,7 +38,7 @@ char *trimwhitespace(char *str) } void -normalize_coord (vector & coord, +normalize_coord (std::vector & coord, const SimulationRegion & region) { int natoms = coord.size() / 3; @@ -58,16 +58,16 @@ normalize_coord (vector & coord, int main(int argc, char * argv[]) { if (argc == 1) { - cerr << "usage " << endl; - cerr << argv[0] << " input_script " << endl; + std::cerr << "usage " << std::endl; + std::cerr << argv[0] << " input_script " << std::endl; return 1; } - ifstream fp (argv[1]); + std::ifstream fp (argv[1]); json jdata; fp >> jdata; - cout << "# using data base" << endl; - cout << setw(4) << jdata << endl; + std::cout << "# using data base" << std::endl; + std::cout << std::setw(4) << jdata << std::endl; int socket; int inet = 1; @@ -79,14 +79,14 @@ int main(int argc, char * argv[]) const char * host = host_str.c_str(); string graph_file = jdata["graph_file"]; string coord_file = jdata["coord_file"]; - map name_type_map = jdata["atom_type"]; + std::map name_type_map = jdata["atom_type"]; bool b_verb = jdata["verbose"]; - vector atom_name; + std::vector atom_name; { - vector > posi; - vector > velo; - vector > forc; + std::vector > posi; + std::vector > velo; + std::vector > forc; XyzFileManager::read (coord_file, atom_name, posi, velo, forc); } @@ -103,13 +103,13 @@ int main(int argc, char * argv[]) double cell_ih[9]; int32_t natoms = -1; double dener (0); - vector dforce; - vector dforce_tmp; - vector dvirial (9, 0); - vector dcoord ; - vector dcoord_tmp ; - vector dtype = cvt.get_type(); - vector dbox (9, 0) ; + std::vector dforce; + std::vector dforce_tmp; + std::vector dvirial (9, 0); + std::vector dcoord ; + std::vector dcoord_tmp ; + std::vector dtype = cvt.get_type(); + std::vector dbox (9, 0) ; SimulationRegion region; double * msg_buff = NULL; double ener; @@ -127,27 +127,27 @@ int main(int argc, char * argv[]) while (true) { readbuffer_ (&socket, header, MSGLEN); string header_str (trimwhitespace(header)); - if (b_verb) cout << "# get header " << header_str << endl; + if (b_verb) std::cout << "# get header " << header_str << std::endl; if (header_str == "STATUS"){ if (! isinit) { writebuffer_ (&socket, msg_needinit, MSGLEN); - if (b_verb) cout << "# send back " << "NEEDINIT" << endl; + if (b_verb) std::cout << "# send back " << "NEEDINIT" << std::endl; } else if (hasdata) { writebuffer_ (&socket, msg_havedata, MSGLEN); - if (b_verb) cout << "# send back " << "HAVEDATA" << endl; + if (b_verb) std::cout << "# send back " << "HAVEDATA" << std::endl; } else { writebuffer_ (&socket, msg_ready, MSGLEN); - if (b_verb) cout << "# send back " << "READY" << endl; + if (b_verb) std::cout << "# send back " << "READY" << std::endl; } } else if (header_str == "INIT") { assert (4 == sizeof(int32_t)); readbuffer_ (&socket, (char *)(&cbuf), sizeof(int32_t)); readbuffer_ (&socket, initbuffer, cbuf); - if (b_verb) cout << "Init sys from wrapper, using " << initbuffer << endl; + if (b_verb) std::cout << "Init sys from wrapper, using " << initbuffer << std::endl; } else if (header_str == "POSDATA"){ assert (8 == sizeof(double)); @@ -164,7 +164,7 @@ int main(int argc, char * argv[]) readbuffer_ (&socket, (char *)(&cbuf), sizeof(int32_t)); if (natoms < 0) { natoms = cbuf; - if (b_verb) cout << "# get number of atoms in system: " << natoms << endl; + if (b_verb) std::cout << "# get number of atoms in system: " << natoms << std::endl; dcoord.resize (3 * natoms); dforce.resize (3 * natoms, 0); @@ -186,12 +186,12 @@ int main(int argc, char * argv[]) nnp_inter.compute (dener, dforce_tmp, dvirial, dcoord, dtype, dbox); #else // model in float prec - vector dcoord_(dcoord.size()); - vector dbox_(dbox.size()); + std::vector dcoord_(dcoord.size()); + std::vector dbox_(dbox.size()); for (unsigned dd = 0; dd < dcoord.size(); ++dd) dcoord_[dd] = dcoord[dd]; for (unsigned dd = 0; dd < dbox.size(); ++dd) dbox_[dd] = dbox[dd]; - vector dforce_(dforce.size(), 0); - vector dvirial_(dvirial.size(), 0); + std::vector dforce_(dforce.size(), 0); + std::vector dvirial_(dvirial.size(), 0); double dener_ = 0; nnp_inter.compute (dener_, dforce_, dvirial_, dcoord_, dtype, dbox_); for (unsigned dd = 0; dd < dforce.size(); ++dd) dforce_tmp[dd] = dforce_[dd]; @@ -209,7 +209,7 @@ int main(int argc, char * argv[]) for (int ii = 0; ii < 9; ++ii){ virial[ii] = dvirial[ii] * icvt_ener * (1.0); } - if (b_verb) cout << "# energy of sys. : " << scientific << setprecision(10) << dener << endl; + if (b_verb) std::cout << "# energy of sys. : " << std::scientific << std::setprecision(10) << dener << std::endl; writebuffer_ (&socket, msg_forceready, MSGLEN); writebuffer_ (&socket, (char *)(&ener), sizeof(double)); writebuffer_ (&socket, (char *)(&natoms), sizeof(int32_t)); @@ -221,7 +221,7 @@ int main(int argc, char * argv[]) hasdata = false; } else { - cerr << "unexpected header " << endl; + std::cerr << "unexpected header " << std::endl; return 1; } } diff --git a/source/ipi/include/Convert.h b/source/ipi/include/Convert.h index 3cfdd7053e..7440aea6d2 100644 --- a/source/ipi/include/Convert.h +++ b/source/ipi/include/Convert.h @@ -4,24 +4,24 @@ #include #include -using namespace std; +// using namespace std; template class Convert { public: - Convert(const vector & atomname, - map & name_type_map); + Convert(const std::vector & atomname, + std::map & name_type_map); void forward ( - vector & out, - const vector & in, + std::vector & out, + const std::vector & in, const int stride = 1) const ; void backward ( - vector & out, - const vector & in, + std::vector & out, + const std::vector & in, const int stride = 1) const ; - const vector & get_type () const {return atype;} + const std::vector & get_type () const {return atype;} private: - vector idx_map; - vector atype; + std::vector idx_map; + std::vector atype; }; diff --git a/source/ipi/include/XyzFileManager.h b/source/ipi/include/XyzFileManager.h index ca8495623a..2f95799cd8 100644 --- a/source/ipi/include/XyzFileManager.h +++ b/source/ipi/include/XyzFileManager.h @@ -2,16 +2,16 @@ #define __XyzFileManager_h_wanghan__ #include -using namespace std; +// using namespace std; namespace XyzFileManager{ void - read (const string & file, - vector & atom_name, - vector > & posi, - vector > & velo, - vector > & forc); + read (const std::string & file, + std::vector & atom_name, + std::vector > & posi, + std::vector > & velo, + std::vector > & forc); }; diff --git a/source/ipi/src/Convert.cc b/source/ipi/src/Convert.cc index 267d950a59..8019181efd 100644 --- a/source/ipi/src/Convert.cc +++ b/source/ipi/src/Convert.cc @@ -5,17 +5,17 @@ template Convert:: -Convert(const vector & atomname, - map & name_type_map) +Convert(const std::vector & atomname, + std::map & name_type_map) { int natoms = atomname.size(); atype.resize (natoms); for (unsigned ii = 0; ii < atype.size(); ++ii){ atype[ii] = name_type_map[atomname[ii]]; } - vector > sorting (natoms); + std::vector > sorting (natoms); for (unsigned ii = 0; ii < sorting.size(); ++ii){ - sorting[ii] = pair (atype[ii], ii); + sorting[ii] = std::pair (atype[ii], ii); } // sort (sorting.begin(), sorting.end()); idx_map.resize(natoms); @@ -28,8 +28,8 @@ Convert(const vector & atomname, template void Convert:: -forward (vector & out, - const vector & in, +forward (std::vector & out, + const std::vector & in, const int stride) const { assert (in.size() == stride * idx_map.size()); @@ -46,8 +46,8 @@ forward (vector & out, template void Convert:: -backward (vector & out, - const vector & in, +backward (std::vector & out, + const std::vector & in, const int stride) const { int natoms = idx_map.size(); diff --git a/source/ipi/src/XyzFileManager.cc b/source/ipi/src/XyzFileManager.cc index d8c17d5195..a90b853fae 100644 --- a/source/ipi/src/XyzFileManager.cc +++ b/source/ipi/src/XyzFileManager.cc @@ -8,37 +8,37 @@ void XyzFileManager:: -read (const string & file, - vector & atom_name, - vector > & posi, - vector > & velo, - vector > & forc) +read (const std::string & file, + std::vector & atom_name, + std::vector > & posi, + std::vector > & velo, + std::vector > & forc) { // getBoxSize (file, boxsize); posi.clear(); velo.clear(); - ifstream data0 (file.c_str()); + std::ifstream data0 (file.c_str()); if (!data0.is_open()) { - cerr << "cannot open file " << file << endl; + std::cerr << "cannot open file " << file << std::endl; exit(1); } - string valueline; - vector words; + std::string valueline; + std::vector words; words.reserve (10); - string tmpname; - vector tmpp(3); - vector tmpv(3); - vector tmpf(3); + std::string tmpname; + std::vector tmpp(3); + std::vector tmpv(3); + std::vector tmpf(3); std::getline(data0, valueline); long long int numb_atom = atoll (valueline.c_str()); std::getline(data0, valueline); for (long long int ii = 0; ii< numb_atom; ++ii) { std::getline(data0, valueline); - StringOperation::split (string(valueline), words); + StringOperation::split (std::string(valueline), words); if (words.size() == 10){ tmpp[0] = atof (words[1+0].c_str()); tmpp[1] = atof (words[1+1].c_str()); @@ -73,7 +73,7 @@ read (const string & file, atom_name.push_back (words[0]); } else { - cerr << "XyzFileManager::read: wrong format, line has "<< words.size() << " words" << endl; + std::cerr << "XyzFileManager::read: wrong format, line has "<< words.size() << " words" << std::endl; exit (1); } } diff --git a/source/lib/include/ComputeDescriptor.h b/source/lib/include/ComputeDescriptor.h index 7d9f571980..b01f9ed44b 100644 --- a/source/lib/include/ComputeDescriptor.h +++ b/source/lib/include/ComputeDescriptor.h @@ -11,135 +11,135 @@ // return: -1 OK // > 0 the type of unsuccessful neighbor list inline -int format_nlist_fill_a (vector & fmt_nei_idx_a, - vector & fmt_nei_idx_r, - const vector & posi, +int format_nlist_fill_a (std::vector & fmt_nei_idx_a, + std::vector & fmt_nei_idx_r, + const std::vector & posi, const int & ntypes, - const vector & type, + const std::vector & type, const SimulationRegion & region, const bool & b_pbc, const int & i_idx, - const vector & nei_idx_a, - const vector & nei_idx_r, + const std::vector & nei_idx_a, + const std::vector & nei_idx_r, const double & rcut, - const vector & sec_a, - const vector & sec_r); + const std::vector & sec_a, + const std::vector & sec_r); inline -void compute_descriptor (vector & descrpt_a, - vector & descrpt_r, - vector & rot_mat, - const vector & posi, +void compute_descriptor (std::vector & descrpt_a, + std::vector & descrpt_r, + std::vector & rot_mat, + const std::vector & posi, const int & ntypes, - const vector & type, + const std::vector & type, const SimulationRegion & region, const bool & b_pbc, const int & i_idx, - const vector & fmt_nlist_a, - const vector & fmt_nlist_r, - const vector & sec_a, - const vector & sec_r, + const std::vector & fmt_nlist_a, + const std::vector & fmt_nlist_r, + const std::vector & sec_a, + const std::vector & sec_r, const int axis0_type, const int axis0_idx, const int axis1_type, const int axis1_idx); inline -void compute_descriptor (vector & descrpt_a, - vector & descrpt_a_deriv, - vector & descrpt_r, - vector & descrpt_r_deriv, - vector & rij_a, - vector & rij_r, - vector & rot_mat, - const vector & posi, +void compute_descriptor (std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & descrpt_r, + std::vector & descrpt_r_deriv, + std::vector & rij_a, + std::vector & rij_r, + std::vector & rot_mat, + const std::vector & posi, const int & ntypes, - const vector & type, + const std::vector & type, const SimulationRegion & region, const bool & b_pbc, const int & i_idx, - const vector & fmt_nlist_a, - const vector & fmt_nlist_r, - const vector & sec_a, - const vector & sec_r, + const std::vector & fmt_nlist_a, + const std::vector & fmt_nlist_r, + const std::vector & sec_a, + const std::vector & sec_r, const int axis0_type, const int axis0_idx, const int axis1_type, const int axis1_idx); inline -void compute_descriptor_se_a (vector & descrpt_a, - vector & descrpt_a_deriv, - vector & rij_a, - const vector & posi, - const int & ntypes, - const vector & type, - const SimulationRegion & region, - const bool & b_pbc, - const int & i_idx, - const vector & fmt_nlist_a, - const vector & sec_a, - const double & rmin, - const double & rmax); +void compute_descriptor_se_a (std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, + const int & ntypes, + const std::vector & type, + const SimulationRegion & region, + const bool & b_pbc, + const int & i_idx, + const std::vector & fmt_nlist_a, + const std::vector & sec_a, + const double & rmin, + const double & rmax); inline -void compute_descriptor_se_a_extf (vector & descrpt_a, - vector & descrpt_a_deriv, - vector & rij_a, - const vector & posi, - const int & ntypes, - const vector & type, +void compute_descriptor_se_a_extf (std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, + const int & ntypes, + const std::vector & type, const SimulationRegion & region, - const bool & b_pbc, - const vector & efield, - const int & i_idx, - const vector & fmt_nlist_a, - const vector & sec_a, - const double & rmin, - const double & rmax); + const bool & b_pbc, + const std::vector & efield, + const int & i_idx, + const std::vector & fmt_nlist_a, + const std::vector & sec_a, + const double & rmin, + const double & rmax); inline -void compute_descriptor_se_a_ef_para (vector & descrpt_a, - vector & descrpt_a_deriv, - vector & rij_a, - const vector & posi, +void compute_descriptor_se_a_ef_para (std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, const int & ntypes, - const vector & type, - const SimulationRegion & region, + const std::vector & type, + const SimulationRegion & region, const bool & b_pbc, - const vector & efield, + const std::vector & efield, const int & i_idx, - const vector & fmt_nlist_a, - const vector & sec_a, - const double & rmin, - const double & rmax); + const std::vector & fmt_nlist_a, + const std::vector & sec_a, + const double & rmin, + const double & rmax); inline -void compute_descriptor_se_a_ef_vert (vector & descrpt_a, - vector & descrpt_a_deriv, - vector & rij_a, - const vector & posi, +void compute_descriptor_se_a_ef_vert (std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, const int & ntypes, - const vector & type, - const SimulationRegion & region, + const std::vector & type, + const SimulationRegion & region, const bool & b_pbc, - const vector & efield, + const std::vector & efield, const int & i_idx, - const vector & fmt_nlist_a, - const vector & sec_a, - const double & rmin, - const double & rmax); + const std::vector & fmt_nlist_a, + const std::vector & sec_a, + const double & rmin, + const double & rmax); inline -void compute_descriptor_se_r (vector & descrpt_r, - vector & descrpt_r_deriv, - vector & rij_r, - const vector & posi, +void compute_descriptor_se_r (std::vector & descrpt_r, + std::vector & descrpt_r_deriv, + std::vector & rij_r, + const std::vector & posi, const int & ntypes, - const vector & type, + const std::vector & type, const SimulationRegion & region, const bool & b_pbc, const int & i_idx, - const vector & fmt_nlist_r, - const vector & sec_r, + const std::vector & fmt_nlist_r, + const std::vector & sec_r, const double & rmin, const double & rmax); @@ -346,19 +346,19 @@ compute_dRdT_2 (double (* dRdT)[9], } } -int format_nlist_fill_a (vector & fmt_nei_idx_a, - vector & fmt_nei_idx_r, - const vector & posi, +int format_nlist_fill_a (std::vector & fmt_nei_idx_a, + std::vector & fmt_nei_idx_r, + const std::vector & posi, const int & ntypes, - const vector & type, + const std::vector & type, const SimulationRegion & region, const bool & b_pbc, const int & i_idx, - const vector & nei_idx_a, - const vector & nei_idx_r, + const std::vector & nei_idx_a, + const std::vector & nei_idx_r, const double & rcut, - const vector & sec_a, - const vector & sec_r) + const std::vector & sec_a, + const std::vector & sec_r) { #ifdef DEBUG assert (sec_a.size() == ntypes + 1); @@ -371,11 +371,11 @@ int format_nlist_fill_a (vector & fmt_nei_idx_a, fill (fmt_nei_idx_r.begin(), fmt_nei_idx_r.end(), -1); // gether all neighbors - vector nei_idx (nei_idx_a); + std::vector nei_idx (nei_idx_a); nei_idx.insert (nei_idx.end(), nei_idx_r.begin(), nei_idx_r.end()); assert (nei_idx.size() == nei_idx_a.size() + nei_idx_r.size()); // allocate the information for all neighbors - vector sel_nei ; + std::vector sel_nei ; sel_nei.reserve (nei_idx_a.size() + nei_idx_r.size()); for (unsigned kk = 0; kk < nei_idx.size(); ++kk){ double diff[3]; @@ -395,7 +395,7 @@ int format_nlist_fill_a (vector & fmt_nei_idx_a, } sort (sel_nei.begin(), sel_nei.end()); - vector nei_iter = sec_a; + std::vector nei_iter = sec_a; int overflowed = -1; for (unsigned kk = 0; kk < sel_nei.size(); ++kk){ const int & nei_type = sel_nei[kk].type; @@ -420,30 +420,30 @@ int format_nlist_fill_a (vector & fmt_nei_idx_a, // output deriv size: n_sel_a_nei x 4 x 12 + n_sel_r_nei x 12 // (1./rr, cos_theta, cos_phi, sin_phi) x 4 x (x, y, z) + (1./rr) x 4 x (x, y, z) -void compute_descriptor (vector & descrpt_a, - vector & descrpt_a_deriv, - vector & descrpt_r, - vector & descrpt_r_deriv, - vector & rij_a, - vector & rij_r, - vector & rot_mat, - const vector & posi, +void compute_descriptor (std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & descrpt_r, + std::vector & descrpt_r_deriv, + std::vector & rij_a, + std::vector & rij_r, + std::vector & rot_mat, + const std::vector & posi, const int & ntypes, - const vector & type, + const std::vector & type, const SimulationRegion & region, const bool & b_pbc, const int & i_idx, - const vector & fmt_nlist_a, - const vector & fmt_nlist_r, - const vector & sec_a, - const vector & sec_r, + const std::vector & fmt_nlist_a, + const std::vector & fmt_nlist_r, + const std::vector & sec_a, + const std::vector & sec_r, const int axis0_type, const int axis0_idx, const int axis1_type, const int axis1_idx) { // compute the diff of the neighbors - vector > sel_a_diff (sec_a.back()); + std::vector > sel_a_diff (sec_a.back()); rij_a.resize (sec_a.back() * 3); fill (rij_a.begin(), rij_a.end(), 0.0); for (int ii = 0; ii < int(sec_a.size()) - 1; ++ii){ @@ -463,7 +463,7 @@ void compute_descriptor (vector & descrpt_a, } } - vector > sel_r_diff (sec_r.back()); + std::vector > sel_r_diff (sec_r.back()); rij_r.resize (sec_r.back() * 3); fill (rij_r.begin(), rij_r.end(), 0.0); for (int ii = 0; ii < int(sec_r.size()) - 1; ++ii){ @@ -759,26 +759,26 @@ void compute_descriptor (vector & descrpt_a, } -void compute_descriptor (vector & descrpt_a, - vector & descrpt_r, - vector & rot_mat, - const vector & posi, +void compute_descriptor (std::vector & descrpt_a, + std::vector & descrpt_r, + std::vector & rot_mat, + const std::vector & posi, const int & ntypes, - const vector & type, + const std::vector & type, const SimulationRegion & region, const bool & b_pbc, const int & i_idx, - const vector & fmt_nlist_a, - const vector & fmt_nlist_r, - const vector & sec_a, - const vector & sec_r, + const std::vector & fmt_nlist_a, + const std::vector & fmt_nlist_r, + const std::vector & sec_a, + const std::vector & sec_r, const int axis0_type, const int axis0_idx, const int axis1_type, const int axis1_idx) { // compute the diff of the neighbors - vector > sel_a_diff (sec_a.back()); + std::vector > sel_a_diff (sec_a.back()); for (int ii = 0; ii < int(sec_a.size()) - 1; ++ii){ for (int jj = sec_a[ii]; jj < sec_a[ii+1]; ++jj){ if (fmt_nlist_a[jj] < 0) break; @@ -794,7 +794,7 @@ void compute_descriptor (vector & descrpt_a, } } } - vector > sel_r_diff (sec_r.back()); + std::vector > sel_r_diff (sec_r.back()); for (int ii = 0; ii < int(sec_r.size()) - 1; ++ii){ for (int jj = sec_r[ii]; jj < sec_r[ii+1]; ++jj){ if (fmt_nlist_r[jj] < 0) break; @@ -977,22 +977,22 @@ spline5_switch (TYPE & vv, // output deriv size: n_sel_a_nei x 4 x 12 // (1./rr, cos_theta, cos_phi, sin_phi) x 4 x (x, y, z) -void compute_descriptor_se_a (vector & descrpt_a, - vector & descrpt_a_deriv, - vector & rij_a, - const vector & posi, +void compute_descriptor_se_a (std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, const int & ntypes, - const vector & type, + const std::vector & type, const SimulationRegion & region, const bool & b_pbc, const int & i_idx, - const vector & fmt_nlist_a, - const vector & sec_a, + const std::vector & fmt_nlist_a, + const std::vector & sec_a, const double & rmin, const double & rmax) { // compute the diff of the neighbors - vector > sel_a_diff (sec_a.back()); + std::vector > sel_a_diff (sec_a.back()); rij_a.resize (sec_a.back() * 3); fill (rij_a.begin(), rij_a.end(), 0.0); for (int ii = 0; ii < int(sec_a.size()) - 1; ++ii){ @@ -1064,22 +1064,22 @@ void compute_descriptor_se_a (vector & descrpt_a, } -void compute_descriptor_se_r (vector & descrpt, - vector & descrpt_deriv, - vector & rij, - const vector & posi, +void compute_descriptor_se_r (std::vector & descrpt, + std::vector & descrpt_deriv, + std::vector & rij, + const std::vector & posi, const int & ntypes, - const vector & type, + const std::vector & type, const SimulationRegion & region, const bool & b_pbc, const int & i_idx, - const vector & fmt_nlist, - const vector & sec, + const std::vector & fmt_nlist, + const std::vector & sec, const double & rmin, const double & rmax) { // compute the diff of the neighbors - vector > sel_diff (sec.back()); + std::vector > sel_diff (sec.back()); rij.resize (sec.back() * 3); fill (rij.begin(), rij.end(), 0.0); for (int ii = 0; ii < int(sec.size()) - 1; ++ii){ @@ -1135,18 +1135,18 @@ void compute_descriptor_se_r (vector & descrpt, // output deriv size: n_sel_a_nei x 4 x 12 // (1./rr, cos_theta, cos_phi, sin_phi) x 4 x (x, y, z) -void compute_descriptor_se_a_extf (vector & descrpt_a, - vector & descrpt_a_deriv, - vector & rij_a, - const vector & posi, +void compute_descriptor_se_a_extf (std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, const int & ntypes, - const vector & type, + const std::vector & type, const SimulationRegion & region, const bool & b_pbc, - const vector & efield, + const std::vector & efield, const int & i_idx, - const vector & fmt_nlist_a, - const vector & sec_a, + const std::vector & fmt_nlist_a, + const std::vector & sec_a, const double & rmin, const double & rmax) { @@ -1161,10 +1161,10 @@ void compute_descriptor_se_a_extf (vector & descrpt_a, ef[ii] = ef_[ii]; } } - assert( fabs(MathUtilities::dot(ef, ef) - 1.0) < 1e-12 ), "ef should be a normalized vector"; + assert( fabs(MathUtilities::dot(ef, ef) - 1.0) < 1e-12 ), "ef should be a normalized std::vector"; // compute the diff of the neighbors - vector > sel_a_diff (sec_a.back()); + std::vector > sel_a_diff (sec_a.back()); rij_a.resize (sec_a.back() * 3); fill (rij_a.begin(), rij_a.end(), 0.0); for (int ii = 0; ii < int(sec_a.size()) - 1; ++ii){ @@ -1244,18 +1244,18 @@ void compute_descriptor_se_a_extf (vector & descrpt_a, // output deriv size: n_sel_a_nei x 4 x 12 // (1./rr, cos_theta, cos_phi, sin_phi) x 4 x (x, y, z) -void compute_descriptor_se_a_ef_para (vector & descrpt_a, - vector & descrpt_a_deriv, - vector & rij_a, - const vector & posi, +void compute_descriptor_se_a_ef_para (std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, const int & ntypes, - const vector & type, + const std::vector & type, const SimulationRegion & region, const bool & b_pbc, - const vector & efield, + const std::vector & efield, const int & i_idx, - const vector & fmt_nlist_a, - const vector & sec_a, + const std::vector & fmt_nlist_a, + const std::vector & sec_a, const double & rmin, const double & rmax) { @@ -1273,7 +1273,7 @@ void compute_descriptor_se_a_ef_para (vector & descrpt_a, assert( fabs(MathUtilities::dot(ef, ef) - 1.0) < 1e-12 ), "ef should be a normalized vector"; // compute the diff of the neighbors - vector > sel_a_diff (sec_a.back()); + std::vector > sel_a_diff (sec_a.back()); rij_a.resize (sec_a.back() * 3); fill (rij_a.begin(), rij_a.end(), 0.0); for (int ii = 0; ii < int(sec_a.size()) - 1; ++ii){ @@ -1352,18 +1352,18 @@ void compute_descriptor_se_a_ef_para (vector & descrpt_a, // output deriv size: n_sel_a_nei x 4 x 12 // (1./rr, cos_theta, cos_phi, sin_phi) x 4 x (x, y, z) -void compute_descriptor_se_a_ef_vert (vector & descrpt_a, - vector & descrpt_a_deriv, - vector & rij_a, - const vector & posi, +void compute_descriptor_se_a_ef_vert (std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, const int & ntypes, - const vector & type, + const std::vector & type, const SimulationRegion & region, const bool & b_pbc, - const vector & efield, + const std::vector & efield, const int & i_idx, - const vector & fmt_nlist_a, - const vector & sec_a, + const std::vector & fmt_nlist_a, + const std::vector & sec_a, const double & rmin, const double & rmax) { @@ -1381,7 +1381,7 @@ void compute_descriptor_se_a_ef_vert (vector & descrpt_a, assert( fabs(MathUtilities::dot(ef, ef) - 1.0) < 1e-12 ), "ef should be a normalized vector"; // compute the diff of the neighbors - vector > sel_a_diff (sec_a.back()); + std::vector > sel_a_diff (sec_a.back()); rij_a.resize (sec_a.back() * 3); fill (rij_a.begin(), rij_a.end(), 0.0); for (int ii = 0; ii < int(sec_a.size()) - 1; ++ii){ diff --git a/source/lib/include/DataModifier.h b/source/lib/include/DataModifier.h index 838b1463ec..1bb3e26488 100644 --- a/source/lib/include/DataModifier.h +++ b/source/lib/include/DataModifier.h @@ -6,44 +6,44 @@ class DataModifier { public: DataModifier(); - DataModifier(const string & model, + DataModifier(const std::string & model, const int & gpu_rank = 0, - const string & name_scope = ""); + const std::string & name_scope = ""); ~DataModifier () {}; - void init (const string & model, + void init (const std::string & model, const int & gpu_rank = 0, - const string & name_scope = ""); - void print_summary(const string &pre) const; + const std::string & name_scope = ""); + void print_summary(const std::string &pre) const; public: - void compute (vector & dfcorr_, - vector & dvcorr_, - const vector & dcoord_, - const vector & datype_, - const vector & dbox, - const vector> & pairs, - const vector & delef_, + void compute (std::vector & dfcorr_, + std::vector & dvcorr_, + const std::vector & dcoord_, + const std::vector & datype_, + const std::vector & dbox, + const std::vector> & pairs, + const std::vector & delef_, const int nghost, const LammpsNeighborList & lmp_list); VALUETYPE cutoff () const {assert(inited); return rcut;}; int numb_types () const {assert(inited); return ntypes;}; - vector sel_types () const {assert(inited); return sel_type;}; + std::vector sel_types () const {assert(inited); return sel_type;}; private: Session* session; - string name_scope, name_prefix; + std::string name_scope, name_prefix; int num_intra_nthreads, num_inter_nthreads; GraphDef graph_def; bool inited; VALUETYPE rcut; VALUETYPE cell_size; int ntypes; - string model_type; - vector sel_type; - template VT get_scalar(const string & name) const; - template void get_vector(vector & vec, const string & name) const; - void run_model (vector & dforce, - vector & dvirial, + std::string model_type; + std::vector sel_type; + template VT get_scalar(const std::string & name) const; + template void get_vector(std::vector & vec, const std::string & name) const; + void run_model (std::vector & dforce, + std::vector & dvirial, Session * session, - const std::vector> & input_tensors, + const std::vector> & input_tensors, const NNPAtomMap & nnpmap, const int nghost); }; diff --git a/source/lib/include/DeepTensor.h b/source/lib/include/DeepTensor.h index 867cff37cc..c9d265763e 100644 --- a/source/lib/include/DeepTensor.h +++ b/source/lib/include/DeepTensor.h @@ -14,21 +14,21 @@ class DeepTensor const string &name_scope = ""); void print_summary(const string &pre) const; public: - void compute (vector & value, - const vector & coord, - const vector & atype, - const vector & box, + void compute (std::vector & value, + const std::vector & coord, + const std::vector & atype, + const std::vector & box, const int nghost = 0); - void compute (vector & value, - const vector & coord, - const vector & atype, - const vector & box, + void compute (std::vector & value, + const std::vector & coord, + const std::vector & atype, + const std::vector & box, const int nghost, const LammpsNeighborList & lmp_list); VALUETYPE cutoff () const {assert(inited); return rcut;}; int numb_types () const {assert(inited); return ntypes;}; int output_dim () const {assert(inited); return odim;}; - const vector & sel_types () const {assert(inited); return sel_type;}; + const std::vector & sel_types () const {assert(inited); return sel_type;}; private: Session* session; string name_scope; @@ -40,24 +40,24 @@ class DeepTensor int ntypes; string model_type; int odim; - vector sel_type; + std::vector sel_type; template VT get_scalar(const string & name) const; - template void get_vector (vector & vec, const string & name) const; - void run_model (vector & d_tensor_, - Session * session, + template void get_vector (std::vector & vec, const string & name) const; + void run_model (std::vector & d_tensor_, + Session * session, const std::vector> & input_tensors, - const NNPAtomMap & nnpmap, - const int nghost = 0); - void compute_inner (vector & value, - const vector & coord, - const vector & atype, - const vector & box, - const int nghost = 0); - void compute_inner (vector & value, - const vector & coord, - const vector & atype, - const vector & box, - const int nghost, - const InternalNeighborList&lmp_list); + const NNPAtomMap & nnpmap, + const int nghost = 0); + void compute_inner (std::vector & value, + const std::vector & coord, + const std::vector & atype, + const std::vector & box, + const int nghost = 0); + void compute_inner (std::vector & value, + const std::vector & coord, + const std::vector & atype, + const std::vector & box, + const int nghost, + const InternalNeighborList& lmp_list); }; diff --git a/source/lib/include/Ewald.h b/source/lib/include/Ewald.h index f6bd016337..8dec44e332 100644 --- a/source/lib/include/Ewald.h +++ b/source/lib/include/Ewald.h @@ -42,7 +42,7 @@ rec_err_esti(const VALUETYPE & test_q, const SimulationRegion& region) { const VALUETYPE & beta = param.beta; - vector KK; + std::vector KK; cmpt_k(KK, region, param); const double * rec_box = region.getRecBoxTensor(); double sum = 0; @@ -80,7 +80,7 @@ rec_err_esti(const VALUETYPE & test_q, template void -cmpt_k(vector & KK, +cmpt_k(std::vector & KK, const SimulationRegion& region, const EwaldParameters& param) { @@ -107,12 +107,12 @@ cmpt_k(vector & KK, // inputs: coordinates charges region template void -EwaldReciprocal(VALUETYPE & ener, - vector & force, - vector & virial, - const vector& coord, - const vector& charge, - const SimulationRegion& region, +EwaldReciprocal(VALUETYPE & ener, + std::vector & force, + std::vector & virial, + const std::vector& coord, + const std::vector& charge, + const SimulationRegion& region, const EwaldParameters& param) { // natoms @@ -134,7 +134,7 @@ EwaldReciprocal(VALUETYPE & ener, } // K grid - vector KK(3); + std::vector KK(3); int totK = 1; cmpt_k(KK, region, param); for (int dd = 0; dd < 3; ++dd){ @@ -144,7 +144,7 @@ EwaldReciprocal(VALUETYPE & ener, for (int dd = 0; dd < 3; ++dd) stride[dd] = KK[dd]+1; // compute the sq - vector > thread_sqr(nthreads), thread_sqi(nthreads); + std::vector > thread_sqr(nthreads), thread_sqi(nthreads); for (int ii = 0; ii < nthreads; ++ii){ thread_sqr[ii].resize(totK, static_cast(0)); thread_sqi[ii].resize(totK, static_cast(0)); @@ -192,9 +192,9 @@ EwaldReciprocal(VALUETYPE & ener, rec_box[ii] = static_cast(rec_box_[ii]); } - vector thread_ener(nthreads, 0.); - vector > thread_force(nthreads); - vector > thread_virial(nthreads); + std::vector thread_ener(nthreads, 0.); + std::vector > thread_force(nthreads); + std::vector > thread_virial(nthreads); for (int ii = 0; ii < nthreads; ++ii){ thread_force[ii].resize(natoms * 3, 0.); thread_virial[ii].resize(9, 0.); diff --git a/source/lib/include/MathUtilities.h b/source/lib/include/MathUtilities.h index e61c3ea9e6..36b2435bdf 100644 --- a/source/lib/include/MathUtilities.h +++ b/source/lib/include/MathUtilities.h @@ -4,7 +4,7 @@ #include #include -using namespace std; +// using namespace std; namespace MathUtilities { @@ -66,22 +66,22 @@ using namespace std; inline TYPE msp_sqrt (const TYPE x); template - inline int searchVec (const vector & vec, + inline int searchVec (const std::vector & vec, const int sta_, const int end_, const VALUETYPE & val); template - inline int lowerBound (const vector & vec, + inline int lowerBound (const std::vector & vec, const int sta_, const int end_, const VALUETYPE & val); template - inline int upperBound (const vector & vec, + inline int upperBound (const std::vector & vec, const int sta_, const int end_, const VALUETYPE & val); template - inline int upperBound (const vector & vec, + inline int upperBound (const std::vector & vec, const int sta_, const int end_, const VALUETYPE & val, diff --git a/source/lib/include/MathUtilities_Impl.h b/source/lib/include/MathUtilities_Impl.h index ac5839f30d..378498c625 100644 --- a/source/lib/include/MathUtilities_Impl.h +++ b/source/lib/include/MathUtilities_Impl.h @@ -213,7 +213,7 @@ det4d (const TYPE * mat) template inline int MathUtilities:: -searchVec (const vector & vec, +searchVec (const std::vector & vec, const int sta_, const int end_, const VALUETYPE & val) @@ -232,7 +232,7 @@ searchVec (const vector & vec, template inline int MathUtilities:: -lowerBound (const vector & vec, +lowerBound (const std::vector & vec, const int sta_, const int end_, const VALUETYPE & val) @@ -256,7 +256,7 @@ lowerBound (const vector & vec, template inline int MathUtilities:: -upperBound (const vector & vec, +upperBound (const std::vector & vec, const int sta_, const int end_, const VALUETYPE & val) @@ -280,7 +280,7 @@ upperBound (const vector & vec, template inline int MathUtilities:: -upperBound (const vector & vec, +upperBound (const std::vector & vec, const int sta_, const int end_, const VALUETYPE & val, @@ -334,7 +334,7 @@ upperBound (const vector & vec, // template // int -// searchVec (const vector & vec, +// searchVec (const std::vector & vec, // const int sta_, // const int end_, // const VALUETYPE & val, diff --git a/source/lib/include/NNPAtomMap.h b/source/lib/include/NNPAtomMap.h index 559dc69dd7..6d537fd99b 100644 --- a/source/lib/include/NNPAtomMap.h +++ b/source/lib/include/NNPAtomMap.h @@ -2,26 +2,26 @@ #include -using namespace std; +// using namespace std; template class NNPAtomMap { public: NNPAtomMap(); - NNPAtomMap(const vector::const_iterator in_begin, - const vector::const_iterator in_end); - void forward (typename vector::iterator out, - const typename vector::const_iterator in, + NNPAtomMap(const std::vector::const_iterator in_begin, + const std::vector::const_iterator in_end); + void forward (typename std::vector::iterator out, + const typename std::vector::const_iterator in, const int stride = 1) const ; - void backward (typename vector::iterator out, - const typename vector::const_iterator in, + void backward (typename std::vector::iterator out, + const typename std::vector::const_iterator in, const int stride = 1) const ; - const vector & get_type () const {return atype;} - const vector & get_fwd_map () const {return fwd_idx_map;} - const vector & get_bkw_map () const {return idx_map;} + const std::vector & get_type () const {return atype;} + const std::vector & get_fwd_map () const {return fwd_idx_map;} + const std::vector & get_bkw_map () const {return idx_map;} private: - vector idx_map; - vector fwd_idx_map; - vector atype; + std::vector idx_map; + std::vector fwd_idx_map; + std::vector atype; }; diff --git a/source/lib/include/NNPInter.h b/source/lib/include/NNPInter.h index 6c37770758..84f305cb8b 100644 --- a/source/lib/include/NNPInter.h +++ b/source/lib/include/NNPInter.h @@ -13,48 +13,48 @@ class NNPInter void print_summary(const string &pre) const; public: void compute (ENERGYTYPE & ener, - vector & force, - vector & virial, - const vector & coord, - const vector & atype, - const vector & box, + std::vector & force, + std::vector & virial, + const std::vector & coord, + const std::vector & atype, + const std::vector & box, const int nghost = 0, - const vector & fparam = vector(), - const vector & aparam = vector()); + const std::vector& fparam = std::vector(), + const std::vector& aparam = std::vector()); void compute (ENERGYTYPE & ener, - vector & force, - vector & virial, - const vector & coord, - const vector & atype, - const vector & box, + std::vector & force, + std::vector & virial, + const std::vector & coord, + const std::vector & atype, + const std::vector & box, const int nghost, const LammpsNeighborList & lmp_list, - const int & ago, - const vector & fparam = vector(), - const vector & aparam = vector()); + const int& ago, + const std::vector& fparam = std::vector(), + const std::vector& aparam = std::vector()); void compute (ENERGYTYPE & ener, - vector & force, - vector & virial, - vector & atom_energy, - vector & atom_virial, - const vector & coord, - const vector & atype, - const vector & box, - const vector & fparam = vector(), - const vector & aparam = vector()); + std::vector & force, + std::vector & virial, + std::vector & atom_energy, + std::vector & atom_virial, + const std::vector & coord, + const std::vector & atype, + const std::vector & box, + const std::vector& fparam = std::vector(), + const std::vector& aparam = std::vector()); void compute (ENERGYTYPE & ener, - vector & force, - vector & virial, - vector & atom_energy, - vector & atom_virial, - const vector & coord, - const vector & atype, - const vector & box, + std::vector & force, + std::vector & virial, + std::vector & atom_energy, + std::vector & atom_virial, + const std::vector & coord, + const std::vector & atype, + const std::vector & box, const int nghost, const LammpsNeighborList & lmp_list, - const int & ago, - const vector & fparam = vector(), - const vector & aparam = vector()); + const int& ago, + const std::vector& fparam = std::vector(), + const std::vector& aparam = std::vector()); VALUETYPE cutoff () const {assert(inited); return rcut;}; int numb_types () const {assert(inited); return ntypes;}; int dim_fparam () const {assert(inited); return dfparam;}; @@ -74,18 +74,18 @@ class NNPInter int dfparam; int daparam; void validate_fparam_aparam(const int & nloc, - const vector &fparam, - const vector &aparam)const ; + const std::vector &fparam, + const std::vector &aparam)const ; void compute_inner (ENERGYTYPE & ener, - vector & force, - vector & virial, - const vector & coord, - const vector & atype, - const vector & box, - const int nghost, - const int & ago, - const vector & fparam = vector(), - const vector & aparam = vector()); + std::vector & force, + std::vector & virial, + const std::vector & coord, + const std::vector & atype, + const std::vector & box, + const int nghost, + const int & ago, + const std::vector& fparam = std::vector(), + const std::vector& aparam = std::vector()); // copy neighbor list info from host bool init_nbor; @@ -97,7 +97,7 @@ class NNPInter int ilist_size, jrange_size, jlist_size; // function used for neighbor list copy - vector get_sel_a() const; + std::vector get_sel_a() const; }; class NNPInterModelDevi @@ -105,68 +105,68 @@ class NNPInterModelDevi public: NNPInterModelDevi () ; ~NNPInterModelDevi() ; - NNPInterModelDevi (const vector & models, const int & gpu_rank = 0); - void init (const vector & models, const int & gpu_rank = 0); + NNPInterModelDevi (const std::vector & models, const int & gpu_rank = 0); + void init (const std::vector & models, const int & gpu_rank = 0); public: void compute (ENERGYTYPE & ener, - vector & force, - vector & virial, - vector & model_devi, - const vector & coord, - const vector & atype, - const vector & box, - const vector & fparam = vector(), - const vector & aparam = vector()); - void compute (vector & all_ener, - vector > & all_force, - vector > & all_virial, - const vector & coord, - const vector & atype, - const vector & box, + std::vector & force, + std::vector & virial, + std::vector & model_devi, + const std::vector & coord, + const std::vector & atype, + const std::vector & box, + const std::vector & fparam = std::vector(), + const std::vector & aparam = std::vector()); + void compute (std::vector & all_ener, + std::vector > & all_force, + std::vector > & all_virial, + const std::vector & coord, + const std::vector & atype, + const std::vector & box, const int nghost, const LammpsNeighborList & lmp_list, const int & ago, - const vector & fparam = vector(), - const vector & aparam = vector()); - void compute (vector & all_ener, - vector > & all_force, - vector > & all_virial, - vector > & all_atom_energy, - vector > & all_atom_virial, - const vector & coord, - const vector & atype, - const vector & box, + const std::vector & fparam = std::vector(), + const std::vector & aparam = std::vector()); + void compute (std::vector & all_ener, + std::vector > & all_force, + std::vector > & all_virial, + std::vector > & all_atom_energy, + std::vector > & all_atom_virial, + const std::vector & coord, + const std::vector & atype, + const std::vector & box, const int nghost, const LammpsNeighborList & lmp_list, const int & ago, - const vector & fparam = vector(), - const vector & aparam = vector()); + const std::vector & fparam = std::vector(), + const std::vector & aparam = std::vector()); VALUETYPE cutoff () const {assert(inited); return rcut;}; int numb_types () const {assert(inited); return ntypes;}; int dim_fparam () const {assert(inited); return dfparam;}; int dim_aparam () const {assert(inited); return daparam;}; #ifndef HIGH_PREC void compute_avg (ENERGYTYPE & dener, - const vector & all_energy); + const std::vector & all_energy); #endif void compute_avg (VALUETYPE & dener, - const vector & all_energy); - void compute_avg (vector & avg, - const vector > & xx); - void compute_std_e (vector & std, - const vector & avg, - const vector >& xx); - void compute_std_f (vector & std, - const vector & avg, - const vector >& xx); - void compute_relative_std_f (vector & std, - const vector & avg, + const std::vector & all_energy); + void compute_avg (std::vector & avg, + const std::vector > & xx); + void compute_std_e (std::vector & std, + const std::vector & avg, + const std::vector >& xx); + void compute_std_f (std::vector & std, + const std::vector & avg, + const std::vector >& xx); + void compute_relative_std_f (std::vector & std, + const std::vector & avg, const VALUETYPE eps); private: unsigned numb_models; - vector sessions; + std::vector sessions; int num_intra_nthreads, num_inter_nthreads; - vector graph_defs; + std::vector graph_defs; bool inited; template VT get_scalar(const string name) const; // VALUETYPE get_rcut () const; @@ -177,20 +177,20 @@ class NNPInterModelDevi int dfparam; int daparam; void validate_fparam_aparam(const int & nloc, - const vector &fparam, - const vector &aparam)const ; + const std::vector &fparam, + const std::vector &aparam)const ; // copy neighbor list info from host bool init_nbor; compute_t *array_double; - vector > sec; + std::vector > sec; InternalNeighborList nlist; NNPAtomMap nnpmap; int *ilist, *jrange, *jlist; int ilist_size, jrange_size, jlist_size; // function used for nborlist copy - vector > get_sel() const; + std::vector > get_sel() const; void cum_sum(const std::vector > n_sel); }; diff --git a/source/lib/include/NeighborList.h b/source/lib/include/NeighborList.h index 8e9f51b8e7..c97fcc3099 100644 --- a/source/lib/include/NeighborList.h +++ b/source/lib/include/NeighborList.h @@ -9,60 +9,60 @@ // build nlist by an extended grid void -build_nlist (vector > & nlist0, - vector > & nlist1, - const vector & coord, - const int & nloc, - const double & rc0, - const double & rc1, - const vector & nat_stt_, - const vector & nat_end_, - const vector & ext_stt_, - const vector & ext_end_, - const SimulationRegion & region, - const vector & global_grid); +build_nlist (std::vector > & nlist0, + std::vector > & nlist1, + const std::vector & coord, + const int & nloc, + const double & rc0, + const double & rc1, + const std::vector & nat_stt_, + const std::vector & nat_end_, + const std::vector & ext_stt_, + const std::vector & ext_end_, + const SimulationRegion & region, + const std::vector & global_grid); // build nlist by a grid for a periodic region void -build_nlist (vector > & nlist0, - vector > & nlist1, - const vector & coord, - const double & rc0, - const double & rc1, - const vector & grid, - const SimulationRegion & region); +build_nlist (std::vector > & nlist0, + std::vector > & nlist1, + const std::vector & coord, + const double & rc0, + const double & rc1, + const std::vector & grid, + const SimulationRegion & region); // build nlist by a grid for a periodic region, atoms selected by sel0 and sel1 void -build_nlist (vector > & nlist0, - vector > & nlist1, - const vector & coord, - const vector & sel0, - const vector & sel1, - const double & rc0, - const double & rc1, - const vector & grid, - const SimulationRegion & region); +build_nlist (std::vector > & nlist0, + std::vector > & nlist1, + const std::vector & coord, + const std::vector & sel0, + const std::vector & sel1, + const double & rc0, + const double & rc1, + const std::vector & grid, + const SimulationRegion & region); // brute force (all-to-all distance computation) neighbor list building // if region is NULL, open boundary is assumed, // otherwise, periodic boundary condition is defined by region void -build_nlist (vector > & nlist0, - vector > & nlist1, - const vector & coord, - const double & rc0_, - const double & rc1_, +build_nlist (std::vector > & nlist0, + std::vector > & nlist1, + const std::vector & coord, + const double & rc0_, + const double & rc1_, const SimulationRegion * region = NULL); // copy periodic images for the system void -copy_coord (vector & out_c, - vector & out_t, - vector & mapping, - vector & ncell, - vector & ngcell, - const vector & in_c, - const vector & in_t, - const double & rc, - const SimulationRegion & region); +copy_coord (std::vector & out_c, + std::vector & out_t, + std::vector & mapping, + std::vector & ncell, + std::vector & ngcell, + const std::vector & in_c, + const std::vector & in_t, + const double & rc, + const SimulationRegion & region); diff --git a/source/lib/include/RandomGenerator.h b/source/lib/include/RandomGenerator.h new file mode 100644 index 0000000000..dea08c4683 --- /dev/null +++ b/source/lib/include/RandomGenerator.h @@ -0,0 +1,23 @@ +#ifndef __wanghan_ToolBox_h__ +#define __wanghan_ToolBox_h__ +#include + +typedef double value_type; + +namespace RandomGenerator_MT19937{ + void init_by_array(unsigned long init_key[], int key_length); + void init_genrand(unsigned long s); + unsigned long genrand_int32(void); + long genrand_int31(void); + double genrand_real1(void); // in [0,1] + double genrand_real2(void); // in [0,1) + double genrand_real3(void); // in (0,1) + double genrand_res53(void); + double gaussian (); // Box Muller + void sphere (double & x, double & y, double & z); +} + + + + +#endif diff --git a/source/lib/include/SimulationRegion.h b/source/lib/include/SimulationRegion.h index 06874ec408..eb625b64e1 100644 --- a/source/lib/include/SimulationRegion.h +++ b/source/lib/include/SimulationRegion.h @@ -14,7 +14,7 @@ void reinitBox (const double * boxv); void affineTransform (const double * affine_map); void reinitOrigin (const double * orig); - void reinitOrigin (const vector & orig); + void reinitOrigin (const std::vector & orig); void backup (); void recover (); public: @@ -94,7 +94,7 @@ double rec_boxt [SPACENDIM*SPACENDIM]; double origin [SPACENDIM]; bool is_periodic [SPACENDIM]; - string class_name; + std::string class_name; bool enable_restart; protected: void computeShiftVec (); @@ -133,7 +133,7 @@ void apply_periodic (int dim, double * dd) const; void apply_periodic (int dim, double * dd, int & shift) const; private: - fstream fp; + std::fstream fp; }; #ifdef MOASP_INLINE_IMPLEMENTATION diff --git a/source/lib/include/SimulationRegion_Impl.h b/source/lib/include/SimulationRegion_Impl.h index 8fa318c561..9f3ecdd241 100644 --- a/source/lib/include/SimulationRegion_Impl.h +++ b/source/lib/include/SimulationRegion_Impl.h @@ -7,7 +7,7 @@ #include #include -using namespace std; +// using namespace std; template SimulationRegion:: @@ -20,9 +20,9 @@ SimulationRegion:: SimulationRegion () { is_periodic[0] = is_periodic[1] = is_periodic[2] = true; - fill (boxt, boxt + SPACENDIM*SPACENDIM, 0); - fill (boxt_bk, boxt_bk + SPACENDIM*SPACENDIM, 0); - fill (origin, origin + SPACENDIM, 0); + std::fill (boxt, boxt + SPACENDIM*SPACENDIM, 0); + std::fill (boxt_bk, boxt_bk + SPACENDIM*SPACENDIM, 0); + std::fill (origin, origin + SPACENDIM, 0); } template @@ -105,7 +105,7 @@ reinitOrigin (const double * orig) template inline void SimulationRegion:: -reinitOrigin (const vector& orig) +reinitOrigin (const std::vector& orig) { for (int ii = 0; ii < SPACENDIM ; ++ii){ origin[ii] = orig[ii]; diff --git a/source/lib/include/common.h b/source/lib/include/common.h index 59167816fe..e07231cdd3 100644 --- a/source/lib/include/common.h +++ b/source/lib/include/common.h @@ -9,7 +9,7 @@ #include using namespace tensorflow; -using namespace std; +// using namespace std; #include #include @@ -55,9 +55,9 @@ struct InternalNeighborList int * pilist; int * pjrange; int * pjlist; - vector ilist; - vector jrange; - vector jlist; + std::vector ilist; + std::vector jrange; + std::vector jlist; void clear () {ilist.clear(); jrange.clear(); jlist.clear();} void make_ptrs () { pilist = &ilist[0]; pjrange = &jrange[0]; pjlist = &jlist[0]; @@ -70,7 +70,7 @@ convert_nlist_lmp_internal (InternalNeighborList & list, void shuffle_nlist (InternalNeighborList & list, - const vector & fwd_map); + const std::vector & fwd_map); void shuffle_nlist (InternalNeighborList & list, @@ -78,32 +78,32 @@ shuffle_nlist (InternalNeighborList & list, void shuffle_nlist_exclude_empty (InternalNeighborList & list, - const vector & fwd_map); + const std::vector & fwd_map); void -select_by_type(vector & fwd_map, - vector & bkw_map, +select_by_type(std::vector & fwd_map, + std::vector & bkw_map, int & nghost_real, - const vector & dcoord_, - const vector & datype_, + const std::vector & dcoord_, + const std::vector & datype_, const int & nghost, - const vector & sel_type_); + const std::vector & sel_type_); void -select_real_atoms(vector & fwd_map, - vector & bkw_map, +select_real_atoms(std::vector & fwd_map, + std::vector & bkw_map, int & nghost_real, - const vector & dcoord_, - const vector & datype_, + const std::vector & dcoord_, + const std::vector & datype_, const int & nghost, const int & ntypes); template void -select_map(vector & out, - const vector & in, - const vector & fwd_map, +select_map(std::vector & out, + const std::vector & in, + const std::vector & fwd_map, const int & stride); void @@ -121,30 +121,30 @@ session_get_scalar(Session* session, const string name, const string scope = "") template void -session_get_vector(vector & o_vec, Session* session, const string name_, const string scope = ""); +session_get_vector(std::vector & o_vec, Session* session, const string name_, const string scope = ""); int session_input_tensors (std::vector> & input_tensors, - const vector & dcoord_, + const std::vector & dcoord_, const int & ntypes, - const vector & datype_, - const vector & dbox, + const std::vector & datype_, + const std::vector & dbox, const VALUETYPE & cell_size, - const vector & fparam_, - const vector & aparam_, + const std::vector & fparam_, + const std::vector & aparam_, const NNPAtomMap& nnpmap, const int nghost = 0, const string scope = ""); int session_input_tensors (std::vector> & input_tensors, - const vector & dcoord_, + const std::vector & dcoord_, const int & ntypes, - const vector & datype_, - const vector & dbox, + const std::vector & datype_, + const std::vector & dbox, InternalNeighborList & dlist, - const vector & fparam_, - const vector & aparam_, + const std::vector & fparam_, + const std::vector & aparam_, const NNPAtomMap& nnpmap, const int nghost, const int ago, @@ -152,28 +152,28 @@ session_input_tensors (std::vector> & input_tensors, int session_input_tensors (std::vector> & input_tensors, - const vector & dcoord_, + const std::vector & dcoord_, const int & ntypes, - const vector & datype_, - const vector & dbox, + const std::vector & datype_, + const std::vector & dbox, InternalNeighborList & dlist, - const vector & fparam_, - const vector & aparam_, + const std::vector & fparam_, + const std::vector & aparam_, const NNPAtomMap& nnpmap, const int nghost, const string scope = ""); int -session_input_tensors (vector>& input_tensors, - const vector & dcoord_, +session_input_tensors (std::vector>& input_tensors, + const std::vector & dcoord_, const int & ntypes, - const vector & atype_, - const vector & dbox, + const std::vector & atype_, + const std::vector & dbox, const int * ilist, const int * jrange, const int * jlist, - const vector & fparam_, - const vector & aparam_, + const std::vector & fparam_, + const std::vector & aparam_, const NNPAtomMap & nnpmap, const int & nghost); @@ -198,7 +198,7 @@ session_get_scalar(Session* session, const string name_, const string scope) template void -session_get_vector(vector & o_vec, Session* session, const string name_, const string scope) +session_get_vector(std::vector & o_vec, Session* session, const string name_, const string scope) { string name = name_; if (scope != "") { @@ -222,9 +222,9 @@ session_get_vector(vector & o_vec, Session* session, const string name_, con template void -select_map(vector & out, - const vector & in, - const vector & idx_map, +select_map(std::vector & out, + const std::vector & in, + const std::vector & idx_map, const int & stride) { #ifdef DEBUG diff --git a/source/lib/include/version.h.in b/source/lib/include/version.h.in index de8052033e..a588d87a33 100644 --- a/source/lib/include/version.h.in +++ b/source/lib/include/version.h.in @@ -1,7 +1,7 @@ #pragma once #include -using namespace std; +// using namespace std; #ifdef HIGH_PREC const string global_float_prec="double"; diff --git a/source/lib/src/DataModifier.cc b/source/lib/src/DataModifier.cc index 03fcd43a07..ba026625c2 100644 --- a/source/lib/src/DataModifier.cc +++ b/source/lib/src/DataModifier.cc @@ -54,19 +54,19 @@ get_scalar (const string & name) const template void DataModifier:: -get_vector (vector & vec, const string & name) const +get_vector (std::vector & vec, const string & name) const { session_get_vector(vec, session, name, name_scope); } void DataModifier:: -run_model (vector & dforce, - vector & dvirial, - Session * session, +run_model (std::vector & dforce, + std::vector & dvirial, + Session * session, const std::vector> & input_tensors, - const NNPAtomMap &nnpmap, - const int nghost) + const NNPAtomMap & nnpmap, + const int nghost) { unsigned nloc = nnpmap.get_type().size(); unsigned nall = nloc + nghost; @@ -114,21 +114,21 @@ run_model (vector & dforce, void DataModifier:: -compute (vector & dfcorr_, - vector & dvcorr_, - const vector & dcoord_, - const vector & datype_, - const vector & dbox, - const vector> & pairs, - const vector & delef_, - const int nghost, - const LammpsNeighborList & lmp_list) +compute (std::vector & dfcorr_, + std::vector & dvcorr_, + const std::vector & dcoord_, + const std::vector & datype_, + const std::vector & dbox, + const std::vector>& pairs, + const std::vector & delef_, + const int nghost, + const LammpsNeighborList & lmp_list) { // firstly do selection int nall = datype_.size(); int nloc = nall - nghost; int nghost_real; - vector real_fwd_map, real_bkw_map; + std::vector real_fwd_map, real_bkw_map; select_real_atoms(real_fwd_map, real_bkw_map, nghost_real, dcoord_, datype_, nghost, ntypes); int nall_real = real_bkw_map.size(); int nloc_real = nall_real - nghost_real; @@ -140,9 +140,9 @@ compute (vector & dfcorr_, return; } // resize to nall_real - vector dcoord_real; - vector delef_real; - vector datype_real; + std::vector dcoord_real; + std::vector delef_real; + std::vector datype_real; dcoord_real.resize(nall_real * 3); delef_real.resize(nall_real * 3); datype_real.resize(nall_real); @@ -157,23 +157,23 @@ compute (vector & dfcorr_, // sort atoms NNPAtomMap nnpmap (datype_real.begin(), datype_real.begin() + nloc_real); assert (nloc_real == nnpmap.get_type().size()); - const vector & sort_fwd_map(nnpmap.get_fwd_map()); - const vector & sort_bkw_map(nnpmap.get_bkw_map()); + const std::vector & sort_fwd_map(nnpmap.get_fwd_map()); + const std::vector & sort_bkw_map(nnpmap.get_bkw_map()); // shuffle nlist InternalNeighborList nlist(nlist_); shuffle_nlist (nlist, nnpmap); // make input tensors std::vector> input_tensors; - int ret = session_input_tensors (input_tensors, dcoord_real, ntypes, datype_real, dbox, nlist, vector(), vector(), nnpmap, nghost_real, name_scope); + int ret = session_input_tensors (input_tensors, dcoord_real, ntypes, datype_real, dbox, nlist, std::vector(), std::vector(), nnpmap, nghost_real, name_scope); assert (nloc_real == ret); // make bond idx map - vector bd_idx(nall, -1); + std::vector bd_idx(nall, -1); for (int ii = 0; ii < pairs.size(); ++ii){ bd_idx[pairs[ii].first] = pairs[ii].second; } // make extf by bond idx map - vector dtype_sort_loc = nnpmap.get_type(); - vector dextf; + std::vector dtype_sort_loc = nnpmap.get_type(); + std::vector dextf; for(int ii = 0; ii < dtype_sort_loc.size(); ++ii){ if (binary_search(sel_type.begin(), sel_type.end(), dtype_sort_loc[ii])){ // selected atom @@ -206,15 +206,15 @@ compute (vector & dfcorr_, // append extf to input tensor input_tensors.push_back({"t_ef", extf_tensor}); // run model - vector dfcorr, dvcorr; + std::vector dfcorr, dvcorr; run_model (dfcorr, dvcorr, session, input_tensors, nnpmap, nghost_real); assert(dfcorr.size() == nall_real * 3); // back map force - vector dfcorr_1 = dfcorr; + std::vector dfcorr_1 = dfcorr; nnpmap.backward (dfcorr_1.begin(), dfcorr.begin(), 3); assert(dfcorr_1.size() == nall_real * 3); // resize to all and clear - vector dfcorr_2(nall*3); + std::vector dfcorr_2(nall*3); fill(dfcorr_2.begin(), dfcorr_2.end(), 0.0); // back map to original position for (int ii = 0; ii < nall_real; ++ii){ diff --git a/source/lib/src/DeepTensor.cc b/source/lib/src/DeepTensor.cc index 9b9715fd0d..9d78bb3f6a 100644 --- a/source/lib/src/DeepTensor.cc +++ b/source/lib/src/DeepTensor.cc @@ -50,14 +50,14 @@ get_scalar (const string & name) const template void DeepTensor:: -get_vector (vector & vec, const string & name) const +get_vector (std::vector & vec, const string & name) const { session_get_vector(vec, session, name, name_scope); } void DeepTensor:: -run_model (vector & d_tensor_, +run_model (std::vector & d_tensor_, Session * session, const std::vector> & input_tensors, const NNPAtomMap &nnpmap, @@ -83,7 +83,7 @@ run_model (vector & d_tensor_, auto ot = output_t.flat (); - vector d_tensor (o_size); + std::vector d_tensor (o_size); for (unsigned ii = 0; ii < o_size; ++ii){ d_tensor[ii] = ot(ii); } @@ -93,14 +93,14 @@ run_model (vector & d_tensor_, void DeepTensor:: -compute (vector & dtensor_, - const vector & dcoord_, - const vector & datype_, - const vector & dbox, +compute (std::vector & dtensor_, + const std::vector & dcoord_, + const std::vector & datype_, + const std::vector & dbox, const int nghost) { - vector dcoord; - vector datype, fwd_map, bkw_map; + std::vector dcoord; + std::vector datype, fwd_map, bkw_map; int nghost_real; select_real_atoms(fwd_map, bkw_map, nghost_real, dcoord_, datype_, nghost, ntypes); // resize to nall_real @@ -114,15 +114,15 @@ compute (vector & dtensor_, void DeepTensor:: -compute (vector & dtensor_, - const vector & dcoord_, - const vector & datype_, - const vector & dbox, +compute (std::vector & dtensor_, + const std::vector & dcoord_, + const std::vector & datype_, + const std::vector & dbox, const int nghost, const LammpsNeighborList & lmp_list) { - vector dcoord; - vector datype, fwd_map, bkw_map; + std::vector dcoord; + std::vector datype, fwd_map, bkw_map; int nghost_real; select_real_atoms(fwd_map, bkw_map, nghost_real, dcoord_, datype_, nghost, ntypes); // resize to nall_real @@ -141,10 +141,10 @@ compute (vector & dtensor_, void DeepTensor:: -compute_inner (vector & dtensor_, - const vector & dcoord_, - const vector & datype_, - const vector & dbox, +compute_inner (std::vector & dtensor_, + const std::vector & dcoord_, + const std::vector & datype_, + const std::vector & dbox, const int nghost) { int nall = dcoord_.size() / 3; @@ -153,7 +153,7 @@ compute_inner (vector & dtensor_, assert (nloc == nnpmap.get_type().size()); std::vector> input_tensors; - int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, vector(), vector(), nnpmap, nghost, name_scope); + int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, std::vector(), std::vector(), nnpmap, nghost, name_scope); assert (ret == nloc); run_model (dtensor_, session, input_tensors, nnpmap, nghost); @@ -161,10 +161,10 @@ compute_inner (vector & dtensor_, void DeepTensor:: -compute_inner (vector & dtensor_, - const vector & dcoord_, - const vector & datype_, - const vector & dbox, +compute_inner (std::vector & dtensor_, + const std::vector & dcoord_, + const std::vector & datype_, + const std::vector & dbox, const int nghost, const InternalNeighborList & nlist_) { @@ -177,7 +177,7 @@ compute_inner (vector & dtensor_, shuffle_nlist (nlist, nnpmap); std::vector> input_tensors; - int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, vector(), vector(), nnpmap, nghost, name_scope); + int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, std::vector(), std::vector(), nnpmap, nghost, name_scope); assert (nloc == ret); run_model (dtensor_, session, input_tensors, nnpmap, nghost); diff --git a/source/lib/src/NNPAtomMap.cc b/source/lib/src/NNPAtomMap.cc index dd4fd73a00..5529bbc0ac 100644 --- a/source/lib/src/NNPAtomMap.cc +++ b/source/lib/src/NNPAtomMap.cc @@ -9,15 +9,15 @@ NNPAtomMap() {} template NNPAtomMap:: -NNPAtomMap(const vector::const_iterator in_begin, - const vector::const_iterator in_end) +NNPAtomMap(const std::vector::const_iterator in_begin, + const std::vector::const_iterator in_end) { int natoms = in_end - in_begin; atype.resize (natoms); - vector > sorting (natoms); - vector::const_iterator iter = in_begin; + std::vector > sorting (natoms); + std::vector::const_iterator iter = in_begin; for (unsigned ii = 0; ii < sorting.size(); ++ii){ - sorting[ii] = pair (*(iter++), ii); + sorting[ii] = std::pair (*(iter++), ii); } sort (sorting.begin(), sorting.end()); idx_map.resize(natoms); @@ -32,8 +32,8 @@ NNPAtomMap(const vector::const_iterator in_begin, template void NNPAtomMap:: -forward (typename vector::iterator out, - const typename vector::const_iterator in, +forward (typename std::vector::iterator out, + const typename std::vector::const_iterator in, const int stride) const { int natoms = idx_map.size(); @@ -49,8 +49,8 @@ forward (typename vector::iterator out, template void NNPAtomMap:: -backward (typename vector::iterator out, - const typename vector::const_iterator in, +backward (typename std::vector::iterator out, + const typename std::vector::const_iterator in, const int stride) const { int natoms = idx_map.size(); diff --git a/source/lib/src/NNPInter.cc b/source/lib/src/NNPInter.cc index 8bedd88c9c..7911f3d844 100644 --- a/source/lib/src/NNPInter.cc +++ b/source/lib/src/NNPInter.cc @@ -33,11 +33,11 @@ std::vector cum_sum (const std::vector & n_sel) { static void run_model (ENERGYTYPE & dener, - vector & dforce_, - vector & dvirial, + std::vector & dforce_, + std::vector & dvirial, Session * session, const std::vector> & input_tensors, - const NNPAtomMap & nnpmap, + const NNPAtomMap& nnpmap, const int nghost = 0) { unsigned nloc = nnpmap.get_type().size(); @@ -69,7 +69,7 @@ run_model (ENERGYTYPE & dener, auto oav = output_av.flat (); dener = oe(0); - vector dforce (3 * nall); + std::vector dforce (3 * nall); dvirial.resize (9); for (unsigned ii = 0; ii < nall * 3; ++ii){ dforce[ii] = of(ii); @@ -89,15 +89,15 @@ run_model (ENERGYTYPE & dener, nnpmap.backward (dforce_.begin(), dforce.begin(), 3); } -static void run_model (ENERGYTYPE & dener, - vector & dforce_, - vector & dvirial, - vector & datom_energy_, - vector & datom_virial_, - Session * session, - const std::vector> & input_tensors, - const NNPAtomMap & nnpmap, - const int & nghost = 0) +static void run_model (ENERGYTYPE & dener, + std::vector& dforce_, + std::vector& dvirial, + std::vector& datom_energy_, + std::vector& datom_virial_, + Session* session, + const std::vector> & input_tensors, + const NNPAtomMap & nnpmap, + const int& nghost = 0) { unsigned nloc = nnpmap.get_type().size(); unsigned nall = nloc + nghost; @@ -136,9 +136,9 @@ static void run_model (ENERGYTYPE & dener, auto oav = output_av.flat (); dener = oe(0); - vector dforce (3 * nall); - vector datom_energy (nall, 0); - vector datom_virial (9 * nall); + std::vector dforce (3 * nall); + std::vector datom_energy (nall, 0); + std::vector datom_virial (9 * nall); dvirial.resize (9); for (int ii = 0; ii < nall * 3; ++ii) { dforce[ii] = of(ii); @@ -229,16 +229,16 @@ void NNPInter:: print_summary(const string &pre) const { - cout << pre << "installed to: " + global_install_prefix << endl; - cout << pre << "source: " + global_git_summ << endl; - cout << pre << "source brach: " + global_git_branch << endl; - cout << pre << "source commit: " + global_git_hash << endl; - cout << pre << "source commit at: " + global_git_date << endl; - cout << pre << "build float prec: " + global_float_prec << endl; - cout << pre << "build with tf inc: " + global_tf_include_dir << endl; - cout << pre << "build with tf lib: " + global_tf_lib << endl; - cout << pre << "set tf intra_op_parallelism_threads: " << num_intra_nthreads << endl; - cout << pre << "set tf inter_op_parallelism_threads: " << num_inter_nthreads << endl; + std::cout << pre << "installed to: " + global_install_prefix << std::endl; + std::cout << pre << "source: " + global_git_summ << std::endl; + std::cout << pre << "source brach: " + global_git_branch << std::endl; + std::cout << pre << "source commit: " + global_git_hash << std::endl; + std::cout << pre << "source commit at: " + global_git_date << std::endl; + std::cout << pre << "build float prec: " + global_float_prec << std::endl; + std::cout << pre << "build with tf inc: " + global_tf_include_dir << std::endl; + std::cout << pre << "build with tf lib: " + global_tf_lib << std::endl; + std::cout << pre << "set tf intra_op_parallelism_threads: " << num_intra_nthreads << std::endl; + std::cout << pre << "set tf inter_op_parallelism_threads: " << num_inter_nthreads << std::endl; } template @@ -297,8 +297,8 @@ std::vector NNPInter::get_sel_a () const { void NNPInter:: validate_fparam_aparam(const int & nloc, - const vector &fparam, - const vector &aparam)const + const std::vector &fparam, + const std::vector &aparam)const { if (fparam.size() != dfparam) { throw std::runtime_error("the dim of frame parameter provided is not consistent with what the model uses"); @@ -311,14 +311,14 @@ validate_fparam_aparam(const int & nloc, void NNPInter:: compute (ENERGYTYPE & dener, - vector & dforce_, - vector & dvirial, - const vector & dcoord_, - const vector & datype_, - const vector & dbox, + std::vector & dforce_, + std::vector & dvirial, + const std::vector & dcoord_, + const std::vector & datype_, + const std::vector & dbox, const int nghost, - const vector & fparam, - const vector & aparam) + const std::vector & fparam, + const std::vector & aparam) { int nall = dcoord_.size() / 3; int nloc = nall - nghost; @@ -336,19 +336,19 @@ compute (ENERGYTYPE & dener, void NNPInter:: compute (ENERGYTYPE & dener, - vector & dforce_, - vector & dvirial, - const vector & dcoord_, - const vector & datype_, - const vector & dbox, + std::vector & dforce_, + std::vector & dvirial, + const std::vector & dcoord_, + const std::vector & datype_, + const std::vector & dbox, const int nghost, const LammpsNeighborList & lmp_list, - const int & ago, - const vector & fparam, - const vector & aparam_) + const int& ago, + const std::vector & fparam, + const std::vector & aparam_) { - vector dcoord, dforce, aparam; - vector datype, fwd_map, bkw_map; + std::vector dcoord, dforce, aparam; + std::vector datype, fwd_map, bkw_map; int nghost_real; select_real_atoms(fwd_map, bkw_map, nghost_real, dcoord_, datype_, nghost, ntypes); // resize to nall_real @@ -375,15 +375,15 @@ compute (ENERGYTYPE & dener, void NNPInter:: compute_inner (ENERGYTYPE & dener, - vector & dforce_, - vector & dvirial, - const vector & dcoord_, - const vector & datype_, - const vector & dbox, + std::vector & dforce_, + std::vector & dvirial, + const std::vector & dcoord_, + const std::vector & datype_, + const std::vector & dbox, const int nghost, - const int & ago, - const vector & fparam, - const vector & aparam) + const int& ago, + const std::vector & fparam, + const std::vector & aparam) { int nall = dcoord_.size() / 3; int nloc = nall - nghost; @@ -408,15 +408,15 @@ compute_inner (ENERGYTYPE & dener, void NNPInter:: compute (ENERGYTYPE & dener, - vector & dforce_, - vector & dvirial, - vector & datom_energy_, - vector & datom_virial_, - const vector & dcoord_, - const vector & datype_, - const vector & dbox, - const vector & fparam, - const vector & aparam) + std::vector & dforce_, + std::vector & dvirial, + std::vector & datom_energy_, + std::vector & datom_virial_, + const std::vector & dcoord_, + const std::vector & datype_, + const std::vector & dbox, + const std::vector & fparam, + const std::vector & aparam) { nnpmap = NNPAtomMap (datype_.begin(), datype_.end()); validate_fparam_aparam(nnpmap.get_type().size(), fparam, aparam); @@ -432,18 +432,18 @@ compute (ENERGYTYPE & dener, void NNPInter:: compute (ENERGYTYPE & dener, - vector & dforce_, - vector & dvirial, - vector & datom_energy_, - vector & datom_virial_, - const vector & dcoord_, - const vector & datype_, - const vector & dbox, + std::vector & dforce_, + std::vector & dvirial, + std::vector & datom_energy_, + std::vector & datom_virial_, + const std::vector & dcoord_, + const std::vector & datype_, + const std::vector & dbox, const int nghost, const LammpsNeighborList & lmp_list, - const int & ago, - const vector & fparam, - const vector & aparam) + const int & ago, + const std::vector & fparam, + const std::vector & aparam) { int nall = dcoord_.size() / 3; int nloc = nall - nghost; @@ -482,7 +482,7 @@ NNPInterModelDevi () } NNPInterModelDevi:: -NNPInterModelDevi (const vector & models, const int & gpu_rank) +NNPInterModelDevi (const std::vector & models, const int & gpu_rank) : inited (false), init_nbor(false), numb_models (0) @@ -495,7 +495,7 @@ NNPInterModelDevi::~NNPInterModelDevi() {} void NNPInterModelDevi:: -init (const vector & models, const int & gpu_rank) +init (const std::vector & models, const int & gpu_rank) { assert (!inited); numb_models = models.size(); @@ -615,8 +615,8 @@ cum_sum (const std::vector > n_sel) void NNPInterModelDevi:: validate_fparam_aparam(const int & nloc, - const vector &fparam, - const vector &aparam)const + const std::vector &fparam, + const std::vector &aparam)const { if (fparam.size() != dfparam) { throw std::runtime_error("the dim of frame parameter provided is not consistent with what the model uses"); @@ -629,14 +629,14 @@ validate_fparam_aparam(const int & nloc, void NNPInterModelDevi:: compute (ENERGYTYPE & dener, - vector & dforce_, - vector & dvirial, - vector & model_devi, - const vector & dcoord_, - const vector & datype_, - const vector & dbox, - const vector & fparam, - const vector & aparam) + std::vector & dforce_, + std::vector & dvirial, + std::vector & model_devi, + const std::vector & dcoord_, + const std::vector & datype_, + const std::vector & dbox, + const std::vector & fparam, + const std::vector & aparam) { if (numb_models == 0) return; @@ -646,9 +646,9 @@ compute (ENERGYTYPE & dener, std::vector> input_tensors; int nloc = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, fparam, aparam, nnpmap); - vector all_energy (numb_models); - vector > all_force (numb_models); - vector > all_virial (numb_models); + std::vector all_energy (numb_models); + std::vector > all_force (numb_models); + std::vector > all_virial (numb_models); for (unsigned ii = 0; ii < numb_models; ++ii){ run_model (all_energy[ii], all_force[ii], all_virial[ii], sessions[ii], input_tensors, nnpmap); @@ -675,17 +675,17 @@ compute (ENERGYTYPE & dener, void NNPInterModelDevi:: -compute (vector & all_energy, - vector> & all_force, - vector> & all_virial, - const vector & dcoord_, - const vector & datype_, - const vector & dbox, - const int nghost, - const LammpsNeighborList & lmp_list, - const int & ago, - const vector & fparam, - const vector & aparam) +compute (std::vector & all_energy, + std::vector> & all_force, + std::vector> & all_virial, + const std::vector & dcoord_, + const std::vector & datype_, + const std::vector & dbox, + const int nghost, + const LammpsNeighborList & lmp_list, + const int & ago, + const std::vector & fparam, + const std::vector & aparam) { if (numb_models == 0) return; int nall = dcoord_.size() / 3; @@ -715,19 +715,19 @@ compute (vector & all_energy, void NNPInterModelDevi:: -compute (vector & all_energy, - vector> & all_force, - vector> & all_virial, - vector> & all_atom_energy, - vector> & all_atom_virial, - const vector & dcoord_, - const vector & datype_, - const vector & dbox, +compute (std::vector & all_energy, + std::vector> & all_force, + std::vector> & all_virial, + std::vector> & all_atom_energy, + std::vector> & all_atom_virial, + const std::vector & dcoord_, + const std::vector & datype_, + const std::vector & dbox, const int nghost, const LammpsNeighborList & lmp_list, - const int & ago, - const vector & fparam, - const vector & aparam) + const int & ago, + const std::vector & fparam, + const std::vector & aparam) { if (numb_models == 0) return; int nall = dcoord_.size() / 3; @@ -760,7 +760,7 @@ compute (vector & all_energy, void NNPInterModelDevi:: compute_avg (VALUETYPE & dener, - const vector & all_energy) + const std::vector & all_energy) { assert (all_energy.size() == numb_models); if (numb_models == 0) return; @@ -776,7 +776,7 @@ compute_avg (VALUETYPE & dener, void NNPInterModelDevi:: compute_avg (ENERGYTYPE & dener, - const vector& all_energy) + const std::vector& all_energy) { assert (all_energy.size() == numb_models); if (numb_models == 0) return; @@ -791,8 +791,8 @@ compute_avg (ENERGYTYPE & dener, void NNPInterModelDevi:: -compute_avg (vector & avg, - const vector > & xx) +compute_avg (std::vector & avg, + const std::vector > & xx) { assert (xx.size() == numb_models); if (numb_models == 0) return; @@ -829,9 +829,9 @@ compute_avg (vector & avg, void NNPInterModelDevi:: -compute_std_e (vector & std, - const vector & avg, - const vector >&xx) +compute_std_e (std::vector & std, + const std::vector & avg, + const std::vector >&xx) { assert (xx.size() == numb_models); if (numb_models == 0) return; @@ -860,9 +860,9 @@ compute_std_e (vector & std, void NNPInterModelDevi:: -compute_std_f (vector & std, - const vector & avg, - const vector >&xx) +compute_std_f (std::vector & std, + const std::vector & avg, + const std::vector >&xx) { assert (xx.size() == numb_models); if (numb_models == 0) return; @@ -894,13 +894,13 @@ compute_std_f (vector & std, void NNPInterModelDevi:: -compute_relative_std_f (vector &std, - const vector &avg, - const VALUETYPE eps) +compute_relative_std_f (std::vector &std, + const std::vector &avg, + const VALUETYPE eps) { unsigned nloc = std.size(); for (unsigned ii = 0; ii < nloc; ++ii){ - const VALUETYPE * tmp_avg = &(avg[ii*3]); + const VALUETYPE * tmp_avg = &(avg[ii*3]); VALUETYPE vdiff[3]; vdiff[0] = tmp_avg[0]; vdiff[1] = tmp_avg[1]; diff --git a/source/lib/src/NeighborList.cpp b/source/lib/src/NeighborList.cpp index e7ced4834b..bd509c15c8 100644 --- a/source/lib/src/NeighborList.cpp +++ b/source/lib/src/NeighborList.cpp @@ -2,15 +2,15 @@ #include // #include -using namespace std; +// using namespace std; enum { MAX_WARN_IDX_OUT_OF_BOUND = 10, }; bool -is_loc (const vector & idx, - const vector & nat_stt, - const vector & nat_end) +is_loc (const std::vector & idx, + const std::vector & nat_stt, + const std::vector & nat_end) { bool ret = true; for (int dd = 0; dd < 3; ++dd) ret = ret && idx[dd] >= nat_stt[dd]; @@ -19,16 +19,16 @@ is_loc (const vector & idx, } int -collapse_index (const vector & idx, - const vector & size) +collapse_index (const std::vector & idx, + const std::vector & size) { return (idx[0] * size[1] + idx[1]) * size[2] + idx[2]; } void -expand_index (vector & o_idx, +expand_index (std::vector & o_idx, const int & i_idx, - const vector & size) + const std::vector & size) { int tmp1 = i_idx / size[2]; o_idx[2] = i_idx - tmp1 * size[2]; @@ -37,15 +37,15 @@ expand_index (vector & o_idx, } void -build_clist (vector > & clist, - const vector & coord, +build_clist (std::vector > & clist, + const std::vector & coord, const int & nloc, - const vector & nat_stt, - const vector & nat_end, - const vector & ext_stt, - const vector & ext_end, + const std::vector & nat_stt, + const std::vector & nat_end, + const std::vector & ext_stt, + const std::vector & ext_end, const SimulationRegion & region, - const vector & global_grid) + const std::vector & global_grid) { static int count_warning_loc_idx_lower = 0; static int count_warning_loc_idx_upper = 0; @@ -53,14 +53,14 @@ build_clist (vector > & clist, static int count_warning_ghost_idx_upper = 0; // compute region info, in terms of internal coord int nall = coord.size() / 3; - vector ext_ncell(3); + std::vector ext_ncell(3); for (int dd = 0; dd < 3; ++dd) ext_ncell[dd] = ext_end[dd] - ext_stt[dd]; int ncell = ext_ncell[0] * ext_ncell[1] * ext_ncell[2]; - vector cell_size (3); + std::vector cell_size (3); for (int dd = 0; dd < 3; ++dd) cell_size[dd] = 1./global_grid[dd]; - vector nat_orig(3); + std::vector nat_orig(3); for (int dd = 0; dd < 3; ++dd) nat_orig[dd] = nat_stt[dd] * cell_size[dd]; - vector idx_orig_shift(3); + std::vector idx_orig_shift(3); for (int dd = 0; dd < 3; ++dd) idx_orig_shift[dd] = nat_stt[dd] - ext_stt[dd]; // allocate the reserve the cell list @@ -75,20 +75,20 @@ build_clist (vector > & clist, for (int ii = 0; ii < nloc; ++ii){ double inter[3]; region.phys2Inter (inter, &(coord[ii*3])); - vector idx(3); + std::vector idx(3); for (int dd = 0; dd < 3; ++dd){ idx[dd] = (inter[dd] - nat_orig[dd]) / cell_size[dd]; if (inter[dd] - nat_orig[dd] < 0.) idx[dd] --; if (idx[dd] < nat_stt[dd]) { if (count_warning_loc_idx_lower < MAX_WARN_IDX_OUT_OF_BOUND) { - cerr << "# warning: loc idx out of lower bound (ignored if warned for more than " << MAX_WARN_IDX_OUT_OF_BOUND << " times) " << endl; + std::cerr << "# warning: loc idx out of lower bound (ignored if warned for more than " << MAX_WARN_IDX_OUT_OF_BOUND << " times) " << std::endl; count_warning_loc_idx_lower ++; } idx[dd] = nat_stt[dd]; } else if (idx[dd] >= nat_end[dd]) { if (count_warning_loc_idx_upper < MAX_WARN_IDX_OUT_OF_BOUND) { - cerr << "# warning: loc idx out of upper bound (ignored if warned for more than " << MAX_WARN_IDX_OUT_OF_BOUND << " times) " << endl; + std::cerr << "# warning: loc idx out of upper bound (ignored if warned for more than " << MAX_WARN_IDX_OUT_OF_BOUND << " times) " << std::endl; count_warning_loc_idx_upper ++; } idx[dd] = nat_end[dd] - 1; @@ -100,23 +100,23 @@ build_clist (vector > & clist, for (int ii = nloc; ii < nall; ++ii){ double inter[3]; region.phys2Inter (inter, &(coord[ii*3])); - vector idx(3); + std::vector idx(3); for (int dd = 0; dd < 3; ++dd){ idx[dd] = (inter[dd] - nat_orig[dd]) / cell_size[dd]; if (inter[dd] - nat_orig[dd] < 0.) idx[dd] --; if (idx[dd] < ext_stt[dd]) { if (count_warning_ghost_idx_lower < MAX_WARN_IDX_OUT_OF_BOUND && fabs((inter[dd] - nat_orig[dd]) - (ext_stt[dd] * cell_size[dd])) - > fabs(ext_stt[dd] * cell_size[dd]) * numeric_limits::epsilon() * 5. + > fabs(ext_stt[dd] * cell_size[dd]) * std::numeric_limits::epsilon() * 5. ) { - cerr << "# warning: ghost idx out of lower bound (ignored if warned for more than " << MAX_WARN_IDX_OUT_OF_BOUND << " times) " << endl; + std::cerr << "# warning: ghost idx out of lower bound (ignored if warned for more than " << MAX_WARN_IDX_OUT_OF_BOUND << " times) " << std::endl; count_warning_ghost_idx_lower ++; } idx[dd] = ext_stt[dd]; } else if (idx[dd] >= ext_end[dd]) { if (count_warning_ghost_idx_upper < MAX_WARN_IDX_OUT_OF_BOUND) { - cerr << "# warning: ghost idx out of upper bound (ignored if warned for more than " << MAX_WARN_IDX_OUT_OF_BOUND << " times) " << endl; + std::cerr << "# warning: ghost idx out of upper bound (ignored if warned for more than " << MAX_WARN_IDX_OUT_OF_BOUND << " times) " << std::endl; count_warning_ghost_idx_upper ++; } idx[dd] = ext_end[dd] - 1; @@ -128,23 +128,23 @@ build_clist (vector > & clist, } void -build_clist (vector > & clist, - const vector & coord, - const vector & sel, - const vector & nat_stt, - const vector & nat_end, +build_clist (std::vector > & clist, + const std::vector & coord, + const std::vector & sel, + const std::vector & nat_stt, + const std::vector & nat_end, const SimulationRegion & region) { static int count_warning_loc_idx_lower = 0; static int count_warning_loc_idx_upper = 0; // compute region info, in terms of internal coord int nall = coord.size() / 3; - vector nat_ncell(3); + std::vector nat_ncell(3); for (int dd = 0; dd < 3; ++dd) nat_ncell[dd] = nat_end[dd] - nat_stt[dd]; int ncell = nat_ncell[0] * nat_ncell[1] * nat_ncell[2]; - vector cell_size (3); + std::vector cell_size (3); for (int dd = 0; dd < 3; ++dd) cell_size[dd] = 1./nat_end[dd]; - vector nat_orig(3); + std::vector nat_orig(3); for (int dd = 0; dd < 3; ++dd) nat_orig[dd] = nat_stt[dd] * cell_size[dd]; // allocate the reserve the cell list @@ -160,20 +160,20 @@ build_clist (vector > & clist, int ii = sel[_]; double inter[3]; region.phys2Inter (inter, &(coord[ii*3])); - vector idx(3); + std::vector idx(3); for (int dd = 0; dd < 3; ++dd){ idx[dd] = (inter[dd] - nat_orig[dd]) / cell_size[dd]; if (inter[dd] - nat_orig[dd] < 0.) idx[dd] --; if (idx[dd] < nat_stt[dd]) { if (count_warning_loc_idx_lower < MAX_WARN_IDX_OUT_OF_BOUND) { - cerr << "# warning: loc idx out of lower bound (ignored if warned for more than " << MAX_WARN_IDX_OUT_OF_BOUND << " times) " << endl; + std::cerr << "# warning: loc idx out of lower bound (ignored if warned for more than " << MAX_WARN_IDX_OUT_OF_BOUND << " times) " << std::endl; count_warning_loc_idx_lower ++; } idx[dd] = nat_stt[dd]; } else if (idx[dd] >= nat_end[dd]) { if (count_warning_loc_idx_upper < MAX_WARN_IDX_OUT_OF_BOUND) { - cerr << "# warning: loc idx out of upper bound (ignored if warned for more than " << MAX_WARN_IDX_OUT_OF_BOUND << " times) " << endl; + std::cerr << "# warning: loc idx out of upper bound (ignored if warned for more than " << MAX_WARN_IDX_OUT_OF_BOUND << " times) " << std::endl; count_warning_loc_idx_upper ++; } idx[dd] = nat_end[dd] - 1; @@ -185,16 +185,16 @@ build_clist (vector > & clist, void -build_nlist_cell (vector > & nlist0, - vector > & nlist1, +build_nlist_cell (std::vector > & nlist0, + std::vector > & nlist1, const int & cidx, const int & tidx, - const vector > & clist, - const vector & coord, + const std::vector > & clist, + const std::vector & coord, const double & rc02, const double & rc12, - const vector & shift = {0, 0, 0}, - const vector & boxt = {0., 0., 0., 0., 0., 0., 0., 0., 0.}) + const std::vector & shift = {0, 0, 0}, + const std::vector & boxt = {0., 0., 0., 0., 0., 0., 0., 0., 0.}) { int nloc = nlist0.size(); // loop over c (current) cell @@ -226,17 +226,17 @@ build_nlist_cell (vector > & nlist0, } void -build_nlist_cell (vector > & nlist0, - vector > & nlist1, +build_nlist_cell (std::vector > & nlist0, + std::vector > & nlist1, const int & cidx, const int & tidx, - const vector > & clist0, - const vector > & clist1, - const vector & coord, + const std::vector > & clist0, + const std::vector > & clist1, + const std::vector & coord, const double & rc02, const double & rc12, - const vector & shift = {0, 0, 0}, - const vector & boxt = {0., 0., 0., 0., 0., 0., 0., 0., 0.}) + const std::vector & shift = {0, 0, 0}, + const std::vector & boxt = {0., 0., 0., 0., 0., 0., 0., 0., 0.}) { // loop over c (current) cell for (unsigned ii = 0; ii < clist0[cidx].size(); ++ii){ @@ -265,38 +265,38 @@ build_nlist_cell (vector > & nlist0, } void -build_nlist (vector > & nlist0, - vector > & nlist1, - const vector & coord, +build_nlist (std::vector > & nlist0, + std::vector > & nlist1, + const std::vector & coord, const int & nloc, const double & rc0, const double & rc1, - const vector & nat_stt_, - const vector & nat_end_, - const vector & ext_stt_, - const vector & ext_end_, + const std::vector & nat_stt_, + const std::vector & nat_end_, + const std::vector & ext_stt_, + const std::vector & ext_end_, const SimulationRegion & region, - const vector & global_grid) + const std::vector & global_grid) { // normalize the index // i require that the ext_stt = {0, 0, 0} - vector nat_stt (nat_stt_); - vector nat_end (nat_end_); - vector ext_stt (ext_stt_); - vector ext_end (ext_end_); + std::vector nat_stt (nat_stt_); + std::vector nat_end (nat_end_); + std::vector ext_stt (ext_stt_); + std::vector ext_end (ext_end_); // compute the clist - vector > clist; + std::vector > clist; build_clist (clist, coord, nloc, nat_stt, nat_end, ext_stt, ext_end, region, global_grid); // compute the region info int nall = coord.size() / 3; - vector ext_ncell(3); + std::vector ext_ncell(3); for (int dd = 0; dd < 3; ++dd) ext_ncell[dd] = ext_end[dd] - ext_stt[dd]; // compute number of iter according to the cut-off assert (rc0 <= rc1); - vector niter (3); + std::vector niter (3); double to_face [3]; region.toFaceDistance (to_face); for (int dd = 0; dd < 3; ++dd){ @@ -329,25 +329,25 @@ build_nlist (vector > & nlist0, } // shift of the idx origin - vector idx_orig_shift(3); + std::vector idx_orig_shift(3); for (int dd = 0; dd < 3; ++dd) idx_orig_shift[dd] = nat_stt[dd] - ext_stt[dd]; // compute the nlists double rc02 = 0; if (rc0 > 0) rc02 = rc0 * rc0; double rc12 = rc1 * rc1; - vector cidx(3); + std::vector cidx(3); for (cidx[0] = nat_stt[0]; cidx[0] < nat_end[0]; ++cidx[0]){ for (cidx[1] = nat_stt[1]; cidx[1] < nat_end[1]; ++cidx[1]){ for (cidx[2] = nat_stt[2]; cidx[2] < nat_end[2]; ++cidx[2]){ - vector mcidx(3); + std::vector mcidx(3); for (int dd = 0; dd < 3; ++dd) mcidx[dd] = cidx[dd] + idx_orig_shift[dd]; int clp_cidx = collapse_index (mcidx, ext_ncell); - vector tidx(3); + std::vector tidx(3); for (tidx[0] = cidx[0] - niter[0]; tidx[0] < cidx[0] + niter[0] + 1; ++tidx[0]) { for (tidx[1] = cidx[1] - niter[1]; tidx[1] < cidx[1] + niter[1] + 1; ++tidx[1]) { for (tidx[2] = cidx[2] - niter[2]; tidx[2] < cidx[2] + niter[2] + 1; ++tidx[2]) { - vector mtidx(3); + std::vector mtidx(3); for (int dd = 0; dd < 3; ++dd) mtidx[dd] = tidx[dd] + idx_orig_shift[dd]; int clp_tidx = collapse_index (mtidx, ext_ncell); if (is_loc(tidx, nat_stt, nat_end) && clp_tidx < clp_cidx) continue; @@ -363,30 +363,30 @@ build_nlist (vector > & nlist0, // assume nat grid is the global grid. only used for serial simulations void -build_nlist (vector > & nlist0, - vector > & nlist1, - const vector & coord, +build_nlist (std::vector > & nlist0, + std::vector > & nlist1, + const std::vector & coord, const double & rc0, const double & rc1, - const vector & grid, + const std::vector & grid, const SimulationRegion & region) { // assuming nloc == nall int nloc = coord.size() / 3; // compute the clist - vector nat_stt(3, 0); - vector nat_end(grid); - vector > clist; + std::vector nat_stt(3, 0); + std::vector nat_end(grid); + std::vector > clist; build_clist (clist, coord, nloc, nat_stt, nat_end, nat_stt, nat_end, region, nat_end); // compute the region info int nall = coord.size() / 3; - vector nat_ncell(3); + std::vector nat_ncell(3); for (int dd = 0; dd < 3; ++dd) nat_ncell[dd] = nat_end[dd] - nat_stt[dd]; // compute number of iter according to the cut-off assert (rc0 <= rc1); - vector niter (3); + std::vector niter (3); double to_face [3]; region.toFaceDistance (to_face); for (int dd = 0; dd < 3; ++dd){ @@ -414,7 +414,7 @@ build_nlist (vector > & nlist0, } // physical cell size - vector phys_cs(9); + std::vector phys_cs(9); for (int dd = 0; dd < 9; ++dd) phys_cs[dd] = region.getBoxTensor()[dd]; // compute the nlists @@ -423,7 +423,7 @@ build_nlist (vector > & nlist0, double rc12 = rc1 * rc1; #ifdef HALF_NEIGHBOR_LIST - vector cidx(3); + std::vector cidx(3); for (cidx[0] = nat_stt[0]; cidx[0] < nat_end[0]; ++cidx[0]){ for (cidx[1] = nat_stt[1]; cidx[1] < nat_end[1]; ++cidx[1]){ for (cidx[2] = nat_stt[2]; cidx[2] < nat_end[2]; ++cidx[2]){ @@ -435,7 +435,7 @@ build_nlist (vector > & nlist0, int idx_total = idx_range[0] * idx_range[1] * idx_range[2]; #pragma omp parallel for for (int tmpidx = 0; tmpidx < idx_total; ++tmpidx) { - vector cidx(3); + std::vector cidx(3); cidx[0] = nat_stt[0] + tmpidx / (idx_range[1] * idx_range[2]); int tmpidx1 = tmpidx - cidx[0] * idx_range[1] * idx_range[2]; cidx[1] = nat_stt[1] + tmpidx1 / idx_range[2]; @@ -444,9 +444,9 @@ build_nlist (vector > & nlist0, { #endif int clp_cidx = collapse_index (cidx, nat_ncell); - vector tidx(3); - vector stidx(3); - vector shift(3); + std::vector tidx(3); + std::vector stidx(3); + std::vector shift(3); for (tidx[0] = cidx[0] - niter[0]; tidx[0] < cidx[0] + niter[0] + 1; ++tidx[0]) { shift[0] = 0; if (tidx[0] < 0) shift[0] += 1; @@ -479,32 +479,32 @@ build_nlist (vector > & nlist0, void -build_nlist (vector > & nlist0, - vector > & nlist1, - const vector & coord, - const vector & sel0, - const vector & sel1, +build_nlist (std::vector > & nlist0, + std::vector > & nlist1, + const std::vector & coord, + const std::vector & sel0, + const std::vector & sel1, const double & rc0, const double & rc1, - const vector & grid, + const std::vector & grid, const SimulationRegion & region) { int nloc = coord.size() / 3; // compute the clist - vector nat_stt(3, 0); - vector nat_end(grid); - vector > clist0, clist1; + std::vector nat_stt(3, 0); + std::vector nat_end(grid); + std::vector > clist0, clist1; build_clist (clist0, coord, sel0, nat_stt, nat_end, region); build_clist (clist1, coord, sel1, nat_stt, nat_end, region); // compute the region info int nall = coord.size() / 3; - vector nat_ncell(3); + std::vector nat_ncell(3); for (int dd = 0; dd < 3; ++dd) nat_ncell[dd] = nat_end[dd] - nat_stt[dd]; // compute number of iter according to the cut-off assert (rc0 <= rc1); - vector niter (3); + std::vector niter (3); double to_face [3]; region.toFaceDistance (to_face); for (int dd = 0; dd < 3; ++dd){ @@ -532,21 +532,21 @@ build_nlist (vector > & nlist0, } // physical cell size - vector phys_cs(9); + std::vector phys_cs(9); for (int dd = 0; dd < 9; ++dd) phys_cs[dd] = region.getBoxTensor()[dd]; // compute the nlists double rc02 = 0; if (rc0 > 0) rc02 = rc0 * rc0; double rc12 = rc1 * rc1; - vector cidx(3); + std::vector cidx(3); for (cidx[0] = nat_stt[0]; cidx[0] < nat_end[0]; ++cidx[0]){ for (cidx[1] = nat_stt[1]; cidx[1] < nat_end[1]; ++cidx[1]){ for (cidx[2] = nat_stt[2]; cidx[2] < nat_end[2]; ++cidx[2]){ int clp_cidx = collapse_index (cidx, nat_ncell); - vector tidx(3); - vector stidx(3); - vector shift(3); + std::vector tidx(3); + std::vector stidx(3); + std::vector shift(3); for (tidx[0] = cidx[0] - niter[0]; tidx[0] < cidx[0] + niter[0] + 1; ++tidx[0]) { shift[0] = 0; if (tidx[0] < 0) shift[0] += 1; @@ -574,9 +574,9 @@ build_nlist (vector > & nlist0, void -build_nlist (vector > & nlist0, - vector > & nlist1, - const vector & posi3, +build_nlist (std::vector > & nlist0, + std::vector > & nlist1, + const std::vector & posi3, const double & rc0_, const double & rc1_, const SimulationRegion * region) @@ -641,13 +641,13 @@ static int compute_pbc_shift (int idx, } void -copy_coord (vector & out_c, - vector & out_t, - vector & mapping, - vector & ncell, - vector & ngcell, - const vector & in_c, - const vector & in_t, +copy_coord (std::vector & out_c, + std::vector & out_t, + std::vector & mapping, + std::vector & ncell, + std::vector & ngcell, + const std::vector & in_c, + const std::vector & in_t, const double & rc, const SimulationRegion & region) { @@ -676,8 +676,8 @@ copy_coord (vector & out_c, mapping.reserve(esti_ntotal * 2); // build cell list - vector > clist; - vector nat_stt(3, 0); + std::vector > clist; + std::vector nat_stt(3, 0); build_clist (clist, in_c, nloc, nat_stt, ncell, nat_stt, ncell, region, ncell); // copy local atoms @@ -689,7 +689,7 @@ copy_coord (vector & out_c, for (int ii = 0; ii < nloc; ++ii) mapping[ii] = ii; // push ghost - vector ii(3), jj(3), pbc_shift(3, 0); + std::vector ii(3), jj(3), pbc_shift(3, 0); double pbc_shift_d[3]; for (ii[0] = -ngcell[0]; ii[0] < ncell[0] + ngcell[0]; ++ii[0]){ pbc_shift[0] = compute_pbc_shift(ii[0], ncell[0]); @@ -712,7 +712,7 @@ copy_coord (vector & out_c, double shift_v [3]; region.inter2Phys(shift_v, pbc_shift_d); int cell_idx = collapse_index(jj, ncell); - vector & cur_clist = clist[cell_idx]; + std::vector & cur_clist = clist[cell_idx]; for (int kk = 0; kk < cur_clist.size(); ++kk){ int p_idx = cur_clist[kk]; double shifted_coord [3]; @@ -728,12 +728,12 @@ copy_coord (vector & out_c, // if ( inter[0] >= 0 && inter[0] < 1 && // inter[1] >= 0 && inter[1] < 1 && // inter[2] >= 0 && inter[2] < 1 ){ - // cout << out_c.size() / 3 << " " + // std::cout << out_c.size() / 3 << " " // << inter[0] << " " // << inter[1] << " " // << inter[2] << " " - // << endl; - // cout << "err here inner" << endl; + // << std::endl; + // std::cout << "err here inner" << std::endl; // exit(1); // } } diff --git a/source/lib/src/common.cc b/source/lib/src/common.cc index d990195e6c..97d4f971ec 100644 --- a/source/lib/src/common.cc +++ b/source/lib/src/common.cc @@ -3,15 +3,15 @@ #include "SimulationRegion.h" void -select_by_type(vector & fwd_map, - vector & bkw_map, +select_by_type(std::vector & fwd_map, + std::vector & bkw_map, int & nghost_real, - const vector & dcoord_, - const vector & datype_, + const std::vector & dcoord_, + const std::vector & datype_, const int & nghost, - const vector & sel_type_) + const std::vector & sel_type_) { - vector sel_type (sel_type_); + std::vector sel_type (sel_type_); sort(sel_type.begin(), sel_type.end()); int nall = dcoord_.size() / 3; int nloc = nall - nghost; @@ -44,15 +44,15 @@ select_by_type(vector & fwd_map, void -select_real_atoms(vector & fwd_map, - vector & bkw_map, +select_real_atoms(std::vector & fwd_map, + std::vector & bkw_map, int & nghost_real, - const vector & dcoord_, - const vector & datype_, + const std::vector & dcoord_, + const std::vector & datype_, const int & nghost, const int & ntypes) { - vector sel_type; + std::vector sel_type; for (int ii = 0; ii < ntypes; ++ii){ sel_type.push_back(ii); } @@ -86,13 +86,13 @@ void shuffle_nlist (InternalNeighborList & list, const NNPAtomMap & map) { - const vector & fwd_map = map.get_fwd_map(); + const std::vector & fwd_map = map.get_fwd_map(); shuffle_nlist(list, fwd_map); } void shuffle_nlist (InternalNeighborList & list, - const vector & fwd_map) + const std::vector & fwd_map) { int nloc = fwd_map.size(); for (unsigned ii = 0; ii < list.ilist.size(); ++ii){ @@ -109,11 +109,11 @@ shuffle_nlist (InternalNeighborList & list, void shuffle_nlist_exclude_empty (InternalNeighborList & list, - const vector & fwd_map) + const std::vector & fwd_map) { int old_nloc = fwd_map.size(); shuffle_nlist(list, fwd_map); - vector new_ilist, new_jrange, new_jlist, new_icount; + std::vector new_ilist, new_jrange, new_jlist, new_icount; new_ilist.reserve(list.ilist.size()); new_icount.reserve(list.ilist.size()); new_jrange.reserve(list.jrange.size()); @@ -187,13 +187,13 @@ name_prefix(const string & scope) int session_input_tensors (std::vector> & input_tensors, - const vector & dcoord_, + const std::vector & dcoord_, const int & ntypes, - const vector & datype_, - const vector & dbox, + const std::vector & datype_, + const std::vector & dbox, const VALUETYPE & cell_size, - const vector & fparam_, - const vector & aparam_, + const std::vector & fparam_, + const std::vector & aparam_, const NNPAtomMap& nnpmap, const int nghost, const string scope) @@ -207,26 +207,26 @@ session_input_tensors (std::vector> & input_tensors, int nloc = nall - nghost; assert (nall == datype_.size()); - vector datype = nnpmap.get_type(); - vector type_count (ntypes, 0); + std::vector datype = nnpmap.get_type(); + std::vector type_count (ntypes, 0); for (unsigned ii = 0; ii < datype.size(); ++ii){ type_count[datype[ii]] ++; } datype.insert (datype.end(), datype_.begin() + nloc, datype_.end()); SimulationRegion region; - vector dbox_(9); + std::vector dbox_(9); for (int dd = 0; dd < 9; ++dd) dbox_[dd] = dbox[dd]; region.reinitBox (&dbox_[0]); double box_l[3]; region.toFaceDistance (box_l); - vector ncell (3, 2); + std::vector ncell (3, 2); for (int dd = 0; dd < 3; ++dd){ ncell[dd] = box_l[dd] / cell_size; if (ncell[dd] < 2) ncell[dd] = 2; } - vector next(3, 0); + std::vector next(3, 0); for (int dd = 0; dd < 3; ++dd){ double cellh = box_l[dd] / ncell[dd]; next[dd] = cellh / cell_size; @@ -282,7 +282,7 @@ session_input_tensors (std::vector> & input_tensors, auto fparam = fparam_tensor.matrix (); auto aparam = aparam_tensor.matrix (); - vector dcoord (dcoord_); + std::vector dcoord (dcoord_); nnpmap.forward (dcoord.begin(), dcoord_.begin(), 3); for (int ii = 0; ii < nframes; ++ii){ @@ -342,13 +342,13 @@ session_input_tensors (std::vector> & input_tensors, int session_input_tensors (std::vector> & input_tensors, - const vector & dcoord_, + const std::vector & dcoord_, const int & ntypes, - const vector & datype_, - const vector & dbox, + const std::vector & datype_, + const std::vector & dbox, InternalNeighborList & dlist, - const vector & fparam_, - const vector & aparam_, + const std::vector & fparam_, + const std::vector & aparam_, const NNPAtomMap& nnpmap, const int nghost, const int ago, @@ -361,8 +361,8 @@ session_input_tensors (std::vector> & input_tensors, int nloc = nall - nghost; assert (nall == datype_.size()); - vector datype = nnpmap.get_type(); - vector type_count (ntypes, 0); + std::vector datype = nnpmap.get_type(); + std::vector type_count (ntypes, 0); for (unsigned ii = 0; ii < datype.size(); ++ii){ type_count[datype[ii]] ++; } @@ -411,7 +411,7 @@ session_input_tensors (std::vector> & input_tensors, auto fparam = fparam_tensor.matrix (); auto aparam = aparam_tensor.matrix (); - vector dcoord (dcoord_); + std::vector dcoord (dcoord_); nnpmap.forward (dcoord.begin(), dcoord_.begin(), 3); for (int ii = 0; ii < nframes; ++ii){ @@ -472,13 +472,13 @@ session_input_tensors (std::vector> & input_tensors, int session_input_tensors (std::vector> & input_tensors, - const vector & dcoord_, + const std::vector & dcoord_, const int & ntypes, - const vector & datype_, - const vector & dbox, + const std::vector & datype_, + const std::vector & dbox, InternalNeighborList & dlist, - const vector & fparam_, - const vector & aparam_, + const std::vector & fparam_, + const std::vector & aparam_, const NNPAtomMap& nnpmap, const int nghost, const string scope) @@ -490,8 +490,8 @@ session_input_tensors (std::vector> & input_tensors, int nloc = nall - nghost; assert (nall == datype_.size()); - vector datype = nnpmap.get_type(); - vector type_count (ntypes, 0); + std::vector datype = nnpmap.get_type(); + std::vector type_count (ntypes, 0); for (unsigned ii = 0; ii < datype.size(); ++ii){ type_count[datype[ii]] ++; } @@ -540,7 +540,7 @@ session_input_tensors (std::vector> & input_tensors, auto fparam = fparam_tensor.matrix (); auto aparam = aparam_tensor.matrix (); - vector dcoord (dcoord_); + std::vector dcoord (dcoord_); nnpmap.forward (dcoord.begin(), dcoord_.begin(), 3); for (int ii = 0; ii < nframes; ++ii){ @@ -601,18 +601,18 @@ session_input_tensors (std::vector> & input_tensors, int session_input_tensors ( - vector> & input_tensors, - const vector & dcoord_, - const int & ntypes, - const vector & datype_, - const vector & dbox, - const int * ilist, - const int * jrange, - const int * jlist, - const vector & fparam_, - const vector & aparam_, - const NNPAtomMap & nnpmap, - const int & nghost) + std::vector> & input_tensors, + const std::vector & dcoord_, + const int & ntypes, + const std::vector & datype_, + const std::vector & dbox, + const int * ilist, + const int * jrange, + const int * jlist, + const std::vector & fparam_, + const std::vector & aparam_, + const NNPAtomMap & nnpmap, + const int & nghost) { assert (dbox.size() == 9); @@ -621,8 +621,8 @@ session_input_tensors ( int nloc = nall - nghost; assert (nall == datype_.size()); - vector datype = nnpmap.get_type(); - vector type_count (ntypes, 0); + std::vector datype = nnpmap.get_type(); + std::vector type_count (ntypes, 0); for (unsigned ii = 0; ii < datype.size(); ++ii) { type_count[datype[ii]] ++; } @@ -671,7 +671,7 @@ session_input_tensors ( auto fparam = fparam_tensor.matrix (); auto aparam = aparam_tensor.matrix (); - vector dcoord (dcoord_); + std::vector dcoord (dcoord_); nnpmap.forward (dcoord.begin(), dcoord_.begin(), 3); for (int ii = 0; ii < nframes; ++ii) { diff --git a/source/op/descrpt.cc b/source/op/descrpt.cc index 147ca687cf..71918b4a5a 100644 --- a/source/op/descrpt.cc +++ b/source/op/descrpt.cc @@ -10,7 +10,7 @@ typedef double boxtensor_t ; typedef double compute_t; using namespace tensorflow; -using namespace std; +// using namespace std; using CPUDevice = Eigen::ThreadPoolDevice; @@ -113,7 +113,7 @@ class DescrptOp : public OpKernel { nei_mode = -1; } else { - throw runtime_error("invalid mesh tensor"); + throw std::runtime_error("invalid mesh tensor"); } bool b_pbc = true; // if region is given extended, do not use pbc @@ -190,7 +190,7 @@ class DescrptOp : public OpKernel { region.reinitBox (boxt); // set & normalize coord - vector d_coord3 (nall*3); + std::vector d_coord3 (nall*3); for (int ii = 0; ii < nall; ++ii){ for (int dd = 0; dd < 3; ++dd){ d_coord3[ii*3+dd] = coord(kk, ii*3+dd); @@ -207,13 +207,13 @@ class DescrptOp : public OpKernel { } // set type - vector d_type (nall); + std::vector d_type (nall); for (int ii = 0; ii < nall; ++ii) d_type[ii] = type(kk, ii); // build nlist - vector > d_nlist_a; - vector > d_nlist_r; - vector nlist_map; + std::vector > d_nlist_a; + std::vector > d_nlist_r; + std::vector nlist_map; bool b_nlist_map = false; if (nei_mode == 3) { int * pilist, *pjrange, *pjlist; @@ -236,22 +236,22 @@ class DescrptOp : public OpKernel { } } else if (nei_mode == 2) { - vector nat_stt = {mesh(1-1), mesh(2-1), mesh(3-1)}; - vector nat_end = {mesh(4-1), mesh(5-1), mesh(6-1)}; - vector ext_stt = {mesh(7-1), mesh(8-1), mesh(9-1)}; - vector ext_end = {mesh(10-1), mesh(11-1), mesh(12-1)}; - vector global_grid (3); + std::vector nat_stt = {mesh(1-1), mesh(2-1), mesh(3-1)}; + std::vector nat_end = {mesh(4-1), mesh(5-1), mesh(6-1)}; + std::vector ext_stt = {mesh(7-1), mesh(8-1), mesh(9-1)}; + std::vector ext_end = {mesh(10-1), mesh(11-1), mesh(12-1)}; + std::vector global_grid (3); for (int dd = 0; dd < 3; ++dd) global_grid[dd] = nat_end[dd] - nat_stt[dd]; ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, rcut_a, rcut_r, nat_stt, nat_end, ext_stt, ext_end, region, global_grid); } else if (nei_mode == 1) { - vector bk_d_coord3 = d_coord3; - vector bk_d_type = d_type; - vector ncell, ngcell; + std::vector bk_d_coord3 = d_coord3; + std::vector bk_d_type = d_type; + std::vector ncell, ngcell; copy_coord(d_coord3, d_type, nlist_map, ncell, ngcell, bk_d_coord3, bk_d_type, rcut_r, region); b_nlist_map = true; - vector nat_stt(3, 0); - vector ext_stt(3), ext_end(3); + std::vector nat_stt(3, 0); + std::vector ext_stt(3), ext_end(3); for (int dd = 0; dd < 3; ++dd){ ext_stt[dd] = -ngcell[dd]; ext_end[dd] = ncell[dd] + ngcell[dd]; @@ -262,40 +262,40 @@ class DescrptOp : public OpKernel { ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, rcut_a, rcut_r, NULL); } else { - throw runtime_error("unknow neighbor mode"); + throw std::runtime_error("unknow neighbor mode"); } // loop over atoms, compute descriptors for each atom #pragma omp parallel for for (int ii = 0; ii < nloc; ++ii){ - vector fmt_nlist_a; - vector fmt_nlist_r; + std::vector fmt_nlist_a; + std::vector fmt_nlist_r; int ret = -1; if (fill_nei_a){ if ((ret = format_nlist_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ if (count_nei_idx_overflow == 0) { - cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << endl; - flush(cout); + std::cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << std::endl; + flush(std::cout); count_nei_idx_overflow ++; } } } // set axis - vector d_axis_type (2); - vector d_axis_idx (2); + std::vector d_axis_type (2); + std::vector d_axis_idx (2); make_axis (d_axis_type, d_axis_idx, d_type[ii], axis_rule, ii, fmt_nlist_a, fmt_nlist_r, d_coord3, region, b_pbc); - // cout << ii << " type " << d_type[ii] + // std::cout << ii << " type " << d_type[ii] // << " axis 0: " << d_axis_type[0] << " " << d_axis_idx[0] - // << " axis 1: " << d_axis_type[1] << " " << d_axis_idx[1] << endl; + // << " axis 1: " << d_axis_type[1] << " " << d_axis_idx[1] << std::endl; - vector d_descrpt_a; - vector d_descrpt_a_deriv; - vector d_descrpt_r; - vector d_descrpt_r_deriv; - vector d_rij_a; - vector d_rij_r; - vector rot; + std::vector d_descrpt_a; + std::vector d_descrpt_a_deriv; + std::vector d_descrpt_r; + std::vector d_descrpt_r_deriv; + std::vector d_rij_a; + std::vector d_rij_r; + std::vector rot; compute_descriptor (d_descrpt_a, d_descrpt_a_deriv, d_descrpt_r, @@ -372,18 +372,18 @@ class DescrptOp : public OpKernel { private: float rcut_a; float rcut_r; - vector sel_r; - vector sel_a; - vector axis_rule; - vector sec_a; - vector sec_r; + std::vector sel_r; + std::vector sel_a; + std::vector axis_rule; + std::vector sec_a; + std::vector sec_r; int ndescrpt, ndescrpt_a, ndescrpt_r; int nnei, nnei_a, nnei_r; bool fill_nei_a; int count_nei_idx_overflow; void - cum_sum (vector & sec, - const vector & n_sel) const { + cum_sum (std::vector & sec, + const std::vector & n_sel) const { sec.resize (n_sel.size() + 1); sec[0] = 0; for (int ii = 1; ii < sec.size(); ++ii){ @@ -391,14 +391,14 @@ class DescrptOp : public OpKernel { } } void - make_axis (vector & axis_type, - vector & axis_idx, + make_axis (std::vector & axis_type, + std::vector & axis_idx, const int & type, - const vector & rule, + const std::vector & rule, const int ii, - const vector & nlist_a, - const vector & nlist_r, - const vector & coord3, + const std::vector & nlist_a, + const std::vector & nlist_r, + const std::vector & coord3, const SimulationRegion & region, const bool b_pbc) const { int backup_axis = -1; @@ -411,7 +411,7 @@ class DescrptOp : public OpKernel { assert(rule.size() == ntypes * 2 * 3); axis_type.resize(2); axis_idx .resize(2); - vector::const_iterator iter; + std::vector::const_iterator iter; iter = rule.begin() + type * 6; if (*(iter+1) >= 0) { make_one_axis (axis_type[0], axis_idx[0], iter); @@ -426,7 +426,7 @@ class DescrptOp : public OpKernel { else { make_one_axis (axis_type[1], axis_idx[1], iter, ii, nlist_a, nlist_r, coord3, region, b_pbc); } - vector backup_rule (3); + std::vector backup_rule (3); copy (iter, iter+3, backup_rule.begin()); backup_rule[2] ++; if (*(iter+1) >= 0) { @@ -442,7 +442,7 @@ class DescrptOp : public OpKernel { } else { axis_idx[1] ++; - // cerr << "wrong backup axis, exit" << endl; + // std::cerr << "wrong backup axis, exit" << std::endl; // exit (1); } } @@ -458,7 +458,7 @@ class DescrptOp : public OpKernel { void make_one_axis (int & axis_type, int & axis_idx, - vector::const_iterator info_i) const { + std::vector::const_iterator info_i) const { axis_type = *info_i; if (axis_type == 0){ axis_idx = sec_a[*(info_i+1)] + *(info_i+2); @@ -470,16 +470,16 @@ class DescrptOp : public OpKernel { void make_one_axis (int & axis_type, int & axis_idx, - vector::const_iterator info_i, + std::vector::const_iterator info_i, const int id, - const vector & nlist_a, - const vector & nlist_r, - const vector & coord3, + const std::vector & nlist_a, + const std::vector & nlist_r, + const std::vector & coord3, const SimulationRegion & region, const bool b_pbc) const { axis_type = *info_i; if (axis_type == 0){ - vector > sort_info; + std::vector > sort_info; int excl_type = - (*(info_i+1) + 1); int ntypes = sel_a.size(); for (unsigned ii = 0; ii < ntypes; ++ii){ @@ -502,7 +502,7 @@ class DescrptOp : public OpKernel { diff[dd] = coord3[3*id+dd] - coord3[3*jd+dd]; } } - sort_info.push_back (pair + sort_info.push_back (std::pair (MathUtilities::dot (diff, diff), list_idx) ); } } @@ -511,7 +511,7 @@ class DescrptOp : public OpKernel { axis_idx = sort_info[*(info_i+2)].second; } else { - vector > sort_info; + std::vector > sort_info; int excl_type = - *(info_i+1); int ntypes = sel_r.size(); for (unsigned ii = 0; ii < ntypes; ++ii){ @@ -534,7 +534,7 @@ class DescrptOp : public OpKernel { diff[dd] = coord3[3*id+dd] - coord3[3*jd+dd]; } } - sort_info.push_back (pair + sort_info.push_back (std::pair (MathUtilities::dot (diff, diff), list_idx) ); } } @@ -544,8 +544,8 @@ class DescrptOp : public OpKernel { } } void - make_axis_default (vector & axis_type, - vector & axis_idx) const { + make_axis_default (std::vector & axis_type, + std::vector & axis_idx) const { axis_type.resize(2); axis_idx .resize(2); if (nnei_a > 1) { @@ -562,12 +562,12 @@ class DescrptOp : public OpKernel { axis_idx[1] = 1; } bool - check_axis (const vector & axis_type, - const vector & axis_idx, + check_axis (const std::vector & axis_type, + const std::vector & axis_idx, const int id, - const vector & nlist_a, - const vector & nlist_r, - const vector & coord3, + const std::vector & nlist_a, + const std::vector & nlist_r, + const std::vector & coord3, const SimulationRegion & region, const bool b_pbc) const { compute_t diff[2][3]; diff --git a/source/op/descrpt_se_a.cc b/source/op/descrpt_se_a.cc index 88f866944d..a9a694887b 100644 --- a/source/op/descrpt_se_a.cc +++ b/source/op/descrpt_se_a.cc @@ -10,7 +10,7 @@ typedef double boxtensor_t ; typedef double compute_t; using namespace tensorflow; -using namespace std; +// using namespace std; using CPUDevice = Eigen::ThreadPoolDevice; using GPUDevice = Eigen::GpuDevice; @@ -115,7 +115,7 @@ class DescrptSeAOp : public OpKernel { nei_mode = -1; } else { - throw runtime_error("invalid mesh tensor"); + throw std::runtime_error("invalid mesh tensor"); } bool b_pbc = true; // if region is given extended, do not use pbc @@ -189,7 +189,7 @@ class DescrptSeAOp : public OpKernel { region.reinitBox (boxt); // set & normalize coord - vector d_coord3 (nall*3); + std::vector d_coord3 (nall*3); for (int ii = 0; ii < nall; ++ii){ for (int dd = 0; dd < 3; ++dd){ d_coord3[ii*3+dd] = coord(kk, ii*3+dd); @@ -206,13 +206,13 @@ class DescrptSeAOp : public OpKernel { } // set type - vector d_type (nall); + std::vector d_type (nall); for (int ii = 0; ii < nall; ++ii) d_type[ii] = type(kk, ii); // build nlist - vector > d_nlist_a; - vector > d_nlist_r; - vector nlist_map; + std::vector > d_nlist_a; + std::vector > d_nlist_r; + std::vector nlist_map; bool b_nlist_map = false; if (nei_mode == 3) { int * pilist, *pjrange, *pjlist; @@ -235,22 +235,22 @@ class DescrptSeAOp : public OpKernel { } } else if (nei_mode == 2) { - vector nat_stt = {mesh(1-1), mesh(2-1), mesh(3-1)}; - vector nat_end = {mesh(4-1), mesh(5-1), mesh(6-1)}; - vector ext_stt = {mesh(7-1), mesh(8-1), mesh(9-1)}; - vector ext_end = {mesh(10-1), mesh(11-1), mesh(12-1)}; - vector global_grid (3); + std::vector nat_stt = {mesh(1-1), mesh(2-1), mesh(3-1)}; + std::vector nat_end = {mesh(4-1), mesh(5-1), mesh(6-1)}; + std::vector ext_stt = {mesh(7-1), mesh(8-1), mesh(9-1)}; + std::vector ext_end = {mesh(10-1), mesh(11-1), mesh(12-1)}; + std::vector global_grid (3); for (int dd = 0; dd < 3; ++dd) global_grid[dd] = nat_end[dd] - nat_stt[dd]; ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, rcut_a, rcut_r, nat_stt, nat_end, ext_stt, ext_end, region, global_grid); } else if (nei_mode == 1) { - vector bk_d_coord3 = d_coord3; - vector bk_d_type = d_type; - vector ncell, ngcell; + std::vector bk_d_coord3 = d_coord3; + std::vector bk_d_type = d_type; + std::vector ncell, ngcell; copy_coord(d_coord3, d_type, nlist_map, ncell, ngcell, bk_d_coord3, bk_d_type, rcut_r, region); b_nlist_map = true; - vector nat_stt(3, 0); - vector ext_stt(3), ext_end(3); + std::vector nat_stt(3, 0); + std::vector ext_stt(3), ext_end(3); for (int dd = 0; dd < 3; ++dd){ ext_stt[dd] = -ngcell[dd]; ext_end[dd] = ncell[dd] + ngcell[dd]; @@ -261,31 +261,31 @@ class DescrptSeAOp : public OpKernel { ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, rcut_a, rcut_r, NULL); } else { - throw runtime_error("unknow neighbor mode"); + throw std::runtime_error("unknow neighbor mode"); } // loop over atoms, compute descriptors for each atom #pragma omp parallel for for (int ii = 0; ii < nloc; ++ii){ - vector fmt_nlist_a; - vector fmt_nlist_r; + std::vector fmt_nlist_a; + std::vector fmt_nlist_r; int ret = -1; if (fill_nei_a){ if ((ret = format_nlist_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ if (count_nei_idx_overflow == 0) { - cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << endl; - flush(cout); + std::cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << std::endl; + flush(std::cout); count_nei_idx_overflow ++; } } } - vector d_descrpt_a; - vector d_descrpt_a_deriv; - vector d_descrpt_r; - vector d_descrpt_r_deriv; - vector d_rij_a; - vector d_rij_r; + std::vector d_descrpt_a; + std::vector d_descrpt_a_deriv; + std::vector d_descrpt_r; + std::vector d_descrpt_r_deriv; + std::vector d_rij_a; + std::vector d_rij_r; compute_descriptor_se_a (d_descrpt_a, d_descrpt_a_deriv, d_rij_a, @@ -329,17 +329,17 @@ class DescrptSeAOp : public OpKernel { float rcut_a; float rcut_r; float rcut_r_smth; - vector sel_r; - vector sel_a; - vector sec_a; - vector sec_r; + std::vector sel_r; + std::vector sel_a; + std::vector sec_a; + std::vector sec_r; int ndescrpt, ndescrpt_a, ndescrpt_r; int nnei, nnei_a, nnei_r; bool fill_nei_a; int count_nei_idx_overflow; void - cum_sum (vector & sec, - const vector & n_sel) const { + cum_sum (std::vector & sec, + const std::vector & n_sel) const { sec.resize (n_sel.size() + 1); sec[0] = 0; for (int ii = 1; ii < sec.size(); ++ii){ diff --git a/source/op/descrpt_se_a_ef.cc b/source/op/descrpt_se_a_ef.cc index cc9a89c31b..b4a631b7cf 100644 --- a/source/op/descrpt_se_a_ef.cc +++ b/source/op/descrpt_se_a_ef.cc @@ -10,7 +10,7 @@ typedef double boxtensor_t ; typedef double compute_t; using namespace tensorflow; -using namespace std; +// using namespace std; #ifdef HIGH_PREC typedef double VALUETYPE ; @@ -142,7 +142,7 @@ class DescrptSeAEfOp : public OpKernel { nei_mode = -1; } else { - throw runtime_error("invalid mesh tensor"); + throw std::runtime_error("invalid mesh tensor"); } bool b_pbc = true; // if region is given extended, do not use pbc @@ -217,7 +217,7 @@ class DescrptSeAEfOp : public OpKernel { region.reinitBox (boxt); // set & normalize coord - vector d_coord3 (nall*3); + std::vector d_coord3 (nall*3); for (int ii = 0; ii < nall; ++ii){ for (int dd = 0; dd < 3; ++dd){ d_coord3[ii*3+dd] = coord(kk, ii*3+dd); @@ -234,7 +234,7 @@ class DescrptSeAEfOp : public OpKernel { } // set efield - vector d_ef(nloc * 3); + std::vector d_ef(nloc * 3); for (int ii = 0; ii < nloc; ++ii){ for (int dd = 0; dd < 3; ++dd){ d_ef[ii*3+dd] = ef(kk, ii*3+dd); @@ -242,13 +242,13 @@ class DescrptSeAEfOp : public OpKernel { } // set type - vector d_type (nall); + std::vector d_type (nall); for (int ii = 0; ii < nall; ++ii) d_type[ii] = type(kk, ii); // build nlist - vector > d_nlist_a; - vector > d_nlist_r; - vector nlist_map; + std::vector > d_nlist_a; + std::vector > d_nlist_r; + std::vector nlist_map; bool b_nlist_map = false; if (nei_mode == 3) { int * pilist, *pjrange, *pjlist; @@ -271,22 +271,22 @@ class DescrptSeAEfOp : public OpKernel { } } else if (nei_mode == 2) { - vector nat_stt = {mesh(1-1), mesh(2-1), mesh(3-1)}; - vector nat_end = {mesh(4-1), mesh(5-1), mesh(6-1)}; - vector ext_stt = {mesh(7-1), mesh(8-1), mesh(9-1)}; - vector ext_end = {mesh(10-1), mesh(11-1), mesh(12-1)}; - vector global_grid (3); + std::vector nat_stt = {mesh(1-1), mesh(2-1), mesh(3-1)}; + std::vector nat_end = {mesh(4-1), mesh(5-1), mesh(6-1)}; + std::vector ext_stt = {mesh(7-1), mesh(8-1), mesh(9-1)}; + std::vector ext_end = {mesh(10-1), mesh(11-1), mesh(12-1)}; + std::vector global_grid (3); for (int dd = 0; dd < 3; ++dd) global_grid[dd] = nat_end[dd] - nat_stt[dd]; ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, rcut_a, rcut_r, nat_stt, nat_end, ext_stt, ext_end, region, global_grid); } else if (nei_mode == 1) { - vector bk_d_coord3 = d_coord3; - vector bk_d_type = d_type; - vector ncell, ngcell; + std::vector bk_d_coord3 = d_coord3; + std::vector bk_d_type = d_type; + std::vector ncell, ngcell; copy_coord(d_coord3, d_type, nlist_map, ncell, ngcell, bk_d_coord3, bk_d_type, rcut_r, region); b_nlist_map = true; - vector nat_stt(3, 0); - vector ext_stt(3), ext_end(3); + std::vector nat_stt(3, 0); + std::vector ext_stt(3), ext_end(3); for (int dd = 0; dd < 3; ++dd){ ext_stt[dd] = -ngcell[dd]; ext_end[dd] = ncell[dd] + ngcell[dd]; @@ -297,31 +297,31 @@ class DescrptSeAEfOp : public OpKernel { ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, rcut_a, rcut_r, NULL); } else { - throw runtime_error("unknow neighbor mode"); + throw std::runtime_error("unknow neighbor mode"); } // loop over atoms, compute descriptors for each atom #pragma omp parallel for for (int ii = 0; ii < nloc; ++ii){ - vector fmt_nlist_a; - vector fmt_nlist_r; + std::vector fmt_nlist_a; + std::vector fmt_nlist_r; int ret = -1; if (fill_nei_a){ if ((ret = format_nlist_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ if (count_nei_idx_overflow == 0) { - cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << endl; - flush(cout); + std::cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << std::endl; + flush(std::cout); count_nei_idx_overflow ++; } } } - vector d_descrpt_a; - vector d_descrpt_a_deriv; - vector d_descrpt_r; - vector d_descrpt_r_deriv; - vector d_rij_a; - vector d_rij_r; + std::vector d_descrpt_a; + std::vector d_descrpt_a_deriv; + std::vector d_descrpt_r; + std::vector d_descrpt_r_deriv; + std::vector d_rij_a; + std::vector d_rij_r; compute_descriptor_se_a_extf (d_descrpt_a, d_descrpt_a_deriv, d_rij_a, @@ -366,17 +366,17 @@ class DescrptSeAEfOp : public OpKernel { float rcut_a; float rcut_r; float rcut_r_smth; - vector sel_r; - vector sel_a; - vector sec_a; - vector sec_r; + std::vector sel_r; + std::vector sel_a; + std::vector sec_a; + std::vector sec_r; int ndescrpt, ndescrpt_a, ndescrpt_r; int nnei, nnei_a, nnei_r; bool fill_nei_a; int count_nei_idx_overflow; void - cum_sum (vector & sec, - const vector & n_sel) const { + cum_sum (std::vector & sec, + const std::vector & n_sel) const { sec.resize (n_sel.size() + 1); sec[0] = 0; for (int ii = 1; ii < sec.size(); ++ii){ diff --git a/source/op/descrpt_se_a_ef_para.cc b/source/op/descrpt_se_a_ef_para.cc index fed1ef670d..af17b3ca12 100644 --- a/source/op/descrpt_se_a_ef_para.cc +++ b/source/op/descrpt_se_a_ef_para.cc @@ -10,7 +10,7 @@ typedef double boxtensor_t ; typedef double compute_t; using namespace tensorflow; -using namespace std; +// using namespace std; #ifdef HIGH_PREC typedef double VALUETYPE ; @@ -142,7 +142,7 @@ class DescrptSeAEfParaOp : public OpKernel { nei_mode = -1; } else { - throw runtime_error("invalid mesh tensor"); + throw std::runtime_error("invalid mesh tensor"); } bool b_pbc = true; // if region is given extended, do not use pbc @@ -217,7 +217,7 @@ class DescrptSeAEfParaOp : public OpKernel { region.reinitBox (boxt); // set & normalize coord - vector d_coord3 (nall*3); + std::vector d_coord3 (nall*3); for (int ii = 0; ii < nall; ++ii){ for (int dd = 0; dd < 3; ++dd){ d_coord3[ii*3+dd] = coord(kk, ii*3+dd); @@ -234,7 +234,7 @@ class DescrptSeAEfParaOp : public OpKernel { } // set efield - vector d_ef(nloc * 3); + std::vector d_ef(nloc * 3); for (int ii = 0; ii < nloc; ++ii){ for (int dd = 0; dd < 3; ++dd){ d_ef[ii*3+dd] = ef(kk, ii*3+dd); @@ -242,13 +242,13 @@ class DescrptSeAEfParaOp : public OpKernel { } // set type - vector d_type (nall); + std::vector d_type (nall); for (int ii = 0; ii < nall; ++ii) d_type[ii] = type(kk, ii); // build nlist - vector > d_nlist_a; - vector > d_nlist_r; - vector nlist_map; + std::vector > d_nlist_a; + std::vector > d_nlist_r; + std::vector nlist_map; bool b_nlist_map = false; if (nei_mode == 3) { int * pilist, *pjrange, *pjlist; @@ -271,22 +271,22 @@ class DescrptSeAEfParaOp : public OpKernel { } } else if (nei_mode == 2) { - vector nat_stt = {mesh(1-1), mesh(2-1), mesh(3-1)}; - vector nat_end = {mesh(4-1), mesh(5-1), mesh(6-1)}; - vector ext_stt = {mesh(7-1), mesh(8-1), mesh(9-1)}; - vector ext_end = {mesh(10-1), mesh(11-1), mesh(12-1)}; - vector global_grid (3); + std::vector nat_stt = {mesh(1-1), mesh(2-1), mesh(3-1)}; + std::vector nat_end = {mesh(4-1), mesh(5-1), mesh(6-1)}; + std::vector ext_stt = {mesh(7-1), mesh(8-1), mesh(9-1)}; + std::vector ext_end = {mesh(10-1), mesh(11-1), mesh(12-1)}; + std::vector global_grid (3); for (int dd = 0; dd < 3; ++dd) global_grid[dd] = nat_end[dd] - nat_stt[dd]; ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, rcut_a, rcut_r, nat_stt, nat_end, ext_stt, ext_end, region, global_grid); } else if (nei_mode == 1) { - vector bk_d_coord3 = d_coord3; - vector bk_d_type = d_type; - vector ncell, ngcell; + std::vector bk_d_coord3 = d_coord3; + std::vector bk_d_type = d_type; + std::vector ncell, ngcell; copy_coord(d_coord3, d_type, nlist_map, ncell, ngcell, bk_d_coord3, bk_d_type, rcut_r, region); b_nlist_map = true; - vector nat_stt(3, 0); - vector ext_stt(3), ext_end(3); + std::vector nat_stt(3, 0); + std::vector ext_stt(3), ext_end(3); for (int dd = 0; dd < 3; ++dd){ ext_stt[dd] = -ngcell[dd]; ext_end[dd] = ncell[dd] + ngcell[dd]; @@ -297,31 +297,31 @@ class DescrptSeAEfParaOp : public OpKernel { ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, rcut_a, rcut_r, NULL); } else { - throw runtime_error("unknow neighbor mode"); + throw std::runtime_error("unknow neighbor mode"); } // loop over atoms, compute descriptors for each atom #pragma omp parallel for for (int ii = 0; ii < nloc; ++ii){ - vector fmt_nlist_a; - vector fmt_nlist_r; + std::vector fmt_nlist_a; + std::vector fmt_nlist_r; int ret = -1; if (fill_nei_a){ if ((ret = format_nlist_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ if (count_nei_idx_overflow == 0) { - cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << endl; - flush(cout); + std::cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << std::endl; + flush(std::cout); count_nei_idx_overflow ++; } } } - vector d_descrpt_a; - vector d_descrpt_a_deriv; - vector d_descrpt_r; - vector d_descrpt_r_deriv; - vector d_rij_a; - vector d_rij_r; + std::vector d_descrpt_a; + std::vector d_descrpt_a_deriv; + std::vector d_descrpt_r; + std::vector d_descrpt_r_deriv; + std::vector d_rij_a; + std::vector d_rij_r; compute_descriptor_se_a_ef_para (d_descrpt_a, d_descrpt_a_deriv, d_rij_a, @@ -366,17 +366,17 @@ class DescrptSeAEfParaOp : public OpKernel { float rcut_a; float rcut_r; float rcut_r_smth; - vector sel_r; - vector sel_a; - vector sec_a; - vector sec_r; + std::vector sel_r; + std::vector sel_a; + std::vector sec_a; + std::vector sec_r; int ndescrpt, ndescrpt_a, ndescrpt_r; int nnei, nnei_a, nnei_r; bool fill_nei_a; int count_nei_idx_overflow; void - cum_sum (vector & sec, - const vector & n_sel) const { + cum_sum (std::vector & sec, + const std::vector & n_sel) const { sec.resize (n_sel.size() + 1); sec[0] = 0; for (int ii = 1; ii < sec.size(); ++ii){ diff --git a/source/op/descrpt_se_a_ef_vert.cc b/source/op/descrpt_se_a_ef_vert.cc index 9a7199c9f9..1d416864e2 100644 --- a/source/op/descrpt_se_a_ef_vert.cc +++ b/source/op/descrpt_se_a_ef_vert.cc @@ -10,7 +10,7 @@ typedef double boxtensor_t ; typedef double compute_t; using namespace tensorflow; -using namespace std; +// using namespace std; #ifdef HIGH_PREC typedef double VALUETYPE ; @@ -142,7 +142,7 @@ class DescrptSeAEfVertOp : public OpKernel { nei_mode = -1; } else { - throw runtime_error("invalid mesh tensor"); + throw std::runtime_error("invalid mesh tensor"); } bool b_pbc = true; // if region is given extended, do not use pbc @@ -217,7 +217,7 @@ class DescrptSeAEfVertOp : public OpKernel { region.reinitBox (boxt); // set & normalize coord - vector d_coord3 (nall*3); + std::vector d_coord3 (nall*3); for (int ii = 0; ii < nall; ++ii){ for (int dd = 0; dd < 3; ++dd){ d_coord3[ii*3+dd] = coord(kk, ii*3+dd); @@ -234,7 +234,7 @@ class DescrptSeAEfVertOp : public OpKernel { } // set efield - vector d_ef(nloc * 3); + std::vector d_ef(nloc * 3); for (int ii = 0; ii < nloc; ++ii){ for (int dd = 0; dd < 3; ++dd){ d_ef[ii*3+dd] = ef(kk, ii*3+dd); @@ -242,13 +242,13 @@ class DescrptSeAEfVertOp : public OpKernel { } // set type - vector d_type (nall); + std::vector d_type (nall); for (int ii = 0; ii < nall; ++ii) d_type[ii] = type(kk, ii); // build nlist - vector > d_nlist_a; - vector > d_nlist_r; - vector nlist_map; + std::vector > d_nlist_a; + std::vector > d_nlist_r; + std::vector nlist_map; bool b_nlist_map = false; if (nei_mode == 3) { int * pilist, *pjrange, *pjlist; @@ -271,22 +271,22 @@ class DescrptSeAEfVertOp : public OpKernel { } } else if (nei_mode == 2) { - vector nat_stt = {mesh(1-1), mesh(2-1), mesh(3-1)}; - vector nat_end = {mesh(4-1), mesh(5-1), mesh(6-1)}; - vector ext_stt = {mesh(7-1), mesh(8-1), mesh(9-1)}; - vector ext_end = {mesh(10-1), mesh(11-1), mesh(12-1)}; - vector global_grid (3); + std::vector nat_stt = {mesh(1-1), mesh(2-1), mesh(3-1)}; + std::vector nat_end = {mesh(4-1), mesh(5-1), mesh(6-1)}; + std::vector ext_stt = {mesh(7-1), mesh(8-1), mesh(9-1)}; + std::vector ext_end = {mesh(10-1), mesh(11-1), mesh(12-1)}; + std::vector global_grid (3); for (int dd = 0; dd < 3; ++dd) global_grid[dd] = nat_end[dd] - nat_stt[dd]; ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, rcut_a, rcut_r, nat_stt, nat_end, ext_stt, ext_end, region, global_grid); } else if (nei_mode == 1) { - vector bk_d_coord3 = d_coord3; - vector bk_d_type = d_type; - vector ncell, ngcell; + std::vector bk_d_coord3 = d_coord3; + std::vector bk_d_type = d_type; + std::vector ncell, ngcell; copy_coord(d_coord3, d_type, nlist_map, ncell, ngcell, bk_d_coord3, bk_d_type, rcut_r, region); b_nlist_map = true; - vector nat_stt(3, 0); - vector ext_stt(3), ext_end(3); + std::vector nat_stt(3, 0); + std::vector ext_stt(3), ext_end(3); for (int dd = 0; dd < 3; ++dd){ ext_stt[dd] = -ngcell[dd]; ext_end[dd] = ncell[dd] + ngcell[dd]; @@ -297,31 +297,31 @@ class DescrptSeAEfVertOp : public OpKernel { ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, rcut_a, rcut_r, NULL); } else { - throw runtime_error("unknow neighbor mode"); + throw std::runtime_error("unknow neighbor mode"); } // loop over atoms, compute descriptors for each atom #pragma omp parallel for for (int ii = 0; ii < nloc; ++ii){ - vector fmt_nlist_a; - vector fmt_nlist_r; + std::vector fmt_nlist_a; + std::vector fmt_nlist_r; int ret = -1; if (fill_nei_a){ if ((ret = format_nlist_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ if (count_nei_idx_overflow == 0) { - cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << endl; - flush(cout); + std::cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << std::endl; + flush(std::cout); count_nei_idx_overflow ++; } } } - vector d_descrpt_a; - vector d_descrpt_a_deriv; - vector d_descrpt_r; - vector d_descrpt_r_deriv; - vector d_rij_a; - vector d_rij_r; + std::vector d_descrpt_a; + std::vector d_descrpt_a_deriv; + std::vector d_descrpt_r; + std::vector d_descrpt_r_deriv; + std::vector d_rij_a; + std::vector d_rij_r; compute_descriptor_se_a_ef_vert (d_descrpt_a, d_descrpt_a_deriv, d_rij_a, @@ -366,17 +366,17 @@ class DescrptSeAEfVertOp : public OpKernel { float rcut_a; float rcut_r; float rcut_r_smth; - vector sel_r; - vector sel_a; - vector sec_a; - vector sec_r; + std::vector sel_r; + std::vector sel_a; + std::vector sec_a; + std::vector sec_r; int ndescrpt, ndescrpt_a, ndescrpt_r; int nnei, nnei_a, nnei_r; bool fill_nei_a; int count_nei_idx_overflow; void - cum_sum (vector & sec, - const vector & n_sel) const { + cum_sum (std::vector & sec, + const std::vector & n_sel) const { sec.resize (n_sel.size() + 1); sec[0] = 0; for (int ii = 1; ii < sec.size(); ++ii){ diff --git a/source/op/descrpt_se_a_multi_device.cc b/source/op/descrpt_se_a_multi_device.cc index ae5e623171..f5888faecd 100644 --- a/source/op/descrpt_se_a_multi_device.cc +++ b/source/op/descrpt_se_a_multi_device.cc @@ -34,12 +34,12 @@ struct DeviceFunctor { template struct DescrptSeAFunctor { - void operator()(const CPUDevice& d, const FPTYPE * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { + void operator()(const CPUDevice& d, const FPTYPE * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::std::vector sec_a, const bool fill_nei_a, const int magic_number) { DescrptSeACPULauncher(coord, type, ilist, jrange, jlist, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ntypes, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); } #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const FPTYPE * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { + void operator()(const GPUDevice& d, const FPTYPE * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::std::vector sec_a, const bool fill_nei_a, const int magic_number) { DescrptSeAGPULauncher(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); } #endif // GOOGLE_CUDA @@ -207,16 +207,16 @@ class DescrptSeAOp : public OpKernel { float rcut_a; float rcut_r; float rcut_r_smth; - std::vector sel_r; - std::vector sel_a; - std::vector sec_a; - std::vector sec_r; + std::std::vector sel_r; + std::std::vector sel_a; + std::std::vector sec_a; + std::std::vector sec_r; int ndescrpt, ndescrpt_a, ndescrpt_r; int nnei, nnei_a, nnei_r, nloc, nall, magic_number; bool fill_nei_a; //private func - void cum_sum (std::vector & sec, const std::vector & n_sel) const { + void cum_sum (std::std::vector & sec, const std::std::vector & n_sel) const { sec.resize (n_sel.size() + 1); sec[0] = 0; for (int ii = 1; ii < sec.size(); ++ii) { diff --git a/source/op/descrpt_se_r.cc b/source/op/descrpt_se_r.cc index a4bfe341ac..c7e989a8a9 100644 --- a/source/op/descrpt_se_r.cc +++ b/source/op/descrpt_se_r.cc @@ -10,7 +10,7 @@ typedef double boxtensor_t ; typedef double compute_t; using namespace tensorflow; -using namespace std; +// using namespace std; using CPUDevice = Eigen::ThreadPoolDevice; @@ -106,7 +106,7 @@ class DescrptSeROp : public OpKernel { nei_mode = -1; } else { - throw runtime_error("invalid mesh tensor"); + throw std::runtime_error("invalid mesh tensor"); } bool b_pbc = true; // if region is given extended, do not use pbc @@ -173,7 +173,7 @@ class DescrptSeROp : public OpKernel { region.reinitBox (boxt); // set & normalize coord - vector d_coord3 (nall*3); + std::vector d_coord3 (nall*3); for (int ii = 0; ii < nall; ++ii){ for (int dd = 0; dd < 3; ++dd){ d_coord3[ii*3+dd] = coord(kk, ii*3+dd); @@ -190,13 +190,13 @@ class DescrptSeROp : public OpKernel { } // set type - vector d_type (nall); + std::vector d_type (nall); for (int ii = 0; ii < nall; ++ii) d_type[ii] = type(kk, ii); // build nlist - vector > d_nlist; - vector > d_nlist_null; - vector nlist_map; + std::vector > d_nlist; + std::vector > d_nlist_null; + std::vector nlist_map; bool b_nlist_map = false; if (nei_mode == 3) { int * pilist, *pjrange, *pjlist; @@ -219,22 +219,22 @@ class DescrptSeROp : public OpKernel { } } else if (nei_mode == 2) { - vector nat_stt = {mesh(1-1), mesh(2-1), mesh(3-1)}; - vector nat_end = {mesh(4-1), mesh(5-1), mesh(6-1)}; - vector ext_stt = {mesh(7-1), mesh(8-1), mesh(9-1)}; - vector ext_end = {mesh(10-1), mesh(11-1), mesh(12-1)}; - vector global_grid (3); + std::vector nat_stt = {mesh(1-1), mesh(2-1), mesh(3-1)}; + std::vector nat_end = {mesh(4-1), mesh(5-1), mesh(6-1)}; + std::vector ext_stt = {mesh(7-1), mesh(8-1), mesh(9-1)}; + std::vector ext_end = {mesh(10-1), mesh(11-1), mesh(12-1)}; + std::vector global_grid (3); for (int dd = 0; dd < 3; ++dd) global_grid[dd] = nat_end[dd] - nat_stt[dd]; ::build_nlist (d_nlist_null, d_nlist, d_coord3, nloc, -1, rcut, nat_stt, nat_end, ext_stt, ext_end, region, global_grid); } else if (nei_mode == 1) { - vector bk_d_coord3 = d_coord3; - vector bk_d_type = d_type; - vector ncell, ngcell; + std::vector bk_d_coord3 = d_coord3; + std::vector bk_d_type = d_type; + std::vector ncell, ngcell; copy_coord(d_coord3, d_type, nlist_map, ncell, ngcell, bk_d_coord3, bk_d_type, rcut, region); b_nlist_map = true; - vector nat_stt(3, 0); - vector ext_stt(3), ext_end(3); + std::vector nat_stt(3, 0); + std::vector ext_stt(3), ext_end(3); for (int dd = 0; dd < 3; ++dd){ ext_stt[dd] = -ngcell[dd]; ext_end[dd] = ncell[dd] + ngcell[dd]; @@ -245,33 +245,33 @@ class DescrptSeROp : public OpKernel { ::build_nlist (d_nlist_null, d_nlist, d_coord3, -1, rcut, NULL); } else { - throw runtime_error("unknow neighbor mode"); + throw std::runtime_error("unknow neighbor mode"); } // loop over atoms, compute descriptors for each atom #pragma omp parallel for for (int ii = 0; ii < nloc; ++ii){ - vector fmt_nlist_null; - vector fmt_nlist; + std::vector fmt_nlist_null; + std::vector fmt_nlist; int ret = -1; if (fill_nei_a){ if ((ret = format_nlist_fill_a (fmt_nlist, fmt_nlist_null, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_null[ii], d_nlist[ii], rcut, sec, sec_null)) != -1){ if (count_nei_idx_overflow == 0) { - cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << endl; - flush(cout); + std::cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << std::endl; + flush(std::cout); count_nei_idx_overflow ++; } } } - // cout << ii << " " ; + // std::cout << ii << " " ; // for (int jj = 0 ; jj < fmt_nlist.size(); ++jj){ - // cout << fmt_nlist[jj] << " " ; + // std::cout << fmt_nlist[jj] << " " ; // } - // cout << endl; + // std::cout << std::endl; - vector d_descrpt; - vector d_descrpt_deriv; - vector d_rij; + std::vector d_descrpt; + std::vector d_descrpt_deriv; + std::vector d_rij; compute_descriptor_se_r (d_descrpt, d_descrpt_deriv, d_rij, @@ -313,17 +313,17 @@ class DescrptSeROp : public OpKernel { private: float rcut; float rcut_smth; - vector sel; - vector sel_null; - vector sec; - vector sec_null; + std::vector sel; + std::vector sel_null; + std::vector sec; + std::vector sec_null; int ndescrpt; int nnei; bool fill_nei_a; int count_nei_idx_overflow; void - cum_sum (vector & sec, - const vector & n_sel) const { + cum_sum (std::vector & sec, + const std::vector & n_sel) const { sec.resize (n_sel.size() + 1); sec[0] = 0; for (int ii = 1; ii < sec.size(); ++ii){ diff --git a/source/op/descrpt_se_r_multi_device.cc b/source/op/descrpt_se_r_multi_device.cc index c5eaff616c..cf620069a5 100644 --- a/source/op/descrpt_se_r_multi_device.cc +++ b/source/op/descrpt_se_r_multi_device.cc @@ -31,12 +31,12 @@ struct DeviceFunctor { template struct DescrptSeRFunctor { - void operator()(const CPUDevice& d, const T * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const T * avg, const T * std, T * descrpt, T * descrpt_deriv, T * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { + void operator()(const CPUDevice& d, const T * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const T * avg, const T * std, T * descrpt, T * descrpt_deriv, T * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::std::vector sec_a, const bool fill_nei_a, const int magic_number) { DescrptSeRCPULauncher(coord, type, ilist, jrange, jlist, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ntypes, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); } #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const T * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const T * avg, const T * std, T * descrpt, T * descrpt_deriv, T * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { + void operator()(const GPUDevice& d, const T * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const T * avg, const T * std, T * descrpt, T * descrpt_deriv, T * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::std::vector sec_a, const bool fill_nei_a, const int magic_number) { DescrptSeRGPULauncher(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); } #endif // GOOGLE_CUDA @@ -57,7 +57,7 @@ class DescrptSeROp : public OpKernel { fill_nei_a = true; magic_number = get_magic_number(nnei); // count_nei_idx_overflow = 0; - // std::cout << "I'm in descrpt_se_r_gpu.cc" << std::endl; + // std::std::cout << "I'm in descrpt_se_r_gpu.cc" << std::std::endl; } void Compute(OpKernelContext* context) override { @@ -197,15 +197,15 @@ class DescrptSeROp : public OpKernel { private: float rcut; float rcut_smth; - std::vector sel; - std::vector sel_null; - std::vector sec; - std::vector sec_null; + std::std::vector sel; + std::std::vector sel_null; + std::std::vector sec; + std::std::vector sec_null; int nnei, ndescrpt, nloc, nall; bool fill_nei_a; //private func - void cum_sum (std::vector & sec, const std::vector & n_sel) const { + void cum_sum (std::std::vector & sec, const std::std::vector & n_sel) const { sec.resize (n_sel.size() + 1); sec[0] = 0; for (int ii = 1; ii < sec.size(); ++ii) { diff --git a/source/op/ewald_recp.cc b/source/op/ewald_recp.cc index 22c61b7429..b2b1356330 100644 --- a/source/op/ewald_recp.cc +++ b/source/op/ewald_recp.cc @@ -8,7 +8,7 @@ typedef double boxtensor_t ; using namespace tensorflow; -using namespace std; +// using namespace std; using CPUDevice = Eigen::ThreadPoolDevice; @@ -95,7 +95,7 @@ class EwaldRecpOp : public OpKernel { region.reinitBox (boxt); // set & normalize coord - vector d_coord3_ (nloc*3); + std::vector d_coord3_ (nloc*3); for (int ii = 0; ii < nloc; ++ii){ for (int dd = 0; dd < 3; ++dd){ d_coord3_[ii*3+dd] = coord(coord_iter + ii*3+dd); @@ -107,19 +107,19 @@ class EwaldRecpOp : public OpKernel { else if (inter[dd] >= 1) inter[dd] -= 1.; } } - vector d_coord3 (nloc*3); + std::vector d_coord3 (nloc*3); for (int ii = 0; ii < nloc * 3; ++ii) { d_coord3[ii] = d_coord3_[ii]; } // set charge - vector d_charge (nloc); + std::vector d_charge (nloc); for (int ii = 0; ii < nloc; ++ii) d_charge[ii] = charge(charge_iter + ii); - // prepare outputs vectors + // prepare outputs std::vectors FPTYPE d_ener; - vector d_force(nloc*3); - vector d_virial(9); + std::vector d_force(nloc*3); + std::vector d_virial(9); // compute EwaldReciprocal(d_ener, d_force, d_virial, d_coord3, d_charge, region, ep); diff --git a/source/op/map_aparam.cc b/source/op/map_aparam.cc index 4cbcc098e2..43bc8a011f 100644 --- a/source/op/map_aparam.cc +++ b/source/op/map_aparam.cc @@ -4,7 +4,7 @@ #include using namespace tensorflow; -using namespace std; +// using namespace std; #ifdef HIGH_PREC typedef double VALUETYPE; diff --git a/source/op/prod_force.cc b/source/op/prod_force.cc index 7ba99b6e81..382f807e53 100644 --- a/source/op/prod_force.cc +++ b/source/op/prod_force.cc @@ -4,7 +4,7 @@ #include using namespace tensorflow; -using namespace std; +// using namespace std; REGISTER_OP("ProdForce") .Attr("T: {float, double}") @@ -68,7 +68,7 @@ class ProdForceOp : public OpKernel { TensorShape force_shape ; force_shape.AddDim (nframes); force_shape.AddDim (3 * nall); - // cout << "forcesahpe " << force_shape.dim_size(0) << " " << force_shape.dim_size(1) << endl; + // std::cout << "forcesahpe " << force_shape.dim_size(0) << " " << force_shape.dim_size(1) << std::endl; Tensor* force_tensor = NULL; OP_REQUIRES_OK(context, context->allocate_output(0, force_shape, &force_tensor)); diff --git a/source/op/prod_force_grad.cc b/source/op/prod_force_grad.cc index 2c8e62550c..71992a110e 100644 --- a/source/op/prod_force_grad.cc +++ b/source/op/prod_force_grad.cc @@ -4,7 +4,7 @@ #include using namespace tensorflow; -using namespace std; +// using namespace std; REGISTER_OP("ProdForceGrad") .Attr("T: {float, double}") @@ -180,4 +180,4 @@ REGISTER_KERNEL_BUILDER( Name("ProdForceGrad").Device(DEVICE_CPU).TypeConstraint("T"), \ ProdForceGradOp); REGISTER_CPU(float); -REGISTER_CPU(double); \ No newline at end of file +REGISTER_CPU(double); diff --git a/source/op/prod_force_se_a.cc b/source/op/prod_force_se_a.cc index 1b5053377c..572b4be8b5 100644 --- a/source/op/prod_force_se_a.cc +++ b/source/op/prod_force_se_a.cc @@ -4,7 +4,7 @@ #include using namespace tensorflow; -using namespace std; +// using namespace std; REGISTER_OP("ProdForceSeA") .Attr("T: {float, double}") diff --git a/source/op/prod_force_se_a_grad.cc b/source/op/prod_force_se_a_grad.cc index 884e46f9a8..dab3819b17 100644 --- a/source/op/prod_force_se_a_grad.cc +++ b/source/op/prod_force_se_a_grad.cc @@ -4,7 +4,7 @@ #include using namespace tensorflow; -using namespace std; +// using namespace std; REGISTER_OP("ProdForceSeAGrad") .Attr("T: {float, double}") @@ -149,4 +149,4 @@ REGISTER_KERNEL_BUILDER( Name("ProdForceSeAGrad").Device(DEVICE_CPU).TypeConstraint("T"), \ ProdForceSeAGradOp); REGISTER_CPU(float); -REGISTER_CPU(double); \ No newline at end of file +REGISTER_CPU(double); diff --git a/source/op/prod_force_se_r.cc b/source/op/prod_force_se_r.cc index 4347442167..34b12f104c 100644 --- a/source/op/prod_force_se_r.cc +++ b/source/op/prod_force_se_r.cc @@ -4,7 +4,7 @@ #include using namespace tensorflow; -using namespace std; +// using namespace std; REGISTER_OP("ProdForceSeR") .Attr("T: {float, double}") diff --git a/source/op/prod_force_se_r_grad.cc b/source/op/prod_force_se_r_grad.cc index dfe9a5ff98..3c2ff96827 100644 --- a/source/op/prod_force_se_r_grad.cc +++ b/source/op/prod_force_se_r_grad.cc @@ -4,7 +4,7 @@ #include using namespace tensorflow; -using namespace std; +// using namespace std; REGISTER_OP("ProdForceSeRGrad") .Attr("T: {float, double}") @@ -124,4 +124,4 @@ REGISTER_KERNEL_BUILDER( Name("ProdForceSeRGrad").Device(DEVICE_CPU).TypeConstraint("T"), \ ProdForceSeRGradOp); REGISTER_CPU(float); -REGISTER_CPU(double); \ No newline at end of file +REGISTER_CPU(double); diff --git a/source/op/prod_virial.cc b/source/op/prod_virial.cc index f42a5055c2..b39567ae82 100644 --- a/source/op/prod_virial.cc +++ b/source/op/prod_virial.cc @@ -4,7 +4,7 @@ #include using namespace tensorflow; -using namespace std; +// using namespace std; REGISTER_OP("ProdVirial") .Attr("T: {float, double}") diff --git a/source/op/prod_virial_grad.cc b/source/op/prod_virial_grad.cc index 5d75f5f649..5cce265935 100644 --- a/source/op/prod_virial_grad.cc +++ b/source/op/prod_virial_grad.cc @@ -4,7 +4,7 @@ #include using namespace tensorflow; -using namespace std; +// using namespace std; REGISTER_OP("ProdVirialGrad") .Attr("T: {float, double}") @@ -189,4 +189,4 @@ REGISTER_KERNEL_BUILDER( Name("ProdVirialGrad").Device(DEVICE_CPU).TypeConstraint("T"), \ ProdVirialGradOp); REGISTER_CPU(float); -REGISTER_CPU(double); \ No newline at end of file +REGISTER_CPU(double); diff --git a/source/op/prod_virial_se_a.cc b/source/op/prod_virial_se_a.cc index ba934fa54e..7a0ffbd20d 100644 --- a/source/op/prod_virial_se_a.cc +++ b/source/op/prod_virial_se_a.cc @@ -4,7 +4,7 @@ #include using namespace tensorflow; -using namespace std; +// using namespace std; REGISTER_OP("ProdVirialSeA") diff --git a/source/op/prod_virial_se_a_grad.cc b/source/op/prod_virial_se_a_grad.cc index ebbd857bf0..1cc02f93c4 100644 --- a/source/op/prod_virial_se_a_grad.cc +++ b/source/op/prod_virial_se_a_grad.cc @@ -4,7 +4,7 @@ #include using namespace tensorflow; -using namespace std; +// using namespace std; REGISTER_OP("ProdVirialSeAGrad") .Attr("T: {float, double}") @@ -153,4 +153,4 @@ REGISTER_KERNEL_BUILDER( Name("ProdVirialSeAGrad").Device(DEVICE_CPU).TypeConstraint("T"), \ ProdVirialSeAGradOp); REGISTER_CPU(float); -REGISTER_CPU(double); \ No newline at end of file +REGISTER_CPU(double); diff --git a/source/op/prod_virial_se_r.cc b/source/op/prod_virial_se_r.cc index 5337246c21..3bb8a0fcd1 100644 --- a/source/op/prod_virial_se_r.cc +++ b/source/op/prod_virial_se_r.cc @@ -4,7 +4,7 @@ #include using namespace tensorflow; -using namespace std; +// using namespace std; REGISTER_OP("ProdVirialSeR") diff --git a/source/op/prod_virial_se_r_grad.cc b/source/op/prod_virial_se_r_grad.cc index 61b8970e71..fa15b3a671 100644 --- a/source/op/prod_virial_se_r_grad.cc +++ b/source/op/prod_virial_se_r_grad.cc @@ -4,7 +4,7 @@ #include using namespace tensorflow; -using namespace std; +//using namespace std; REGISTER_OP("ProdVirialSeRGrad") .Attr("T: {float, double}") @@ -128,4 +128,4 @@ REGISTER_KERNEL_BUILDER( Name("ProdVirialSeRGrad").Device(DEVICE_CPU).TypeConstraint("T"), \ ProdVirialSeRGradOp); REGISTER_CPU(float); -REGISTER_CPU(double); \ No newline at end of file +REGISTER_CPU(double); diff --git a/source/op/soft_min.cc b/source/op/soft_min.cc index 6f3bc58932..786439a7bf 100644 --- a/source/op/soft_min.cc +++ b/source/op/soft_min.cc @@ -6,7 +6,7 @@ #include "ComputeDescriptor.h" using namespace tensorflow; -using namespace std; +// using namespace std; REGISTER_OP("SoftMinSwitch") @@ -152,26 +152,26 @@ class SoftMinSwitchOp : public OpKernel { sw_deriv(kk, rij_idx_shift + 0) += ts * dr[0]; sw_deriv(kk, rij_idx_shift + 1) += ts * dr[1]; sw_deriv(kk, rij_idx_shift + 2) += ts * dr[2]; - // cout << ii << " " << jj << " " << j_idx << " " + // std::cout << ii << " " << jj << " " << j_idx << " " // << vv << " " // << sw_deriv(kk, rij_idx_shift+0) << " " // << sw_deriv(kk, rij_idx_shift+1) << " " // << sw_deriv(kk, rij_idx_shift+2) << " " - // << endl; + // << std::endl; } } } } private: - vector sel_r; - vector sel_a; - vector sec_a; - vector sec_r; + std::vector sel_r; + std::vector sel_a; + std::vector sec_a; + std::vector sec_r; float alpha, rmin, rmax; int nnei, nnei_a, nnei_r; void - cum_sum (vector & sec, - const vector & n_sel) const { + cum_sum (std::vector & sec, + const std::vector & n_sel) const { sec.resize (n_sel.size() + 1); sec[0] = 0; for (int ii = 1; ii < sec.size(); ++ii){ diff --git a/source/op/soft_min_force.cc b/source/op/soft_min_force.cc index ffd6442a1a..916f42f60f 100644 --- a/source/op/soft_min_force.cc +++ b/source/op/soft_min_force.cc @@ -4,7 +4,7 @@ #include using namespace tensorflow; -using namespace std; +// using namespace std; REGISTER_OP("SoftMinForce") .Attr("T: {float, double}") @@ -93,10 +93,10 @@ class SoftMinForceOp : public OpKernel { force(kk, j_idx * 3 + 0) -= du(kk, i_idx) * sw_deriv(kk, rij_idx_shift + 0); force(kk, j_idx * 3 + 1) -= du(kk, i_idx) * sw_deriv(kk, rij_idx_shift + 1); force(kk, j_idx * 3 + 2) -= du(kk, i_idx) * sw_deriv(kk, rij_idx_shift + 2); - // cout << "soft_min_force " << i_idx << " " << j_idx << " " + // std::cout << "soft_min_force " << i_idx << " " << j_idx << " " // << du(kk, i_idx) << " " // << du(kk, i_idx) * sw_deriv(kk, rij_idx_shift + 0) - // << endl; + // << std::endl; } } } diff --git a/source/op/soft_min_force_grad.cc b/source/op/soft_min_force_grad.cc index 2461828853..53d17d42a9 100644 --- a/source/op/soft_min_force_grad.cc +++ b/source/op/soft_min_force_grad.cc @@ -4,7 +4,7 @@ #include using namespace tensorflow; -using namespace std; +// using namespace std; REGISTER_OP("SoftMinForceGrad") .Attr("T: {float, double}") @@ -117,4 +117,4 @@ REGISTER_KERNEL_BUILDER( Name("SoftMinForceGrad").Device(DEVICE_CPU).TypeConstraint("T"), \ SoftMinForceGradOp); REGISTER_CPU(float); -REGISTER_CPU(double); \ No newline at end of file +REGISTER_CPU(double); diff --git a/source/op/soft_min_virial.cc b/source/op/soft_min_virial.cc index f369808685..88016dbfd2 100644 --- a/source/op/soft_min_virial.cc +++ b/source/op/soft_min_virial.cc @@ -4,7 +4,7 @@ #include using namespace tensorflow; -using namespace std; +// using namespace std; REGISTER_OP("SoftMinVirial") .Attr("T: {float, double}") diff --git a/source/op/soft_min_virial_grad.cc b/source/op/soft_min_virial_grad.cc index 0bafaa5bfa..b3cefef771 100644 --- a/source/op/soft_min_virial_grad.cc +++ b/source/op/soft_min_virial_grad.cc @@ -4,7 +4,7 @@ #include using namespace tensorflow; -using namespace std; +// using namespace std; REGISTER_OP("SoftMinVirialGrad") @@ -140,4 +140,4 @@ REGISTER_KERNEL_BUILDER( Name("SoftMinVirialGrad").Device(DEVICE_CPU).TypeConstraint("T"), \ SoftMinVirialGradOp); REGISTER_CPU(float); -REGISTER_CPU(double); \ No newline at end of file +REGISTER_CPU(double); diff --git a/source/op/tab_inter.cc b/source/op/tab_inter.cc index 63c7af210c..7cef2ea5d7 100644 --- a/source/op/tab_inter.cc +++ b/source/op/tab_inter.cc @@ -4,7 +4,7 @@ #include using namespace tensorflow; -using namespace std; +//using namespace std; REGISTER_OP("TabInter") @@ -43,9 +43,9 @@ void tabulated_inter (double & ener, double r2 = dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2]; double rr = sqrt(r2); double uu = (rr - rmin) * hi; - // cout << rr << " " << rmin << " " << hh << " " << uu << endl; + // std::cout << rr << " " << rmin << " " << hh << " " << uu << std::endl; if (uu < 0) { - cerr << "coord go beyond table lower boundary" << endl; + std::cerr << "coord go beyond table lower boundary" << std::endl; exit(1); } int idx = uu; @@ -153,8 +153,8 @@ class TabInterOp : public OpKernel { int nspline = table_info(2)+0.1; int tab_stride = 4 * nspline; assert(ntypes * ntypes * tab_stride == table_data_tensor.shape().dim_size(0)); - vector d_table_info(4); - vector d_table_data(ntypes * ntypes * tab_stride); + std::vector d_table_info(4); + std::vector d_table_data(ntypes * ntypes * tab_stride); for (unsigned ii = 0; ii < d_table_info.size(); ++ii){ d_table_info[ii] = table_info(ii); } @@ -285,14 +285,14 @@ class TabInterOp : public OpKernel { } } private: - vector sel_r; - vector sel_a; - vector sec_a; - vector sec_r; + std::vector sel_r; + std::vector sel_a; + std::vector sec_a; + std::vector sec_r; int nnei, nnei_a, nnei_r; void - cum_sum (vector & sec, - const vector & n_sel) const { + cum_sum (std::vector & sec, + const std::vector & n_sel) const { sec.resize (n_sel.size() + 1); sec[0] = 0; for (int ii = 1; ii < sec.size(); ++ii){ From 283c04d27d6839e74cce0f43eaecf22edf3af220 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 19 Jan 2021 07:35:08 +0800 Subject: [PATCH 052/562] rm unnecessary file --- source/lib/include/RandomGenerator.h | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 source/lib/include/RandomGenerator.h diff --git a/source/lib/include/RandomGenerator.h b/source/lib/include/RandomGenerator.h deleted file mode 100644 index dea08c4683..0000000000 --- a/source/lib/include/RandomGenerator.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef __wanghan_ToolBox_h__ -#define __wanghan_ToolBox_h__ -#include - -typedef double value_type; - -namespace RandomGenerator_MT19937{ - void init_by_array(unsigned long init_key[], int key_length); - void init_genrand(unsigned long s); - unsigned long genrand_int32(void); - long genrand_int31(void); - double genrand_real1(void); // in [0,1] - double genrand_real2(void); // in [0,1) - double genrand_real3(void); // in (0,1) - double genrand_res53(void); - double gaussian (); // Box Muller - void sphere (double & x, double & y, double & z); -} - - - - -#endif From 22f99a644094fe550d394088124aefd3054b8029 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 20 Jan 2021 12:58:12 +0800 Subject: [PATCH 053/562] change 0 -> 0.0 when providing a float variable --- deepmd/loss/ener.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/deepmd/loss/ener.py b/deepmd/loss/ener.py index 2f628502d7..2762634378 100644 --- a/deepmd/loss/ener.py +++ b/deepmd/loss/ener.py @@ -15,12 +15,12 @@ def __init__ (self, limit_pref_e : float = 1.00, start_pref_f : float = 1000, limit_pref_f : float = 1.00, - start_pref_v : float = 0, - limit_pref_v : float = 0, - start_pref_ae : float = 0, - limit_pref_ae : float = 0, - start_pref_pf : float = 0, - limit_pref_pf : float = 0, + start_pref_v : float = 0.0, + limit_pref_v : float = 0.0, + start_pref_ae : float = 0.0, + limit_pref_ae : float = 0.0, + start_pref_pf : float = 0.0, + limit_pref_pf : float = 0.0, relative_f : float = None ) -> None: self.starter_learning_rate = starter_learning_rate @@ -35,11 +35,11 @@ def __init__ (self, self.start_pref_pf = start_pref_pf self.limit_pref_pf = limit_pref_pf self.relative_f = relative_f - self.has_e = (self.start_pref_e != 0 or self.limit_pref_e != 0) - self.has_f = (self.start_pref_f != 0 or self.limit_pref_f != 0) - self.has_v = (self.start_pref_v != 0 or self.limit_pref_v != 0) - self.has_ae = (self.start_pref_ae != 0 or self.limit_pref_ae != 0) - self.has_pf = (self.start_pref_pf != 0 or self.limit_pref_pf != 0) + self.has_e = (self.start_pref_e != 0.0 or self.limit_pref_e != 0.0) + self.has_f = (self.start_pref_f != 0.0 or self.limit_pref_f != 0.0) + self.has_v = (self.start_pref_v != 0.0 or self.limit_pref_v != 0.0) + self.has_ae = (self.start_pref_ae != 0.0 or self.limit_pref_ae != 0.0) + self.has_pf = (self.start_pref_pf != 0.0 or self.limit_pref_pf != 0.0) # data required add_data_requirement('energy', 1, atomic=False, must=False, high_prec=True) add_data_requirement('force', 3, atomic=True, must=False, high_prec=False) From f252c757cd538f7cd3c28dd0bed6f4a421220070 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Tue, 26 Jan 2021 12:46:00 +0800 Subject: [PATCH 054/562] fix bug of nbor sorting When the number of sel is smaller than the lammps nbors, the program may have a gpu sorting error. --- source/op/cuda/descrpt_se_a.cu | 95 +------------------------- source/op/cuda/descrpt_se_r.cu | 95 +------------------------- source/op/descrpt_se_a_multi_device.cc | 8 +-- source/op/descrpt_se_r_multi_device.cc | 8 +-- 4 files changed, 8 insertions(+), 198 deletions(-) diff --git a/source/op/cuda/descrpt_se_a.cu b/source/op/cuda/descrpt_se_a.cu index 5965254111..222c24ff49 100644 --- a/source/op/cuda/descrpt_se_a.cu +++ b/source/op/cuda/descrpt_se_a.cu @@ -228,73 +228,6 @@ __global__ void compute_descriptor_se_a (FPTYPE* descript, } } -template -void format_nbor_list_256 ( - const FPTYPE* coord, - const int* type, - const int* jrange, - const int* jlist, - const int& nloc, - const float& rcut_r, - int * i_idx, - int_64 * key -) -{ - const int LEN = 256; - const int MAGIC_NUMBER = 256; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; - dim3 block_grid(nloc, nblock); - dim3 thread_grid(1, LEN); - format_nlist_fill_a_se_a - <<>> ( - coord, - type, - jrange, - jlist, - rcut_r, - key, - i_idx, - MAGIC_NUMBER - ); - const int ITEMS_PER_THREAD = 4; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; - // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); -} - -template -void format_nbor_list_512 ( - const FPTYPE* coord, - const int* type, - const int* jrange, - const int* jlist, - const int& nloc, - const float& rcut_r, - int * i_idx, - int_64 * key -) -{ - const int LEN = 256; - const int MAGIC_NUMBER = 512; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; - dim3 block_grid(nloc, nblock); - dim3 thread_grid(1, LEN); - format_nlist_fill_a_se_a - <<>> ( - coord, - type, - jrange, - jlist, - rcut_r, - key, - i_idx, - MAGIC_NUMBER - ); - const int ITEMS_PER_THREAD = 4; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; - // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); -} template void format_nbor_list_1024 ( @@ -419,29 +352,7 @@ void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const // cudaProfilerStart(); get_i_idx_se_a<<>> (nloc, ilist, i_idx); - if (nnei <= 256) { - format_nbor_list_256 ( - coord, - type, - jrange, - jlist, - nloc, - rcut_r, - i_idx, - key - ); - } else if (nnei <= 512) { - format_nbor_list_512 ( - coord, - type, - jrange, - jlist, - nloc, - rcut_r, - i_idx, - key - ); - } else if (nnei <= 1024) { + if (MAGIC_NUMBER <= 1024) { format_nbor_list_1024 ( coord, type, @@ -452,7 +363,7 @@ void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const i_idx, key ); - } else if (nnei <= 2048) { + } else if (MAGIC_NUMBER <= 2048) { format_nbor_list_2048 ( coord, type, @@ -463,7 +374,7 @@ void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const i_idx, key ); - } else if (nnei <= 4096) { + } else if (MAGIC_NUMBER <= 4096) { format_nbor_list_4096 ( coord, type, diff --git a/source/op/cuda/descrpt_se_r.cu b/source/op/cuda/descrpt_se_r.cu index a65ba5887a..17e76daae2 100644 --- a/source/op/cuda/descrpt_se_r.cu +++ b/source/op/cuda/descrpt_se_r.cu @@ -210,73 +210,6 @@ __global__ void compute_descriptor_se_r (FPTYPE* descript, } } -template -void format_nbor_list_256 ( - const FPTYPE* coord, - const int* type, - const int* jrange, - const int* jlist, - const int& nloc, - const float& rcut_r, - int * i_idx, - int_64 * key -) -{ - const int LEN = 256; - const int MAGIC_NUMBER = 256; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; - dim3 block_grid(nloc, nblock); - dim3 thread_grid(1, LEN); - format_nlist_fill_a_se_r - <<>> ( - coord, - type, - jrange, - jlist, - rcut_r, - key, - i_idx, - MAGIC_NUMBER - ); - const int ITEMS_PER_THREAD = 4; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; - // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); -} - -template -void format_nbor_list_512 ( - const FPTYPE* coord, - const int* type, - const int* jrange, - const int* jlist, - const int& nloc, - const float& rcut_r, - int * i_idx, - int_64 * key -) -{ - const int LEN = 256; - const int MAGIC_NUMBER = 512; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; - dim3 block_grid(nloc, nblock); - dim3 thread_grid(1, LEN); - format_nlist_fill_a_se_r - <<>> ( - coord, - type, - jrange, - jlist, - rcut_r, - key, - i_idx, - MAGIC_NUMBER - ); - const int ITEMS_PER_THREAD = 4; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; - // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); -} template void format_nbor_list_1024 ( @@ -401,29 +334,7 @@ void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const // cudaProfilerStart(); get_i_idx_se_r<<>> (nloc, ilist, i_idx); - if (nnei <= 256) { - format_nbor_list_256 ( - coord, - type, - jrange, - jlist, - nloc, - rcut_r, - i_idx, - key - ); - } else if (nnei <= 512) { - format_nbor_list_512 ( - coord, - type, - jrange, - jlist, - nloc, - rcut_r, - i_idx, - key - ); - } else if (nnei <= 1024) { + if (MAGIC_NUMBER <= 1024) { format_nbor_list_1024 ( coord, type, @@ -434,7 +345,7 @@ void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const i_idx, key ); - } else if (nnei <= 2048) { + } else if (MAGIC_NUMBER <= 2048) { format_nbor_list_2048 ( coord, type, @@ -445,7 +356,7 @@ void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const i_idx, key ); - } else if (nnei <= 4096) { + } else if (MAGIC_NUMBER <= 4096) { format_nbor_list_4096 ( coord, type, diff --git a/source/op/descrpt_se_a_multi_device.cc b/source/op/descrpt_se_a_multi_device.cc index ae5e623171..914e611e2d 100644 --- a/source/op/descrpt_se_a_multi_device.cc +++ b/source/op/descrpt_se_a_multi_device.cc @@ -271,13 +271,7 @@ class DescrptSeAOp : public OpKernel { } int get_magic_number(int const nnei) { - if (nnei <= 256) { - return 256; - } - else if (nnei <= 512) { - return 512; - } - else if (nnei <= 1024) { + if (nnei <= 1024) { return 1024; } else if (nnei <= 2048) { diff --git a/source/op/descrpt_se_r_multi_device.cc b/source/op/descrpt_se_r_multi_device.cc index c5eaff616c..07a9618270 100644 --- a/source/op/descrpt_se_r_multi_device.cc +++ b/source/op/descrpt_se_r_multi_device.cc @@ -261,13 +261,7 @@ class DescrptSeROp : public OpKernel { } int get_magic_number(int const nnei) { - if (nnei <= 256) { - return 256; - } - else if (nnei <= 512) { - return 512; - } - else if (nnei <= 1024) { + if (nnei <= 1024) { return 1024; } else if (nnei <= 2048) { From aee92de11e282009a7699fef1e5b277dd12d950e Mon Sep 17 00:00:00 2001 From: denghuilu Date: Tue, 26 Jan 2021 17:07:05 +0800 Subject: [PATCH 055/562] use lammps max_nbor_size as the upper boundary of gpu sorting --- source/lib/include/CustomeOperation.h | 12 +++--- source/op/cuda/descrpt_se_a.cu | 54 +++++++++++++------------- source/op/cuda/descrpt_se_r.cu | 54 +++++++++++++------------- source/op/descrpt_se_a_multi_device.cc | 34 +++++++--------- source/op/descrpt_se_r_multi_device.cc | 35 +++++++---------- 5 files changed, 88 insertions(+), 101 deletions(-) diff --git a/source/lib/include/CustomeOperation.h b/source/lib/include/CustomeOperation.h index c446db8130..f7fd7c2496 100644 --- a/source/lib/include/CustomeOperation.h +++ b/source/lib/include/CustomeOperation.h @@ -169,7 +169,7 @@ void compute_descriptor_se_a_cpu ( } template -void DescrptSeACPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { +void DescrptSeACPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { // set & normalize coord std::vector d_coord3(nall * 3); for (int ii = 0; ii < nall; ++ii) { @@ -235,8 +235,8 @@ void DescrptSeACPULauncher(const FPTYPE * coord, const int * type, const int * i #if GOOGLE_CUDA template -void DescrptSeAGPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { - DescrptSeAGPUExecuteFunctor()(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); +void DescrptSeAGPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { + DescrptSeAGPUExecuteFunctor()(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); } #endif // GOOGLE_CUDA // ****************************************************************************** @@ -432,7 +432,7 @@ void compute_descriptor_se_r_cpu ( } template -void DescrptSeRCPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { +void DescrptSeRCPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { // set & normalize coord std::vector d_coord3(nall * 3); for (int ii = 0; ii < nall; ++ii) { @@ -498,8 +498,8 @@ void DescrptSeRCPULauncher(const FPTYPE * coord, const int * type, const int * i #if GOOGLE_CUDA template -void DescrptSeRGPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { - DescrptSeRGPUExecuteFunctor()(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); +void DescrptSeRGPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { + DescrptSeRGPUExecuteFunctor()(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); } #endif // GOOGLE_CUDA // ****************************************************************************** diff --git a/source/op/cuda/descrpt_se_a.cu b/source/op/cuda/descrpt_se_a.cu index 222c24ff49..a528c4c477 100644 --- a/source/op/cuda/descrpt_se_a.cu +++ b/source/op/cuda/descrpt_se_a.cu @@ -84,9 +84,9 @@ __global__ void format_nlist_fill_a_se_a(const FPTYPE * coord, const float rcut, int_64 * key, int * i_idx, - const int MAGIC_NUMBER) + const int MAX_NBOR_SIZE) { - // <<>> + // <<>> const unsigned int idx = blockIdx.x; const unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y; @@ -98,7 +98,7 @@ __global__ void format_nlist_fill_a_se_a(const FPTYPE * coord, const int * nei_idx = jlist + jrange[i_idx[idx]]; // dev_copy(nei_idx, &jlist[jrange[i_idx]], nsize); - int_64 * key_in = key + idx * MAGIC_NUMBER; + int_64 * key_in = key + idx * MAX_NBOR_SIZE; FPTYPE diff[3]; const int & j_idx = nei_idx[idy]; @@ -121,7 +121,7 @@ __global__ void format_nlist_fill_b_se_a(int * nlist, const int * sec_a, const int sec_a_size, int * nei_iter_dev, - const int MAGIC_NUMBER) + const int MAX_NBOR_SIZE) { const unsigned int idy = blockIdx.x * blockDim.x + threadIdx.x; @@ -132,13 +132,13 @@ __global__ void format_nlist_fill_b_se_a(int * nlist, int * row_nlist = nlist + idy * nlist_size; int * nei_iter = nei_iter_dev + idy * sec_a_size; - int_64 * key_out = key + nloc * MAGIC_NUMBER + idy * MAGIC_NUMBER; + int_64 * key_out = key + nloc * MAX_NBOR_SIZE + idy * MAX_NBOR_SIZE; for (int ii = 0; ii < sec_a_size; ii++) { nei_iter[ii] = sec_a[ii]; } - for (unsigned int kk = 0; key_out[kk] != key_out[MAGIC_NUMBER - 1]; kk++) { + for (unsigned int kk = 0; key_out[kk] != key_out[MAX_NBOR_SIZE - 1]; kk++) { const int & nei_type = key_out[kk] / 1E15; if (nei_iter[nei_type] < sec_a[nei_type + 1]) { row_nlist[nei_iter[nei_type]++] = key_out[kk] % 100000; @@ -242,8 +242,8 @@ void format_nbor_list_1024 ( ) { const int LEN = 256; - const int MAGIC_NUMBER = 1024; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; + const int MAX_NBOR_SIZE = 1024; + const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; dim3 block_grid(nloc, nblock); dim3 thread_grid(1, LEN); format_nlist_fill_a_se_a @@ -255,12 +255,12 @@ void format_nbor_list_1024 ( rcut_r, key, i_idx, - MAGIC_NUMBER + MAX_NBOR_SIZE ); const int ITEMS_PER_THREAD = 8; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; + const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); + BlockSortKernel <<>> (key, key + nloc * MAX_NBOR_SIZE); } template @@ -276,8 +276,8 @@ void format_nbor_list_2048 ( ) { const int LEN = 256; - const int MAGIC_NUMBER = 2048; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; + const int MAX_NBOR_SIZE = 2048; + const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; dim3 block_grid(nloc, nblock); dim3 thread_grid(1, LEN); format_nlist_fill_a_se_a @@ -289,12 +289,12 @@ void format_nbor_list_2048 ( rcut_r, key, i_idx, - MAGIC_NUMBER + MAX_NBOR_SIZE ); const int ITEMS_PER_THREAD = 8; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; + const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); + BlockSortKernel <<>> (key, key + nloc * MAX_NBOR_SIZE); } template @@ -310,8 +310,8 @@ void format_nbor_list_4096 ( ) { const int LEN = 256; - const int MAGIC_NUMBER = 4096; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; + const int MAX_NBOR_SIZE = 4096; + const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; dim3 block_grid(nloc, nblock); dim3 thread_grid(1, LEN); format_nlist_fill_a_se_a @@ -323,16 +323,16 @@ void format_nbor_list_4096 ( rcut_r, key, i_idx, - MAGIC_NUMBER + MAX_NBOR_SIZE ); const int ITEMS_PER_THREAD = 16; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; + const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); + BlockSortKernel <<>> (key, key + nloc * MAX_NBOR_SIZE); } template -void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descript, FPTYPE * descript_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int MAGIC_NUMBER) { +void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descript, FPTYPE * descript_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { const int LEN = 256; int nblock = (nloc + LEN -1) / LEN; int * sec_a_dev = array_int; @@ -342,7 +342,7 @@ void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const cudaError_t res = cudaSuccess; res = cudaMemcpy(sec_a_dev, &sec_a[0], sizeof(int) * sec_a.size(), cudaMemcpyHostToDevice); cudaErrcheck(res); - res = cudaMemset(key, 0xffffffff, sizeof(int_64) * nloc * MAGIC_NUMBER); cudaErrcheck(res); + res = cudaMemset(key, 0xffffffff, sizeof(int_64) * nloc * max_nbor_size); cudaErrcheck(res); res = cudaMemset(nlist, -1, sizeof(int) * nloc * nnei); cudaErrcheck(res); res = cudaMemset(descript, 0.0, sizeof(FPTYPE) * nloc * ndescrpt); cudaErrcheck(res); res = cudaMemset(descript_deriv, 0.0, sizeof(FPTYPE) * nloc * ndescrpt * 3); cudaErrcheck(res); @@ -352,7 +352,7 @@ void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const // cudaProfilerStart(); get_i_idx_se_a<<>> (nloc, ilist, i_idx); - if (MAGIC_NUMBER <= 1024) { + if (max_nbor_size <= 1024) { format_nbor_list_1024 ( coord, type, @@ -363,7 +363,7 @@ void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const i_idx, key ); - } else if (MAGIC_NUMBER <= 2048) { + } else if (max_nbor_size <= 2048) { format_nbor_list_2048 ( coord, type, @@ -374,7 +374,7 @@ void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const i_idx, key ); - } else if (MAGIC_NUMBER <= 4096) { + } else if (max_nbor_size <= 4096) { format_nbor_list_4096 ( coord, type, @@ -397,7 +397,7 @@ void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const sec_a_dev, sec_a.size(), nei_iter, - MAGIC_NUMBER + max_nbor_size ); } diff --git a/source/op/cuda/descrpt_se_r.cu b/source/op/cuda/descrpt_se_r.cu index 17e76daae2..0715f19c5e 100644 --- a/source/op/cuda/descrpt_se_r.cu +++ b/source/op/cuda/descrpt_se_r.cu @@ -84,9 +84,9 @@ __global__ void format_nlist_fill_a_se_r(const FPTYPE * coord, const float rcut, int_64 * key, int * i_idx, - const int MAGIC_NUMBER) + const int MAX_NBOR_SIZE) { - // <<>> + // <<>> const unsigned int idx = blockIdx.x; const unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y; @@ -98,7 +98,7 @@ __global__ void format_nlist_fill_a_se_r(const FPTYPE * coord, const int * nei_idx = jlist + jrange[i_idx[idx]]; // dev_copy(nei_idx, &jlist[jrange[i_idx]], nsize); - int_64 * key_in = key + idx * MAGIC_NUMBER; + int_64 * key_in = key + idx * MAX_NBOR_SIZE; FPTYPE diff[3]; const int & j_idx = nei_idx[idy]; @@ -121,7 +121,7 @@ __global__ void format_nlist_fill_b_se_r(int * nlist, const int * sec_a, const int sec_a_size, int * nei_iter_dev, - const int MAGIC_NUMBER) + const int MAX_NBOR_SIZE) { const unsigned int idy = blockIdx.x * blockDim.x + threadIdx.x; @@ -132,13 +132,13 @@ __global__ void format_nlist_fill_b_se_r(int * nlist, int * row_nlist = nlist + idy * nlist_size; int * nei_iter = nei_iter_dev + idy * sec_a_size; - int_64 * key_out = key + nloc * MAGIC_NUMBER + idy * MAGIC_NUMBER; + int_64 * key_out = key + nloc * MAX_NBOR_SIZE + idy * MAX_NBOR_SIZE; for (int ii = 0; ii < sec_a_size; ii++) { nei_iter[ii] = sec_a[ii]; } - for (unsigned int kk = 0; key_out[kk] != key_out[MAGIC_NUMBER - 1]; kk++) { + for (unsigned int kk = 0; key_out[kk] != key_out[MAX_NBOR_SIZE - 1]; kk++) { const int & nei_type = key_out[kk] / 1E15; if (nei_iter[nei_type] < sec_a[nei_type + 1]) { row_nlist[nei_iter[nei_type]++] = key_out[kk] % 100000; @@ -224,8 +224,8 @@ void format_nbor_list_1024 ( ) { const int LEN = 256; - const int MAGIC_NUMBER = 1024; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; + const int MAX_NBOR_SIZE = 1024; + const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; dim3 block_grid(nloc, nblock); dim3 thread_grid(1, LEN); format_nlist_fill_a_se_r @@ -237,12 +237,12 @@ void format_nbor_list_1024 ( rcut_r, key, i_idx, - MAGIC_NUMBER + MAX_NBOR_SIZE ); const int ITEMS_PER_THREAD = 8; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; + const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); + BlockSortKernel <<>> (key, key + nloc * MAX_NBOR_SIZE); } template @@ -258,8 +258,8 @@ void format_nbor_list_2048 ( ) { const int LEN = 256; - const int MAGIC_NUMBER = 2048; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; + const int MAX_NBOR_SIZE = 2048; + const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; dim3 block_grid(nloc, nblock); dim3 thread_grid(1, LEN); format_nlist_fill_a_se_r @@ -271,12 +271,12 @@ void format_nbor_list_2048 ( rcut_r, key, i_idx, - MAGIC_NUMBER + MAX_NBOR_SIZE ); const int ITEMS_PER_THREAD = 8; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; + const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); + BlockSortKernel <<>> (key, key + nloc * MAX_NBOR_SIZE); } template @@ -292,8 +292,8 @@ void format_nbor_list_4096 ( ) { const int LEN = 256; - const int MAGIC_NUMBER = 4096; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; + const int MAX_NBOR_SIZE = 4096; + const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; dim3 block_grid(nloc, nblock); dim3 thread_grid(1, LEN); format_nlist_fill_a_se_r @@ -305,16 +305,16 @@ void format_nbor_list_4096 ( rcut_r, key, i_idx, - MAGIC_NUMBER + MAX_NBOR_SIZE ); const int ITEMS_PER_THREAD = 16; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; + const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); + BlockSortKernel <<>> (key, key + nloc * MAX_NBOR_SIZE); } template -void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descript, FPTYPE * descript_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int MAGIC_NUMBER) { +void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descript, FPTYPE * descript_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { const int LEN = 256; int nblock = (nloc + LEN -1) / LEN; int * sec_a_dev = array_int; @@ -324,7 +324,7 @@ void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const cudaError_t res = cudaSuccess; res = cudaMemcpy(sec_a_dev, &sec_a[0], sizeof(int) * sec_a.size(), cudaMemcpyHostToDevice); cudaErrcheck(res); - res = cudaMemset(key, 0xffffffff, sizeof(int_64) * nloc * MAGIC_NUMBER); cudaErrcheck(res); + res = cudaMemset(key, 0xffffffff, sizeof(int_64) * nloc * max_nbor_size); cudaErrcheck(res); res = cudaMemset(nlist, -1, sizeof(int) * nloc * nnei); cudaErrcheck(res); res = cudaMemset(descript, 0.0, sizeof(FPTYPE) * nloc * ndescrpt); cudaErrcheck(res); res = cudaMemset(descript_deriv, 0.0, sizeof(FPTYPE) * nloc * ndescrpt * 3); cudaErrcheck(res); @@ -334,7 +334,7 @@ void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const // cudaProfilerStart(); get_i_idx_se_r<<>> (nloc, ilist, i_idx); - if (MAGIC_NUMBER <= 1024) { + if (max_nbor_size <= 1024) { format_nbor_list_1024 ( coord, type, @@ -345,7 +345,7 @@ void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const i_idx, key ); - } else if (MAGIC_NUMBER <= 2048) { + } else if (max_nbor_size <= 2048) { format_nbor_list_2048 ( coord, type, @@ -356,7 +356,7 @@ void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const i_idx, key ); - } else if (MAGIC_NUMBER <= 4096) { + } else if (max_nbor_size <= 4096) { format_nbor_list_4096 ( coord, type, @@ -379,7 +379,7 @@ void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const sec_a_dev, sec_a.size(), nei_iter, - MAGIC_NUMBER + max_nbor_size ); } diff --git a/source/op/descrpt_se_a_multi_device.cc b/source/op/descrpt_se_a_multi_device.cc index 914e611e2d..62676c56a3 100644 --- a/source/op/descrpt_se_a_multi_device.cc +++ b/source/op/descrpt_se_a_multi_device.cc @@ -34,13 +34,13 @@ struct DeviceFunctor { template struct DescrptSeAFunctor { - void operator()(const CPUDevice& d, const FPTYPE * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { - DescrptSeACPULauncher(coord, type, ilist, jrange, jlist, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ntypes, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); + void operator()(const CPUDevice& d, const FPTYPE * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { + DescrptSeACPULauncher(coord, type, ilist, jrange, jlist, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ntypes, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); } #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const FPTYPE * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { - DescrptSeAGPULauncher(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); + void operator()(const GPUDevice& d, const FPTYPE * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { + DescrptSeAGPULauncher(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); } #endif // GOOGLE_CUDA }; @@ -66,7 +66,7 @@ class DescrptSeAOp : public OpKernel { nnei_r = sec_r.back(); nnei = nnei_a + nnei_r; fill_nei_a = (rcut_a < 0); - magic_number = get_magic_number(nnei); + max_nbor_size = 1024; } void Compute(OpKernelContext* context) override { @@ -117,7 +117,6 @@ class DescrptSeAOp : public OpKernel { OP_REQUIRES (context, (ntypes == int(sel_a.size())), errors::InvalidArgument ("number of types should match the length of sel array")); OP_REQUIRES (context, (ntypes == int(sel_r.size())), errors::InvalidArgument ("number of types should match the length of sel array")); - OP_REQUIRES (context, (nnei <= 4096), errors::InvalidArgument ("Assert failed, max neighbor size of atom(nnei) " + std::to_string(nnei) + " is larger than 4096, which currently is not supported by deepmd-kit.")); // Create output tensors TensorShape descrpt_shape ; @@ -159,13 +158,14 @@ class DescrptSeAOp : public OpKernel { OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); Tensor uint64_temp; TensorShape uint64_shape; - uint64_shape.AddDim(nloc * magic_number * 2); + uint64_shape.AddDim(nloc * max_nbor_size * 2); OP_REQUIRES_OK(context, context->allocate_temp(DT_UINT64, uint64_shape, &uint64_temp)); array_int = int_temp.flat().data(); array_longlong = uint64_temp.flat().data(); nbor_update(mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); + OP_REQUIRES (context, (max_nbor_size <= 4096), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than 4096, which currently is not supported by deepmd-kit.")); } else if (device == "CPU") { memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); @@ -198,7 +198,7 @@ class DescrptSeAOp : public OpKernel { rcut_r_smth, sec_a, fill_nei_a, - magic_number + max_nbor_size ); } @@ -212,7 +212,7 @@ class DescrptSeAOp : public OpKernel { std::vector sec_a; std::vector sec_r; int ndescrpt, ndescrpt_a, ndescrpt_r; - int nnei, nnei_a, nnei_r, nloc, nall, magic_number; + int nnei, nnei_a, nnei_r, nloc, nall, max_nbor_size; bool fill_nei_a; //private func @@ -266,21 +266,15 @@ class DescrptSeAOp : public OpKernel { cudaErrcheck(cudaMemcpy(ilist, ilist_host, sizeof(int) * mesh_host[1], cudaMemcpyHostToDevice)); cudaErrcheck(cudaMemcpy(jrange, jrange_host, sizeof(int) * mesh_host[2], cudaMemcpyHostToDevice)); cudaErrcheck(cudaMemcpy(jlist, jlist_host, sizeof(int) * mesh_host[3], cudaMemcpyHostToDevice)); + + max_nbor_size = 1024; + for(int ii = 0; ii < mesh_host[2] - 1; ii++) { + max_nbor_size = (jrange_host[ii + 1] - jrange_host[ii]) > max_nbor_size ? (jrange_host[ii + 1] - jrange_host[ii]) : max_nbor_size; + } } delete [] mesh_host; } - int get_magic_number(int const nnei) { - if (nnei <= 1024) { - return 1024; - } - else if (nnei <= 2048) { - return 2048; - } - else if (nnei <= 4096) { - return 4096; - } - } }; // Register the CPU kernels. diff --git a/source/op/descrpt_se_r_multi_device.cc b/source/op/descrpt_se_r_multi_device.cc index 07a9618270..ba2ec377b7 100644 --- a/source/op/descrpt_se_r_multi_device.cc +++ b/source/op/descrpt_se_r_multi_device.cc @@ -31,13 +31,13 @@ struct DeviceFunctor { template struct DescrptSeRFunctor { - void operator()(const CPUDevice& d, const T * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const T * avg, const T * std, T * descrpt, T * descrpt_deriv, T * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { - DescrptSeRCPULauncher(coord, type, ilist, jrange, jlist, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ntypes, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); + void operator()(const CPUDevice& d, const T * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const T * avg, const T * std, T * descrpt, T * descrpt_deriv, T * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { + DescrptSeRCPULauncher(coord, type, ilist, jrange, jlist, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ntypes, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); } #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const T * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const T * avg, const T * std, T * descrpt, T * descrpt_deriv, T * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { - DescrptSeRGPULauncher(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); + void operator()(const GPUDevice& d, const T * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const T * avg, const T * std, T * descrpt, T * descrpt_deriv, T * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { + DescrptSeRGPULauncher(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); } #endif // GOOGLE_CUDA }; @@ -55,9 +55,7 @@ class DescrptSeROp : public OpKernel { ndescrpt = sec.back() * 1; nnei = sec.back(); fill_nei_a = true; - magic_number = get_magic_number(nnei); - // count_nei_idx_overflow = 0; - // std::cout << "I'm in descrpt_se_r_gpu.cc" << std::endl; + max_nbor_size = 1024; } void Compute(OpKernelContext* context) override { @@ -149,13 +147,14 @@ class DescrptSeROp : public OpKernel { OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); Tensor uint64_temp; TensorShape uint64_shape; - uint64_shape.AddDim(nloc * magic_number * 2); + uint64_shape.AddDim(nloc * max_nbor_size * 2); OP_REQUIRES_OK(context, context->allocate_temp(DT_UINT64, uint64_shape, &uint64_temp)); array_int = int_temp.flat().data(); array_longlong = uint64_temp.flat().data(); nbor_update(mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); + OP_REQUIRES (context, (max_nbor_size <= 4096), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than 4096, which currently is not supported by deepmd-kit.")); } else if (device == "CPU") { memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); @@ -188,7 +187,7 @@ class DescrptSeROp : public OpKernel { rcut_smth, sec, fill_nei_a, - magic_number + max_nbor_size ); } @@ -213,7 +212,7 @@ class DescrptSeROp : public OpKernel { } } - int magic_number; + int max_nbor_size; std::string device; int *array_int; unsigned long long*array_longlong; @@ -256,21 +255,15 @@ class DescrptSeROp : public OpKernel { cudaErrcheck(cudaMemcpy(ilist, ilist_host, sizeof(int) * mesh_host[1], cudaMemcpyHostToDevice)); cudaErrcheck(cudaMemcpy(jrange, jrange_host, sizeof(int) * mesh_host[2], cudaMemcpyHostToDevice)); cudaErrcheck(cudaMemcpy(jlist, jlist_host, sizeof(int) * mesh_host[3], cudaMemcpyHostToDevice)); + + max_nbor_size = 1024; + for(int ii = 0; ii < mesh_host[2] - 1; ii++) { + max_nbor_size = (jrange_host[ii + 1] - jrange_host[ii]) > max_nbor_size ? (jrange_host[ii + 1] - jrange_host[ii]) : max_nbor_size; + } } delete [] mesh_host; } - int get_magic_number(int const nnei) { - if (nnei <= 1024) { - return 1024; - } - else if (nnei <= 2048) { - return 2048; - } - else if (nnei <= 4096) { - return 4096; - } - } }; // Register the CPU kernels. From 9a39df93b89c882c04530de125d2da27629ffb9e Mon Sep 17 00:00:00 2001 From: denghuilu Date: Wed, 27 Jan 2021 11:37:59 +0800 Subject: [PATCH 056/562] fix a potential bug --- source/op/descrpt_se_a_multi_device.cc | 2 +- source/op/descrpt_se_r_multi_device.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/op/descrpt_se_a_multi_device.cc b/source/op/descrpt_se_a_multi_device.cc index 62676c56a3..93e2cdccac 100644 --- a/source/op/descrpt_se_a_multi_device.cc +++ b/source/op/descrpt_se_a_multi_device.cc @@ -268,7 +268,7 @@ class DescrptSeAOp : public OpKernel { cudaErrcheck(cudaMemcpy(jlist, jlist_host, sizeof(int) * mesh_host[3], cudaMemcpyHostToDevice)); max_nbor_size = 1024; - for(int ii = 0; ii < mesh_host[2] - 1; ii++) { + for(int ii = 0; ii < mesh_host[2]; ii++) { max_nbor_size = (jrange_host[ii + 1] - jrange_host[ii]) > max_nbor_size ? (jrange_host[ii + 1] - jrange_host[ii]) : max_nbor_size; } } diff --git a/source/op/descrpt_se_r_multi_device.cc b/source/op/descrpt_se_r_multi_device.cc index ba2ec377b7..b94f97d6e1 100644 --- a/source/op/descrpt_se_r_multi_device.cc +++ b/source/op/descrpt_se_r_multi_device.cc @@ -257,7 +257,7 @@ class DescrptSeROp : public OpKernel { cudaErrcheck(cudaMemcpy(jlist, jlist_host, sizeof(int) * mesh_host[3], cudaMemcpyHostToDevice)); max_nbor_size = 1024; - for(int ii = 0; ii < mesh_host[2] - 1; ii++) { + for(int ii = 0; ii < mesh_host[2]; ii++) { max_nbor_size = (jrange_host[ii + 1] - jrange_host[ii]) > max_nbor_size ? (jrange_host[ii + 1] - jrange_host[ii]) : max_nbor_size; } } From ff10780fb20e46b34dcdf5a965f5b0b31cf70cce Mon Sep 17 00:00:00 2001 From: denghuilu Date: Tue, 26 Jan 2021 12:46:00 +0800 Subject: [PATCH 057/562] fix bug of nbor sorting When the number of sel is smaller than the lammps nbors, the program may have a gpu sorting error. --- source/op/cuda/descrpt_se_a.cu | 95 +------------------------- source/op/cuda/descrpt_se_r.cu | 95 +------------------------- source/op/descrpt_se_a_multi_device.cc | 8 +-- source/op/descrpt_se_r_multi_device.cc | 8 +-- 4 files changed, 8 insertions(+), 198 deletions(-) diff --git a/source/op/cuda/descrpt_se_a.cu b/source/op/cuda/descrpt_se_a.cu index 5965254111..222c24ff49 100644 --- a/source/op/cuda/descrpt_se_a.cu +++ b/source/op/cuda/descrpt_se_a.cu @@ -228,73 +228,6 @@ __global__ void compute_descriptor_se_a (FPTYPE* descript, } } -template -void format_nbor_list_256 ( - const FPTYPE* coord, - const int* type, - const int* jrange, - const int* jlist, - const int& nloc, - const float& rcut_r, - int * i_idx, - int_64 * key -) -{ - const int LEN = 256; - const int MAGIC_NUMBER = 256; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; - dim3 block_grid(nloc, nblock); - dim3 thread_grid(1, LEN); - format_nlist_fill_a_se_a - <<>> ( - coord, - type, - jrange, - jlist, - rcut_r, - key, - i_idx, - MAGIC_NUMBER - ); - const int ITEMS_PER_THREAD = 4; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; - // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); -} - -template -void format_nbor_list_512 ( - const FPTYPE* coord, - const int* type, - const int* jrange, - const int* jlist, - const int& nloc, - const float& rcut_r, - int * i_idx, - int_64 * key -) -{ - const int LEN = 256; - const int MAGIC_NUMBER = 512; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; - dim3 block_grid(nloc, nblock); - dim3 thread_grid(1, LEN); - format_nlist_fill_a_se_a - <<>> ( - coord, - type, - jrange, - jlist, - rcut_r, - key, - i_idx, - MAGIC_NUMBER - ); - const int ITEMS_PER_THREAD = 4; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; - // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); -} template void format_nbor_list_1024 ( @@ -419,29 +352,7 @@ void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const // cudaProfilerStart(); get_i_idx_se_a<<>> (nloc, ilist, i_idx); - if (nnei <= 256) { - format_nbor_list_256 ( - coord, - type, - jrange, - jlist, - nloc, - rcut_r, - i_idx, - key - ); - } else if (nnei <= 512) { - format_nbor_list_512 ( - coord, - type, - jrange, - jlist, - nloc, - rcut_r, - i_idx, - key - ); - } else if (nnei <= 1024) { + if (MAGIC_NUMBER <= 1024) { format_nbor_list_1024 ( coord, type, @@ -452,7 +363,7 @@ void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const i_idx, key ); - } else if (nnei <= 2048) { + } else if (MAGIC_NUMBER <= 2048) { format_nbor_list_2048 ( coord, type, @@ -463,7 +374,7 @@ void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const i_idx, key ); - } else if (nnei <= 4096) { + } else if (MAGIC_NUMBER <= 4096) { format_nbor_list_4096 ( coord, type, diff --git a/source/op/cuda/descrpt_se_r.cu b/source/op/cuda/descrpt_se_r.cu index a65ba5887a..17e76daae2 100644 --- a/source/op/cuda/descrpt_se_r.cu +++ b/source/op/cuda/descrpt_se_r.cu @@ -210,73 +210,6 @@ __global__ void compute_descriptor_se_r (FPTYPE* descript, } } -template -void format_nbor_list_256 ( - const FPTYPE* coord, - const int* type, - const int* jrange, - const int* jlist, - const int& nloc, - const float& rcut_r, - int * i_idx, - int_64 * key -) -{ - const int LEN = 256; - const int MAGIC_NUMBER = 256; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; - dim3 block_grid(nloc, nblock); - dim3 thread_grid(1, LEN); - format_nlist_fill_a_se_r - <<>> ( - coord, - type, - jrange, - jlist, - rcut_r, - key, - i_idx, - MAGIC_NUMBER - ); - const int ITEMS_PER_THREAD = 4; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; - // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); -} - -template -void format_nbor_list_512 ( - const FPTYPE* coord, - const int* type, - const int* jrange, - const int* jlist, - const int& nloc, - const float& rcut_r, - int * i_idx, - int_64 * key -) -{ - const int LEN = 256; - const int MAGIC_NUMBER = 512; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; - dim3 block_grid(nloc, nblock); - dim3 thread_grid(1, LEN); - format_nlist_fill_a_se_r - <<>> ( - coord, - type, - jrange, - jlist, - rcut_r, - key, - i_idx, - MAGIC_NUMBER - ); - const int ITEMS_PER_THREAD = 4; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; - // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); -} template void format_nbor_list_1024 ( @@ -401,29 +334,7 @@ void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const // cudaProfilerStart(); get_i_idx_se_r<<>> (nloc, ilist, i_idx); - if (nnei <= 256) { - format_nbor_list_256 ( - coord, - type, - jrange, - jlist, - nloc, - rcut_r, - i_idx, - key - ); - } else if (nnei <= 512) { - format_nbor_list_512 ( - coord, - type, - jrange, - jlist, - nloc, - rcut_r, - i_idx, - key - ); - } else if (nnei <= 1024) { + if (MAGIC_NUMBER <= 1024) { format_nbor_list_1024 ( coord, type, @@ -434,7 +345,7 @@ void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const i_idx, key ); - } else if (nnei <= 2048) { + } else if (MAGIC_NUMBER <= 2048) { format_nbor_list_2048 ( coord, type, @@ -445,7 +356,7 @@ void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const i_idx, key ); - } else if (nnei <= 4096) { + } else if (MAGIC_NUMBER <= 4096) { format_nbor_list_4096 ( coord, type, diff --git a/source/op/descrpt_se_a_multi_device.cc b/source/op/descrpt_se_a_multi_device.cc index f5888faecd..2ef5083708 100644 --- a/source/op/descrpt_se_a_multi_device.cc +++ b/source/op/descrpt_se_a_multi_device.cc @@ -271,13 +271,7 @@ class DescrptSeAOp : public OpKernel { } int get_magic_number(int const nnei) { - if (nnei <= 256) { - return 256; - } - else if (nnei <= 512) { - return 512; - } - else if (nnei <= 1024) { + if (nnei <= 1024) { return 1024; } else if (nnei <= 2048) { diff --git a/source/op/descrpt_se_r_multi_device.cc b/source/op/descrpt_se_r_multi_device.cc index cf620069a5..1d9a06cdcd 100644 --- a/source/op/descrpt_se_r_multi_device.cc +++ b/source/op/descrpt_se_r_multi_device.cc @@ -261,13 +261,7 @@ class DescrptSeROp : public OpKernel { } int get_magic_number(int const nnei) { - if (nnei <= 256) { - return 256; - } - else if (nnei <= 512) { - return 512; - } - else if (nnei <= 1024) { + if (nnei <= 1024) { return 1024; } else if (nnei <= 2048) { From b23d6699760db275ba4d1946c0268ea8f8d628c9 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Tue, 26 Jan 2021 17:07:05 +0800 Subject: [PATCH 058/562] fix conflicts of cherry-pick --- source/lib/include/CustomeOperation.h | 12 +++--- source/op/cuda/descrpt_se_a.cu | 54 +++++++++++++------------- source/op/cuda/descrpt_se_r.cu | 54 +++++++++++++------------- source/op/descrpt_se_a_multi_device.cc | 34 +++++++--------- source/op/descrpt_se_r_multi_device.cc | 35 +++++++---------- 5 files changed, 88 insertions(+), 101 deletions(-) diff --git a/source/lib/include/CustomeOperation.h b/source/lib/include/CustomeOperation.h index c446db8130..f7fd7c2496 100644 --- a/source/lib/include/CustomeOperation.h +++ b/source/lib/include/CustomeOperation.h @@ -169,7 +169,7 @@ void compute_descriptor_se_a_cpu ( } template -void DescrptSeACPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { +void DescrptSeACPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { // set & normalize coord std::vector d_coord3(nall * 3); for (int ii = 0; ii < nall; ++ii) { @@ -235,8 +235,8 @@ void DescrptSeACPULauncher(const FPTYPE * coord, const int * type, const int * i #if GOOGLE_CUDA template -void DescrptSeAGPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { - DescrptSeAGPUExecuteFunctor()(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); +void DescrptSeAGPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { + DescrptSeAGPUExecuteFunctor()(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); } #endif // GOOGLE_CUDA // ****************************************************************************** @@ -432,7 +432,7 @@ void compute_descriptor_se_r_cpu ( } template -void DescrptSeRCPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { +void DescrptSeRCPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { // set & normalize coord std::vector d_coord3(nall * 3); for (int ii = 0; ii < nall; ++ii) { @@ -498,8 +498,8 @@ void DescrptSeRCPULauncher(const FPTYPE * coord, const int * type, const int * i #if GOOGLE_CUDA template -void DescrptSeRGPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { - DescrptSeRGPUExecuteFunctor()(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); +void DescrptSeRGPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { + DescrptSeRGPUExecuteFunctor()(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); } #endif // GOOGLE_CUDA // ****************************************************************************** diff --git a/source/op/cuda/descrpt_se_a.cu b/source/op/cuda/descrpt_se_a.cu index 222c24ff49..a528c4c477 100644 --- a/source/op/cuda/descrpt_se_a.cu +++ b/source/op/cuda/descrpt_se_a.cu @@ -84,9 +84,9 @@ __global__ void format_nlist_fill_a_se_a(const FPTYPE * coord, const float rcut, int_64 * key, int * i_idx, - const int MAGIC_NUMBER) + const int MAX_NBOR_SIZE) { - // <<>> + // <<>> const unsigned int idx = blockIdx.x; const unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y; @@ -98,7 +98,7 @@ __global__ void format_nlist_fill_a_se_a(const FPTYPE * coord, const int * nei_idx = jlist + jrange[i_idx[idx]]; // dev_copy(nei_idx, &jlist[jrange[i_idx]], nsize); - int_64 * key_in = key + idx * MAGIC_NUMBER; + int_64 * key_in = key + idx * MAX_NBOR_SIZE; FPTYPE diff[3]; const int & j_idx = nei_idx[idy]; @@ -121,7 +121,7 @@ __global__ void format_nlist_fill_b_se_a(int * nlist, const int * sec_a, const int sec_a_size, int * nei_iter_dev, - const int MAGIC_NUMBER) + const int MAX_NBOR_SIZE) { const unsigned int idy = blockIdx.x * blockDim.x + threadIdx.x; @@ -132,13 +132,13 @@ __global__ void format_nlist_fill_b_se_a(int * nlist, int * row_nlist = nlist + idy * nlist_size; int * nei_iter = nei_iter_dev + idy * sec_a_size; - int_64 * key_out = key + nloc * MAGIC_NUMBER + idy * MAGIC_NUMBER; + int_64 * key_out = key + nloc * MAX_NBOR_SIZE + idy * MAX_NBOR_SIZE; for (int ii = 0; ii < sec_a_size; ii++) { nei_iter[ii] = sec_a[ii]; } - for (unsigned int kk = 0; key_out[kk] != key_out[MAGIC_NUMBER - 1]; kk++) { + for (unsigned int kk = 0; key_out[kk] != key_out[MAX_NBOR_SIZE - 1]; kk++) { const int & nei_type = key_out[kk] / 1E15; if (nei_iter[nei_type] < sec_a[nei_type + 1]) { row_nlist[nei_iter[nei_type]++] = key_out[kk] % 100000; @@ -242,8 +242,8 @@ void format_nbor_list_1024 ( ) { const int LEN = 256; - const int MAGIC_NUMBER = 1024; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; + const int MAX_NBOR_SIZE = 1024; + const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; dim3 block_grid(nloc, nblock); dim3 thread_grid(1, LEN); format_nlist_fill_a_se_a @@ -255,12 +255,12 @@ void format_nbor_list_1024 ( rcut_r, key, i_idx, - MAGIC_NUMBER + MAX_NBOR_SIZE ); const int ITEMS_PER_THREAD = 8; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; + const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); + BlockSortKernel <<>> (key, key + nloc * MAX_NBOR_SIZE); } template @@ -276,8 +276,8 @@ void format_nbor_list_2048 ( ) { const int LEN = 256; - const int MAGIC_NUMBER = 2048; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; + const int MAX_NBOR_SIZE = 2048; + const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; dim3 block_grid(nloc, nblock); dim3 thread_grid(1, LEN); format_nlist_fill_a_se_a @@ -289,12 +289,12 @@ void format_nbor_list_2048 ( rcut_r, key, i_idx, - MAGIC_NUMBER + MAX_NBOR_SIZE ); const int ITEMS_PER_THREAD = 8; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; + const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); + BlockSortKernel <<>> (key, key + nloc * MAX_NBOR_SIZE); } template @@ -310,8 +310,8 @@ void format_nbor_list_4096 ( ) { const int LEN = 256; - const int MAGIC_NUMBER = 4096; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; + const int MAX_NBOR_SIZE = 4096; + const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; dim3 block_grid(nloc, nblock); dim3 thread_grid(1, LEN); format_nlist_fill_a_se_a @@ -323,16 +323,16 @@ void format_nbor_list_4096 ( rcut_r, key, i_idx, - MAGIC_NUMBER + MAX_NBOR_SIZE ); const int ITEMS_PER_THREAD = 16; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; + const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); + BlockSortKernel <<>> (key, key + nloc * MAX_NBOR_SIZE); } template -void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descript, FPTYPE * descript_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int MAGIC_NUMBER) { +void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descript, FPTYPE * descript_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { const int LEN = 256; int nblock = (nloc + LEN -1) / LEN; int * sec_a_dev = array_int; @@ -342,7 +342,7 @@ void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const cudaError_t res = cudaSuccess; res = cudaMemcpy(sec_a_dev, &sec_a[0], sizeof(int) * sec_a.size(), cudaMemcpyHostToDevice); cudaErrcheck(res); - res = cudaMemset(key, 0xffffffff, sizeof(int_64) * nloc * MAGIC_NUMBER); cudaErrcheck(res); + res = cudaMemset(key, 0xffffffff, sizeof(int_64) * nloc * max_nbor_size); cudaErrcheck(res); res = cudaMemset(nlist, -1, sizeof(int) * nloc * nnei); cudaErrcheck(res); res = cudaMemset(descript, 0.0, sizeof(FPTYPE) * nloc * ndescrpt); cudaErrcheck(res); res = cudaMemset(descript_deriv, 0.0, sizeof(FPTYPE) * nloc * ndescrpt * 3); cudaErrcheck(res); @@ -352,7 +352,7 @@ void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const // cudaProfilerStart(); get_i_idx_se_a<<>> (nloc, ilist, i_idx); - if (MAGIC_NUMBER <= 1024) { + if (max_nbor_size <= 1024) { format_nbor_list_1024 ( coord, type, @@ -363,7 +363,7 @@ void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const i_idx, key ); - } else if (MAGIC_NUMBER <= 2048) { + } else if (max_nbor_size <= 2048) { format_nbor_list_2048 ( coord, type, @@ -374,7 +374,7 @@ void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const i_idx, key ); - } else if (MAGIC_NUMBER <= 4096) { + } else if (max_nbor_size <= 4096) { format_nbor_list_4096 ( coord, type, @@ -397,7 +397,7 @@ void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const sec_a_dev, sec_a.size(), nei_iter, - MAGIC_NUMBER + max_nbor_size ); } diff --git a/source/op/cuda/descrpt_se_r.cu b/source/op/cuda/descrpt_se_r.cu index 17e76daae2..0715f19c5e 100644 --- a/source/op/cuda/descrpt_se_r.cu +++ b/source/op/cuda/descrpt_se_r.cu @@ -84,9 +84,9 @@ __global__ void format_nlist_fill_a_se_r(const FPTYPE * coord, const float rcut, int_64 * key, int * i_idx, - const int MAGIC_NUMBER) + const int MAX_NBOR_SIZE) { - // <<>> + // <<>> const unsigned int idx = blockIdx.x; const unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y; @@ -98,7 +98,7 @@ __global__ void format_nlist_fill_a_se_r(const FPTYPE * coord, const int * nei_idx = jlist + jrange[i_idx[idx]]; // dev_copy(nei_idx, &jlist[jrange[i_idx]], nsize); - int_64 * key_in = key + idx * MAGIC_NUMBER; + int_64 * key_in = key + idx * MAX_NBOR_SIZE; FPTYPE diff[3]; const int & j_idx = nei_idx[idy]; @@ -121,7 +121,7 @@ __global__ void format_nlist_fill_b_se_r(int * nlist, const int * sec_a, const int sec_a_size, int * nei_iter_dev, - const int MAGIC_NUMBER) + const int MAX_NBOR_SIZE) { const unsigned int idy = blockIdx.x * blockDim.x + threadIdx.x; @@ -132,13 +132,13 @@ __global__ void format_nlist_fill_b_se_r(int * nlist, int * row_nlist = nlist + idy * nlist_size; int * nei_iter = nei_iter_dev + idy * sec_a_size; - int_64 * key_out = key + nloc * MAGIC_NUMBER + idy * MAGIC_NUMBER; + int_64 * key_out = key + nloc * MAX_NBOR_SIZE + idy * MAX_NBOR_SIZE; for (int ii = 0; ii < sec_a_size; ii++) { nei_iter[ii] = sec_a[ii]; } - for (unsigned int kk = 0; key_out[kk] != key_out[MAGIC_NUMBER - 1]; kk++) { + for (unsigned int kk = 0; key_out[kk] != key_out[MAX_NBOR_SIZE - 1]; kk++) { const int & nei_type = key_out[kk] / 1E15; if (nei_iter[nei_type] < sec_a[nei_type + 1]) { row_nlist[nei_iter[nei_type]++] = key_out[kk] % 100000; @@ -224,8 +224,8 @@ void format_nbor_list_1024 ( ) { const int LEN = 256; - const int MAGIC_NUMBER = 1024; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; + const int MAX_NBOR_SIZE = 1024; + const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; dim3 block_grid(nloc, nblock); dim3 thread_grid(1, LEN); format_nlist_fill_a_se_r @@ -237,12 +237,12 @@ void format_nbor_list_1024 ( rcut_r, key, i_idx, - MAGIC_NUMBER + MAX_NBOR_SIZE ); const int ITEMS_PER_THREAD = 8; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; + const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); + BlockSortKernel <<>> (key, key + nloc * MAX_NBOR_SIZE); } template @@ -258,8 +258,8 @@ void format_nbor_list_2048 ( ) { const int LEN = 256; - const int MAGIC_NUMBER = 2048; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; + const int MAX_NBOR_SIZE = 2048; + const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; dim3 block_grid(nloc, nblock); dim3 thread_grid(1, LEN); format_nlist_fill_a_se_r @@ -271,12 +271,12 @@ void format_nbor_list_2048 ( rcut_r, key, i_idx, - MAGIC_NUMBER + MAX_NBOR_SIZE ); const int ITEMS_PER_THREAD = 8; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; + const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); + BlockSortKernel <<>> (key, key + nloc * MAX_NBOR_SIZE); } template @@ -292,8 +292,8 @@ void format_nbor_list_4096 ( ) { const int LEN = 256; - const int MAGIC_NUMBER = 4096; - const int nblock = (MAGIC_NUMBER + LEN - 1) / LEN; + const int MAX_NBOR_SIZE = 4096; + const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; dim3 block_grid(nloc, nblock); dim3 thread_grid(1, LEN); format_nlist_fill_a_se_r @@ -305,16 +305,16 @@ void format_nbor_list_4096 ( rcut_r, key, i_idx, - MAGIC_NUMBER + MAX_NBOR_SIZE ); const int ITEMS_PER_THREAD = 16; - const int BLOCK_THREADS = MAGIC_NUMBER / ITEMS_PER_THREAD; + const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAGIC_NUMBER); + BlockSortKernel <<>> (key, key + nloc * MAX_NBOR_SIZE); } template -void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descript, FPTYPE * descript_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int MAGIC_NUMBER) { +void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descript, FPTYPE * descript_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { const int LEN = 256; int nblock = (nloc + LEN -1) / LEN; int * sec_a_dev = array_int; @@ -324,7 +324,7 @@ void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const cudaError_t res = cudaSuccess; res = cudaMemcpy(sec_a_dev, &sec_a[0], sizeof(int) * sec_a.size(), cudaMemcpyHostToDevice); cudaErrcheck(res); - res = cudaMemset(key, 0xffffffff, sizeof(int_64) * nloc * MAGIC_NUMBER); cudaErrcheck(res); + res = cudaMemset(key, 0xffffffff, sizeof(int_64) * nloc * max_nbor_size); cudaErrcheck(res); res = cudaMemset(nlist, -1, sizeof(int) * nloc * nnei); cudaErrcheck(res); res = cudaMemset(descript, 0.0, sizeof(FPTYPE) * nloc * ndescrpt); cudaErrcheck(res); res = cudaMemset(descript_deriv, 0.0, sizeof(FPTYPE) * nloc * ndescrpt * 3); cudaErrcheck(res); @@ -334,7 +334,7 @@ void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const // cudaProfilerStart(); get_i_idx_se_r<<>> (nloc, ilist, i_idx); - if (MAGIC_NUMBER <= 1024) { + if (max_nbor_size <= 1024) { format_nbor_list_1024 ( coord, type, @@ -345,7 +345,7 @@ void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const i_idx, key ); - } else if (MAGIC_NUMBER <= 2048) { + } else if (max_nbor_size <= 2048) { format_nbor_list_2048 ( coord, type, @@ -356,7 +356,7 @@ void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const i_idx, key ); - } else if (MAGIC_NUMBER <= 4096) { + } else if (max_nbor_size <= 4096) { format_nbor_list_4096 ( coord, type, @@ -379,7 +379,7 @@ void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const sec_a_dev, sec_a.size(), nei_iter, - MAGIC_NUMBER + max_nbor_size ); } diff --git a/source/op/descrpt_se_a_multi_device.cc b/source/op/descrpt_se_a_multi_device.cc index 2ef5083708..a7996c65ac 100644 --- a/source/op/descrpt_se_a_multi_device.cc +++ b/source/op/descrpt_se_a_multi_device.cc @@ -34,13 +34,13 @@ struct DeviceFunctor { template struct DescrptSeAFunctor { - void operator()(const CPUDevice& d, const FPTYPE * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::std::vector sec_a, const bool fill_nei_a, const int magic_number) { - DescrptSeACPULauncher(coord, type, ilist, jrange, jlist, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ntypes, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); + void operator()(const CPUDevice& d, const FPTYPE * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { + DescrptSeACPULauncher(coord, type, ilist, jrange, jlist, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ntypes, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); } #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const FPTYPE * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::std::vector sec_a, const bool fill_nei_a, const int magic_number) { - DescrptSeAGPULauncher(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); + void operator()(const GPUDevice& d, const FPTYPE * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { + DescrptSeAGPULauncher(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); } #endif // GOOGLE_CUDA }; @@ -66,7 +66,7 @@ class DescrptSeAOp : public OpKernel { nnei_r = sec_r.back(); nnei = nnei_a + nnei_r; fill_nei_a = (rcut_a < 0); - magic_number = get_magic_number(nnei); + max_nbor_size = 1024; } void Compute(OpKernelContext* context) override { @@ -117,7 +117,6 @@ class DescrptSeAOp : public OpKernel { OP_REQUIRES (context, (ntypes == int(sel_a.size())), errors::InvalidArgument ("number of types should match the length of sel array")); OP_REQUIRES (context, (ntypes == int(sel_r.size())), errors::InvalidArgument ("number of types should match the length of sel array")); - OP_REQUIRES (context, (nnei <= 4096), errors::InvalidArgument ("Assert failed, max neighbor size of atom(nnei) " + std::to_string(nnei) + " is larger than 4096, which currently is not supported by deepmd-kit.")); // Create output tensors TensorShape descrpt_shape ; @@ -159,13 +158,14 @@ class DescrptSeAOp : public OpKernel { OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); Tensor uint64_temp; TensorShape uint64_shape; - uint64_shape.AddDim(nloc * magic_number * 2); + uint64_shape.AddDim(nloc * max_nbor_size * 2); OP_REQUIRES_OK(context, context->allocate_temp(DT_UINT64, uint64_shape, &uint64_temp)); array_int = int_temp.flat().data(); array_longlong = uint64_temp.flat().data(); nbor_update(mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); + OP_REQUIRES (context, (max_nbor_size <= 4096), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than 4096, which currently is not supported by deepmd-kit.")); } else if (device == "CPU") { memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); @@ -198,7 +198,7 @@ class DescrptSeAOp : public OpKernel { rcut_r_smth, sec_a, fill_nei_a, - magic_number + max_nbor_size ); } @@ -212,7 +212,7 @@ class DescrptSeAOp : public OpKernel { std::std::vector sec_a; std::std::vector sec_r; int ndescrpt, ndescrpt_a, ndescrpt_r; - int nnei, nnei_a, nnei_r, nloc, nall, magic_number; + int nnei, nnei_a, nnei_r, nloc, nall, max_nbor_size; bool fill_nei_a; //private func @@ -266,21 +266,15 @@ class DescrptSeAOp : public OpKernel { cudaErrcheck(cudaMemcpy(ilist, ilist_host, sizeof(int) * mesh_host[1], cudaMemcpyHostToDevice)); cudaErrcheck(cudaMemcpy(jrange, jrange_host, sizeof(int) * mesh_host[2], cudaMemcpyHostToDevice)); cudaErrcheck(cudaMemcpy(jlist, jlist_host, sizeof(int) * mesh_host[3], cudaMemcpyHostToDevice)); + + max_nbor_size = 1024; + for(int ii = 0; ii < mesh_host[2] - 1; ii++) { + max_nbor_size = (jrange_host[ii + 1] - jrange_host[ii]) > max_nbor_size ? (jrange_host[ii + 1] - jrange_host[ii]) : max_nbor_size; + } } delete [] mesh_host; } - int get_magic_number(int const nnei) { - if (nnei <= 1024) { - return 1024; - } - else if (nnei <= 2048) { - return 2048; - } - else if (nnei <= 4096) { - return 4096; - } - } }; // Register the CPU kernels. diff --git a/source/op/descrpt_se_r_multi_device.cc b/source/op/descrpt_se_r_multi_device.cc index 1d9a06cdcd..9ca7c076e7 100644 --- a/source/op/descrpt_se_r_multi_device.cc +++ b/source/op/descrpt_se_r_multi_device.cc @@ -31,13 +31,13 @@ struct DeviceFunctor { template struct DescrptSeRFunctor { - void operator()(const CPUDevice& d, const T * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const T * avg, const T * std, T * descrpt, T * descrpt_deriv, T * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::std::vector sec_a, const bool fill_nei_a, const int magic_number) { - DescrptSeRCPULauncher(coord, type, ilist, jrange, jlist, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ntypes, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); + void operator()(const CPUDevice& d, const T * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const T * avg, const T * std, T * descrpt, T * descrpt_deriv, T * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { + DescrptSeRCPULauncher(coord, type, ilist, jrange, jlist, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ntypes, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); } #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const T * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const T * avg, const T * std, T * descrpt, T * descrpt_deriv, T * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::std::vector sec_a, const bool fill_nei_a, const int magic_number) { - DescrptSeRGPULauncher(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); + void operator()(const GPUDevice& d, const T * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const T * avg, const T * std, T * descrpt, T * descrpt_deriv, T * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { + DescrptSeRGPULauncher(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); } #endif // GOOGLE_CUDA }; @@ -55,9 +55,7 @@ class DescrptSeROp : public OpKernel { ndescrpt = sec.back() * 1; nnei = sec.back(); fill_nei_a = true; - magic_number = get_magic_number(nnei); - // count_nei_idx_overflow = 0; - // std::std::cout << "I'm in descrpt_se_r_gpu.cc" << std::std::endl; + max_nbor_size = 1024; } void Compute(OpKernelContext* context) override { @@ -149,13 +147,14 @@ class DescrptSeROp : public OpKernel { OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); Tensor uint64_temp; TensorShape uint64_shape; - uint64_shape.AddDim(nloc * magic_number * 2); + uint64_shape.AddDim(nloc * max_nbor_size * 2); OP_REQUIRES_OK(context, context->allocate_temp(DT_UINT64, uint64_shape, &uint64_temp)); array_int = int_temp.flat().data(); array_longlong = uint64_temp.flat().data(); nbor_update(mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); + OP_REQUIRES (context, (max_nbor_size <= 4096), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than 4096, which currently is not supported by deepmd-kit.")); } else if (device == "CPU") { memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); @@ -188,7 +187,7 @@ class DescrptSeROp : public OpKernel { rcut_smth, sec, fill_nei_a, - magic_number + max_nbor_size ); } @@ -213,7 +212,7 @@ class DescrptSeROp : public OpKernel { } } - int magic_number; + int max_nbor_size; std::string device; int *array_int; unsigned long long*array_longlong; @@ -256,21 +255,15 @@ class DescrptSeROp : public OpKernel { cudaErrcheck(cudaMemcpy(ilist, ilist_host, sizeof(int) * mesh_host[1], cudaMemcpyHostToDevice)); cudaErrcheck(cudaMemcpy(jrange, jrange_host, sizeof(int) * mesh_host[2], cudaMemcpyHostToDevice)); cudaErrcheck(cudaMemcpy(jlist, jlist_host, sizeof(int) * mesh_host[3], cudaMemcpyHostToDevice)); + + max_nbor_size = 1024; + for(int ii = 0; ii < mesh_host[2] - 1; ii++) { + max_nbor_size = (jrange_host[ii + 1] - jrange_host[ii]) > max_nbor_size ? (jrange_host[ii + 1] - jrange_host[ii]) : max_nbor_size; + } } delete [] mesh_host; } - int get_magic_number(int const nnei) { - if (nnei <= 1024) { - return 1024; - } - else if (nnei <= 2048) { - return 2048; - } - else if (nnei <= 4096) { - return 4096; - } - } }; // Register the CPU kernels. From e0dd5b50e2032de49a04eb5d59ac87ced239699f Mon Sep 17 00:00:00 2001 From: denghuilu Date: Wed, 27 Jan 2021 11:37:59 +0800 Subject: [PATCH 059/562] fix a potential bug --- source/op/descrpt_se_a_multi_device.cc | 2 +- source/op/descrpt_se_r_multi_device.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/op/descrpt_se_a_multi_device.cc b/source/op/descrpt_se_a_multi_device.cc index a7996c65ac..fa2d085316 100644 --- a/source/op/descrpt_se_a_multi_device.cc +++ b/source/op/descrpt_se_a_multi_device.cc @@ -268,7 +268,7 @@ class DescrptSeAOp : public OpKernel { cudaErrcheck(cudaMemcpy(jlist, jlist_host, sizeof(int) * mesh_host[3], cudaMemcpyHostToDevice)); max_nbor_size = 1024; - for(int ii = 0; ii < mesh_host[2] - 1; ii++) { + for(int ii = 0; ii < mesh_host[2]; ii++) { max_nbor_size = (jrange_host[ii + 1] - jrange_host[ii]) > max_nbor_size ? (jrange_host[ii + 1] - jrange_host[ii]) : max_nbor_size; } } diff --git a/source/op/descrpt_se_r_multi_device.cc b/source/op/descrpt_se_r_multi_device.cc index 9ca7c076e7..6761cf3b29 100644 --- a/source/op/descrpt_se_r_multi_device.cc +++ b/source/op/descrpt_se_r_multi_device.cc @@ -257,7 +257,7 @@ class DescrptSeROp : public OpKernel { cudaErrcheck(cudaMemcpy(jlist, jlist_host, sizeof(int) * mesh_host[3], cudaMemcpyHostToDevice)); max_nbor_size = 1024; - for(int ii = 0; ii < mesh_host[2] - 1; ii++) { + for(int ii = 0; ii < mesh_host[2]; ii++) { max_nbor_size = (jrange_host[ii + 1] - jrange_host[ii]) > max_nbor_size ? (jrange_host[ii + 1] - jrange_host[ii]) : max_nbor_size; } } From ede4eab807c6ce00fc4623eb5f4aee81217a3986 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 2 Feb 2021 08:06:39 +0800 Subject: [PATCH 060/562] fix bug of std::std:: --- source/op/descrpt_se_a_multi_device.cc | 12 ++++++------ source/op/descrpt_se_r_multi_device.cc | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/source/op/descrpt_se_a_multi_device.cc b/source/op/descrpt_se_a_multi_device.cc index fa2d085316..5200ce0527 100644 --- a/source/op/descrpt_se_a_multi_device.cc +++ b/source/op/descrpt_se_a_multi_device.cc @@ -207,16 +207,16 @@ class DescrptSeAOp : public OpKernel { float rcut_a; float rcut_r; float rcut_r_smth; - std::std::vector sel_r; - std::std::vector sel_a; - std::std::vector sec_a; - std::std::vector sec_r; + std::vector sel_r; + std::vector sel_a; + std::vector sec_a; + std::vector sec_r; int ndescrpt, ndescrpt_a, ndescrpt_r; int nnei, nnei_a, nnei_r, nloc, nall, max_nbor_size; bool fill_nei_a; //private func - void cum_sum (std::std::vector & sec, const std::std::vector & n_sel) const { + void cum_sum (std::vector & sec, const std::vector & n_sel) const { sec.resize (n_sel.size() + 1); sec[0] = 0; for (int ii = 1; ii < sec.size(); ++ii) { @@ -292,4 +292,4 @@ REGISTER_KERNEL_BUILDER( DescrptSeAOp); REGISTER_GPU(float); REGISTER_GPU(double); -#endif // GOOGLE_CUDA \ No newline at end of file +#endif // GOOGLE_CUDA diff --git a/source/op/descrpt_se_r_multi_device.cc b/source/op/descrpt_se_r_multi_device.cc index 6761cf3b29..36d4357cfa 100644 --- a/source/op/descrpt_se_r_multi_device.cc +++ b/source/op/descrpt_se_r_multi_device.cc @@ -196,15 +196,15 @@ class DescrptSeROp : public OpKernel { private: float rcut; float rcut_smth; - std::std::vector sel; - std::std::vector sel_null; - std::std::vector sec; - std::std::vector sec_null; + std::vector sel; + std::vector sel_null; + std::vector sec; + std::vector sec_null; int nnei, ndescrpt, nloc, nall; bool fill_nei_a; //private func - void cum_sum (std::std::vector & sec, const std::std::vector & n_sel) const { + void cum_sum (std::vector & sec, const std::vector & n_sel) const { sec.resize (n_sel.size() + 1); sec[0] = 0; for (int ii = 1; ii < sec.size(); ++ii) { @@ -281,4 +281,4 @@ REGISTER_KERNEL_BUILDER( DescrptSeROp); REGISTER_GPU(float); REGISTER_GPU(double); -#endif // GOOGLE_CUDA \ No newline at end of file +#endif // GOOGLE_CUDA From ebccb0c04932c112fc9dabb4c6881fdaf095064e Mon Sep 17 00:00:00 2001 From: denghuilu Date: Tue, 2 Feb 2021 13:06:14 +0800 Subject: [PATCH 061/562] fix bugs of std error --- source/lib/include/CustomeOperation.h | 48 +++++++++++++-------------- source/lib/include/DeepTensor.h | 20 +++++------ source/lib/include/NNPInter.h | 14 ++++---- source/lib/include/common.h | 33 +++++++++--------- source/lib/include/version.h.in | 18 +++++----- source/lib/src/DataModifier.cc | 16 ++++----- source/lib/src/DeepTensor.cc | 18 +++++----- source/lib/src/NNPInter.cc | 32 +++++++++--------- source/lib/src/common.cc | 30 ++++++++--------- source/lmp/fix_dplr.h | 22 ++++++------ source/lmp/pair_nnp.h.in | 22 ++++++------ source/lmp/pppm_dplr.h | 5 ++- 12 files changed, 138 insertions(+), 140 deletions(-) diff --git a/source/lib/include/CustomeOperation.h b/source/lib/include/CustomeOperation.h index f7fd7c2496..0bdd91c3dd 100644 --- a/source/lib/include/CustomeOperation.h +++ b/source/lib/include/CustomeOperation.h @@ -49,14 +49,14 @@ inline void spline5_switch ( template int format_nlist_fill_se_a_cpu ( - vector & fmt_nei_idx_a, - const vector & posi, + std::vector & fmt_nei_idx_a, + const std::vector & posi, const int & ntypes, - const vector & type, + const std::vector & type, const int & i_idx, - const vector & nei_idx_a, + const std::vector & nei_idx_a, const float & rcut, - const vector & sec_a) + const std::vector & sec_a) { fmt_nei_idx_a.resize (sec_a.back()); fill (fmt_nei_idx_a.begin(), fmt_nei_idx_a.end(), -1); @@ -64,7 +64,7 @@ int format_nlist_fill_se_a_cpu ( // gether all neighbors std::vector nei_idx (nei_idx_a); // allocate the information for all neighbors - vector sel_nei; + std::vector sel_nei; sel_nei.reserve (nei_idx_a.size()); for (unsigned kk = 0; kk < nei_idx.size(); ++kk) { FPTYPE diff[3]; @@ -92,15 +92,15 @@ int format_nlist_fill_se_a_cpu ( template void compute_descriptor_se_a_cpu ( - vector & descrpt_a, - vector & descrpt_a_deriv, - vector & rij_a, - const vector & posi, + std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, const int & ntypes, - const vector & type, + const std::vector & type, const int & i_idx, - const vector & fmt_nlist_a, - const vector & sec_a, + const std::vector & fmt_nlist_a, + const std::vector & sec_a, const float & rmin, const float & rmax) { @@ -185,7 +185,7 @@ void DescrptSeACPULauncher(const FPTYPE * coord, const int * type, const int * i } // build nlist - std::vector > d_nlist_a(nloc); + std::vector > d_nlist_a(nloc); for (unsigned ii = 0; ii < nloc; ++ii) { d_nlist_a.reserve (jrange[nloc] / nloc + 10); @@ -200,7 +200,7 @@ void DescrptSeACPULauncher(const FPTYPE * coord, const int * type, const int * i #pragma omp parallel for for (int ii = 0; ii < nloc; ++ii) { - vector fmt_nlist_a; + std::vector fmt_nlist_a; int ret = -1; if (fill_nei_a) { format_nlist_fill_se_a_cpu(fmt_nlist_a, d_coord3, ntypes, d_type, ii, d_nlist_a[ii], rcut_r, sec_a); @@ -373,15 +373,15 @@ void GeluGradGradGPULauncher(const FPTYPE * dy, const FPTYPE * dy_, const FPTYPE template void compute_descriptor_se_r_cpu ( - vector & descrpt_a, - vector & descrpt_a_deriv, - vector & rij_a, - const vector & posi, + std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, const int & ntypes, - const vector & type, + const std::vector & type, const int & i_idx, - const vector & fmt_nlist_a, - const vector & sec_a, + const std::vector & fmt_nlist_a, + const std::vector & sec_a, const float & rmin, const float & rmax) { @@ -448,7 +448,7 @@ void DescrptSeRCPULauncher(const FPTYPE * coord, const int * type, const int * i } // build nlist - std::vector > d_nlist_a(nloc); + std::vector > d_nlist_a(nloc); for (unsigned ii = 0; ii < nloc; ++ii) { d_nlist_a.reserve (jrange[nloc] / nloc + 10); @@ -463,7 +463,7 @@ void DescrptSeRCPULauncher(const FPTYPE * coord, const int * type, const int * i #pragma omp parallel for for (int ii = 0; ii < nloc; ++ii) { - vector fmt_nlist_a; + std::vector fmt_nlist_a; int ret = -1; if (fill_nei_a) { format_nlist_fill_se_a_cpu(fmt_nlist_a, d_coord3, ntypes, d_type, ii, d_nlist_a[ii], rcut_r, sec_a); diff --git a/source/lib/include/DeepTensor.h b/source/lib/include/DeepTensor.h index c9d265763e..f73957137d 100644 --- a/source/lib/include/DeepTensor.h +++ b/source/lib/include/DeepTensor.h @@ -6,13 +6,13 @@ class DeepTensor { public: DeepTensor(); - DeepTensor(const string & model, + DeepTensor(const std::string & model, const int & gpu_rank = 0, - const string &name_scope = ""); - void init (const string & model, + const std::string &name_scope = ""); + void init (const std::string & model, const int & gpu_rank = 0, - const string &name_scope = ""); - void print_summary(const string &pre) const; + const std::string &name_scope = ""); + void print_summary(const std::string &pre) const; public: void compute (std::vector & value, const std::vector & coord, @@ -31,21 +31,21 @@ class DeepTensor const std::vector & sel_types () const {assert(inited); return sel_type;}; private: Session* session; - string name_scope; + std::string name_scope; int num_intra_nthreads, num_inter_nthreads; GraphDef graph_def; bool inited; VALUETYPE rcut; VALUETYPE cell_size; int ntypes; - string model_type; + std::string model_type; int odim; std::vector sel_type; - template VT get_scalar(const string & name) const; - template void get_vector (std::vector & vec, const string & name) const; + template VT get_scalar(const std::string & name) const; + template void get_vector (std::vector & vec, const std::string & name) const; void run_model (std::vector & d_tensor_, Session * session, - const std::vector> & input_tensors, + const std::vector> & input_tensors, const NNPAtomMap & nnpmap, const int nghost = 0); void compute_inner (std::vector & value, diff --git a/source/lib/include/NNPInter.h b/source/lib/include/NNPInter.h index 84f305cb8b..6793431e34 100644 --- a/source/lib/include/NNPInter.h +++ b/source/lib/include/NNPInter.h @@ -8,9 +8,9 @@ class NNPInter public: NNPInter () ; ~NNPInter() ; - NNPInter (const string & model, const int & gpu_rank = 0); - void init (const string & model, const int & gpu_rank = 0); - void print_summary(const string &pre) const; + NNPInter (const std::string & model, const int & gpu_rank = 0); + void init (const std::string & model, const int & gpu_rank = 0); + void print_summary(const std::string &pre) const; public: void compute (ENERGYTYPE & ener, std::vector & force, @@ -65,7 +65,7 @@ class NNPInter int num_intra_nthreads, num_inter_nthreads; GraphDef graph_def; bool inited; - template VT get_scalar(const string & name) const; + template VT get_scalar(const std::string & name) const; // VALUETYPE get_rcut () const; // int get_ntypes () const; VALUETYPE rcut; @@ -105,8 +105,8 @@ class NNPInterModelDevi public: NNPInterModelDevi () ; ~NNPInterModelDevi() ; - NNPInterModelDevi (const std::vector & models, const int & gpu_rank = 0); - void init (const std::vector & models, const int & gpu_rank = 0); + NNPInterModelDevi (const std::vector & models, const int & gpu_rank = 0); + void init (const std::vector & models, const int & gpu_rank = 0); public: void compute (ENERGYTYPE & ener, std::vector & force, @@ -168,7 +168,7 @@ class NNPInterModelDevi int num_intra_nthreads, num_inter_nthreads; std::vector graph_defs; bool inited; - template VT get_scalar(const string name) const; + template VT get_scalar(const std::string name) const; // VALUETYPE get_rcut () const; // int get_ntypes () const; VALUETYPE rcut; diff --git a/source/lib/include/common.h b/source/lib/include/common.h index e07231cdd3..644dc3593d 100644 --- a/source/lib/include/common.h +++ b/source/lib/include/common.h @@ -21,7 +21,6 @@ typedef std::string STRINGTYPE; #include "NNPAtomMap.h" #include -#include #include #include "version.h" @@ -113,18 +112,18 @@ get_env_nthreads(int & num_intra_nthreads, void checkStatus(const tensorflow::Status& status); -string name_prefix(const string & name_scope); +std::string name_prefix(const std::string & name_scope); template VT -session_get_scalar(Session* session, const string name, const string scope = ""); +session_get_scalar(Session* session, const std::string name, const std::string scope = ""); template void -session_get_vector(std::vector & o_vec, Session* session, const string name_, const string scope = ""); +session_get_vector(std::vector & o_vec, Session* session, const std::string name_, const std::string scope = ""); int -session_input_tensors (std::vector> & input_tensors, +session_input_tensors (std::vector> & input_tensors, const std::vector & dcoord_, const int & ntypes, const std::vector & datype_, @@ -134,10 +133,10 @@ session_input_tensors (std::vector> & input_tensors, const std::vector & aparam_, const NNPAtomMap& nnpmap, const int nghost = 0, - const string scope = ""); + const std::string scope = ""); int -session_input_tensors (std::vector> & input_tensors, +session_input_tensors (std::vector> & input_tensors, const std::vector & dcoord_, const int & ntypes, const std::vector & datype_, @@ -148,10 +147,10 @@ session_input_tensors (std::vector> & input_tensors, const NNPAtomMap& nnpmap, const int nghost, const int ago, - const string scope = ""); + const std::string scope = ""); int -session_input_tensors (std::vector> & input_tensors, +session_input_tensors (std::vector> & input_tensors, const std::vector & dcoord_, const int & ntypes, const std::vector & datype_, @@ -161,10 +160,10 @@ session_input_tensors (std::vector> & input_tensors, const std::vector & aparam_, const NNPAtomMap& nnpmap, const int nghost, - const string scope = ""); + const std::string scope = ""); int -session_input_tensors (std::vector>& input_tensors, +session_input_tensors (std::vector>& input_tensors, const std::vector & dcoord_, const int & ntypes, const std::vector & atype_, @@ -180,14 +179,14 @@ session_input_tensors (std::vector>& input_tensors, template VT -session_get_scalar(Session* session, const string name_, const string scope) +session_get_scalar(Session* session, const std::string name_, const std::string scope) { - string name = name_; + std::string name = name_; if (scope != "") { name = scope + "/" + name; } std::vector output_tensors; - checkStatus (session->Run(std::vector> ({}), + checkStatus (session->Run(std::vector> ({}), {name.c_str()}, {}, &output_tensors)); @@ -198,14 +197,14 @@ session_get_scalar(Session* session, const string name_, const string scope) template void -session_get_vector(std::vector & o_vec, Session* session, const string name_, const string scope) +session_get_vector(std::vector & o_vec, Session* session, const std::string name_, const std::string scope) { - string name = name_; + std::string name = name_; if (scope != "") { name = scope + "/" + name; } std::vector output_tensors; - checkStatus (session->Run(std::vector> ({}), + checkStatus (session->Run(std::vector> ({}), {name.c_str()}, {}, &output_tensors)); diff --git a/source/lib/include/version.h.in b/source/lib/include/version.h.in index a588d87a33..d3acbf5aff 100644 --- a/source/lib/include/version.h.in +++ b/source/lib/include/version.h.in @@ -4,15 +4,15 @@ // using namespace std; #ifdef HIGH_PREC -const string global_float_prec="double"; +const std::string global_float_prec="double"; #else -const string global_float_prec="float"; +const std::string global_float_prec="float"; #endif -const string global_install_prefix="@CMAKE_INSTALL_PREFIX@"; -const string global_git_summ="@GIT_SUMM@"; -const string global_git_hash="@GIT_HASH@"; -const string global_git_date="@GIT_DATE@"; -const string global_git_branch="@GIT_BRANCH@"; -const string global_tf_include_dir="@TensorFlow_INCLUDE_DIRS@"; -const string global_tf_lib="@TensorFlow_LIBRARY@"; +const std::string global_install_prefix="@CMAKE_INSTALL_PREFIX@"; +const std::string global_git_summ="@GIT_SUMM@"; +const std::string global_git_hash="@GIT_HASH@"; +const std::string global_git_date="@GIT_DATE@"; +const std::string global_git_branch="@GIT_BRANCH@"; +const std::string global_tf_include_dir="@TensorFlow_INCLUDE_DIRS@"; +const std::string global_tf_lib="@TensorFlow_LIBRARY@"; diff --git a/source/lib/src/DataModifier.cc b/source/lib/src/DataModifier.cc index ba026625c2..8144451841 100644 --- a/source/lib/src/DataModifier.cc +++ b/source/lib/src/DataModifier.cc @@ -7,9 +7,9 @@ DataModifier() } DataModifier:: -DataModifier(const string & model, +DataModifier(const std::string & model, const int & gpu_rank, - const string &name_scope_) + const std::string &name_scope_) : inited (false), name_scope(name_scope_) { get_env_nthreads(num_intra_nthreads, num_inter_nthreads); @@ -18,9 +18,9 @@ DataModifier(const string & model, void DataModifier:: -init (const string & model, +init (const std::string & model, const int & gpu_rank, - const string &name_scope_) + const std::string &name_scope_) { assert (!inited); name_scope = name_scope_; @@ -46,7 +46,7 @@ init (const string & model, template VT DataModifier:: -get_scalar (const string & name) const +get_scalar (const std::string & name) const { return session_get_scalar(session, name, name_scope); } @@ -54,7 +54,7 @@ get_scalar (const string & name) const template void DataModifier:: -get_vector (std::vector & vec, const string & name) const +get_vector (std::vector & vec, const std::string & name) const { session_get_vector(vec, session, name, name_scope); } @@ -64,7 +64,7 @@ DataModifier:: run_model (std::vector & dforce, std::vector & dvirial, Session * session, - const std::vector> & input_tensors, + const std::vector> & input_tensors, const NNPAtomMap & nnpmap, const int nghost) { @@ -163,7 +163,7 @@ compute (std::vector & dfcorr_, InternalNeighborList nlist(nlist_); shuffle_nlist (nlist, nnpmap); // make input tensors - std::vector> input_tensors; + std::vector> input_tensors; int ret = session_input_tensors (input_tensors, dcoord_real, ntypes, datype_real, dbox, nlist, std::vector(), std::vector(), nnpmap, nghost_real, name_scope); assert (nloc_real == ret); // make bond idx map diff --git a/source/lib/src/DeepTensor.cc b/source/lib/src/DeepTensor.cc index 9d78bb3f6a..311cd1051d 100644 --- a/source/lib/src/DeepTensor.cc +++ b/source/lib/src/DeepTensor.cc @@ -7,9 +7,9 @@ DeepTensor() } DeepTensor:: -DeepTensor(const string & model, +DeepTensor(const std::string & model, const int & gpu_rank, - const string &name_scope_) + const std::string &name_scope_) : inited (false), name_scope(name_scope_) { get_env_nthreads(num_intra_nthreads, num_inter_nthreads); @@ -18,9 +18,9 @@ DeepTensor(const string & model, void DeepTensor:: -init (const string & model, +init (const std::string & model, const int & gpu_rank, - const string &name_scope_) + const std::string &name_scope_) { assert (!inited); name_scope = name_scope_; @@ -42,7 +42,7 @@ init (const string & model, template VT DeepTensor:: -get_scalar (const string & name) const +get_scalar (const std::string & name) const { return session_get_scalar(session, name, name_scope); } @@ -50,7 +50,7 @@ get_scalar (const string & name) const template void DeepTensor:: -get_vector (std::vector & vec, const string & name) const +get_vector (std::vector & vec, const std::string & name) const { session_get_vector(vec, session, name, name_scope); } @@ -59,7 +59,7 @@ void DeepTensor:: run_model (std::vector & d_tensor_, Session * session, - const std::vector> & input_tensors, + const std::vector> & input_tensors, const NNPAtomMap &nnpmap, const int nghost) { @@ -152,7 +152,7 @@ compute_inner (std::vector & dtensor_, NNPAtomMap nnpmap (datype_.begin(), datype_.begin() + nloc); assert (nloc == nnpmap.get_type().size()); - std::vector> input_tensors; + std::vector> input_tensors; int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, std::vector(), std::vector(), nnpmap, nghost, name_scope); assert (ret == nloc); @@ -176,7 +176,7 @@ compute_inner (std::vector & dtensor_, InternalNeighborList nlist(nlist_); shuffle_nlist (nlist, nnpmap); - std::vector> input_tensors; + std::vector> input_tensors; int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, std::vector(), std::vector(), nnpmap, nghost, name_scope); assert (nloc == ret); diff --git a/source/lib/src/NNPInter.cc b/source/lib/src/NNPInter.cc index 7911f3d844..67c75fa69b 100644 --- a/source/lib/src/NNPInter.cc +++ b/source/lib/src/NNPInter.cc @@ -36,7 +36,7 @@ run_model (ENERGYTYPE & dener, std::vector & dforce_, std::vector & dvirial, Session * session, - const std::vector> & input_tensors, + const std::vector> & input_tensors, const NNPAtomMap& nnpmap, const int nghost = 0) { @@ -95,7 +95,7 @@ static void run_model (ENERGYTYPE & dener, std::vector& datom_energy_, std::vector& datom_virial_, Session* session, - const std::vector> & input_tensors, + const std::vector> & input_tensors, const NNPAtomMap & nnpmap, const int& nghost = 0) { @@ -177,7 +177,7 @@ NNPInter () } NNPInter:: -NNPInter (const string & model, const int & gpu_rank) +NNPInter (const std::string & model, const int & gpu_rank) : inited (false), init_nbor (false) { get_env_nthreads(num_intra_nthreads, num_inter_nthreads); @@ -188,7 +188,7 @@ NNPInter::~NNPInter() {} void NNPInter:: -init (const string & model, const int & gpu_rank) +init (const std::string & model, const int & gpu_rank) { assert (!inited); SessionOptions options; @@ -227,7 +227,7 @@ init (const string & model, const int & gpu_rank) void NNPInter:: -print_summary(const string &pre) const +print_summary(const std::string &pre) const { std::cout << pre << "installed to: " + global_install_prefix << std::endl; std::cout << pre << "source: " + global_git_summ << std::endl; @@ -244,7 +244,7 @@ print_summary(const string &pre) const template VT NNPInter:: -get_scalar (const string & name) const +get_scalar (const std::string & name) const { return session_get_scalar(session, name); } @@ -326,7 +326,7 @@ compute (ENERGYTYPE & dener, assert (nloc == nnpmap.get_type().size()); validate_fparam_aparam(nloc, fparam, aparam); - std::vector> input_tensors; + std::vector> input_tensors; int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, fparam, aparam, nnpmap, nghost); assert (ret == nloc); @@ -389,7 +389,7 @@ compute_inner (ENERGYTYPE & dener, int nloc = nall - nghost; validate_fparam_aparam(nloc, fparam, aparam); - std::vector> input_tensors; + std::vector> input_tensors; // agp == 0 means that the LAMMPS nbor list has been updated if (ago == 0) { @@ -421,7 +421,7 @@ compute (ENERGYTYPE & dener, nnpmap = NNPAtomMap (datype_.begin(), datype_.end()); validate_fparam_aparam(nnpmap.get_type().size(), fparam, aparam); - std::vector> input_tensors; + std::vector> input_tensors; int nloc = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, fparam, aparam, nnpmap); run_model (dener, dforce_, dvirial, datom_energy_, datom_virial_, session, input_tensors, nnpmap); @@ -448,7 +448,7 @@ compute (ENERGYTYPE & dener, int nall = dcoord_.size() / 3; int nloc = nall - nghost; validate_fparam_aparam(nloc, fparam, aparam); - std::vector> input_tensors; + std::vector> input_tensors; if (ago == 0) { nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); @@ -482,7 +482,7 @@ NNPInterModelDevi () } NNPInterModelDevi:: -NNPInterModelDevi (const std::vector & models, const int & gpu_rank) +NNPInterModelDevi (const std::vector & models, const int & gpu_rank) : inited (false), init_nbor(false), numb_models (0) @@ -495,7 +495,7 @@ NNPInterModelDevi::~NNPInterModelDevi() {} void NNPInterModelDevi:: -init (const std::vector & models, const int & gpu_rank) +init (const std::vector & models, const int & gpu_rank) { assert (!inited); numb_models = models.size(); @@ -551,7 +551,7 @@ init (const std::vector & models, const int & gpu_rank) template VT NNPInterModelDevi:: -get_scalar(const string name) const +get_scalar(const std::string name) const { VT myrcut = 0; for (unsigned ii = 0; ii < numb_models; ++ii){ @@ -643,7 +643,7 @@ compute (ENERGYTYPE & dener, nnpmap = NNPAtomMap (datype_.begin(), datype_.end()); validate_fparam_aparam(nnpmap.get_type().size(), fparam, aparam); - std::vector> input_tensors; + std::vector> input_tensors; int nloc = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, fparam, aparam, nnpmap); std::vector all_energy (numb_models); @@ -691,7 +691,7 @@ compute (std::vector & all_energy, int nall = dcoord_.size() / 3; int nloc = nall - nghost; validate_fparam_aparam(nloc, fparam, aparam); - std::vector> input_tensors; + std::vector> input_tensors; // agp == 0 means that the LAMMPS nbor list has been updated if (ago == 0) { @@ -733,7 +733,7 @@ compute (std::vector & all_energy, int nall = dcoord_.size() / 3; int nloc = nall - nghost; validate_fparam_aparam(nloc, fparam, aparam); - std::vector> input_tensors; + std::vector> input_tensors; // agp == 0 means that the LAMMPS nbor list has been updated if (ago == 0) { diff --git a/source/lib/src/common.cc b/source/lib/src/common.cc index 97d4f971ec..23fc998560 100644 --- a/source/lib/src/common.cc +++ b/source/lib/src/common.cc @@ -162,23 +162,23 @@ get_env_nthreads(int & num_intra_nthreads, const char* env_intra_nthreads = std::getenv("TF_INTRA_OP_PARALLELISM_THREADS"); const char* env_inter_nthreads = std::getenv("TF_INTER_OP_PARALLELISM_THREADS"); if (env_intra_nthreads && - string(env_intra_nthreads) != string("") && + std::string(env_intra_nthreads) != std::string("") && atoi(env_intra_nthreads) >= 0 ) { num_intra_nthreads = atoi(env_intra_nthreads); } if (env_inter_nthreads && - string(env_inter_nthreads) != string("") && + std::string(env_inter_nthreads) != std::string("") && atoi(env_inter_nthreads) >= 0 ) { num_inter_nthreads = atoi(env_inter_nthreads); } } -string -name_prefix(const string & scope) +std::string +name_prefix(const std::string & scope) { - string prefix = ""; + std::string prefix = ""; if (scope != ""){ prefix = scope + "/"; } @@ -186,7 +186,7 @@ name_prefix(const string & scope) } int -session_input_tensors (std::vector> & input_tensors, +session_input_tensors (std::vector> & input_tensors, const std::vector & dcoord_, const int & ntypes, const std::vector & datype_, @@ -196,7 +196,7 @@ session_input_tensors (std::vector> & input_tensors, const std::vector & aparam_, const NNPAtomMap& nnpmap, const int nghost, - const string scope) + const std::string scope) { bool b_ghost = (nghost != 0); @@ -320,7 +320,7 @@ session_input_tensors (std::vector> & input_tensors, natoms (1) = nall; for (int ii = 0; ii < ntypes; ++ii) natoms(ii+2) = type_count[ii]; - string prefix = ""; + std::string prefix = ""; if (scope != ""){ prefix = scope + "/"; } @@ -341,7 +341,7 @@ session_input_tensors (std::vector> & input_tensors, } int -session_input_tensors (std::vector> & input_tensors, +session_input_tensors (std::vector> & input_tensors, const std::vector & dcoord_, const int & ntypes, const std::vector & datype_, @@ -352,7 +352,7 @@ session_input_tensors (std::vector> & input_tensors, const NNPAtomMap& nnpmap, const int nghost, const int ago, - const string scope) + const std::string scope) { assert (dbox.size() == 9); @@ -450,7 +450,7 @@ session_input_tensors (std::vector> & input_tensors, natoms (1) = nall; for (int ii = 0; ii < ntypes; ++ii) natoms(ii+2) = type_count[ii]; - string prefix = ""; + std::string prefix = ""; if (scope != ""){ prefix = scope + "/"; } @@ -471,7 +471,7 @@ session_input_tensors (std::vector> & input_tensors, } int -session_input_tensors (std::vector> & input_tensors, +session_input_tensors (std::vector> & input_tensors, const std::vector & dcoord_, const int & ntypes, const std::vector & datype_, @@ -481,7 +481,7 @@ session_input_tensors (std::vector> & input_tensors, const std::vector & aparam_, const NNPAtomMap& nnpmap, const int nghost, - const string scope) + const std::string scope) { assert (dbox.size() == 9); @@ -578,7 +578,7 @@ session_input_tensors (std::vector> & input_tensors, natoms (1) = nall; for (int ii = 0; ii < ntypes; ++ii) natoms(ii+2) = type_count[ii]; - string prefix = ""; + std::string prefix = ""; if (scope != ""){ prefix = scope + "/"; } @@ -601,7 +601,7 @@ session_input_tensors (std::vector> & input_tensors, int session_input_tensors ( - std::vector> & input_tensors, + std::vector> & input_tensors, const std::vector & dcoord_, const int & ntypes, const std::vector & datype_, diff --git a/source/lmp/fix_dplr.h b/source/lmp/fix_dplr.h index a0f45185b4..e52215151c 100644 --- a/source/lmp/fix_dplr.h +++ b/source/lmp/fix_dplr.h @@ -38,19 +38,19 @@ namespace LAMMPS_NS { PairNNP * pair_nnp; DeepTensor dpt; DataModifier dtm; - string model; + std::string model; int ntypes; - vector sel_type; - vector dpl_type; - vector bond_type; - map type_asso; - map bk_type_asso; - vector dipole_recd; - vector dfcorr_buff; - vector efield; - vector efield_fsum, efield_fsum_all; + std::vector sel_type; + std::vector dpl_type; + std::vector bond_type; + std::map type_asso; + std::map bk_type_asso; + std::vector dipole_recd; + std::vector dfcorr_buff; + std::vector efield; + std::vector efield_fsum, efield_fsum_all; int efield_force_flag; - void get_valid_pairs(vector >& pairs); + void get_valid_pairs(std::vector >& pairs); }; } diff --git a/source/lmp/pair_nnp.h.in b/source/lmp/pair_nnp.h.in index d41546438c..4d1a995a3a 100644 --- a/source/lmp/pair_nnp.h.in +++ b/source/lmp/pair_nnp.h.in @@ -62,7 +62,7 @@ class PairNNP : public Pair { double init_one(int i, int j); int pack_reverse_comm(int, int, double *); void unpack_reverse_comm(int, int *, double *); - void print_summary(const string pre) const; + void print_summary(const std::string pre) const; int get_node_rank(); protected: virtual void allocate(); @@ -74,10 +74,10 @@ private: unsigned numb_models; double cutoff; int numb_types; - vector > all_force; - ofstream fp; + std::vector > all_force; + std::ofstream fp; int out_freq; - string out_file; + std::string out_file; int dim_fparam; int dim_aparam; int out_each; @@ -86,23 +86,23 @@ private: bool multi_models_mod_devi; bool multi_models_no_mod_devi; #ifdef HIGH_PREC - vector fparam; - vector aparam; + std::vector fparam; + std::vector aparam; double eps; #else - vector fparam; - vector aparam; + std::vector fparam; + std::vector aparam; float eps; #endif void make_ttm_aparam( #ifdef HIGH_PREC - vector & dparam + std::vector & dparam #else - vector & dparam + std::vector & dparam #endif ); bool do_ttm; - string ttm_fix_id; + std::string ttm_fix_id; }; } diff --git a/source/lmp/pppm_dplr.h b/source/lmp/pppm_dplr.h index 17680c01cd..d9752583d5 100644 --- a/source/lmp/pppm_dplr.h +++ b/source/lmp/pppm_dplr.h @@ -29,7 +29,6 @@ KSpaceStyle(pppm/dplr,PPPMDPLR) #include "pppm.h" #include #include -using namespace std; namespace LAMMPS_NS { @@ -42,13 +41,13 @@ namespace LAMMPS_NS { #endif virtual ~PPPMDPLR () {}; void init(); - const vector & get_fele() const {return fele;}; + const std::vector & get_fele() const {return fele;}; protected: virtual void compute(int, int); virtual void fieldforce_ik(); virtual void fieldforce_ad(); private: - vector fele; + std::vector fele; }; } From b5166a81812bedd44660b8bece1b91dc0f3c51e1 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Wed, 3 Feb 2021 00:55:02 +0800 Subject: [PATCH 062/562] model compression model compression through tabulating --- deepmd/common.py | 12 + deepmd/descriptor/se_a.py | 181 +++++++++- deepmd/utils/tabulate.py | 185 ++++++++++ source/lib/include/CustomeOperation.h | 218 +++++++++++- source/lib/include/DeviceFunctor.h | 16 + source/op/CMakeLists.txt | 4 +- source/op/_tabulate_grad.py | 32 ++ source/op/cuda/CMakeLists.txt | 3 +- source/op/cuda/descrpt_se_a.cu | 153 ++++----- source/op/cuda/tabulate.cu | 475 ++++++++++++++++++++++++++ source/op/data_info.cc | 408 ++++++++++++++++++++++ source/op/tabulate.cc | 379 ++++++++++++++++++++ source/op/tabulate_multi_device.cc | 194 +++++++++++ source/op/unaggregated_grad.cc | 320 +++++++++++++++++ source/train/CMakeLists.txt | 2 +- source/train/Model.py | 3 + source/train/Trainer.py | 1 + source/train/compress.py | 52 +++ source/train/main.py | 14 + source/train/transform.py | 6 +- 20 files changed, 2560 insertions(+), 98 deletions(-) create mode 100644 deepmd/utils/tabulate.py create mode 100644 source/op/_tabulate_grad.py create mode 100644 source/op/cuda/tabulate.cu create mode 100644 source/op/data_info.cc create mode 100644 source/op/tabulate.cc create mode 100644 source/op/tabulate_multi_device.cc create mode 100644 source/op/unaggregated_grad.cc create mode 100644 source/train/compress.py diff --git a/deepmd/common.py b/deepmd/common.py index cad4110ac5..e00485b99a 100644 --- a/deepmd/common.py +++ b/deepmd/common.py @@ -216,3 +216,15 @@ def dec(obj): obj.__doc__ = obj.__doc__.format(*sub) return obj return dec + +def get_np_precision(precision): + if precision == "default": + return global_np_float_precision + elif precision == "float16": + return np.float16 + elif precision == "float32": + return np.float32 + elif precision == "float64": + return np.float64 + else: + raise RuntimeError("%d is not a valid precision" % precision) \ No newline at end of file diff --git a/deepmd/descriptor/se_a.py b/deepmd/descriptor/se_a.py index 410cf0d9b4..d7ee320bd4 100644 --- a/deepmd/descriptor/se_a.py +++ b/deepmd/descriptor/se_a.py @@ -1,14 +1,17 @@ +import math import numpy as np from typing import Tuple, List from deepmd.env import tf -from deepmd.common import get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter +from deepmd.common import get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter, get_np_precision from deepmd.utils.argcheck import list_to_doc from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision from deepmd.env import op_module from deepmd.env import default_tf_session_config from deepmd.utils.network import embedding_net +from deepmd.utils.tabulate import DeepTabulate +from tqdm import tqdm class DescrptSeA (): @@ -26,7 +29,10 @@ def __init__ (self, exclude_types: List[int] = [], set_davg_zero: bool = False, activation_function: str = 'tanh', - precision: str = 'default' + precision: str = 'default', + compress: bool = False, + model_file: str = 'frozen_model.pb', + table_info: list = [5, 0.01, 0.1, -1] ) -> None: """ Constructor @@ -60,6 +66,12 @@ def __init__ (self, The activation function in the embedding net. Supported options are {0} precision The precision of the embedding net parameters. Supported options are {1} + compress + Try to compress the embedding nets. Otherwise, building original embedding nets + model_file + The original frozen model, that will be compressed. + table_info + The data info of tabulation. """ self.sel_a = sel self.rcut_r = rcut @@ -71,6 +83,7 @@ def __init__ (self, self.trainable = trainable self.filter_activation_fn = get_activation_func(activation_function) self.filter_precision = get_precision(precision) + self.filter_np_precision = get_np_precision(precision) self.exclude_types = set() for tt in exclude_types: assert(len(tt) == 2) @@ -96,6 +109,13 @@ def __init__ (self, self.useBN = False self.dstd = None self.davg = None + + # compress config + self.compress = compress + self.model_file = model_file + self.table_info = table_info + if (self.compress): + self.table = DeepTabulate(self.model_file, self.filter_np_precision, self.type_one_side) self.place_holders = {} avg_zero = np.zeros([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) @@ -103,7 +123,7 @@ def __init__ (self, sub_graph = tf.Graph() with sub_graph.as_default(): name_pfx = 'd_sea_' - for ii in ['coord', 'box']: + for ii in ['coord', 'box', 'avg', 'std']: self.place_holders[ii] = tf.placeholder(global_np_float_precision, [None, None], name = name_pfx+'t_'+ii) self.place_holders['type'] = tf.placeholder(tf.int32, [None, None], name=name_pfx+'t_type') self.place_holders['natoms_vec'] = tf.placeholder(tf.int32, [self.ntypes+2], name=name_pfx+'t_natoms') @@ -121,6 +141,19 @@ def __init__ (self, rcut_r_smth = self.rcut_r_smth, sel_a = self.sel_a, sel_r = self.sel_r) + descrpt, descrpt_deriv, rij, nlist, self.distance, self.max_nbor_size, self.table_range \ + = op_module.data_info(self.place_holders['coord'], + self.place_holders['type'], + self.place_holders['natoms_vec'], + self.place_holders['box'], + self.place_holders['default_mesh'], + self.place_holders['avg'], + self.place_holders['std'], + rcut_a = self.rcut_a, + rcut_r = self.rcut_r, + rcut_r_smth = self.rcut_r_smth, + sel_a = self.sel_a, + sel_r = self.sel_r) self.sub_sess = tf.Session(graph = sub_graph, config=default_tf_session_config) @@ -324,6 +357,15 @@ def build (self, self.descrpt_deriv = tf.identity(self.descrpt_deriv, name = 'o_rmat_deriv') self.rij = tf.identity(self.rij, name = 'o_rij') self.nlist = tf.identity(self.nlist, name = 'o_nlist') + + if (self.compress): + self.lower = math.floor(self.lower) + self.upper = math.ceil(self.upper) + self.table.build(self.lower, + self.upper, + self.upper * self.table_info[0], + self.table_info[1], + self.table_info[2]) self.dout, self.qmat = self._pass_filter(self.descrpt_reshape, atype, @@ -337,6 +379,58 @@ def build (self, tf.summary.histogram('embedding_net_output', self.dout) return self.dout + def data_info(self, data) -> None: + """ + Print the data info(tabulation boundary, the nearest distance of atoms, max neighbor size) of the training data + + Parameters + ---------- + data + The data class that controls input data information + """ + self.lower = 0.0 + self.upper = 0.0 + self.dist = 100.0 + self.max_nbor = 0 + + davg = self.davg + dstd = self.dstd + if davg is None: + davg = np.zeros([self.ntypes, self.ndescrpt]) + if dstd is None: + dstd = np.ones ([self.ntypes, self.ndescrpt]) + + for ii in tqdm(range(len(data.system_dirs)), desc = '# DEEPMD: getting data info'): + for jj in data.data_systems[ii].dirs: + data_set = data.data_systems[ii]._load_set(jj) + for kk in range(np.array(data_set['type']).shape[0]): + dt, mn, tr \ + = self.sub_sess.run([self.distance, self.max_nbor_size, self.table_range], + feed_dict = { + self.place_holders['coord']: np.array(data_set['coord'])[kk].reshape([-1, data.natoms[ii] * 3]), + self.place_holders['type']: np.array(data_set['type'])[kk].reshape([-1, data.natoms[ii]]), + self.place_holders['natoms_vec']: np.array(data.natoms_vec[ii]), + self.place_holders['box']: np.array(data_set['box'])[kk].reshape([-1, 9]), + self.place_holders['default_mesh']: np.array(data.default_mesh[ii]), + self.place_holders['avg']: davg, + self.place_holders['std']: dstd, + }) + dr = np.array([np.min(tr), np.max(tr)]).astype(global_np_float_precision) + dt = np.min(dt) + mn = np.max(mn) + if (dr[0] < self.lower): + self.lower = dr[0] + if (dr[1] > self.upper): + self.upper = dr[1] + if (dt < self.dist): + self.dist = dt + if (mn > self.max_nbor): + self.max_nbor = mn + + print('# DEEPMD: training data with lower boundary: ' + str(self.lower)) + print('# DEEPMD: training data with upper boundary: ' + str(self.upper)) + print('# DEEPMD: training data with min distance: ' + str(self.dist)) + print('# DEEPMD: training data with max nborsize: ' + str(self.max_nbor)) def get_rot_mat(self) -> tf.Tensor: """ @@ -413,7 +507,10 @@ def _pass_filter(self, [ 0, start_index* self.ndescrpt], [-1, natoms[2+type_i]* self.ndescrpt] ) inputs_i = tf.reshape(inputs_i, [-1, self.ndescrpt]) - layer, qmat = self._filter(tf.cast(inputs_i, self.filter_precision), type_i, name='filter_type_'+str(type_i)+suffix, natoms=natoms, reuse=reuse, seed = self.seed, trainable = trainable, activation_fn = self.filter_activation_fn) + if not self.compress: + layer, qmat = self._filter(tf.cast(inputs_i, self.filter_precision), type_i, name='filter_type_'+str(type_i)+suffix, natoms=natoms, reuse=reuse, seed = self.seed, trainable = trainable, activation_fn = self.filter_activation_fn) + else: + layer, qmat = self._compress_filter(tf.cast(inputs_i, self.filter_precision), type_i, name='filter_type_'+str(type_i)+suffix, natoms=natoms, reuse=reuse, seed = self.seed, trainable = trainable, activation_fn = self.filter_activation_fn) layer = tf.reshape(layer, [tf.shape(inputs)[0], natoms[2+type_i] * self.get_dim_out()]) qmat = tf.reshape(qmat, [tf.shape(inputs)[0], natoms[2+type_i] * self.get_dim_rot_mat_1() * 3]) output.append(layer) @@ -423,7 +520,10 @@ def _pass_filter(self, inputs_i = inputs inputs_i = tf.reshape(inputs_i, [-1, self.ndescrpt]) type_i = -1 - layer, qmat = self._filter(tf.cast(inputs_i, self.filter_precision), type_i, name='filter_type_all'+suffix, natoms=natoms, reuse=reuse, seed = self.seed, trainable = trainable, activation_fn = self.filter_activation_fn) + if not self.compress: + layer, qmat = self._filter(tf.cast(inputs_i, self.filter_precision), type_i, name='filter_type_all'+suffix, natoms=natoms, reuse=reuse, seed = self.seed, trainable = trainable, activation_fn = self.filter_activation_fn) + else: + layer, qmat = self._compress_filter(tf.cast(inputs_i, self.filter_precision), type_i, name='filter_type_all'+suffix, natoms=natoms, reuse=reuse, seed = self.seed, trainable = trainable, activation_fn = self.filter_activation_fn) layer = tf.reshape(layer, [tf.shape(inputs)[0], natoms[0] * self.get_dim_out()]) qmat = tf.reshape(qmat, [tf.shape(inputs)[0], natoms[0] * self.get_dim_rot_mat_1() * 3]) output.append(layer) @@ -559,3 +659,74 @@ def _filter(self, result = tf.reshape(result, [-1, outputs_size_2 * outputs_size[-1]]) return result, qmat + + def _compress_filter(self, + inputs, + type_input, + natoms, + activation_fn=tf.nn.tanh, + stddev=1.0, + bavg=0.0, + name='linear', + reuse=None, + seed=None, + trainable = True): + # natom x (nei x 4) + shape = inputs.get_shape().as_list() + outputs_size = [1] + self.filter_neuron + outputs_size_2 = self.n_axis_neuron + with tf.variable_scope(name, reuse=reuse): + start_index = 0 + xyz_scatter_total = [] + for type_i in range(self.ntypes): + # cut-out inputs + # with natom x (nei_type_i x 4) + inputs_i = tf.slice (inputs, + [ 0, start_index* 4], + [-1, self.sel_a[type_i]* 4] ) + start_index += self.sel_a[type_i] + shape_i = inputs_i.get_shape().as_list() + # with (natom x nei_type_i) x 4 + inputs_reshape = tf.reshape(inputs_i, [-1, 4]) + xyz_scatter = tf.reshape(tf.slice(inputs_reshape, [0,0],[-1,1]),[-1,1]) + if (type_input, type_i) in self.exclude_types: + w = tf.zeros((outputs_size[0], outputs_size[-1]), dtype=global_tf_float_precision) + xyz_scatter = tf.matmul(xyz_scatter, w) + xyz_scatter = tf.reshape(xyz_scatter, (-1, shape_i[1]//4, outputs_size[-1])) + if type_i == 0: + xyz_scatter_1 = tf.matmul(tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]), xyz_scatter, transpose_a = True) + else: + xyz_scatter_1 += tf.matmul(tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]), xyz_scatter, transpose_a = True) + else: + ti = [self.lower, self.upper, self.upper * self.table_info[0], self.table_info[1], self.table_info[2], self.table_info[3]] + if self.type_one_side: + assert type_input == -1, "Error: when type_one_side was set True, the value of type_input must be -1." + net = 'filter_-1_net_' + str(type_i) + else: + net = 'filter_' + str(type_input) + '_net_' + str(type_i) + if type_i == 0: + xyz_scatter_1 = op_module.tabulate_fusion(self.table.data[net], ti, xyz_scatter, tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]), last_layer_size = outputs_size[-1]) + else: + xyz_scatter_1 += op_module.tabulate_fusion(self.table.data[net], ti, xyz_scatter, tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]), last_layer_size = outputs_size[-1]) + # not needed any more! + # natom x nei x outputs_size + # xyz_scatter = tf.concat(xyz_scatter_total, axis=1) + # natom x nei x 4 + # inputs_reshape = tf.reshape(inputs, [-1, shape[1]//4, 4]) + # natom x 4 x outputs_size + # xyz_scatter_1 = tf.matmul(inputs_reshape, xyz_scatter, transpose_a = True) + xyz_scatter_1 = xyz_scatter_1 * (4.0 / shape[1]) + # natom x 4 x outputs_size_2 + xyz_scatter_2 = tf.slice(xyz_scatter_1, [0,0,0],[-1,-1,outputs_size_2]) + # # natom x 3 x outputs_size_2 + # qmat = tf.slice(xyz_scatter_2, [0,1,0], [-1, 3, -1]) + # natom x 3 x outputs_size_1 + qmat = tf.slice(xyz_scatter_1, [0,1,0], [-1, 3, -1]) + # natom x outputs_size_2 x 3 + qmat = tf.transpose(qmat, perm = [0, 2, 1]) + # natom x outputs_size x outputs_size_2 + result = tf.matmul(xyz_scatter_1, xyz_scatter_2, transpose_a = True) + # natom x (outputs_size x outputs_size_2) + result = tf.reshape(result, [-1, outputs_size_2 * outputs_size[-1]]) + + return result, qmat \ No newline at end of file diff --git a/deepmd/utils/tabulate.py b/deepmd/utils/tabulate.py new file mode 100644 index 0000000000..04b3bde7e9 --- /dev/null +++ b/deepmd/utils/tabulate.py @@ -0,0 +1,185 @@ +import re +import math +import numpy as np +import tensorflow.compat.v1 as tf +from tensorflow.python.platform import gfile +from tensorflow.python.framework import tensor_util +from tqdm import tqdm +from deepmd.env import op_module + +class DeepTabulate(): + def __init__(self, + model_file, + data_type, + type_one_side = False): + + self.model_file = model_file + self.data_type = data_type + self.type_one_side = type_one_side + + self.graph, self.graph_def = self.load_graph() + self.sess = tf.Session(graph = self.graph) + + self.sub_graph, self.sub_graph_def = self.load_sub_graph() + self.sub_sess = tf.Session(graph = self.sub_graph) + + self.sel_a = self.graph.get_operation_by_name('DescrptSeA').get_attr('sel_a') + self.ntypes = self.get_tensor_value(self.graph.get_tensor_by_name ('descrpt_attr/ntypes:0')) + + self.filter_variable_nodes = self.load_matrix_node() + self.layer_size = int(len(self.filter_variable_nodes) / (self.ntypes * self.ntypes * 2)) + if type_one_side : + self.layer_size = int(len(self.filter_variable_nodes) / (self.ntypes * 2)) + # self.value_type = self.filter_variable_nodes["filter_type_0/matrix_1_0"].dtype #"filter_type_0/matrix_1_0" must exit~ + # get trained variables + self.bias = self.get_bias() + self.matrix = self.get_matrix() + # self.matrix_layer_3 must exist + # self.data_type = type(self.matrix["layer_1"][0][0][0]) + assert self.matrix["layer_1"][0].size > 0, "no matrix exist in matrix array!" + self.last_layer_size = self.matrix["layer_" + str(self.layer_size)][0].shape[1] + # define tables + self.data = {} + + # TODO: Need a check function to determine if the current model is properly + # Need be more robust! + + def load_graph(self): + graph_def = tf.GraphDef() + with open(self.model_file, "rb") as f: + graph_def.ParseFromString(f.read()) + with tf.Graph().as_default() as graph: + tf.import_graph_def(graph_def, name = "") + return graph, graph_def + + def load_sub_graph(self): + sub_graph_def = tf.GraphDef() + with tf.Graph().as_default() as sub_graph: + tf.import_graph_def(sub_graph_def, name = "") + return sub_graph, sub_graph_def + + def get_tensor_value(self, tensor) : + with self.sess.as_default(): + self.sess.run(tensor) + value = tensor.eval() + return value + + def load_matrix_node(self): + matrix_node = {} + matrix_node_pattern = "filter_type_\d+/matrix_\d+_\d+|filter_type_\d+/bias_\d+_\d+|filter_type_\d+/idt_\d+_\d+|filter_type_all/matrix_\d+_\d+|filter_type_all/bias_\d+_\d+|filter_type_all/idt_\d+_\d" + for node in self.graph_def.node: + if re.fullmatch(matrix_node_pattern, node.name) != None: + matrix_node[node.name] = node.attr["value"].tensor + for key in matrix_node.keys() : + assert key.find('bias') > 0 or key.find('matrix') > 0, "currently, only support weight matrix and bias matrix at the tabulation op!" + return matrix_node + + def get_bias(self): + bias = {} + for layer in range(1, self.layer_size + 1): + bias["layer_" + str(layer)] = [] + if self.type_one_side: + for ii in range(0, self.ntypes): + tensor_value = np.frombuffer (self.filter_variable_nodes["filter_type_all/bias_" + str(layer) + "_" + str(int(ii))].tensor_content) + tensor_shape = tf.TensorShape(self.filter_variable_nodes["filter_type_all/bias_" + str(layer) + "_" + str(int(ii))].tensor_shape).as_list() + bias["layer_" + str(layer)].append(np.reshape(tensor_value, tensor_shape).astype(self.data_type)) + else: + for ii in range(0, self.ntypes * self.ntypes): + tensor_value = np.frombuffer(self.filter_variable_nodes["filter_type_" + str(int(ii / self.ntypes)) + "/bias_" + str(layer) + "_" + str(int(ii % self.ntypes))].tensor_content) + tensor_shape = tf.TensorShape(self.filter_variable_nodes["filter_type_" + str(int(ii / self.ntypes)) + "/bias_" + str(layer) + "_" + str(int(ii % self.ntypes))].tensor_shape).as_list() + bias["layer_" + str(layer)].append(np.reshape(tensor_value, tensor_shape).astype(self.data_type)) + return bias + + def get_matrix(self): + matrix = {} + for layer in range(1, self.layer_size + 1): + matrix["layer_" + str(layer)] = [] + if self.type_one_side: + for ii in range(0, self.ntypes): + tensor_value = np.frombuffer (self.filter_variable_nodes["filter_type_all/matrix_" + str(layer) + "_" + str(int(ii))].tensor_content) + tensor_shape = tf.TensorShape(self.filter_variable_nodes["filter_type_all/matrix_" + str(layer) + "_" + str(int(ii))].tensor_shape).as_list() + matrix["layer_" + str(layer)].append(np.reshape(tensor_value, tensor_shape).astype(self.data_type)) + else: + for ii in range(0, self.ntypes * self.ntypes): + tensor_value = np.frombuffer(self.filter_variable_nodes["filter_type_" + str(int(ii / self.ntypes)) + "/matrix_" + str(layer) + "_" + str(int(ii % self.ntypes))].tensor_content) + tensor_shape = tf.TensorShape(self.filter_variable_nodes["filter_type_" + str(int(ii / self.ntypes)) + "/matrix_" + str(layer) + "_" + str(int(ii % self.ntypes))].tensor_shape).as_list() + matrix["layer_" + str(layer)].append(np.reshape(tensor_value, tensor_shape).astype(self.data_type)) + return matrix + + def build(self, lower, upper, _max, stride0, stride1): + # tabulate range [lower, upper] with stride0 'stride0' + lower = math.floor(lower) + upper = math.ceil(upper) + xx = np.arange(lower, upper, stride0, dtype = self.data_type) + xx = np.append(xx, np.arange(upper, _max, stride1, dtype = self.data_type)) + xx = np.append(xx, np.array([_max], dtype = self.data_type)) + self.nspline = int((upper - lower) / stride0 + (_max - upper) / stride1) + if self.type_one_side: + for ii in range(self.ntypes): + vv, dd, d2 = self.make_data(xx, ii) + net = "filter_-1_net_" + str(int(ii)) + self.data[net] = np.zeros([self.nspline, 6 * self.last_layer_size], dtype = self.data_type) + for jj in tqdm(range(self.nspline), desc = '# DEEPMD: ' + net + ', tabulating'): + for kk in range(self.last_layer_size): + if jj < int((upper - lower) / stride0): + tt = stride0 + else: + tt = stride1 + hh = vv[jj + 1][kk] - vv[jj][kk] + self.data[net][jj][kk * 6 + 0] = vv[jj][kk] + self.data[net][jj][kk * 6 + 1] = dd[jj][kk] + self.data[net][jj][kk * 6 + 2] = 0.5 * d2[jj][kk] + self.data[net][jj][kk * 6 + 3] = (1 / (2 * tt * tt * tt)) * (20 * hh - (8 * dd[jj + 1][kk] + 12 * dd[jj][kk]) * tt - (3 * d2[jj][kk] - d2[jj + 1][kk]) * tt * tt) + self.data[net][jj][kk * 6 + 4] = (1 / (2 * tt * tt * tt * tt)) * (-30 * hh + (14 * dd[jj + 1][kk] + 16 * dd[jj][kk]) * tt + (3 * d2[jj][kk] - 2 * d2[jj + 1][kk]) * tt * tt) + self.data[net][jj][kk * 6 + 5] = (1 / (2 * tt * tt * tt * tt * tt)) * (12 * hh - 6 * (dd[jj + 1][kk] + dd[jj][kk]) * tt + (d2[jj + 1][kk] - d2[jj][kk]) * tt * tt) + else: + for ii in range(self.ntypes * self.ntypes): + vv, dd, d2 = self.make_data(xx, ii) + net = "filter_" + str(int(ii / self.ntypes)) + "_net_" + str(int(ii % self.ntypes)) + self.data[net] = np.zeros([self.nspline, 6 * self.last_layer_size], dtype = self.data_type) + for jj in tqdm(range(self.nspline), desc = '# DEEPMD: ' + net + ', tabulating'): + for kk in range(self.last_layer_size): + if jj < int((upper - lower) / stride0): + tt = stride0 + else: + tt = stride1 + hh = vv[jj + 1][kk] - vv[jj][kk] + self.data[net][jj][kk * 6 + 0] = vv[jj][kk] + self.data[net][jj][kk * 6 + 1] = dd[jj][kk] + self.data[net][jj][kk * 6 + 2] = 0.5 * d2[jj][kk] + self.data[net][jj][kk * 6 + 3] = (1 / (2 * tt * tt * tt)) * (20 * hh - (8 * dd[jj + 1][kk] + 12 * dd[jj][kk]) * tt - (3 * d2[jj][kk] - d2[jj + 1][kk]) * tt * tt) + self.data[net][jj][kk * 6 + 4] = (1 / (2 * tt * tt * tt * tt)) * (-30 * hh + (14 * dd[jj + 1][kk] + 16 * dd[jj][kk]) * tt + (3 * d2[jj][kk] - 2 * d2[jj + 1][kk]) * tt * tt) + self.data[net][jj][kk * 6 + 5] = (1 / (2 * tt * tt * tt * tt * tt)) * (12 * hh - 6 * (dd[jj + 1][kk] + dd[jj][kk]) * tt + (d2[jj + 1][kk] - d2[jj][kk]) * tt * tt) + + # one-by-one executions + def make_data(self, xx, idx): + with self.sub_graph.as_default(): + with self.sub_sess.as_default(): + xx = tf.reshape(xx, [xx.size, -1]) + for layer in range(self.layer_size): + if layer == 0: + yy = self.layer_0(xx, self.matrix["layer_" + str(layer + 1)][idx], self.bias["layer_" + str(layer + 1)][idx]) + dy = op_module.unaggregated_dy_dx_s(yy, self.matrix["layer_" + str(layer + 1)][idx]) + dy2 = op_module.unaggregated_dy2_dx_s(yy, dy, self.matrix["layer_" + str(layer + 1)][idx]) + else: + tt, yy = self.layer_1(yy, self.matrix["layer_" + str(layer + 1)][idx], self.bias["layer_" + str(layer + 1)][idx]) + dz = op_module.unaggregated_dy_dx(yy - tt, self.matrix["layer_" + str(layer + 1)][idx], dy) + dy2 = op_module.unaggregated_dy2_dx(yy - tt, self.matrix["layer_" + str(layer + 1)][idx], dz, dy, dy2) + dy = dz + + vv = yy.eval() + dd = dy.eval() + d2 = dy2.eval() + return vv, dd, d2 + + def layer_0(self, x, w, b): + return tf.nn.tanh(tf.matmul(x, w) + b) + + def layer_1(self, x, w, b): + t = tf.concat([x, x], axis = 1) + return t, tf.nn.tanh(tf.matmul(x, w) + b) + t + + def save_data(self): + for ii in range(self.ntypes * self.ntypes): + net = "filter_" + str(int(ii / self.ntypes)) + "_net_" + str(int(ii % self.ntypes)) + np.savetxt('data_' + str(int(ii)), self.data[net]) \ No newline at end of file diff --git a/source/lib/include/CustomeOperation.h b/source/lib/include/CustomeOperation.h index 0bdd91c3dd..0c0d891fd4 100644 --- a/source/lib/include/CustomeOperation.h +++ b/source/lib/include/CustomeOperation.h @@ -169,7 +169,7 @@ void compute_descriptor_se_a_cpu ( } template -void DescrptSeACPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { +void DescrptSeACPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { // set & normalize coord std::vector d_coord3(nall * 3); for (int ii = 0; ii < nall; ++ii) { @@ -235,8 +235,8 @@ void DescrptSeACPULauncher(const FPTYPE * coord, const int * type, const int * i #if GOOGLE_CUDA template -void DescrptSeAGPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { - DescrptSeAGPUExecuteFunctor()(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); +void DescrptSeAGPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { + DescrptSeAGPUExecuteFunctor()(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); } #endif // GOOGLE_CUDA // ****************************************************************************** @@ -432,7 +432,7 @@ void compute_descriptor_se_r_cpu ( } template -void DescrptSeRCPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { +void DescrptSeRCPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { // set & normalize coord std::vector d_coord3(nall * 3); for (int ii = 0; ii < nall; ++ii) { @@ -498,8 +498,8 @@ void DescrptSeRCPULauncher(const FPTYPE * coord, const int * type, const int * i #if GOOGLE_CUDA template -void DescrptSeRGPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { - DescrptSeRGPUExecuteFunctor()(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); +void DescrptSeRGPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { + DescrptSeRGPUExecuteFunctor()(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); } #endif // GOOGLE_CUDA // ****************************************************************************** @@ -570,3 +570,209 @@ void ProdVirialSeRGPULauncher(FPTYPE * virial, FPTYPE * atom_virial, const FPTYP // ****************************************************************************** // end of custome op ProdVirialSeR // ****************************************************************************** + +template +inline FPTYPE dot(FPTYPE a[4], FPTYPE b[4]) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; +} + +/* + This inline function was designed to get the table info and bias value for current input xx! + lower: indicate the lower boundary of the first table; + upper: indicate the upper boundary of the first table as well as the lower boundary of the second table; + max: indicate the upper boundary of the second table; + stride0: indicate the stride of the first table; + stride1: indicate the stride of the second table; + xx: indicate the inputs value; + table_idx: indicate the location of table info of input value xx; +*/ +template +inline void locate_xx(const FPTYPE& lower, const FPTYPE& upper, const FPTYPE& max, const FPTYPE& stride0, const FPTYPE& stride1, FPTYPE& xx, int& table_idx) { + if (xx < lower) { + table_idx = 0; + xx = 0; + } + else if (xx < upper) { + table_idx = (int)((xx - lower) / stride0); + xx -= (table_idx * stride0 + lower); + } + else if (xx < max) { + int first_stride = int((upper - lower) / stride0); + table_idx = first_stride + (int)((xx - upper) / stride1); + xx -= ((table_idx - first_stride) * stride1 + upper); + } + else { + table_idx = int((upper - lower) / stride0) + (int)((max - upper) / stride1) - 1; + xx = 0; + } +} + +template +void TabulateFusionCPULauncher(const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const int nloc, const int nnei, const int last_layer_size, FPTYPE * out) { + //Currently, Do nothing at all! + // std::cout << "I'm in tabulate @CPU!" << std::endl; + memset(out, 0.0, sizeof(FPTYPE) * nloc * 4 * last_layer_size); + FPTYPE const lower = table_info[0]; + FPTYPE const upper = table_info[1]; + FPTYPE const _max = table_info[2]; + FPTYPE const stride0 = table_info[3]; + FPTYPE const stride1 = table_info[4]; + // for every atom, execute a small gemm~ + // FPTYPE * res = new FPTYPE[4 * last_layer_size]; + #pragma omp parallel for + for (int ii = 0; ii < nloc; ii++) { + FPTYPE ll[4] = {0}; + FPTYPE ago = in[ii * nnei + nnei - 1]; + bool unloop = false; + for (int jj = 0; jj < nnei; jj++) { + ll[0] = ff[ii * nnei * 4 + jj * 4 + 0]; + ll[1] = ff[ii * nnei * 4 + jj * 4 + 1]; + ll[2] = ff[ii * nnei * 4 + jj * 4 + 2]; + ll[3] = ff[ii * nnei * 4 + jj * 4 + 3]; + FPTYPE xx = in[ii * nnei + jj]; + if (ago == xx) { + unloop = true; + } + int table_idx = 0; + locate_xx(lower, upper, _max, stride0, stride1, xx, table_idx); + for (int kk = 0; kk < last_layer_size; kk++) { + // 1.094 timesteps/s + FPTYPE a0 = table[table_idx * last_layer_size * 6 + 6 * kk + 0]; + FPTYPE a1 = table[table_idx * last_layer_size * 6 + 6 * kk + 1]; + FPTYPE a2 = table[table_idx * last_layer_size * 6 + 6 * kk + 2]; + FPTYPE a3 = table[table_idx * last_layer_size * 6 + 6 * kk + 3]; + FPTYPE a4 = table[table_idx * last_layer_size * 6 + 6 * kk + 4]; + FPTYPE a5 = table[table_idx * last_layer_size * 6 + 6 * kk + 5]; + FPTYPE var = a0 + a1 * xx + a2 * xx * xx + a3 * xx * xx * xx + a4 * xx * xx * xx * xx + a5 * xx * xx * xx * xx * xx; + if (unloop) { + out[ii * last_layer_size * 4 + 0 * last_layer_size + kk] += (nnei - jj) * var * ll[0]; + out[ii * last_layer_size * 4 + 1 * last_layer_size + kk] += (nnei - jj) * var * ll[1]; + out[ii * last_layer_size * 4 + 2 * last_layer_size + kk] += (nnei - jj) * var * ll[2]; + out[ii * last_layer_size * 4 + 3 * last_layer_size + kk] += (nnei - jj) * var * ll[3]; + } + else { + out[ii * last_layer_size * 4 + 0 * last_layer_size + kk] += var * ll[0]; + out[ii * last_layer_size * 4 + 1 * last_layer_size + kk] += var * ll[1]; + out[ii * last_layer_size * 4 + 2 * last_layer_size + kk] += var * ll[2]; + out[ii * last_layer_size * 4 + 3 * last_layer_size + kk] += var * ll[3]; + } + } + if (unloop) break; + } + } +} + +template +void TabulateFusionGradCPULauncher(const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const FPTYPE * dy, const int nloc, const int nnei, const int last_layer_size, FPTYPE * dy_dx, FPTYPE * dy_df) { + // std::cout << "I'm in tabulate gradient @CPU!" << std::endl; + memset(dy_dx, 0.0, sizeof(FPTYPE) * nloc * nnei); + memset(dy_df, 0.0, sizeof(FPTYPE) * nloc * nnei * 4); + FPTYPE const lower = table_info[0]; + FPTYPE const upper = table_info[1]; + FPTYPE const _max = table_info[2]; + FPTYPE const stride0 = table_info[3]; + FPTYPE const stride1 = table_info[4]; + // for every atom, execute a small gemm~ + // FPTYPE * res = new FPTYPE[4 * last_layer_size]; + #pragma omp parallel for + for (int ii = 0; ii < nloc; ii++) { + FPTYPE ll[4]; + FPTYPE rr[4]; + FPTYPE ago = in[ii * nnei + nnei - 1]; + bool unloop = false; + for (int jj = 0; jj < nnei; jj++) { + // construct the dy/dx + ll[0] = ff[ii * nnei * 4 + jj * 4 + 0]; + ll[1] = ff[ii * nnei * 4 + jj * 4 + 1]; + ll[2] = ff[ii * nnei * 4 + jj * 4 + 2]; + ll[3] = ff[ii * nnei * 4 + jj * 4 + 3]; + FPTYPE xx = in[ii * nnei + jj]; + if (ago == xx) { + unloop = true; + } + int table_idx = 0; + locate_xx(lower, upper, _max, stride0, stride1, xx, table_idx); + FPTYPE grad = 0.0; + for (int kk = 0; kk < last_layer_size; kk++) { + rr[0] = dy[ii * last_layer_size * 4 + 0 * last_layer_size + kk]; + rr[1] = dy[ii * last_layer_size * 4 + 1 * last_layer_size + kk]; + rr[2] = dy[ii * last_layer_size * 4 + 2 * last_layer_size + kk]; + rr[3] = dy[ii * last_layer_size * 4 + 3 * last_layer_size + kk]; + // 1.094 timesteps/s + FPTYPE a0 = table[table_idx * last_layer_size * 6 + 6 * kk + 0]; + FPTYPE a1 = table[table_idx * last_layer_size * 6 + 6 * kk + 1]; + FPTYPE a2 = table[table_idx * last_layer_size * 6 + 6 * kk + 2]; + FPTYPE a3 = table[table_idx * last_layer_size * 6 + 6 * kk + 3]; + FPTYPE a4 = table[table_idx * last_layer_size * 6 + 6 * kk + 4]; + FPTYPE a5 = table[table_idx * last_layer_size * 6 + 6 * kk + 5]; + FPTYPE res = a0 + a1 * xx + a2 * xx * xx + a3 * xx * xx * xx + a4 * xx * xx * xx * xx + a5 * xx * xx * xx * xx * xx; + if (unloop) { + grad += (a1 + 2 * a2 * xx + 3 * a3 * xx * xx + 4 * a4 * xx * xx * xx + 5 * a5 * xx * xx * xx * xx) * dot(ll, rr) * (nnei - jj); + dy_df[ii * nnei * 4 + jj * 4 + 0] += res * rr[0] * (nnei - jj); + dy_df[ii * nnei * 4 + jj * 4 + 1] += res * rr[1] * (nnei - jj); + dy_df[ii * nnei * 4 + jj * 4 + 2] += res * rr[2] * (nnei - jj); + dy_df[ii * nnei * 4 + jj * 4 + 3] += res * rr[3] * (nnei - jj); + } + else { + grad += (a1 + 2 * a2 * xx + 3 * a3 * xx * xx + 4 * a4 * xx * xx * xx + 5 * a5 * xx * xx * xx * xx) * dot(ll, rr); + dy_df[ii * nnei * 4 + jj * 4 + 0] += res * rr[0]; + dy_df[ii * nnei * 4 + jj * 4 + 1] += res * rr[1]; + dy_df[ii * nnei * 4 + jj * 4 + 2] += res * rr[2]; + dy_df[ii * nnei * 4 + jj * 4 + 3] += res * rr[3]; + } + } + dy_dx[ii * nnei + jj] = grad; + if (unloop) break; + } + } +} + +template +void TabulateCheckerCPULauncher(const FPTYPE * table_info, const FPTYPE * in, int * out, const int nloc, const int nnei) { + FPTYPE const lower = table_info[0]; + FPTYPE const upper = table_info[1]; + FPTYPE const _max = table_info[2]; + FPTYPE const stride0 = table_info[3]; + FPTYPE const stride1 = table_info[4]; + // for every atom, execute a small gemm~ + // FPTYPE * res = new FPTYPE[4 * last_layer_size]; + int Csub = 0; // summation of second table approximate; + int Dsub = 0; // summation of the endpoint approximate; + for (int ii = 0; ii < nloc; ii++) { + for (int jj = 0; jj < nnei; jj++) { + FPTYPE xx = in[ii * nnei + jj]; + if (xx < lower || xx > _max) { + Csub += 1; + } + else if (xx >= upper && xx <= _max) { + Dsub += 1; + } + } + } + if(Csub > 0) { + std::cout << "# DEEPMD: warning! some values [" << Csub << "/" << nloc * nnei << "] overflow the range of the table, using the endpoint approximate processing.." << std::endl; + } + if(Dsub > 0) { + std::cout << "# DEEPMD: warning! some values [" << Dsub << "/" << nloc * nnei << "] overflow the range of the table, using second table approximate processing.." << std::endl; + } +} + +#if GOOGLE_CUDA +template +void TabulateFusionGPULauncher(const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const int nloc, const int nnei, const int last_layer_size, FPTYPE * out) { + TabulateFusionGPUExecuteFunctor()(table, table_info, in, ff, nloc, nnei, last_layer_size, out); +} + +template +void TabulateFusionGradGPULauncher(const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const FPTYPE * dy, const int nloc, const int nnei, const int last_layer_size, FPTYPE * dy_dx, FPTYPE * dy_df) { + TabulateFusionGradGPUExecuteFunctor()(table, table_info, in, ff, dy, nloc, nnei, last_layer_size, dy_dx, dy_df); +} + +template +void TabulateCheckerGPULauncher(const FPTYPE * table_info, const FPTYPE * in, int * out, const int nloc, const int nnei) { + TabulateCheckerGPUExecuteFunctor()(table_info, in, out, nloc, nnei); +} +#endif // GOOGLE_CUDA +// ****************************************************************************** +// end of custome op Tabulate +// ****************************************************************************** diff --git a/source/lib/include/DeviceFunctor.h b/source/lib/include/DeviceFunctor.h index d51d617f84..f482545df3 100644 --- a/source/lib/include/DeviceFunctor.h +++ b/source/lib/include/DeviceFunctor.h @@ -7,6 +7,7 @@ typedef unsigned long long int_64; #define SQRT_2_PI 0.7978845608028654 +#define TPB 256 #define cudaErrcheck(res) {cudaAssert((res), __FILE__, __LINE__);} inline void cudaAssert(cudaError_t code, const char *file, int line, bool abort=true) { @@ -59,4 +60,19 @@ struct GeluGradGPUExecuteFunctor { template struct GeluGradGradGPUExecuteFunctor { void operator()(const FPTYPE * dy, const FPTYPE * dy_, const FPTYPE * in, FPTYPE * out, const int size); +}; + +template +struct TabulateFusionGPUExecuteFunctor { + void operator()(const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const int nloc, const int nnei, const int last_layer_size, FPTYPE * out); +}; + +template +struct TabulateFusionGradGPUExecuteFunctor { + void operator()(const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const FPTYPE * dy, const int nloc, const int nnei, const int last_layer_size, FPTYPE * dy_dx, FPTYPE * dy_df); +}; + +template +struct TabulateCheckerGPUExecuteFunctor { + void operator()(const FPTYPE * table_info, const FPTYPE * in, int * out, const int nloc, const int nnei); }; \ No newline at end of file diff --git a/source/op/CMakeLists.txt b/source/op/CMakeLists.txt index 25f125d6be..0e10c24bb4 100644 --- a/source/op/CMakeLists.txt +++ b/source/op/CMakeLists.txt @@ -3,8 +3,8 @@ set(OP_LIB ${PROJECT_SOURCE_DIR}/lib/src/SimulationRegion.cpp ${PROJECT_SOURCE_DIR}/lib/src/NeighborList.cpp) set (OP_CXX_FLAG -D_GLIBCXX_USE_CXX11_ABI=${OP_CXX_ABI} ) -file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc descrpt_se_r.cc tab_inter.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc gelu.cc map_aparam.cc) -file(GLOB OP_CUDA_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a_multi_device.cc descrpt_se_r_multi_device.cc tab_inter.cc prod_force_se_a_multi_device.cc prod_virial_se_a_multi_device.cc prod_force_se_r_multi_device.cc prod_virial_se_r_multi_device.cc soft_min.cc soft_min_force.cc soft_min_virial.cc gelu_multi_device.cc) +file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc descrpt_se_r.cc tab_inter.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc gelu.cc map_aparam.cc data_info.cc unaggregated_grad.cc tabulate.cc) +file(GLOB OP_CUDA_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a_multi_device.cc descrpt_se_r_multi_device.cc tab_inter.cc prod_force_se_a_multi_device.cc prod_virial_se_a_multi_device.cc prod_force_se_r_multi_device.cc prod_virial_se_r_multi_device.cc soft_min.cc soft_min_force.cc soft_min_virial.cc gelu_multi_device.cc tabulate_multi_device.cc) file(GLOB OP_GRADS_SRC prod_force_grad.cc prod_force_se_a_grad.cc prod_force_se_r_grad.cc prod_virial_grad.cc prod_virial_se_a_grad.cc prod_virial_se_r_grad.cc soft_min_force_grad.cc soft_min_virial_grad.cc ) file(GLOB OP_PY *.py) diff --git a/source/op/_tabulate_grad.py b/source/op/_tabulate_grad.py new file mode 100644 index 0000000000..6f8ba1f8bc --- /dev/null +++ b/source/op/_tabulate_grad.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +""" +Gradients for tabulate. +""" + +from tensorflow.python.framework import ops +from deepmd.env import op_module +from deepmd.env import tf +# from deepmd.DescrptSeATabulate import last_layer_size + +# refine is needed! +# accurate gradient is needed! +# 'tabulate_one_side' is needed! +@ops.RegisterGradient("TabulateGrad") +def _tabulate_grad_cc (op, dy): + return [None, dy] + +@ops.RegisterGradient("TabulateFusionGrad") +def _tabulate_grad_cc (op, dy, dy_): + return [None, None, dy, dy_, None, None] + +# old implementations here. + +@ops.RegisterGradient("Tabulate") +def _tabulate_grad_cc (op, dy, dy_): + dy = op_module.tabulate_grad(dy, op.outputs[1]) + return [None, None, dy] + +@ops.RegisterGradient("TabulateFusion") +def _tabulate_fusion_grad_cc (op, dy): + dy_dx, dy_df = op_module.tabulate_fusion_grad(op.inputs[0], op.inputs[1], op.inputs[2], op.inputs[3], dy, op.outputs[0]) + return [None, None, dy_dx, dy_df] \ No newline at end of file diff --git a/source/op/cuda/CMakeLists.txt b/source/op/cuda/CMakeLists.txt index 89dd0b5922..20ef4d672e 100644 --- a/source/op/cuda/CMakeLists.txt +++ b/source/op/cuda/CMakeLists.txt @@ -28,6 +28,7 @@ if (${CUDA_VERSION_MAJOR} GREATER "10") -gencode arch=compute_61,code=sm_61; # Pascal - GTX 1080, GTX 1070, GTX 1060, GTX 1050, GTX 1030, Titan Xp, Tesla P40, Tesla P4, Discrete GPU on the NVIDIA Drive PX2 -gencode arch=compute_70,code=sm_70; # Volta - GV100/Tesla V100, GTX 1180 (GV104) -gencode arch=compute_75,code=sm_75; # Turing - RTX 2080, Titan RTX, Quadro R8000 + -gencode arch=compute_80,code=sm_86; # Anpere - RTX 2080, Titan RTX, Quadro R8000 -O3; -Xcompiler -fPIC; ) elseif (${CUDA_VERSION_MAJOR} STREQUAL "10") @@ -80,7 +81,7 @@ else () endif() set (SOURCE_FILES - descrpt_se_a.cu descrpt_se_r.cu prod_force_se_a.cu prod_force_se_r.cu prod_virial_se_a.cu prod_virial_se_r.cu gelu.cu + descrpt_se_a.cu descrpt_se_r.cu prod_force_se_a.cu prod_force_se_r.cu prod_virial_se_a.cu prod_virial_se_r.cu gelu.cu tabulate.cu ) cuda_add_library(deepmd_op_cuda SHARED ${SOURCE_FILES}) diff --git a/source/op/cuda/descrpt_se_a.cu b/source/op/cuda/descrpt_se_a.cu index a528c4c477..999d4c2b39 100644 --- a/source/op/cuda/descrpt_se_a.cu +++ b/source/op/cuda/descrpt_se_a.cu @@ -147,8 +147,10 @@ __global__ void format_nlist_fill_b_se_a(int * nlist, } //it's ok! -template -__global__ void compute_descriptor_se_a (FPTYPE* descript, +template< + typename FPTYPE, + int THREADS_PER_BLOCK> +__global__ void compute_descriptor_se_a(FPTYPE* descript, const int ndescrpt, FPTYPE* descript_deriv, const int descript_deriv_size, @@ -164,67 +166,77 @@ __global__ void compute_descriptor_se_a (FPTYPE* descript, const float rmax, const int sec_a_size) { - // <<>> - const unsigned int idx = blockIdx.x; - const unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y; - const int idx_deriv = idy * 4 * 3; // 4 components time 3 directions - const int idx_value = idy * 4; // 4 components - if (idy >= sec_a_size) {return;} + // <<>> + const unsigned int bid = blockIdx.x; + const unsigned int tid = threadIdx.x; + // usually false... + if (tid >= sec_a_size) { + return; + } + // const int idx_deriv = idy * 4 * 3; // 4 components time 3 directions + // const int idx_value = idy * 4; // 4 components + int * row_nlist = nlist + bid * nlist_size; + FPTYPE * row_rij = rij + bid * rij_size; + FPTYPE * row_descript = descript + bid * ndescrpt; + FPTYPE * row_descript_deriv = descript_deriv + bid * descript_deriv_size; - // else {return;} - FPTYPE * row_descript = descript + idx * ndescrpt; - FPTYPE * row_descript_deriv = descript_deriv + idx * descript_deriv_size; - FPTYPE * row_rij = rij + idx * rij_size; - int * row_nlist = nlist + idx * nlist_size; + for (int ii = tid; ii < sec_a_size; ii += THREADS_PER_BLOCK) { + const int idx_value = ii * 4; // 4 components + const int idx_deriv = ii * 12; // 4 components time 3 directions + if (row_nlist[ii] >= 0) { + FPTYPE rr[3] = {0}; + FPTYPE dd[4] = {0}; + FPTYPE vv[12] = {0}; + const int & j_idx = row_nlist[ii]; + for (int kk = 0; kk < 3; kk++) { + rr[kk] = coord[j_idx * 3 + kk] - coord[bid * 3 + kk]; + row_rij[ii * 3 + kk] = rr[kk]; + } + // const FPTYPE * rr = &row_rij[ii * 3]; + FPTYPE nr2 = dev_dot(rr, rr); + FPTYPE inr = 1./sqrt(nr2); + FPTYPE nr = nr2 * inr; + FPTYPE inr2 = inr * inr; + FPTYPE inr4 = inr2 * inr2; + FPTYPE inr3 = inr4 * nr; + FPTYPE sw, dsw; + spline5_switch(sw, dsw, nr, rmin, rmax); + dd[0] = (1./nr) ;//* sw; + dd[1] = (rr[0] / nr2) ;//* sw; + dd[2] = (rr[1] / nr2) ;//* sw; + dd[3] = (rr[2] / nr2) ;//* sw; - if (row_nlist[idy] >= 0) { - const int & j_idx = row_nlist[idy]; - for (int kk = 0; kk < 3; kk++) { - row_rij[idy * 3 + kk] = coord[j_idx * 3 + kk] - coord[idx * 3 + kk]; + vv[0] = (rr[0] * inr3 * sw - dd[0] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 0) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 0) % (ndescrpt * 3)) / 3]; + vv[1] = (rr[1] * inr3 * sw - dd[0] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 1) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 1) % (ndescrpt * 3)) / 3]; + vv[2] = (rr[2] * inr3 * sw - dd[0] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 2) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 2) % (ndescrpt * 3)) / 3]; + // ****deriv of component x/r2 + vv[3] = ((2. * rr[0] * rr[0] * inr4 - inr2) * sw - dd[1] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 3) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 3) % (ndescrpt * 3)) / 3]; + vv[4] = ((2. * rr[0] * rr[1] * inr4 ) * sw - dd[1] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 4) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 4) % (ndescrpt * 3)) / 3]; + vv[5] = ((2. * rr[0] * rr[2] * inr4 ) * sw - dd[1] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 5) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 5) % (ndescrpt * 3)) / 3]; + // ***deriv of component y/r2 + vv[6] = ((2. * rr[1] * rr[0] * inr4 ) * sw - dd[2] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 6) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 6) % (ndescrpt * 3)) / 3]; + vv[7] = ((2. * rr[1] * rr[1] * inr4 - inr2) * sw - dd[2] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 7) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 7) % (ndescrpt * 3)) / 3]; + vv[8] = ((2. * rr[1] * rr[2] * inr4 ) * sw - dd[2] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 8) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 8) % (ndescrpt * 3)) / 3]; + // ***deriv of component z/r2 + vv[9] = ((2. * rr[2] * rr[0] * inr4 ) * sw - dd[3] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 9) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 9) % (ndescrpt * 3)) / 3]; + vv[10]= ((2. * rr[2] * rr[1] * inr4 ) * sw - dd[3] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 10) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 10) % (ndescrpt * 3)) / 3]; + vv[11]= ((2. * rr[2] * rr[2] * inr4 - inr2) * sw - dd[3] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 11) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 11) % (ndescrpt * 3)) / 3]; + // 4 value components + dd[0] *= sw; // * descript[idx * ndescrpt + idx_value + 0]);// - avg[type[idx] * ndescrpt + idx_value + 0]) / std[type[idx] * ndescrpt + idx_value + 0]; + dd[1] *= sw; // * descript[idx * ndescrpt + idx_value + 1]);// - avg[type[idx] * ndescrpt + idx_value + 1]) / std[type[idx] * ndescrpt + idx_value + 1]; + dd[2] *= sw; // * descript[idx * ndescrpt + idx_value + 2]);// - avg[type[idx] * ndescrpt + idx_value + 2]) / std[type[idx] * ndescrpt + idx_value + 2]; + dd[3] *= sw; // * descript[idx * ndescrpt + idx_value + 3]);// - avg[type[idx] * ndescrpt + idx_value + 3]) / std[type[idx] * ndescrpt + idx_value + 3]; + for (int ii = 0; ii < 12; ii++) { + row_descript_deriv[idx_deriv + ii] = vv[ii] / std[type[bid] * ndescrpt + idx_value + ii / 3]; + } + for (int ii = 0; ii < 4; ii++) { + row_descript[idx_value + ii] = (dd[ii] - avg[type[bid] * ndescrpt + idx_value + ii]) / std[type[bid] * ndescrpt + idx_value + ii]; + } + } + else { + // TODO: move it to the memset. + row_descript[idx_value] -= avg[type[bid] * ndescrpt + idx_value] / std[type[bid] * ndescrpt + idx_value]; } - const FPTYPE * rr = &row_rij[idy * 3 + 0]; - FPTYPE nr2 = dev_dot(rr, rr); - FPTYPE inr = 1./sqrt(nr2); - FPTYPE nr = nr2 * inr; - FPTYPE inr2 = inr * inr; - FPTYPE inr4 = inr2 * inr2; - FPTYPE inr3 = inr4 * nr; - FPTYPE sw, dsw; - spline5_switch(sw, dsw, nr, rmin, rmax); - row_descript[idx_value + 0] = (1./nr) ;//* sw; - row_descript[idx_value + 1] = (rr[0] / nr2) ;//* sw; - row_descript[idx_value + 2] = (rr[1] / nr2) ;//* sw; - row_descript[idx_value + 3] = (rr[2] / nr2) ;//* sw; - - row_descript_deriv[idx_deriv + 0] = (rr[0] * inr3 * sw - row_descript[idx_value + 0] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 0) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 0) % (ndescrpt * 3)) / 3]; - row_descript_deriv[idx_deriv + 1] = (rr[1] * inr3 * sw - row_descript[idx_value + 0] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 1) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 1) % (ndescrpt * 3)) / 3]; - row_descript_deriv[idx_deriv + 2] = (rr[2] * inr3 * sw - row_descript[idx_value + 0] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 2) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 2) % (ndescrpt * 3)) / 3]; - // ****deriv of component x/r2 - row_descript_deriv[idx_deriv + 3] = ((2. * rr[0] * rr[0] * inr4 - inr2) * sw - row_descript[idx_value + 1] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 3) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 3) % (ndescrpt * 3)) / 3]; - row_descript_deriv[idx_deriv + 4] = ((2. * rr[0] * rr[1] * inr4 ) * sw - row_descript[idx_value + 1] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 4) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 4) % (ndescrpt * 3)) / 3]; - row_descript_deriv[idx_deriv + 5] = ((2. * rr[0] * rr[2] * inr4 ) * sw - row_descript[idx_value + 1] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 5) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 5) % (ndescrpt * 3)) / 3]; - // ***deriv of component y/r2 - row_descript_deriv[idx_deriv + 6] = ((2. * rr[1] * rr[0] * inr4 ) * sw - row_descript[idx_value + 2] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 6) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 6) % (ndescrpt * 3)) / 3]; - row_descript_deriv[idx_deriv + 7] = ((2. * rr[1] * rr[1] * inr4 - inr2) * sw - row_descript[idx_value + 2] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 7) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 7) % (ndescrpt * 3)) / 3]; - row_descript_deriv[idx_deriv + 8] = ((2. * rr[1] * rr[2] * inr4 ) * sw - row_descript[idx_value + 2] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 8) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 8) % (ndescrpt * 3)) / 3]; - // ***deriv of component z/r2 - row_descript_deriv[idx_deriv + 9] = ((2. * rr[2] * rr[0] * inr4 ) * sw - row_descript[idx_value + 3] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 9) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 9) % (ndescrpt * 3)) / 3]; - row_descript_deriv[idx_deriv +10] = ((2. * rr[2] * rr[1] * inr4 ) * sw - row_descript[idx_value + 3] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 10) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 10) % (ndescrpt * 3)) / 3]; - row_descript_deriv[idx_deriv +11] = ((2. * rr[2] * rr[2] * inr4 - inr2) * sw - row_descript[idx_value + 3] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 11) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 11) % (ndescrpt * 3)) / 3]; - // 4 value components - row_descript[idx_value + 0] *= sw; // * descript[idx * ndescrpt + idx_value + 0]);// - avg[type[idx] * ndescrpt + idx_value + 0]) / std[type[idx] * ndescrpt + idx_value + 0]; - row_descript[idx_value + 1] *= sw; // * descript[idx * ndescrpt + idx_value + 1]);// - avg[type[idx] * ndescrpt + idx_value + 1]) / std[type[idx] * ndescrpt + idx_value + 1]; - row_descript[idx_value + 2] *= sw; // * descript[idx * ndescrpt + idx_value + 2]);// - avg[type[idx] * ndescrpt + idx_value + 2]) / std[type[idx] * ndescrpt + idx_value + 2]; - row_descript[idx_value + 3] *= sw; // * descript[idx * ndescrpt + idx_value + 3]);// - avg[type[idx] * ndescrpt + idx_value + 3]) / std[type[idx] * ndescrpt + idx_value + 3]; - } - - for (int ii = 0; ii < 4; ii++) { - row_descript[idx_value + ii] = (row_descript[idx_value + ii] - avg[type[idx] * ndescrpt + idx_value + ii]) / std[type[idx] * ndescrpt + idx_value + ii]; - } - // idy nloc, idx ndescrpt * 3 - // descript_deriv[idy * ndescrpt * 3 + idx] = (descript_deriv_dev[idy * (ndescrpt * 3) + idx]) / std[type[idy] * ndescrpt + idx / 3]; - for (int ii = 0; ii < 12; ii++) { - row_descript_deriv[idx_deriv + ii] /= std[type[idx] * ndescrpt + (idx_deriv + ii) / 3]; } } @@ -401,26 +413,7 @@ void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const ); } - const int nblock_ = (sec_a.back() + LEN -1) / LEN; - dim3 block_grid(nloc, nblock_); - dim3 thread_grid(1, LEN); - compute_descriptor_se_a<<>> ( - descript, - ndescrpt, - descript_deriv, - ndescrpt * 3, - rij, - nnei * 3, - type, - avg, - std, - nlist, - nnei, - coord, - rcut_r_smth, - rcut_r, - sec_a.back() - ); + compute_descriptor_se_a <<>> (descript, ndescrpt, descript_deriv, ndescrpt * 3, rij, nnei * 3, type, avg, std, nlist, nnei, coord, rcut_r_smth, rcut_r, sec_a.back()); } template struct DescrptSeAGPUExecuteFunctor; diff --git a/source/op/cuda/tabulate.cu b/source/op/cuda/tabulate.cu new file mode 100644 index 0000000000..a7231b413f --- /dev/null +++ b/source/op/cuda/tabulate.cu @@ -0,0 +1,475 @@ +#include +#include +#include +#include +#include // or equivalently +#include +#include "DeviceFunctor.h" + +#define MM 4 +#define KK 4 +#define TPB 256 +#define WARP_SIZE 32 +#define FULL_MASK 0xffffffff + +template +__forceinline__ +__device__ +void locate_xx(const FPTYPE& lower, const FPTYPE& upper, const FPTYPE& max, const FPTYPE& stride0, const FPTYPE& stride1, FPTYPE& xx, int& table_idx) { + if (xx < lower) { + table_idx = 0; + xx = 0; + } + else if (xx < upper) { + table_idx = (int)((xx - lower) / stride0); + xx -= (table_idx * stride0 + lower); + } + else if (xx < max) { + int first_stride = int((upper - lower) / stride0); + table_idx = first_stride + (int)((xx - upper) / stride1); + xx -= ((table_idx - first_stride) * stride1 + upper); + } + else { + table_idx = int((upper - lower) / stride0) + (int)((max - upper) / stride1) - 1; + xx = 0; + } +} + +template +__forceinline__ +__device__ +FPTYPE dot(FPTYPE ll[4], FPTYPE rr[4]) { + return ll[0] * rr[0] + ll[1] * rr[1] + ll[2] * rr[2] + ll[3] * rr[3]; +} + +template +__forceinline__ +__device__ +void warp_reduce(FPTYPE & val) { + for (int offset = 16; offset > 0; offset >>= 1) + val += __shfl_down_sync(FULL_MASK, val, offset); +} + +// last_layer_size must larger than MTILE * KTILE! +// TODO: A more flexible implementation of sparse +template < + typename FPTYPE, + int MTILE, + int KTILE> +__global__ void tabulate_fusion(const FPTYPE * table, const FPTYPE * in, const FPTYPE * ff, FPTYPE * out, const FPTYPE lower, const FPTYPE upper, const FPTYPE max, const FPTYPE stride0, const FPTYPE stride1, const int nnei, const int last_layer_size) { + extern __shared__ int _data[]; + int const block_idx = blockIdx.x; // nloc + int const thread_idx = threadIdx.x; // last_layer_size + FPTYPE ago = __shfl_sync(0xffffffff, in[block_idx * nnei + nnei - 1], 0); + bool unloop = false; + int breakpoint = nnei - 1; + // int const warp_idx = __shfl_sync(0xffffffff, threadIdx.x / 32, 0); + // int const lane_idx = threadIdx.x % 32; + // iteratorC for data reuse... + FPTYPE * iteratorC = (FPTYPE*) &_data[0]; + for (int kk = 0; kk < MTILE; kk++) + iteratorC[kk * last_layer_size + thread_idx] = 0.f; + __syncthreads(); + + for (int ii = 0; ii < nnei; ii++) { + FPTYPE var[4]; + FPTYPE xx = in[block_idx * nnei + ii]; + + if (ago == xx) { + unloop = true; + breakpoint = ii; + } + int table_idx = 0; + locate_xx(lower, upper, max, stride0, stride1, xx, table_idx); + var[0] = table[table_idx * last_layer_size * 4 + thread_idx * 4 + 0]; + var[1] = table[table_idx * last_layer_size * 4 + thread_idx * 4 + 1]; + var[2] = table[table_idx * last_layer_size * 4 + thread_idx * 4 + 2]; + var[3] = table[table_idx * last_layer_size * 4 + thread_idx * 4 + 3]; + FPTYPE res = ((var[0] * xx + var[1]) * xx + var[2]) * xx + var[3]; + for (int kk = 0; kk < MTILE; kk++) { + iteratorC[kk * last_layer_size + thread_idx] += (nnei - breakpoint) * ff[block_idx * nnei * MTILE + ii * MTILE + kk] * res; + } + if (unloop) break; + } + for (int ii = 0; ii < MTILE; ii++) { + out[block_idx * MTILE * last_layer_size + ii * last_layer_size + thread_idx] = iteratorC[ii * last_layer_size + thread_idx]; + } +} + +// last_layer_size must larger than MTILE * KTILE! +// TODO: A more flexible implementation of sparse + + +template < + typename FPTYPE, + int MTILE, + int KTILE> +__global__ void tabulate_fusion_grad_warp_reduce(const FPTYPE * table, const FPTYPE * in, const FPTYPE * ff, const FPTYPE * dy, FPTYPE * dy_dx, FPTYPE * dy_df, const FPTYPE lower, const FPTYPE upper, const FPTYPE max, const FPTYPE stride0, const FPTYPE stride1, const int nnei, const int last_layer_size) { + extern __shared__ int _data[]; + int const block_idx = blockIdx.x; // nloc + int const thread_idx = threadIdx.x; // KTILE * WARP_SIZE, usally 128 here~ + int warp_idx = __shfl_sync(0xffffffff, threadIdx.x / 32, 0); + int lane_idx = threadIdx.x % 32; + int breakpoint = nnei - 1; + bool unloop = false; + + FPTYPE * iteratorA = (FPTYPE *)&_data[0]; // dy + for (int ii = 0; ii < MTILE; ii++) { + if (thread_idx < last_layer_size) { + iteratorA[ii * last_layer_size + thread_idx] = dy[block_idx * MTILE * last_layer_size + ii * last_layer_size + thread_idx]; + } + } + __syncthreads(); + FPTYPE ago = __shfl_sync(0xffffffff, in[block_idx * nnei + nnei - 1], 0); + for (int ii = 0; ii < nnei; ii += KTILE) { + FPTYPE xx = in[block_idx * nnei + ii + warp_idx]; + // if (ago == xx) { + // unloop = true; + // breakpoint = ii; + // } + + int table_idx = 0; + locate_xx(lower, upper, max, stride0, stride1, xx, table_idx); + FPTYPE sum[KTILE] = {0.f}; + FPTYPE Csub = 0.f; + for (int jj = lane_idx; jj < last_layer_size; jj += WARP_SIZE) { + // load iteratorB through table + FPTYPE var[KTILE]; + var[0] = table[table_idx * last_layer_size * 4 + jj * 4 + 0]; + var[1] = table[table_idx * last_layer_size * 4 + jj * 4 + 1]; + var[2] = table[table_idx * last_layer_size * 4 + jj * 4 + 2]; + var[3] = table[table_idx * last_layer_size * 4 + jj * 4 + 3]; + FPTYPE tmp = (var[0] * xx + var[1]) * xx + var[2]; + for (int kk = 0; kk < KTILE; kk++) { + sum[kk] += (nnei - breakpoint) * iteratorA[kk * last_layer_size + jj] * (tmp * xx + var[3]); + } + var[2] = ff[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 0] * iteratorA[0 * last_layer_size + jj]; + var[2] += ff[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 1] * iteratorA[1 * last_layer_size + jj]; + var[2] += ff[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 2] * iteratorA[2 * last_layer_size + jj]; + var[2] += ff[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 3] * iteratorA[3 * last_layer_size + jj]; + Csub += (nnei - breakpoint) * ((2.0 * var[0] * xx + var[1]) * xx + tmp) * var[2]; + } + __syncwarp(); + for (int kk = 0; kk < KTILE; kk++) { + warp_reduce(sum[kk]); + } + warp_reduce(Csub); + if (lane_idx == 0) { + for (int kk = 0; kk < KTILE; kk++) { + dy_df[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + kk] = sum[kk]; + } + dy_dx[block_idx * nnei + ii + warp_idx] = Csub; + } + if (unloop) break; + } +} + +template < + typename FPTYPE, + int MTILE, + int KTILE> +__global__ void tabulate_fusion_special(const FPTYPE * table, const FPTYPE * in, const FPTYPE * ff, FPTYPE * out, const FPTYPE lower, const FPTYPE upper, const FPTYPE max, const FPTYPE stride0, const FPTYPE stride1, const int nnei, const int last_layer_size) { + extern __shared__ int _data[]; + int const block_idx = blockIdx.x; // nloc + int const thread_idx = threadIdx.x; // last_layer_size + FPTYPE ago = __shfl_sync(0xffffffff, in[block_idx * nnei + nnei - 1], 0); + bool unloop = false; + int breakpoint = nnei - 1; + + FPTYPE * iteratorC = (FPTYPE*) &_data[0]; + for (int kk = 0; kk < MTILE; kk++) + iteratorC[kk * last_layer_size + thread_idx] = 0.f; + __syncthreads(); + + for (int ii = 0; ii < nnei; ii++) { + FPTYPE var[6]; + FPTYPE xx = in[block_idx * nnei + ii]; + if (xx == ago) { + unloop = true; + breakpoint = ii; + } + int table_idx = 0; + locate_xx(lower, upper, max, stride0, stride1, xx, table_idx); + var[0] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 0]; + var[1] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 1]; + var[2] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 2]; + var[3] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 3]; + var[4] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 4]; + var[5] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 5]; + FPTYPE res = var[0] + var[1] * xx + var[2] * xx * xx + var[3] * xx * xx * xx + var[4] * xx * xx * xx * xx + var[5] * xx * xx * xx * xx * xx; + for (int kk = 0; kk < MTILE; kk++) { + iteratorC[kk * last_layer_size + thread_idx] += (nnei - breakpoint) * ff[block_idx * nnei * MTILE + ii * MTILE + kk] * res; + } + if (unloop) break; + } + for (int ii = 0; ii < MTILE; ii++) { + out[block_idx * MTILE * last_layer_size + ii * last_layer_size + thread_idx] = iteratorC[ii * last_layer_size + thread_idx]; + } +} + +template < + typename FPTYPE, + int MTILE, + int KTILE> +__global__ void tabulate_fusion_grad_warp_reduce_special(const FPTYPE * table, const FPTYPE * in, const FPTYPE * ff, const FPTYPE * dy, FPTYPE * dy_dx, FPTYPE * dy_df, const FPTYPE lower, const FPTYPE upper, const FPTYPE max, const FPTYPE stride0, const FPTYPE stride1, const int nnei, const int last_layer_size) { + extern __shared__ int _data[]; + int const block_idx = blockIdx.x; // nloc + int const thread_idx = threadIdx.x; // KTILE * WARP_SIZE, usally 128 here~ + int warp_idx = __shfl_sync(0xffffffff, threadIdx.x / 32, 0); + int lane_idx = threadIdx.x % 32; + int breakpoint = nnei - 1; + bool unloop = false; + + FPTYPE * iteratorA = (FPTYPE *)&_data[0]; // dy + for (int ii = 0; ii < MTILE; ii++) { + if (thread_idx < last_layer_size) { + iteratorA[ii * last_layer_size + thread_idx] = dy[block_idx * MTILE * last_layer_size + ii * last_layer_size + thread_idx]; + } + } + __syncthreads(); + FPTYPE ago = __shfl_sync(0xffffffff, in[block_idx * nnei + nnei - 1], 0); + for (int ii = 0; ii < nnei; ii += KTILE) { + FPTYPE xx = in[block_idx * nnei + ii + warp_idx]; + if (ago == xx) { + unloop = true; + breakpoint = ii; + } + + int table_idx = 0; + locate_xx(lower, upper, max, stride0, stride1, xx, table_idx); + FPTYPE sum[KTILE] = {0.f}; + FPTYPE Csub = 0.f; + for (int jj = lane_idx; jj < last_layer_size; jj += WARP_SIZE) { + // load iteratorB through table + FPTYPE a0 = table[table_idx * last_layer_size * 6 + 6 * jj + 0]; + FPTYPE a1 = table[table_idx * last_layer_size * 6 + 6 * jj + 1]; + FPTYPE a2 = table[table_idx * last_layer_size * 6 + 6 * jj + 2]; + FPTYPE a3 = table[table_idx * last_layer_size * 6 + 6 * jj + 3]; + FPTYPE a4 = table[table_idx * last_layer_size * 6 + 6 * jj + 4]; + FPTYPE a5 = table[table_idx * last_layer_size * 6 + 6 * jj + 5]; + FPTYPE res = a0 + a1 * xx + a2 * xx * xx + a3 * xx * xx * xx + a4 * xx * xx * xx * xx + a5 * xx * xx * xx * xx * xx; + for (int kk = 0; kk < KTILE; kk++) { + sum[kk] += (nnei - breakpoint) * iteratorA[kk * last_layer_size + jj] * res; + } + res = ff[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 0] * iteratorA[0 * last_layer_size + jj]; + res += ff[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 1] * iteratorA[1 * last_layer_size + jj]; + res += ff[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 2] * iteratorA[2 * last_layer_size + jj]; + res += ff[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 3] * iteratorA[3 * last_layer_size + jj]; + Csub += (nnei - breakpoint) * (a1 + 2 * a2 * xx + 3 * a3 * xx * xx + 4 * a4 * xx * xx * xx + 5 * a5 * xx * xx * xx * xx) * res; + } + __syncwarp(); + for (int kk = 0; kk < KTILE; kk++) { + warp_reduce(sum[kk]); + } + warp_reduce(Csub); + if (lane_idx == 0) { + for (int kk = 0; kk < KTILE; kk++) { + dy_df[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + kk] = sum[kk]; + } + dy_dx[block_idx * nnei + ii + warp_idx] = Csub; + } + if (unloop) break; + } +} + +template +__global__ void tabulate_checker(const FPTYPE * in, int * out, const FPTYPE lower, const FPTYPE upper, const FPTYPE max, const int nloc, const int nnei) { + __shared__ int Csub[THREADS_PER_BLOCK]; + __shared__ int Dsub[THREADS_PER_BLOCK]; + int const bid = blockIdx.x; + int const tid = threadIdx.x; + + Csub[tid] = 0; + Dsub[tid] = 0; + __syncthreads(); + + for (int ii = tid; ii < nnei; ii += THREADS_PER_BLOCK) { + FPTYPE xx = in[bid * nnei + ii]; + if (xx < lower || xx > max) { + Csub[tid] += 1; + printf("# DEEPMD: level 2 overflow, xx:\t%f\n", xx); + } + else if (xx >= upper && xx <= max) { + Dsub[tid] += 1; + // printf("# DEEPMD: level 1 overflow, xx:\t%f\n", xx); + } + } + __syncthreads(); + // do reduction in shared memory + for (int ii = THREADS_PER_BLOCK >> 1; ii > 0; ii >>= 1) { + if (tid < ii) { + Csub[tid] += Csub[tid + ii]; + Dsub[tid] += Dsub[tid + ii]; + } + __syncthreads(); + } + if (tid == 0) { + out[bid] = Csub[0]; + out[nloc + bid] = Dsub[0]; + } +} + +void TabulateFusionLauncher(const double * table, const double * table_info, const double * in, const double * ff, const int nloc, const int nnei, const int last_layer_size, double * out) { + // std::cout << "I'm in tabulate GPU!" << std::endl; + tabulate_fusion_special <<>>(table, in, ff, out, table_info[0], table_info[1], table_info[2], table_info[3], table_info[4], nnei, last_layer_size); +} +void TabulateFusionLauncher(const float * table, const float * table_info, const float * in, const float * ff, const int nloc, const int nnei, const int last_layer_size, float * out) { + tabulate_fusion_special <<>>(table, in, ff, out, table_info[0], table_info[1], table_info[2], table_info[3], table_info[4], nnei, last_layer_size); +} + +void TabulateFusionGradLauncher(const double * table, const double * table_info, const double * in, const double * ff, const double * dy, const int nloc, const int nnei, const int last_layer_size, double * dy_dx, double * dy_df) { + // cudaMemset(dy_df, 0.0, sizeof(double) * nloc * nnei * 4); + cudaMemset(dy_dx, 0.0, sizeof(double) * nloc * nnei); + cudaMemset(dy_df, 0.0, sizeof(double) * nloc * nnei * 4); + tabulate_fusion_grad_warp_reduce_special <<>>(table, in, ff, dy, dy_dx, dy_df, table_info[0], table_info[1], table_info[2], table_info[3], table_info[4], nnei, last_layer_size); +} +void TabulateFusionGradLauncher(const float * table, const float * table_info, const float * in, const float * ff, const float * dy, const int nloc, const int nnei, const int last_layer_size, float * dy_dx, float * dy_df) { + // cudaMemset(dy_df, 0.0, sizeof(float) * nloc * nnei * 4); + cudaMemset(dy_dx, 0.0, sizeof(float) * nloc * nnei); + cudaMemset(dy_df, 0.0, sizeof(float) * nloc * nnei * 4); + tabulate_fusion_grad_warp_reduce_special <<>>(table, in, ff, dy, dy_dx, dy_df, table_info[0], table_info[1], table_info[2], table_info[3], table_info[4], nnei, last_layer_size); +} + +void TabulateCheckerLauncher(const double * table_info, const double * in, int * out, const int nloc, const int nnei) { + tabulate_checker <<>>(in, out, table_info[0], table_info[1], table_info[2], nloc, nnei); + // Declare, allocate, and initialize device-accessible pointers for input and output + int * d_out = NULL; + int * h_out = NULL; + cudaMalloc((void **)&d_out, sizeof(int)); + h_out = (int*)malloc(sizeof(int)); + // Determine temporary device storage requirements + void *d_temp_storage = NULL; + size_t temp_storage_bytes = 0; + cub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, out, d_out, nloc); + + // Allocate temporary storage + cudaMalloc(&d_temp_storage, temp_storage_bytes); + + // Run sum-reduction + cub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, out, d_out, nloc); + + // d_out <-- [38] + cudaMemcpy(h_out, d_out, sizeof(int), cudaMemcpyDeviceToHost); + + if(h_out[0] > 0) { + std::cout << "# DEEPMD: warning! some values [" << h_out[0] << "/" << nloc * nnei << "] overflow the range of the table, using the endpoint approximate processing.." << std::endl; + } + + // Run sum-reduction + cub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, out + nloc, d_out, nloc); + + // d_out <-- [38] + cudaMemcpy(h_out, d_out, sizeof(int), cudaMemcpyDeviceToHost); + + if(h_out[0] > 0) { + std::cout << "# DEEPMD: warning! some values [" << h_out[0] << "/" << nloc * nnei << "] overflow the range of the table, using second table approximate processing.." << std::endl; + } + + // free the temperary storage + cudaFree(d_out); + cudaFree(d_temp_storage); + free(h_out); +} + +void TabulateCheckerLauncher(const float * table_info, const float * in, int * out, const int nloc, const int nnei) { + tabulate_checker <<>>(in, out, table_info[0], table_info[1], table_info[2], nloc, nnei); + // Declare, allocate, and initialize device-accessible pointers for input and output + int * d_out = NULL; + int * h_out = NULL; + cudaMalloc((void **)&d_out, sizeof(int)); + h_out = (int*)malloc(sizeof(int)); + // Determine temporary device storage requirements + void *d_temp_storage = NULL; + size_t temp_storage_bytes = 0; + cub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, out, d_out, nloc); + + // Allocate temporary storage + cudaMalloc(&d_temp_storage, temp_storage_bytes); + + // Run sum-reduction + cub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, out, d_out, nloc); + + // d_out <-- [38] + cudaMemcpy(h_out, d_out, sizeof(int), cudaMemcpyDeviceToHost); + + if(h_out[0] > 0) { + std::cout << "# DEEPMD: warning! some values [" << h_out[0] << "/" << nloc * nnei << "] overflow the range of the table, using the endpoint approximate processing.." << std::endl; + } + + // Run sum-reduction + cub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, out + nloc, d_out, nloc); + + // d_out <-- [38] + cudaMemcpy(h_out, d_out, sizeof(int), cudaMemcpyDeviceToHost); + + if(h_out[0] > 0) { + std::cout << "# DEEPMD: warning! some values [" << h_out[0] << "/" << nloc * nnei << "] overflow the range of the table, using second table approximate processing.." << std::endl; + } + + // free the temperary storage + cudaFree(d_out); + cudaFree(d_temp_storage); + free(h_out); +} + +template +void TabulateFusionGPUExecuteFunctor::operator()(const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const int nloc, const int nnei, const int last_layer_size, FPTYPE * out) { + tabulate_fusion_special <<>>(table, in, ff, out, table_info[0], table_info[1], table_info[2], table_info[3], table_info[4], nnei, last_layer_size); +} + +template +void TabulateFusionGradGPUExecuteFunctor::operator()(const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const FPTYPE * dy, const int nloc, const int nnei, const int last_layer_size, FPTYPE * dy_dx, FPTYPE * dy_df) { + cudaErrcheck(cudaMemset(dy_dx, 0.0, sizeof(FPTYPE) * nloc * nnei)); + cudaErrcheck(cudaMemset(dy_df, 0.0, sizeof(FPTYPE) * nloc * nnei * 4)); + tabulate_fusion_grad_warp_reduce_special <<>>(table, in, ff, dy, dy_dx, dy_df, table_info[0], table_info[1], table_info[2], table_info[3], table_info[4], nnei, last_layer_size); +} + +template +void TabulateCheckerGPUExecuteFunctor::operator()(const FPTYPE * table_info, const FPTYPE * in, int * out, const int nloc, const int nnei) { + tabulate_checker <<>>(in, out, table_info[0], table_info[1], table_info[2], nloc, nnei); + // Declare, allocate, and initialize device-accessible pointers for input and output + int * d_out = NULL; + int * h_out = NULL; + cudaMalloc((void **)&d_out, sizeof(int)); + h_out = (int*)malloc(sizeof(int)); + // Determine temporary device storage requirements + void *d_temp_storage = NULL; + size_t temp_storage_bytes = 0; + cub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, out, d_out, nloc); + + // Allocate temporary storage + cudaMalloc(&d_temp_storage, temp_storage_bytes); + + // Run sum-reduction + cub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, out, d_out, nloc); + + // d_out <-- [38] + cudaMemcpy(h_out, d_out, sizeof(int), cudaMemcpyDeviceToHost); + + if(h_out[0] > 0) { + std::cout << "# DEEPMD: warning! some values [" << h_out[0] << "/" << nloc * nnei << "] overflow the range of the table, using the endpoint approximate processing.." << std::endl; + } + + // Run sum-reduction + cub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, out + nloc, d_out, nloc); + + // d_out <-- [38] + cudaMemcpy(h_out, d_out, sizeof(int), cudaMemcpyDeviceToHost); + + if(h_out[0] > 0) { + std::cout << "# DEEPMD: warning! some values [" << h_out[0] << "/" << nloc * nnei << "] overflow the range of the table, using second table approximate processing.." << std::endl; + } + + // free the temperary storage + cudaFree(d_out); + cudaFree(d_temp_storage); + free(h_out); +} + +template struct TabulateFusionGPUExecuteFunctor; +template struct TabulateFusionGPUExecuteFunctor; +template struct TabulateFusionGradGPUExecuteFunctor; +template struct TabulateFusionGradGPUExecuteFunctor; +template struct TabulateCheckerGPUExecuteFunctor; +template struct TabulateCheckerGPUExecuteFunctor; \ No newline at end of file diff --git a/source/op/data_info.cc b/source/op/data_info.cc new file mode 100644 index 0000000000..08e0f77691 --- /dev/null +++ b/source/op/data_info.cc @@ -0,0 +1,408 @@ +#include "tensorflow/core/framework/op.h" +#include "tensorflow/core/framework/op_kernel.h" +#include "tensorflow/core/framework/shape_inference.h" +#include + +#include "ComputeDescriptor.h" +#include "NeighborList.h" + +typedef double boxtensor_t ; +typedef double compute_t; + +using namespace tensorflow; +// using namespace std; + +using CPUDevice = Eigen::ThreadPoolDevice; +using GPUDevice = Eigen::GpuDevice; + +REGISTER_OP("DataInfo") + .Attr("T: {float, double}") + .Input("coord: T") //atomic coordinates + .Input("type: int32") //atomic type + .Input("natoms: int32") //local atomic number; each type atomic number; daizheyingxiangqude atomic numbers + .Input("box : T") + .Input("mesh : int32") + .Input("davg: T") //average value of data + .Input("dstd: T") //standard deviation + .Attr("rcut_a: float") //no use + .Attr("rcut_r: float") + .Attr("rcut_r_smth: float") + .Attr("sel_a: list(int)") + .Attr("sel_r: list(int)") //all zero + .Output("descrpt: T") + .Output("descrpt_deriv: T") + .Output("rij: T") + .Output("nlist: int32") + .Output("distance: T") + .Output("max_nbor_size: int32") + .Output("table_range: T"); + +template +class DataInfoOp : public OpKernel { +public: + explicit DataInfoOp(OpKernelConstruction* context) : OpKernel(context) { + OP_REQUIRES_OK(context, context->GetAttr("rcut_a", &rcut_a)); + OP_REQUIRES_OK(context, context->GetAttr("rcut_r", &rcut_r)); + OP_REQUIRES_OK(context, context->GetAttr("rcut_r_smth", &rcut_r_smth)); + OP_REQUIRES_OK(context, context->GetAttr("sel_a", &sel_a)); + OP_REQUIRES_OK(context, context->GetAttr("sel_r", &sel_r)); + cum_sum (sec_a, sel_a); + cum_sum (sec_r, sel_r); + ndescrpt_a = sec_a.back() * 4; + ndescrpt_r = sec_r.back() * 1; + ndescrpt = ndescrpt_a + ndescrpt_r; + nnei_a = sec_a.back(); + nnei_r = sec_r.back(); + nnei = nnei_a + nnei_r; + fill_nei_a = (rcut_a < 0); + count_nei_idx_overflow = 0; + } + + void Compute(OpKernelContext* context) override { + counter++; + // Grab the input tensor + int context_input_index = 0; + const Tensor& coord_tensor = context->input(context_input_index++); + const Tensor& type_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); + const Tensor& box_tensor = context->input(context_input_index++); + const Tensor& mesh_tensor = context->input(context_input_index++); + const Tensor& avg_tensor = context->input(context_input_index++); + const Tensor& std_tensor = context->input(context_input_index++); + + // set size of the sample + OP_REQUIRES (context, (coord_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of coord should be 2")); + OP_REQUIRES (context, (type_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of type should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + OP_REQUIRES (context, (box_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of box should be 2")); + OP_REQUIRES (context, (mesh_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of mesh should be 1")); + OP_REQUIRES (context, (avg_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of avg should be 2")); + OP_REQUIRES (context, (std_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of std should be 2")); + OP_REQUIRES (context, (fill_nei_a), errors::InvalidArgument ("Rotational free descriptor only support the case rcut_a < 0")); + OP_REQUIRES (context, (sec_r.back() == 0), errors::InvalidArgument ("Rotational free descriptor only support all-angular information: sel_r should be all zero.")); + + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + auto natoms = natoms_tensor .flat(); + int nloc = natoms(0); + int nall = natoms(1); + int ntypes = natoms_tensor.shape().dim_size(0) - 2; + int nsamples = coord_tensor.shape().dim_size(0); + + // check the sizes + OP_REQUIRES (context, (nsamples == type_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nsamples == box_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (ntypes == avg_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of avg should be ntype")); + OP_REQUIRES (context, (ntypes == std_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of std should be ntype")); + + OP_REQUIRES (context, (nall * 3 == coord_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); + OP_REQUIRES (context, (nall == type_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); + OP_REQUIRES (context, (9 == box_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of box should be 9")); + OP_REQUIRES (context, (ndescrpt == avg_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of avg should be ndescrpt")); + OP_REQUIRES (context, (ndescrpt == std_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of std should be ndescrpt")); + + int nei_mode = 0; + if (mesh_tensor.shape().dim_size(0) == 16) { + // lammps neighbor list + nei_mode = 3; + } + else if (mesh_tensor.shape().dim_size(0) == 12) { + // user provided extended mesh + nei_mode = 2; + } + else if (mesh_tensor.shape().dim_size(0) == 6) { + // manual copied pbc + assert (nloc == nall); + nei_mode = 1; + } + else if (mesh_tensor.shape().dim_size(0) == 0) { + // no pbc + nei_mode = -1; + } + else { + throw std::runtime_error("invalid mesh tensor"); + } + bool b_pbc = true; + // if region is given extended, do not use pbc + if (nei_mode >= 1 || nei_mode == -1) { + b_pbc = false; + } + bool b_norm_atom = false; + if (nei_mode == 1){ + b_norm_atom = true; + } + + // Create an output tensor + TensorShape descrpt_shape ; + descrpt_shape.AddDim (nsamples); + descrpt_shape.AddDim (nloc * ndescrpt); + TensorShape descrpt_deriv_shape ; + descrpt_deriv_shape.AddDim (nsamples); + descrpt_deriv_shape.AddDim (nloc * ndescrpt * 3); + TensorShape rij_shape ; + rij_shape.AddDim (nsamples); + rij_shape.AddDim (nloc * nnei * 3); + TensorShape nlist_shape ; + nlist_shape.AddDim (nsamples); + nlist_shape.AddDim (nloc * nnei); + TensorShape distance_shape ; + distance_shape.AddDim (nloc * nnei); + TensorShape max_nbor_size_shape ; + max_nbor_size_shape.AddDim (nloc); + TensorShape table_range_shape ; + table_range_shape.AddDim (nloc * nnei); + + int context_output_index = 0; + Tensor* descrpt_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + descrpt_shape, + &descrpt_tensor)); + Tensor* descrpt_deriv_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + descrpt_deriv_shape, + &descrpt_deriv_tensor)); + Tensor* rij_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + rij_shape, + &rij_tensor)); + Tensor* nlist_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + nlist_shape, + &nlist_tensor)); + + Tensor* distance_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + distance_shape, + &distance_tensor)); + Tensor* max_nbor_size_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + max_nbor_size_shape, + &max_nbor_size_tensor)); + Tensor* table_range_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + table_range_shape, + &table_range_tensor)); + + auto coord = coord_tensor .matrix(); + auto type = type_tensor .matrix(); + auto box = box_tensor .matrix(); + auto mesh = mesh_tensor .flat(); + auto avg = avg_tensor .matrix(); + auto std = std_tensor .matrix(); + auto descrpt = descrpt_tensor ->matrix(); + auto descrpt_deriv = descrpt_deriv_tensor ->matrix(); + auto rij = rij_tensor ->matrix(); + auto nlist = nlist_tensor ->matrix(); + auto distance = distance_tensor ->flat(); + // find a potential bug here! + auto max_nbor_size = max_nbor_size_tensor ->flat(); + auto table_range = table_range_tensor ->flat(); + + for (int ii = 0; ii < static_cast(distance_tensor->NumElements()); ii++) { + distance(ii) = 10000.0; + } + for (int ii = 0; ii < static_cast(max_nbor_size_tensor->NumElements()); ii++) { + max_nbor_size(ii) = 0; + } + for (int ii = 0; ii < static_cast(table_range_tensor->NumElements()); ii++) { + table_range(ii) = 0.0; + } + // // check the types + // int max_type_v = 0; + // for (int ii = 0; ii < natoms; ++ii){ + // if (type(0, ii) > max_type_v) max_type_v = type(0, ii); + // } + // int ntypes = max_type_v + 1; + OP_REQUIRES (context, (ntypes == int(sel_a.size())), errors::InvalidArgument ("number of types should match the length of sel array")); + OP_REQUIRES (context, (ntypes == int(sel_r.size())), errors::InvalidArgument ("number of types should match the length of sel array")); + + for (int kk = 0; kk < nsamples; ++kk){ + // set region + boxtensor_t boxt [9] = {0}; + for (int dd = 0; dd < 9; ++dd) { + boxt[dd] = box(kk, dd); + } + SimulationRegion region; + region.reinitBox (boxt); + + // set & normalize coord + std::vector d_coord3 (nall*3); + for (int ii = 0; ii < nall; ++ii){ + for (int dd = 0; dd < 3; ++dd){ + d_coord3[ii*3+dd] = coord(kk, ii*3+dd); + } + if (b_norm_atom){ + compute_t inter[3]; + region.phys2Inter (inter, &d_coord3[3*ii]); + for (int dd = 0; dd < 3; ++dd){ + if (inter[dd] < 0 ) inter[dd] += 1.; + else if (inter[dd] >= 1) inter[dd] -= 1.; + } + region.inter2Phys (&d_coord3[3*ii], inter); + } + } + + // set type + std::vector d_type (nall); + for (int ii = 0; ii < nall; ++ii) d_type[ii] = type(kk, ii); + + // build nlist + std::vector > d_nlist_a; + std::vector > d_nlist_r; + std::vector nlist_map; + bool b_nlist_map = false; + if (nei_mode == 3) { + int * pilist, *pjrange, *pjlist; + memcpy (&pilist, &mesh(4), sizeof(int *)); + memcpy (&pjrange, &mesh(8), sizeof(int *)); + memcpy (&pjlist, &mesh(12), sizeof(int *)); + int inum = mesh(1); + assert (inum == nloc); + d_nlist_a.resize (inum); + d_nlist_r.resize (inum); + for (unsigned ii = 0; ii < inum; ++ii){ + d_nlist_r.reserve (pjrange[inum] / inum + 10); + } + for (unsigned ii = 0; ii < inum; ++ii){ + int i_idx = pilist[ii]; + for (unsigned jj = pjrange[ii]; jj < pjrange[ii+1]; ++jj){ + int j_idx = pjlist[jj]; + d_nlist_r[i_idx].push_back (j_idx); + } + } + } + else if (nei_mode == 2) { + // std::cout << "I'm in nei_mode 2" << std::endl; + std::vector nat_stt = {mesh(1-1), mesh(2-1), mesh(3-1)}; + std::vector nat_end = {mesh(4-1), mesh(5-1), mesh(6-1)}; + std::vector ext_stt = {mesh(7-1), mesh(8-1), mesh(9-1)}; + std::vector ext_end = {mesh(10-1), mesh(11-1), mesh(12-1)}; + std::vector global_grid (3); + for (int dd = 0; dd < 3; ++dd) global_grid[dd] = nat_end[dd] - nat_stt[dd]; + ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, rcut_a, rcut_r, nat_stt, nat_end, ext_stt, ext_end, region, global_grid); + } + else if (nei_mode == 1) { + // std::cout << "I'm in nei_mode 1" << std::endl; + std::vector bk_d_coord3 = d_coord3; + std::vector bk_d_type = d_type; + std::vector ncell, ngcell; + copy_coord(d_coord3, d_type, nlist_map, ncell, ngcell, bk_d_coord3, bk_d_type, rcut_r, region); + b_nlist_map = true; + std::vector nat_stt(3, 0); + std::vector ext_stt(3), ext_end(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, rcut_a, rcut_r, nat_stt, ncell, ext_stt, ext_end, region, ncell); + } + else if (nei_mode == -1){ + ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, rcut_a, rcut_r, NULL); + } + else { + throw std::runtime_error("unknow neighbor mode"); + } + + for (int ii = 0; ii < nloc; ii++) { + max_nbor_size(ii) = d_nlist_r[ii].size(); + } + // loop over atoms, compute descriptors for each atom +#pragma omp parallel for + for (int ii = 0; ii < nloc; ++ii){ + std::vector fmt_nlist_a; + std::vector fmt_nlist_r; + int ret = -1; + if (fill_nei_a){ + if ((ret = format_nlist_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ + if (count_nei_idx_overflow == 0) { + std::cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << std::endl; + flush(std::cout); + count_nei_idx_overflow ++; + } + } + } + + std::vector d_descrpt_a; + std::vector d_descrpt_a_deriv; + std::vector d_descrpt_r; + std::vector d_descrpt_r_deriv; + std::vector d_rij_a; + std::vector d_rij_r; + compute_descriptor_se_a (d_descrpt_a, + d_descrpt_a_deriv, + d_rij_a, + d_coord3, + ntypes, + d_type, + region, + b_pbc, + ii, + fmt_nlist_a, + sec_a, + rcut_r_smth, + rcut_r); + + // check sizes + assert (d_descrpt_a.size() == ndescrpt_a); + assert (d_descrpt_a_deriv.size() == ndescrpt_a * 3); + assert (d_rij_a.size() == nnei_a * 3); + assert (int(fmt_nlist_a.size()) == nnei_a); + // std::cout << "min:\t" << (0 - avg(0, 0)) / std(0, 0) << std::endl; + // if (counter % 1000 == 0) { + // std::cout << "min:\t" << (0 - avg(0, 0)) / std(0, 0) << std::endl; + // } + // record outputs + for (int jj = 0; jj < ndescrpt_a; ++jj) { + descrpt(kk, ii * ndescrpt + jj) = (d_descrpt_a[jj] - avg(d_type[ii], jj)) / std(d_type[ii], jj); + if (jj % 4 == 0) { + table_range(ii * nnei + jj / 4) = descrpt(kk, ii * ndescrpt + jj); + } + } + for (int jj = 0; jj < ndescrpt_a * 3; ++jj) { + descrpt_deriv(kk, ii * ndescrpt * 3 + jj) = d_descrpt_a_deriv[jj] / std(d_type[ii], jj/3); + } + for (int jj = 0; jj < nnei_a * 3; ++jj){ + rij (kk, ii * nnei * 3 + jj) = d_rij_a[jj]; + if (jj % 3 == 0 && d_rij_a[jj] > 0) { + distance(ii * nnei + jj / 3) = sqrt(d_rij_a[jj] * d_rij_a[jj] + d_rij_a[jj + 1] * d_rij_a[jj + 1] + d_rij_a[jj + 2] * d_rij_a[jj + 2]); + } + } + for (int jj = 0; jj < nnei_a; ++jj){ + int record = fmt_nlist_a[jj]; + if (b_nlist_map && record >= 0) { + record = nlist_map[record]; + } + nlist (kk, ii * nnei + jj) = record; + } + } + } + } +private: + int counter = -1; + float rcut_a; + float rcut_r; + float rcut_r_smth; + std::vector sel_r; + std::vector sel_a; + std::vector sec_a; + std::vector sec_r; + int ndescrpt, ndescrpt_a, ndescrpt_r; + int nnei, nnei_a, nnei_r; + bool fill_nei_a; + int count_nei_idx_overflow; + void + cum_sum (std::vector & sec, + const std::vector & n_sel) const { + sec.resize (n_sel.size() + 1); + sec[0] = 0; + for (int ii = 1; ii < sec.size(); ++ii){ + sec[ii] = sec[ii-1] + n_sel[ii-1]; + } + } +}; + +#define REGISTER_CPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("DataInfo").Device(DEVICE_CPU).TypeConstraint("T"), \ + DataInfoOp); +REGISTER_CPU(float); +REGISTER_CPU(double); \ No newline at end of file diff --git a/source/op/tabulate.cc b/source/op/tabulate.cc new file mode 100644 index 0000000000..14e9b51474 --- /dev/null +++ b/source/op/tabulate.cc @@ -0,0 +1,379 @@ +#include "tensorflow/core/framework/op.h" +#include "tensorflow/core/framework/op_kernel.h" +#include "tensorflow/core/framework/register_types.h" +#include "tensorflow/core/framework/shape_inference.h" + +using namespace tensorflow; +using CPUDevice = Eigen::ThreadPoolDevice; +using GPUDevice = Eigen::GpuDevice; + +REGISTER_OP("TabulateFusion") + .Attr("T: {float, double}") + .Input("table: T") + .Input("table_info: T") + .Input("input: T") + .Input("ff: T") + .Attr("last_layer_size: int") + .Output("output: T"); + +REGISTER_OP("TabulateFusionGrad") + .Attr("T: {float, double}") + .Input("table: T") + .Input("table_info: T") + .Input("input: T") + .Input("ff: T") + .Input("dy: T") + .Input("output: T") + .Output("dy_dx: T") + .Output("dy_df: T"); + +void TabulateFusionLauncher(const float * table, const float * table_info, const float * in, const float * ff, const int nloc, const int nnei, const int last_layer_size, float * out); +void TabulateFusionLauncher(const double * table, const double * table_info, const double * in, const double * ff, const int nloc, const int nnei, const int last_layer_size, double * out); +void TabulateFusionGradLauncher(const float * table, const float * table_info, const float * in, const float * ff, const float * dy, const int nloc, const int nnei, const int last_layer_size, float * dy_dx, float * dy_df); +void TabulateFusionGradLauncher(const double * table, const double * table_info, const double * in, const double * ff, const double * dy, const int nloc, const int nnei, const int last_layer_size, double * dy_dx, double * dy_df); +void TabulateCheckerLauncher(const float * table_info, const float * in, int * out, const int nloc, const int nnei); +void TabulateCheckerLauncher(const double * table_info, const double * in, int * out, const int nloc, const int nnei); + +template +inline FPTYPE dot(FPTYPE a[4], FPTYPE b[4]) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; +} + +/* + This inline function was designed to get the table info and bias value for current input xx! + lower: indicate the lower boundary of the first table; + upper: indicate the upper boundary of the first table as well as the lower boundary of the second table; + max: indicate the upper boundary of the second table; + stride0: indicate the stride of the first table; + stride1: indicate the stride of the second table; + xx: indicate the inputs value; + table_idx: indicate the location of table info of input value xx; +*/ +template +inline void locate_xx(const FPTYPE& lower, const FPTYPE& upper, const FPTYPE& max, const FPTYPE& stride0, const FPTYPE& stride1, FPTYPE& xx, int& table_idx) { + if (xx < lower) { + table_idx = 0; + xx = 0; + } + else if (xx < upper) { + table_idx = (int)((xx - lower) / stride0); + xx -= (table_idx * stride0 + lower); + } + else if (xx < max) { + int first_stride = int((upper - lower) / stride0); + table_idx = first_stride + (int)((xx - upper) / stride1); + xx -= ((table_idx - first_stride) * stride1 + upper); + } + else { + table_idx = int((upper - lower) / stride0) + (int)((max - upper) / stride1) - 1; + xx = 0; + } +} + +template +struct TabulateFusionFunctor { + void operator()(const CPUDevice& d, const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const int nloc, const int nnei, const int last_layer_size, FPTYPE * out) { + //Currently, Do nothing at all! + // std::cout << "I'm in tabulate @CPU!" << std::endl; + memset(out, 0.0, sizeof(FPTYPE) * nloc * 4 * last_layer_size); + FPTYPE const lower = table_info[0]; + FPTYPE const upper = table_info[1]; + FPTYPE const _max = table_info[2]; + FPTYPE const stride0 = table_info[3]; + FPTYPE const stride1 = table_info[4]; + // for every atom, execute a small gemm~ + // FPTYPE * res = new FPTYPE[4 * last_layer_size]; + #pragma omp parallel for + for (int ii = 0; ii < nloc; ii++) { + FPTYPE ll[4] = {0}; + FPTYPE ago = in[ii * nnei + nnei - 1]; + bool unloop = false; + for (int jj = 0; jj < nnei; jj++) { + ll[0] = ff[ii * nnei * 4 + jj * 4 + 0]; + ll[1] = ff[ii * nnei * 4 + jj * 4 + 1]; + ll[2] = ff[ii * nnei * 4 + jj * 4 + 2]; + ll[3] = ff[ii * nnei * 4 + jj * 4 + 3]; + FPTYPE xx = in[ii * nnei + jj]; + if (ago == xx) { + unloop = true; + } + int table_idx = 0; + locate_xx(lower, upper, _max, stride0, stride1, xx, table_idx); + for (int kk = 0; kk < last_layer_size; kk++) { + // 1.094 timesteps/s + FPTYPE a0 = table[table_idx * last_layer_size * 6 + 6 * kk + 0]; + FPTYPE a1 = table[table_idx * last_layer_size * 6 + 6 * kk + 1]; + FPTYPE a2 = table[table_idx * last_layer_size * 6 + 6 * kk + 2]; + FPTYPE a3 = table[table_idx * last_layer_size * 6 + 6 * kk + 3]; + FPTYPE a4 = table[table_idx * last_layer_size * 6 + 6 * kk + 4]; + FPTYPE a5 = table[table_idx * last_layer_size * 6 + 6 * kk + 5]; + FPTYPE var = a0 + a1 * xx + a2 * xx * xx + a3 * xx * xx * xx + a4 * xx * xx * xx * xx + a5 * xx * xx * xx * xx * xx; + if (unloop) { + out[ii * last_layer_size * 4 + 0 * last_layer_size + kk] += (nnei - jj) * var * ll[0]; + out[ii * last_layer_size * 4 + 1 * last_layer_size + kk] += (nnei - jj) * var * ll[1]; + out[ii * last_layer_size * 4 + 2 * last_layer_size + kk] += (nnei - jj) * var * ll[2]; + out[ii * last_layer_size * 4 + 3 * last_layer_size + kk] += (nnei - jj) * var * ll[3]; + } + else { + out[ii * last_layer_size * 4 + 0 * last_layer_size + kk] += var * ll[0]; + out[ii * last_layer_size * 4 + 1 * last_layer_size + kk] += var * ll[1]; + out[ii * last_layer_size * 4 + 2 * last_layer_size + kk] += var * ll[2]; + out[ii * last_layer_size * 4 + 3 * last_layer_size + kk] += var * ll[3]; + } + } + if (unloop) break; + } + } + } + #if GOOGLE_CUDA + void operator()(const GPUDevice& d, const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const int nloc, const int nnei, const int last_layer_size, FPTYPE * out) { + //Currently, Do nothing at all! + TabulateFusionLauncher(table, table_info, in, ff, nloc, nnei, last_layer_size, out); + } + #endif // GOOGLE_CUDA +}; + +template +struct TabulateFusionGradFunctor { + void operator()(const CPUDevice& d, const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const FPTYPE * dy, const int nloc, const int nnei, const int last_layer_size, FPTYPE * dy_dx, FPTYPE * dy_df) { + // std::cout << "I'm in tabulate gradient @CPU!" << std::endl; + memset(dy_dx, 0.0, sizeof(FPTYPE) * nloc * nnei); + memset(dy_df, 0.0, sizeof(FPTYPE) * nloc * nnei * 4); + FPTYPE const lower = table_info[0]; + FPTYPE const upper = table_info[1]; + FPTYPE const _max = table_info[2]; + FPTYPE const stride0 = table_info[3]; + FPTYPE const stride1 = table_info[4]; + // for every atom, execute a small gemm~ + // FPTYPE * res = new FPTYPE[4 * last_layer_size]; + #pragma omp parallel for + for (int ii = 0; ii < nloc; ii++) { + FPTYPE ll[4]; + FPTYPE rr[4]; + FPTYPE ago = in[ii * nnei + nnei - 1]; + bool unloop = false; + for (int jj = 0; jj < nnei; jj++) { + // construct the dy/dx + ll[0] = ff[ii * nnei * 4 + jj * 4 + 0]; + ll[1] = ff[ii * nnei * 4 + jj * 4 + 1]; + ll[2] = ff[ii * nnei * 4 + jj * 4 + 2]; + ll[3] = ff[ii * nnei * 4 + jj * 4 + 3]; + FPTYPE xx = in[ii * nnei + jj]; + if (ago == xx) { + unloop = true; + } + int table_idx = 0; + locate_xx(lower, upper, _max, stride0, stride1, xx, table_idx); + FPTYPE grad = 0.0; + for (int kk = 0; kk < last_layer_size; kk++) { + rr[0] = dy[ii * last_layer_size * 4 + 0 * last_layer_size + kk]; + rr[1] = dy[ii * last_layer_size * 4 + 1 * last_layer_size + kk]; + rr[2] = dy[ii * last_layer_size * 4 + 2 * last_layer_size + kk]; + rr[3] = dy[ii * last_layer_size * 4 + 3 * last_layer_size + kk]; + // 1.094 timesteps/s + FPTYPE a0 = table[table_idx * last_layer_size * 6 + 6 * kk + 0]; + FPTYPE a1 = table[table_idx * last_layer_size * 6 + 6 * kk + 1]; + FPTYPE a2 = table[table_idx * last_layer_size * 6 + 6 * kk + 2]; + FPTYPE a3 = table[table_idx * last_layer_size * 6 + 6 * kk + 3]; + FPTYPE a4 = table[table_idx * last_layer_size * 6 + 6 * kk + 4]; + FPTYPE a5 = table[table_idx * last_layer_size * 6 + 6 * kk + 5]; + FPTYPE res = a0 + a1 * xx + a2 * xx * xx + a3 * xx * xx * xx + a4 * xx * xx * xx * xx + a5 * xx * xx * xx * xx * xx; + + if (unloop) { + grad += (a1 + 2 * a2 * xx + 3 * a3 * xx * xx + 4 * a4 * xx * xx * xx + 5 * a5 * xx * xx * xx * xx) * dot(ll, rr) * (nnei - jj); + dy_df[ii * nnei * 4 + jj * 4 + 0] += res * rr[0] * (nnei - jj); + dy_df[ii * nnei * 4 + jj * 4 + 1] += res * rr[1] * (nnei - jj); + dy_df[ii * nnei * 4 + jj * 4 + 2] += res * rr[2] * (nnei - jj); + dy_df[ii * nnei * 4 + jj * 4 + 3] += res * rr[3] * (nnei - jj); + } + else { + grad += (a1 + 2 * a2 * xx + 3 * a3 * xx * xx + 4 * a4 * xx * xx * xx + 5 * a5 * xx * xx * xx * xx) * dot(ll, rr); + dy_df[ii * nnei * 4 + jj * 4 + 0] += res * rr[0]; + dy_df[ii * nnei * 4 + jj * 4 + 1] += res * rr[1]; + dy_df[ii * nnei * 4 + jj * 4 + 2] += res * rr[2]; + dy_df[ii * nnei * 4 + jj * 4 + 3] += res * rr[3]; + } + } + dy_dx[ii * nnei + jj] = grad; + if (unloop) break; + } + } + } + #if GOOGLE_CUDA + void operator()(const GPUDevice& d, const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const FPTYPE * dy, const int nloc, const int nnei, const int last_layer_size, FPTYPE * dy_dx, FPTYPE * dy_df) { + //Currently, Do nothing at all! + TabulateFusionGradLauncher(table, table_info, in, ff, dy, nloc, nnei, last_layer_size, dy_dx, dy_df); + } + #endif // GOOGLE_CUDA +}; + +template +struct TabulateCheckerFunctor { + void operator()(const CPUDevice& d, const FPTYPE * table_info, const FPTYPE * in, int * out, const int nloc, const int nnei) { + FPTYPE const lower = table_info[0]; + FPTYPE const upper = table_info[1]; + FPTYPE const _max = table_info[2]; + FPTYPE const stride0 = table_info[3]; + FPTYPE const stride1 = table_info[4]; + // for every atom, execute a small gemm~ + // FPTYPE * res = new FPTYPE[4 * last_layer_size]; + int Csub = 0; // summation of second table approximate; + int Dsub = 0; // summation of the endpoint approximate; + for (int ii = 0; ii < nloc; ii++) { + for (int jj = 0; jj < nnei; jj++) { + FPTYPE xx = in[ii * nnei + jj]; + if (xx < lower || xx > _max) { + Csub += 1; + } + else if (xx >= upper && xx <= _max) { + Dsub += 1; + } + } + } + if(Csub > 0) { + std::cout << "# DEEPMD: warning! some values [" << Csub << "/" << nloc * nnei << "] overflow the range of the table, using the endpoint approximate processing.." << std::endl; + } + if(Dsub > 0) { + std::cout << "# DEEPMD: warning! some values [" << Dsub << "/" << nloc * nnei << "] overflow the range of the table, using second table approximate processing.." << std::endl; + } + } + #if GOOGLE_CUDA + void operator()(const GPUDevice& d, const FPTYPE * table_info, const FPTYPE * in, int * out, const int nloc, const int nnei) { + //Currently, Do nothing at all! + TabulateCheckerLauncher(table_info, in, out, nloc, nnei); + } + #endif // GOOGLE_CUDA +}; + +template +class TabulateFusionOp : public OpKernel { + public: + explicit TabulateFusionOp(OpKernelConstruction* context) : OpKernel(context) { + OP_REQUIRES_OK(context, context->GetAttr("last_layer_size", &last_layer_size)); + counter = -1; + } + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& table = context->input(context_input_index++); + const Tensor& table_info = context->input(context_input_index++); + const Tensor& input = context->input(context_input_index++); + const Tensor& ff = context->input(context_input_index++); + + // set size of the sample + OP_REQUIRES (context, (table.shape().dims() == 2), errors::InvalidArgument ("Dim of table should be 2")); + OP_REQUIRES (context, (input.shape().dims() == 2), errors::InvalidArgument ("Dim of input should be 2")); + OP_REQUIRES (context, (ff.shape().dims() == 3), errors::InvalidArgument ("Dim of input should be 3")); + + TensorShape output_shape; + output_shape.AddDim (ff.shape().dim_size(0)); + output_shape.AddDim (4); + output_shape.AddDim (last_layer_size); + + int context_output_index = 0; + Tensor* output = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + output_shape, + &output)); + + counter++; + if ((int)table_info.flat().data()[5] != -1 && counter % (int)table_info.flat().data()[5] == 0) { + Tensor int_temp; + TensorShape int_shape; + int_shape.AddDim(2 * ff.shape().dim_size(0)); + OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); + TabulateCheckerFunctor()( + context->eigen_device(), + table_info.flat().data(), + input.flat().data(), + int_temp.flat().data(), + ff.shape().dim_size(0), + ff.shape().dim_size(1) + ); + } + + TabulateFusionFunctor()( + context->eigen_device(), // define actually graph execution device + table.flat().data(), + table_info.flat().data(), + input.flat().data(), + ff.flat().data(), + ff.shape().dim_size(0), + ff.shape().dim_size(1), + last_layer_size, + output->flat().data() + ); + } +private: + int counter; + int last_layer_size; +}; + +template +class TabulateFusionGradOp : public OpKernel { + public: + explicit TabulateFusionGradOp(OpKernelConstruction* context) : OpKernel(context) {} + + void Compute(OpKernelContext* context) override { + // std::cout << "I'm here" << std::endl; + // Grab the input tensor + int context_input_index = 0; + const Tensor& table = context->input(context_input_index++); + const Tensor& table_info = context->input(context_input_index++); + const Tensor& input = context->input(context_input_index++); + const Tensor& ff = context->input(context_input_index++); + const Tensor& dy = context->input(context_input_index++); + const Tensor& output = context->input(context_input_index++); + + // set size of the sample + OP_REQUIRES (context, (dy.shape().dims() == 3), errors::InvalidArgument ("Dim of table should be 1")); + + int context_output_index = 0; + Tensor* dy_dx = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + input.shape(), + &dy_dx)); + Tensor* dy_df = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + ff.shape(), + &dy_df)); + + TabulateFusionGradFunctor()( + context->eigen_device(), // define actually graph execution device + table.flat().data(), + table_info.flat().data(), + input.flat().data(), + ff.flat().data(), + dy.flat().data(), + ff.shape().dim_size(0), + ff.shape().dim_size(1), + output.shape().dim_size(2), + dy_dx->flat().data(), + dy_df->flat().data() + ); + } +private: +}; + +#define REGISTER_CPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("TabulateFusion").Device(DEVICE_CPU).TypeConstraint("T").HostMemory("table_info"), \ + TabulateFusionOp); \ +REGISTER_KERNEL_BUILDER( \ + Name("TabulateFusionGrad").Device(DEVICE_CPU).TypeConstraint("T").HostMemory("table_info"), \ + TabulateFusionGradOp); +REGISTER_CPU(float); +REGISTER_CPU(double); + +#if GOOGLE_CUDA +#define REGISTER_GPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("TabulateFusion").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("table_info"), \ + TabulateFusionOp); \ +REGISTER_KERNEL_BUILDER( \ + Name("TabulateFusionGrad").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("table_info"), \ + TabulateFusionGradOp); +REGISTER_GPU(float); +REGISTER_GPU(double); +#endif // GOOGLE_CUDA diff --git a/source/op/tabulate_multi_device.cc b/source/op/tabulate_multi_device.cc new file mode 100644 index 0000000000..1e5e8da2a7 --- /dev/null +++ b/source/op/tabulate_multi_device.cc @@ -0,0 +1,194 @@ +#include "common.h" +#include "CustomeOperation.h" + +REGISTER_OP("TabulateFusion") + .Attr("T: {float, double}") + .Input("table: T") + .Input("table_info: T") + .Input("input: T") + .Input("ff: T") + .Attr("last_layer_size: int") + .Output("output: T"); + +REGISTER_OP("TabulateFusionGrad") + .Attr("T: {float, double}") + .Input("table: T") + .Input("table_info: T") + .Input("input: T") + .Input("ff: T") + .Input("dy: T") + .Input("output: T") + .Output("dy_dx: T") + .Output("dy_df: T"); + +template +struct TabulateFusionFunctor { + void operator()(const CPUDevice& d, const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const int nloc, const int nnei, const int last_layer_size, FPTYPE * out) { + TabulateFusionCPULauncher(table, table_info, in, ff, nloc, nnei, last_layer_size, out); + } + #if GOOGLE_CUDA + void operator()(const GPUDevice& d, const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const int nloc, const int nnei, const int last_layer_size, FPTYPE * out) { + //Currently, Do nothing at all! + TabulateFusionGPULauncher(table, table_info, in, ff, nloc, nnei, last_layer_size, out); + } + #endif // GOOGLE_CUDA +}; + +template +struct TabulateFusionGradFunctor { + void operator()(const CPUDevice& d, const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const FPTYPE * dy, const int nloc, const int nnei, const int last_layer_size, FPTYPE * dy_dx, FPTYPE * dy_df) { + TabulateFusionGradCPULauncher(table, table_info, in, ff, dy, nloc, nnei, last_layer_size, dy_dx, dy_df); + } + #if GOOGLE_CUDA + void operator()(const GPUDevice& d, const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const FPTYPE * dy, const int nloc, const int nnei, const int last_layer_size, FPTYPE * dy_dx, FPTYPE * dy_df) { + //Currently, Do nothing at all! + TabulateFusionGradGPULauncher(table, table_info, in, ff, dy, nloc, nnei, last_layer_size, dy_dx, dy_df); + } + #endif // GOOGLE_CUDA +}; + +template +struct TabulateCheckerFunctor { + void operator()(const CPUDevice& d, const FPTYPE * table_info, const FPTYPE * in, int * out, const int nloc, const int nnei) { + TabulateCheckerCPULauncher(table_info, in, out, nloc, nnei); + } + #if GOOGLE_CUDA + void operator()(const GPUDevice& d, const FPTYPE * table_info, const FPTYPE * in, int * out, const int nloc, const int nnei) { + //Currently, Do nothing at all! + TabulateCheckerGPULauncher(table_info, in, out, nloc, nnei); + } + #endif // GOOGLE_CUDA +}; + +template +class TabulateFusionOp : public OpKernel { + public: + explicit TabulateFusionOp(OpKernelConstruction* context) : OpKernel(context) { + OP_REQUIRES_OK(context, context->GetAttr("last_layer_size", &last_layer_size)); + counter = -1; + } + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& table = context->input(context_input_index++); + const Tensor& table_info = context->input(context_input_index++); + const Tensor& input = context->input(context_input_index++); + const Tensor& ff = context->input(context_input_index++); + + // set size of the sample + OP_REQUIRES (context, (table.shape().dims() == 2), errors::InvalidArgument ("Dim of table should be 2")); + OP_REQUIRES (context, (input.shape().dims() == 2), errors::InvalidArgument ("Dim of input should be 2")); + OP_REQUIRES (context, (ff.shape().dims() == 3), errors::InvalidArgument ("Dim of input should be 3")); + + TensorShape output_shape; + output_shape.AddDim (ff.shape().dim_size(0)); + output_shape.AddDim (4); + output_shape.AddDim (last_layer_size); + + int context_output_index = 0; + Tensor* output = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + output_shape, + &output)); + + counter++; + if ((int)table_info.flat().data()[5] != -1 && counter % (int)table_info.flat().data()[5] == 0) { + Tensor int_temp; + TensorShape int_shape; + int_shape.AddDim(2 * ff.shape().dim_size(0)); + OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); + TabulateCheckerFunctor()( + context->eigen_device(), + table_info.flat().data(), + input.flat().data(), + int_temp.flat().data(), + ff.shape().dim_size(0), + ff.shape().dim_size(1) + ); + } + + TabulateFusionFunctor()( + context->eigen_device(), // define actually graph execution device + table.flat().data(), + table_info.flat().data(), + input.flat().data(), + ff.flat().data(), + ff.shape().dim_size(0), + ff.shape().dim_size(1), + last_layer_size, + output->flat().data() + ); + } +private: + int counter; + int last_layer_size; +}; + +template +class TabulateFusionGradOp : public OpKernel { + public: + explicit TabulateFusionGradOp(OpKernelConstruction* context) : OpKernel(context) {} + + void Compute(OpKernelContext* context) override { + // std::cout << "I'm here" << std::endl; + // Grab the input tensor + int context_input_index = 0; + const Tensor& table = context->input(context_input_index++); + const Tensor& table_info = context->input(context_input_index++); + const Tensor& input = context->input(context_input_index++); + const Tensor& ff = context->input(context_input_index++); + const Tensor& dy = context->input(context_input_index++); + const Tensor& output = context->input(context_input_index++); + + // set size of the sample + OP_REQUIRES (context, (dy.shape().dims() == 3), errors::InvalidArgument ("Dim of table should be 1")); + + int context_output_index = 0; + Tensor* dy_dx = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + input.shape(), + &dy_dx)); + Tensor* dy_df = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + ff.shape(), + &dy_df)); + + TabulateFusionGradFunctor()( + context->eigen_device(), // define actually graph execution device + table.flat().data(), + table_info.flat().data(), + input.flat().data(), + ff.flat().data(), + dy.flat().data(), + ff.shape().dim_size(0), + ff.shape().dim_size(1), + output.shape().dim_size(2), + dy_dx->flat().data(), + dy_df->flat().data() + ); + } +private: +}; + +#define REGISTER_CPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("TabulateFusion").Device(DEVICE_CPU).TypeConstraint("T").HostMemory("table_info"), \ + TabulateFusionOp); \ +REGISTER_KERNEL_BUILDER( \ + Name("TabulateFusionGrad").Device(DEVICE_CPU).TypeConstraint("T").HostMemory("table_info"), \ + TabulateFusionGradOp); +REGISTER_CPU(float); +REGISTER_CPU(double); + +#if GOOGLE_CUDA +#define REGISTER_GPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("TabulateFusion").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("table_info"), \ + TabulateFusionOp); \ +REGISTER_KERNEL_BUILDER( \ + Name("TabulateFusionGrad").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("table_info"), \ + TabulateFusionGradOp); +REGISTER_GPU(float); +REGISTER_GPU(double); +#endif // GOOGLE_CUDA diff --git a/source/op/unaggregated_grad.cc b/source/op/unaggregated_grad.cc new file mode 100644 index 0000000000..bc489c61ff --- /dev/null +++ b/source/op/unaggregated_grad.cc @@ -0,0 +1,320 @@ +#include "tensorflow/core/framework/op.h" +#include "tensorflow/core/framework/op_kernel.h" +#include "tensorflow/core/framework/shape_inference.h" +#include + +#include "ComputeDescriptor.h" +#include "NeighborList.h" + +using namespace tensorflow; +// using namespace std; + +using CPUDevice = Eigen::ThreadPoolDevice; +using GPUDevice = Eigen::GpuDevice; + +REGISTER_OP("UnaggregatedDyDxS") + .Attr("T: {float, double}") + .Input("y: T") + .Input("w: T") + .Output("dy_dx: T"); + +REGISTER_OP("UnaggregatedDyDx") + .Attr("T: {float, double}") + .Input("z: T") + .Input("w: T") + .Input("dy_dx: T") + .Output("dz_dx: T"); + +REGISTER_OP("UnaggregatedDy2DxS") + .Attr("T: {float, double}") + .Input("y: T") + .Input("dy: T") + .Input("w: T") + .Output("dy2_dx: T"); + +REGISTER_OP("UnaggregatedDy2Dx") + .Attr("T: {float, double}") + .Input("z: T") + .Input("w: T") + .Input("dz_dx: T") + .Input("dy_dx: T") + .Input("dy2_dx: T") + .Output("dz2_dx: T"); + +template +struct UnaggregatedDyDxSFunctor { + void operator()(const CPUDevice& d, const FPTYPE * y, const FPTYPE * w, const int length, const int width, FPTYPE * dy_dx) { + #pragma omp parallel for + for (int ii = 0; ii < length; ii++) { + for (int jj = 0; jj < width; jj++) { + dy_dx[ii * width + jj] = (1 - y[ii * width + jj] * y[ii * width + jj]) * w[jj]; + } + } + } + + #if GOOGLE_CUDA + void operator()(const GPUDevice& d, const FPTYPE * y, const FPTYPE * w, const int length, const int width, FPTYPE * dy_dx) { + //Currently, Do nothing at all! + return; + } + #endif // GOOGLE_CUDA +}; + +// calculate the gradient for all variables! +template +struct UnaggregatedDyDxFunctor { + void operator()(const CPUDevice& d, const FPTYPE * z, const FPTYPE * w, const FPTYPE * dy_dx, const int length, const int width, const int size, FPTYPE * dz_dx) { + #pragma omp parallel for + for (int kk = 0; kk < length; kk++) { + for (int ii = 0; ii < width; ii++) { + //FPTYPE dz_drou = 1 - (z[kk * width + ii] - y[kk * size + ii % size]) * (z[kk * width + ii] - y[kk * size + ii % size]); + FPTYPE dz_drou = 1 - z[kk * width + ii] * z[kk * width + ii]; + FPTYPE accumulator = 0.0; + for (int jj = 0; jj < size; jj++) { + accumulator += w[jj * width + ii] * dy_dx[kk * size + jj]; + } + dz_drou *= accumulator; + dz_drou += dy_dx[kk * size + ii % size]; + dz_dx[kk * width + ii] = dz_drou; + } + } + } + + #if GOOGLE_CUDA + void operator()(const GPUDevice& d, const FPTYPE * z, const FPTYPE * w, const FPTYPE * dy_dx, const int length, const int width, const int size, FPTYPE * dz_dx) { + //Currently, Do nothing at all! + return; + } + #endif // GOOGLE_CUDA +}; + +template +struct UnaggregatedDy2DxSFunctor { + void operator()(const CPUDevice& d, const FPTYPE * y, const FPTYPE * dy, const FPTYPE * w, const int length, const int width, FPTYPE * dy2_dx) { + #pragma omp parallel for + for (int ii = 0; ii < length; ii++) { + for (int jj = 0; jj < width; jj++) { + dy2_dx[ii * width + jj] = -2 * w[jj] * y[ii * width + jj] * dy[ii * width + jj]; + } + } + } + + #if GOOGLE_CUDA + void operator()(const GPUDevice& d, const FPTYPE * y, const FPTYPE * w, const int length, const int width, FPTYPE * dy_dx) { + //Currently, Do nothing at all! + return; + } + #endif // GOOGLE_CUDA +}; + +// calculate the gradient for all variables! +template +struct UnaggregatedDy2DxFunctor { + void operator()(const CPUDevice& d, const FPTYPE * z, const FPTYPE * w, const FPTYPE * dz_dx, const FPTYPE * dy_dx, const FPTYPE * dy2_dx, const int length, const int width, const int size, FPTYPE * dz2_dx) { + #pragma omp parallel for + for (int kk = 0; kk < length; kk++) { + for (int ii = 0; ii < width; ii++) { + //FPTYPE dz_drou = 1 - (z[kk * width + ii] - y[kk * size + ii % size]) * (z[kk * width + ii] - y[kk * size + ii % size]); + FPTYPE dz_drou = 1 - z[kk * width + ii] * z[kk * width + ii]; + FPTYPE accumulator = 0.0; + for (int jj = 0; jj < size; jj++) { + accumulator += w[jj * width + ii] * dy2_dx[kk * size + jj]; + } + dz_drou *= accumulator; + accumulator = 0.0; + for (int jj = 0; jj < size; jj++) { + accumulator += w[jj * width + ii] * dy_dx[kk * size + jj]; + } + dz_drou -= 2 * z[kk * width + ii] * (dz_dx[kk * width + ii] - dy_dx[kk * size + ii % size]) * accumulator; + dz_drou += dy2_dx[kk * size + ii % size]; + dz2_dx[kk * width + ii] = dz_drou; + } + } + } + + #if GOOGLE_CUDA + void operator()(const GPUDevice& d, const FPTYPE * z, const FPTYPE * w, const FPTYPE * dz_dx, const FPTYPE * dy_dx, const FPTYPE * dy2_dx, const int length, const int width, const int size, FPTYPE * dz2_dx) { + //Currently, Do nothing at all! + return; + } + #endif // GOOGLE_CUDA +}; + +template +class UnaggregatedDyDxSOp : public OpKernel { + public: + explicit UnaggregatedDyDxSOp(OpKernelConstruction* context) : OpKernel(context) {} + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& y = context->input(context_input_index++); + const Tensor& w = context->input(context_input_index++); + + // set size of the sample + OP_REQUIRES (context, (y.shape().dims() == 2), errors::InvalidArgument ("Dim of table should be 1")); + OP_REQUIRES (context, (w.shape().dims() == 2), errors::InvalidArgument ("Dim of input should be 2")); + + int context_output_index = 0; + Tensor* dy_dx = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + y.shape(), + &dy_dx)); + + UnaggregatedDyDxSFunctor()( + context->eigen_device(), // define actually graph execution device + y.flat().data(), + w.flat().data(), + y.shape().dim_size(0), + y.shape().dim_size(1), + dy_dx->flat().data() + ); + } +private: +}; + +template +class UnaggregatedDy2DxSOp : public OpKernel { + public: + explicit UnaggregatedDy2DxSOp(OpKernelConstruction* context) : OpKernel(context) {} + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& y = context->input(context_input_index++); + const Tensor& dy = context->input(context_input_index++); + const Tensor& w = context->input(context_input_index++); + + // set size of the sample + OP_REQUIRES (context, (y.shape().dims() == 2), errors::InvalidArgument ("Dim of input should be 2")); + OP_REQUIRES (context, (dy.shape().dims() == 2), errors::InvalidArgument ("Dim of input should be 2")); + OP_REQUIRES (context, (w.shape().dims() == 2), errors::InvalidArgument ("Dim of input should be 2")); + + int context_output_index = 0; + Tensor* dy2_dx = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + y.shape(), + &dy2_dx)); + + UnaggregatedDy2DxSFunctor()( + context->eigen_device(), // define actually graph execution device + y.flat().data(), + dy.flat().data(), + w.flat().data(), + y.shape().dim_size(0), + y.shape().dim_size(1), + dy2_dx->flat().data() + ); + } +private: +}; + +template +class UnaggregatedDyDxOp : public OpKernel { + public: + explicit UnaggregatedDyDxOp(OpKernelConstruction* context) : OpKernel(context) {} + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& z = context->input(context_input_index++); + const Tensor& w = context->input(context_input_index++); + const Tensor& dy_dx = context->input(context_input_index++); + + // set size of the sample + OP_REQUIRES (context, (z.shape().dims() == 2), errors::InvalidArgument ("Dim of table should be 1")); + OP_REQUIRES (context, (w.shape().dims() == 2), errors::InvalidArgument ("Dim of input should be 2")); + OP_REQUIRES (context, (dy_dx.shape().dims() == 2), errors::InvalidArgument ("Dim of input should be 2")); + + int context_output_index = 0; + Tensor* dz_dx = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + z.shape(), + &dz_dx)); + + UnaggregatedDyDxFunctor()( + context->eigen_device(), // define actually graph execution device + z.flat().data(), + w.flat().data(), + dy_dx.flat().data(), + z.shape().dim_size(0), + z.shape().dim_size(1), + w.shape().dim_size(0), + dz_dx->flat().data() + ); + } +private: +}; + +template +class UnaggregatedDy2DxOp : public OpKernel { + public: + explicit UnaggregatedDy2DxOp(OpKernelConstruction* context) : OpKernel(context) {} + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& z = context->input(context_input_index++); + const Tensor& w = context->input(context_input_index++); + const Tensor& dz_dx = context->input(context_input_index++); + const Tensor& dy_dx = context->input(context_input_index++); + const Tensor& dy2_dx = context->input(context_input_index++); + + // set size of the sample + OP_REQUIRES (context, (z.shape().dims() == 2), errors::InvalidArgument ("Dim of input should be 2")); + OP_REQUIRES (context, (w.shape().dims() == 2), errors::InvalidArgument ("Dim of input should be 2")); + OP_REQUIRES (context, (dz_dx.shape().dims() == 2), errors::InvalidArgument ("Dim of input should be 2")); + OP_REQUIRES (context, (dy_dx.shape().dims() == 2), errors::InvalidArgument ("Dim of input should be 2")); + OP_REQUIRES (context, (dy2_dx.shape().dims() == 2), errors::InvalidArgument ("Dim of input should be 2")); + + int context_output_index = 0; + Tensor* dz2_dx = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + z.shape(), + &dz2_dx)); + + UnaggregatedDy2DxFunctor()( + context->eigen_device(), // define actually graph execution device + z.flat().data(), + w.flat().data(), + dz_dx.flat().data(), + dy_dx.flat().data(), + dy2_dx.flat().data(), + z.shape().dim_size(0), + z.shape().dim_size(1), + w.shape().dim_size(0), + dz2_dx->flat().data() + ); + } +private: +}; + +// Register the CPU kernels. +#define REGISTER_CPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("UnaggregatedDyDxS").Device(DEVICE_CPU).TypeConstraint("T"), \ + UnaggregatedDyDxSOp); \ +REGISTER_KERNEL_BUILDER( \ + Name("UnaggregatedDyDx").Device(DEVICE_CPU).TypeConstraint("T"), \ + UnaggregatedDyDxOp); \ +REGISTER_KERNEL_BUILDER( \ + Name("UnaggregatedDy2DxS").Device(DEVICE_CPU).TypeConstraint("T"), \ + UnaggregatedDy2DxSOp); \ +REGISTER_KERNEL_BUILDER( \ + Name("UnaggregatedDy2Dx").Device(DEVICE_CPU).TypeConstraint("T"), \ + UnaggregatedDy2DxOp); +REGISTER_CPU(float); +REGISTER_CPU(double); +// Not required in the current situation +// // Register the GPU kernels. +// #if GOOGLE_CUDA +// #define REGISTER_GPU(T) \ +// REGISTER_KERNEL_BUILDER( \ +// Name("UnaggregatedDyDxS").Device(DEVICE_GPU).TypeConstraint("T"), \ +// UnaggregatedDyDxSOp); \ +// REGISTER_KERNEL_BUILDER( \ +// Name("UnaggregatedDyDx").Device(DEVICE_GPU).TypeConstraint("T"), \ +// UnaggregatedDyDxOp); +// REGISTER_GPU(float); +// REGISTER_GPU(double); +// #endif // GOOGLE_CUDA \ No newline at end of file diff --git a/source/train/CMakeLists.txt b/source/train/CMakeLists.txt index 818b2f4225..176f20d5e4 100644 --- a/source/train/CMakeLists.txt +++ b/source/train/CMakeLists.txt @@ -2,7 +2,7 @@ configure_file("RunOptions.py.in" "${CMAKE_CURRENT_BINARY_DIR}/RunOptions.py" @ONLY) -file(GLOB LIB_PY main.py calculator.py Model*.py Trainer.py ${CMAKE_CURRENT_BINARY_DIR}/RunOptions.py transform.py doc.py) +file(GLOB LIB_PY main.py calculator.py Model*.py Trainer.py ${CMAKE_CURRENT_BINARY_DIR}/RunOptions.py transform.py doc.py compress.py) file(GLOB CLS_PY Local.py Slurm.py) diff --git a/source/train/Model.py b/source/train/Model.py index 9c9cd7ddff..5a6ae6f153 100644 --- a/source/train/Model.py +++ b/source/train/Model.py @@ -114,6 +114,9 @@ def data_stat(self, data): m_all_stat = merge_sys_stat(all_stat) self._compute_input_stat(m_all_stat, protection = self.data_stat_protect) self._compute_output_stat(all_stat) + + if hasattr(self.descrpt, 'compress') and self.descrpt.compress: + self.descrpt.data_info(data) # self.bias_atom_e = data.compute_energy_shift(self.rcond) def _compute_input_stat (self, all_stat, protection = 1e-2) : diff --git a/source/train/Trainer.py b/source/train/Trainer.py index 765a25d206..c16a0e7157 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -32,6 +32,7 @@ import deepmd._prod_virial_se_r_grad import deepmd._soft_min_force_grad import deepmd._soft_min_virial_grad +import deepmd._tabulate_grad import deepmd._gelu from deepmd.common import j_must_have, ClassArg diff --git a/source/train/compress.py b/source/train/compress.py new file mode 100644 index 0000000000..2174171ef6 --- /dev/null +++ b/source/train/compress.py @@ -0,0 +1,52 @@ +import re +import json +import copy +import argparse +import numpy as np +from deepmd.env import tf +from .train import train +from .freeze import freeze +from .transform import transform +from deepmd.common import j_loader +from deepmd.utils.argcheck import normalize + +def compress(args): + jdata = j_loader(args.INPUT) + if not 'model' in jdata.keys(): + jdata = convert_input_v0_v1(jdata, + warning = True, + dump = 'input_v1_compat.json') + + jdata = normalize(jdata) + jdata['model']['descriptor']['compress'] = True + jdata['model']['descriptor']['model_file'] = args.input + jdata['model']['descriptor']['table_info'] = args.table_info + + # check the descriptor type of input file + assert jdata['model']['descriptor']['type'] == 'se_a', 'Model compression error: descriptor type must be se_a!' + + # stage 1: training or refining the model with tabulation + print('\n\n# DEEPMD: stage 1: train or refine the model with tabulation') + args_train = copy.deepcopy(args) + args_train.INPUT = 'compress.json' + args_train.output = 'compress.json' + args_train.init_model = None + args_train.restart = None + jdata['training']['stop_batch'] = jdata['training']['save_freq'] # be careful here, if we want refine the model + with open(args_train.INPUT, 'w') as fp: + json.dump(jdata, fp, indent=4) + train(args_train) + + # stage 2: freeze the model + print('\n\n# DEEPMD: stage 2: freeze the model') + args_frz = copy.deepcopy(args) + args_frz.nodes = None + freeze(args_frz) + + # stage 3: transform the model + print('\n\n# DEEPMD: stage 3: transform the model') + args_transform = copy.deepcopy(args) + args_transform.old_model = args.input + args_transform.raw_model = args.output + args_transform.output = args.output + transform(args_transform) diff --git a/source/train/main.py b/source/train/main.py index b7dd0d0215..248c33f961 100644 --- a/source/train/main.py +++ b/source/train/main.py @@ -5,6 +5,7 @@ from .config import config from .test import test from .transform import transform +from .compress import compress from .doc import doc_train_input def main () : @@ -63,6 +64,17 @@ def main () : parser_tst.add_argument("-a", "--atomic-energy", action = 'store_true', help="Test the accuracy of atomic energy") + parser_compress = subparsers.add_parser('compress', help='compress a model') + parser_compress.add_argument('INPUT', + help='the input parameter file in json or yaml format') + parser_compress.add_argument('-i', "--input", default = "frozen_model.pb", type=str, + help = "the original model") + parser_compress.add_argument("-o","--output", default = "frozen_model_tab.pb", type=str, + help='the compressed model') + parser_compress.add_argument('-t', '--table-info', nargs='+', default = [5, 0.01, 0.1, 1], type=float) + parser_compress.add_argument("-d", "--folder", type=str, default = ".", + help="path to checkpoint folder") + parser_train = subparsers.add_parser('doc-train-input', help='print the documentation (in rst format) of input training parameters.') @@ -81,6 +93,8 @@ def main () : test(args) elif args.command == 'transform' : transform(args) + elif args.command == 'compress' : + compress(args) elif args.command == 'doc-train-input' : doc_train_input(args) else : diff --git a/source/train/transform.py b/source/train/transform.py index 1d587ae531..19efd42976 100644 --- a/source/train/transform.py +++ b/source/train/transform.py @@ -44,8 +44,8 @@ def transform_graph(raw_graph,old_graph): raw_graph_node = load_transform_node(raw_graph_def) old_graph_node = load_transform_node(old_graph_def) - if len(raw_graph_node) != len(old_graph_node): - raise RuntimeError("raw graph and old graph has different network structure") + # if len(raw_graph_node) != len(old_graph_node): + # raise RuntimeError("raw graph and old graph has different network structure") for node in raw_graph_def.node: if node.name in raw_graph_node.keys(): @@ -108,7 +108,7 @@ def check_dim(raw_graph_node, old_graph_node, node_name): raw_graph_dim = raw_graph_node[node_name].tensor_shape old_graph_dim = old_graph_node[node_name].tensor_shape if raw_graph_dim != old_graph_dim: - raise RuntimeError("old graph and raw graph has different"+node_name+" dim") + raise RuntimeError("old graph " + str(old_graph_dim) + " and raw graph " + str(raw_graph_dim) + " has different " + str(node_name) + " dim") def load_transform_node(graph): From c9525a20252924b8bf3b045f354f92fd1649ea1e Mon Sep 17 00:00:00 2001 From: Denghui Lu Date: Wed, 3 Feb 2021 11:33:55 +0800 Subject: [PATCH 063/562] Update deepmd/utils/tabulate.py Co-authored-by: Jinzhe Zeng --- deepmd/utils/tabulate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deepmd/utils/tabulate.py b/deepmd/utils/tabulate.py index 04b3bde7e9..2a453ce584 100644 --- a/deepmd/utils/tabulate.py +++ b/deepmd/utils/tabulate.py @@ -1,7 +1,7 @@ import re import math import numpy as np -import tensorflow.compat.v1 as tf +from deepmd.env import tf from tensorflow.python.platform import gfile from tensorflow.python.framework import tensor_util from tqdm import tqdm @@ -182,4 +182,4 @@ def layer_1(self, x, w, b): def save_data(self): for ii in range(self.ntypes * self.ntypes): net = "filter_" + str(int(ii / self.ntypes)) + "_net_" + str(int(ii % self.ntypes)) - np.savetxt('data_' + str(int(ii)), self.data[net]) \ No newline at end of file + np.savetxt('data_' + str(int(ii)), self.data[net]) From 4afed270882f5b811eeaacc93c316a851c522c41 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 3 Feb 2021 01:04:41 -0500 Subject: [PATCH 064/562] migrate from travis-ci to github actions --- .github/workflows/build_wheel.yml | 67 ++++++++++++++++++++++ .github/workflows/test_python.yml | 63 ++++++++++++++++++++ .travis.yml | 95 ------------------------------- 3 files changed, 130 insertions(+), 95 deletions(-) create mode 100644 .github/workflows/build_wheel.yml create mode 100644 .github/workflows/test_python.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml new file mode 100644 index 0000000000..2d522e5cf3 --- /dev/null +++ b/.github/workflows/build_wheel.yml @@ -0,0 +1,67 @@ +name: Build and upload to PyPI + +on: + push: + pull_request: + +jobs: + build_wheels: + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-18.04] #, windows-latest, macos-latest] + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + name: Install Python + with: + python-version: '3.8' + + - name: Install cibuildwheel + run: | + python -m pip install cibuildwheel + + - name: Build wheels + env: + CIBW_BUILD: "cp36-* cp37-* cp38-*" + CIBW_BEFORE_BUILD: pip install tensorflow && sed -i 's/libresolv.so.2"/libresolv.so.2", "libtensorflow_framework.so.2"/g' /opt/_internal/tools/lib/python*/site-packages/auditwheel/policy/policy.json + CIBW_SKIP: "*-win32 *-manylinux_i686" + run: | + python -m cibuildwheel --output-dir wheelhouse + - uses: actions/upload-artifact@v2 + with: + path: ./wheelhouse/*.whl + + build_sdist: + name: Build source distribution + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + name: Install Python + with: + python-version: '3.8' + - run: pip install -U scikit-build tensorflow setuptools_scm + - name: Build sdist + run: python setup.py sdist + + - uses: actions/upload-artifact@v2 + with: + path: dist/*.tar.gz + + upload_pypi: + needs: [build_wheels, build_sdist] + runs-on: ubuntu-latest + if: startsWith(github.event.ref, 'refs/tags/v') + steps: + - uses: actions/download-artifact@v2 + with: + name: artifact + path: dist + + - uses: pypa/gh-action-pypi-publish@master + with: + user: __token__ + password: ${{ secrets.pypi_password }} diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml new file mode 100644 index 0000000000..c52e3921d3 --- /dev/null +++ b/.github/workflows/test_python.yml @@ -0,0 +1,63 @@ +on: + push: + pull_request: +name: Test Python +jobs: + testpython: + name: Test Python + runs-on: ubuntu-latest + strategy: + matrix: + include: + - python: 3.6 + gcc: 4.8 + tf: 1.8 + - python: 3.6 + gcc: 4.8 + tf: 1.12 + - python: 3.6 + gcc: 4.8 + tf: 1.14 + - python: 3.6 + gcc: 5 + tf: 1.14 + - python: 3.6 + gcc: 8 + tf: 1.14 + - python: 3.7 + gcc: 5 + tf: 1.14 + - python: 3.7 + gcc: 6 + tf: 1.14 + - python: 3.7 + gcc: 7 + tf: 1.14 + - python: 3.7 + gcc: 8 + tf: 1.14 + - python: 3.7 + gcc: 5 + tf: 2.3 + - python: 3.7 + gcc: 8 + tf: 2.3 + + steps: + - uses: actions/checkout@master + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python }} + - name: pip cache + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: + ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }} + restore-keys: | + ${{ runner.os }}-pip- + - run: | + sudo apt update + sudo apt install gcc-${{ matrix.gcc }} g++-${{ matrix.gcc }} + - run: pip install .[cpu,test] + - run: cd source/tests && python -m unittest diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b434af6819..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,95 +0,0 @@ -language: python -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - gcc-4.8 - - g++-4.8 - - gcc-5 - - g++-5 - - gcc-6 - - g++-6 - - gcc-7 - - g++-7 - - gcc-8 - - g++-8 -jobs: - include: - - stage: unit tests - python: 3.6 - env: - - CC=gcc-4.8 - - CXX=g++-4.8 - - TENSORFLOW_VERSION=1.8 - - python: 3.6 - env: - - CC=gcc-4.8 - - CXX=g++-4.8 - - TENSORFLOW_VERSION=1.12 - - python: 3.6 - env: - - CC=gcc-4.8 - - CXX=g++-4.8 - - TENSORFLOW_VERSION=1.14 - - python: 3.6 - env: - - CC=gcc-5 - - CXX=g++-5 - - TENSORFLOW_VERSION=1.14 - - python: 3.6 - env: - - CC=gcc-8 - - CXX=g++-8 - - TENSORFLOW_VERSION=1.14 - - python: 3.7 - env: - - CC=gcc-5 - - CXX=g++-5 - - TENSORFLOW_VERSION=1.14 - - python: 3.7 - env: - - CC=gcc-6 - - CXX=g++-6 - - TENSORFLOW_VERSION=1.14 - - python: 3.7 - env: - - CC=gcc-7 - - CXX=g++-7 - - TENSORFLOW_VERSION=1.14 - - python: 3.7 - env: - - CC=gcc-8 - - CXX=g++-8 - - TENSORFLOW_VERSION=1.14 - - python: 3.7 - env: - - CC=gcc-5 - - CXX=g++-5 - - TENSORFLOW_VERSION=2.3 - - python: 3.7 - env: - - CC=gcc-8 - - CXX=g++-8 - - TENSORFLOW_VERSION=2.3 - - stage: build whls - services: docker - env: - - TWINE_USERNAME=__token__ - - CIBW_BUILD="cp36-* cp37-*" - - CIBW_BEFORE_BUILD="sed -i 's/libresolv.so.2\"/libresolv.so.2\", \"libtensorflow_framework.so.2\"/g' \$(find / -name policy.json)" - - CIBW_SKIP="*-win32 *-manylinux_i686" - - CC=gcc-7 - - CXX=g++-7 - - TENSORFLOW_VERSION=2.3 - install: - - python -m pip install twine cibuildwheel==1.6.3 scikit-build setuptools_scm - script: - - python -m cibuildwheel --output-dir wheelhouse - - python setup.py sdist - after_success: - - if [[ $TRAVIS_TAG ]]; then python -m twine upload wheelhouse/*; python -m twine upload dist/*.tar.gz; fi -install: - - pip install .[cpu,test] -script: - - cd source/tests && python -m unittest From 0e101566a5edef9f598c1927542cb1cdad016b38 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Wed, 3 Feb 2021 15:12:09 +0800 Subject: [PATCH 065/562] add package tqdm into setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b7b104d33c..57335193b5 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ with open(readme_file) as f: readme = f.read() -install_requires=['numpy', 'scipy', 'pyyaml', 'dargs'] +install_requires=['numpy', 'scipy', 'pyyaml', 'dargs', 'tqdm'] setup_requires=['setuptools_scm', 'scikit-build'] tf_version = os.environ.get('TENSORFLOW_VERSION', '2.3') From a2efd34c80e125cfa67d65de2fcde83d4244d06e Mon Sep 17 00:00:00 2001 From: denghuilu Date: Wed, 3 Feb 2021 16:22:06 +0800 Subject: [PATCH 066/562] add the reference of global_np_float_precision into common.py --- deepmd/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deepmd/common.py b/deepmd/common.py index e00485b99a..c46f31bb82 100644 --- a/deepmd/common.py +++ b/deepmd/common.py @@ -3,7 +3,7 @@ import math from deepmd.env import tf from deepmd.env import op_module -from deepmd.RunOptions import global_tf_float_precision +from deepmd.RunOptions import global_tf_float_precision, global_np_float_precision import json import yaml From 20ccc0ea32753c72bc84c0a22075f3e33c7b3582 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Wed, 3 Feb 2021 17:02:58 +0800 Subject: [PATCH 067/562] optimize the performance of gpu implementations of custome ops --- source/op/cuda/descrpt_se_r.cu | 116 ++++++++++++++---------------- source/op/cuda/prod_force_se_a.cu | 53 +++++++++----- source/op/cuda/prod_force_se_r.cu | 53 +++++++++----- 3 files changed, 124 insertions(+), 98 deletions(-) diff --git a/source/op/cuda/descrpt_se_r.cu b/source/op/cuda/descrpt_se_r.cu index 0715f19c5e..33932f4325 100644 --- a/source/op/cuda/descrpt_se_r.cu +++ b/source/op/cuda/descrpt_se_r.cu @@ -147,8 +147,10 @@ __global__ void format_nlist_fill_b_se_r(int * nlist, } //it's ok! -template -__global__ void compute_descriptor_se_r (FPTYPE* descript, +template< + typename FPTYPE, + int THREADS_PER_BLOCK> +__global__ void compute_descriptor_se_r(FPTYPE* descript, const int ndescrpt, FPTYPE* descript_deriv, const int descript_deriv_size, @@ -164,49 +166,58 @@ __global__ void compute_descriptor_se_r (FPTYPE* descript, const float rmax, const int sec_a_size) { - // <<>> - const unsigned int idx = blockIdx.x; - const unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y; - const int idx_deriv = idy * 3; // 4 components time 3 directions - const int idx_value = idy; // 4 components - if (idy >= sec_a_size) {return;} + // <<>> + const unsigned int bid = blockIdx.x; + const unsigned int tid = threadIdx.x; + // usually false... + if (tid >= sec_a_size) { + return; + } + // const int idx_deriv = idy * 4 * 3; // 4 components time 3 directions + // const int idx_value = idy * 4; // 4 components + int * row_nlist = nlist + bid * nlist_size; + FPTYPE * row_rij = rij + bid * rij_size; + FPTYPE * row_descript = descript + bid * ndescrpt; + FPTYPE * row_descript_deriv = descript_deriv + bid * descript_deriv_size; - // else {return;} - FPTYPE * row_descript = descript + idx * ndescrpt; - FPTYPE * row_descript_deriv = descript_deriv + idx * descript_deriv_size; - FPTYPE * row_rij = rij + idx * rij_size; - int * row_nlist = nlist + idx * nlist_size; + for (int ii = tid; ii < sec_a_size; ii += THREADS_PER_BLOCK) { + const int idx_value = ii; // 4 components + const int idx_deriv = ii * 3; // 4 components time 3 directions + if (row_nlist[ii] >= 0) { + FPTYPE rr[3] = {0}; + FPTYPE vv[3] = {0}; + FPTYPE dd = 0; + const int & j_idx = row_nlist[ii]; + for (int kk = 0; kk < 3; kk++) { + rr[kk] = coord[j_idx * 3 + kk] - coord[bid * 3 + kk]; + row_rij[ii * 3 + kk] = rr[kk]; + } + // const FPTYPE * rr = &row_rij[ii * 3]; + FPTYPE nr2 = dev_dot(rr, rr); + FPTYPE inr = 1./sqrt(nr2); + FPTYPE nr = nr2 * inr; + FPTYPE inr2 = inr * inr; + FPTYPE inr4 = inr2 * inr2; + FPTYPE inr3 = inr4 * nr; + FPTYPE sw, dsw; + spline5_switch(sw, dsw, nr, rmin, rmax); + dd = (1./nr) ;//* sw; - if (row_nlist[idy] >= 0) { - const int & j_idx = row_nlist[idy]; - for (int kk = 0; kk < 3; kk++) { - row_rij[idy * 3 + kk] = coord[j_idx * 3 + kk] - coord[idx * 3 + kk]; + vv[0] = (rr[0] * inr3 * sw - dd * dsw * rr[0] * inr); // avg[type[(idx_deriv + 0) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 0) % (ndescrpt * 3)) / 3]; + vv[1] = (rr[1] * inr3 * sw - dd * dsw * rr[1] * inr); // avg[type[(idx_deriv + 1) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 1) % (ndescrpt * 3)) / 3]; + vv[2] = (rr[2] * inr3 * sw - dd * dsw * rr[2] * inr); // avg[type[(idx_deriv + 2) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 2) % (ndescrpt * 3)) / 3]; + + // 4 value components + dd *= sw; // * descript[idx * ndescrpt + idx_value + 0]);// - avg[type[idx] * ndescrpt + idx_value + 0]) / std[type[idx] * ndescrpt + idx_value + 0]; + for (int ii = 0; ii < 3; ii++) { + row_descript_deriv[idx_deriv + ii] = vv[ii] / std[type[bid] * ndescrpt + idx_value + ii / 3]; + } + row_descript[idx_value] = (dd - avg[type[bid] * ndescrpt + idx_value]) / std[type[bid] * ndescrpt + idx_value]; + } + else { + // TODO: move it to the memset. + row_descript[idx_value] -= avg[type[bid] * ndescrpt + idx_value] / std[type[bid] * ndescrpt + idx_value]; } - const FPTYPE * rr = &row_rij[idy * 3 + 0]; - FPTYPE nr2 = dev_dot(rr, rr); - FPTYPE inr = 1./sqrt(nr2); - FPTYPE nr = nr2 * inr; - FPTYPE inr2 = inr * inr; - FPTYPE inr4 = inr2 * inr2; - FPTYPE inr3 = inr4 * nr; - FPTYPE sw, dsw; - spline5_switch(sw, dsw, nr, rmin, rmax); - row_descript[idx_value + 0] = (1./nr) ;//* sw; - - row_descript_deriv[idx_deriv + 0] = (rr[0] * inr3 * sw - row_descript[idx_value + 0] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 0) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 0) % (ndescrpt * 3)) / 3]; - row_descript_deriv[idx_deriv + 1] = (rr[1] * inr3 * sw - row_descript[idx_value + 0] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 1) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 1) % (ndescrpt * 3)) / 3]; - row_descript_deriv[idx_deriv + 2] = (rr[2] * inr3 * sw - row_descript[idx_value + 0] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 2) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 2) % (ndescrpt * 3)) / 3]; - // 4 value components - row_descript[idx_value + 0] *= sw; // * descript[idx * ndescrpt + idx_value + 0]);// - avg[type[idx] * ndescrpt + idx_value + 0]) / std[type[idx] * ndescrpt + idx_value + 0]; - } - - for (int ii = 0; ii < 1; ii++) { - row_descript[idx_value + ii] = (row_descript[idx_value + ii] - avg[type[idx] * ndescrpt + idx_value + ii]) / std[type[idx] * ndescrpt + idx_value + ii]; - } - // idy nloc, idx ndescrpt * 3 - // descript_deriv[idy * ndescrpt * 3 + idx] = (descript_deriv_dev[idy * (ndescrpt * 3) + idx]) / std[type[idy] * ndescrpt + idx / 3]; - for (int ii = 0; ii < 3; ii++) { - row_descript_deriv[idx_deriv + ii] /= std[type[idx] * ndescrpt + (idx_deriv + ii) / 3]; } } @@ -383,26 +394,7 @@ void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const ); } - const int nblock_ = (sec_a.back() + LEN -1) / LEN; - dim3 block_grid(nloc, nblock_); - dim3 thread_grid(1, LEN); - compute_descriptor_se_r<<>> ( - descript, - ndescrpt, - descript_deriv, - ndescrpt * 3, - rij, - nnei * 3, - type, - avg, - std, - nlist, - nnei, - coord, - rcut_r_smth, - rcut_r, - sec_a.back() - ); + compute_descriptor_se_r <<>> (descript, ndescrpt, descript_deriv, ndescrpt * 3, rij, nnei * 3, type, avg, std, nlist, nnei, coord, rcut_r_smth, rcut_r, sec_a.back()); } template struct DescrptSeRGPUExecuteFunctor; diff --git a/source/op/cuda/prod_force_se_a.cu b/source/op/cuda/prod_force_se_a.cu index 1667c15f90..84615ff275 100644 --- a/source/op/cuda/prod_force_se_a.cu +++ b/source/op/cuda/prod_force_se_a.cu @@ -14,23 +14,44 @@ static __inline__ __device__ double atomicAdd(double* address, double val) { } #endif -template -__global__ void deriv_wrt_center_atom_se_a(FPTYPE * force, - const FPTYPE * net_deriv, - const FPTYPE * in_deriv, - const int ndescrpt) +template < + typename FPTYPE, + int THREADS_PER_BLOCK> +__global__ void force_deriv_wrt_center_atom_se_a(FPTYPE * force, const FPTYPE * net_deriv, const FPTYPE * in_deriv, const int ndescrpt) { - const unsigned int idx = blockIdx.x; - const unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y; - const unsigned int idz = threadIdx.x; + __shared__ FPTYPE data[THREADS_PER_BLOCK * 3]; + unsigned int bid = blockIdx.x; + unsigned int tid = threadIdx.x; + for (int ii = tid; ii < THREADS_PER_BLOCK * 3; ii += THREADS_PER_BLOCK) { + data[ii] = 0.f; + } - if (idy >= ndescrpt) {return;} - - atomicAdd(force + idx * 3 + idz, -1.0 * net_deriv[idx * ndescrpt + idy] * in_deriv[idx * ndescrpt * 3 + idy * 3 + idz]); + for (int ii = tid; ii < ndescrpt; ii += THREADS_PER_BLOCK) { + for (int jj = 0; jj < 3; jj++) { + data[jj * THREADS_PER_BLOCK + tid] += net_deriv[bid * ndescrpt + ii] * in_deriv[bid * ndescrpt * 3 + ii * 3 + jj]; + } + } + __syncthreads(); + + // do reduction in shared memory + for (int ii = THREADS_PER_BLOCK >> 1; ii > 0; ii >>= 1) { + if (tid < ii) { + for (int jj = 0; jj < 3; jj++) { + data[jj * THREADS_PER_BLOCK + tid] += data[jj * THREADS_PER_BLOCK + tid + ii]; + } + } + __syncthreads(); + } + // write result for this block to global memory + if (tid == 0) { + force[bid * 3 + 0] -= data[THREADS_PER_BLOCK * 0]; + force[bid * 3 + 1] -= data[THREADS_PER_BLOCK * 1]; + force[bid * 3 + 2] -= data[THREADS_PER_BLOCK * 2]; + } } template -__global__ void deriv_wrt_neighbors_se_a(FPTYPE * force, +__global__ void force_deriv_wrt_neighbors_se_a(FPTYPE * force, const FPTYPE * net_deriv, const FPTYPE * in_deriv, const int * nlist, @@ -71,17 +92,13 @@ void ProdForceSeAGPUExecuteFunctor::operator()(FPTYPE * force, { // std::cout << "I'm here!" << std::endl; cudaErrcheck(cudaMemset(force, 0.0, sizeof(FPTYPE) * nall * 3)); - const int LEN1 = 256; - const int nblock1 = (ndescrpt + LEN1 -1) / LEN1; - dim3 grid(nloc, nblock1); - dim3 thread(3, LEN1); - deriv_wrt_center_atom_se_a<<>>(force, net_deriv, in_deriv, ndescrpt); + force_deriv_wrt_center_atom_se_a <<>>(force, net_deriv, in_deriv, ndescrpt); const int LEN = 64; int nblock = (nloc + LEN -1) / LEN; dim3 block_grid(nblock, nnei); dim3 thread_grid(LEN, 3, 4); - deriv_wrt_neighbors_se_a<<>>(force, net_deriv, in_deriv, nlist, nloc, nnei, ndescrpt, n_a_sel, n_a_shift); + force_deriv_wrt_neighbors_se_a<<>>(force, net_deriv, in_deriv, nlist, nloc, nnei, ndescrpt, n_a_sel, n_a_shift); } template struct ProdForceSeAGPUExecuteFunctor; diff --git a/source/op/cuda/prod_force_se_r.cu b/source/op/cuda/prod_force_se_r.cu index 5a4b582dd0..88e2962536 100644 --- a/source/op/cuda/prod_force_se_r.cu +++ b/source/op/cuda/prod_force_se_r.cu @@ -14,23 +14,44 @@ static __inline__ __device__ double atomicAdd(double* address, double val) { } #endif -template -__global__ void deriv_wrt_center_atom_se_r(FPTYPE * force, - const FPTYPE * net_deriv, - const FPTYPE * in_deriv, - const int ndescrpt) +template < + typename FPTYPE, + int THREADS_PER_BLOCK> +__global__ void force_deriv_wrt_center_atom_se_r(FPTYPE * force, const FPTYPE * net_deriv, const FPTYPE * in_deriv, const int ndescrpt) { - const unsigned int idx = blockIdx.x; - const unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y; - const unsigned int idz = threadIdx.x; + __shared__ FPTYPE data[THREADS_PER_BLOCK * 3]; + unsigned int bid = blockIdx.x; + unsigned int tid = threadIdx.x; + for (int ii = tid; ii < THREADS_PER_BLOCK * 3; ii += THREADS_PER_BLOCK) { + data[ii] = 0.f; + } - if (idy >= ndescrpt) {return;} - - atomicAdd(force + idx * 3 + idz, -1.0 * net_deriv[idx * ndescrpt + idy] * in_deriv[idx * ndescrpt * 3 + idy * 3 + idz]); + for (int ii = tid; ii < ndescrpt; ii += THREADS_PER_BLOCK) { + for (int jj = 0; jj < 3; jj++) { + data[jj * THREADS_PER_BLOCK + tid] += net_deriv[bid * ndescrpt + ii] * in_deriv[bid * ndescrpt * 3 + ii * 3 + jj]; + } + } + __syncthreads(); + + // do reduction in shared memory + for (int ii = THREADS_PER_BLOCK >> 1; ii > 0; ii >>= 1) { + if (tid < ii) { + for (int jj = 0; jj < 3; jj++) { + data[jj * THREADS_PER_BLOCK + tid] += data[jj * THREADS_PER_BLOCK + tid + ii]; + } + } + __syncthreads(); + } + // write result for this block to global memory + if (tid == 0) { + force[bid * 3 + 0] -= data[THREADS_PER_BLOCK * 0]; + force[bid * 3 + 1] -= data[THREADS_PER_BLOCK * 1]; + force[bid * 3 + 2] -= data[THREADS_PER_BLOCK * 2]; + } } template -__global__ void deriv_wrt_neighbors_se_r(FPTYPE * force, +__global__ void force_deriv_wrt_neighbors_se_r(FPTYPE * force, const FPTYPE * net_deriv, const FPTYPE * in_deriv, const int * nlist, @@ -66,17 +87,13 @@ void ProdForceSeRGPUExecuteFunctor::operator()(FPTYPE * force, { // std::cout << "I'm here!" << std::endl; cudaErrcheck(cudaMemset(force, 0.0, sizeof(FPTYPE) * nall * 3)); - const int LEN1 = 256; - const int nblock1 = (ndescrpt + LEN1 -1) / LEN1; - dim3 grid(nloc, nblock1); - dim3 thread(3, LEN1); - deriv_wrt_center_atom_se_r<<>>(force, net_deriv, in_deriv, ndescrpt); + force_deriv_wrt_center_atom_se_r <<>>(force, net_deriv, in_deriv, ndescrpt); const int LEN = 64; int nblock = (nloc + LEN -1) / LEN; dim3 block_grid(nblock, nnei); dim3 thread_grid(LEN, 3); - deriv_wrt_neighbors_se_r<<>>(force, net_deriv, in_deriv, nlist, nloc, nnei, ndescrpt); + force_deriv_wrt_neighbors_se_r<<>>(force, net_deriv, in_deriv, nlist, nloc, nnei, ndescrpt); } template struct ProdForceSeRGPUExecuteFunctor; From ed571e10748f1120c7477d47a21dfcf0f13dc72a Mon Sep 17 00:00:00 2001 From: denghuilu Date: Wed, 3 Feb 2021 19:19:57 +0800 Subject: [PATCH 068/562] through compression error when resnet_dt is set true for descriptor --- source/train/compress.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/train/compress.py b/source/train/compress.py index 2174171ef6..fb4a505261 100644 --- a/source/train/compress.py +++ b/source/train/compress.py @@ -22,8 +22,9 @@ def compress(args): jdata['model']['descriptor']['model_file'] = args.input jdata['model']['descriptor']['table_info'] = args.table_info - # check the descriptor type of input file + # check the descriptor info of the input file assert jdata['model']['descriptor']['type'] == 'se_a', 'Model compression error: descriptor type must be se_a!' + assert jdata['model']['descriptor']['resnet_dt'] == False, 'Model compression error: descriptor resnet_dt must be false!' # stage 1: training or refining the model with tabulation print('\n\n# DEEPMD: stage 1: train or refine the model with tabulation') From 043a2f8c178104058e4c9c67157b2e2349c87981 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Wed, 3 Feb 2021 19:28:39 +0800 Subject: [PATCH 069/562] update cmake support for Anpere architecture devices --- source/op/cuda/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/op/cuda/CMakeLists.txt b/source/op/cuda/CMakeLists.txt index 20ef4d672e..96a030909c 100644 --- a/source/op/cuda/CMakeLists.txt +++ b/source/op/cuda/CMakeLists.txt @@ -28,7 +28,8 @@ if (${CUDA_VERSION_MAJOR} GREATER "10") -gencode arch=compute_61,code=sm_61; # Pascal - GTX 1080, GTX 1070, GTX 1060, GTX 1050, GTX 1030, Titan Xp, Tesla P40, Tesla P4, Discrete GPU on the NVIDIA Drive PX2 -gencode arch=compute_70,code=sm_70; # Volta - GV100/Tesla V100, GTX 1180 (GV104) -gencode arch=compute_75,code=sm_75; # Turing - RTX 2080, Titan RTX, Quadro R8000 - -gencode arch=compute_80,code=sm_86; # Anpere - RTX 2080, Titan RTX, Quadro R8000 + -gencode arch=compute_80,code=sm_80; # Anpere - A100 + -gencode arch=compute_86,code=sm_86; # Anpere - RTX 3090 -O3; -Xcompiler -fPIC; ) elseif (${CUDA_VERSION_MAJOR} STREQUAL "10") From 4eb6286b7ce4e2a1cd84585b61b7b61ac2f17b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Wed, 3 Feb 2021 13:03:25 +0100 Subject: [PATCH 070/562] add dosctings, pathlib, typing, uppercase constants to few base files --- deepmd/__init__.py | 28 +- deepmd/__main__.py | 3 +- deepmd/common.py | 459 +++++++++++++++++-------- deepmd/descriptor/se_a.py | 4 +- deepmd/descriptor/se_a_ef.py | 4 +- deepmd/descriptor/se_a_t.py | 4 +- deepmd/descriptor/se_r.py | 4 +- deepmd/env.py | 121 +++++-- deepmd/fit/dipole.py | 4 +- deepmd/fit/ener.py | 6 +- deepmd/fit/polar.py | 6 +- deepmd/fit/wfc.py | 2 +- deepmd/utils/argcheck.py | 26 +- deepmd/utils/compat.py | 309 +++++++++++------ setup.py | 139 ++++---- source/tests/test_model_loc_frame.py | 2 +- source/tests/test_model_se_a.py | 2 +- source/tests/test_model_se_a_aparam.py | 2 +- source/tests/test_model_se_a_fparam.py | 2 +- source/tests/test_model_se_a_srtab.py | 2 +- source/tests/test_model_se_r.py | 2 +- source/tests/test_polar_se_a.py | 2 +- source/tests/test_wfc.py | 2 +- 23 files changed, 757 insertions(+), 378 deletions(-) diff --git a/deepmd/__init__.py b/deepmd/__init__.py index a856bfe13d..b07ccc16c4 100644 --- a/deepmd/__init__.py +++ b/deepmd/__init__.py @@ -1,15 +1,17 @@ +"""Root of the deepmd package, exposes all public classes and submodules.""" + from . import descriptor from . import fit from . import loss from . import utils import deepmd.utils.network as network -from .infer.deep_eval import DeepEval -from .infer.deep_pot import DeepPot +from .infer.deep_eval import DeepEval +from .infer.deep_pot import DeepPot from .infer.deep_dipole import DeepDipole -from .infer.deep_polar import DeepPolar -from .infer.deep_polar import DeepGlobalPolar -from .infer.deep_wfc import DeepWFC -from .infer.data_modifier import DipoleChargeModifier +from .infer.deep_polar import DeepPolar +from .infer.deep_polar import DeepGlobalPolar +from .infer.deep_wfc import DeepWFC +from .infer.data_modifier import DipoleChargeModifier from .env import set_mkl set_mkl() @@ -19,3 +21,17 @@ except ImportError: from .__about__ import __version__ +__all__ = [ + "descriptor", + "fit", + "loss", + "utils", + "network", + "DeepEval", + "DeepPot", + "DeepDipole", + "DeepPolar", + "DeepGlobalPolar", + "DeepWFC", + "DipoleChargeModifier", +] diff --git a/deepmd/__main__.py b/deepmd/__main__.py index 04b1c9aca5..7ffb7018f9 100644 --- a/deepmd/__main__.py +++ b/deepmd/__main__.py @@ -1,5 +1,6 @@ +"""Package dp entry point.""" + from .main import main if __name__ == '__main__': main() - diff --git a/deepmd/common.py b/deepmd/common.py index cad4110ac5..8ba59c1e9c 100644 --- a/deepmd/common.py +++ b/deepmd/common.py @@ -1,218 +1,387 @@ -import os,warnings,fnmatch -import numpy as np -import math -from deepmd.env import tf -from deepmd.env import op_module -from deepmd.RunOptions import global_tf_float_precision import json +import warnings +from functools import wraps +from pathlib import Path +from typing import (TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, + TypeVar, Union) + +import numpy as np import yaml -# def gelu(x): -# """Gaussian Error Linear Unit. -# This is a smoother version of the RELU. -# Original paper: https://arxiv.org/abs/1606.08415 -# Args: -# x: float Tensor to perform activation. -# Returns: -# `x` with the GELU activation applied. -# """ -# cdf = 0.5 * (1.0 + tf.tanh((math.sqrt(2 / math.pi) * (x + 0.044715 * tf.pow(x, 3))))) -# return x * cdf -def gelu(x): +from deepmd.env import op_module, tf +from deepmd.RunOptions import global_tf_float_precision + +if TYPE_CHECKING: + _DICT_VAL = TypeVar("_DICT_VAL") + _OBJ = TypeVar("_OBJ") + try: + from typing import Literal # python 3.6 + except ImportError: + from typing_extensions import Literal + _ACTIVATION = Literal["relu", "relu6", "softplus", "sigmoid", "tanh", "gelu"] + _PRECISION = Literal["default", "float16", "float32", "float64"] + +# define constants +PRECISION_DICT = { + "default": global_tf_float_precision, + "float16": tf.float16, + "float32": tf.float32, + "float64": tf.float64, +} + + +def gelu(x: tf.Tensor) -> tf.Tensor: + """Gaussian Error Linear Unit. + + This is a smoother version of the RELU. + + Parameters + ---------- + x : tf.Tensor + float Tensor to perform activation + + Returns + ------- + `x` with the GELU activation applied + + References + ---------- + Original paper + https://arxiv.org/abs/1606.08415 + """ return op_module.gelu(x) + +# TODO this is not a good way to do things. This is some global variable to which +# TODO anyone can write and there is no good way to keep track of the changes data_requirement = {} -activation_fn_dict = { +ACTIVATION_FN_DICT = { "relu": tf.nn.relu, "relu6": tf.nn.relu6, "softplus": tf.nn.softplus, "sigmoid": tf.sigmoid, "tanh": tf.nn.tanh, - "gelu": gelu + "gelu": gelu, } -precision_dict = { - "default": global_tf_float_precision, - "float16": tf.float16, - "float32": tf.float32, - "float64": tf.float64, -} -def add_data_requirement(key, - ndof, - atomic = False, - must = False, - high_prec = False, - type_sel = None, - repeat = 1) : - data_requirement[key] = {'ndof': ndof, - 'atomic': atomic, - 'must': must, - 'high_prec': high_prec, - 'type_sel': type_sel, - 'repeat': repeat, +def add_data_requirement( + key: str, + ndof: int, + atomic: bool = False, + must: bool = False, + high_prec: bool = False, + type_sel: bool = None, + repeat: int = 1, +): + """Specify data requirements for training. + + Parameters + ---------- + key : str + type of data stored in corresponding `*.npy` file e.g. `forces` or `energy` + ndof : int + number of the degrees of freedom, this is tied to `atomic` parameter e.g. forces + have `atomic=True` and `ndof=3` + atomic : bool, optional + specifies whwther the `ndof` keyworrd applies to per atom quantity or not, + by default False + must : bool, optional + specifi if the `*.npy` data file must exist, by default False + high_prec : bool, optional + if tru load data to `np.float64` else `np.float32`, by default False + type_sel : bool, optional + select only certain type of atoms, by default None + repeat : int, optional + if specify repaeat data `repeat` times, by default 1 + """ + data_requirement[key] = { + "ndof": ndof, + "atomic": atomic, + "must": must, + "high_prec": high_prec, + "type_sel": type_sel, + "repeat": repeat, } - -def select_idx_map(atom_type, - type_sel): - sort_type_sel = np.sort(type_sel) - idx_map = np.array([], dtype = int) - for ii in sort_type_sel: - idx_map = np.append(idx_map, np.where(atom_type == ii)) + + +def select_idx_map( + atom_types: np.ndarray[int], select_types: np.ndarray[int] +) -> np.ndarray[int]: + """Build map of indices for element supplied element types from all atoms list. + + Parameters + ---------- + atom_types : np.ndarray[int] + array specifing type for each atoms as integer + select_types : np.ndarray[int] + types of atoms you want to find indices for + + Returns + ------- + np.ndarray[int] + indices of types of atoms defined by `select_types` in `atom_types` array + + Warnings + -------- + `select_types` array will be sorted before finding indices in `atom_types` + """ + sort_select_types = np.sort(select_types) + idx_map = np.array([], dtype=int) + for ii in sort_select_types: + idx_map = np.append(idx_map, np.where(atom_types == ii)) return idx_map -def make_default_mesh(test_box, cell_size = 3.0) : - # nframes = test_box.shape[0] - # default_mesh = np.zeros([nframes, 6], dtype = np.int32) - # for ff in range(nframes): - # ncell = np.ones (3, dtype=np.int32) - # for ii in range(3) : - # ncell[ii] = int ( np.linalg.norm(test_box[ff][ii]) / cell_size ) - # if (ncell[ii] < 2) : ncell[ii] = 2 - # default_mesh[ff][3] = ncell[0] - # default_mesh[ff][4] = ncell[1] - # default_mesh[ff][5] = ncell[2] - # return default_mesh - nframes = test_box.shape[0] - lboxv = np.linalg.norm(test_box.reshape([-1, 3, 3]), axis = 2) - avg_lboxv = np.average(lboxv, axis = 0) - ncell = (avg_lboxv / cell_size).astype(np.int32) +# TODO not really sure if the docstring is right the purpose of this is a bit unclear +def make_default_mesh( + test_box: np.ndarray[float], cell_size: float = 3.0 +) -> np.ndarray[int]: + """Get number of cells of size=`cell_size` fit into average box. + + Parameters + ---------- + test_box : np.ndarray[float] + numpy array with cells of shape Nx9 + cell_size : float, optional + length of one cell, by default 3.0 + + Returns + ------- + np.ndarray[float] + mesh for supplied boxes, how many cells fit in each direction + """ + cell_lengths = np.linalg.norm(test_box.reshape([-1, 3, 3]), axis=2) + avg_cell_lengths = np.average(cell_lengths, axis=0) + ncell = (avg_cell_lengths / cell_size).astype(np.int32) ncell[ncell < 2] = 2 - default_mesh = np.zeros (6, dtype = np.int32) + default_mesh = np.zeros(6, dtype=np.int32) default_mesh[3:6] = ncell - return default_mesh + return default_mesh -class ClassArg () : - def __init__ (self) : +# TODO not a good approach, every class uses this to parse arguments on its own, +# TODO json shoul be parsed once and the parsed result passed to all objects taht need it +class ClassArg: + def __init__(self): self.arg_dict = {} self.alias_map = {} - - def add (self, - key, - types_, - alias = None, - default = None, - must = False) : - if type(types_) is not list : + + def add( + self, + key: str, + types_: Union[type, List[type]], + alias: Optional[Union[str, List[str]]] = None, + default: Any = None, + must: bool = False, + ): + if not isinstance(types_, list): types = [types_] - else : + else: types = types_ - if alias is not None : - if type(alias) is not list : + if alias is not None: + if not isinstance(alias, list): alias_ = [alias] else: alias_ = alias - else : + else: alias_ = [] - self.arg_dict[key] = {'types' : types, - 'alias' : alias_, - 'value' : default, - 'must': must} - for ii in alias_ : + self.arg_dict[key] = { + "types": types, + "alias": alias_, + "value": default, + "must": must, + } + for ii in alias_: self.alias_map[ii] = key return self - - def _add_single(self, key, data) : + def _add_single(self, key: str, data: Any): vtype = type(data) if data is None: return data - if not(vtype in self.arg_dict[key]['types']) : - # ! altered by Marián Rynik - # try the type convertion to one of the types - for tp in self.arg_dict[key]['types']: - try : + if not (vtype in self.arg_dict[key]["types"]): + for tp in self.arg_dict[key]["types"]: + try: vv = tp(data) except TypeError: pass else: break else: - raise TypeError ("cannot convert provided key \"%s\" to type(s) %s " % (key, str(self.arg_dict[key]['types'])) ) - else : + raise TypeError( + 'cannot convert provided key "%s" to type(s) %s ' + % (key, str(self.arg_dict[key]["types"])) + ) + else: vv = data - self.arg_dict[key]['value'] = vv + self.arg_dict[key]["value"] = vv - - def _check_must(self) : + def _check_must(self): for kk in self.arg_dict: - if self.arg_dict[kk]['must'] and self.arg_dict[kk]['value'] is None: - raise RuntimeError('key \"%s\" must be provided' % kk) + if self.arg_dict[kk]["must"] and self.arg_dict[kk]["value"] is None: + raise RuntimeError('key "%s" must be provided' % kk) - - def parse(self, jdata) : - for kk in jdata.keys() : - if kk in self.arg_dict : + def parse(self, jdata: Dict[str, Any]) -> Dict[str, Any]: + for kk in jdata.keys(): + if kk in self.arg_dict: key = kk self._add_single(key, jdata[kk]) else: - if kk in self.alias_map: + if kk in self.alias_map: key = self.alias_map[kk] self._add_single(key, jdata[kk]) self._check_must() return self.get_dict() - def get_dict(self) : + def get_dict(self) -> Dict[str, Any]: ret = {} - for kk in self.arg_dict.keys() : - ret[kk] = self.arg_dict[kk]['value'] + for kk in self.arg_dict.keys(): + ret[kk] = self.arg_dict[kk]["value"] return ret -def j_must_have (jdata, key) : - if not key in jdata.keys() : - raise RuntimeError ("json database must provide key " + key ) - else : - return jdata[key] -def j_must_have_d (jdata, key, deprecated_key) : - if not key in jdata.keys() : - # raise RuntimeError ("json database must provide key " + key ) - for ii in deprecated_key : - if ii in jdata.keys() : - warnings.warn("the key \"%s\" is deprecated, please use \"%s\" instead" % (ii,key)) +# TODO maybe rename this to j_deprecated and only warn about deprecated keys, otherwise +# TODO its puppose is only custom error since dict[key] already raises KeyError when the +# TODO key is missing +def j_must_have( + jdata: Dict[str, "_DICT_VAL"], key: str, deprecated_key: List[str] = [] +) -> "_DICT_VAL": + """Assert that supplied dictionary conaines specified key. + + Returns + ------- + _DICT_VAL + value that was store unde supplied key + + Raises + ------ + RuntimeError + if the key is not present + """ + if key not in jdata.keys(): + for ii in deprecated_key: + if ii in jdata.keys(): + warnings.warn(f"the key {ii} is deprecated, please use {key} instead") return jdata[ii] - raise RuntimeError ("json database must provide key " + key ) - else : + else: + raise RuntimeError(f"json database must provide key {key}") + else: return jdata[key] -def j_have (jdata, key) : - return key in jdata.keys() -def j_loader(filename): +def j_loader(filename: Union[str, Path]) -> Dict[str, Any]: + """Load yaml or json settings file. + + Parameters + ---------- + filename : Union[str, Path] + path to file - if filename.endswith("json"): - with open(filename, 'r') as fp: + Returns + ------- + Dict[str, Any] + loaded dictionary + + Raises + ------ + TypeError + if the supplied file is of unsupported type + """ + filepath = Path(filename) + if filepath.suffix.endswith("json"): + with filepath.open() as fp: return json.load(fp) - elif filename.endswith(("yml", "yaml")): - with open(filename, 'r') as fp: + elif filepath.suffix.endswith(("yml", "yaml")): + with filepath.open() as fp: return yaml.safe_load(fp) else: raise TypeError("config file must be json, or yaml/yml") -def get_activation_func(activation_fn): - if activation_fn not in activation_fn_dict: - raise RuntimeError(activation_fn+" is not a valid activation function") - return activation_fn_dict[activation_fn] - -def get_precision(precision): - if precision not in precision_dict: - raise RuntimeError(precision+" is not a valid precision") - return precision_dict[precision] - -def expand_sys_str(root_dir): - matches = [] - for root, dirnames, filenames in os.walk(root_dir, followlinks=True): - for filename in fnmatch.filter(filenames, 'type.raw'): - matches.append(root) - return matches - -def docstring_parameter(*sub): - def dec(obj): - obj.__doc__ = obj.__doc__.format(*sub) + +def get_activation_func(activation_fn: "_ACTIVATION") -> Callable[[tf.Tensor], tf.Tensor]: + """Get activation function callable based on string name. + + Parameters + ---------- + activation_fn : _ACTIVATION + one of the defined activation functions + + Returns + ------- + Callable[[tf.Tensor], tf.Tensor] + correspondingg TF callable + + Raises + ------ + RuntimeError + if unknown activation function is specified + """ + if activation_fn not in ACTIVATION_FN_DICT: + raise RuntimeError(f"{activation_fn} is not a valid activation function") + return ACTIVATION_FN_DICT[activation_fn] + + +def get_precision(precision: "_PRECISION") -> tf.python.framework.dtypes.DType: + """Convert str to TF DType constant. + + Parameters + ---------- + precision : _PRECISION + one of the allowed precisions + + Returns + ------- + tf.python.framework.dtypes.DType + appropriate TF constant + + Raises + ------ + RuntimeError + if supplied precision string does not have acorresponding TF constant + """ + if precision not in PRECISION_DICT: + raise RuntimeError(f"{precision} is not a valid precision") + return PRECISION_DICT[precision] + + +# TODO port completely to pathlib when all callers are ported +def expand_sys_str(root_dir: Union[str, Path]) -> List[str]: + """Recursively iterate over directories taking those that contain `type.raw` file. + + Parameters + ---------- + root_dir : Union[str, Path] + starting directory + + Returns + ------- + List[str] + list of string pointing to system directories + """ + matches = [d for d in Path(root_dir).rglob("*") if (d / "type.raw").is_file()] + return [str(m.resolve()) for m in matches] + + +def docstring_parameter(*sub: Tuple[str, ...]): + """Add parameters to object docstring. + + Parameters + ---------- + sub: Tuple[str, ...] + list of strings that will be inserted into prepared locations in docstring. + + Note + ---- + Can be used on both object and classes. + """ + @wraps + def dec(obj: "_OBJ") -> "_OBJ": + if obj.__doc__ is not None: + obj.__doc__ = obj.__doc__.format(*sub) return obj + return dec diff --git a/deepmd/descriptor/se_a.py b/deepmd/descriptor/se_a.py index 410cf0d9b4..369a57d677 100644 --- a/deepmd/descriptor/se_a.py +++ b/deepmd/descriptor/se_a.py @@ -2,7 +2,7 @@ from typing import Tuple, List from deepmd.env import tf -from deepmd.common import get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter +from deepmd.common import get_activation_func, get_precision, ACTIVATION_FN_DICT, PRECISION_DICT, docstring_parameter from deepmd.utils.argcheck import list_to_doc from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision @@ -12,7 +12,7 @@ class DescrptSeA (): - @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + @docstring_parameter(list_to_doc(ACTIVATION_FN_DICT.keys()), list_to_doc(PRECISION_DICT.keys())) def __init__ (self, rcut: float, rcut_smth: float, diff --git a/deepmd/descriptor/se_a_ef.py b/deepmd/descriptor/se_a_ef.py index fd05669cbb..7315f75401 100644 --- a/deepmd/descriptor/se_a_ef.py +++ b/deepmd/descriptor/se_a_ef.py @@ -2,7 +2,7 @@ from typing import Tuple, List from deepmd.env import tf -from deepmd.common import add_data_requirement,get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter +from deepmd.common import add_data_requirement,get_activation_func, get_precision, ACTIVATION_FN_DICT, PRECISION_DICT, docstring_parameter from deepmd.utils.argcheck import list_to_doc from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision @@ -11,7 +11,7 @@ from .se_a import DescrptSeA class DescrptSeAEf (): - @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + @docstring_parameter(list_to_doc(ACTIVATION_FN_DICT.keys()), list_to_doc(PRECISION_DICT.keys())) def __init__(self, rcut: float, rcut_smth: float, diff --git a/deepmd/descriptor/se_a_t.py b/deepmd/descriptor/se_a_t.py index 64732b496f..c1987e9e02 100644 --- a/deepmd/descriptor/se_a_t.py +++ b/deepmd/descriptor/se_a_t.py @@ -2,7 +2,7 @@ from typing import Tuple, List from deepmd.env import tf -from deepmd.common import get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter +from deepmd.common import get_activation_func, get_precision, ACTIVATION_FN_DICT, PRECISION_DICT, docstring_parameter from deepmd.utils.argcheck import list_to_doc from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision @@ -11,7 +11,7 @@ from deepmd.utils.network import embedding_net class DescrptSeAT (): - @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + @docstring_parameter(list_to_doc(ACTIVATION_FN_DICT.keys()), list_to_doc(PRECISION_DICT.keys())) def __init__ (self, rcut: float, rcut_smth: float, diff --git a/deepmd/descriptor/se_r.py b/deepmd/descriptor/se_r.py index 2eab2afe09..3a7b9a3f49 100644 --- a/deepmd/descriptor/se_r.py +++ b/deepmd/descriptor/se_r.py @@ -2,7 +2,7 @@ from typing import Tuple, List from deepmd.env import tf -from deepmd.common import get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter +from deepmd.common import get_activation_func, get_precision, ACTIVATION_FN_DICT, PRECISION_DICT, docstring_parameter from deepmd.utils.argcheck import list_to_doc from deepmd.RunOptions import global_tf_float_precision from deepmd.RunOptions import global_np_float_precision @@ -11,7 +11,7 @@ from deepmd.utils.network import embedding_net class DescrptSeR (): - @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + @docstring_parameter(list_to_doc(ACTIVATION_FN_DICT.keys()), list_to_doc(PRECISION_DICT.keys())) def __init__ (self, rcut: float, rcut_smth: float, diff --git a/deepmd/env.py b/deepmd/env.py index dec9ec8eaa..f7290d5887 100644 --- a/deepmd/env.py +++ b/deepmd/env.py @@ -1,62 +1,135 @@ +"""This module sets tensorflow working environment.""" + import os +from pathlib import Path import logging import platform +from typing import Tuple, TYPE_CHECKING, Any import numpy as np from imp import reload +if TYPE_CHECKING: + from types import ModuleType + # import tensorflow v1 compatability try: import tensorflow.compat.v1 as tf + tf.disable_v2_behavior() except ImportError: import tensorflow as tf -def set_env_if_empty(key, value, verbose=True): + +def set_env_if_empty(key: str, value: str, verbose: bool = True): + """Set environment variable only if it is empty. + + Parameters + ---------- + key : str + env variable name + value : str + env variable value + verbose : bool, optional + if True action will be logged, by default True + """ if os.environ.get(key) is None: os.environ[key] = value if verbose: - logging.warn("Environment variable {} is empty. Use the default value {}".format(key, value)) + logging.warn( + f"Environment variable {key} is empty. Use the default value {value}" + ) + def set_mkl(): - """Tuning MKL for the best performance + """Tuning MKL for the best performance. + + References + ---------- + TF overview https://www.tensorflow.org/guide/performance/overview - - Fixing an issue in numpy built by MKL. See + + Fixing an issue in numpy built by MKL https://github.com/ContinuumIO/anaconda-issues/issues/11367 https://github.com/numpy/numpy/issues/12374 - """ - # check whether the numpy is built by mkl, see - # https://github.com/numpy/numpy/issues/14751 - if 'mkl_rt' in np.__config__.get_info("blas_mkl_info").get('libraries', []): + check whether the numpy is built by mkl, see + https://github.com/numpy/numpy/issues/14751 + """ + if "mkl_rt" in np.__config__.get_info("blas_mkl_info").get("libraries", []): set_env_if_empty("KMP_BLOCKTIME", "0") set_env_if_empty("KMP_AFFINITY", "granularity=fine,verbose,compact,1,0") reload(np) + def set_tf_default_nthreads(): + """Set TF internal number of threads to default=automatic selection. + + Notes + ----- + `TF_INTRA_OP_PARALLELISM_THREADS` and `TF_INTER_OP_PARALLELISM_THREADS` + control TF configuration of multithreading. + """ set_env_if_empty("TF_INTRA_OP_PARALLELISM_THREADS", "0", verbose=False) set_env_if_empty("TF_INTER_OP_PARALLELISM_THREADS", "0", verbose=False) -def get_tf_default_nthreads(): - return int(os.environ.get('TF_INTRA_OP_PARALLELISM_THREADS')), int(os.environ.get('TF_INTER_OP_PARALLELISM_THREADS')) - -def get_tf_session_config(): - set_tf_default_nthreads() + +def get_tf_default_nthreads() -> Tuple[int, int]: + """Get TF paralellism settings. + + Returns + ------- + Tuple[int, int] + number of `TF_INTRA_OP_PARALLELISM_THREADS` and + `TF_INTER_OP_PARALLELISM_THREADS` + """ + return int(os.environ.get("TF_INTRA_OP_PARALLELISM_THREADS", "0")), int( + os.environ.get("TF_INTER_OP_PARALLELISM_THREADS", "0") + ) + + +def get_tf_session_config() -> Any: + """Configure tensorflow session. + + Returns + ------- + Any + session configure object + """ + set_tf_default_nthreads() intra, inter = get_tf_default_nthreads() - return tf.ConfigProto(intra_op_parallelism_threads=intra, inter_op_parallelism_threads=inter) + return tf.ConfigProto( + intra_op_parallelism_threads=intra, inter_op_parallelism_threads=inter + ) + -def get_module(module_name): - """Load force module.""" +def get_module(module_name: str) -> "ModuleType": + """Load force module. + + Returns + ------- + ModuleType + loaded force module + + Raises + ------ + FileNotFoundError + if module is not found in directory + """ if platform.system() == "Windows": - ext = "dll" + ext = ".dll" elif platform.system() == "Darwin": - ext = "dylib" + ext = ".dylib" else: - ext = "so" - module_path = os.path.dirname(os.path.realpath(__file__)) + "/" - assert (os.path.isfile (module_path + "{}.{}".format(module_name, ext) )), "module %s does not exist" % module_name - module = tf.load_op_library(module_path + "{}.{}".format(module_name, ext)) - return module + ext = ".so" + + module_file = (Path(__file__).parent / module_name).with_suffix(ext) + + if not module_file.is_file(): + raise FileNotFoundError(f"module {module_name} does not exist") + else: + module = tf.load_op_library(os.fspath(module_file)) + return module + op_module = get_module("libop_abi") op_grads_module = get_module("libop_grads") diff --git a/deepmd/fit/dipole.py b/deepmd/fit/dipole.py index 85bc1065f1..fbe3b3fcf0 100644 --- a/deepmd/fit/dipole.py +++ b/deepmd/fit/dipole.py @@ -3,7 +3,7 @@ from typing import Tuple, List from deepmd.env import tf -from deepmd.common import add_data_requirement, get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter +from deepmd.common import add_data_requirement, get_activation_func, get_precision, ACTIVATION_FN_DICT, PRECISION_DICT, docstring_parameter from deepmd.utils.argcheck import list_to_doc from deepmd.utils.network import one_layer from deepmd.descriptor import DescrptSeA @@ -15,7 +15,7 @@ class DipoleFittingSeA () : """ Fit the atomic dipole with descriptor se_a """ - @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + @docstring_parameter(list_to_doc(ACTIVATION_FN_DICT.keys()), list_to_doc(PRECISION_DICT.keys())) def __init__ (self, descrpt : tf.Tensor, neuron : List[int] = [120,120,120], diff --git a/deepmd/fit/ener.py b/deepmd/fit/ener.py index 5c766f729b..97118d2b33 100644 --- a/deepmd/fit/ener.py +++ b/deepmd/fit/ener.py @@ -3,7 +3,7 @@ from typing import Tuple, List from deepmd.env import tf -from deepmd.common import ClassArg, add_data_requirement, get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter +from deepmd.common import ClassArg, add_data_requirement, get_activation_func, get_precision, ACTIVATION_FN_DICT, PRECISION_DICT, docstring_parameter from deepmd.utils.argcheck import list_to_doc from deepmd.utils.network import one_layer from deepmd.descriptor import DescrptLocFrame @@ -13,7 +13,7 @@ from deepmd.RunOptions import global_tf_float_precision class EnerFitting (): - @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + @docstring_parameter(list_to_doc(ACTIVATION_FN_DICT.keys()), list_to_doc(PRECISION_DICT.keys())) def __init__ (self, descrpt : tf.Tensor, neuron : List[int] = [120,120,120], @@ -64,7 +64,7 @@ def __init__ (self, # model param self.ntypes = descrpt.get_ntypes() self.dim_descrpt = descrpt.get_dim_out() - # args = ClassArg()\ + # args = ()\ # .add('numb_fparam', int, default = 0)\ # .add('numb_aparam', int, default = 0)\ # .add('neuron', list, default = [120,120,120], alias = 'n_neuron')\ diff --git a/deepmd/fit/polar.py b/deepmd/fit/polar.py index c93aa43d1b..3a03650946 100644 --- a/deepmd/fit/polar.py +++ b/deepmd/fit/polar.py @@ -3,7 +3,7 @@ from typing import Tuple, List from deepmd.env import tf -from deepmd.common import add_data_requirement, get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter +from deepmd.common import add_data_requirement, get_activation_func, get_precision, ACTIVATION_FN_DICT, PRECISION_DICT, docstring_parameter from deepmd.utils.argcheck import list_to_doc from deepmd.utils.network import one_layer from deepmd.descriptor import DescrptLocFrame @@ -102,7 +102,7 @@ class PolarFittingSeA () : """ Fit the atomic polarizability with descriptor se_a """ - @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + @docstring_parameter(list_to_doc(ACTIVATION_FN_DICT.keys()), list_to_doc(PRECISION_DICT.keys())) def __init__ (self, descrpt : tf.Tensor, neuron : List[int] = [120,120,120], @@ -325,7 +325,7 @@ class GlobalPolarFittingSeA () : """ Fit the system polarizability with descriptor se_a """ - @docstring_parameter(list_to_doc(activation_fn_dict.keys()), list_to_doc(precision_dict.keys())) + @docstring_parameter(list_to_doc(ACTIVATION_FN_DICT.keys()), list_to_doc(PRECISION_DICT.keys())) def __init__ (self, descrpt : tf.Tensor, neuron : List[int] = [120,120,120], diff --git a/deepmd/fit/wfc.py b/deepmd/fit/wfc.py index 88f63a366e..c3a565d714 100644 --- a/deepmd/fit/wfc.py +++ b/deepmd/fit/wfc.py @@ -3,7 +3,7 @@ from typing import Tuple, List from deepmd.env import tf -from deepmd.common import ClassArg, add_data_requirement, get_activation_func, get_precision, activation_fn_dict, precision_dict, docstring_parameter +from deepmd.common import ClassArg, add_data_requirement, get_activation_func, get_precision, ACTIVATION_FN_DICT, PRECISION_DICT, docstring_parameter from deepmd.utils.argcheck import list_to_doc from deepmd.utils.network import one_layer from deepmd.descriptor import DescrptLocFrame diff --git a/deepmd/utils/argcheck.py b/deepmd/utils/argcheck.py index 74cf886fa6..a3f4d56b1e 100644 --- a/deepmd/utils/argcheck.py +++ b/deepmd/utils/argcheck.py @@ -1,5 +1,5 @@ from dargs import Argument, Variant -from deepmd.common import activation_fn_dict, precision_dict +from deepmd.common import ACTIVATION_FN_DICT, PRECISION_DICT def list_to_doc (xx): items = [] @@ -42,10 +42,10 @@ def descrpt_se_a_args(): doc_rcut_smth = 'Where to start smoothing. For example the 1/r term is smoothed from `rcut` to `rcut_smth`' doc_neuron = 'Number of neurons in each hidden layers of the embedding net. When two layers are of the same size or one layer is twice as large as the previous layer, a skip connection is built.' doc_axis_neuron = 'Size of the submatrix of G (embedding matrix).' - doc_activation_function = f'The activation function in the embedding net. Supported activation functions are {list_to_doc(activation_fn_dict.keys())}' + doc_activation_function = f'The activation function in the embedding net. Supported activation functions are {list_to_doc(ACTIVATION_FN_DICT.keys())}' doc_resnet_dt = 'Whether to use a "Timestep" in the skip connection' doc_type_one_side = 'Try to build N_types embedding nets. Otherwise, building N_types^2 embedding nets' - doc_precision = f'The precision of the embedding net parameters, supported options are {list_to_doc(precision_dict.keys())}' + doc_precision = f'The precision of the embedding net parameters, supported options are {list_to_doc(PRECISION_DICT.keys())}' doc_trainable = 'If the parameters in the embedding net is trainable' doc_seed = 'Random seed for parameter initialization' doc_exclude_types = 'The Excluded types' @@ -73,9 +73,9 @@ def descrpt_se_a_3be_args(): doc_rcut = 'The cut-off radius.' doc_rcut_smth = 'Where to start smoothing. For example the 1/r term is smoothed from `rcut` to `rcut_smth`' doc_neuron = 'Number of neurons in each hidden layers of the embedding net. When two layers are of the same size or one layer is twice as large as the previous layer, a skip connection is built.' - doc_activation_function = f'The activation function in the embedding net. Supported activation functions are {list_to_doc(activation_fn_dict.keys())}' + doc_activation_function = f'The activation function in the embedding net. Supported activation functions are {list_to_doc(ACTIVATION_FN_DICT.keys())}' doc_resnet_dt = 'Whether to use a "Timestep" in the skip connection' - doc_precision = f'The precision of the embedding net parameters, supported options are {list_to_doc(precision_dict.keys())}' + doc_precision = f'The precision of the embedding net parameters, supported options are {list_to_doc(PRECISION_DICT.keys())}' doc_trainable = 'If the parameters in the embedding net is trainable' doc_seed = 'Random seed for parameter initialization' doc_set_davg_zero = 'Set the normalization average to zero. This option should be set when `atom_ener` in the energy fitting is used' @@ -112,10 +112,10 @@ def descrpt_se_r_args(): doc_rcut = 'The cut-off radius.' doc_rcut_smth = 'Where to start smoothing. For example the 1/r term is smoothed from `rcut` to `rcut_smth`' doc_neuron = 'Number of neurons in each hidden layers of the embedding net. When two layers are of the same size or one layer is twice as large as the previous layer, a skip connection is built.' - doc_activation_function = f'The activation function in the embedding net. Supported activation functions are {list_to_doc(activation_fn_dict.keys())}' + doc_activation_function = f'The activation function in the embedding net. Supported activation functions are {list_to_doc(ACTIVATION_FN_DICT.keys())}' doc_resnet_dt = 'Whether to use a "Timestep" in the skip connection' doc_type_one_side = 'Try to build N_types embedding nets. Otherwise, building N_types^2 embedding nets' - doc_precision = f'The precision of the embedding net parameters, supported options are {list_to_doc(precision_dict.keys())}' + doc_precision = f'The precision of the embedding net parameters, supported options are {list_to_doc(PRECISION_DICT.keys())}' doc_trainable = 'If the parameters in the embedding net is trainable' doc_seed = 'Random seed for parameter initialization' doc_exclude_types = 'The Excluded types' @@ -188,8 +188,8 @@ def fitting_ener(): doc_numb_fparam = 'The dimension of the frame parameter. If set to >0, file `fparam.npy` should be included to provided the input fparams.' doc_numb_aparam = 'The dimension of the atomic parameter. If set to >0, file `aparam.npy` should be included to provided the input aparams.' doc_neuron = 'The number of neurons in each hidden layers of the fitting net. When two hidden layers are of the same size, a skip connection is built.' - doc_activation_function = f'The activation function in the fitting net. Supported activation functions are {list_to_doc(activation_fn_dict.keys())}' - doc_precision = f'The precision of the fitting net parameters, supported options are {list_to_doc(precision_dict.keys())}' + doc_activation_function = f'The activation function in the fitting net. Supported activation functions are {list_to_doc(ACTIVATION_FN_DICT.keys())}' + doc_precision = f'The precision of the fitting net parameters, supported options are {list_to_doc(PRECISION_DICT.keys())}' doc_resnet_dt = 'Whether to use a "Timestep" in the skip connection' doc_trainable = 'Whether the parameters in the fitting net are trainable. This option can be\n\n\ - bool: True if all parameters of the fitting net are trainable, False otherwise.\n\n\ @@ -214,9 +214,9 @@ def fitting_ener(): def fitting_polar(): doc_neuron = 'The number of neurons in each hidden layers of the fitting net. When two hidden layers are of the same size, a skip connection is built.' - doc_activation_function = f'The activation function in the fitting net. Supported activation functions are {list_to_doc(activation_fn_dict.keys())}' + doc_activation_function = f'The activation function in the fitting net. Supported activation functions are {list_to_doc(ACTIVATION_FN_DICT.keys())}' doc_resnet_dt = 'Whether to use a "Timestep" in the skip connection' - doc_precision = f'The precision of the fitting net parameters, supported options are {list_to_doc(precision_dict.keys())}' + doc_precision = f'The precision of the fitting net parameters, supported options are {list_to_doc(PRECISION_DICT.keys())}' doc_scale = 'The output of the fitting net (polarizability matrix) will be scaled by ``scale``' doc_diag_shift = 'The diagonal part of the polarizability matrix will be shifted by ``diag_shift``. The shift operation is carried out after ``scale``.' doc_fit_diag = 'Fit the diagonal part of the rotational invariant polarizability matrix, which will be converted to normal polarizability matrix by contracting with the rotation matrix.' @@ -242,9 +242,9 @@ def fitting_global_polar(): def fitting_dipole(): doc_neuron = 'The number of neurons in each hidden layers of the fitting net. When two hidden layers are of the same size, a skip connection is built.' - doc_activation_function = f'The activation function in the fitting net. Supported activation functions are {list_to_doc(activation_fn_dict.keys())}' + doc_activation_function = f'The activation function in the fitting net. Supported activation functions are {list_to_doc(ACTIVATION_FN_DICT.keys())}' doc_resnet_dt = 'Whether to use a "Timestep" in the skip connection' - doc_precision = f'The precision of the fitting net parameters, supported options are {list_to_doc(precision_dict.keys())}' + doc_precision = f'The precision of the fitting net parameters, supported options are {list_to_doc(PRECISION_DICT.keys())}' doc_sel_type = 'The atom types for which the atomic dipole will be provided. If not set, all types will be selected.' doc_seed = 'Random seed for parameter initialization of the fitting net' return [ diff --git a/deepmd/utils/compat.py b/deepmd/utils/compat.py index 40ac118e23..9962e96f12 100644 --- a/deepmd/utils/compat.py +++ b/deepmd/utils/compat.py @@ -1,133 +1,240 @@ -import json,warnings -from deepmd.common import j_have,j_must_have,j_must_have_d +"""Module providing compatibility between `0.x.x` and `1.x.x` input versions.""" -def convert_input_v0_v1(jdata, warning = True, dump = None) : +import json +import warnings +from pathlib import Path +from typing import Any, Dict, Optional, Sequence, Union + +from deepmd.common import j_must_have + + +def convert_input_v0_v1( + jdata: Dict[str, Any], warning: bool = True, dump: Optional[Union[str, Path]] = None +): output = {} - if 'with_distrib' in jdata: - output['with_distrib'] = jdata['with_distrib'] - if jdata['use_smooth'] : - output['model'] = _smth_model(jdata) - else: - output['model'] = _nonsmth_model(jdata) - output['learning_rate'] = _learning_rate(jdata) - output['loss'] = _loss(jdata) - output['training'] = _training(jdata) - _warnning_input_v0_v1(dump) + if "with_distrib" in jdata: + output["with_distrib"] = jdata["with_distrib"] + output["model"] = _model(jdata, jdata["use_smooth"]) + output["learning_rate"] = _learning_rate(jdata) + output["loss"] = _loss(jdata) + output["training"] = _training(jdata) + if warning: + _warnning_input_v0_v1(dump) if dump is not None: - with open(dump, 'w') as fp: - json.dump(output, fp, indent=4) + with open(dump, "w") as fp: + json.dump(output, fp, indent=4) return output -def _warnning_input_v0_v1(fname) : - msg = 'It seems that you are using a deepmd-kit input of version 0.x.x, which is deprecated. we have converted the input to >1.0.0 compatible' + +def _warnning_input_v0_v1(fname: Optional[Union[str, Path]]): + msg = ( + "It seems that you are using a deepmd-kit input of version 0.x.x, " + "which is deprecated. we have converted the input to >1.0.0 compatible" + ) if fname is not None: - msg += ', and output it to file ' + fname + msg += f", and output it to file {fname}" warnings.warn(msg) -def _nonsmth_model(jdata): - model = {} - model['descriptor'] = _nonsmth_descriptor(jdata) - model['fitting_net'] = _fitting_net(jdata) - return model -def _smth_model(jdata): +def _model(jdata: Dict[str, Any], smooth: bool) -> Dict[str, Dict[str, Any]]: + """Convert data to v1 input for non-smooth model. + + Parameters + ---------- + jdata : Dict[str, Any] + parsed input json/yaml data + smooth : bool + whether to use smooth or non-smooth descriptor version + + Returns + ------- + Dict[str, Dict[str, Any]] + dictionary with model input parameters and sub-dictionaries for descriptor and + fitting net + """ model = {} - model['descriptor'] = _smth_descriptor(jdata) - model['fitting_net'] = _fitting_net(jdata) + model["descriptor"] = ( + _smth_descriptor(jdata) if smooth else _nonsmth_descriptor(jdata) + ) + model["fitting_net"] = _fitting_net(jdata) return model -def _nonsmth_descriptor(jdata) : - # model + +def _nonsmth_descriptor(jdata: Dict[str, Any]) -> Dict[str, Any]: + """Convert data to v1 input for non-smooth descriptor. + + Parameters + ---------- + jdata : Dict[str, Any] + parsed input json/yaml data + + Returns + ------- + Dict[str, Any] + dict with descriptor parameters + """ descriptor = {} - descriptor['type'] = 'loc_frame' - descriptor['sel_a'] = jdata['sel_a'] - descriptor['sel_r'] = jdata['sel_r'] - descriptor['rcut'] = jdata['rcut'] - descriptor['axis_rule'] = jdata['axis_rule'] + descriptor["type"] = "loc_frame" + _jcopy(jdata, descriptor, ("sel_a", "sel_r", "rcut", "axis_rule")) return descriptor -def _smth_descriptor(jdata): + +def _smth_descriptor(jdata: Dict[str, Any]) -> Dict[str, Any]: + """Convert data to v1 input for smooth descriptor. + + Parameters + ---------- + jdata : Dict[str, Any] + parsed input json/yaml data + + Returns + ------- + Dict[str, Any] + dict with descriptor parameters + """ descriptor = {} - seed = None - if j_have (jdata, 'seed') : - seed = jdata['seed'] - descriptor['type'] = 'se_a' - descriptor['sel'] = jdata['sel_a'] - if j_have(jdata, 'rcut_smth') : - descriptor['rcut_smth'] = jdata['rcut_smth'] - else : - descriptor['rcut_smth'] = descriptor['rcut'] - descriptor['rcut'] = jdata['rcut'] - descriptor['neuron'] = j_must_have (jdata, 'filter_neuron') - descriptor['axis_neuron'] = j_must_have_d (jdata, 'axis_neuron', ['n_axis_neuron']) - descriptor['resnet_dt'] = False - if j_have(jdata, 'resnet_dt') : - descriptor['resnet_dt'] = jdata['filter_resnet_dt'] + seed = jdata.get("seed", None) if seed is not None: - descriptor['seed'] = seed + descriptor["seed"] = seed + descriptor["type"] = "se_a" + _jcopy(jdata, descriptor, ("sel_a", "rcut")) + descriptor["rcut_smth"] = jdata.get("rcut_smth", descriptor["rcut"]) + descriptor["neuron"] = j_must_have(jdata, "filter_neuron") + descriptor["axis_neuron"] = j_must_have(jdata, "axis_neuron", ["n_axis_neuron"]) + descriptor["resnet_dt"] = False + if "resnet_dt" in jdata: + descriptor["resnet_dt"] = jdata["filter_resnet_dt"] + return descriptor -def _fitting_net(jdata): + +def _fitting_net(jdata: Dict[str, Any]) -> Dict[str, Any]: + """Convert data to v1 input for fitting net. + + Parameters + ---------- + jdata : Dict[str, Any] + parsed input json/yaml data + + Returns + ------- + Dict[str, Any] + dict with fitting net parameters + """ fitting_net = {} - seed = None - if j_have (jdata, 'seed') : - seed = jdata['seed'] - fitting_net['neuron']= j_must_have_d (jdata, 'fitting_neuron', ['n_neuron']) - fitting_net['resnet_dt'] = True - if j_have(jdata, 'resnet_dt') : - fitting_net['resnet_dt'] = jdata['resnet_dt'] - if j_have(jdata, 'fitting_resnet_dt') : - fitting_net['resnet_dt'] = jdata['fitting_resnet_dt'] + + seed = jdata.get("seed", None) if seed is not None: - fitting_net['seed'] = seed + fitting_net["seed"] = seed + fitting_net["neuron"] = j_must_have(jdata, "fitting_neuron", ["n_neuron"]) + fitting_net["resnet_dt"] = True + if "resnet_dt" in jdata: + fitting_net["resnet_dt"] = jdata["resnet_dt"] + if "fitting_resnet_dt" in jdata: + fitting_net["resnet_dt"] = jdata["fitting_resnet_dt"] return fitting_net -def _learning_rate(jdata): - # learning rate + +def _learning_rate(jdata: Dict[str, Any]) -> Dict[str, Any]: + """Convert data to v1 input for learning rate section. + + Parameters + ---------- + jdata : Dict[str, Any] + parsed input json/yaml data + + Returns + ------- + Dict[str, Any] + dict with learning rate parameters + """ learning_rate = {} - learning_rate['type'] = 'exp' - learning_rate['decay_steps'] = j_must_have(jdata, 'decay_steps') - learning_rate['decay_rate'] = j_must_have(jdata, 'decay_rate') - learning_rate['start_lr'] = j_must_have(jdata, 'start_lr') + learning_rate["type"] = "exp" + _jcopy(jdata, learning_rate, ("decay_steps", "decay_rate", "start_lr")) return learning_rate -def _loss(jdata): - # loss + +def _loss(jdata: Dict[str, Any]) -> Dict[str, Any]: + """Convert data to v1 input for loss function. + + Parameters + ---------- + jdata : Dict[str, Any] + parsed input json/yaml data + + Returns + ------- + Dict[str, Any] + dict with loss function parameters + """ loss = {} - loss['start_pref_e'] = j_must_have (jdata, 'start_pref_e') - loss['limit_pref_e'] = j_must_have (jdata, 'limit_pref_e') - loss['start_pref_f'] = j_must_have (jdata, 'start_pref_f') - loss['limit_pref_f'] = j_must_have (jdata, 'limit_pref_f') - loss['start_pref_v'] = j_must_have (jdata, 'start_pref_v') - loss['limit_pref_v'] = j_must_have (jdata, 'limit_pref_v') - if j_have(jdata, 'start_pref_ae') : - loss['start_pref_ae'] = jdata['start_pref_ae'] - if j_have(jdata, 'limit_pref_ae') : - loss['limit_pref_ae'] = jdata['limit_pref_ae'] + _jcopy( + jdata, + loss, + ( + "start_pref_e", + "limit_pref_e", + "start_pref_f", + "limit_pref_f", + "start_pref_v", + "limit_pref_v", + ), + ) + if "start_pref_ae" in jdata: + loss["start_pref_ae"] = jdata["start_pref_ae"] + if "limit_pref_ae" in jdata: + loss["limit_pref_ae"] = jdata["limit_pref_ae"] return loss -def _training(jdata): - # training + +def _training(jdata: Dict[str, Any]) -> Dict[str, Any]: + """Convert data to v1 input for training. + + Parameters + ---------- + jdata : Dict[str, Any] + parsed input json/yaml data + + Returns + ------- + Dict[str, Any] + dict with training parameters + """ training = {} - seed = None - if j_have (jdata, 'seed') : - seed = jdata['seed'] - training['systems'] = jdata['systems'] - training['set_prefix'] = jdata['set_prefix'] - training['stop_batch'] = jdata['stop_batch'] - training['batch_size'] = jdata['batch_size'] + seed = jdata.get("seed", None) if seed is not None: - training['seed'] = seed - training['disp_file'] = "lcurve.out" - if j_have (jdata, "disp_file") : training['disp_file'] = jdata["disp_file"] - training['disp_freq'] = j_must_have (jdata, 'disp_freq') - training['numb_test'] = j_must_have (jdata, 'numb_test') - training['save_freq'] = j_must_have (jdata, 'save_freq') - training['save_ckpt'] = j_must_have (jdata, 'save_ckpt') - training['disp_training'] = j_must_have (jdata, 'disp_training') - training['time_training'] = j_must_have (jdata, 'time_training') - if j_have (jdata, 'profiling') : - training['profiling'] = jdata['profiling'] - if training['profiling'] : - training['profiling_file'] = j_must_have (jdata, 'profiling_file') + training["seed"] = seed + + _jcopy(jdata, training, ("systems", "set_prefix", "stop_batch", "batch_size")) + training["disp_file"] = "lcurve.out" + if "disp_file" in jdata: + training["disp_file"] = jdata["disp_file"] + training["disp_freq"] = j_must_have(jdata, "disp_freq") + training["numb_test"] = j_must_have(jdata, "numb_test") + training["save_freq"] = j_must_have(jdata, "save_freq") + training["save_ckpt"] = j_must_have(jdata, "save_ckpt") + training["disp_training"] = j_must_have(jdata, "disp_training") + training["time_training"] = j_must_have(jdata, "time_training") + if "profiling" in jdata: + training["profiling"] = jdata["profiling"] + if training["profiling"]: + training["profiling_file"] = j_must_have(jdata, "profiling_file") return training + + +def _jcopy(src: Dict[str, Any], dst: Dict[str, Any], keys: Sequence[str], must_have: bool): + """Copy specified keys from one dict to another. + + Parameters + ---------- + src : Dict[str, Any] + source dictionary + dst : Dict[str, Any] + destination dictionary, will be modified in place + keys : Sequence[str] + list of keys to copy + must_have : bool + ensure that the source dictionary contains the copyyied keys + """ + for k in keys: + dst[k] = src[k] diff --git a/setup.py b/setup.py index b7b104d33c..bb41ed3a67 100644 --- a/setup.py +++ b/setup.py @@ -1,95 +1,108 @@ +"""Setup script for DeePMD-kit package.""" + +import os +from distutils.util import get_platform +from importlib.machinery import FileFinder +from importlib.util import find_spec +from pathlib import Path +from sysconfig import get_path + +from packaging.specifiers import SpecifierSet +from pkg_resources import Distribution from skbuild import setup -from skbuild.exceptions import SKBuildError from skbuild.cmaker import get_cmake_version -from setuptools_scm import get_version -from packaging.version import LegacyVersion -from os import path, makedirs -import os, importlib -import pkg_resources -from distutils.util import get_platform +from skbuild.exceptions import SKBuildError +# define constants +INSTALL_REQUIRES = ["numpy", "scipy", "pyyaml", "dargs", "typing_extensions"] +setup_requires = ["setuptools_scm", "scikit-build"] -readme_file = path.join(path.dirname(path.abspath(__file__)), 'README.md') -try: - from m2r import parse_from_file - readme = parse_from_file(readme_file) -except ImportError: - with open(readme_file) as f: - readme = f.read() +# read readme to markdown +readme_file = Path(__file__).parent / "README.md" +readme = readme_file.read_text() -install_requires=['numpy', 'scipy', 'pyyaml', 'dargs'] -setup_requires=['setuptools_scm', 'scikit-build'] +tf_version = os.environ.get("TENSORFLOW_VERSION", "2.3") -tf_version = os.environ.get('TENSORFLOW_VERSION', '2.3') -if LegacyVersion(tf_version) < LegacyVersion("1.15") or (LegacyVersion(tf_version) >= LegacyVersion("2.0") and LegacyVersion(tf_version) < LegacyVersion("2.1")): - extras_require = {"cpu": ["tensorflow==" + tf_version], "gpu": ["tensorflow-gpu==" + tf_version]} -else: - extras_require = {"cpu": ["tensorflow-cpu==" + tf_version], "gpu": ["tensorflow==" + tf_version]} -tf_spec = importlib.util.find_spec("tensorflow") -if tf_spec: - tf_install_dir = tf_spec.submodule_search_locations[0] +if tf_version in SpecifierSet("<1.15") or tf_version in SpecifierSet(">=2.0,<2.1"): + extras_require = { + "cpu": [f"tensorflow=={tf_version}"], + "gpu": [f"tensorflow-gpu=={tf_version}"], + } else: - site_packages_path = path.join(path.dirname(path.__file__), 'site-packages') - tf_spec = importlib.machinery.FileFinder(site_packages_path).find_spec("tensorflow") - if tf_spec: - tf_install_dir = tf_spec.submodule_search_locations[0] - else: - setup_requires.append("tensorflow==" + tf_version) - tf_install_dir = path.join(path.dirname(path.abspath(__file__)), '.egg', - pkg_resources.Distribution(project_name="tensorflow", version=tf_version, - platform=get_platform()).egg_name(), - 'tensorflow') + extras_require = { + "cpu": [f"tensorflow-cpu=={tf_version}"], + "gpu": [f"tensorflow=={tf_version}"], + } -# add cmake as a build requirement if cmake>3.7 is not installed +# get tensorflow spec +tf_spec = find_spec("tensorflow") +if not tf_spec: + # purelib gets site-packages path + site_packages = get_path("purelib") + if site_packages: + tf_spec = FileFinder(site_packages).find_spec("tensorflow") + +# get install dir from spec try: - if LegacyVersion(get_cmake_version()) < LegacyVersion("3.7"): - setup_requires.append('cmake') -except SKBuildError: - setup_requires.append('cmake') + tf_install_dir = tf_spec.submodule_search_locations[0] # type: ignore + # AttributeError if ft_spec is None + # TypeError if submodule_search_locations are None + # IndexError if submodule_search_locations is an empty list +except (AttributeError, TypeError, IndexError): + setup_requires.append(f"tensorflow=={tf_version}") + dist = Distribution( + project_name="tensorflow", version=tf_version, platform=get_platform() + ).egg_name() + tf_install_dir = Path(__file__).parent.joinpath(".egg", dist, "tensorflow") +# add cmake as a build requirement if cmake>3.7 is not installed try: - makedirs('deepmd') -except OSError: - pass + cmake_version = get_cmake_version() +except SKBuildError: + setup_requires.append("cmake") +else: + if cmake_version in SpecifierSet("<3.7"): + setup_requires.append("cmake") +Path("deepmd").mkdir(exist_ok=True) setup( name="deepmd-kit", - setup_requires=setup_requires, - use_scm_version={'write_to': 'deepmd/_version.py'}, + setup_requires=INSTALL_REQUIRES, + use_scm_version={"write_to": "deepmd/_version.py"}, author="Han Wang", author_email="wang_han@iapcm.ac.cn", description="A deep learning package for many-body potential energy representation and molecular dynamics", long_description=readme, long_description_content_type="text/markdown", url="https://github.com/deepmodeling/deepmd-kit", - packages=['deepmd', - 'deepmd/descriptor', - 'deepmd/fit', - 'deepmd/infer', - 'deepmd/loss', - 'deepmd/utils', + packages=[ + "deepmd", + "deepmd/descriptor", + "deepmd/fit", + "deepmd/infer", + "deepmd/loss", + "deepmd/utils", ], python_requires=">=3.6", classifiers=[ "Programming Language :: Python :: 3.6", "License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)", ], - keywords='deepmd', - install_requires=install_requires, - cmake_args=['-DTENSORFLOW_ROOT:STRING=%s' % tf_install_dir, - '-DBUILD_PY_IF:BOOL=TRUE', - '-DBUILD_CPP_IF:BOOL=FALSE', - '-DFLOAT_PREC:STRING=high', + keywords="deepmd", + install_requires=INSTALL_REQUIRES, + cmake_args=[ + f"-DTENSORFLOW_ROOT:STRING={os.fspath(tf_install_dir)}", + "-DBUILD_PY_IF:BOOL=TRUE", + "-DBUILD_CPP_IF:BOOL=FALSE", + "-DFLOAT_PREC:STRING=high", ], - cmake_source_dir='source', - cmake_minimum_required_version='3.0', + cmake_source_dir="source", + cmake_minimum_required_version="3.0", extras_require={ - 'test': ['dpdata>=0.1.9'], - 'docs': ['sphinx', 'recommonmark', 'sphinx_rtd_theme'], + "test": ["dpdata>=0.1.9"], + "docs": ["sphinx", "recommonmark", "sphinx_rtd_theme"], **extras_require, }, - entry_points={ - 'console_scripts': ['dp = deepmd.main:main'] - } + entry_points={"console_scripts": ["dp = deepmd.main:main"]}, ) diff --git a/source/tests/test_model_loc_frame.py b/source/tests/test_model_loc_frame.py index b91fc1a2c7..f18018c653 100644 --- a/source/tests/test_model_loc_frame.py +++ b/source/tests/test_model_loc_frame.py @@ -8,7 +8,7 @@ from deepmd.descriptor import DescrptLocFrame from deepmd.fit import EnerFitting from deepmd.Model import Model -from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader +from deepmd.common import j_must_have, j_loader global_ener_float_precision = tf.float64 global_tf_float_precision = tf.float64 diff --git a/source/tests/test_model_se_a.py b/source/tests/test_model_se_a.py index 59e17b97fa..968d5001f1 100644 --- a/source/tests/test_model_se_a.py +++ b/source/tests/test_model_se_a.py @@ -9,7 +9,7 @@ from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting from deepmd.Model import Model -from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader +from deepmd.common import j_must_have, j_loader global_ener_float_precision = tf.float64 global_tf_float_precision = tf.float64 diff --git a/source/tests/test_model_se_a_aparam.py b/source/tests/test_model_se_a_aparam.py index 3ba2b60500..725f3aea3e 100644 --- a/source/tests/test_model_se_a_aparam.py +++ b/source/tests/test_model_se_a_aparam.py @@ -8,7 +8,7 @@ from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting from deepmd.Model import Model -from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader +from deepmd.common import j_must_have, j_loader global_ener_float_precision = tf.float64 global_tf_float_precision = tf.float64 diff --git a/source/tests/test_model_se_a_fparam.py b/source/tests/test_model_se_a_fparam.py index 143f818d45..38d37291d0 100644 --- a/source/tests/test_model_se_a_fparam.py +++ b/source/tests/test_model_se_a_fparam.py @@ -8,7 +8,7 @@ from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting from deepmd.Model import Model -from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader +from deepmd.common import j_must_have, j_loader global_ener_float_precision = tf.float64 global_tf_float_precision = tf.float64 diff --git a/source/tests/test_model_se_a_srtab.py b/source/tests/test_model_se_a_srtab.py index fd2ff980e4..3f2649ae36 100644 --- a/source/tests/test_model_se_a_srtab.py +++ b/source/tests/test_model_se_a_srtab.py @@ -8,7 +8,7 @@ from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting from deepmd.Model import Model -from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader +from deepmd.common import j_must_have, j_loader global_ener_float_precision = tf.float64 global_tf_float_precision = tf.float64 diff --git a/source/tests/test_model_se_r.py b/source/tests/test_model_se_r.py index dbc3d79c93..978f27cc2e 100644 --- a/source/tests/test_model_se_r.py +++ b/source/tests/test_model_se_r.py @@ -8,7 +8,7 @@ from deepmd.descriptor import DescrptSeR from deepmd.fit import EnerFitting from deepmd.Model import Model -from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader +from deepmd.common import j_must_have, j_loader global_ener_float_precision = tf.float64 global_tf_float_precision = tf.float64 diff --git a/source/tests/test_polar_se_a.py b/source/tests/test_polar_se_a.py index bb6068449e..1178949c4f 100644 --- a/source/tests/test_polar_se_a.py +++ b/source/tests/test_polar_se_a.py @@ -8,7 +8,7 @@ from deepmd.descriptor import DescrptSeA from deepmd.fit import PolarFittingSeA from deepmd.Model import PolarModel -from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader +from deepmd.common import j_must_have, j_loader global_ener_float_precision = tf.float64 global_tf_float_precision = tf.float64 diff --git a/source/tests/test_wfc.py b/source/tests/test_wfc.py index 81b912ca58..70f9968409 100644 --- a/source/tests/test_wfc.py +++ b/source/tests/test_wfc.py @@ -8,7 +8,7 @@ from deepmd.descriptor import DescrptLocFrame from deepmd.fit import WFCFitting from deepmd.Model import WFCModel -from deepmd.common import j_must_have, j_must_have_d, j_have, j_loader +from deepmd.common import j_must_have, j_loader global_ener_float_precision = tf.float64 global_tf_float_precision = tf.float64 From 851d8661a06937f7042d6579241cd72bc918aa05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Wed, 3 Feb 2021 14:21:04 +0100 Subject: [PATCH 071/562] updates to common --- deepmd/common.py | 70 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 9 deletions(-) diff --git a/deepmd/common.py b/deepmd/common.py index 8ba59c1e9c..a507ec289c 100644 --- a/deepmd/common.py +++ b/deepmd/common.py @@ -161,9 +161,22 @@ def make_default_mesh( return default_mesh -# TODO not a good approach, every class uses this to parse arguments on its own, -# TODO json shoul be parsed once and the parsed result passed to all objects taht need it +# TODO not an ideal approach, every class uses this to parse arguments on its own, +# TODO json should be parsed once and the parsed result passed to all objects that need it class ClassArg: + """Class that take care of input json/yaml parsing. + + The rules for parsing are defined by the `add` method, than `parse` is called to + process the supplied dict + + Attributes + ---------- + arg_dict: Dict[str, Any] + dictionary containing parsing rules + alias_map: Dict[str, Any] + dictionary with keyword aliases + """ + def __init__(self): self.arg_dict = {} self.alias_map = {} @@ -175,7 +188,27 @@ def add( alias: Optional[Union[str, List[str]]] = None, default: Any = None, must: bool = False, - ): + ) -> "ClassArg": + """Add key to be parsed. + + Parameters + ---------- + key : str + key name + types_ : Union[type, List[type]] + list of allowed key types + alias : Optional[Union[str, List[str]]], optional + alias for the key, by default None + default : Any, optional + default value for the key, by default None + must : bool, optional + if the key is mandatory, by default False + + Returns + ------- + ClassArg + instance with added key + """ if not isinstance(types_, list): types = [types_] else: @@ -213,8 +246,8 @@ def _add_single(self, key: str, data: Any): break else: raise TypeError( - 'cannot convert provided key "%s" to type(s) %s ' - % (key, str(self.arg_dict[key]["types"])) + f'cannot convert provided key {key} to type(s) ' + f'{self.arg_dict[key]["types"]} ' ) else: vv = data @@ -223,9 +256,21 @@ def _add_single(self, key: str, data: Any): def _check_must(self): for kk in self.arg_dict: if self.arg_dict[kk]["must"] and self.arg_dict[kk]["value"] is None: - raise RuntimeError('key "%s" must be provided' % kk) + raise RuntimeError(f'key {kk} must be provided') def parse(self, jdata: Dict[str, Any]) -> Dict[str, Any]: + """Parse input dictionary, use the rules defined by add method. + + Parameters + ---------- + jdata : Dict[str, Any] + loaded json/yaml data + + Returns + ------- + Dict[str, Any] + parsed dictionary + """ for kk in jdata.keys(): if kk in self.arg_dict: key = kk @@ -238,15 +283,22 @@ def parse(self, jdata: Dict[str, Any]) -> Dict[str, Any]: return self.get_dict() def get_dict(self) -> Dict[str, Any]: + """Get dictionary built from rules defined by add method. + + Returns + ------- + Dict[str, Any] + settings dictionary with default values + """ ret = {} for kk in self.arg_dict.keys(): ret[kk] = self.arg_dict[kk]["value"] return ret -# TODO maybe rename this to j_deprecated and only warn about deprecated keys, otherwise -# TODO its puppose is only custom error since dict[key] already raises KeyError when the -# TODO key is missing +# TODO maybe rename this to j_deprecated and only warn about deprecated keys, +# TODO if the deprecated_key argument is left empty function puppose is only custom +# TODO error since dict[key] already raises KeyError when the key is missing def j_must_have( jdata: Dict[str, "_DICT_VAL"], key: str, deprecated_key: List[str] = [] ) -> "_DICT_VAL": From 43d6dcc47b767dfb29b3ed8e5baf4d3f2e7c26b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Wed, 3 Feb 2021 16:22:37 +0100 Subject: [PATCH 072/562] rewrite config script --- source/scripts/config.py | 402 ++++++++++++++++++++++++++++----------- 1 file changed, 288 insertions(+), 114 deletions(-) diff --git a/source/scripts/config.py b/source/scripts/config.py index 5d3d804b26..ef956271bc 100644 --- a/source/scripts/config.py +++ b/source/scripts/config.py @@ -1,191 +1,365 @@ #!/usr/bin/env python3 +"""Quickly create a configuration file for smooth model.""" + +import json +import yaml +from pathlib import Path +from typing import Any, Dict, List, Tuple, TYPE_CHECKING -import glob,os,json import numpy as np +if TYPE_CHECKING: + try: + from typing import Protocol # python >=3.8 + except ImportError: + from typing_extensions import Protocol + + class ArgsProto(Protocol): + """Prococol mimicking parser object.""" + + output: str + + +DEFAULT_DATA: Dict[str, Any] = { + "use_smooth": True, + "sel_a": [], + "rcut_smth": -1, + "rcut": -1, + "filter_neuron": [20, 40, 80], + "filter_resnet_dt": False, + "axis_neuron": 8, + "fitting_neuron": [240, 240, 240], + "fitting_resnet_dt": True, + "coord_norm": True, + "type_fitting_net": False, + "systems": [], + "set_prefix": "set", + "stop_batch": -1, + "batch_size": -1, + "start_lr": 0.001, + "decay_steps": -1, + "decay_rate": 0.95, + "start_pref_e": 0.02, + "limit_pref_e": 1, + "start_pref_f": 1000, + "limit_pref_f": 1, + "start_pref_v": 0, + "limit_pref_v": 0, + "seed": 1, + "disp_file": "lcurve.out", + "disp_freq": 1000, + "numb_test": 10, + "save_freq": 10000, + "save_ckpt": "model.ckpt", + "disp_training": True, + "time_training": True, +} + + +def valid_dir(path: Path): + """Check if directory is a valid deepmd system directory. + + Parameters + ---------- + path : Path + path to directory -def valid_dir(name) : - if not os.path.isfile(os.path.join(name, 'type.raw')) : + Raises + ------ + OSError + if `type.raw` is missing on dir or `box.npy` or `coord.npy` are missing in one + of the sets subdirs + """ + if not (path / "type.raw").is_file(): raise OSError - sets = glob.glob(os.path.join(name, 'set.*')) - for ii in sets : - if not os.path.isfile(os.path.join(ii, 'box.npy')) : + for ii in path.glob("set.*"): + if not (ii / "box.npy").is_file(): raise OSError - if not os.path.isfile(os.path.join(ii, 'coord.npy')) : + if not (ii / "coord.npy").is_file(): raise OSError - -def load_systems(dirs) : + +def load_systems( + dirs: List[Path], +) -> Tuple[List[np.ndarray[int]], List[np.ndarray[float]]]: + """Load systems to memory for disk. + + Parameters + ---------- + dirs : List[Path] + list of system directories paths + + Returns + ------- + Tuple[List[np.ndarray[int]], List[np.ndarray[float]]] + atoms types and structure cells formated as Nx9 array + """ all_type = [] all_box = [] - for ii in dirs : - sys_type = np.loadtxt(os.path.join(ii, 'type.raw'), dtype = int) - sys_box = None - sets = glob.glob(os.path.join(ii, 'set.*')) - for ii in sets : - if type(sys_box) is not np.ndarray : - sys_box = np.load(os.path.join(ii, 'box.npy')) - else : - sys_box = np.concatenate((sys_box, np.load(os.path.join(ii, 'box.npy'))), axis = 0) + for d in dirs: + sys_type = np.loadtxt(d / "type.raw", dtype=int) + sys_box = np.vstack([np.load(s / "box.npy") for s in d.glob("set.*")]) all_type.append(sys_type) all_box.append(sys_box) return all_type, all_box -def get_system_names() : - dirs = input("Enter system path(s) (seperated by space, wide card supported): \n") - dirs = dirs.split() - real_dirs = [] - for ii in dirs : - real_dirs += glob.glob(ii) - for ii in real_dirs : - valid_dir(ii) - return real_dirs +def get_system_names() -> List[Path]: + """Get system directory paths from stdin. + + Returns + ------- + List[Path] + list of system directories paths + """ + dirs = input("Enter system path(s) (seperated by space, wild card supported): \n") + system_dirs = [] + for dir_str in dirs.split(): + found_dirs = Path.cwd().glob(dir_str) + for d in found_dirs: + valid_dir(d) + system_dirs.append(d) + + return system_dirs + + +def get_rcut() -> float: + """Get rcut from stdin from user. + + Returns + ------- + float + input rcut lenght converted to float -def get_rcut() : + Raises + ------ + ValueError + if rcut is smaller than 0.0 + """ dv = 6 - rcut = input("Enter rcut (default %f A): \n" % dv) + rcut_input = input(f"Enter rcut (default {dv:.1f} A): \n") try: - rcut = float(rcut) - except ValueError: + rcut = float(rcut_input) + except ValueError as e: + print(f"invalid rcut: {e} setting to default: {dv:.1f}") rcut = dv if rcut <= 0: - raise ValueError('rcut should be > 0') + raise ValueError("rcut should be > 0") return rcut -def get_batch_size_rule() : +def get_batch_size_rule() -> int: + """Get minimal batch size from user from stdin. + + Returns + ------- + int + size of the batch + + Raises + ------ + ValueError + if batch size is <= 0 + """ dv = 32 - matom = input("Enter the minimal number of atoms in a batch (default %d): \n" % dv) + matom_input = input( + f"Enter the minimal number of atoms in a batch (default {dv:d}: \n" + ) try: - matom = int(matom) - except ValueError: + matom = int(matom_input) + except ValueError as e: + print(f"invalid batch size: {e} setting to default: {dv:d}") matom = dv if matom <= 0: - raise ValueError('the number should be > 0') + raise ValueError("the number should be > 0") return matom -def get_stop_batch(): +def get_stop_batch() -> int: + """Get stop batch from user from stdin. + + Returns + ------- + int + size of the batch + + Raises + ------ + ValueError + if stop batch is <= 0 + """ dv = 1000000 - sb = input("Enter the stop batch (default %d): \n" % dv) + sb_input = input(f"Enter the stop batch (default {dv:d}): \n") try: - sb = int(sb) - except ValueError: + sb = int(sb_input) + except ValueError as e: + print(f"invalid stop batch: {e} setting to default: {dv:d}") sb = dv if sb <= 0: - raise ValueError('the number should be > 0') + raise ValueError("the number should be > 0") return sb -def get_ntypes (all_type) : - coll = [] - for ii in all_type: - coll += list(ii) - list_coll = set(coll) - return len(list_coll) +def get_ntypes(all_type: List[np.ndarray[int]]) -> int: + """Count number of unique elements. + + Parameters + ---------- + all_type : List[np.ndarray[int]] + list with arrays specifying elements of structures + + Returns + ------- + int + number of unique elements + """ + return len(np.unique(all_type)) + + +def get_max_density( + all_type: List[np.ndarray[int]], all_box: List[np.ndarray[float]] +) -> np.ndarray[float]: + """Compute maximum density in suppliedd cells. + Parameters + ---------- + all_type : List[np.ndarray[int]] + list with arrays specifying elements of structures + all_box : List[np.ndarray[float]] + list with arrays specifying cells for all structures -def get_max_density(all_type, all_box) : + Returns + ------- + float + maximum atom density in all supplies structures for each element individually + """ ntypes = get_ntypes(all_type) all_max = [] - for tt, bb in zip(all_type, all_box) : - vv = np.reshape(bb, [-1,3,3]) + for tt, bb in zip(all_type, all_box): + vv = np.reshape(bb, [-1, 3, 3]) vv = np.linalg.det(vv) min_v = np.min(vv) type_count = [] - for ii in range(ntypes) : + for ii in range(ntypes): type_count.append(sum(tt == ii)) max_den = type_count / min_v all_max.append(max_den) - all_max = np.max(all_max, axis = 0) + all_max = np.max(all_max, axis=0) return all_max +def suggest_sel( + all_type: List[np.ndarray[int]], + all_box: List[np.ndarray[float]], + rcut: float, + ratio: float = 1.5, +) -> List[int]: + """Suggest selection parameter. + Parameters + ---------- + all_type : List[np.ndarray[int]] + list with arrays specifying elements of structures + all_box : List[np.ndarray[float]] + list with arrays specifying cells for all structures + rcut : float + cutoff radius + ratio : float, optional + safety margin to add to estimated value, by default 1.5 -def suggest_sel(all_type, all_box, rcut, ratio = 1.5) : + Returns + ------- + List[int] + [description] + """ max_den = get_max_density(all_type, all_box) - return [int(ii) for ii in max_den * 4./3. * np.pi * rcut**3 * ratio] + return [int(ii) for ii in max_den * 4.0 / 3.0 * np.pi * rcut ** 3 * ratio] -def suggest_batch_size(all_type, min_atom) : +def suggest_batch_size(all_type: List[np.ndarray[int]], min_atom: int) -> List[int]: + """Get suggestion for batch size. + + Parameters + ---------- + all_type : List[np.ndarray[int]] + list with arrays specifying elements of structures + min_atom : int + minimal number of atoms in batch + + Returns + ------- + List[int] + suggested batch sizes for each system + """ bs = [] - for ii in all_type : + for ii in all_type: natoms = len(ii) tbs = min_atom // natoms - if (min_atom // natoms) * natoms != min_atom : + if (min_atom // natoms) * natoms != min_atom: tbs += 1 bs.append(tbs) return bs -def suggest_decay(sb): - decay_steps = int(sb // 200) +def suggest_decay(stop_batch: int) -> Tuple[int, float]: + """Suggest number of decay steps and decay rate. + + Parameters + ---------- + stop_batch : int + stop batch number + + Returns + ------- + Tuple[int, float] + number of decay steps and decay rate + """ + decay_steps = int(stop_batch // 200) decay_rate = 0.95 return decay_steps, decay_rate -def default_data() : - data = {} - data['use_smooth'] = True - data['sel_a'] = [] - data['rcut_smth'] = -1 - data['rcut'] = -1 - data['filter_neuron'] = [20, 40, 80] - data['filter_resnet_dt'] = False - data['axis_neuron'] = 8 - data['fitting_neuron'] = [240, 240, 240] - data['fitting_resnet_dt'] = True - data['coord_norm'] = True - data['type_fitting_net'] = False - data['systems'] = [] - data['set_prefix'] = 'set' - data['stop_batch'] = -1 - data['batch_size'] = -1 - data['start_lr'] = 0.001 - data['decay_steps'] = -1 - data['decay_rate'] = 0.95 - data['start_pref_e'] = 0.02 - data['limit_pref_e'] = 1 - data['start_pref_f'] = 1000 - data['limit_pref_f'] = 1 - data['start_pref_v'] = 0 - data['limit_pref_v'] = 0 - data['seed'] = 1 - data['disp_file'] = 'lcurve.out' - data['disp_freq'] = 1000 - data['numb_test'] = 10 - data['save_freq'] = 10000 - data["save_ckpt"] = "model.ckpt" - data["disp_training"] = True - data["time_training"] = True - return data - - -def config(args) : +def config(args: "ArgsProto"): + """Auto config file generator. + + Parameters + ---------- + args : ArgsProto + argparse:parser instance with output attribute + + Raises + ------ + RuntimeError + if user does not input any systems + ValueError + if output file is of wrong type + """ all_sys = get_system_names() - if len(all_sys) == 0 : - raise RuntimeError('no system specified') + if len(all_sys) == 0: + raise RuntimeError("no system specified") rcut = get_rcut() matom = get_batch_size_rule() stop_batch = get_stop_batch() all_type, all_box = load_systems(all_sys) - sel = suggest_sel(all_type, all_box, rcut, ratio = 1.5) + sel = suggest_sel(all_type, all_box, rcut, ratio=1.5) bs = suggest_batch_size(all_type, matom) decay_steps, decay_rate = suggest_decay(stop_batch) - - jdata = default_data() - jdata['systems'] = all_sys - jdata['sel_a'] = sel - jdata['rcut'] = rcut - jdata['rcut_smth'] = rcut - 0.2 - jdata['stop_batch'] = stop_batch - jdata['batch_size'] = bs - jdata['decay_steps'] = decay_steps - jdata['decay_rate'] = decay_rate - - with open(args.output, 'w') as fp: - json.dump(jdata, fp, indent=4) + jdata = DEFAULT_DATA.copy() + jdata["systems"] = all_sys + jdata["sel_a"] = sel + jdata["rcut"] = rcut + jdata["rcut_smth"] = rcut - 0.2 + jdata["stop_batch"] = stop_batch + jdata["batch_size"] = bs + jdata["decay_steps"] = decay_steps + jdata["decay_rate"] = decay_rate + + with open(args.output, "w") as fp: + if args.output.endswith("json"): + json.dump(jdata, fp, indent=4) + elif args.output.endswith(("yml", "yaml")): + yaml.safe_dump(jdata, fp, default_flow_style=False) + else: + raise ValueError("output file must be of type json or yaml") From 565de53e09dd5cf5db5ff36f593ad515890bd3d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Wed, 3 Feb 2021 16:29:34 +0100 Subject: [PATCH 073/562] small fixes --- deepmd/common.py | 30 ++++++++++++++++++++++-------- deepmd/utils/compat.py | 22 +++++++++++++++++++--- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/deepmd/common.py b/deepmd/common.py index a507ec289c..529da5dae5 100644 --- a/deepmd/common.py +++ b/deepmd/common.py @@ -1,9 +1,20 @@ +"""Collection of functions and classes used throughout the whole package.""" + import json import warnings from functools import wraps from pathlib import Path -from typing import (TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, - TypeVar, Union) +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Dict, + List, + Optional, + Tuple, + TypeVar, + Union, +) import numpy as np import yaml @@ -15,7 +26,7 @@ _DICT_VAL = TypeVar("_DICT_VAL") _OBJ = TypeVar("_OBJ") try: - from typing import Literal # python 3.6 + from typing import Literal # python >3.6 except ImportError: from typing_extensions import Literal _ACTIVATION = Literal["relu", "relu6", "softplus", "sigmoid", "tanh", "gelu"] @@ -161,8 +172,8 @@ def make_default_mesh( return default_mesh -# TODO not an ideal approach, every class uses this to parse arguments on its own, -# TODO json should be parsed once and the parsed result passed to all objects that need it +# TODO not an ideal approach, every class uses this to parse arguments on its own, json +# TODO should be parsed once and the parsed result passed to all objects that need it class ClassArg: """Class that take care of input json/yaml parsing. @@ -246,7 +257,7 @@ def _add_single(self, key: str, data: Any): break else: raise TypeError( - f'cannot convert provided key {key} to type(s) ' + f"cannot convert provided key {key} to type(s) " f'{self.arg_dict[key]["types"]} ' ) else: @@ -256,7 +267,7 @@ def _add_single(self, key: str, data: Any): def _check_must(self): for kk in self.arg_dict: if self.arg_dict[kk]["must"] and self.arg_dict[kk]["value"] is None: - raise RuntimeError(f'key {kk} must be provided') + raise RuntimeError(f"key {kk} must be provided") def parse(self, jdata: Dict[str, Any]) -> Dict[str, Any]: """Parse input dictionary, use the rules defined by add method. @@ -354,7 +365,9 @@ def j_loader(filename: Union[str, Path]) -> Dict[str, Any]: raise TypeError("config file must be json, or yaml/yml") -def get_activation_func(activation_fn: "_ACTIVATION") -> Callable[[tf.Tensor], tf.Tensor]: +def get_activation_func( + activation_fn: "_ACTIVATION", +) -> Callable[[tf.Tensor], tf.Tensor]: """Get activation function callable based on string name. Parameters @@ -430,6 +443,7 @@ def docstring_parameter(*sub: Tuple[str, ...]): ---- Can be used on both object and classes. """ + @wraps def dec(obj: "_OBJ") -> "_OBJ": if obj.__doc__ is not None: diff --git a/deepmd/utils/compat.py b/deepmd/utils/compat.py index 9962e96f12..794c8c14aa 100644 --- a/deepmd/utils/compat.py +++ b/deepmd/utils/compat.py @@ -10,7 +10,23 @@ def convert_input_v0_v1( jdata: Dict[str, Any], warning: bool = True, dump: Optional[Union[str, Path]] = None -): +) -> Dict[str, Any]: + """Convert input from v0 format to v1. + + Parameters + ---------- + jdata : Dict[str, Any] + loaded json/yaml file + warning : bool, optional + whether to show deprecation warning, by default True + dump : Optional[Union[str, Path]], optional + whether to dump converted file, by default None + + Returns + ------- + Dict[str, Any] + converted output + """ output = {} if "with_distrib" in jdata: output["with_distrib"] = jdata["with_distrib"] @@ -167,7 +183,7 @@ def _loss(jdata: Dict[str, Any]) -> Dict[str, Any]: Dict[str, Any] dict with loss function parameters """ - loss = {} + loss: Dict[str, Any] = {} _jcopy( jdata, loss, @@ -222,7 +238,7 @@ def _training(jdata: Dict[str, Any]) -> Dict[str, Any]: return training -def _jcopy(src: Dict[str, Any], dst: Dict[str, Any], keys: Sequence[str], must_have: bool): +def _jcopy(src: Dict[str, Any], dst: Dict[str, Any], keys: Sequence[str]): """Copy specified keys from one dict to another. Parameters From 8bd83799d7ad6b28400fa90000cd191b28c55a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Wed, 3 Feb 2021 17:09:51 +0100 Subject: [PATCH 074/562] frezer script rewrite --- source/scripts/freeze.py | 206 +++++++++++++++++++++++++++++++-------- 1 file changed, 167 insertions(+), 39 deletions(-) diff --git a/source/scripts/freeze.py b/source/scripts/freeze.py index 2e6b211bc8..7e4593bb2d 100755 --- a/source/scripts/freeze.py +++ b/source/scripts/freeze.py @@ -1,10 +1,14 @@ #!/usr/bin/env python3 +"""This script freezes TF trained graph so it can be used with LAMMPS ain i-PI. -# freeze.py : -# see https://blog.metaflow.fr/tensorflow-how-to-freeze-a-model-and-serve-it-with-a-python-api-d4f3596b3adc +References +---------- +https://blog.metaflow.fr/tensorflow-how-to-freeze-a-model-and-serve-it-with-a-python-api-d4f3596b3adc +""" from deepmd.env import tf from deepmd.env import op_module +from os.path import abspath # load grad of force module import deepmd._prod_force_grad @@ -16,44 +20,158 @@ import deepmd._soft_min_force_grad import deepmd._soft_min_virial_grad -def _make_node_names(model_type, modifier_type = None) : - if model_type == 'ener': - nodes = "o_energy,o_force,o_virial,o_atom_energy,o_atom_virial,descrpt_attr/rcut,descrpt_attr/ntypes,fitting_attr/dfparam,fitting_attr/daparam,model_attr/tmap,model_attr/model_type" - elif model_type == 'wfc': - nodes = "o_wfc,descrpt_attr/rcut,descrpt_attr/ntypes,model_attr/tmap,model_attr/sel_type,model_attr/model_type" - elif model_type == 'dipole': - nodes = "o_dipole,o_rmat,o_rmat_deriv,o_nlist,o_rij,descrpt_attr/rcut,descrpt_attr/ntypes,descrpt_attr/sel,descrpt_attr/ndescrpt,model_attr/tmap,model_attr/sel_type,model_attr/model_type,model_attr/output_dim" - elif model_type == 'polar': - nodes = "o_polar,descrpt_attr/rcut,descrpt_attr/ntypes,model_attr/tmap,model_attr/sel_type,model_attr/model_type" - elif model_type == 'global_polar': - nodes = "o_global_polar,descrpt_attr/rcut,descrpt_attr/ntypes,model_attr/tmap,model_attr/sel_type,model_attr/model_type" +from typing import List, Optional, TYPE_CHECKING + + +if TYPE_CHECKING: + try: + from typing import Protocol # python >=3.8 + except ImportError: + from typing_extensions import Protocol + + class ArgsProto(Protocol): + """Prococol mimicking parser object.""" + + folder: str + output: str + nodes: str + + +def _make_node_names(model_type: str, modifier_type: Optional[str] = None) -> List[str]: + """Get node names based on model type. + + Parameters + ---------- + model_type : str + str type of model + modifier_type : Optional[str], optional + modifier type if any, by default None + + Returns + ------- + List[str] + list with all node names to freeze + + Raises + ------ + RuntimeError + if unknown model type + """ + if model_type == "ener": + nodes = [ + "o_energy", + "o_force", + "o_virial", + "o_atom_energy", + "o_atom_virial", + "descrpt_attr/rcut", + "descrpt_attr/ntypes", + "fitting_attr/dfparam", + "fitting_attr/daparam", + "model_attr/tmap", + "model_attr/model_type", + ] + elif model_type == "wfc": + nodes = [ + "o_wfc", + "descrpt_attr/rcut", + "descrpt_attr/ntypes", + "model_attr/tmap", + "model_attr/sel_type", + "model_attr/model_type", + ] + elif model_type == "dipole": + nodes = [ + "o_dipole", + "o_rmat", + "o_rmat_deriv", + "o_nlist", + "o_rij", + "descrpt_attr/rcut", + "descrpt_attr/ntypes", + "descrpt_attr/sel", + "descrpt_attr/ndescrpt", + "model_attr/tmap", + "model_attr/sel_type", + "model_attr/model_type", + "model_attr/output_dim", + ] + elif model_type == "polar": + nodes = [ + "o_polar", + "descrpt_attr/rcut", + "descrpt_attr/ntypes", + "model_attr/tmap", + "model_attr/sel_type", + "model_attr/model_type", + ] + elif model_type == "global_polar": + nodes = [ + "o_global_polar", + "descrpt_attr/rcut", + "descrpt_attr/ntypes", + "model_attr/tmap", + "model_attr/sel_type", + "model_attr/model_type", + ] else: - raise RuntimeError('unknow model type ' + model_type) - if modifier_type == 'dipole_charge': - nodes += ",modifier_attr/type,modifier_attr/mdl_name,modifier_attr/mdl_charge_map,modifier_attr/sys_charge_map,modifier_attr/ewald_h,modifier_attr/ewald_beta,dipole_charge/descrpt_attr/rcut,dipole_charge/descrpt_attr/ntypes,dipole_charge/model_attr/tmap,dipole_charge/model_attr/model_type,o_dm_force,dipole_charge/model_attr/sel_type,dipole_charge/o_dipole,dipole_charge/model_attr/output_dim,o_dm_virial,o_dm_av" + raise RuntimeError("unknow model type " + model_type) + if modifier_type == "dipole_charge": + nodes += [ + "modifier_attr/type", + "modifier_attr/mdl_name", + "modifier_attr/mdl_charge_map", + "modifier_attr/sys_charge_map", + "modifier_attr/ewald_h", + "modifier_attr/ewald_beta", + "dipole_charge/descrpt_attr/rcut", + "dipole_charge/descrpt_attr/ntypes", + "dipole_charge/model_attr/tmap", + "dipole_charge/model_attr/model_type", + "o_dm_force", + "dipole_charge/model_attr/sel_type", + "dipole_charge/o_dipole", + "dipole_charge/model_attr/output_dim", + "o_dm_virial", + "o_dm_av", + ] return nodes -def freeze_graph(model_folder, - output, - output_node_names = None): + +def freeze_graph( + model_folder: str, output: str, output_node_names: Optional[str] = None +): + """Freeze the graph in supplied folder. + + Parameters + ---------- + model_folder : str + location of the folder with model + output : str + output file name + output_node_names : Optional[str], optional + names of nodes to output, by default None + """ # We retrieve our checkpoint fullpath checkpoint = tf.train.get_checkpoint_state(model_folder) input_checkpoint = checkpoint.model_checkpoint_path - - # We precise the file fullname of our freezed graph - absolute_model_folder = "/".join(input_checkpoint.split('/')[:-1]) - output_graph = absolute_model_folder + "/" + output + + # expand the output file to full path + output_graph = abspath(output) # Before exporting our graph, we need to precise what is our output node # This is how TF decides what part of the Graph he has to keep and what part it can dump # NOTE: this variable is plural, because you can have multiple output nodes # output_node_names = "energy_test,force_test,virial_test,t_rcut" - # We clear devices to allow TensorFlow to control on which device it will load operations + # We clear devices to allow TensorFlow to control + # on which device it will load operations clear_devices = True - + # We import the meta graph and retrieve a Saver - saver = tf.train.import_meta_graph(input_checkpoint + '.meta', clear_devices=clear_devices) + saver = tf.train.import_meta_graph( + f"{input_checkpoint}.meta", clear_devices=clear_devices + ) # We retrieve the protobuf graph definition graph = tf.get_default_graph() @@ -63,28 +181,38 @@ def freeze_graph(model_folder, # We start a session and restore the graph weights with tf.Session() as sess: saver.restore(sess, input_checkpoint) - model_type = sess.run('model_attr/model_type:0', feed_dict = {}).decode('utf-8') - if 'modifier_attr/type' in nodes: - modifier_type = sess.run('modifier_attr/type:0', feed_dict = {}).decode('utf-8') + model_type = sess.run("model_attr/model_type:0", feed_dict={}).decode("utf-8") + if "modifier_attr/type" in nodes: + modifier_type = sess.run("modifier_attr/type:0", feed_dict={}).decode( + "utf-8" + ) else: modifier_type = None - if output_node_names is None : - output_node_names = _make_node_names(model_type, modifier_type) - print('The following nodes will be frozen: %s' % output_node_names) + if output_node_names is None: + output_node_list = _make_node_names(model_type, modifier_type) + else: + output_node_list = output_node_names.split(",") + print(f"The following nodes will be frozen: {output_node_list}") # We use a built-in TF helper to export variables to constants output_graph_def = tf.graph_util.convert_variables_to_constants( - sess, # The session is used to retrieve the weights - input_graph_def, # The graph_def is used to retrieve the nodes - output_node_names.split(",") # The output node names are used to select the usefull nodes - ) + sess, # The session is used to retrieve the weights + input_graph_def, # The graph_def is used to retrieve the nodes + output_node_list, # The output node names are used to select the usefull nodes + ) # Finally we serialize and dump the output graph to the filesystem with tf.gfile.GFile(output_graph, "wb") as f: f.write(output_graph_def.SerializeToString()) - print("%d ops in the final graph." % len(output_graph_def.node)) + print(f"{len(output_graph_def.node):d} ops in the final graph.") -def freeze (args): - freeze_graph(args.folder, args.output, args.nodes) +def freeze(args: "ArgsProto"): + """Graph freeze script entry point. + Parameters + ---------- + args : ArgsProto + parser instance + """ + freeze_graph(args.folder, args.output, args.nodes) From 57e1117c677824123f3ba791367e9fbc5e0f670d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Wed, 3 Feb 2021 17:40:04 +0100 Subject: [PATCH 075/562] enhancements to calculator --- deepmd/common.py | 2 +- source/train/calculator.py | 128 +++++++++++++++++++++++++------------ 2 files changed, 89 insertions(+), 41 deletions(-) diff --git a/deepmd/common.py b/deepmd/common.py index 529da5dae5..2fcf4a3bed 100644 --- a/deepmd/common.py +++ b/deepmd/common.py @@ -188,7 +188,7 @@ class ClassArg: dictionary with keyword aliases """ - def __init__(self): + def __init__(self) -> None: self.arg_dict = {} self.alias_map = {} diff --git a/source/train/calculator.py b/source/train/calculator.py index de439c3f78..a99fc0086f 100644 --- a/source/train/calculator.py +++ b/source/train/calculator.py @@ -1,55 +1,103 @@ -"""An ASE calculator interface. - -Example: -```python -from ase import Atoms -from deepmd.calculator import DP - -water = Atoms('H2O', - positions=[(0.7601, 1.9270, 1), - (1.9575, 1, 1), - (1., 1., 1.)], - cell=[100, 100, 100], - calculator=DP(model="frozen_model.pb")) -print(water.get_potential_energy()) -print(water.get_forces()) -``` - -Optimization is also available: -```python -from ase.optimize import BFGS -dyn = BFGS(water) -dyn.run(fmax=1e-6) -print(water.get_positions()) -``` -""" +"""ASE calculator interface module.""" + +from os import fspath +from typing import TYPE_CHECKING, Dict, List, Optional, Union -from ase.calculators.calculator import Calculator, all_changes import deepmd.DeepPot as DeepPot +from ase.calculators.calculator import Calculator, all_changes + +if TYPE_CHECKING: + from pathlib import Path + + from ase import Atoms class DP(Calculator): + """Implementation of ASE deepmd calculator. + + Implemented propertie are `energy`, `forces` and `stress` + + Parameters + ---------- + model : Union[str, Path] + path to the model + label : str, optional + calculator label, by default "DP" + type_dict : Dict[str, int], optional + mapping of element types and their numbers, best left None and the calculator + will infer this information from model, by default None + + Examples + -------- + Compute potential energy + + >>> from ase import Atoms + >>> from deepmd.calculator import DP + >>> water = Atoms('H2O', + >>> positions=[(0.7601, 1.9270, 1), + >>> (1.9575, 1, 1), + >>> (1., 1., 1.)], + >>> cell=[100, 100, 100], + >>> calculator=DP(model="frozen_model.pb")) + >>> print(water.get_potential_energy()) + >>> print(water.get_forces()) + + Run BFGS structure optimization + + >>> from ase.optimize import BFGS + >>> dyn = BFGS(water) + >>> dyn.run(fmax=1e-6) + >>> print(water.get_positions()) + """ + name = "DP" implemented_properties = ["energy", "forces", "stress"] - def __init__(self, model, label="DP", type_dict=None, **kwargs): + def __init__( + self, + model: Union[str, "Path"], + label: str = "DP", + type_dict: Dict[str, int] = None, + **kwargs + ) -> None: Calculator.__init__(self, label=label, **kwargs) - self.dp = DeepPot(model) + self.dp = DeepPot(fspath(model)) if type_dict: - self.type_dict=type_dict + self.type_dict = type_dict else: - self.type_dict = dict(zip(self.dp.get_type_map(), range(self.dp.get_ntypes()))) + self.type_dict = dict( + zip(self.dp.get_type_map(), range(self.dp.get_ntypes())) + ) - def calculate(self, atoms=None, properties=["energy", "forces", "stress"], system_changes=all_changes): - coord = atoms.get_positions().reshape([1, -1]) - if sum(atoms.get_pbc())>0: - cell = atoms.get_cell().reshape([1, -1]) + def calculate( + self, + atoms: Optional["Atoms"] = None, + properties: List[str] = ["energy", "forces", "stress"], + system_changes: List[str] = all_changes, + ): + """Run calculation with deepmd model. + + Parameters + ---------- + atoms : Optional[Atoms], optional + atoms object to run the calculation on, by default None + properties : List[str], optional + unused, only for function signature compatibility, + by default ["energy", "forces", "stress"] + system_changes : List[str], optional + unused, only for function signature compatibility, by default all_changes + """ + if atoms is not None: + self.atoms = atoms.copy() + + coord = self.atoms.get_positions().reshape([1, -1]) + if sum(self.atoms.get_pbc()) > 0: + cell = self.atoms.get_cell().reshape([1, -1]) else: - cell = None - symbols = atoms.get_chemical_symbols() + cell = None + symbols = self.atoms.get_chemical_symbols() atype = [self.type_dict[k] for k in symbols] e, f, v = self.dp.eval(coords=coord, cells=cell, atom_types=atype) - self.results['energy'] = e[0] - self.results['forces'] = f[0] - self.results['stress'] = v[0] - + self.results["energy"] = e[0] + self.results["forces"] = f[0] + self.results["stress"] = v[0] From d1d15389ad6b21934b363047af48a595f7f45d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Wed, 3 Feb 2021 18:35:05 +0100 Subject: [PATCH 076/562] debug git action cmake build --- deepmd/env.py | 4 ++-- setup.py | 4 ++-- source/train/calculator.py | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/deepmd/env.py b/deepmd/env.py index f7290d5887..b76016e44d 100644 --- a/deepmd/env.py +++ b/deepmd/env.py @@ -122,12 +122,12 @@ def get_module(module_name: str) -> "ModuleType": else: ext = ".so" - module_file = (Path(__file__).parent / module_name).with_suffix(ext) + module_file = (Path(__file__).parent / module_name).with_suffix(ext).resolve() if not module_file.is_file(): raise FileNotFoundError(f"module {module_name} does not exist") else: - module = tf.load_op_library(os.fspath(module_file)) + module = tf.load_op_library(str(module_file)) return module diff --git a/setup.py b/setup.py index bb41ed3a67..d622ae4458 100644 --- a/setup.py +++ b/setup.py @@ -53,7 +53,7 @@ dist = Distribution( project_name="tensorflow", version=tf_version, platform=get_platform() ).egg_name() - tf_install_dir = Path(__file__).parent.joinpath(".egg", dist, "tensorflow") + tf_install_dir = Path(__file__).parent.joinpath(".egg", dist, "tensorflow").resolve() # add cmake as a build requirement if cmake>3.7 is not installed try: @@ -92,7 +92,7 @@ keywords="deepmd", install_requires=INSTALL_REQUIRES, cmake_args=[ - f"-DTENSORFLOW_ROOT:STRING={os.fspath(tf_install_dir)}", + f"-DTENSORFLOW_ROOT:STRING={str(tf_install_dir)}", "-DBUILD_PY_IF:BOOL=TRUE", "-DBUILD_CPP_IF:BOOL=FALSE", "-DFLOAT_PREC:STRING=high", diff --git a/source/train/calculator.py b/source/train/calculator.py index a99fc0086f..d86de92183 100644 --- a/source/train/calculator.py +++ b/source/train/calculator.py @@ -1,6 +1,5 @@ """ASE calculator interface module.""" -from os import fspath from typing import TYPE_CHECKING, Dict, List, Optional, Union import deepmd.DeepPot as DeepPot @@ -61,7 +60,7 @@ def __init__( **kwargs ) -> None: Calculator.__init__(self, label=label, **kwargs) - self.dp = DeepPot(fspath(model)) + self.dp = DeepPot(str(Path(model).resolve())) if type_dict: self.type_dict = type_dict else: From 232c2a3cb919a0354db848ed01190b945bb18d38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Wed, 3 Feb 2021 18:54:47 +0100 Subject: [PATCH 077/562] install tf in git actions since it is not found --- .github/workflows/test_python.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index c52e3921d3..aad0379bc7 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -59,5 +59,6 @@ jobs: - run: | sudo apt update sudo apt install gcc-${{ matrix.gcc }} g++-${{ matrix.gcc }} + - run: pip install tensorflow - run: pip install .[cpu,test] - run: cd source/tests && python -m unittest From d9712b305075061f2e158d614a4d06455e41bf33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Wed, 3 Feb 2021 20:38:13 +0100 Subject: [PATCH 078/562] fix failing tests --- deepmd/common.py | 20 ++++++++++---------- deepmd/utils/compat.py | 3 ++- setup.py | 4 ++-- source/scripts/config.py | 28 ++++++++++++++-------------- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/deepmd/common.py b/deepmd/common.py index 2fcf4a3bed..830f92e981 100644 --- a/deepmd/common.py +++ b/deepmd/common.py @@ -118,20 +118,20 @@ def add_data_requirement( def select_idx_map( - atom_types: np.ndarray[int], select_types: np.ndarray[int] -) -> np.ndarray[int]: + atom_types: np.ndarray, select_types: np.ndarray +) -> np.ndarray: """Build map of indices for element supplied element types from all atoms list. Parameters ---------- - atom_types : np.ndarray[int] + atom_types : np.ndarray array specifing type for each atoms as integer - select_types : np.ndarray[int] + select_types : np.ndarray types of atoms you want to find indices for Returns ------- - np.ndarray[int] + np.ndarray indices of types of atoms defined by `select_types` in `atom_types` array Warnings @@ -147,20 +147,20 @@ def select_idx_map( # TODO not really sure if the docstring is right the purpose of this is a bit unclear def make_default_mesh( - test_box: np.ndarray[float], cell_size: float = 3.0 -) -> np.ndarray[int]: + test_box: np.ndarray, cell_size: float = 3.0 +) -> np.ndarray: """Get number of cells of size=`cell_size` fit into average box. Parameters ---------- - test_box : np.ndarray[float] + test_box : np.ndarray numpy array with cells of shape Nx9 cell_size : float, optional length of one cell, by default 3.0 Returns ------- - np.ndarray[float] + np.ndarray mesh for supplied boxes, how many cells fit in each direction """ cell_lengths = np.linalg.norm(test_box.reshape([-1, 3, 3]), axis=2) @@ -390,7 +390,7 @@ def get_activation_func( return ACTIVATION_FN_DICT[activation_fn] -def get_precision(precision: "_PRECISION") -> tf.python.framework.dtypes.DType: +def get_precision(precision: "_PRECISION") -> Any: """Convert str to TF DType constant. Parameters diff --git a/deepmd/utils/compat.py b/deepmd/utils/compat.py index 794c8c14aa..782f973f69 100644 --- a/deepmd/utils/compat.py +++ b/deepmd/utils/compat.py @@ -113,7 +113,8 @@ def _smth_descriptor(jdata: Dict[str, Any]) -> Dict[str, Any]: if seed is not None: descriptor["seed"] = seed descriptor["type"] = "se_a" - _jcopy(jdata, descriptor, ("sel_a", "rcut")) + descriptor["sel"] = jdata["sel_a"] + _jcopy(jdata, descriptor, ("rcut", )) descriptor["rcut_smth"] = jdata.get("rcut_smth", descriptor["rcut"]) descriptor["neuron"] = j_must_have(jdata, "filter_neuron") descriptor["axis_neuron"] = j_must_have(jdata, "axis_neuron", ["n_axis_neuron"]) diff --git a/setup.py b/setup.py index d622ae4458..278d56b79f 100644 --- a/setup.py +++ b/setup.py @@ -53,7 +53,7 @@ dist = Distribution( project_name="tensorflow", version=tf_version, platform=get_platform() ).egg_name() - tf_install_dir = Path(__file__).parent.joinpath(".egg", dist, "tensorflow").resolve() + tf_install_dir = Path(__file__).parent.resolve().joinpath(".egg", dist, "tensorflow").resolve() # add cmake as a build requirement if cmake>3.7 is not installed try: @@ -92,7 +92,7 @@ keywords="deepmd", install_requires=INSTALL_REQUIRES, cmake_args=[ - f"-DTENSORFLOW_ROOT:STRING={str(tf_install_dir)}", + f"-DTENSORFLOW_ROOT:STRING={tf_install_dir}", "-DBUILD_PY_IF:BOOL=TRUE", "-DBUILD_CPP_IF:BOOL=FALSE", "-DFLOAT_PREC:STRING=high", diff --git a/source/scripts/config.py b/source/scripts/config.py index ef956271bc..ea8de980d9 100644 --- a/source/scripts/config.py +++ b/source/scripts/config.py @@ -81,7 +81,7 @@ def valid_dir(path: Path): def load_systems( dirs: List[Path], -) -> Tuple[List[np.ndarray[int]], List[np.ndarray[float]]]: +) -> Tuple[List[np.ndarray], List[np.ndarray]]: """Load systems to memory for disk. Parameters @@ -91,7 +91,7 @@ def load_systems( Returns ------- - Tuple[List[np.ndarray[int]], List[np.ndarray[float]]] + Tuple[List[np.ndarray], List[np.ndarray]] atoms types and structure cells formated as Nx9 array """ all_type = [] @@ -200,12 +200,12 @@ def get_stop_batch() -> int: return sb -def get_ntypes(all_type: List[np.ndarray[int]]) -> int: +def get_ntypes(all_type: List[np.ndarray]) -> int: """Count number of unique elements. Parameters ---------- - all_type : List[np.ndarray[int]] + all_type : List[np.ndarray] list with arrays specifying elements of structures Returns @@ -217,15 +217,15 @@ def get_ntypes(all_type: List[np.ndarray[int]]) -> int: def get_max_density( - all_type: List[np.ndarray[int]], all_box: List[np.ndarray[float]] -) -> np.ndarray[float]: + all_type: List[np.ndarray], all_box: List[np.ndarray] +) -> np.ndarray: """Compute maximum density in suppliedd cells. Parameters ---------- - all_type : List[np.ndarray[int]] + all_type : List[np.ndarray] list with arrays specifying elements of structures - all_box : List[np.ndarray[float]] + all_box : List[np.ndarray] list with arrays specifying cells for all structures Returns @@ -249,8 +249,8 @@ def get_max_density( def suggest_sel( - all_type: List[np.ndarray[int]], - all_box: List[np.ndarray[float]], + all_type: List[np.ndarray], + all_box: List[np.ndarray], rcut: float, ratio: float = 1.5, ) -> List[int]: @@ -258,9 +258,9 @@ def suggest_sel( Parameters ---------- - all_type : List[np.ndarray[int]] + all_type : List[np.ndarray] list with arrays specifying elements of structures - all_box : List[np.ndarray[float]] + all_box : List[np.ndarray] list with arrays specifying cells for all structures rcut : float cutoff radius @@ -276,12 +276,12 @@ def suggest_sel( return [int(ii) for ii in max_den * 4.0 / 3.0 * np.pi * rcut ** 3 * ratio] -def suggest_batch_size(all_type: List[np.ndarray[int]], min_atom: int) -> List[int]: +def suggest_batch_size(all_type: List[np.ndarray], min_atom: int) -> List[int]: """Get suggestion for batch size. Parameters ---------- - all_type : List[np.ndarray[int]] + all_type : List[np.ndarray] list with arrays specifying elements of structures min_atom : int minimal number of atoms in batch From 25ce4cd7d87c7570511e2f5b812674bc1b782add Mon Sep 17 00:00:00 2001 From: denghuilu Date: Thu, 4 Feb 2021 11:06:44 +0800 Subject: [PATCH 079/562] update compiler support for Ampere architecture devices --- source/op/cuda/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/op/cuda/CMakeLists.txt b/source/op/cuda/CMakeLists.txt index 89dd0b5922..0201e50130 100644 --- a/source/op/cuda/CMakeLists.txt +++ b/source/op/cuda/CMakeLists.txt @@ -28,6 +28,8 @@ if (${CUDA_VERSION_MAJOR} GREATER "10") -gencode arch=compute_61,code=sm_61; # Pascal - GTX 1080, GTX 1070, GTX 1060, GTX 1050, GTX 1030, Titan Xp, Tesla P40, Tesla P4, Discrete GPU on the NVIDIA Drive PX2 -gencode arch=compute_70,code=sm_70; # Volta - GV100/Tesla V100, GTX 1180 (GV104) -gencode arch=compute_75,code=sm_75; # Turing - RTX 2080, Titan RTX, Quadro R8000 + -gencode arch=compute_80,code=sm_80; # Anpere - A100 + -gencode arch=compute_86,code=sm_86; # Anpere - RTX 3090 -O3; -Xcompiler -fPIC; ) elseif (${CUDA_VERSION_MAJOR} STREQUAL "10") From d885e919dd455e131bc8ff30e0b4a2b3f72b06df Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Thu, 4 Feb 2021 02:12:58 -0500 Subject: [PATCH 080/562] fix github actions --- .github/workflows/test_python.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index aad0379bc7..92d45a3c9b 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -59,6 +59,9 @@ jobs: - run: | sudo apt update sudo apt install gcc-${{ matrix.gcc }} g++-${{ matrix.gcc }} - - run: pip install tensorflow - run: pip install .[cpu,test] + env: + CC: gcc-${{ matrix.gcc }} + CXX: g++-${{ matrix.gcc }} + TENSORFLOW_VERSION: ${{ matrix.tf }} - run: cd source/tests && python -m unittest From 38f6161433e49a4853782877f1d3a07aa6861996 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Thu, 4 Feb 2021 02:17:42 -0500 Subject: [PATCH 081/562] fix setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 278d56b79f..71848c6011 100644 --- a/setup.py +++ b/setup.py @@ -68,7 +68,7 @@ setup( name="deepmd-kit", - setup_requires=INSTALL_REQUIRES, + setup_requires=setup_requires, use_scm_version={"write_to": "deepmd/_version.py"}, author="Han Wang", author_email="wang_han@iapcm.ac.cn", From 5f02155864466c7020ab67236e2c932e951579f2 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Thu, 4 Feb 2021 02:19:24 -0500 Subject: [PATCH 082/562] fix github actions forgot to add environment varibles --- .github/workflows/test_python.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index c52e3921d3..92d45a3c9b 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -60,4 +60,8 @@ jobs: sudo apt update sudo apt install gcc-${{ matrix.gcc }} g++-${{ matrix.gcc }} - run: pip install .[cpu,test] + env: + CC: gcc-${{ matrix.gcc }} + CXX: g++-${{ matrix.gcc }} + TENSORFLOW_VERSION: ${{ matrix.tf }} - run: cd source/tests && python -m unittest From 13ba30f3bdff288bb090ec1e50a7b05865f6cc71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 4 Feb 2021 11:55:00 +0100 Subject: [PATCH 083/562] add python lint git action --- .github/workflows/lint_python.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/lint_python.yml diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml new file mode 100644 index 0000000000..f254573335 --- /dev/null +++ b/.github/workflows/lint_python.yml @@ -0,0 +1,19 @@ +on: + push: + pull_request: +name: Lint Python +jobs: + testpython: + name: Lint Python + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - uses: rahul-deepsource/pyaction@v1.4.0 + with: + python-root-list: "./deepmd/*.py ./deepmd/*/*.py ./source/train/*.py ./source/tests/*.py, ./source/scripts/*.py ./source/op/*.py" + use-black: true + use-isort: true + use-mypy: true + use-pycodestyle: true + extra-pycodestyle-options: "--max-line-length=88" From e6e9c340f02b9a0a753c3e11c8e062387dc6f933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 4 Feb 2021 12:04:38 +0100 Subject: [PATCH 084/562] failing to resolve used action repo --- .github/workflows/lint_python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml index f254573335..1623cd1556 100644 --- a/.github/workflows/lint_python.yml +++ b/.github/workflows/lint_python.yml @@ -9,7 +9,7 @@ jobs: steps: - uses: actions/checkout@v1 - - uses: rahul-deepsource/pyaction@v1.4.0 + - uses: rahul-deepsource/pyaction@master with: python-root-list: "./deepmd/*.py ./deepmd/*/*.py ./source/train/*.py ./source/tests/*.py, ./source/scripts/*.py ./source/op/*.py" use-black: true From 390c82f078cde0c581b7ec5a12fc65cc7492e237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 4 Feb 2021 13:29:42 +0100 Subject: [PATCH 085/562] fix pyaction --- .github/workflows/lint_python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml index 1623cd1556..31e14e60b5 100644 --- a/.github/workflows/lint_python.yml +++ b/.github/workflows/lint_python.yml @@ -9,7 +9,7 @@ jobs: steps: - uses: actions/checkout@v1 - - uses: rahul-deepsource/pyaction@master + - uses: marian-code/pyaction@master with: python-root-list: "./deepmd/*.py ./deepmd/*/*.py ./source/train/*.py ./source/tests/*.py, ./source/scripts/*.py ./source/op/*.py" use-black: true From 6a70ef9cfdce59d1a2bcfe28739a3ab329c120c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 4 Feb 2021 14:16:39 +0100 Subject: [PATCH 086/562] changes to test the lintner action --- source/train/Local.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/source/train/Local.py b/source/train/Local.py index d2564ff17c..1b1ddee931 100644 --- a/source/train/Local.py +++ b/source/train/Local.py @@ -1,13 +1,26 @@ -import os, socket +"""Get local GPU resources from `CUDA_VISIBLE_DEVICES` enviroment variable.""" -def get_resource (): +import os +import socket +from typing import List, Tuple, Optional + + +def get_resource() -> Tuple[str, List[str], Optional[List[int]]]: + """Get loacl resources: nodename, nodelist, and gpus. + + Returns + ------- + Tuple[str, List[str], Optional[List[int]]] + nodename, nodelist, and gpus + """ nodename = socket.gethostname() nodelist = [nodename] - gpus = os.getenv('CUDA_VISIBLE_DEVICES') - if gpus is not None : - if gpus != "" : - gpus = gpus.split(",") - gpus = [int(ii) for ii in gpus] - else : - gpus = [] + gpus_env = os.getenv("CUDA_VISIBLE_DEVICES", None) + if gpus_env is None: + gpus = None + elif gpus_env == "": + gpus = [] + else: + gpus = [int(gpu) for gpu in gpus_env.split(",")] + return nodename, nodelist, gpus From 5d159b697704d196f4e51d71c3a7e9a46469e974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 4 Feb 2021 14:37:41 +0100 Subject: [PATCH 087/562] bugfixes to lint action --- .github/workflows/lint_python.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml index 31e14e60b5..fb9c8479b4 100644 --- a/.github/workflows/lint_python.yml +++ b/.github/workflows/lint_python.yml @@ -11,9 +11,12 @@ jobs: - uses: actions/checkout@v1 - uses: marian-code/pyaction@master with: - python-root-list: "./deepmd/*.py ./deepmd/*/*.py ./source/train/*.py ./source/tests/*.py, ./source/scripts/*.py ./source/op/*.py" + python-root-list: "./deepmd/*.py ./deepmd/*/*.py ./source/train/*.py ./source/tests/*.py ./source/scripts/*.py ./source/op/*.py" use-black: true use-isort: true use-mypy: true use-pycodestyle: true extra-pycodestyle-options: "--max-line-length=88" + use-pylint: false + use-flake8: false + use-vulture: false From af07f964555c9a3c9330bd83efca352b4cc7fbea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 4 Feb 2021 14:58:43 +0100 Subject: [PATCH 088/562] add missing requirements and python 3.8 tests --- .github/workflows/lint_python.yml | 10 +++++++++- .github/workflows/test_python.yml | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml index fb9c8479b4..8263d523c0 100644 --- a/.github/workflows/lint_python.yml +++ b/.github/workflows/lint_python.yml @@ -3,12 +3,20 @@ on: pull_request: name: Lint Python jobs: - testpython: + lintpython: name: Lint Python runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.6] steps: - uses: actions/checkout@v1 + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python }} + - name: Install requirements + run: pip install -r requirements.txt - uses: marian-code/pyaction@master with: python-root-list: "./deepmd/*.py ./deepmd/*/*.py ./source/train/*.py ./source/tests/*.py ./source/scripts/*.py ./source/op/*.py" diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index 92d45a3c9b..84534996d3 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -42,6 +42,12 @@ jobs: - python: 3.7 gcc: 8 tf: 2.3 + - python: 3.8 + gcc: 5 + tf: 2.3 + - python: 3.8 + gcc: 8 + tf: 2.3 steps: - uses: actions/checkout@master From b32e57d38e3437041fe43ec357429e4f1b4877d6 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Thu, 4 Feb 2021 22:00:47 +0800 Subject: [PATCH 089/562] optimize the code structure of model compression --- deepmd/descriptor/se_a.py | 207 +++++--------------------- deepmd/utils/data_info.py | 132 ++++++++++++++++ deepmd/utils/tabulate.py | 95 +++++++----- source/lib/include/CustomeOperation.h | 9 +- source/op/cuda/CMakeLists.txt | 4 +- source/op/cuda/tabulate.cu | 21 +-- source/op/data_info.cc | 10 +- source/op/tabulate.cc | 14 +- source/train/Model.py | 3 - source/train/Trainer.py | 24 ++- source/train/compress.py | 2 +- source/train/main.py | 2 +- 12 files changed, 281 insertions(+), 242 deletions(-) create mode 100644 deepmd/utils/data_info.py diff --git a/deepmd/descriptor/se_a.py b/deepmd/descriptor/se_a.py index d7ee320bd4..2ca03378dd 100644 --- a/deepmd/descriptor/se_a.py +++ b/deepmd/descriptor/se_a.py @@ -11,7 +11,6 @@ from deepmd.env import default_tf_session_config from deepmd.utils.network import embedding_net from deepmd.utils.tabulate import DeepTabulate -from tqdm import tqdm class DescrptSeA (): @@ -114,7 +113,10 @@ def __init__ (self, self.compress = compress self.model_file = model_file self.table_info = table_info - if (self.compress): + if self.compress: + self.distance = 100.0 + self.max_nbor_size = 0 + self.table_range = [-1, 20] self.table = DeepTabulate(self.model_file, self.filter_np_precision, self.type_one_side) self.place_holders = {} @@ -123,7 +125,7 @@ def __init__ (self, sub_graph = tf.Graph() with sub_graph.as_default(): name_pfx = 'd_sea_' - for ii in ['coord', 'box', 'avg', 'std']: + for ii in ['coord', 'box']: self.place_holders[ii] = tf.placeholder(global_np_float_precision, [None, None], name = name_pfx+'t_'+ii) self.place_holders['type'] = tf.placeholder(tf.int32, [None, None], name=name_pfx+'t_type') self.place_holders['natoms_vec'] = tf.placeholder(tf.int32, [self.ntypes+2], name=name_pfx+'t_natoms') @@ -141,19 +143,6 @@ def __init__ (self, rcut_r_smth = self.rcut_r_smth, sel_a = self.sel_a, sel_r = self.sel_r) - descrpt, descrpt_deriv, rij, nlist, self.distance, self.max_nbor_size, self.table_range \ - = op_module.data_info(self.place_holders['coord'], - self.place_holders['type'], - self.place_holders['natoms_vec'], - self.place_holders['box'], - self.place_holders['default_mesh'], - self.place_holders['avg'], - self.place_holders['std'], - rcut_a = self.rcut_a, - rcut_r = self.rcut_r, - rcut_r_smth = self.rcut_r_smth, - sel_a = self.sel_a, - sel_r = self.sel_r) self.sub_sess = tf.Session(graph = sub_graph, config=default_tf_session_config) @@ -358,9 +347,9 @@ def build (self, self.rij = tf.identity(self.rij, name = 'o_rij') self.nlist = tf.identity(self.nlist, name = 'o_nlist') - if (self.compress): - self.lower = math.floor(self.lower) - self.upper = math.ceil(self.upper) + if self.compress: + self.lower = math.floor(self.table_range[0]) + self.upper = math.ceil(self.table_range[1]) self.table.build(self.lower, self.upper, self.upper * self.table_info[0], @@ -378,59 +367,6 @@ def build (self, # only used when tensorboard was set as true tf.summary.histogram('embedding_net_output', self.dout) return self.dout - - def data_info(self, data) -> None: - """ - Print the data info(tabulation boundary, the nearest distance of atoms, max neighbor size) of the training data - - Parameters - ---------- - data - The data class that controls input data information - """ - self.lower = 0.0 - self.upper = 0.0 - self.dist = 100.0 - self.max_nbor = 0 - - davg = self.davg - dstd = self.dstd - if davg is None: - davg = np.zeros([self.ntypes, self.ndescrpt]) - if dstd is None: - dstd = np.ones ([self.ntypes, self.ndescrpt]) - - for ii in tqdm(range(len(data.system_dirs)), desc = '# DEEPMD: getting data info'): - for jj in data.data_systems[ii].dirs: - data_set = data.data_systems[ii]._load_set(jj) - for kk in range(np.array(data_set['type']).shape[0]): - dt, mn, tr \ - = self.sub_sess.run([self.distance, self.max_nbor_size, self.table_range], - feed_dict = { - self.place_holders['coord']: np.array(data_set['coord'])[kk].reshape([-1, data.natoms[ii] * 3]), - self.place_holders['type']: np.array(data_set['type'])[kk].reshape([-1, data.natoms[ii]]), - self.place_holders['natoms_vec']: np.array(data.natoms_vec[ii]), - self.place_holders['box']: np.array(data_set['box'])[kk].reshape([-1, 9]), - self.place_holders['default_mesh']: np.array(data.default_mesh[ii]), - self.place_holders['avg']: davg, - self.place_holders['std']: dstd, - }) - dr = np.array([np.min(tr), np.max(tr)]).astype(global_np_float_precision) - dt = np.min(dt) - mn = np.max(mn) - if (dr[0] < self.lower): - self.lower = dr[0] - if (dr[1] > self.upper): - self.upper = dr[1] - if (dt < self.dist): - self.dist = dt - if (mn > self.max_nbor): - self.max_nbor = mn - - print('# DEEPMD: training data with lower boundary: ' + str(self.lower)) - print('# DEEPMD: training data with upper boundary: ' + str(self.upper)) - print('# DEEPMD: training data with min distance: ' + str(self.dist)) - print('# DEEPMD: training data with max nborsize: ' + str(self.max_nbor)) def get_rot_mat(self) -> tf.Tensor: """ @@ -507,10 +443,7 @@ def _pass_filter(self, [ 0, start_index* self.ndescrpt], [-1, natoms[2+type_i]* self.ndescrpt] ) inputs_i = tf.reshape(inputs_i, [-1, self.ndescrpt]) - if not self.compress: - layer, qmat = self._filter(tf.cast(inputs_i, self.filter_precision), type_i, name='filter_type_'+str(type_i)+suffix, natoms=natoms, reuse=reuse, seed = self.seed, trainable = trainable, activation_fn = self.filter_activation_fn) - else: - layer, qmat = self._compress_filter(tf.cast(inputs_i, self.filter_precision), type_i, name='filter_type_'+str(type_i)+suffix, natoms=natoms, reuse=reuse, seed = self.seed, trainable = trainable, activation_fn = self.filter_activation_fn) + layer, qmat = self._filter(tf.cast(inputs_i, self.filter_precision), type_i, name='filter_type_'+str(type_i)+suffix, natoms=natoms, reuse=reuse, seed = self.seed, trainable = trainable, activation_fn = self.filter_activation_fn) layer = tf.reshape(layer, [tf.shape(inputs)[0], natoms[2+type_i] * self.get_dim_out()]) qmat = tf.reshape(qmat, [tf.shape(inputs)[0], natoms[2+type_i] * self.get_dim_rot_mat_1() * 3]) output.append(layer) @@ -520,10 +453,7 @@ def _pass_filter(self, inputs_i = inputs inputs_i = tf.reshape(inputs_i, [-1, self.ndescrpt]) type_i = -1 - if not self.compress: - layer, qmat = self._filter(tf.cast(inputs_i, self.filter_precision), type_i, name='filter_type_all'+suffix, natoms=natoms, reuse=reuse, seed = self.seed, trainable = trainable, activation_fn = self.filter_activation_fn) - else: - layer, qmat = self._compress_filter(tf.cast(inputs_i, self.filter_precision), type_i, name='filter_type_all'+suffix, natoms=natoms, reuse=reuse, seed = self.seed, trainable = trainable, activation_fn = self.filter_activation_fn) + layer, qmat = self._filter(tf.cast(inputs_i, self.filter_precision), type_i, name='filter_type_all'+suffix, natoms=natoms, reuse=reuse, seed = self.seed, trainable = trainable, activation_fn = self.filter_activation_fn) layer = tf.reshape(layer, [tf.shape(inputs)[0], natoms[0] * self.get_dim_out()]) qmat = tf.reshape(qmat, [tf.shape(inputs)[0], natoms[0] * self.get_dim_rot_mat_1() * 3]) output.append(layer) @@ -616,99 +546,38 @@ def _filter(self, # with (natom x nei_type_i) x 1 xyz_scatter = tf.reshape(tf.slice(inputs_reshape, [0,0],[-1,1]),[-1,1]) # with (natom x nei_type_i) x out_size - if (type_input, type_i) not in self.exclude_types: - xyz_scatter = embedding_net(xyz_scatter, - self.filter_neuron, - self.filter_precision, - activation_fn = activation_fn, - resnet_dt = self.filter_resnet_dt, - name_suffix = "_"+str(type_i), - stddev = stddev, - bavg = bavg, - seed = seed, - trainable = trainable) - else: - w = tf.zeros((outputs_size[0], outputs_size[-1]), dtype=global_tf_float_precision) - xyz_scatter = tf.matmul(xyz_scatter, w) - # natom x nei_type_i x out_size - xyz_scatter = tf.reshape(xyz_scatter, (-1, shape_i[1]//4, outputs_size[-1])) - - # xyz_scatter_total.append(xyz_scatter) - if type_i == 0 : - xyz_scatter_1 = tf.matmul(tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]), xyz_scatter, transpose_a = True) - else : - xyz_scatter_1 += tf.matmul(tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]), xyz_scatter, transpose_a = True) - # natom x nei x outputs_size - # xyz_scatter = tf.concat(xyz_scatter_total, axis=1) - # natom x nei x 4 - # inputs_reshape = tf.reshape(inputs, [-1, shape[1]//4, 4]) - # natom x 4 x outputs_size - # xyz_scatter_1 = tf.matmul(inputs_reshape, xyz_scatter, transpose_a = True) - xyz_scatter_1 = xyz_scatter_1 * (4.0 / shape[1]) - # natom x 4 x outputs_size_2 - xyz_scatter_2 = tf.slice(xyz_scatter_1, [0,0,0],[-1,-1,outputs_size_2]) - # # natom x 3 x outputs_size_2 - # qmat = tf.slice(xyz_scatter_2, [0,1,0], [-1, 3, -1]) - # natom x 3 x outputs_size_1 - qmat = tf.slice(xyz_scatter_1, [0,1,0], [-1, 3, -1]) - # natom x outputs_size_1 x 3 - qmat = tf.transpose(qmat, perm = [0, 2, 1]) - # natom x outputs_size x outputs_size_2 - result = tf.matmul(xyz_scatter_1, xyz_scatter_2, transpose_a = True) - # natom x (outputs_size x outputs_size_2) - result = tf.reshape(result, [-1, outputs_size_2 * outputs_size[-1]]) - - return result, qmat - - def _compress_filter(self, - inputs, - type_input, - natoms, - activation_fn=tf.nn.tanh, - stddev=1.0, - bavg=0.0, - name='linear', - reuse=None, - seed=None, - trainable = True): - # natom x (nei x 4) - shape = inputs.get_shape().as_list() - outputs_size = [1] + self.filter_neuron - outputs_size_2 = self.n_axis_neuron - with tf.variable_scope(name, reuse=reuse): - start_index = 0 - xyz_scatter_total = [] - for type_i in range(self.ntypes): - # cut-out inputs - # with natom x (nei_type_i x 4) - inputs_i = tf.slice (inputs, - [ 0, start_index* 4], - [-1, self.sel_a[type_i]* 4] ) - start_index += self.sel_a[type_i] - shape_i = inputs_i.get_shape().as_list() - # with (natom x nei_type_i) x 4 - inputs_reshape = tf.reshape(inputs_i, [-1, 4]) - xyz_scatter = tf.reshape(tf.slice(inputs_reshape, [0,0],[-1,1]),[-1,1]) - if (type_input, type_i) in self.exclude_types: - w = tf.zeros((outputs_size[0], outputs_size[-1]), dtype=global_tf_float_precision) - xyz_scatter = tf.matmul(xyz_scatter, w) - xyz_scatter = tf.reshape(xyz_scatter, (-1, shape_i[1]//4, outputs_size[-1])) - if type_i == 0: - xyz_scatter_1 = tf.matmul(tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]), xyz_scatter, transpose_a = True) - else: - xyz_scatter_1 += tf.matmul(tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]), xyz_scatter, transpose_a = True) - else: - ti = [self.lower, self.upper, self.upper * self.table_info[0], self.table_info[1], self.table_info[2], self.table_info[3]] + if self.compress and (type_input, type_i) not in self.exclude_types: + info = [self.lower, self.upper, self.upper * self.table_info[0], self.table_info[1], self.table_info[2], self.table_info[3]] if self.type_one_side: - assert type_input == -1, "Error: when type_one_side was set True, the value of type_input must be -1." net = 'filter_-1_net_' + str(type_i) else: net = 'filter_' + str(type_input) + '_net_' + str(type_i) if type_i == 0: - xyz_scatter_1 = op_module.tabulate_fusion(self.table.data[net], ti, xyz_scatter, tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]), last_layer_size = outputs_size[-1]) + xyz_scatter_1 = op_module.tabulate_fusion(self.table.data[net], info, xyz_scatter, tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]), last_layer_size = outputs_size[-1]) else: - xyz_scatter_1 += op_module.tabulate_fusion(self.table.data[net], ti, xyz_scatter, tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]), last_layer_size = outputs_size[-1]) - # not needed any more! + xyz_scatter_1 += op_module.tabulate_fusion(self.table.data[net], info, xyz_scatter, tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]), last_layer_size = outputs_size[-1]) + else: + if (type_input, type_i) not in self.exclude_types: + xyz_scatter = embedding_net(xyz_scatter, + self.filter_neuron, + self.filter_precision, + activation_fn = activation_fn, + resnet_dt = self.filter_resnet_dt, + name_suffix = "_"+str(type_i), + stddev = stddev, + bavg = bavg, + seed = seed, + trainable = trainable) + else: + w = tf.zeros((outputs_size[0], outputs_size[-1]), dtype=global_tf_float_precision) + xyz_scatter = tf.matmul(xyz_scatter, w) + # natom x nei_type_i x out_size + xyz_scatter = tf.reshape(xyz_scatter, (-1, shape_i[1]//4, outputs_size[-1])) + # xyz_scatter_total.append(xyz_scatter) + if type_i == 0 : + xyz_scatter_1 = tf.matmul(tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]), xyz_scatter, transpose_a = True) + else : + xyz_scatter_1 += tf.matmul(tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]), xyz_scatter, transpose_a = True) # natom x nei x outputs_size # xyz_scatter = tf.concat(xyz_scatter_total, axis=1) # natom x nei x 4 @@ -722,11 +591,11 @@ def _compress_filter(self, # qmat = tf.slice(xyz_scatter_2, [0,1,0], [-1, 3, -1]) # natom x 3 x outputs_size_1 qmat = tf.slice(xyz_scatter_1, [0,1,0], [-1, 3, -1]) - # natom x outputs_size_2 x 3 + # natom x outputs_size_1 x 3 qmat = tf.transpose(qmat, perm = [0, 2, 1]) # natom x outputs_size x outputs_size_2 result = tf.matmul(xyz_scatter_1, xyz_scatter_2, transpose_a = True) # natom x (outputs_size x outputs_size_2) result = tf.reshape(result, [-1, outputs_size_2 * outputs_size[-1]]) - return result, qmat \ No newline at end of file + return result, qmat diff --git a/deepmd/utils/data_info.py b/deepmd/utils/data_info.py new file mode 100644 index 0000000000..0e760f9c1b --- /dev/null +++ b/deepmd/utils/data_info.py @@ -0,0 +1,132 @@ +import math +import numpy as np +from tqdm import tqdm +from deepmd.env import tf +from typing import Tuple, List +from deepmd.env import op_module +from deepmd.env import default_tf_session_config +from deepmd.RunOptions import global_np_float_precision + +class DataInfo(): + """ + Class for getting training data information. + It loads data from DeepmdData object, and measures the data info, including neareest nbor distance between atoms, max nbor size of atoms and the output data range of the environment matrix. + """ + def __init__(self, + descrpt_type : str, + ntypes : int, + rcut, + rcut_smth, + sel, + davg, + dstd) -> None: + """ + Constructor + + Parameters + ---------- + descrpt_type + The descrpt type of the embedding net + ntypes + The num of atom types + rcut + The cut-off radius + rcut_smth + From where the environment matrix should be smoothed + sel : list[str] + sel[i] specifies the maxmum number of type i atoms in the cut-off radius + davg + Average of training data + dstd + Standard deviation of training data + """ + self.ntypes = ntypes + self.davg = davg + self.dstd = dstd + self.descrpt_type = descrpt_type + assert self.descrpt_type == 'se_a', 'Model compression error: descriptor type must be se_a!' + self.place_holders = {} + sub_graph = tf.Graph() + with sub_graph.as_default(): + for ii in ['coord', 'box', 'avg', 'std']: + self.place_holders[ii] = tf.placeholder(global_np_float_precision, [None, None], name='t_'+ii) + self.place_holders['type'] = tf.placeholder(tf.int32, [None, None], name='t_type') + self.place_holders['natoms_vec'] = tf.placeholder(tf.int32, [self.ntypes+2], name='t_natoms') + self.place_holders['default_mesh'] = tf.placeholder(tf.int32, [None], name='t_mesh') + if self.descrpt_type == 'se_a': + self.rcut_a = -1 + self.rcut_r = rcut + self.rcut_r_smth = rcut_smth + self.sel_a = sel + self.sel_r = [ 0 for ii in range(len(self.sel_a)) ] + descrpt, descrpt_deriv, rij, nlist, self.distance, self.max_nbor_size, self.table_range \ + = op_module.data_info_se_a(self.place_holders['coord'], + self.place_holders['type'], + self.place_holders['natoms_vec'], + self.place_holders['box'], + self.place_holders['default_mesh'], + self.place_holders['avg'], + self.place_holders['std'], + rcut_a = self.rcut_a, + rcut_r = self.rcut_r, + rcut_r_smth = self.rcut_r_smth, + sel_a = self.sel_a, + sel_r = self.sel_r) + self.sub_sess = tf.Session(graph = sub_graph, config=default_tf_session_config) + + def data_info(self, + data) -> Tuple[float, int, list]: + """ + get the data info of the training data, including neareest nbor distance between atoms, max nbor size of atoms and the output data range of the environment matrix + + Parameters + ---------- + data + Class for manipulating many data systems. It is implemented with the help of DeepmdData. + """ + self.lower = 0.0 + self.upper = 0.0 + self.dist = 100.0 + self.max_nbor = 0 + + davg = self.davg + dstd = self.dstd + if davg is None: + davg = np.zeros([self.ntypes, self.ndescrpt]) + if dstd is None: + dstd = np.ones ([self.ntypes, self.ndescrpt]) + + for ii in tqdm(range(len(data.system_dirs)), desc = '# DEEPMD: getting data info'): + for jj in data.data_systems[ii].dirs: + data_set = data.data_systems[ii]._load_set(jj) + for kk in range(np.array(data_set['type']).shape[0]): + dt, mn, tr \ + = self.sub_sess.run([self.distance, self.max_nbor_size, self.table_range], + feed_dict = { + self.place_holders['coord']: np.array(data_set['coord'])[kk].reshape([-1, data.natoms[ii] * 3]), + self.place_holders['type']: np.array(data_set['type'])[kk].reshape([-1, data.natoms[ii]]), + self.place_holders['natoms_vec']: np.array(data.natoms_vec[ii]), + self.place_holders['box']: np.array(data_set['box'])[kk].reshape([-1, 9]), + self.place_holders['default_mesh']: np.array(data.default_mesh[ii]), + self.place_holders['avg']: davg, + self.place_holders['std']: dstd, + }) + dr = np.array([np.min(tr), np.max(tr)]).astype(global_np_float_precision) + dt = np.min(dt) + mn = np.max(mn) + if (dr[0] < self.lower): + self.lower = dr[0] + if (dr[1] > self.upper): + self.upper = dr[1] + if (dt < self.dist): + self.dist = dt + if (mn > self.max_nbor): + self.max_nbor = mn + + print('# DEEPMD: training data with lower boundary: ' + str(self.lower)) + print('# DEEPMD: training data with upper boundary: ' + str(self.upper)) + print('# DEEPMD: training data with min distance: ' + str(self.dist)) + print('# DEEPMD: training data with max nborsize: ' + str(self.max_nbor)) + + return self.distance, self.max_nbor_size, [self.lower, self.upper] + \ No newline at end of file diff --git a/deepmd/utils/tabulate.py b/deepmd/utils/tabulate.py index 2a453ce584..35a5603ce9 100644 --- a/deepmd/utils/tabulate.py +++ b/deepmd/utils/tabulate.py @@ -1,17 +1,34 @@ import re import math import numpy as np +from tqdm import tqdm from deepmd.env import tf +from deepmd.env import op_module from tensorflow.python.platform import gfile from tensorflow.python.framework import tensor_util -from tqdm import tqdm -from deepmd.env import op_module + class DeepTabulate(): + """ + Class for tabulation. + It reads the trained weights and bias from the frozen model, and builds the table according to the weights and bias. + """ def __init__(self, model_file, data_type, - type_one_side = False): + type_one_side = False) -> None: + """ + Constructor + + Parameters + ---------- + model_file + The frozen model + data_type + The precision of the table. Supported options are {1} + type_one_side + Try to build N_types tables. Otherwise, building N_types^2 tables + """ self.model_file = model_file self.data_type = data_type @@ -28,8 +45,10 @@ def __init__(self, self.filter_variable_nodes = self.load_matrix_node() self.layer_size = int(len(self.filter_variable_nodes) / (self.ntypes * self.ntypes * 2)) + self.table_size = self.ntypes * self.ntypes if type_one_side : self.layer_size = int(len(self.filter_variable_nodes) / (self.ntypes * 2)) + self.table_size = self.ntypes # self.value_type = self.filter_variable_nodes["filter_type_0/matrix_1_0"].dtype #"filter_type_0/matrix_1_0" must exit~ # get trained variables self.bias = self.get_bias() @@ -42,7 +61,6 @@ def __init__(self, self.data = {} # TODO: Need a check function to determine if the current model is properly - # Need be more robust! def load_graph(self): graph_def = tf.GraphDef() @@ -107,6 +125,22 @@ def get_matrix(self): return matrix def build(self, lower, upper, _max, stride0, stride1): + """ + Build the tables for model compression + + Parameters + ---------- + lower + The lower boundary of the first table + upper + The upper boundary of the first table as well as the lower boundary of the second table + _max + The upper boundary of the second table + stride0 + The stride of the first table + stride1 + The stride of the second table + """ # tabulate range [lower, upper] with stride0 'stride0' lower = math.floor(lower) upper = math.ceil(upper) @@ -114,42 +148,27 @@ def build(self, lower, upper, _max, stride0, stride1): xx = np.append(xx, np.arange(upper, _max, stride1, dtype = self.data_type)) xx = np.append(xx, np.array([_max], dtype = self.data_type)) self.nspline = int((upper - lower) / stride0 + (_max - upper) / stride1) - if self.type_one_side: - for ii in range(self.ntypes): - vv, dd, d2 = self.make_data(xx, ii) + + for ii in range(self.table_size): + vv, dd, d2 = self.make_data(xx, ii) + if self.type_one_side: net = "filter_-1_net_" + str(int(ii)) - self.data[net] = np.zeros([self.nspline, 6 * self.last_layer_size], dtype = self.data_type) - for jj in tqdm(range(self.nspline), desc = '# DEEPMD: ' + net + ', tabulating'): - for kk in range(self.last_layer_size): - if jj < int((upper - lower) / stride0): - tt = stride0 - else: - tt = stride1 - hh = vv[jj + 1][kk] - vv[jj][kk] - self.data[net][jj][kk * 6 + 0] = vv[jj][kk] - self.data[net][jj][kk * 6 + 1] = dd[jj][kk] - self.data[net][jj][kk * 6 + 2] = 0.5 * d2[jj][kk] - self.data[net][jj][kk * 6 + 3] = (1 / (2 * tt * tt * tt)) * (20 * hh - (8 * dd[jj + 1][kk] + 12 * dd[jj][kk]) * tt - (3 * d2[jj][kk] - d2[jj + 1][kk]) * tt * tt) - self.data[net][jj][kk * 6 + 4] = (1 / (2 * tt * tt * tt * tt)) * (-30 * hh + (14 * dd[jj + 1][kk] + 16 * dd[jj][kk]) * tt + (3 * d2[jj][kk] - 2 * d2[jj + 1][kk]) * tt * tt) - self.data[net][jj][kk * 6 + 5] = (1 / (2 * tt * tt * tt * tt * tt)) * (12 * hh - 6 * (dd[jj + 1][kk] + dd[jj][kk]) * tt + (d2[jj + 1][kk] - d2[jj][kk]) * tt * tt) - else: - for ii in range(self.ntypes * self.ntypes): - vv, dd, d2 = self.make_data(xx, ii) + else: net = "filter_" + str(int(ii / self.ntypes)) + "_net_" + str(int(ii % self.ntypes)) - self.data[net] = np.zeros([self.nspline, 6 * self.last_layer_size], dtype = self.data_type) - for jj in tqdm(range(self.nspline), desc = '# DEEPMD: ' + net + ', tabulating'): - for kk in range(self.last_layer_size): - if jj < int((upper - lower) / stride0): - tt = stride0 - else: - tt = stride1 - hh = vv[jj + 1][kk] - vv[jj][kk] - self.data[net][jj][kk * 6 + 0] = vv[jj][kk] - self.data[net][jj][kk * 6 + 1] = dd[jj][kk] - self.data[net][jj][kk * 6 + 2] = 0.5 * d2[jj][kk] - self.data[net][jj][kk * 6 + 3] = (1 / (2 * tt * tt * tt)) * (20 * hh - (8 * dd[jj + 1][kk] + 12 * dd[jj][kk]) * tt - (3 * d2[jj][kk] - d2[jj + 1][kk]) * tt * tt) - self.data[net][jj][kk * 6 + 4] = (1 / (2 * tt * tt * tt * tt)) * (-30 * hh + (14 * dd[jj + 1][kk] + 16 * dd[jj][kk]) * tt + (3 * d2[jj][kk] - 2 * d2[jj + 1][kk]) * tt * tt) - self.data[net][jj][kk * 6 + 5] = (1 / (2 * tt * tt * tt * tt * tt)) * (12 * hh - 6 * (dd[jj + 1][kk] + dd[jj][kk]) * tt + (d2[jj + 1][kk] - d2[jj][kk]) * tt * tt) + self.data[net] = np.zeros([self.nspline, 6 * self.last_layer_size], dtype = self.data_type) + for jj in tqdm(range(self.nspline), desc = '# DEEPMD: ' + net + ', tabulating'): + for kk in range(self.last_layer_size): + if jj < int((upper - lower) / stride0): + tt = stride0 + else: + tt = stride1 + hh = vv[jj + 1][kk] - vv[jj][kk] + self.data[net][jj][kk * 6 + 0] = vv[jj][kk] + self.data[net][jj][kk * 6 + 1] = dd[jj][kk] + self.data[net][jj][kk * 6 + 2] = 0.5 * d2[jj][kk] + self.data[net][jj][kk * 6 + 3] = (1 / (2 * tt * tt * tt)) * (20 * hh - (8 * dd[jj + 1][kk] + 12 * dd[jj][kk]) * tt - (3 * d2[jj][kk] - d2[jj + 1][kk]) * tt * tt) + self.data[net][jj][kk * 6 + 4] = (1 / (2 * tt * tt * tt * tt)) * (-30 * hh + (14 * dd[jj + 1][kk] + 16 * dd[jj][kk]) * tt + (3 * d2[jj][kk] - 2 * d2[jj + 1][kk]) * tt * tt) + self.data[net][jj][kk * 6 + 5] = (1 / (2 * tt * tt * tt * tt * tt)) * (12 * hh - 6 * (dd[jj + 1][kk] + dd[jj][kk]) * tt + (d2[jj + 1][kk] - d2[jj][kk]) * tt * tt) # one-by-one executions def make_data(self, xx, idx): diff --git a/source/lib/include/CustomeOperation.h b/source/lib/include/CustomeOperation.h index 0c0d891fd4..98b64e44af 100644 --- a/source/lib/include/CustomeOperation.h +++ b/source/lib/include/CustomeOperation.h @@ -643,7 +643,7 @@ void TabulateFusionCPULauncher(const FPTYPE * table, const FPTYPE * table_info, FPTYPE a3 = table[table_idx * last_layer_size * 6 + 6 * kk + 3]; FPTYPE a4 = table[table_idx * last_layer_size * 6 + 6 * kk + 4]; FPTYPE a5 = table[table_idx * last_layer_size * 6 + 6 * kk + 5]; - FPTYPE var = a0 + a1 * xx + a2 * xx * xx + a3 * xx * xx * xx + a4 * xx * xx * xx * xx + a5 * xx * xx * xx * xx * xx; + FPTYPE var = a0 + (a1 + (a2 + (a3 + (a4 + a5 * xx) * xx) * xx) * xx) * xx; if (unloop) { out[ii * last_layer_size * 4 + 0 * last_layer_size + kk] += (nnei - jj) * var * ll[0]; out[ii * last_layer_size * 4 + 1 * last_layer_size + kk] += (nnei - jj) * var * ll[1]; @@ -705,16 +705,17 @@ void TabulateFusionGradCPULauncher(const FPTYPE * table, const FPTYPE * table_in FPTYPE a3 = table[table_idx * last_layer_size * 6 + 6 * kk + 3]; FPTYPE a4 = table[table_idx * last_layer_size * 6 + 6 * kk + 4]; FPTYPE a5 = table[table_idx * last_layer_size * 6 + 6 * kk + 5]; - FPTYPE res = a0 + a1 * xx + a2 * xx * xx + a3 * xx * xx * xx + a4 * xx * xx * xx * xx + a5 * xx * xx * xx * xx * xx; + FPTYPE res = a0 + (a1 + (a2 + (a3 + (a4 + a5 * xx) * xx) * xx) * xx) * xx; + if (unloop) { - grad += (a1 + 2 * a2 * xx + 3 * a3 * xx * xx + 4 * a4 * xx * xx * xx + 5 * a5 * xx * xx * xx * xx) * dot(ll, rr) * (nnei - jj); + grad += (a1 + (2 * a2 + (3 * a3 + (4 * a4 + 5 * a5 * xx) * xx) * xx) * xx) * dot(ll, rr) * (nnei - jj); dy_df[ii * nnei * 4 + jj * 4 + 0] += res * rr[0] * (nnei - jj); dy_df[ii * nnei * 4 + jj * 4 + 1] += res * rr[1] * (nnei - jj); dy_df[ii * nnei * 4 + jj * 4 + 2] += res * rr[2] * (nnei - jj); dy_df[ii * nnei * 4 + jj * 4 + 3] += res * rr[3] * (nnei - jj); } else { - grad += (a1 + 2 * a2 * xx + 3 * a3 * xx * xx + 4 * a4 * xx * xx * xx + 5 * a5 * xx * xx * xx * xx) * dot(ll, rr); + grad += (a1 + (2 * a2 + (3 * a3 + (4 * a4 + 5 * a5 * xx) * xx) * xx) * xx) * dot(ll, rr); dy_df[ii * nnei * 4 + jj * 4 + 0] += res * rr[0]; dy_df[ii * nnei * 4 + jj * 4 + 1] += res * rr[1]; dy_df[ii * nnei * 4 + jj * 4 + 2] += res * rr[2]; diff --git a/source/op/cuda/CMakeLists.txt b/source/op/cuda/CMakeLists.txt index 96a030909c..4f47aa1435 100644 --- a/source/op/cuda/CMakeLists.txt +++ b/source/op/cuda/CMakeLists.txt @@ -28,8 +28,8 @@ if (${CUDA_VERSION_MAJOR} GREATER "10") -gencode arch=compute_61,code=sm_61; # Pascal - GTX 1080, GTX 1070, GTX 1060, GTX 1050, GTX 1030, Titan Xp, Tesla P40, Tesla P4, Discrete GPU on the NVIDIA Drive PX2 -gencode arch=compute_70,code=sm_70; # Volta - GV100/Tesla V100, GTX 1180 (GV104) -gencode arch=compute_75,code=sm_75; # Turing - RTX 2080, Titan RTX, Quadro R8000 - -gencode arch=compute_80,code=sm_80; # Anpere - A100 - -gencode arch=compute_86,code=sm_86; # Anpere - RTX 3090 + -gencode arch=compute_80,code=sm_80; # Ampere - A100 + -gencode arch=compute_86,code=sm_86; # Ampere - RTX 3090 -O3; -Xcompiler -fPIC; ) elseif (${CUDA_VERSION_MAJOR} STREQUAL "10") diff --git a/source/op/cuda/tabulate.cu b/source/op/cuda/tabulate.cu index a7231b413f..83befeb571 100644 --- a/source/op/cuda/tabulate.cu +++ b/source/op/cuda/tabulate.cu @@ -196,7 +196,8 @@ __global__ void tabulate_fusion_special(const FPTYPE * table, const FPTYPE * in, var[3] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 3]; var[4] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 4]; var[5] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 5]; - FPTYPE res = var[0] + var[1] * xx + var[2] * xx * xx + var[3] * xx * xx * xx + var[4] * xx * xx * xx * xx + var[5] * xx * xx * xx * xx * xx; + FPTYPE res = var[0] + (var[1] + (var[2] + (var[3] + (var[4] + var[5] * xx) * xx) * xx) * xx) * xx; + for (int kk = 0; kk < MTILE; kk++) { iteratorC[kk * last_layer_size + thread_idx] += (nnei - breakpoint) * ff[block_idx * nnei * MTILE + ii * MTILE + kk] * res; } @@ -240,14 +241,16 @@ __global__ void tabulate_fusion_grad_warp_reduce_special(const FPTYPE * table, c FPTYPE sum[KTILE] = {0.f}; FPTYPE Csub = 0.f; for (int jj = lane_idx; jj < last_layer_size; jj += WARP_SIZE) { + FPTYPE var[6]; // load iteratorB through table - FPTYPE a0 = table[table_idx * last_layer_size * 6 + 6 * jj + 0]; - FPTYPE a1 = table[table_idx * last_layer_size * 6 + 6 * jj + 1]; - FPTYPE a2 = table[table_idx * last_layer_size * 6 + 6 * jj + 2]; - FPTYPE a3 = table[table_idx * last_layer_size * 6 + 6 * jj + 3]; - FPTYPE a4 = table[table_idx * last_layer_size * 6 + 6 * jj + 4]; - FPTYPE a5 = table[table_idx * last_layer_size * 6 + 6 * jj + 5]; - FPTYPE res = a0 + a1 * xx + a2 * xx * xx + a3 * xx * xx * xx + a4 * xx * xx * xx * xx + a5 * xx * xx * xx * xx * xx; + var[0] = table[table_idx * last_layer_size * 6 + 6 * jj + 0]; + var[1] = table[table_idx * last_layer_size * 6 + 6 * jj + 1]; + var[2] = table[table_idx * last_layer_size * 6 + 6 * jj + 2]; + var[3] = table[table_idx * last_layer_size * 6 + 6 * jj + 3]; + var[4] = table[table_idx * last_layer_size * 6 + 6 * jj + 4]; + var[5] = table[table_idx * last_layer_size * 6 + 6 * jj + 5]; + FPTYPE res = var[0] + (var[1] + (var[2] + (var[3] + (var[4] + var[5] * xx) * xx) * xx) * xx) * xx; + for (int kk = 0; kk < KTILE; kk++) { sum[kk] += (nnei - breakpoint) * iteratorA[kk * last_layer_size + jj] * res; } @@ -255,7 +258,7 @@ __global__ void tabulate_fusion_grad_warp_reduce_special(const FPTYPE * table, c res += ff[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 1] * iteratorA[1 * last_layer_size + jj]; res += ff[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 2] * iteratorA[2 * last_layer_size + jj]; res += ff[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 3] * iteratorA[3 * last_layer_size + jj]; - Csub += (nnei - breakpoint) * (a1 + 2 * a2 * xx + 3 * a3 * xx * xx + 4 * a4 * xx * xx * xx + 5 * a5 * xx * xx * xx * xx) * res; + Csub += (nnei - breakpoint) * (var[1] + (2 * var[2] + (3 * var[3] + (4 * var[4] + 5 * var[5] * xx) * xx) * xx) * xx) * res; } __syncwarp(); for (int kk = 0; kk < KTILE; kk++) { diff --git a/source/op/data_info.cc b/source/op/data_info.cc index 08e0f77691..12df043918 100644 --- a/source/op/data_info.cc +++ b/source/op/data_info.cc @@ -15,7 +15,7 @@ using namespace tensorflow; using CPUDevice = Eigen::ThreadPoolDevice; using GPUDevice = Eigen::GpuDevice; -REGISTER_OP("DataInfo") +REGISTER_OP("DataInfoSeA") .Attr("T: {float, double}") .Input("coord: T") //atomic coordinates .Input("type: int32") //atomic type @@ -38,9 +38,9 @@ REGISTER_OP("DataInfo") .Output("table_range: T"); template -class DataInfoOp : public OpKernel { +class DataInfoSeAOp : public OpKernel { public: - explicit DataInfoOp(OpKernelConstruction* context) : OpKernel(context) { + explicit DataInfoSeAOp(OpKernelConstruction* context) : OpKernel(context) { OP_REQUIRES_OK(context, context->GetAttr("rcut_a", &rcut_a)); OP_REQUIRES_OK(context, context->GetAttr("rcut_r", &rcut_r)); OP_REQUIRES_OK(context, context->GetAttr("rcut_r_smth", &rcut_r_smth)); @@ -402,7 +402,7 @@ class DataInfoOp : public OpKernel { #define REGISTER_CPU(T) \ REGISTER_KERNEL_BUILDER( \ - Name("DataInfo").Device(DEVICE_CPU).TypeConstraint("T"), \ - DataInfoOp); + Name("DataInfoSeA").Device(DEVICE_CPU).TypeConstraint("T"), \ + DataInfoSeAOp); REGISTER_CPU(float); REGISTER_CPU(double); \ No newline at end of file diff --git a/source/op/tabulate.cc b/source/op/tabulate.cc index 14e9b51474..ba7cc550fe 100644 --- a/source/op/tabulate.cc +++ b/source/op/tabulate.cc @@ -27,12 +27,14 @@ REGISTER_OP("TabulateFusionGrad") .Output("dy_dx: T") .Output("dy_df: T"); +#if GOOGLE_CUDA void TabulateFusionLauncher(const float * table, const float * table_info, const float * in, const float * ff, const int nloc, const int nnei, const int last_layer_size, float * out); void TabulateFusionLauncher(const double * table, const double * table_info, const double * in, const double * ff, const int nloc, const int nnei, const int last_layer_size, double * out); void TabulateFusionGradLauncher(const float * table, const float * table_info, const float * in, const float * ff, const float * dy, const int nloc, const int nnei, const int last_layer_size, float * dy_dx, float * dy_df); void TabulateFusionGradLauncher(const double * table, const double * table_info, const double * in, const double * ff, const double * dy, const int nloc, const int nnei, const int last_layer_size, double * dy_dx, double * dy_df); void TabulateCheckerLauncher(const float * table_info, const float * in, int * out, const int nloc, const int nnei); void TabulateCheckerLauncher(const double * table_info, const double * in, int * out, const int nloc, const int nnei); +#endif template inline FPTYPE dot(FPTYPE a[4], FPTYPE b[4]) { @@ -107,7 +109,8 @@ struct TabulateFusionFunctor { FPTYPE a3 = table[table_idx * last_layer_size * 6 + 6 * kk + 3]; FPTYPE a4 = table[table_idx * last_layer_size * 6 + 6 * kk + 4]; FPTYPE a5 = table[table_idx * last_layer_size * 6 + 6 * kk + 5]; - FPTYPE var = a0 + a1 * xx + a2 * xx * xx + a3 * xx * xx * xx + a4 * xx * xx * xx * xx + a5 * xx * xx * xx * xx * xx; + // FPTYPE var = a0 + a1 * xx + a2 * xx * xx + a3 * xx * xx * xx + a4 * xx * xx * xx * xx + a5 * xx * xx * xx * xx * xx; + FPTYPE var = a0 + (a1 + (a2 + (a3 + (a4 + a5 * xx) * xx) * xx) * xx) * xx; if (unloop) { out[ii * last_layer_size * 4 + 0 * last_layer_size + kk] += (nnei - jj) * var * ll[0]; out[ii * last_layer_size * 4 + 1 * last_layer_size + kk] += (nnei - jj) * var * ll[1]; @@ -177,17 +180,20 @@ struct TabulateFusionGradFunctor { FPTYPE a3 = table[table_idx * last_layer_size * 6 + 6 * kk + 3]; FPTYPE a4 = table[table_idx * last_layer_size * 6 + 6 * kk + 4]; FPTYPE a5 = table[table_idx * last_layer_size * 6 + 6 * kk + 5]; - FPTYPE res = a0 + a1 * xx + a2 * xx * xx + a3 * xx * xx * xx + a4 * xx * xx * xx * xx + a5 * xx * xx * xx * xx * xx; + // FPTYPE res = a0 + a1 * xx + a2 * xx * xx + a3 * xx * xx * xx + a4 * xx * xx * xx * xx + a5 * xx * xx * xx * xx * xx; + FPTYPE res = a0 + (a1 + (a2 + (a3 + (a4 + a5 * xx) * xx) * xx) * xx) * xx; if (unloop) { - grad += (a1 + 2 * a2 * xx + 3 * a3 * xx * xx + 4 * a4 * xx * xx * xx + 5 * a5 * xx * xx * xx * xx) * dot(ll, rr) * (nnei - jj); + // grad += (a1 + 2 * a2 * xx + 3 * a3 * xx * xx + 4 * a4 * xx * xx * xx + 5 * a5 * xx * xx * xx * xx) * dot(ll, rr) * (nnei - jj); + grad += (a1 + (2 * a2 + (3 * a3 + (4 * a4 + 5 * a5 * xx) * xx) * xx) * xx) * dot(ll, rr) * (nnei - jj); dy_df[ii * nnei * 4 + jj * 4 + 0] += res * rr[0] * (nnei - jj); dy_df[ii * nnei * 4 + jj * 4 + 1] += res * rr[1] * (nnei - jj); dy_df[ii * nnei * 4 + jj * 4 + 2] += res * rr[2] * (nnei - jj); dy_df[ii * nnei * 4 + jj * 4 + 3] += res * rr[3] * (nnei - jj); } else { - grad += (a1 + 2 * a2 * xx + 3 * a3 * xx * xx + 4 * a4 * xx * xx * xx + 5 * a5 * xx * xx * xx * xx) * dot(ll, rr); + // grad += (a1 + 2 * a2 * xx + 3 * a3 * xx * xx + 4 * a4 * xx * xx * xx + 5 * a5 * xx * xx * xx * xx) * dot(ll, rr); + grad += (a1 + (2 * a2 + (3 * a3 + (4 * a4 + 5 * a5 * xx) * xx) * xx) * xx) * dot(ll, rr); dy_df[ii * nnei * 4 + jj * 4 + 0] += res * rr[0]; dy_df[ii * nnei * 4 + jj * 4 + 1] += res * rr[1]; dy_df[ii * nnei * 4 + jj * 4 + 2] += res * rr[2]; diff --git a/source/train/Model.py b/source/train/Model.py index 5a6ae6f153..9c9cd7ddff 100644 --- a/source/train/Model.py +++ b/source/train/Model.py @@ -114,9 +114,6 @@ def data_stat(self, data): m_all_stat = merge_sys_stat(all_stat) self._compute_input_stat(m_all_stat, protection = self.data_stat_protect) self._compute_output_stat(all_stat) - - if hasattr(self.descrpt, 'compress') and self.descrpt.compress: - self.descrpt.data_info(data) # self.bias_atom_e = data.compute_energy_shift(self.rcond) def _compute_input_stat (self, all_stat, protection = 1e-2) : diff --git a/source/train/Trainer.py b/source/train/Trainer.py index c16a0e7157..ce434ae467 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -19,6 +19,7 @@ from deepmd.Model import Model, WFCModel, DipoleModel, PolarModel, GlobalPolarModel from deepmd.loss import EnerStdLoss, EnerDipoleLoss, TensorLoss from deepmd.utils.learning_rate import LearningRateExp +from deepmd.utils.data_info import DataInfo from tensorflow.python.client import timeline from deepmd.env import op_module @@ -91,11 +92,11 @@ def _init_param(self, jdata): # descriptor try: - descrpt_type = descrpt_param['type'] + self.descrpt_type = descrpt_param['type'] except KeyError: raise KeyError('the type of descriptor should be set by `type`') - if descrpt_type != 'hybrid': + if self.descrpt_type != 'hybrid': self.descrpt = _generate_descrpt_from_param_dict(descrpt_param) else : descrpt_list = [] @@ -115,19 +116,19 @@ def _init_param(self, jdata): # elif fitting_type == 'wfc': # self.fitting = WFCFitting(fitting_param, self.descrpt) elif fitting_type == 'dipole': - if descrpt_type == 'se_a': + if self.descrpt_type == 'se_a': self.fitting = DipoleFittingSeA(**fitting_param) else : raise RuntimeError('fitting dipole only supports descrptors: se_a') elif fitting_type == 'polar': - # if descrpt_type == 'loc_frame': + # if self.descrpt_type == 'loc_frame': # self.fitting = PolarFittingLocFrame(fitting_param, self.descrpt) - if descrpt_type == 'se_a': + if self.descrpt_type == 'se_a': self.fitting = PolarFittingSeA(**fitting_param) else : raise RuntimeError('fitting polar only supports descrptors: loc_frame and se_a') elif fitting_type == 'global_polar': - if descrpt_type == 'se_a': + if self.descrpt_type == 'se_a': self.fitting = GlobalPolarFittingSeA(**fitting_param) else : raise RuntimeError('fitting global_polar only supports descrptors: loc_frame and se_a') @@ -272,6 +273,17 @@ def build (self, self.model.data_stat(data) + if hasattr(self.descrpt, 'compress') and self.descrpt.compress: + assert hasattr(self.descrpt, 'distance'), "Compression error: descrpt must have attr distance" + assert hasattr(self.descrpt, 'max_nbor_size'), "Compression error: descrpt must have attr max_nbor_size" + assert hasattr(self.descrpt, 'table_range'), "Compression error: descrpt must have attr table_range" + if self.descrpt_type == 'se_a': + info = DataInfo(self.descrpt_type, self.descrpt.ntypes, self.descrpt.rcut_r, self.descrpt.rcut_r_smth, self.descrpt.sel_a, self.descrpt.davg, self.descrpt.dstd) + else: + raise RuntimeError ("Model compression error: descriptor type must be se_a!") + self.descrpt.distance, self.descrpt.max_nbor_size, self.descrpt.table_range\ + = info.data_info(data) + worker_device = "/job:%s/task:%d/%s" % (self.run_opt.my_job_name, self.run_opt.my_task_index, self.run_opt.my_device) diff --git a/source/train/compress.py b/source/train/compress.py index fb4a505261..64035d53ed 100644 --- a/source/train/compress.py +++ b/source/train/compress.py @@ -33,7 +33,7 @@ def compress(args): args_train.output = 'compress.json' args_train.init_model = None args_train.restart = None - jdata['training']['stop_batch'] = jdata['training']['save_freq'] # be careful here, if we want refine the model + jdata['training']['stop_batch'] = jdata['training']['save_freq'] # be careful here, if one want to refine the model with open(args_train.INPUT, 'w') as fp: json.dump(jdata, fp, indent=4) train(args_train) diff --git a/source/train/main.py b/source/train/main.py index 248c33f961..bd5fbc1d8a 100644 --- a/source/train/main.py +++ b/source/train/main.py @@ -69,7 +69,7 @@ def main () : help='the input parameter file in json or yaml format') parser_compress.add_argument('-i', "--input", default = "frozen_model.pb", type=str, help = "the original model") - parser_compress.add_argument("-o","--output", default = "frozen_model_tab.pb", type=str, + parser_compress.add_argument("-o","--output", default = "frozen_model_compress.pb", type=str, help='the compressed model') parser_compress.add_argument('-t', '--table-info', nargs='+', default = [5, 0.01, 0.1, 1], type=float) parser_compress.add_argument("-d", "--folder", type=str, default = ".", From 426efdc1aa9f669fbfbe512c506eb08b266c54d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 4 Feb 2021 15:02:21 +0100 Subject: [PATCH 090/562] add requirements file --- requirements.txt | 5 +++++ setup.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000..0e8ce85ec8 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +numpy +scipy +pyyaml +dargs +typing_extensions \ No newline at end of file diff --git a/setup.py b/setup.py index 71848c6011..41b4e048a7 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ from skbuild.exceptions import SKBuildError # define constants -INSTALL_REQUIRES = ["numpy", "scipy", "pyyaml", "dargs", "typing_extensions"] +INSTALL_REQUIRES = (Path(__file__).parent / "requirements.txt").read_text().splitlines() setup_requires = ["setuptools_scm", "scikit-build"] # read readme to markdown From dddeb658f28a88b2a88f78bd35c7df9032af367e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 4 Feb 2021 16:29:16 +0100 Subject: [PATCH 091/562] trigerr new actions lint --- source/train/Local.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/train/Local.py b/source/train/Local.py index 1b1ddee931..e44e93806d 100644 --- a/source/train/Local.py +++ b/source/train/Local.py @@ -23,4 +23,4 @@ def get_resource() -> Tuple[str, List[str], Optional[List[int]]]: else: gpus = [int(gpu) for gpu in gpus_env.split(",")] - return nodename, nodelist, gpus + return nodename, nodelist, gpus From 213c06370edf3ee51a05f6313316ccb8e60645eb Mon Sep 17 00:00:00 2001 From: marian-code Date: Thu, 4 Feb 2021 18:23:16 +0100 Subject: [PATCH 092/562] trigger actions lint --- source/train/Local.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/train/Local.py b/source/train/Local.py index e44e93806d..1b1ddee931 100644 --- a/source/train/Local.py +++ b/source/train/Local.py @@ -23,4 +23,4 @@ def get_resource() -> Tuple[str, List[str], Optional[List[int]]]: else: gpus = [int(gpu) for gpu in gpus_env.split(",")] - return nodename, nodelist, gpus + return nodename, nodelist, gpus From 49afc73506d0ac26154eddc9d0ada60e6d1a535c Mon Sep 17 00:00:00 2001 From: denghuilu Date: Fri, 5 Feb 2021 11:12:03 +0800 Subject: [PATCH 093/562] change the class name from DataInfo to EnvMatStat --- .../utils/{data_info.py => env_mat_stat.py} | 21 +++++--- deepmd/utils/tabulate.py | 49 ++++++++++--------- source/op/CMakeLists.txt | 2 +- source/op/{data_info.cc => env_mat_stat.cc} | 10 ++-- source/train/Trainer.py | 6 +-- 5 files changed, 51 insertions(+), 37 deletions(-) rename deepmd/utils/{data_info.py => env_mat_stat.py} (91%) rename source/op/{data_info.cc => env_mat_stat.cc} (98%) diff --git a/deepmd/utils/data_info.py b/deepmd/utils/env_mat_stat.py similarity index 91% rename from deepmd/utils/data_info.py rename to deepmd/utils/env_mat_stat.py index 0e760f9c1b..a77ce0ab62 100644 --- a/deepmd/utils/data_info.py +++ b/deepmd/utils/env_mat_stat.py @@ -7,7 +7,7 @@ from deepmd.env import default_tf_session_config from deepmd.RunOptions import global_np_float_precision -class DataInfo(): +class EnvMatStat(): """ Class for getting training data information. It loads data from DeepmdData object, and measures the data info, including neareest nbor distance between atoms, max nbor size of atoms and the output data range of the environment matrix. @@ -60,7 +60,7 @@ def __init__(self, self.sel_a = sel self.sel_r = [ 0 for ii in range(len(self.sel_a)) ] descrpt, descrpt_deriv, rij, nlist, self.distance, self.max_nbor_size, self.table_range \ - = op_module.data_info_se_a(self.place_holders['coord'], + = op_module.env_mat_stat_se_a(self.place_holders['coord'], self.place_holders['type'], self.place_holders['natoms_vec'], self.place_holders['box'], @@ -74,8 +74,8 @@ def __init__(self, sel_r = self.sel_r) self.sub_sess = tf.Session(graph = sub_graph, config=default_tf_session_config) - def data_info(self, - data) -> Tuple[float, int, list]: + def env_mat_stat(self, + data) -> Tuple[float, int, List[float]]: """ get the data info of the training data, including neareest nbor distance between atoms, max nbor size of atoms and the output data range of the environment matrix @@ -83,6 +83,15 @@ def data_info(self, ---------- data Class for manipulating many data systems. It is implemented with the help of DeepmdData. + + Returns + ------- + distance + The neareest nbor distance between atoms + max_nbor_size + The max nbor size of atoms + table_range + The output data range of the environment matrix """ self.lower = 0.0 self.upper = 0.0 @@ -127,6 +136,6 @@ def data_info(self, print('# DEEPMD: training data with upper boundary: ' + str(self.upper)) print('# DEEPMD: training data with min distance: ' + str(self.dist)) print('# DEEPMD: training data with max nborsize: ' + str(self.max_nbor)) - - return self.distance, self.max_nbor_size, [self.lower, self.upper] + table_range = [self.lower, self.upper] + return self.distance, self.max_nbor_size, table_range \ No newline at end of file diff --git a/deepmd/utils/tabulate.py b/deepmd/utils/tabulate.py index 35a5603ce9..57ffc0cb5e 100644 --- a/deepmd/utils/tabulate.py +++ b/deepmd/utils/tabulate.py @@ -34,16 +34,16 @@ def __init__(self, self.data_type = data_type self.type_one_side = type_one_side - self.graph, self.graph_def = self.load_graph() + self.graph, self.graph_def = self._load_graph() self.sess = tf.Session(graph = self.graph) - self.sub_graph, self.sub_graph_def = self.load_sub_graph() + self.sub_graph, self.sub_graph_def = self._load_sub_graph() self.sub_sess = tf.Session(graph = self.sub_graph) self.sel_a = self.graph.get_operation_by_name('DescrptSeA').get_attr('sel_a') - self.ntypes = self.get_tensor_value(self.graph.get_tensor_by_name ('descrpt_attr/ntypes:0')) + self.ntypes = self._get_tensor_value(self.graph.get_tensor_by_name ('descrpt_attr/ntypes:0')) - self.filter_variable_nodes = self.load_matrix_node() + self.filter_variable_nodes = self._load_matrix_node() self.layer_size = int(len(self.filter_variable_nodes) / (self.ntypes * self.ntypes * 2)) self.table_size = self.ntypes * self.ntypes if type_one_side : @@ -51,8 +51,8 @@ def __init__(self, self.table_size = self.ntypes # self.value_type = self.filter_variable_nodes["filter_type_0/matrix_1_0"].dtype #"filter_type_0/matrix_1_0" must exit~ # get trained variables - self.bias = self.get_bias() - self.matrix = self.get_matrix() + self.bias = self._get_bias() + self.matrix = self._get_matrix() # self.matrix_layer_3 must exist # self.data_type = type(self.matrix["layer_1"][0][0][0]) assert self.matrix["layer_1"][0].size > 0, "no matrix exist in matrix array!" @@ -62,7 +62,7 @@ def __init__(self, # TODO: Need a check function to determine if the current model is properly - def load_graph(self): + def _load_graph(self): graph_def = tf.GraphDef() with open(self.model_file, "rb") as f: graph_def.ParseFromString(f.read()) @@ -70,19 +70,19 @@ def load_graph(self): tf.import_graph_def(graph_def, name = "") return graph, graph_def - def load_sub_graph(self): + def _load_sub_graph(self): sub_graph_def = tf.GraphDef() with tf.Graph().as_default() as sub_graph: tf.import_graph_def(sub_graph_def, name = "") return sub_graph, sub_graph_def - def get_tensor_value(self, tensor) : + def _get_tensor_value(self, tensor) : with self.sess.as_default(): self.sess.run(tensor) value = tensor.eval() return value - def load_matrix_node(self): + def _load_matrix_node(self): matrix_node = {} matrix_node_pattern = "filter_type_\d+/matrix_\d+_\d+|filter_type_\d+/bias_\d+_\d+|filter_type_\d+/idt_\d+_\d+|filter_type_all/matrix_\d+_\d+|filter_type_all/bias_\d+_\d+|filter_type_all/idt_\d+_\d" for node in self.graph_def.node: @@ -92,7 +92,7 @@ def load_matrix_node(self): assert key.find('bias') > 0 or key.find('matrix') > 0, "currently, only support weight matrix and bias matrix at the tabulation op!" return matrix_node - def get_bias(self): + def _get_bias(self): bias = {} for layer in range(1, self.layer_size + 1): bias["layer_" + str(layer)] = [] @@ -108,7 +108,7 @@ def get_bias(self): bias["layer_" + str(layer)].append(np.reshape(tensor_value, tensor_shape).astype(self.data_type)) return bias - def get_matrix(self): + def _get_matrix(self): matrix = {} for layer in range(1, self.layer_size + 1): matrix["layer_" + str(layer)] = [] @@ -124,7 +124,12 @@ def get_matrix(self): matrix["layer_" + str(layer)].append(np.reshape(tensor_value, tensor_shape).astype(self.data_type)) return matrix - def build(self, lower, upper, _max, stride0, stride1): + def build(self, + lower, + upper, + _max, + stride0, + stride1) -> None: """ Build the tables for model compression @@ -148,9 +153,9 @@ def build(self, lower, upper, _max, stride0, stride1): xx = np.append(xx, np.arange(upper, _max, stride1, dtype = self.data_type)) xx = np.append(xx, np.array([_max], dtype = self.data_type)) self.nspline = int((upper - lower) / stride0 + (_max - upper) / stride1) - + for ii in range(self.table_size): - vv, dd, d2 = self.make_data(xx, ii) + vv, dd, d2 = self._make_data(xx, ii) if self.type_one_side: net = "filter_-1_net_" + str(int(ii)) else: @@ -171,34 +176,34 @@ def build(self, lower, upper, _max, stride0, stride1): self.data[net][jj][kk * 6 + 5] = (1 / (2 * tt * tt * tt * tt * tt)) * (12 * hh - 6 * (dd[jj + 1][kk] + dd[jj][kk]) * tt + (d2[jj + 1][kk] - d2[jj][kk]) * tt * tt) # one-by-one executions - def make_data(self, xx, idx): + def _make_data(self, xx, idx): with self.sub_graph.as_default(): with self.sub_sess.as_default(): xx = tf.reshape(xx, [xx.size, -1]) for layer in range(self.layer_size): if layer == 0: - yy = self.layer_0(xx, self.matrix["layer_" + str(layer + 1)][idx], self.bias["layer_" + str(layer + 1)][idx]) + yy = self._layer_0(xx, self.matrix["layer_" + str(layer + 1)][idx], self.bias["layer_" + str(layer + 1)][idx]) dy = op_module.unaggregated_dy_dx_s(yy, self.matrix["layer_" + str(layer + 1)][idx]) dy2 = op_module.unaggregated_dy2_dx_s(yy, dy, self.matrix["layer_" + str(layer + 1)][idx]) else: - tt, yy = self.layer_1(yy, self.matrix["layer_" + str(layer + 1)][idx], self.bias["layer_" + str(layer + 1)][idx]) + tt, yy = self._layer_1(yy, self.matrix["layer_" + str(layer + 1)][idx], self.bias["layer_" + str(layer + 1)][idx]) dz = op_module.unaggregated_dy_dx(yy - tt, self.matrix["layer_" + str(layer + 1)][idx], dy) dy2 = op_module.unaggregated_dy2_dx(yy - tt, self.matrix["layer_" + str(layer + 1)][idx], dz, dy, dy2) dy = dz - + vv = yy.eval() dd = dy.eval() d2 = dy2.eval() return vv, dd, d2 - def layer_0(self, x, w, b): + def _layer_0(self, x, w, b): return tf.nn.tanh(tf.matmul(x, w) + b) - def layer_1(self, x, w, b): + def _layer_1(self, x, w, b): t = tf.concat([x, x], axis = 1) return t, tf.nn.tanh(tf.matmul(x, w) + b) + t - def save_data(self): + def _save_data(self): for ii in range(self.ntypes * self.ntypes): net = "filter_" + str(int(ii / self.ntypes)) + "_net_" + str(int(ii % self.ntypes)) np.savetxt('data_' + str(int(ii)), self.data[net]) diff --git a/source/op/CMakeLists.txt b/source/op/CMakeLists.txt index 0e10c24bb4..da18377683 100644 --- a/source/op/CMakeLists.txt +++ b/source/op/CMakeLists.txt @@ -3,7 +3,7 @@ set(OP_LIB ${PROJECT_SOURCE_DIR}/lib/src/SimulationRegion.cpp ${PROJECT_SOURCE_DIR}/lib/src/NeighborList.cpp) set (OP_CXX_FLAG -D_GLIBCXX_USE_CXX11_ABI=${OP_CXX_ABI} ) -file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc descrpt_se_r.cc tab_inter.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc gelu.cc map_aparam.cc data_info.cc unaggregated_grad.cc tabulate.cc) +file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc descrpt_se_r.cc tab_inter.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc gelu.cc map_aparam.cc env_mat_stat.cc unaggregated_grad.cc tabulate.cc) file(GLOB OP_CUDA_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a_multi_device.cc descrpt_se_r_multi_device.cc tab_inter.cc prod_force_se_a_multi_device.cc prod_virial_se_a_multi_device.cc prod_force_se_r_multi_device.cc prod_virial_se_r_multi_device.cc soft_min.cc soft_min_force.cc soft_min_virial.cc gelu_multi_device.cc tabulate_multi_device.cc) file(GLOB OP_GRADS_SRC prod_force_grad.cc prod_force_se_a_grad.cc prod_force_se_r_grad.cc prod_virial_grad.cc prod_virial_se_a_grad.cc prod_virial_se_r_grad.cc soft_min_force_grad.cc soft_min_virial_grad.cc ) file(GLOB OP_PY *.py) diff --git a/source/op/data_info.cc b/source/op/env_mat_stat.cc similarity index 98% rename from source/op/data_info.cc rename to source/op/env_mat_stat.cc index 12df043918..c90dc0b92f 100644 --- a/source/op/data_info.cc +++ b/source/op/env_mat_stat.cc @@ -15,7 +15,7 @@ using namespace tensorflow; using CPUDevice = Eigen::ThreadPoolDevice; using GPUDevice = Eigen::GpuDevice; -REGISTER_OP("DataInfoSeA") +REGISTER_OP("EnvMatStatSeA") .Attr("T: {float, double}") .Input("coord: T") //atomic coordinates .Input("type: int32") //atomic type @@ -38,9 +38,9 @@ REGISTER_OP("DataInfoSeA") .Output("table_range: T"); template -class DataInfoSeAOp : public OpKernel { +class EnvMatStatSeAOp : public OpKernel { public: - explicit DataInfoSeAOp(OpKernelConstruction* context) : OpKernel(context) { + explicit EnvMatStatSeAOp(OpKernelConstruction* context) : OpKernel(context) { OP_REQUIRES_OK(context, context->GetAttr("rcut_a", &rcut_a)); OP_REQUIRES_OK(context, context->GetAttr("rcut_r", &rcut_r)); OP_REQUIRES_OK(context, context->GetAttr("rcut_r_smth", &rcut_r_smth)); @@ -402,7 +402,7 @@ class DataInfoSeAOp : public OpKernel { #define REGISTER_CPU(T) \ REGISTER_KERNEL_BUILDER( \ - Name("DataInfoSeA").Device(DEVICE_CPU).TypeConstraint("T"), \ - DataInfoSeAOp); + Name("EnvMatStatSeA").Device(DEVICE_CPU).TypeConstraint("T"), \ + EnvMatStatSeAOp); REGISTER_CPU(float); REGISTER_CPU(double); \ No newline at end of file diff --git a/source/train/Trainer.py b/source/train/Trainer.py index ce434ae467..fd4b3eac42 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -19,7 +19,7 @@ from deepmd.Model import Model, WFCModel, DipoleModel, PolarModel, GlobalPolarModel from deepmd.loss import EnerStdLoss, EnerDipoleLoss, TensorLoss from deepmd.utils.learning_rate import LearningRateExp -from deepmd.utils.data_info import DataInfo +from deepmd.utils.env_mat_stat import EnvMatStat from tensorflow.python.client import timeline from deepmd.env import op_module @@ -278,11 +278,11 @@ def build (self, assert hasattr(self.descrpt, 'max_nbor_size'), "Compression error: descrpt must have attr max_nbor_size" assert hasattr(self.descrpt, 'table_range'), "Compression error: descrpt must have attr table_range" if self.descrpt_type == 'se_a': - info = DataInfo(self.descrpt_type, self.descrpt.ntypes, self.descrpt.rcut_r, self.descrpt.rcut_r_smth, self.descrpt.sel_a, self.descrpt.davg, self.descrpt.dstd) + stat = EnvMatStat(self.descrpt_type, self.descrpt.ntypes, self.descrpt.rcut_r, self.descrpt.rcut_r_smth, self.descrpt.sel_a, self.descrpt.davg, self.descrpt.dstd) else: raise RuntimeError ("Model compression error: descriptor type must be se_a!") self.descrpt.distance, self.descrpt.max_nbor_size, self.descrpt.table_range\ - = info.data_info(data) + = stat.env_mat_stat(data) worker_device = "/job:%s/task:%d/%s" % (self.run_opt.my_job_name, self.run_opt.my_task_index, From 5885eed8c86459c0669785d0a9b4b9969a3c4b81 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Fri, 5 Feb 2021 21:37:47 +0800 Subject: [PATCH 094/562] optimize the interface of EnvMatStat class --- deepmd/descriptor/se_a.py | 65 ++++++++++------- deepmd/utils/env_mat_stat.py | 45 +++++------- source/op/env_mat_stat.cc | 137 +++++++++++++++-------------------- source/train/Trainer.py | 37 ++++++---- source/train/compress.py | 7 +- source/train/main.py | 2 +- 6 files changed, 145 insertions(+), 148 deletions(-) diff --git a/deepmd/descriptor/se_a.py b/deepmd/descriptor/se_a.py index 2ca03378dd..e40210de1a 100644 --- a/deepmd/descriptor/se_a.py +++ b/deepmd/descriptor/se_a.py @@ -28,10 +28,7 @@ def __init__ (self, exclude_types: List[int] = [], set_davg_zero: bool = False, activation_function: str = 'tanh', - precision: str = 'default', - compress: bool = False, - model_file: str = 'frozen_model.pb', - table_info: list = [5, 0.01, 0.1, -1] + precision: str = 'default' ) -> None: """ Constructor @@ -65,12 +62,6 @@ def __init__ (self, The activation function in the embedding net. Supported options are {0} precision The precision of the embedding net parameters. Supported options are {1} - compress - Try to compress the embedding nets. Otherwise, building original embedding nets - model_file - The original frozen model, that will be compressed. - table_info - The data info of tabulation. """ self.sel_a = sel self.rcut_r = rcut @@ -108,17 +99,8 @@ def __init__ (self, self.useBN = False self.dstd = None self.davg = None + self.compress = False - # compress config - self.compress = compress - self.model_file = model_file - self.table_info = table_info - if self.compress: - self.distance = 100.0 - self.max_nbor_size = 0 - self.table_range = [-1, 20] - self.table = DeepTabulate(self.model_file, self.filter_np_precision, self.type_one_side) - self.place_holders = {} avg_zero = np.zeros([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) std_ones = np.ones ([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) @@ -248,6 +230,37 @@ def compute_input_stats (self, self.davg = np.array(all_davg) self.dstd = np.array(all_dstd) + def enable_compression(self, + distance, + max_nbor_size, + env_mat_range, + model_file = 'frozon_model.pb', + table_config = [5, 0.01, 0.1, -1] + ) -> None: + """ + Reveive the statisitcs (distance, max_nbor_size and env_mat_range) of the training data. + + Parameters + ---------- + distance + The nearest nbor distance between atoms + max_nbor_size + The max nbor size of atoms + env_mat_range + The output data range of the environment matrix + model_file + The original frozen model, that will be compressed + table_info + The configuration of the tabulation + """ + self.compress = True + self.model_file = model_file + self.table_config = table_config + self.distance = distance + self.max_nbor_size = max_nbor_size + self.env_mat_range = env_mat_range + self.table = DeepTabulate(self.model_file, self.filter_np_precision, self.type_one_side) + def build (self, coord_ : tf.Tensor, @@ -348,13 +361,13 @@ def build (self, self.nlist = tf.identity(self.nlist, name = 'o_nlist') if self.compress: - self.lower = math.floor(self.table_range[0]) - self.upper = math.ceil(self.table_range[1]) + self.lower = math.floor(self.env_mat_range[0]) + self.upper = math.ceil(self.env_mat_range[1]) self.table.build(self.lower, self.upper, - self.upper * self.table_info[0], - self.table_info[1], - self.table_info[2]) + self.upper * self.table_config[0], + self.table_config[1], + self.table_config[2]) self.dout, self.qmat = self._pass_filter(self.descrpt_reshape, atype, @@ -547,7 +560,7 @@ def _filter(self, xyz_scatter = tf.reshape(tf.slice(inputs_reshape, [0,0],[-1,1]),[-1,1]) # with (natom x nei_type_i) x out_size if self.compress and (type_input, type_i) not in self.exclude_types: - info = [self.lower, self.upper, self.upper * self.table_info[0], self.table_info[1], self.table_info[2], self.table_info[3]] + info = [self.lower, self.upper, self.upper * self.table_config[0], self.table_config[1], self.table_config[2], self.table_config[3]] if self.type_one_side: net = 'filter_-1_net_' + str(type_i) else: diff --git a/deepmd/utils/env_mat_stat.py b/deepmd/utils/env_mat_stat.py index a77ce0ab62..4096024007 100644 --- a/deepmd/utils/env_mat_stat.py +++ b/deepmd/utils/env_mat_stat.py @@ -40,9 +40,9 @@ def __init__(self, dstd Standard deviation of training data """ - self.ntypes = ntypes self.davg = davg self.dstd = dstd + self.ntypes = ntypes self.descrpt_type = descrpt_type assert self.descrpt_type == 'se_a', 'Model compression error: descriptor type must be se_a!' self.place_holders = {} @@ -53,29 +53,24 @@ def __init__(self, self.place_holders['type'] = tf.placeholder(tf.int32, [None, None], name='t_type') self.place_holders['natoms_vec'] = tf.placeholder(tf.int32, [self.ntypes+2], name='t_natoms') self.place_holders['default_mesh'] = tf.placeholder(tf.int32, [None], name='t_mesh') - if self.descrpt_type == 'se_a': - self.rcut_a = -1 - self.rcut_r = rcut - self.rcut_r_smth = rcut_smth - self.sel_a = sel - self.sel_r = [ 0 for ii in range(len(self.sel_a)) ] - descrpt, descrpt_deriv, rij, nlist, self.distance, self.max_nbor_size, self.table_range \ - = op_module.env_mat_stat_se_a(self.place_holders['coord'], - self.place_holders['type'], - self.place_holders['natoms_vec'], - self.place_holders['box'], - self.place_holders['default_mesh'], - self.place_holders['avg'], - self.place_holders['std'], - rcut_a = self.rcut_a, - rcut_r = self.rcut_r, - rcut_r_smth = self.rcut_r_smth, - sel_a = self.sel_a, - sel_r = self.sel_r) + self.sel = sel + self.rcut = rcut + self.rcut_smth = rcut_smth + self.distance, self.max_nbor_size, self.table_range \ + = op_module.env_mat_stat(self.place_holders['coord'], + self.place_holders['type'], + self.place_holders['natoms_vec'], + self.place_holders['box'], + self.place_holders['default_mesh'], + self.place_holders['avg'], + self.place_holders['std'], + sel = self.sel, + rcut = self.rcut, + rcut_smth = self.rcut_smth) self.sub_sess = tf.Session(graph = sub_graph, config=default_tf_session_config) def env_mat_stat(self, - data) -> Tuple[float, int, List[float]]: + data) -> Tuple[float, int, List[float]]: """ get the data info of the training data, including neareest nbor distance between atoms, max nbor size of atoms and the output data range of the environment matrix @@ -87,10 +82,10 @@ def env_mat_stat(self, Returns ------- distance - The neareest nbor distance between atoms + The nearest nbor distance between atoms max_nbor_size The max nbor size of atoms - table_range + env_mat_range The output data range of the environment matrix """ self.lower = 0.0 @@ -136,6 +131,6 @@ def env_mat_stat(self, print('# DEEPMD: training data with upper boundary: ' + str(self.upper)) print('# DEEPMD: training data with min distance: ' + str(self.dist)) print('# DEEPMD: training data with max nborsize: ' + str(self.max_nbor)) - table_range = [self.lower, self.upper] - return self.distance, self.max_nbor_size, table_range + env_mat_range = [self.lower, self.upper] + return self.distance, self.max_nbor_size, env_mat_range \ No newline at end of file diff --git a/source/op/env_mat_stat.cc b/source/op/env_mat_stat.cc index c90dc0b92f..58e555083c 100644 --- a/source/op/env_mat_stat.cc +++ b/source/op/env_mat_stat.cc @@ -15,7 +15,7 @@ using namespace tensorflow; using CPUDevice = Eigen::ThreadPoolDevice; using GPUDevice = Eigen::GpuDevice; -REGISTER_OP("EnvMatStatSeA") +REGISTER_OP("EnvMatStat") .Attr("T: {float, double}") .Input("coord: T") //atomic coordinates .Input("type: int32") //atomic type @@ -24,37 +24,24 @@ REGISTER_OP("EnvMatStatSeA") .Input("mesh : int32") .Input("davg: T") //average value of data .Input("dstd: T") //standard deviation - .Attr("rcut_a: float") //no use - .Attr("rcut_r: float") - .Attr("rcut_r_smth: float") - .Attr("sel_a: list(int)") - .Attr("sel_r: list(int)") //all zero - .Output("descrpt: T") - .Output("descrpt_deriv: T") - .Output("rij: T") - .Output("nlist: int32") + .Attr("rcut: float") //no use + .Attr("rcut_smth: float") + .Attr("sel: list(int)") .Output("distance: T") .Output("max_nbor_size: int32") - .Output("table_range: T"); + .Output("env_stat_range: T"); template -class EnvMatStatSeAOp : public OpKernel { +class EnvMatStatOp : public OpKernel { public: - explicit EnvMatStatSeAOp(OpKernelConstruction* context) : OpKernel(context) { - OP_REQUIRES_OK(context, context->GetAttr("rcut_a", &rcut_a)); - OP_REQUIRES_OK(context, context->GetAttr("rcut_r", &rcut_r)); - OP_REQUIRES_OK(context, context->GetAttr("rcut_r_smth", &rcut_r_smth)); - OP_REQUIRES_OK(context, context->GetAttr("sel_a", &sel_a)); - OP_REQUIRES_OK(context, context->GetAttr("sel_r", &sel_r)); - cum_sum (sec_a, sel_a); - cum_sum (sec_r, sel_r); - ndescrpt_a = sec_a.back() * 4; - ndescrpt_r = sec_r.back() * 1; - ndescrpt = ndescrpt_a + ndescrpt_r; - nnei_a = sec_a.back(); - nnei_r = sec_r.back(); - nnei = nnei_a + nnei_r; - fill_nei_a = (rcut_a < 0); + explicit EnvMatStatOp(OpKernelConstruction* context) : OpKernel(context) { + OP_REQUIRES_OK(context, context->GetAttr("rcut", &rcut)); + OP_REQUIRES_OK(context, context->GetAttr("rcut_smth", &rcut_smth)); + OP_REQUIRES_OK(context, context->GetAttr("sel", &sel)); + cum_sum (sec, sel); + ndescrpt = sec.back() * 4; + nnei = sec.back(); + fill_nei_a = true; count_nei_idx_overflow = 0; } @@ -78,8 +65,7 @@ class EnvMatStatSeAOp : public OpKernel { OP_REQUIRES (context, (mesh_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of mesh should be 1")); OP_REQUIRES (context, (avg_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of avg should be 2")); OP_REQUIRES (context, (std_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of std should be 2")); - OP_REQUIRES (context, (fill_nei_a), errors::InvalidArgument ("Rotational free descriptor only support the case rcut_a < 0")); - OP_REQUIRES (context, (sec_r.back() == 0), errors::InvalidArgument ("Rotational free descriptor only support all-angular information: sel_r should be all zero.")); + OP_REQUIRES (context, (fill_nei_a), errors::InvalidArgument ("Rotational free descriptor only support the case -1 < 0")); OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); auto natoms = natoms_tensor .flat(); @@ -151,24 +137,19 @@ class EnvMatStatSeAOp : public OpKernel { TensorShape table_range_shape ; table_range_shape.AddDim (nloc * nnei); - int context_output_index = 0; - Tensor* descrpt_tensor = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - descrpt_shape, - &descrpt_tensor)); - Tensor* descrpt_deriv_tensor = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - descrpt_deriv_shape, - &descrpt_deriv_tensor)); - Tensor* rij_tensor = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - rij_shape, - &rij_tensor)); - Tensor* nlist_tensor = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - nlist_shape, - &nlist_tensor)); + Tensor descrpt_tensor; + OP_REQUIRES_OK(context, context->allocate_temp(DT_DOUBLE, descrpt_shape, &descrpt_tensor)); + Tensor descrpt_deriv_tensor; + OP_REQUIRES_OK(context, context->allocate_temp(DT_DOUBLE, descrpt_deriv_shape, &descrpt_deriv_tensor)); + + Tensor rij_tensor; + OP_REQUIRES_OK(context, context->allocate_temp(DT_DOUBLE, rij_shape, &rij_tensor)); + + Tensor nlist_tensor; + OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, nlist_shape, &nlist_tensor)); + + int context_output_index = 0; Tensor* distance_tensor = NULL; OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, distance_shape, @@ -188,10 +169,10 @@ class EnvMatStatSeAOp : public OpKernel { auto mesh = mesh_tensor .flat(); auto avg = avg_tensor .matrix(); auto std = std_tensor .matrix(); - auto descrpt = descrpt_tensor ->matrix(); - auto descrpt_deriv = descrpt_deriv_tensor ->matrix(); - auto rij = rij_tensor ->matrix(); - auto nlist = nlist_tensor ->matrix(); + auto descrpt = descrpt_tensor .matrix(); + auto descrpt_deriv = descrpt_deriv_tensor .matrix(); + auto rij = rij_tensor .matrix(); + auto nlist = nlist_tensor .matrix(); auto distance = distance_tensor ->flat(); // find a potential bug here! auto max_nbor_size = max_nbor_size_tensor ->flat(); @@ -212,8 +193,7 @@ class EnvMatStatSeAOp : public OpKernel { // if (type(0, ii) > max_type_v) max_type_v = type(0, ii); // } // int ntypes = max_type_v + 1; - OP_REQUIRES (context, (ntypes == int(sel_a.size())), errors::InvalidArgument ("number of types should match the length of sel array")); - OP_REQUIRES (context, (ntypes == int(sel_r.size())), errors::InvalidArgument ("number of types should match the length of sel array")); + OP_REQUIRES (context, (ntypes == int(sel.size())), errors::InvalidArgument ("number of types should match the length of sel array")); for (int kk = 0; kk < nsamples; ++kk){ // set region @@ -278,14 +258,14 @@ class EnvMatStatSeAOp : public OpKernel { std::vector ext_end = {mesh(10-1), mesh(11-1), mesh(12-1)}; std::vector global_grid (3); for (int dd = 0; dd < 3; ++dd) global_grid[dd] = nat_end[dd] - nat_stt[dd]; - ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, rcut_a, rcut_r, nat_stt, nat_end, ext_stt, ext_end, region, global_grid); + ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, -1, rcut, nat_stt, nat_end, ext_stt, ext_end, region, global_grid); } else if (nei_mode == 1) { // std::cout << "I'm in nei_mode 1" << std::endl; std::vector bk_d_coord3 = d_coord3; std::vector bk_d_type = d_type; std::vector ncell, ngcell; - copy_coord(d_coord3, d_type, nlist_map, ncell, ngcell, bk_d_coord3, bk_d_type, rcut_r, region); + copy_coord(d_coord3, d_type, nlist_map, ncell, ngcell, bk_d_coord3, bk_d_type, rcut, region); b_nlist_map = true; std::vector nat_stt(3, 0); std::vector ext_stt(3), ext_end(3); @@ -293,10 +273,10 @@ class EnvMatStatSeAOp : public OpKernel { ext_stt[dd] = -ngcell[dd]; ext_end[dd] = ncell[dd] + ngcell[dd]; } - ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, rcut_a, rcut_r, nat_stt, ncell, ext_stt, ext_end, region, ncell); + ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, -1, rcut, nat_stt, ncell, ext_stt, ext_end, region, ncell); } else if (nei_mode == -1){ - ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, rcut_a, rcut_r, NULL); + ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, -1, rcut, NULL); } else { throw std::runtime_error("unknow neighbor mode"); @@ -310,9 +290,11 @@ class EnvMatStatSeAOp : public OpKernel { for (int ii = 0; ii < nloc; ++ii){ std::vector fmt_nlist_a; std::vector fmt_nlist_r; + std::vector sec_r(sec.size(), 0); + int ret = -1; if (fill_nei_a){ - if ((ret = format_nlist_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ + if ((ret = format_nlist_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut, sec, sec_r)) != -1){ if (count_nei_idx_overflow == 0) { std::cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << std::endl; flush(std::cout); @@ -337,36 +319,36 @@ class EnvMatStatSeAOp : public OpKernel { b_pbc, ii, fmt_nlist_a, - sec_a, - rcut_r_smth, - rcut_r); + sec, + rcut_smth, + rcut); // check sizes - assert (d_descrpt_a.size() == ndescrpt_a); - assert (d_descrpt_a_deriv.size() == ndescrpt_a * 3); - assert (d_rij_a.size() == nnei_a * 3); - assert (int(fmt_nlist_a.size()) == nnei_a); + assert (d_descrpt_a.size() == ndescrpt); + assert (d_descrpt_a_deriv.size() == ndescrpt * 3); + assert (d_rij_a.size() == nnei * 3); + assert (int(fmt_nlist_a.size()) == nnei); // std::cout << "min:\t" << (0 - avg(0, 0)) / std(0, 0) << std::endl; // if (counter % 1000 == 0) { // std::cout << "min:\t" << (0 - avg(0, 0)) / std(0, 0) << std::endl; // } // record outputs - for (int jj = 0; jj < ndescrpt_a; ++jj) { + for (int jj = 0; jj < ndescrpt; ++jj) { descrpt(kk, ii * ndescrpt + jj) = (d_descrpt_a[jj] - avg(d_type[ii], jj)) / std(d_type[ii], jj); if (jj % 4 == 0) { table_range(ii * nnei + jj / 4) = descrpt(kk, ii * ndescrpt + jj); } } - for (int jj = 0; jj < ndescrpt_a * 3; ++jj) { + for (int jj = 0; jj < ndescrpt * 3; ++jj) { descrpt_deriv(kk, ii * ndescrpt * 3 + jj) = d_descrpt_a_deriv[jj] / std(d_type[ii], jj/3); } - for (int jj = 0; jj < nnei_a * 3; ++jj){ + for (int jj = 0; jj < nnei * 3; ++jj){ rij (kk, ii * nnei * 3 + jj) = d_rij_a[jj]; if (jj % 3 == 0 && d_rij_a[jj] > 0) { distance(ii * nnei + jj / 3) = sqrt(d_rij_a[jj] * d_rij_a[jj] + d_rij_a[jj + 1] * d_rij_a[jj + 1] + d_rij_a[jj + 2] * d_rij_a[jj + 2]); } } - for (int jj = 0; jj < nnei_a; ++jj){ + for (int jj = 0; jj < nnei; ++jj){ int record = fmt_nlist_a[jj]; if (b_nlist_map && record >= 0) { record = nlist_map[record]; @@ -378,15 +360,12 @@ class EnvMatStatSeAOp : public OpKernel { } private: int counter = -1; - float rcut_a; - float rcut_r; - float rcut_r_smth; - std::vector sel_r; - std::vector sel_a; - std::vector sec_a; - std::vector sec_r; - int ndescrpt, ndescrpt_a, ndescrpt_r; - int nnei, nnei_a, nnei_r; + float rcut; + float rcut_smth; + std::vector sel; + std::vector sec; + int ndescrpt; + int nnei; bool fill_nei_a; int count_nei_idx_overflow; void @@ -402,7 +381,7 @@ class EnvMatStatSeAOp : public OpKernel { #define REGISTER_CPU(T) \ REGISTER_KERNEL_BUILDER( \ - Name("EnvMatStatSeA").Device(DEVICE_CPU).TypeConstraint("T"), \ - EnvMatStatSeAOp); + Name("EnvMatStat").Device(DEVICE_CPU).TypeConstraint("T"), \ + EnvMatStatOp); REGISTER_CPU(float); REGISTER_CPU(double); \ No newline at end of file diff --git a/source/train/Trainer.py b/source/train/Trainer.py index fd4b3eac42..671a69e4d0 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -89,14 +89,19 @@ def _init_param(self, jdata): model_param = j_must_have(jdata, 'model') descrpt_param = j_must_have(model_param, 'descriptor') fitting_param = j_must_have(model_param, 'fitting_net') - + self.model_param = model_param + self.descrpt_param = descrpt_param + self.descrpt_type = descrpt_param['type'] + if 'compress' in model_param: + self.compress_param = model_param['compress'] + # descriptor try: - self.descrpt_type = descrpt_param['type'] + descrpt_type = descrpt_param['type'] except KeyError: raise KeyError('the type of descriptor should be set by `type`') - if self.descrpt_type != 'hybrid': + if descrpt_type != 'hybrid': self.descrpt = _generate_descrpt_from_param_dict(descrpt_param) else : descrpt_list = [] @@ -116,19 +121,19 @@ def _init_param(self, jdata): # elif fitting_type == 'wfc': # self.fitting = WFCFitting(fitting_param, self.descrpt) elif fitting_type == 'dipole': - if self.descrpt_type == 'se_a': + if descrpt_type == 'se_a': self.fitting = DipoleFittingSeA(**fitting_param) else : raise RuntimeError('fitting dipole only supports descrptors: se_a') elif fitting_type == 'polar': - # if self.descrpt_type == 'loc_frame': + # if descrpt_type == 'loc_frame': # self.fitting = PolarFittingLocFrame(fitting_param, self.descrpt) - if self.descrpt_type == 'se_a': + if descrpt_type == 'se_a': self.fitting = PolarFittingSeA(**fitting_param) else : raise RuntimeError('fitting polar only supports descrptors: loc_frame and se_a') elif fitting_type == 'global_polar': - if self.descrpt_type == 'se_a': + if descrpt_type == 'se_a': self.fitting = GlobalPolarFittingSeA(**fitting_param) else : raise RuntimeError('fitting global_polar only supports descrptors: loc_frame and se_a') @@ -248,7 +253,6 @@ def _init_param(self, jdata): else : self.numb_fparam = 0 - def _message (self, msg) : self.run_opt.message(msg) @@ -273,16 +277,21 @@ def build (self, self.model.data_stat(data) - if hasattr(self.descrpt, 'compress') and self.descrpt.compress: - assert hasattr(self.descrpt, 'distance'), "Compression error: descrpt must have attr distance" - assert hasattr(self.descrpt, 'max_nbor_size'), "Compression error: descrpt must have attr max_nbor_size" - assert hasattr(self.descrpt, 'table_range'), "Compression error: descrpt must have attr table_range" + if 'compress' in self.model_param and self.compress_param['compress']: + assert hasattr(self.descrpt, 'davg'), "Model compression error: descriptor must have attr davg!" + assert hasattr(self.descrpt, 'dstd'), "Model compression error: descriptor must have attr dstd!" + assert hasattr(self.descrpt, 'ntypes'), "Model compression error: descriptor must have attr ntypes!" + assert 'sel' in self.descrpt_param, "Model compression error: descriptor must have attr sel!" + assert 'rcut' in self.descrpt_param, "Model compression error: descriptor must have attr rcut!" + assert 'rcut_smth' in self.descrpt_param, "Model compression error: descriptor must have attr rcut_smth!" if self.descrpt_type == 'se_a': - stat = EnvMatStat(self.descrpt_type, self.descrpt.ntypes, self.descrpt.rcut_r, self.descrpt.rcut_r_smth, self.descrpt.sel_a, self.descrpt.davg, self.descrpt.dstd) + stat = EnvMatStat(self.descrpt_type, self.descrpt.ntypes, self.descrpt_param['rcut'], self.descrpt_param['rcut_smth'], self.descrpt_param['sel'], self.descrpt.davg, self.descrpt.dstd) else: raise RuntimeError ("Model compression error: descriptor type must be se_a!") - self.descrpt.distance, self.descrpt.max_nbor_size, self.descrpt.table_range\ + + distance, max_nbor_size, env_mat_range\ = stat.env_mat_stat(data) + self.descrpt.enable_compression(distance, max_nbor_size, env_mat_range, self.compress_param['model_file'], self.compress_param['table_config']) # send the statistics of the training data and activate the descriptor compression mode worker_device = "/job:%s/task:%d/%s" % (self.run_opt.my_job_name, self.run_opt.my_task_index, diff --git a/source/train/compress.py b/source/train/compress.py index 64035d53ed..1f36f8e9e1 100644 --- a/source/train/compress.py +++ b/source/train/compress.py @@ -18,9 +18,10 @@ def compress(args): dump = 'input_v1_compat.json') jdata = normalize(jdata) - jdata['model']['descriptor']['compress'] = True - jdata['model']['descriptor']['model_file'] = args.input - jdata['model']['descriptor']['table_info'] = args.table_info + jdata['model']['compress'] = {} + jdata['model']['compress']['compress'] = True + jdata['model']['compress']['model_file'] = args.input + jdata['model']['compress']['table_config'] = args.table_config # check the descriptor info of the input file assert jdata['model']['descriptor']['type'] == 'se_a', 'Model compression error: descriptor type must be se_a!' diff --git a/source/train/main.py b/source/train/main.py index bd5fbc1d8a..9baaffce4e 100644 --- a/source/train/main.py +++ b/source/train/main.py @@ -71,7 +71,7 @@ def main () : help = "the original model") parser_compress.add_argument("-o","--output", default = "frozen_model_compress.pb", type=str, help='the compressed model') - parser_compress.add_argument('-t', '--table-info', nargs='+', default = [5, 0.01, 0.1, 1], type=float) + parser_compress.add_argument('-t', '--table-config', nargs='+', default = [5, 0.01, 0.1, 1], type=float) parser_compress.add_argument("-d", "--folder", type=str, default = ".", help="path to checkpoint folder") From 8588554e1d9a8e4eb036494a0d9728d1f0fec9bb Mon Sep 17 00:00:00 2001 From: denghuilu Date: Fri, 5 Feb 2021 22:08:14 +0800 Subject: [PATCH 095/562] use standard tensorflow op style for custome ops --- source/op/descrpt.cc | 2 +- source/op/descrpt_se_a_ef.cc | 70 +++++++++++------------------- source/op/descrpt_se_a_ef_para.cc | 71 +++++++++++-------------------- source/op/descrpt_se_a_ef_vert.cc | 70 +++++++++++------------------- source/op/map_aparam.cc | 36 ++++++---------- 5 files changed, 93 insertions(+), 156 deletions(-) diff --git a/source/op/descrpt.cc b/source/op/descrpt.cc index 71918b4a5a..201169f7f1 100644 --- a/source/op/descrpt.cc +++ b/source/op/descrpt.cc @@ -602,7 +602,7 @@ class DescrptOp : public OpKernel { #define REGISTER_CPU(T) \ REGISTER_KERNEL_BUILDER( \ - Name("Descrpt").Device(DEVICE_CPU).TypeConstraint("T"), \ + Name("Descrpt").Device(DEVICE_CPU).TypeConstraint("T"), \ DescrptOp); REGISTER_CPU(float); REGISTER_CPU(double); diff --git a/source/op/descrpt_se_a_ef.cc b/source/op/descrpt_se_a_ef.cc index b4a631b7cf..9aca7eb720 100644 --- a/source/op/descrpt_se_a_ef.cc +++ b/source/op/descrpt_se_a_ef.cc @@ -12,52 +12,30 @@ typedef double compute_t; using namespace tensorflow; // using namespace std; -#ifdef HIGH_PREC -typedef double VALUETYPE ; -#else -typedef float VALUETYPE ; -#endif +using CPUDevice = Eigen::ThreadPoolDevice; +using GPUDevice = Eigen::GpuDevice; -#ifdef HIGH_PREC REGISTER_OP("DescrptSeAEf") -.Input("coord: double") +.Attr("T: {float, double}") +.Input("coord: T") .Input("type: int32") .Input("natoms: int32") -.Input("box: double") +.Input("box: T") .Input("mesh: int32") -.Input("ef: double") -.Input("davg: double") -.Input("dstd: double") +.Input("ef: T") +.Input("davg: T") +.Input("dstd: T") .Attr("rcut_a: float") .Attr("rcut_r: float") .Attr("rcut_r_smth: float") .Attr("sel_a: list(int)") .Attr("sel_r: list(int)") -.Output("descrpt: double") -.Output("descrpt_deriv: double") -.Output("rij: double") +.Output("descrpt: T") +.Output("descrpt_deriv: T") +.Output("rij: T") .Output("nlist: int32"); -#else -REGISTER_OP("DescrptSeAEf") -.Input("coord: float") -.Input("type: int32") -.Input("natoms: int32") -.Input("box: float") -.Input("mesh: int32") -.Input("ef: float") -.Input("davg: float") -.Input("dstd: float") -.Attr("rcut_a: float") -.Attr("rcut_r: float") -.Attr("rcut_r_smth: float") -.Attr("sel_a: list(int)") -.Attr("sel_r: list(int)") -.Output("descrpt: float") -.Output("descrpt_deriv: float") -.Output("rij: float") -.Output("nlist: int32"); -#endif +template class DescrptSeAEfOp : public OpKernel { public: explicit DescrptSeAEfOp(OpKernelConstruction* context) : OpKernel(context) { @@ -186,16 +164,16 @@ class DescrptSeAEfOp : public OpKernel { nlist_shape, &nlist_tensor)); - auto coord = coord_tensor .matrix(); + auto coord = coord_tensor .matrix(); auto type = type_tensor .matrix(); - auto box = box_tensor .matrix(); + auto box = box_tensor .matrix(); auto mesh = mesh_tensor .flat(); - auto ef = ef_tensor .matrix(); - auto avg = avg_tensor .matrix(); - auto std = std_tensor .matrix(); - auto descrpt = descrpt_tensor ->matrix(); - auto descrpt_deriv = descrpt_deriv_tensor ->matrix(); - auto rij = rij_tensor ->matrix(); + auto ef = ef_tensor .matrix(); + auto avg = avg_tensor .matrix(); + auto std = std_tensor .matrix(); + auto descrpt = descrpt_tensor ->matrix(); + auto descrpt_deriv = descrpt_deriv_tensor ->matrix(); + auto rij = rij_tensor ->matrix(); auto nlist = nlist_tensor ->matrix(); // // check the types @@ -385,5 +363,9 @@ class DescrptSeAEfOp : public OpKernel { } }; -REGISTER_KERNEL_BUILDER(Name("DescrptSeAEf").Device(DEVICE_CPU), DescrptSeAEfOp); - +#define REGISTER_CPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("DescrptSeAEf").Device(DEVICE_CPU).TypeConstraint("T"), \ + DescrptSeAEfOp); +REGISTER_CPU(float); +REGISTER_CPU(double); diff --git a/source/op/descrpt_se_a_ef_para.cc b/source/op/descrpt_se_a_ef_para.cc index af17b3ca12..2dccb40ae3 100644 --- a/source/op/descrpt_se_a_ef_para.cc +++ b/source/op/descrpt_se_a_ef_para.cc @@ -11,53 +11,30 @@ typedef double compute_t; using namespace tensorflow; // using namespace std; +using CPUDevice = Eigen::ThreadPoolDevice; +using GPUDevice = Eigen::GpuDevice; -#ifdef HIGH_PREC -typedef double VALUETYPE ; -#else -typedef float VALUETYPE ; -#endif - -#ifdef HIGH_PREC -REGISTER_OP("DescrptSeAEfPara") -.Input("coord: double") -.Input("type: int32") -.Input("natoms: int32") -.Input("box: double") -.Input("mesh: int32") -.Input("ef: double") -.Input("davg: double") -.Input("dstd: double") -.Attr("rcut_a: float") -.Attr("rcut_r: float") -.Attr("rcut_r_smth: float") -.Attr("sel_a: list(int)") -.Attr("sel_r: list(int)") -.Output("descrpt: double") -.Output("descrpt_deriv: double") -.Output("rij: double") -.Output("nlist: int32"); -#else REGISTER_OP("DescrptSeAEfPara") -.Input("coord: float") +.Attr("T: {float, double}") +.Input("coord: T") .Input("type: int32") .Input("natoms: int32") -.Input("box: float") +.Input("box: T") .Input("mesh: int32") -.Input("ef: float") -.Input("davg: float") -.Input("dstd: float") +.Input("ef: T") +.Input("davg: T") +.Input("dstd: T") .Attr("rcut_a: float") .Attr("rcut_r: float") .Attr("rcut_r_smth: float") .Attr("sel_a: list(int)") .Attr("sel_r: list(int)") -.Output("descrpt: float") -.Output("descrpt_deriv: float") -.Output("rij: float") +.Output("descrpt: T") +.Output("descrpt_deriv: T") +.Output("rij: T") .Output("nlist: int32"); -#endif +template class DescrptSeAEfParaOp : public OpKernel { public: explicit DescrptSeAEfParaOp(OpKernelConstruction* context) : OpKernel(context) { @@ -186,16 +163,16 @@ class DescrptSeAEfParaOp : public OpKernel { nlist_shape, &nlist_tensor)); - auto coord = coord_tensor .matrix(); + auto coord = coord_tensor .matrix(); auto type = type_tensor .matrix(); - auto box = box_tensor .matrix(); + auto box = box_tensor .matrix(); auto mesh = mesh_tensor .flat(); - auto ef = ef_tensor .matrix(); - auto avg = avg_tensor .matrix(); - auto std = std_tensor .matrix(); - auto descrpt = descrpt_tensor ->matrix(); - auto descrpt_deriv = descrpt_deriv_tensor ->matrix(); - auto rij = rij_tensor ->matrix(); + auto ef = ef_tensor .matrix(); + auto avg = avg_tensor .matrix(); + auto std = std_tensor .matrix(); + auto descrpt = descrpt_tensor ->matrix(); + auto descrpt_deriv = descrpt_deriv_tensor ->matrix(); + auto rij = rij_tensor ->matrix(); auto nlist = nlist_tensor ->matrix(); // // check the types @@ -385,5 +362,9 @@ class DescrptSeAEfParaOp : public OpKernel { } }; -REGISTER_KERNEL_BUILDER(Name("DescrptSeAEfPara").Device(DEVICE_CPU), DescrptSeAEfParaOp); - +#define REGISTER_CPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("DescrptSeAEfPara").Device(DEVICE_CPU).TypeConstraint("T"), \ + DescrptSeAEfParaOp); +REGISTER_CPU(float); +REGISTER_CPU(double); diff --git a/source/op/descrpt_se_a_ef_vert.cc b/source/op/descrpt_se_a_ef_vert.cc index 1d416864e2..5734a8811f 100644 --- a/source/op/descrpt_se_a_ef_vert.cc +++ b/source/op/descrpt_se_a_ef_vert.cc @@ -12,52 +12,30 @@ typedef double compute_t; using namespace tensorflow; // using namespace std; -#ifdef HIGH_PREC -typedef double VALUETYPE ; -#else -typedef float VALUETYPE ; -#endif +using CPUDevice = Eigen::ThreadPoolDevice; +using GPUDevice = Eigen::GpuDevice; -#ifdef HIGH_PREC REGISTER_OP("DescrptSeAEfVert") -.Input("coord: double") +.Attr("T: {float, double}") +.Input("coord: T") .Input("type: int32") .Input("natoms: int32") -.Input("box: double") +.Input("box: T") .Input("mesh: int32") -.Input("ef: double") -.Input("davg: double") -.Input("dstd: double") +.Input("ef: T") +.Input("davg: T") +.Input("dstd: T") .Attr("rcut_a: float") .Attr("rcut_r: float") .Attr("rcut_r_smth: float") .Attr("sel_a: list(int)") .Attr("sel_r: list(int)") -.Output("descrpt: double") -.Output("descrpt_deriv: double") -.Output("rij: double") +.Output("descrpt: T") +.Output("descrpt_deriv: T") +.Output("rij: T") .Output("nlist: int32"); -#else -REGISTER_OP("DescrptSeAEfVert") -.Input("coord: float") -.Input("type: int32") -.Input("natoms: int32") -.Input("box: float") -.Input("mesh: int32") -.Input("ef: float") -.Input("davg: float") -.Input("dstd: float") -.Attr("rcut_a: float") -.Attr("rcut_r: float") -.Attr("rcut_r_smth: float") -.Attr("sel_a: list(int)") -.Attr("sel_r: list(int)") -.Output("descrpt: float") -.Output("descrpt_deriv: float") -.Output("rij: float") -.Output("nlist: int32"); -#endif +template class DescrptSeAEfVertOp : public OpKernel { public: explicit DescrptSeAEfVertOp(OpKernelConstruction* context) : OpKernel(context) { @@ -186,16 +164,16 @@ class DescrptSeAEfVertOp : public OpKernel { nlist_shape, &nlist_tensor)); - auto coord = coord_tensor .matrix(); + auto coord = coord_tensor .matrix(); auto type = type_tensor .matrix(); - auto box = box_tensor .matrix(); + auto box = box_tensor .matrix(); auto mesh = mesh_tensor .flat(); - auto ef = ef_tensor .matrix(); - auto avg = avg_tensor .matrix(); - auto std = std_tensor .matrix(); - auto descrpt = descrpt_tensor ->matrix(); - auto descrpt_deriv = descrpt_deriv_tensor ->matrix(); - auto rij = rij_tensor ->matrix(); + auto ef = ef_tensor .matrix(); + auto avg = avg_tensor .matrix(); + auto std = std_tensor .matrix(); + auto descrpt = descrpt_tensor ->matrix(); + auto descrpt_deriv = descrpt_deriv_tensor ->matrix(); + auto rij = rij_tensor ->matrix(); auto nlist = nlist_tensor ->matrix(); // // check the types @@ -385,5 +363,9 @@ class DescrptSeAEfVertOp : public OpKernel { } }; -REGISTER_KERNEL_BUILDER(Name("DescrptSeAEfVert").Device(DEVICE_CPU), DescrptSeAEfVertOp); - +#define REGISTER_CPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("DescrptSeAEfVert").Device(DEVICE_CPU).TypeConstraint("T"), \ + DescrptSeAEfVertOp); +REGISTER_CPU(float); +REGISTER_CPU(double); \ No newline at end of file diff --git a/source/op/map_aparam.cc b/source/op/map_aparam.cc index 43bc8a011f..608f5f614b 100644 --- a/source/op/map_aparam.cc +++ b/source/op/map_aparam.cc @@ -6,32 +6,19 @@ using namespace tensorflow; // using namespace std; -#ifdef HIGH_PREC -typedef double VALUETYPE; -#else -typedef float VALUETYPE; -#endif +using CPUDevice = Eigen::ThreadPoolDevice; +using GPUDevice = Eigen::GpuDevice; -#ifdef HIGH_PREC REGISTER_OP("MapAparam") -.Input("aparam: double") +.Attr("T: {float, double}") +.Input("aparam: T") .Input("nlist: int32") .Input("natoms: int32") .Attr("n_a_sel: int") .Attr("n_r_sel: int") -.Output("output: double"); -#else -REGISTER_OP("MapAparam") -.Input("aparam: float") -.Input("nlist: int32") -.Input("natoms: int32") -.Attr("n_a_sel: int") -.Attr("n_r_sel: int") -.Output("mapped: float"); -#endif - -using namespace tensorflow; +.Output("output: T"); +template class MapAparamOp : public OpKernel { public: explicit MapAparamOp(OpKernelConstruction* context) : OpKernel(context) { @@ -73,9 +60,9 @@ class MapAparamOp : public OpKernel { OP_REQUIRES_OK(context, context->allocate_output(0, output_shape, &output_tensor)); // flat the tensors - auto aparam = aparam_tensor.flat(); + auto aparam = aparam_tensor.flat(); auto nlist = nlist_tensor.flat(); - auto output = output_tensor->flat(); + auto output = output_tensor->flat(); // loop over samples #pragma omp parallel for @@ -110,7 +97,12 @@ class MapAparamOp : public OpKernel { int n_r_sel, n_a_sel, n_a_shift; }; -REGISTER_KERNEL_BUILDER(Name("MapAparam").Device(DEVICE_CPU), MapAparamOp); +#define REGISTER_CPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("MapAparam").Device(DEVICE_CPU).TypeConstraint("T"), \ + MapAparamOp); +REGISTER_CPU(float); +REGISTER_CPU(double); From ee11430faaf6eca23f058a235ed878bdd004364a Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 5 Feb 2021 23:47:05 +0800 Subject: [PATCH 096/562] mv the c++ API to api_cc. Cleaning up the code for formatting neighbor list and building environment matrix. Add unittest for the lib --- source/CMakeLists.txt | 7 +- source/api_cc/CMakeLists.txt | 30 ++ source/{lib => api_cc}/include/DataModifier.h | 0 source/{lib => api_cc}/include/DeepTensor.h | 0 source/{lib => api_cc}/include/NNPAtomMap.h | 0 source/{lib => api_cc}/include/NNPInter.h | 0 source/{lib => api_cc}/include/common.h | 0 source/{lib => api_cc}/include/version.h.in | 0 source/{lib => api_cc}/src/DataModifier.cc | 0 source/{lib => api_cc}/src/DeepTensor.cc | 0 source/{lib => api_cc}/src/NNPAtomMap.cc | 0 source/{lib => api_cc}/src/NNPInter.cc | 0 source/{lib => api_cc}/src/common.cc | 0 source/ipi/CMakeLists.txt | 2 +- source/lib/CMakeLists.txt | 7 +- source/lib/include/ComputeDescriptor.h | 296 +----------------- source/lib/include/CustomeOperation.h | 147 +-------- source/lib/include/env_mat.h | 33 ++ source/lib/include/fmt_nlist.h | 57 ++++ source/lib/include/switcher.h | 114 +++++++ source/lib/src/env_mat.cc | 201 ++++++++++++ source/lib/src/fmt_nlist.cc | 146 +++++++++ source/lib/tests/.gitignore | 4 + source/lib/tests/CMakeLists.txt | 28 ++ source/lib/tests/test_env_mat.cc | 244 +++++++++++++++ source/lib/tests/test_fmt_nlist.cc | 147 +++++++++ source/lib/tests/test_main.cc | 6 + source/lib/tests/test_simulation_region.cc | 17 + source/lmp/env.sh.in | 2 +- source/op/descrpt.cc | 1 + source/op/descrpt_se_a.cc | 28 +- source/op/descrpt_se_a_ef.cc | 1 + source/op/descrpt_se_a_ef_para.cc | 1 + source/op/descrpt_se_a_ef_vert.cc | 1 + source/op/descrpt_se_r.cc | 1 + 35 files changed, 1060 insertions(+), 461 deletions(-) create mode 100644 source/api_cc/CMakeLists.txt rename source/{lib => api_cc}/include/DataModifier.h (100%) rename source/{lib => api_cc}/include/DeepTensor.h (100%) rename source/{lib => api_cc}/include/NNPAtomMap.h (100%) rename source/{lib => api_cc}/include/NNPInter.h (100%) rename source/{lib => api_cc}/include/common.h (100%) rename source/{lib => api_cc}/include/version.h.in (100%) rename source/{lib => api_cc}/src/DataModifier.cc (100%) rename source/{lib => api_cc}/src/DeepTensor.cc (100%) rename source/{lib => api_cc}/src/NNPAtomMap.cc (100%) rename source/{lib => api_cc}/src/NNPInter.cc (100%) rename source/{lib => api_cc}/src/common.cc (100%) create mode 100644 source/lib/include/env_mat.h create mode 100644 source/lib/include/fmt_nlist.h create mode 100644 source/lib/include/switcher.h create mode 100644 source/lib/src/env_mat.cc create mode 100644 source/lib/src/fmt_nlist.cc create mode 100644 source/lib/tests/.gitignore create mode 100644 source/lib/tests/CMakeLists.txt create mode 100644 source/lib/tests/test_env_mat.cc create mode 100644 source/lib/tests/test_fmt_nlist.cc create mode 100644 source/lib/tests/test_main.cc create mode 100644 source/lib/tests/test_simulation_region.cc diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index dc35ee5dc0..75c90b6c4f 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -175,6 +175,10 @@ endif() # headers of lib list (APPEND DeePMD_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/lib/include/) list (APPEND DeePMD_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/3rdparty/) +if (BUILD_CPP_IF) + list (APPEND DeePMD_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/api_cc/include/) + include_directories(${CMAKE_BINARY_DIR}/api_cc/) +endif (BUILD_CPP_IF) # include include_directories(${DeePMD_INCLUDE_DIRS}) @@ -184,6 +188,7 @@ include_directories(${TensorFlow_INCLUDE_DIRS}) if (BUILD_CPP_IF) set (LIB_DEEPMD "deepmd") set (LIB_DEEPMD_OP "deepmd_op") + set (LIB_DEEPMD_CC "deepmd_cc") if (USE_CUDA_TOOLKIT) set (LIB_DEEPMD_OP_CUDA "deepmd_op_cuda") else () @@ -197,7 +202,6 @@ if (BUILD_CPP_IF) endif () endif (BUILD_CPP_IF) -include_directories(${CMAKE_BINARY_DIR}/lib/) add_subdirectory (op/) if (BUILD_PY_IF) add_subdirectory (train/) @@ -205,6 +209,7 @@ if (BUILD_PY_IF) add_subdirectory (tests/) endif (BUILD_PY_IF) if (BUILD_CPP_IF) + add_subdirectory (api_cc/) add_subdirectory (lib/) add_subdirectory (lmp/) if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.9) diff --git a/source/api_cc/CMakeLists.txt b/source/api_cc/CMakeLists.txt new file mode 100644 index 0000000000..855732b26b --- /dev/null +++ b/source/api_cc/CMakeLists.txt @@ -0,0 +1,30 @@ +# libmd + +set (libname ${LIB_DEEPMD_CC}) + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/include/version.h.in + version.h + @ONLY +) + +if (USE_CUDA_TOOLKIT) + include_directories("${CUDA_INCLUDE_DIRS}") +endif() + +file(GLOB LIB_SRC src/*.cc src/*.cpp) +file(GLOB INC_SRC include/*.h ${CMAKE_CURRENT_BINARY_DIR}/version.h) + +add_library(${libname} SHARED ${LIB_SRC}) + +if (USE_CUDA_TOOLKIT) + target_link_libraries (${libname} ${CUDA_LIBRARIES}) +endif() + +install(TARGETS ${libname} DESTINATION lib/) + +install( + FILES ${INC_SRC} + DESTINATION include/deepmd +) + diff --git a/source/lib/include/DataModifier.h b/source/api_cc/include/DataModifier.h similarity index 100% rename from source/lib/include/DataModifier.h rename to source/api_cc/include/DataModifier.h diff --git a/source/lib/include/DeepTensor.h b/source/api_cc/include/DeepTensor.h similarity index 100% rename from source/lib/include/DeepTensor.h rename to source/api_cc/include/DeepTensor.h diff --git a/source/lib/include/NNPAtomMap.h b/source/api_cc/include/NNPAtomMap.h similarity index 100% rename from source/lib/include/NNPAtomMap.h rename to source/api_cc/include/NNPAtomMap.h diff --git a/source/lib/include/NNPInter.h b/source/api_cc/include/NNPInter.h similarity index 100% rename from source/lib/include/NNPInter.h rename to source/api_cc/include/NNPInter.h diff --git a/source/lib/include/common.h b/source/api_cc/include/common.h similarity index 100% rename from source/lib/include/common.h rename to source/api_cc/include/common.h diff --git a/source/lib/include/version.h.in b/source/api_cc/include/version.h.in similarity index 100% rename from source/lib/include/version.h.in rename to source/api_cc/include/version.h.in diff --git a/source/lib/src/DataModifier.cc b/source/api_cc/src/DataModifier.cc similarity index 100% rename from source/lib/src/DataModifier.cc rename to source/api_cc/src/DataModifier.cc diff --git a/source/lib/src/DeepTensor.cc b/source/api_cc/src/DeepTensor.cc similarity index 100% rename from source/lib/src/DeepTensor.cc rename to source/api_cc/src/DeepTensor.cc diff --git a/source/lib/src/NNPAtomMap.cc b/source/api_cc/src/NNPAtomMap.cc similarity index 100% rename from source/lib/src/NNPAtomMap.cc rename to source/api_cc/src/NNPAtomMap.cc diff --git a/source/lib/src/NNPInter.cc b/source/api_cc/src/NNPInter.cc similarity index 100% rename from source/lib/src/NNPInter.cc rename to source/api_cc/src/NNPInter.cc diff --git a/source/lib/src/common.cc b/source/api_cc/src/common.cc similarity index 100% rename from source/lib/src/common.cc rename to source/api_cc/src/common.cc diff --git a/source/ipi/CMakeLists.txt b/source/ipi/CMakeLists.txt index 08516ed798..c60122da78 100644 --- a/source/ipi/CMakeLists.txt +++ b/source/ipi/CMakeLists.txt @@ -8,7 +8,7 @@ add_library(${LIB_DEEPMD_IPI} SHARED ${IN_SRC}) set(DRIVER_SOURCE_FILES driver.cc) add_executable(dp_ipi ${DRIVER_SOURCE_FILES}) -target_link_libraries(dp_ipi ${LIB_DEEPMD_IPI} ${LIB_DEEPMD_OP} ${LIB_DEEPMD} ${TensorFlow_LIBRARY}) +target_link_libraries(dp_ipi ${LIB_DEEPMD_IPI} ${LIB_DEEPMD_OP} ${LIB_DEEPMD_CC} ${LIB_DEEPMD} ${TensorFlow_LIBRARY}) set_target_properties( dp_ipi diff --git a/source/lib/CMakeLists.txt b/source/lib/CMakeLists.txt index 231b0a5ae8..d6a7d40ff5 100644 --- a/source/lib/CMakeLists.txt +++ b/source/lib/CMakeLists.txt @@ -2,12 +2,6 @@ set (libname ${LIB_DEEPMD}) -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/include/version.h.in - version.h - @ONLY -) - if (USE_CUDA_TOOLKIT) include_directories("${CUDA_INCLUDE_DIRS}") endif() @@ -27,3 +21,4 @@ install( FILES ${INC_SRC} DESTINATION include/deepmd ) + diff --git a/source/lib/include/ComputeDescriptor.h b/source/lib/include/ComputeDescriptor.h index b01f9ed44b..8f1fef9820 100644 --- a/source/lib/include/ComputeDescriptor.h +++ b/source/lib/include/ComputeDescriptor.h @@ -6,25 +6,9 @@ #include "SimulationRegion.h" #include "MathUtilities.h" +#include "switcher.h" -// return: -1 OK -// > 0 the type of unsuccessful neighbor list -inline -int format_nlist_fill_a (std::vector & fmt_nei_idx_a, - std::vector & fmt_nei_idx_r, - const std::vector & posi, - const int & ntypes, - const std::vector & type, - const SimulationRegion & region, - const bool & b_pbc, - const int & i_idx, - const std::vector & nei_idx_a, - const std::vector & nei_idx_r, - const double & rcut, - const std::vector & sec_a, - const std::vector & sec_r); - inline void compute_descriptor (std::vector & descrpt_a, std::vector & descrpt_r, @@ -67,20 +51,6 @@ void compute_descriptor (std::vector & descrpt_a, const int axis1_type, const int axis1_idx); -inline -void compute_descriptor_se_a (std::vector & descrpt_a, - std::vector & descrpt_a_deriv, - std::vector & rij_a, - const std::vector & posi, - const int & ntypes, - const std::vector & type, - const SimulationRegion & region, - const bool & b_pbc, - const int & i_idx, - const std::vector & fmt_nlist_a, - const std::vector & sec_a, - const double & rmin, - const double & rmax); inline void compute_descriptor_se_a_extf (std::vector & descrpt_a, @@ -144,28 +114,6 @@ void compute_descriptor_se_r (std::vector & descrpt_r, const double & rmax); -struct NeighborInfo -{ - int type; - double dist; - int index; - NeighborInfo () - : type (0), dist(0), index(0) - { - } - NeighborInfo (int tt, double dd, int ii) - : type (tt), dist(dd), index(ii) - { - } - bool operator < (const NeighborInfo & b) const - { - return (type < b.type || - (type == b.type && - (dist < b.dist || - (dist == b.dist && index < b.index) ) ) ); - } -}; - static void compute_dRdT (double (* dRdT)[9], const double * r1, @@ -346,76 +294,6 @@ compute_dRdT_2 (double (* dRdT)[9], } } -int format_nlist_fill_a (std::vector & fmt_nei_idx_a, - std::vector & fmt_nei_idx_r, - const std::vector & posi, - const int & ntypes, - const std::vector & type, - const SimulationRegion & region, - const bool & b_pbc, - const int & i_idx, - const std::vector & nei_idx_a, - const std::vector & nei_idx_r, - const double & rcut, - const std::vector & sec_a, - const std::vector & sec_r) -{ -#ifdef DEBUG - assert (sec_a.size() == ntypes + 1); - assert (sec_r.size() == ntypes + 1); -#endif - - fmt_nei_idx_a.resize (sec_a.back()); - fmt_nei_idx_r.resize (sec_r.back()); - fill (fmt_nei_idx_a.begin(), fmt_nei_idx_a.end(), -1); - fill (fmt_nei_idx_r.begin(), fmt_nei_idx_r.end(), -1); - - // gether all neighbors - std::vector nei_idx (nei_idx_a); - nei_idx.insert (nei_idx.end(), nei_idx_r.begin(), nei_idx_r.end()); - assert (nei_idx.size() == nei_idx_a.size() + nei_idx_r.size()); - // allocate the information for all neighbors - std::vector sel_nei ; - sel_nei.reserve (nei_idx_a.size() + nei_idx_r.size()); - for (unsigned kk = 0; kk < nei_idx.size(); ++kk){ - double diff[3]; - const int & j_idx = nei_idx[kk]; - if (b_pbc){ - region.diffNearestNeighbor (posi[j_idx*3+0], posi[j_idx*3+1], posi[j_idx*3+2], - posi[i_idx*3+0], posi[i_idx*3+1], posi[i_idx*3+2], - diff[0], diff[1], diff[2]); - } - else { - for (int dd = 0; dd < 3; ++dd) diff[dd] = posi[j_idx*3+dd] - posi[i_idx*3+dd]; - } - double rr = sqrt(MathUtilities::dot (diff, diff)); - if (rr <= rcut) { - sel_nei.push_back(NeighborInfo (type[j_idx], rr, j_idx)); - } - } - sort (sel_nei.begin(), sel_nei.end()); - - std::vector nei_iter = sec_a; - int overflowed = -1; - for (unsigned kk = 0; kk < sel_nei.size(); ++kk){ - const int & nei_type = sel_nei[kk].type; - if (nei_iter[nei_type] >= sec_a[nei_type+1]) { - int r_idx_iter = (nei_iter[nei_type] ++) - sec_a[nei_type+1] + sec_r[nei_type]; - if (r_idx_iter >= sec_r[nei_type+1]) { - // return nei_type; - overflowed = nei_type; - } - else { - fmt_nei_idx_r[r_idx_iter] = sel_nei[kk].index; - } - } - else { - fmt_nei_idx_a[nei_iter[nei_type] ++] = sel_nei[kk].index; - } - } - - return overflowed; -} // output deriv size: n_sel_a_nei x 4 x 12 + n_sel_r_nei x 12 @@ -887,181 +765,9 @@ void compute_descriptor (std::vector & descrpt_a, } } -inline double -cos_switch (const double & xx, - const double & rmin, - const double & rmax) -{ - if (xx < rmin) { - return 1.; - } - else if (xx < rmax) { - const double value = (xx - rmin) / (rmax - rmin) * M_PI; - return 0.5 * (cos(value) + 1); - } - else { - return 0.; - } -} - -inline void -cos_switch (double & vv, - double & dd, - const double & xx, - const double & rmin, - const double & rmax) -{ - if (xx < rmin) { - dd = 0; - vv = 1; - } - else if (xx < rmax) { - double value = (xx - rmin) / (rmax - rmin) * M_PI; - dd = -0.5 * sin(value) * M_PI / (rmax - rmin); - vv = 0.5 * (cos(value) + 1); - } - else { - dd = 0; - vv = 0; - } -} -inline void -spline3_switch (double & vv, - double & dd, - const double & xx, - const double & rmin, - const double & rmax) -{ - if (xx < rmin) { - dd = 0; - vv = 1; - } - else if (xx < rmax) { - double uu = (xx - rmin) / (rmax - rmin) ; - double du = 1. / (rmax - rmin) ; - // s(u) = (1+2u)(1-u)^2 - // s'(u) = 2(2u+1)(u-1) + 2(u-1)^2 - vv = (1 + 2*uu) * (1-uu) * (1-uu); - dd = (2 * (2*uu + 1) * (uu-1) + 2 * (uu-1) * (uu-1) ) * du; - } - else { - dd = 0; - vv = 0; - } -} - -template -inline void -spline5_switch (TYPE & vv, - TYPE & dd, - const TYPE & xx, - const TYPE & rmin, - const TYPE & rmax) -{ - if (xx < rmin) { - dd = 0; - vv = 1; - } - else if (xx < rmax) { - double uu = (xx - rmin) / (rmax - rmin) ; - double du = 1. / (rmax - rmin) ; - vv = uu*uu*uu * (-6 * uu*uu + 15 * uu - 10) + 1; - dd = ( 3 * uu*uu * (-6 * uu*uu + 15 * uu - 10) + uu*uu*uu * (-12 * uu + 15) ) * du; - } - else { - dd = 0; - vv = 0; - } -} -// output deriv size: n_sel_a_nei x 4 x 12 -// (1./rr, cos_theta, cos_phi, sin_phi) x 4 x (x, y, z) -void compute_descriptor_se_a (std::vector & descrpt_a, - std::vector & descrpt_a_deriv, - std::vector & rij_a, - const std::vector & posi, - const int & ntypes, - const std::vector & type, - const SimulationRegion & region, - const bool & b_pbc, - const int & i_idx, - const std::vector & fmt_nlist_a, - const std::vector & sec_a, - const double & rmin, - const double & rmax) -{ - // compute the diff of the neighbors - std::vector > sel_a_diff (sec_a.back()); - rij_a.resize (sec_a.back() * 3); - fill (rij_a.begin(), rij_a.end(), 0.0); - for (int ii = 0; ii < int(sec_a.size()) - 1; ++ii){ - for (int jj = sec_a[ii]; jj < sec_a[ii+1]; ++jj){ - if (fmt_nlist_a[jj] < 0) break; - sel_a_diff[jj].resize(3); - const int & j_idx = fmt_nlist_a[jj]; - if (b_pbc){ - region.diffNearestNeighbor (posi[j_idx*3+0], posi[j_idx*3+1], posi[j_idx*3+2], - posi[i_idx*3+0], posi[i_idx*3+1], posi[i_idx*3+2], - sel_a_diff[jj][0], sel_a_diff[jj][1], sel_a_diff[jj][2]); - } - else { - for (int dd = 0; dd < 3; ++dd) sel_a_diff[jj][dd] = posi[j_idx*3+dd] - posi[i_idx*3+dd]; - } - for (int dd = 0; dd < 3; ++dd) rij_a[jj*3+dd] = sel_a_diff[jj][dd]; - } - } - - // 1./rr, cos(theta), cos(phi), sin(phi) - descrpt_a.resize (sec_a.back() * 4); - fill (descrpt_a.begin(), descrpt_a.end(), 0.0); - // deriv wrt center: 3 - descrpt_a_deriv.resize (sec_a.back() * 4 * 3); - fill (descrpt_a_deriv.begin(), descrpt_a_deriv.end(), 0.0); - for (int sec_iter = 0; sec_iter < int(sec_a.size()) - 1; ++sec_iter){ - for (int nei_iter = sec_a[sec_iter]; nei_iter < sec_a[sec_iter+1]; ++nei_iter) { - if (fmt_nlist_a[nei_iter] < 0) break; - const double * rr = &sel_a_diff[nei_iter][0]; - double nr2 = MathUtilities::dot(rr, rr); - double inr = 1./sqrt(nr2); - double nr = nr2 * inr; - double inr2 = inr * inr; - double inr4 = inr2 * inr2; - double inr3 = inr4 * nr; - double sw, dsw; - spline5_switch(sw, dsw, nr, rmin, rmax); - int idx_deriv = nei_iter * 4 * 3; // 4 components time 3 directions - int idx_value = nei_iter * 4; // 4 components - // 4 value components - descrpt_a[idx_value + 0] = 1./nr; - descrpt_a[idx_value + 1] = rr[0] / nr2; - descrpt_a[idx_value + 2] = rr[1] / nr2; - descrpt_a[idx_value + 3] = rr[2] / nr2; - // deriv of component 1/r - descrpt_a_deriv[idx_deriv + 0] = rr[0] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[0] * inr; - descrpt_a_deriv[idx_deriv + 1] = rr[1] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[1] * inr; - descrpt_a_deriv[idx_deriv + 2] = rr[2] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[2] * inr; - // deriv of component x/r2 - descrpt_a_deriv[idx_deriv + 3] = (2. * rr[0] * rr[0] * inr4 - inr2) * sw - descrpt_a[idx_value + 1] * dsw * rr[0] * inr; - descrpt_a_deriv[idx_deriv + 4] = (2. * rr[0] * rr[1] * inr4 ) * sw - descrpt_a[idx_value + 1] * dsw * rr[1] * inr; - descrpt_a_deriv[idx_deriv + 5] = (2. * rr[0] * rr[2] * inr4 ) * sw - descrpt_a[idx_value + 1] * dsw * rr[2] * inr; - // deriv of component y/r2 - descrpt_a_deriv[idx_deriv + 6] = (2. * rr[1] * rr[0] * inr4 ) * sw - descrpt_a[idx_value + 2] * dsw * rr[0] * inr; - descrpt_a_deriv[idx_deriv + 7] = (2. * rr[1] * rr[1] * inr4 - inr2) * sw - descrpt_a[idx_value + 2] * dsw * rr[1] * inr; - descrpt_a_deriv[idx_deriv + 8] = (2. * rr[1] * rr[2] * inr4 ) * sw - descrpt_a[idx_value + 2] * dsw * rr[2] * inr; - // deriv of component z/r2 - descrpt_a_deriv[idx_deriv + 9] = (2. * rr[2] * rr[0] * inr4 ) * sw - descrpt_a[idx_value + 3] * dsw * rr[0] * inr; - descrpt_a_deriv[idx_deriv +10] = (2. * rr[2] * rr[1] * inr4 ) * sw - descrpt_a[idx_value + 3] * dsw * rr[1] * inr; - descrpt_a_deriv[idx_deriv +11] = (2. * rr[2] * rr[2] * inr4 - inr2) * sw - descrpt_a[idx_value + 3] * dsw * rr[2] * inr; - // 4 value components - descrpt_a[idx_value + 0] *= sw; - descrpt_a[idx_value + 1] *= sw; - descrpt_a[idx_value + 2] *= sw; - descrpt_a[idx_value + 3] *= sw; - } - } -} void compute_descriptor_se_r (std::vector & descrpt, diff --git a/source/lib/include/CustomeOperation.h b/source/lib/include/CustomeOperation.h index 0bdd91c3dd..decdf7118f 100644 --- a/source/lib/include/CustomeOperation.h +++ b/source/lib/include/CustomeOperation.h @@ -4,6 +4,7 @@ #include #include #include "MathUtilities.h" +#include "fmt_nlist.h" #if GOOGLE_CUDA #include "DeviceFunctor.h" #endif // GOOGLE_CUDA @@ -23,150 +24,8 @@ struct NeighborInfo { } }; -template -inline void spline5_switch ( - FPTYPE & vv, - FPTYPE & dd, - const FPTYPE & xx, - const float & rmin, - const float & rmax) -{ - if (xx < rmin) { - dd = 0; - vv = 1; - } - else if (xx < rmax) { - FPTYPE uu = (xx - rmin) / (rmax - rmin) ; - FPTYPE du = 1. / (rmax - rmin) ; - vv = uu*uu*uu * (-6 * uu*uu + 15 * uu - 10) + 1; - dd = ( 3 * uu*uu * (-6 * uu*uu + 15 * uu - 10) + uu*uu*uu * (-12 * uu + 15) ) * du; - } - else { - dd = 0; - vv = 0; - } -} - -template -int format_nlist_fill_se_a_cpu ( - std::vector & fmt_nei_idx_a, - const std::vector & posi, - const int & ntypes, - const std::vector & type, - const int & i_idx, - const std::vector & nei_idx_a, - const float & rcut, - const std::vector & sec_a) -{ - fmt_nei_idx_a.resize (sec_a.back()); - fill (fmt_nei_idx_a.begin(), fmt_nei_idx_a.end(), -1); - - // gether all neighbors - std::vector nei_idx (nei_idx_a); - // allocate the information for all neighbors - std::vector sel_nei; - sel_nei.reserve (nei_idx_a.size()); - for (unsigned kk = 0; kk < nei_idx.size(); ++kk) { - FPTYPE diff[3]; - const int & j_idx = nei_idx[kk]; - for (int dd = 0; dd < 3; ++dd) { - diff[dd] = posi[j_idx * 3 + dd] - posi[i_idx * 3 + dd]; - } - FPTYPE rr = sqrt(MathUtilities::dot (diff, diff)); - if (rr <= rcut) { - sel_nei.push_back(NeighborInfo(type[j_idx], rr, j_idx)); - } - } - sort(sel_nei.begin(), sel_nei.end()); - - std::vector nei_iter = sec_a; - int overflowed = -1; - for (unsigned kk = 0; kk < sel_nei.size(); ++kk) { - const int & nei_type = sel_nei[kk].type; - if (nei_iter[nei_type] < sec_a[nei_type+1]) { - fmt_nei_idx_a[nei_iter[nei_type] ++] = sel_nei[kk].index; - } - } - return overflowed; -} - -template -void compute_descriptor_se_a_cpu ( - std::vector & descrpt_a, - std::vector & descrpt_a_deriv, - std::vector & rij_a, - const std::vector & posi, - const int & ntypes, - const std::vector & type, - const int & i_idx, - const std::vector & fmt_nlist_a, - const std::vector & sec_a, - const float & rmin, - const float & rmax) -{ - // compute the diff of the neighbors - rij_a.resize (sec_a.back() * 3); - fill (rij_a.begin(), rij_a.end(), 0.0); - for (int ii = 0; ii < int(sec_a.size()) - 1; ++ii) { - for (int jj = sec_a[ii]; jj < sec_a[ii + 1]; ++jj) { - if (fmt_nlist_a[jj] < 0) break; - const int & j_idx = fmt_nlist_a[jj]; - for (int dd = 0; dd < 3; ++dd) { - rij_a[jj * 3 + dd] = posi[j_idx * 3 + dd] - posi[i_idx * 3 + dd]; - } - } - } - // 1./rr, cos(theta), cos(phi), sin(phi) - descrpt_a.resize (sec_a.back() * 4); - fill (descrpt_a.begin(), descrpt_a.end(), 0.0); - // deriv wrt center: 3 - descrpt_a_deriv.resize (sec_a.back() * 4 * 3); - fill (descrpt_a_deriv.begin(), descrpt_a_deriv.end(), 0.0); - for (int sec_iter = 0; sec_iter < int(sec_a.size()) - 1; ++sec_iter) { - for (int nei_iter = sec_a[sec_iter]; nei_iter < sec_a[sec_iter+1]; ++nei_iter) { - if (fmt_nlist_a[nei_iter] < 0) break; - const FPTYPE * rr = &rij_a[nei_iter * 3]; - FPTYPE nr2 = MathUtilities::dot(rr, rr); - FPTYPE inr = 1./sqrt(nr2); - FPTYPE nr = nr2 * inr; - FPTYPE inr2 = inr * inr; - FPTYPE inr4 = inr2 * inr2; - FPTYPE inr3 = inr4 * nr; - FPTYPE sw, dsw; - spline5_switch(sw, dsw, nr, rmin, rmax); - int idx_deriv = nei_iter * 4 * 3; // 4 components time 3 directions - int idx_value = nei_iter * 4; // 4 components - // 4 value components - descrpt_a[idx_value + 0] = 1./nr; - descrpt_a[idx_value + 1] = rr[0] / nr2; - descrpt_a[idx_value + 2] = rr[1] / nr2; - descrpt_a[idx_value + 3] = rr[2] / nr2; - // deriv of component 1/r - descrpt_a_deriv[idx_deriv + 0] = rr[0] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[0] * inr; - descrpt_a_deriv[idx_deriv + 1] = rr[1] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[1] * inr; - descrpt_a_deriv[idx_deriv + 2] = rr[2] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[2] * inr; - // deriv of component x/r2 - descrpt_a_deriv[idx_deriv + 3] = (2. * rr[0] * rr[0] * inr4 - inr2) * sw - descrpt_a[idx_value + 1] * dsw * rr[0] * inr; - descrpt_a_deriv[idx_deriv + 4] = (2. * rr[0] * rr[1] * inr4 ) * sw - descrpt_a[idx_value + 1] * dsw * rr[1] * inr; - descrpt_a_deriv[idx_deriv + 5] = (2. * rr[0] * rr[2] * inr4 ) * sw - descrpt_a[idx_value + 1] * dsw * rr[2] * inr; - // deriv of component y/r2 - descrpt_a_deriv[idx_deriv + 6] = (2. * rr[1] * rr[0] * inr4 ) * sw - descrpt_a[idx_value + 2] * dsw * rr[0] * inr; - descrpt_a_deriv[idx_deriv + 7] = (2. * rr[1] * rr[1] * inr4 - inr2) * sw - descrpt_a[idx_value + 2] * dsw * rr[1] * inr; - descrpt_a_deriv[idx_deriv + 8] = (2. * rr[1] * rr[2] * inr4 ) * sw - descrpt_a[idx_value + 2] * dsw * rr[2] * inr; - // deriv of component z/r2 - descrpt_a_deriv[idx_deriv + 9] = (2. * rr[2] * rr[0] * inr4 ) * sw - descrpt_a[idx_value + 3] * dsw * rr[0] * inr; - descrpt_a_deriv[idx_deriv +10] = (2. * rr[2] * rr[1] * inr4 ) * sw - descrpt_a[idx_value + 3] * dsw * rr[1] * inr; - descrpt_a_deriv[idx_deriv +11] = (2. * rr[2] * rr[2] * inr4 - inr2) * sw - descrpt_a[idx_value + 3] * dsw * rr[2] * inr; - // 4 value components - descrpt_a[idx_value + 0] *= sw; - descrpt_a[idx_value + 1] *= sw; - descrpt_a[idx_value + 2] *= sw; - descrpt_a[idx_value + 3] *= sw; - } - } -} template void DescrptSeACPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { @@ -203,7 +62,7 @@ void DescrptSeACPULauncher(const FPTYPE * coord, const int * type, const int * i std::vector fmt_nlist_a; int ret = -1; if (fill_nei_a) { - format_nlist_fill_se_a_cpu(fmt_nlist_a, d_coord3, ntypes, d_type, ii, d_nlist_a[ii], rcut_r, sec_a); + format_nlist_cpu(fmt_nlist_a, d_coord3, ntypes, d_type, ii, d_nlist_a[ii], rcut_r, sec_a); } std::vector d_descrpt_a; std::vector d_descrpt_a_deriv; @@ -466,7 +325,7 @@ void DescrptSeRCPULauncher(const FPTYPE * coord, const int * type, const int * i std::vector fmt_nlist_a; int ret = -1; if (fill_nei_a) { - format_nlist_fill_se_a_cpu(fmt_nlist_a, d_coord3, ntypes, d_type, ii, d_nlist_a[ii], rcut_r, sec_a); + format_nlist_cpu(fmt_nlist_a, d_coord3, ntypes, d_type, ii, d_nlist_a[ii], rcut_r, sec_a); } std::vector d_descrpt_a; std::vector d_descrpt_a_deriv; diff --git a/source/lib/include/env_mat.h b/source/lib/include/env_mat.h new file mode 100644 index 0000000000..3e712888c2 --- /dev/null +++ b/source/lib/include/env_mat.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include "SimulationRegion.h" + +void env_mat_a ( + std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, + const int & ntypes, + const std::vector & type, + const SimulationRegion & region, + const bool & b_pbc, + const int & i_idx, + const std::vector & fmt_nlist_a, + const std::vector & sec_a, + const double & rmin, + const double & rmax); + +template +void env_mat_a_cpu ( + std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, + const int & ntypes, + const std::vector & type, + const int & i_idx, + const std::vector & fmt_nlist_a, + const std::vector & sec_a, + const float & rmin, + const float & rmax) ; diff --git a/source/lib/include/fmt_nlist.h b/source/lib/include/fmt_nlist.h new file mode 100644 index 0000000000..f60f9de0d8 --- /dev/null +++ b/source/lib/include/fmt_nlist.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include "SimulationRegion.h" + +// return: -1 OK +// > 0 the type of unsuccessful neighbor list +int format_nlist_fill_a ( + std::vector & fmt_nei_idx_a, + std::vector & fmt_nei_idx_r, + const std::vector & posi, + const int & ntypes, + const std::vector & type, + const SimulationRegion & region, + const bool & b_pbc, + const int & i_idx, + const std::vector & nei_idx_a, + const std::vector & nei_idx_r, + const double & rcut, + const std::vector & sec_a, + const std::vector & sec_r); + + +template +int format_nlist_cpu ( + std::vector & fmt_nei_idx_a, + const std::vector & posi, + const int & ntypes, + const std::vector & type, + const int & i_idx, + const std::vector & nei_idx_a, + const float & rcut, + const std::vector & sec_a); + + + +struct NeighborInfo +{ + int type; + double dist; + int index; + NeighborInfo () + : type (0), dist(0), index(0) + { + } + NeighborInfo (int tt, double dd, int ii) + : type (tt), dist(dd), index(ii) + { + } + bool operator < (const NeighborInfo & b) const + { + return (type < b.type || + (type == b.type && + (dist < b.dist || + (dist == b.dist && index < b.index) ) ) ); + } +}; diff --git a/source/lib/include/switcher.h b/source/lib/include/switcher.h new file mode 100644 index 0000000000..671c8be137 --- /dev/null +++ b/source/lib/include/switcher.h @@ -0,0 +1,114 @@ +#pragma once + +inline double +cos_switch (const double & xx, + const double & rmin, + const double & rmax) +{ + if (xx < rmin) { + return 1.; + } + else if (xx < rmax) { + const double value = (xx - rmin) / (rmax - rmin) * M_PI; + return 0.5 * (cos(value) + 1); + } + else { + return 0.; + } +} + +inline void +cos_switch (double & vv, + double & dd, + const double & xx, + const double & rmin, + const double & rmax) +{ + if (xx < rmin) { + dd = 0; + vv = 1; + } + else if (xx < rmax) { + double value = (xx - rmin) / (rmax - rmin) * M_PI; + dd = -0.5 * sin(value) * M_PI / (rmax - rmin); + vv = 0.5 * (cos(value) + 1); + } + else { + dd = 0; + vv = 0; + } +} + +inline void +spline3_switch (double & vv, + double & dd, + const double & xx, + const double & rmin, + const double & rmax) +{ + if (xx < rmin) { + dd = 0; + vv = 1; + } + else if (xx < rmax) { + double uu = (xx - rmin) / (rmax - rmin) ; + double du = 1. / (rmax - rmin) ; + // s(u) = (1+2u)(1-u)^2 + // s'(u) = 2(2u+1)(u-1) + 2(u-1)^2 + vv = (1 + 2*uu) * (1-uu) * (1-uu); + dd = (2 * (2*uu + 1) * (uu-1) + 2 * (uu-1) * (uu-1) ) * du; + } + else { + dd = 0; + vv = 0; + } +} + +// template +// inline void +// spline5_switch (TYPE & vv, +// TYPE & dd, +// const TYPE & xx, +// const TYPE & rmin, +// const TYPE & rmax) +// { +// if (xx < rmin) { +// dd = 0; +// vv = 1; +// } +// else if (xx < rmax) { +// double uu = (xx - rmin) / (rmax - rmin) ; +// double du = 1. / (rmax - rmin) ; +// vv = uu*uu*uu * (-6 * uu*uu + 15 * uu - 10) + 1; +// dd = ( 3 * uu*uu * (-6 * uu*uu + 15 * uu - 10) + uu*uu*uu * (-12 * uu + 15) ) * du; +// } +// else { +// dd = 0; +// vv = 0; +// } +// } + +template +inline void +spline5_switch ( + FPTYPE & vv, + FPTYPE & dd, + const FPTYPE & xx, + const float & rmin, + const float & rmax) +{ + if (xx < rmin) { + dd = 0; + vv = 1; + } + else if (xx < rmax) { + FPTYPE uu = (xx - rmin) / (rmax - rmin) ; + FPTYPE du = 1. / (rmax - rmin) ; + vv = uu*uu*uu * (-6 * uu*uu + 15 * uu - 10) + 1; + dd = ( 3 * uu*uu * (-6 * uu*uu + 15 * uu - 10) + uu*uu*uu * (-12 * uu + 15) ) * du; + } + else { + dd = 0; + vv = 0; + } +} diff --git a/source/lib/src/env_mat.cc b/source/lib/src/env_mat.cc new file mode 100644 index 0000000000..0247e2b77a --- /dev/null +++ b/source/lib/src/env_mat.cc @@ -0,0 +1,201 @@ +#include "env_mat.h" +#include "switcher.h" + +// output deriv size: n_sel_a_nei x 4 x 12 +// (1./rr, cos_theta, cos_phi, sin_phi) x 4 x (x, y, z) +void env_mat_a ( + std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, + const int & ntypes, + const std::vector & type, + const SimulationRegion & region, + const bool & b_pbc, + const int & i_idx, + const std::vector & fmt_nlist_a, + const std::vector & sec_a, + const double & rmin, + const double & rmax) +{ + // compute the diff of the neighbors + std::vector > sel_a_diff (sec_a.back()); + rij_a.resize (sec_a.back() * 3); + fill (rij_a.begin(), rij_a.end(), 0.0); + for (int ii = 0; ii < int(sec_a.size()) - 1; ++ii){ + for (int jj = sec_a[ii]; jj < sec_a[ii+1]; ++jj){ + if (fmt_nlist_a[jj] < 0) break; + sel_a_diff[jj].resize(3); + const int & j_idx = fmt_nlist_a[jj]; + if (b_pbc){ + region.diffNearestNeighbor (posi[j_idx*3+0], posi[j_idx*3+1], posi[j_idx*3+2], + posi[i_idx*3+0], posi[i_idx*3+1], posi[i_idx*3+2], + sel_a_diff[jj][0], sel_a_diff[jj][1], sel_a_diff[jj][2]); + } + else { + for (int dd = 0; dd < 3; ++dd) sel_a_diff[jj][dd] = posi[j_idx*3+dd] - posi[i_idx*3+dd]; + } + for (int dd = 0; dd < 3; ++dd) rij_a[jj*3+dd] = sel_a_diff[jj][dd]; + } + } + + // 1./rr, cos(theta), cos(phi), sin(phi) + descrpt_a.resize (sec_a.back() * 4); + fill (descrpt_a.begin(), descrpt_a.end(), 0.0); + // deriv wrt center: 3 + descrpt_a_deriv.resize (sec_a.back() * 4 * 3); + fill (descrpt_a_deriv.begin(), descrpt_a_deriv.end(), 0.0); + + for (int sec_iter = 0; sec_iter < int(sec_a.size()) - 1; ++sec_iter){ + for (int nei_iter = sec_a[sec_iter]; nei_iter < sec_a[sec_iter+1]; ++nei_iter) { + if (fmt_nlist_a[nei_iter] < 0) break; + const double * rr = &sel_a_diff[nei_iter][0]; + double nr2 = MathUtilities::dot(rr, rr); + double inr = 1./sqrt(nr2); + double nr = nr2 * inr; + double inr2 = inr * inr; + double inr4 = inr2 * inr2; + double inr3 = inr4 * nr; + double sw, dsw; + spline5_switch(sw, dsw, nr, rmin, rmax); + int idx_deriv = nei_iter * 4 * 3; // 4 components time 3 directions + int idx_value = nei_iter * 4; // 4 components + // 4 value components + descrpt_a[idx_value + 0] = 1./nr; + descrpt_a[idx_value + 1] = rr[0] / nr2; + descrpt_a[idx_value + 2] = rr[1] / nr2; + descrpt_a[idx_value + 3] = rr[2] / nr2; + // deriv of component 1/r + descrpt_a_deriv[idx_deriv + 0] = rr[0] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv + 1] = rr[1] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv + 2] = rr[2] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[2] * inr; + // deriv of component x/r2 + descrpt_a_deriv[idx_deriv + 3] = (2. * rr[0] * rr[0] * inr4 - inr2) * sw - descrpt_a[idx_value + 1] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv + 4] = (2. * rr[0] * rr[1] * inr4 ) * sw - descrpt_a[idx_value + 1] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv + 5] = (2. * rr[0] * rr[2] * inr4 ) * sw - descrpt_a[idx_value + 1] * dsw * rr[2] * inr; + // deriv of component y/r2 + descrpt_a_deriv[idx_deriv + 6] = (2. * rr[1] * rr[0] * inr4 ) * sw - descrpt_a[idx_value + 2] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv + 7] = (2. * rr[1] * rr[1] * inr4 - inr2) * sw - descrpt_a[idx_value + 2] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv + 8] = (2. * rr[1] * rr[2] * inr4 ) * sw - descrpt_a[idx_value + 2] * dsw * rr[2] * inr; + // deriv of component z/r2 + descrpt_a_deriv[idx_deriv + 9] = (2. * rr[2] * rr[0] * inr4 ) * sw - descrpt_a[idx_value + 3] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv +10] = (2. * rr[2] * rr[1] * inr4 ) * sw - descrpt_a[idx_value + 3] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv +11] = (2. * rr[2] * rr[2] * inr4 - inr2) * sw - descrpt_a[idx_value + 3] * dsw * rr[2] * inr; + // 4 value components + descrpt_a[idx_value + 0] *= sw; + descrpt_a[idx_value + 1] *= sw; + descrpt_a[idx_value + 2] *= sw; + descrpt_a[idx_value + 3] *= sw; + } + } +} + + +template +void env_mat_a_cpu ( + std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, + const int & ntypes, + const std::vector & type, + const int & i_idx, + const std::vector & fmt_nlist_a, + const std::vector & sec_a, + const float & rmin, + const float & rmax) +{ + // compute the diff of the neighbors + rij_a.resize (sec_a.back() * 3); + fill (rij_a.begin(), rij_a.end(), 0.0); + for (int ii = 0; ii < int(sec_a.size()) - 1; ++ii) { + for (int jj = sec_a[ii]; jj < sec_a[ii + 1]; ++jj) { + if (fmt_nlist_a[jj] < 0) break; + const int & j_idx = fmt_nlist_a[jj]; + for (int dd = 0; dd < 3; ++dd) { + rij_a[jj * 3 + dd] = posi[j_idx * 3 + dd] - posi[i_idx * 3 + dd]; + } + } + } + // 1./rr, cos(theta), cos(phi), sin(phi) + descrpt_a.resize (sec_a.back() * 4); + fill (descrpt_a.begin(), descrpt_a.end(), 0.0); + // deriv wrt center: 3 + descrpt_a_deriv.resize (sec_a.back() * 4 * 3); + fill (descrpt_a_deriv.begin(), descrpt_a_deriv.end(), 0.0); + + for (int sec_iter = 0; sec_iter < int(sec_a.size()) - 1; ++sec_iter) { + for (int nei_iter = sec_a[sec_iter]; nei_iter < sec_a[sec_iter+1]; ++nei_iter) { + if (fmt_nlist_a[nei_iter] < 0) break; + const FPTYPE * rr = &rij_a[nei_iter * 3]; + FPTYPE nr2 = MathUtilities::dot(rr, rr); + FPTYPE inr = 1./sqrt(nr2); + FPTYPE nr = nr2 * inr; + FPTYPE inr2 = inr * inr; + FPTYPE inr4 = inr2 * inr2; + FPTYPE inr3 = inr4 * nr; + FPTYPE sw, dsw; + spline5_switch(sw, dsw, nr, rmin, rmax); + int idx_deriv = nei_iter * 4 * 3; // 4 components time 3 directions + int idx_value = nei_iter * 4; // 4 components + // 4 value components + descrpt_a[idx_value + 0] = 1./nr; + descrpt_a[idx_value + 1] = rr[0] / nr2; + descrpt_a[idx_value + 2] = rr[1] / nr2; + descrpt_a[idx_value + 3] = rr[2] / nr2; + // deriv of component 1/r + descrpt_a_deriv[idx_deriv + 0] = rr[0] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv + 1] = rr[1] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv + 2] = rr[2] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[2] * inr; + // deriv of component x/r2 + descrpt_a_deriv[idx_deriv + 3] = (2. * rr[0] * rr[0] * inr4 - inr2) * sw - descrpt_a[idx_value + 1] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv + 4] = (2. * rr[0] * rr[1] * inr4 ) * sw - descrpt_a[idx_value + 1] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv + 5] = (2. * rr[0] * rr[2] * inr4 ) * sw - descrpt_a[idx_value + 1] * dsw * rr[2] * inr; + // deriv of component y/r2 + descrpt_a_deriv[idx_deriv + 6] = (2. * rr[1] * rr[0] * inr4 ) * sw - descrpt_a[idx_value + 2] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv + 7] = (2. * rr[1] * rr[1] * inr4 - inr2) * sw - descrpt_a[idx_value + 2] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv + 8] = (2. * rr[1] * rr[2] * inr4 ) * sw - descrpt_a[idx_value + 2] * dsw * rr[2] * inr; + // deriv of component z/r2 + descrpt_a_deriv[idx_deriv + 9] = (2. * rr[2] * rr[0] * inr4 ) * sw - descrpt_a[idx_value + 3] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv +10] = (2. * rr[2] * rr[1] * inr4 ) * sw - descrpt_a[idx_value + 3] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv +11] = (2. * rr[2] * rr[2] * inr4 - inr2) * sw - descrpt_a[idx_value + 3] * dsw * rr[2] * inr; + // 4 value components + descrpt_a[idx_value + 0] *= sw; + descrpt_a[idx_value + 1] *= sw; + descrpt_a[idx_value + 2] *= sw; + descrpt_a[idx_value + 3] *= sw; + } + } +} + + +template +void env_mat_a_cpu ( + std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, + const int & ntypes, + const std::vector & type, + const int & i_idx, + const std::vector & fmt_nlist_a, + const std::vector & sec_a, + const float & rmin, + const float & rmax) ; + + +template +void env_mat_a_cpu ( + std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, + const int & ntypes, + const std::vector & type, + const int & i_idx, + const std::vector & fmt_nlist_a, + const std::vector & sec_a, + const float & rmin, + const float & rmax) ; + + diff --git a/source/lib/src/fmt_nlist.cc b/source/lib/src/fmt_nlist.cc new file mode 100644 index 0000000000..6275a30539 --- /dev/null +++ b/source/lib/src/fmt_nlist.cc @@ -0,0 +1,146 @@ +#include +#include +#include +#include "fmt_nlist.h" +#include "SimulationRegion.h" +#include + +int format_nlist_fill_a ( + std::vector & fmt_nei_idx_a, + std::vector & fmt_nei_idx_r, + const std::vector & posi, + const int & ntypes, + const std::vector & type, + const SimulationRegion & region, + const bool & b_pbc, + const int & i_idx, + const std::vector & nei_idx_a, + const std::vector & nei_idx_r, + const double & rcut, + const std::vector & sec_a, + const std::vector & sec_r) +{ +#ifdef DEBUG + assert (sec_a.size() == ntypes + 1); + assert (sec_r.size() == ntypes + 1); +#endif + + fmt_nei_idx_a.resize (sec_a.back()); + fmt_nei_idx_r.resize (sec_r.back()); + fill (fmt_nei_idx_a.begin(), fmt_nei_idx_a.end(), -1); + fill (fmt_nei_idx_r.begin(), fmt_nei_idx_r.end(), -1); + + // gether all neighbors + std::vector nei_idx (nei_idx_a); + nei_idx.insert (nei_idx.end(), nei_idx_r.begin(), nei_idx_r.end()); + assert (nei_idx.size() == nei_idx_a.size() + nei_idx_r.size()); + // allocate the information for all neighbors + std::vector sel_nei ; + sel_nei.reserve (nei_idx_a.size() + nei_idx_r.size()); + for (unsigned kk = 0; kk < nei_idx.size(); ++kk){ + double diff[3]; + const int & j_idx = nei_idx[kk]; + if (b_pbc){ + region.diffNearestNeighbor (posi[j_idx*3+0], posi[j_idx*3+1], posi[j_idx*3+2], + posi[i_idx*3+0], posi[i_idx*3+1], posi[i_idx*3+2], + diff[0], diff[1], diff[2]); + } + else { + for (int dd = 0; dd < 3; ++dd) diff[dd] = posi[j_idx*3+dd] - posi[i_idx*3+dd]; + } + double rr = sqrt(MathUtilities::dot (diff, diff)); + if (rr <= rcut) { + sel_nei.push_back(NeighborInfo (type[j_idx], rr, j_idx)); + } + } + sort (sel_nei.begin(), sel_nei.end()); + + std::vector nei_iter = sec_a; + int overflowed = -1; + for (unsigned kk = 0; kk < sel_nei.size(); ++kk){ + const int & nei_type = sel_nei[kk].type; + if (nei_iter[nei_type] >= sec_a[nei_type+1]) { + int r_idx_iter = (nei_iter[nei_type] ++) - sec_a[nei_type+1] + sec_r[nei_type]; + if (r_idx_iter >= sec_r[nei_type+1]) { + // return nei_type; + overflowed = nei_type; + } + else { + fmt_nei_idx_r[r_idx_iter] = sel_nei[kk].index; + } + } + else { + fmt_nei_idx_a[nei_iter[nei_type] ++] = sel_nei[kk].index; + } + } + return overflowed; +} + + +template +int format_nlist_cpu ( + std::vector & fmt_nei_idx_a, + const std::vector &posi, + const int & ntypes, + const std::vector & type, + const int & i_idx, + const std::vector & nei_idx_a, + const float & rcut, + const std::vector & sec_a) +{ + fmt_nei_idx_a.resize (sec_a.back()); + fill (fmt_nei_idx_a.begin(), fmt_nei_idx_a.end(), -1); + + // gether all neighbors + std::vector nei_idx (nei_idx_a); + // allocate the information for all neighbors + std::vector sel_nei; + sel_nei.reserve (nei_idx_a.size()); + for (unsigned kk = 0; kk < nei_idx.size(); ++kk) { + FPTYPE diff[3]; + const int & j_idx = nei_idx[kk]; + for (int dd = 0; dd < 3; ++dd) { + diff[dd] = posi[j_idx * 3 + dd] - posi[i_idx * 3 + dd]; + } + FPTYPE rr = sqrt(MathUtilities::dot (diff, diff)); + if (rr <= rcut) { + sel_nei.push_back(NeighborInfo(type[j_idx], rr, j_idx)); + } + } + sort(sel_nei.begin(), sel_nei.end()); + + std::vector nei_iter = sec_a; + int overflowed = -1; + for (unsigned kk = 0; kk < sel_nei.size(); ++kk) { + const int & nei_type = sel_nei[kk].type; + if (nei_iter[nei_type] < sec_a[nei_type+1]) { + fmt_nei_idx_a[nei_iter[nei_type] ++] = sel_nei[kk].index; + } + } + return overflowed; +} + +template +int format_nlist_cpu ( + std::vector & fmt_nei_idx_a, + const std::vector &posi, + const int & ntypes, + const std::vector & type, + const int & i_idx, + const std::vector & nei_idx_a, + const float & rcut, + const std::vector & sec_a); + + +template +int format_nlist_cpu ( + std::vector & fmt_nei_idx_a, + const std::vector & posi, + const int & ntypes, + const std::vector & type, + const int & i_idx, + const std::vector & nei_idx_a, + const float & rcut, + const std::vector & sec_a); + + diff --git a/source/lib/tests/.gitignore b/source/lib/tests/.gitignore new file mode 100644 index 0000000000..843af95067 --- /dev/null +++ b/source/lib/tests/.gitignore @@ -0,0 +1,4 @@ +*.cmake +Makefile +libdeepmd.a +runUnitTests diff --git a/source/lib/tests/CMakeLists.txt b/source/lib/tests/CMakeLists.txt new file mode 100644 index 0000000000..12693830c7 --- /dev/null +++ b/source/lib/tests/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.9) +project(libdeepmd_test) + +enable_testing() + +set(libname "deepmd") +set(LIB_BASE_DIR ${CMAKE_SOURCE_DIR}/../) + +include_directories(${LIB_BASE_DIR}/include) +file(GLOB LIB_SRC ${LIB_BASE_DIR}/src/*.cc ${LIB_BASE_DIR}/src/*.cpp) +message(status ${LIB_SRC}) +# add_library(${libname} SHARED ${LIB_SRC}) +add_library(${libname} ${LIB_SRC}) + +message(status "${CMAKE_SOURCE_DIR}") + +file(GLOB TEST_SRC test_*.cc) +add_executable( runUnitTests ${TEST_SRC} ) +target_link_libraries(runUnitTests gtest gtest_main ${libname}) +add_test( runUnitTests runUnitTests ) + +# include(GoogleTest) +# add_executable(FooTest tests/test_simulation_region.cc) +# gtest_add_tests(TARGET FooTest +# TEST_SUFFIX .noArgs +# TEST_LIST noArgsTests +# ) + diff --git a/source/lib/tests/test_env_mat.cc b/source/lib/tests/test_env_mat.cc new file mode 100644 index 0000000000..17887323be --- /dev/null +++ b/source/lib/tests/test_env_mat.cc @@ -0,0 +1,244 @@ +#include +#include +#include "fmt_nlist.h" +#include "env_mat.h" +#include "NeighborList.h" + +class TestEnvMat : public ::testing::Test +{ +protected: + std::vector posi = {12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall; + double rc = 6; + double rc_smth = 0.8; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sec_a = {0, 10, 20}; + std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector> nlist_a, nlist_r; + std::vector> nlist_a_cpy, nlist_r_cpy; + std::vector expected_env = { + 0.12206, 0.12047, 0.01502, -0.01263, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.02167, -0.77271, 0.32370, 0.58475, 0.99745, 0.41810, 0.75655, -0.49773, 0.10564, 0.10495, -0.00143, 0.01198, 0.03103, 0.03041, 0.00452, -0.00425, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + 1.02167, 0.77271, -0.32370, -0.58475, 0.04135, 0.04039, 0.00123, -0.00880, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.59220, 0.42028, 0.16304, -0.38405, 0.03694, 0.03680, -0.00300, -0.00117, 0.00336, 0.00327, 0.00022, -0.00074, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + 0.99745, -0.41810, -0.75655, 0.49773, 0.19078, 0.18961, -0.01951, 0.00793, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.59220, -0.42028, -0.16304, 0.38405, 0.13499, 0.12636, -0.03140, 0.03566, 0.07054, 0.07049, -0.00175, -0.00210, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + 0.12206, -0.12047, -0.01502, 0.01263, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.06176, 0.16913, -0.55250, 0.89077, 1.03163, 0.96880, 0.23422, -0.26615, 0.19078, -0.18961, 0.01951, -0.00793, 0.04135, -0.04039, -0.00123, 0.00880, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + 1.06176, -0.16913, 0.55250, -0.89077, 0.10564, -0.10495, 0.00143, -0.01198, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.66798, 0.34516, 0.32245, -0.47232, 0.13499, -0.12636, 0.03140, -0.03566, 0.03694, -0.03680, 0.00300, 0.00117, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + 1.03163, -0.96880, -0.23422, 0.26615, 0.03103, -0.03041, -0.00452, 0.00425, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.66798, -0.34516, -0.32245, 0.47232, 0.07054, -0.07049, 0.00175, 0.00210, 0.00336, -0.00327, -0.00022, 0.00074, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + }; + + void SetUp() override { + double box[] = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + region.reinitBox(box); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + build_nlist(nlist_a, nlist_r, posi, rc, rc, ncell, region); + build_nlist(nlist_a_cpy, nlist_r_cpy, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + } + void TearDown() override { + } +}; + +TEST_F(TestEnvMat, orig_cpy) +{ + std::vector fmt_nlist_a, fmt_nlist_r; + std::vector env, env_deriv, rij_a; + bool pbc = false; + for(int ii = 0; ii < nloc; ++ii){ + int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi_cpy, ntypes, atype_cpy, region, pbc, ii, nlist_a_cpy[ii], nlist_r_cpy[ii], rc, sec_a, sec_r); + EXPECT_EQ(ret, -1); + env_mat_a(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < sec_a[2]; ++jj){ + for (int dd = 0; dd < 4; ++dd){ + EXPECT_LT(fabs(env[jj*4+dd] - expected_env[ii*sec_a[2]*4 + jj*4 + dd]) , 1e-5); + } + } + // for (int jj = 0; jj < sec_a[2]; ++jj){ + // printf("%7.5f, %7.5f, %7.5f, %7.5f, ", env[jj*4+0], env[jj*4+1], env[jj*4+2], env[jj*4+3]); + // } + // printf("\n"); + } +} + +TEST_F(TestEnvMat, orig_pbc) +{ + std::vector fmt_nlist_a, fmt_nlist_r; + std::vector env, env_deriv, rij_a; + bool pbc = true; + for(int ii = 0; ii < nloc; ++ii){ + int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi, ntypes, atype, region, pbc, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); + EXPECT_EQ(ret, -1); + env_mat_a(env, env_deriv, rij_a, posi, ntypes, atype, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < sec_a[2]; ++jj){ + for (int dd = 0; dd < 4; ++dd){ + EXPECT_LT(fabs(env[jj*4+dd] - expected_env[ii*sec_a[2]*4 + jj*4 + dd]) , 1e-5); + } + } + } +} + + +TEST_F(TestEnvMat, orig_cpy_equal_pbc) +{ + std::vector fmt_nlist_a_0, fmt_nlist_r_0; + std::vector fmt_nlist_a_1, fmt_nlist_r_1; + std::vector env_0, env_deriv_0, rij_a_0; + std::vector env_1, env_deriv_1, rij_a_1; + for(int ii = 0; ii < nloc; ++ii){ + int ret_0 = format_nlist_fill_a(fmt_nlist_a_0, fmt_nlist_r_0, posi_cpy, ntypes, atype_cpy, region, false, ii, nlist_a_cpy[ii], nlist_r_cpy[ii], rc, sec_a, sec_r); + EXPECT_EQ(ret_0, -1); + env_mat_a(env_0, env_deriv_0, rij_a_0, posi_cpy, ntypes, atype_cpy, region, false, ii, fmt_nlist_a_0, sec_a, rc_smth, rc); + int ret_1 = format_nlist_fill_a(fmt_nlist_a_1, fmt_nlist_r_1, posi, ntypes, atype, region, true, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); + EXPECT_EQ(ret_1, -1); + env_mat_a(env_1, env_deriv_1, rij_a_1, posi, ntypes, atype, region, true, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + EXPECT_EQ(env_0.size(), env_1.size()); + EXPECT_EQ(env_deriv_0.size(), env_deriv_1.size()); + EXPECT_EQ(rij_a_0.size(), rij_a_1.size()); + for (unsigned jj = 0; jj < env_0.size(); ++jj){ + EXPECT_LT(fabs(env_0[jj] - env_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < env_deriv_0.size(); ++jj){ + EXPECT_LT(fabs(env_deriv_0[jj] - env_deriv_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < rij_a_0.size(); ++jj){ + EXPECT_LT(fabs(rij_a_0[jj] - rij_a_1[jj]), 1e-10); + } + } +} + + +TEST_F(TestEnvMat, orig_cpy_num_deriv) +{ + std::vector fmt_nlist_a, fmt_nlist_r; + std::vector env, env_0, env_1, env_deriv, env_deriv_tmp, rij_a; + bool pbc = false; + double hh = 1e-5; + for(int ii = 0; ii < nloc; ++ii){ + int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi_cpy, ntypes, atype_cpy, region, pbc, ii, nlist_a_cpy[ii], nlist_r_cpy[ii], rc, sec_a, sec_r); + EXPECT_EQ(ret, -1); + env_mat_a(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + + for (int jj = 0; jj < sec_a[2]; ++jj){ + int j_idx = fmt_nlist_a[jj]; + if (j_idx < 0) continue; + for (int kk = 0; kk < 4; ++kk){ + for (int dd = 0; dd < 3; ++dd){ + std::vector posi_0 = posi_cpy; + std::vector posi_1 = posi_cpy; + posi_0[j_idx*3+dd] -= hh; + posi_1[j_idx*3+dd] += hh; + env_mat_a(env_0, env_deriv_tmp, rij_a, posi_0, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a(env_1, env_deriv_tmp, rij_a, posi_1, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + double num_deriv = (env_1[jj*4+kk] - env_0[jj*4+kk])/(2.*hh); + double ana_deriv = -env_deriv[jj*12+kk*3+dd]; + EXPECT_LT(fabs(num_deriv - ana_deriv), 1e-5); + } + } + } + // for (int jj = 0; jj < sec_a[2]; ++jj){ + // printf("%7.5f, %7.5f, %7.5f, %7.5f, ", env[jj*4+0], env[jj*4+1], env[jj*4+2], env[jj*4+3]); + // } + // printf("\n"); + } +} + + +TEST_F(TestEnvMat, cpu) +{ + std::vector fmt_nlist_a, fmt_nlist_r; + std::vector env, env_deriv, rij_a; + bool pbc = false; + for(int ii = 0; ii < nloc; ++ii){ + int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi_cpy, ntypes, atype_cpy, region, pbc, ii, nlist_a_cpy[ii], nlist_r_cpy[ii], rc, sec_a, sec_r); + EXPECT_EQ(ret, -1); + env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < sec_a[2]; ++jj){ + for (int dd = 0; dd < 4; ++dd){ + EXPECT_LT(fabs(env[jj*4+dd] - expected_env[ii*sec_a[2]*4 + jj*4 + dd]) , 1e-5); + } + } + } +} + +TEST_F(TestEnvMat, cpu_equal_orig_cpy) +{ + std::vector fmt_nlist_a_0, fmt_nlist_r_0; + std::vector fmt_nlist_a_1, fmt_nlist_r_1; + std::vector env_0, env_deriv_0, rij_a_0; + std::vector env_1, env_deriv_1, rij_a_1; + for(int ii = 0; ii < nloc; ++ii){ + int ret_0 = format_nlist_fill_a(fmt_nlist_a_0, fmt_nlist_r_0, posi_cpy, ntypes, atype_cpy, region, false, ii, nlist_a_cpy[ii], nlist_r_cpy[ii], rc, sec_a, sec_r); + EXPECT_EQ(ret_0, -1); + env_mat_a(env_0, env_deriv_0, rij_a_0, posi_cpy, ntypes, atype_cpy, region, false, ii, fmt_nlist_a_0, sec_a, rc_smth, rc); + + int ret_1 = format_nlist_fill_a(fmt_nlist_a_1, fmt_nlist_r_1, posi_cpy, ntypes, atype_cpy, region, false, ii, nlist_a_cpy[ii], nlist_r_cpy[ii], rc, sec_a, sec_r); + EXPECT_EQ(ret_1, -1); + env_mat_a_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + + EXPECT_EQ(env_0.size(), env_1.size()); + EXPECT_EQ(env_deriv_0.size(), env_deriv_1.size()); + EXPECT_EQ(rij_a_0.size(), rij_a_1.size()); + for (unsigned jj = 0; jj < env_0.size(); ++jj){ + EXPECT_LT(fabs(env_0[jj] - env_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < env_deriv_0.size(); ++jj){ + EXPECT_LT(fabs(env_deriv_0[jj] - env_deriv_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < rij_a_0.size(); ++jj){ + EXPECT_LT(fabs(rij_a_0[jj] - rij_a_1[jj]), 1e-10); + } + } +} + +TEST_F(TestEnvMat, cpu_num_deriv) +{ + std::vector fmt_nlist_a, fmt_nlist_r; + std::vector env, env_0, env_1, env_deriv, env_deriv_tmp, rij_a; + bool pbc = false; + double hh = 1e-5; + for(int ii = 0; ii < nloc; ++ii){ + int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi_cpy, ntypes, atype_cpy, region, pbc, ii, nlist_a_cpy[ii], nlist_r_cpy[ii], rc, sec_a, sec_r); + EXPECT_EQ(ret, -1); + env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + + for (int jj = 0; jj < sec_a[2]; ++jj){ + int j_idx = fmt_nlist_a[jj]; + if (j_idx < 0) continue; + for (int kk = 0; kk < 4; ++kk){ + for (int dd = 0; dd < 3; ++dd){ + std::vector posi_0 = posi_cpy; + std::vector posi_1 = posi_cpy; + posi_0[j_idx*3+dd] -= hh; + posi_1[j_idx*3+dd] += hh; + env_mat_a(env_0, env_deriv_tmp, rij_a, posi_0, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a(env_1, env_deriv_tmp, rij_a, posi_1, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + double num_deriv = (env_1[jj*4+kk] - env_0[jj*4+kk])/(2.*hh); + double ana_deriv = -env_deriv[jj*12+kk*3+dd]; + EXPECT_LT(fabs(num_deriv - ana_deriv), 1e-5); + } + } + } + // for (int jj = 0; jj < sec_a[2]; ++jj){ + // printf("%7.5f, %7.5f, %7.5f, %7.5f, ", env[jj*4+0], env[jj*4+1], env[jj*4+2], env[jj*4+3]); + // } + // printf("\n"); + } +} diff --git a/source/lib/tests/test_fmt_nlist.cc b/source/lib/tests/test_fmt_nlist.cc new file mode 100644 index 0000000000..ef98484396 --- /dev/null +++ b/source/lib/tests/test_fmt_nlist.cc @@ -0,0 +1,147 @@ +#include +#include "fmt_nlist.h" +#include "NeighborList.h" + +class TestFormatNlist : public ::testing::Test +{ +protected: + std::vector posi = {12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall; + double rc = 6; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sec_a = {0, 10, 20}; + std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector expect_nlist_cpy = { + 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1 , 32, 34, 35, -1, -1, -1, -1, -1, -1, + 0 , 33, -1, -1, -1, -1, -1, -1, -1, -1, 32, 34, 35, -1, -1, -1, -1, -1, -1, -1, + 6 , 3 , -1, -1, -1, -1, -1, -1, -1, -1, 7 , 4 , 5 , -1, -1, -1, -1, -1, -1, -1, + 6 , -1, -1, -1, -1, -1, -1, -1, -1, -1, 4 , 5 , 2 , 7 , -1, -1, -1, -1, -1, -1, + 3 , 6 , -1, -1, -1, -1, -1, -1, -1, -1, 5 , 2 , 7 , -1, -1, -1, -1, -1, -1, -1, + 3 , 6 , -1, -1, -1, -1, -1, -1, -1, -1, 4 , 2 , 7 , -1, -1, -1, -1, -1, -1, -1 + }; + std::vector expect_nlist; + + void SetUp() override { + double box[] = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + region.reinitBox(box); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + for (unsigned ii = 0; ii < expect_nlist_cpy.size(); ++ii){ + if (expect_nlist_cpy[ii] >= 0){ + expect_nlist.push_back(mapping[expect_nlist_cpy[ii]]); + } + else{ + expect_nlist.push_back(-1); + } + } + } + void TearDown() override { + } +}; + + +// orginal implementation. copy ghost +TEST_F(TestFormatNlist, orig_cpy) +{ + std::vector> nlist_a, nlist_r; + std::vector fmt_nlist_a, fmt_nlist_r; + build_nlist(nlist_a, nlist_r, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + + bool pbc = false; + int ii = 0; + for (ii = 0; ii < nloc; ++ii){ + int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi_cpy, ntypes, atype_cpy, region, pbc, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); + + EXPECT_EQ(ret, -1); + for (int jj = 0; jj < sec_a[2]; ++jj){ + EXPECT_EQ(fmt_nlist_a[jj], expect_nlist_cpy[ii*sec_a[2]+jj]); + } + } +} + +// orginal implementation. copy ghost should be equal to pbc +TEST_F(TestFormatNlist, orig_pbc) +{ + std::vector> nlist_a_1, nlist_r_1; + build_nlist(nlist_a_1, nlist_r_1, posi, rc, rc, ncell, region); + + std::vector fmt_nlist_a_1, fmt_nlist_r_1; + + for (int ii = 0; ii < nloc; ++ii){ + int ret_1 = format_nlist_fill_a(fmt_nlist_a_1, fmt_nlist_r_1, posi, ntypes, atype, region, true, ii, nlist_a_1[ii], nlist_r_1[ii], rc, sec_a, sec_r); + + EXPECT_EQ(ret_1, -1); + for (int jj = 0; jj < sec_a[2]; ++jj){ + EXPECT_EQ(fmt_nlist_a_1[jj], expect_nlist[ii*sec_a[2]+jj]); + } + } +} + +// orginal implementation. copy ghost should be equal to pbc +TEST_F(TestFormatNlist, orig_cpy_equal_pbc) +{ + std::vector> nlist_a_0, nlist_r_0; + build_nlist(nlist_a_0, nlist_r_0, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + std::vector> nlist_a_1, nlist_r_1; + build_nlist(nlist_a_1, nlist_r_1, posi, rc, rc, ncell, region); + + std::vector fmt_nlist_a_0, fmt_nlist_r_0; + std::vector fmt_nlist_a_1, fmt_nlist_r_1; + + for (int ii = 0; ii < nloc; ++ii){ + int ret_0 = format_nlist_fill_a(fmt_nlist_a_0, fmt_nlist_r_0, posi_cpy, ntypes, atype_cpy, region, false, ii, nlist_a_0[ii], nlist_r_0[ii], rc, sec_a, sec_r); + int ret_1 = format_nlist_fill_a(fmt_nlist_a_1, fmt_nlist_r_1, posi, ntypes, atype, region, true, ii, nlist_a_1[ii], nlist_r_1[ii], rc, sec_a, sec_r); + + EXPECT_EQ(ret_0, -1); + EXPECT_EQ(ret_1, -1); + for (int jj = 0; jj < sec_a[2]; ++jj){ + if (fmt_nlist_a_0[jj] == -1){ + // null record + EXPECT_EQ(fmt_nlist_a_1[jj], -1); + } + else{ + EXPECT_EQ(fmt_nlist_a_1[jj], mapping[fmt_nlist_a_0[jj]]); + } + } + } +} + +TEST_F(TestFormatNlist, cpu_equal_orig) +{ + std::vector> nlist_a_0, nlist_r_0; + build_nlist(nlist_a_0, nlist_r_0, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + + std::vector fmt_nlist_a_0, fmt_nlist_r_0; + std::vector fmt_nlist_a_1; + + for (int ii = 0; ii < nloc; ++ii){ + int ret_0 = format_nlist_fill_a(fmt_nlist_a_0, fmt_nlist_r_0, posi_cpy, ntypes, atype_cpy, region, false, ii, nlist_a_0[ii], nlist_r_0[ii], rc, sec_a, sec_r); + int ret_1 = format_nlist_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_0[ii], rc, sec_a); + EXPECT_EQ(ret_0, -1); + EXPECT_EQ(ret_1, -1); + for (int jj = 0; jj < sec_a[2]; ++jj){ + EXPECT_EQ(fmt_nlist_a_1[jj], fmt_nlist_a_0[jj]); + } + } +} + diff --git a/source/lib/tests/test_main.cc b/source/lib/tests/test_main.cc new file mode 100644 index 0000000000..4d820af774 --- /dev/null +++ b/source/lib/tests/test_main.cc @@ -0,0 +1,6 @@ +#include + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/source/lib/tests/test_simulation_region.cc b/source/lib/tests/test_simulation_region.cc new file mode 100644 index 0000000000..4803fddef2 --- /dev/null +++ b/source/lib/tests/test_simulation_region.cc @@ -0,0 +1,17 @@ + +#include +#include +#include "SimulationRegion.h" + +double square_root (const double xx) +{ + return sqrt(xx); +} + +TEST (SquareRootTest, PositiveNos) { + EXPECT_EQ (18.0, square_root (324.0)); + EXPECT_EQ (25.4, square_root (645.16)); + EXPECT_EQ (50.332, square_root (2533.310224)); +} + + diff --git a/source/lmp/env.sh.in b/source/lmp/env.sh.in index 2e091432f6..4baf835aff 100644 --- a/source/lmp/env.sh.in +++ b/source/lmp/env.sh.in @@ -8,4 +8,4 @@ TF_RPATH=`echo $TENSORFLOW_LIBRARY_PATH | sed "s/;/ -Wl,-rpath=/g"` NNP_INC=" -std=c++11 @PREC_DEF@ @TTM_DEF@ @OLD_LMP_PPPM_DEF@ -I$TF_INCLUDE_DIRS -I$DEEPMD_ROOT/include/deepmd " NNP_PATH=" -L$TF_LIBRARY_PATH -L$DEEPMD_ROOT/lib" -NNP_LIB=" -Wl,--no-as-needed -l@LIB_DEEPMD_OP_CUDA@ -l@LIB_DEEPMD_OP@ -l@LIB_DEEPMD@ -ltensorflow_cc -ltensorflow_framework -Wl,-rpath=$TF_RPATH -Wl,-rpath=$DEEPMD_ROOT/lib" +NNP_LIB=" -Wl,--no-as-needed -l@LIB_DEEPMD_OP_CUDA@ -l@LIB_DEEPMD_OP@ -l@LIB_DEEPMD_CC@ -l@LIB_DEEPMD@ -ltensorflow_cc -ltensorflow_framework -Wl,-rpath=$TF_RPATH -Wl,-rpath=$DEEPMD_ROOT/lib" diff --git a/source/op/descrpt.cc b/source/op/descrpt.cc index 71918b4a5a..0e15e75d43 100644 --- a/source/op/descrpt.cc +++ b/source/op/descrpt.cc @@ -5,6 +5,7 @@ #include "ComputeDescriptor.h" #include "NeighborList.h" +#include "fmt_nlist.h" typedef double boxtensor_t ; typedef double compute_t; diff --git a/source/op/descrpt_se_a.cc b/source/op/descrpt_se_a.cc index a9a694887b..c0f49433ec 100644 --- a/source/op/descrpt_se_a.cc +++ b/source/op/descrpt_se_a.cc @@ -5,6 +5,8 @@ #include "ComputeDescriptor.h" #include "NeighborList.h" +#include "fmt_nlist.h" +#include "env_mat.h" typedef double boxtensor_t ; typedef double compute_t; @@ -286,19 +288,19 @@ class DescrptSeAOp : public OpKernel { std::vector d_descrpt_r_deriv; std::vector d_rij_a; std::vector d_rij_r; - compute_descriptor_se_a (d_descrpt_a, - d_descrpt_a_deriv, - d_rij_a, - d_coord3, - ntypes, - d_type, - region, - b_pbc, - ii, - fmt_nlist_a, - sec_a, - rcut_r_smth, - rcut_r); + env_mat_a (d_descrpt_a, + d_descrpt_a_deriv, + d_rij_a, + d_coord3, + ntypes, + d_type, + region, + b_pbc, + ii, + fmt_nlist_a, + sec_a, + rcut_r_smth, + rcut_r); // check sizes assert (d_descrpt_a.size() == ndescrpt_a); diff --git a/source/op/descrpt_se_a_ef.cc b/source/op/descrpt_se_a_ef.cc index b4a631b7cf..8cd081434c 100644 --- a/source/op/descrpt_se_a_ef.cc +++ b/source/op/descrpt_se_a_ef.cc @@ -5,6 +5,7 @@ #include "ComputeDescriptor.h" #include "NeighborList.h" +#include "fmt_nlist.h" typedef double boxtensor_t ; typedef double compute_t; diff --git a/source/op/descrpt_se_a_ef_para.cc b/source/op/descrpt_se_a_ef_para.cc index af17b3ca12..97c836dcc8 100644 --- a/source/op/descrpt_se_a_ef_para.cc +++ b/source/op/descrpt_se_a_ef_para.cc @@ -5,6 +5,7 @@ #include "ComputeDescriptor.h" #include "NeighborList.h" +#include "fmt_nlist.h" typedef double boxtensor_t ; typedef double compute_t; diff --git a/source/op/descrpt_se_a_ef_vert.cc b/source/op/descrpt_se_a_ef_vert.cc index 1d416864e2..ea02156acf 100644 --- a/source/op/descrpt_se_a_ef_vert.cc +++ b/source/op/descrpt_se_a_ef_vert.cc @@ -5,6 +5,7 @@ #include "ComputeDescriptor.h" #include "NeighborList.h" +#include "fmt_nlist.h" typedef double boxtensor_t ; typedef double compute_t; diff --git a/source/op/descrpt_se_r.cc b/source/op/descrpt_se_r.cc index c7e989a8a9..e8777f680d 100644 --- a/source/op/descrpt_se_r.cc +++ b/source/op/descrpt_se_r.cc @@ -5,6 +5,7 @@ #include "ComputeDescriptor.h" #include "NeighborList.h" +#include "fmt_nlist.h" typedef double boxtensor_t ; typedef double compute_t; From cb25cdca6ed3f8e079427fe1ca82a7dac9cb0cac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Sat, 6 Feb 2021 10:52:03 +0100 Subject: [PATCH 097/562] add requested relative paths --- deepmd/common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deepmd/common.py b/deepmd/common.py index 830f92e981..0e6db4c363 100644 --- a/deepmd/common.py +++ b/deepmd/common.py @@ -28,7 +28,7 @@ try: from typing import Literal # python >3.6 except ImportError: - from typing_extensions import Literal + from typing_extensions import Literal # type: ignore _ACTIVATION = Literal["relu", "relu6", "softplus", "sigmoid", "tanh", "gelu"] _PRECISION = Literal["default", "float16", "float32", "float64"] @@ -428,7 +428,7 @@ def expand_sys_str(root_dir: Union[str, Path]) -> List[str]: list of string pointing to system directories """ matches = [d for d in Path(root_dir).rglob("*") if (d / "type.raw").is_file()] - return [str(m.resolve()) for m in matches] + return [str(m.relative_to(root_dir)) for m in matches] def docstring_parameter(*sub: Tuple[str, ...]): From feb0669b7666ce256040fc8941378e649a083760 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Sat, 6 Feb 2021 19:21:40 +0800 Subject: [PATCH 098/562] optimize code structure for method EnvMatStat --- deepmd/descriptor/se_a.py | 16 ++- deepmd/utils/env_mat_stat.py | 121 +++++++++++++++-------- source/lib/include/ComputeDescriptor.h | 46 +++++++++ source/lib/include/CustomeOperation.h | 4 +- source/op/descrpt.cc | 2 +- source/op/env_mat_stat.cc | 131 ++++--------------------- source/train/Trainer.py | 10 +- 7 files changed, 159 insertions(+), 171 deletions(-) diff --git a/deepmd/descriptor/se_a.py b/deepmd/descriptor/se_a.py index e40210de1a..3b9a4db0af 100644 --- a/deepmd/descriptor/se_a.py +++ b/deepmd/descriptor/se_a.py @@ -231,8 +231,6 @@ def compute_input_stats (self, self.dstd = np.array(all_dstd) def enable_compression(self, - distance, - max_nbor_size, env_mat_range, model_file = 'frozon_model.pb', table_config = [5, 0.01, 0.1, -1] @@ -242,22 +240,22 @@ def enable_compression(self, Parameters ---------- - distance - The nearest nbor distance between atoms - max_nbor_size - The max nbor size of atoms env_mat_range The output data range of the environment matrix + env_mat_range[0] denotes the lower boundary of environment matrix + env_mat_range[1] denotes the upper boundary of environment matrix model_file The original frozen model, that will be compressed - table_info + table_config The configuration of the tabulation + Table_config[0] denotes the scale of model extrapolation + Table_config[1] denotes the first table stride + Table_config[2] denotes the second table stride + Table_config[3] denotes the overflow check frequency """ self.compress = True self.model_file = model_file self.table_config = table_config - self.distance = distance - self.max_nbor_size = max_nbor_size self.env_mat_range = env_mat_range self.table = DeepTabulate(self.model_file, self.filter_np_precision, self.type_one_side) diff --git a/deepmd/utils/env_mat_stat.py b/deepmd/utils/env_mat_stat.py index 4096024007..1518207de7 100644 --- a/deepmd/utils/env_mat_stat.py +++ b/deepmd/utils/env_mat_stat.py @@ -15,6 +15,7 @@ class EnvMatStat(): def __init__(self, descrpt_type : str, ntypes : int, + ndescrpt : int, rcut, rcut_smth, sel, @@ -29,6 +30,8 @@ def __init__(self, The descrpt type of the embedding net ntypes The num of atom types + ndescrpt + The width of environment matrix rcut The cut-off radius rcut_smth @@ -40,9 +43,15 @@ def __init__(self, dstd Standard deviation of training data """ + self.init_stat = False self.davg = davg self.dstd = dstd + if self.davg is None: + self.davg = np.zeros([self.ntypes, self.ndescrpt]) + if self.dstd is None: + self.dstd = np.ones ([self.ntypes, self.ndescrpt]) self.ntypes = ntypes + self.ndescrpt = ndescrpt self.descrpt_type = descrpt_type assert self.descrpt_type == 'se_a', 'Model compression error: descriptor type must be se_a!' self.place_holders = {} @@ -56,23 +65,21 @@ def __init__(self, self.sel = sel self.rcut = rcut self.rcut_smth = rcut_smth - self.distance, self.max_nbor_size, self.table_range \ + self._min_nbor_dist, self._max_nbor_size \ = op_module.env_mat_stat(self.place_holders['coord'], self.place_holders['type'], self.place_holders['natoms_vec'], self.place_holders['box'], self.place_holders['default_mesh'], - self.place_holders['avg'], - self.place_holders['std'], sel = self.sel, rcut = self.rcut, rcut_smth = self.rcut_smth) self.sub_sess = tf.Session(graph = sub_graph, config=default_tf_session_config) - def env_mat_stat(self, - data) -> Tuple[float, int, List[float]]: + def get_env_mat_stat(self, + data) -> Tuple[float, int]: """ - get the data info of the training data, including neareest nbor distance between atoms, max nbor size of atoms and the output data range of the environment matrix + get the data statistics of the training data, including nearest nbor distance between atoms, max nbor size of atoms Parameters ---------- @@ -81,56 +88,90 @@ def env_mat_stat(self, Returns ------- - distance + min_nbor_dist The nearest nbor distance between atoms max_nbor_size The max nbor size of atoms - env_mat_range - The output data range of the environment matrix """ - self.lower = 0.0 - self.upper = 0.0 - self.dist = 100.0 - self.max_nbor = 0 - - davg = self.davg - dstd = self.dstd - if davg is None: - davg = np.zeros([self.ntypes, self.ndescrpt]) - if dstd is None: - dstd = np.ones ([self.ntypes, self.ndescrpt]) + self.max_nbor_size = 0 + self.min_nbor_dist = 100.0 for ii in tqdm(range(len(data.system_dirs)), desc = '# DEEPMD: getting data info'): for jj in data.data_systems[ii].dirs: data_set = data.data_systems[ii]._load_set(jj) for kk in range(np.array(data_set['type']).shape[0]): - dt, mn, tr \ - = self.sub_sess.run([self.distance, self.max_nbor_size, self.table_range], + dt, mn \ + = self.sub_sess.run([self._min_nbor_dist, self._max_nbor_size], feed_dict = { self.place_holders['coord']: np.array(data_set['coord'])[kk].reshape([-1, data.natoms[ii] * 3]), self.place_holders['type']: np.array(data_set['type'])[kk].reshape([-1, data.natoms[ii]]), self.place_holders['natoms_vec']: np.array(data.natoms_vec[ii]), self.place_holders['box']: np.array(data_set['box'])[kk].reshape([-1, 9]), self.place_holders['default_mesh']: np.array(data.default_mesh[ii]), - self.place_holders['avg']: davg, - self.place_holders['std']: dstd, }) - dr = np.array([np.min(tr), np.max(tr)]).astype(global_np_float_precision) dt = np.min(dt) mn = np.max(mn) - if (dr[0] < self.lower): - self.lower = dr[0] - if (dr[1] > self.upper): - self.upper = dr[1] - if (dt < self.dist): - self.dist = dt - if (mn > self.max_nbor): - self.max_nbor = mn + if (dt < self.min_nbor_dist): + self.min_nbor_dist = dt + if (mn > self.max_nbor_size): + self.max_nbor_size = mn + self.init_stat = True + return self.min_nbor_dist, self.max_nbor_size + + def get_env_mat_range(self, + data) -> List[float]: + """ + get the data statistics of the training data, including the output data range of the environment matrix + + Parameters + ---------- + data + Class for manipulating many data systems. It is implemented with the help of DeepmdData. + + Returns + ------- + env_mat_range + The output data range of the environment matrix + env_mat_range[0] denotes the lower boundary of environment matrix + env_mat_range[1] denotes the upper boundary of environment matrix + """ + if self.init_stat: + min_nbor_dist = self.min_nbor_dist + max_nbor_size = self.max_nbor_size + else: + min_nbor_dist, max_nbor_size = self.get_env_mat_stat(data) + self.env_mat_range = self._get_internal_env_mat_range(min_nbor_dist, max_nbor_size) + print('# DEEPMD: training data with lower boundary: ' + str(self.env_mat_range[0])) + print('# DEEPMD: training data with upper boundary: ' + str(self.env_mat_range[1])) + print('# DEEPMD: training data with min distance: ' + str(self.min_nbor_dist)) + print('# DEEPMD: training data with max nborsize: ' + str(self.max_nbor_size)) + return self.env_mat_range + + def _get_internal_env_mat_range(self, + min_nbor_dist, + max_nbor_size): + """ + Warning: different descrpt_type may have different method to get the mat range + """ + lower = 100.0 + upper = -10.0 + sw = self._spline5_switch(self.min_nbor_dist, self.rcut_smth, self.rcut) + for ii in range(self.ntypes): + if lower > -self.davg[ii][0] / self.dstd[ii][0]: + lower = -self.davg[ii][0] / self.dstd[ii][0] + if upper < ((1 / self.min_nbor_dist) * sw - self.davg[ii][0]) / self.dstd[ii][0]: + upper = ((1 / self.min_nbor_dist) * sw - self.davg[ii][0]) / self.dstd[ii][0] + return [lower, upper] - print('# DEEPMD: training data with lower boundary: ' + str(self.lower)) - print('# DEEPMD: training data with upper boundary: ' + str(self.upper)) - print('# DEEPMD: training data with min distance: ' + str(self.dist)) - print('# DEEPMD: training data with max nborsize: ' + str(self.max_nbor)) - env_mat_range = [self.lower, self.upper] - return self.distance, self.max_nbor_size, env_mat_range - \ No newline at end of file + def _spline5_switch(self, + xx, + rmin, + rmax): + if xx < rmin: + vv = 1 + elif xx < rmax: + uu = (xx - rmin) / (rmax - rmin) + vv = uu*uu*uu * (-6 * uu*uu + 15 * uu - 10) + 1 + else: + vv = 0 + return vv diff --git a/source/lib/include/ComputeDescriptor.h b/source/lib/include/ComputeDescriptor.h index b01f9ed44b..bab9032828 100644 --- a/source/lib/include/ComputeDescriptor.h +++ b/source/lib/include/ComputeDescriptor.h @@ -143,6 +143,18 @@ void compute_descriptor_se_r (std::vector & descrpt_r, const double & rmin, const double & rmax); +inline +void get_rij(std::vector & rij_a, + const std::vector & posi, + const int & ntypes, + const std::vector & type, + const SimulationRegion & region, + const bool & b_pbc, + const int & i_idx, + const std::vector & fmt_nlist_a, + const std::vector & sec_a, + const double & rmin, + const double & rmax); struct NeighborInfo { @@ -1063,6 +1075,40 @@ void compute_descriptor_se_a (std::vector & descrpt_a, } } +void get_rij(std::vector & rij_a, + const std::vector & posi, + const int & ntypes, + const std::vector & type, + const SimulationRegion & region, + const bool & b_pbc, + const int & i_idx, + const std::vector & fmt_nlist_a, + const std::vector & sec_a, + const double & rmin, + const double & rmax) +{ + // compute the diff of the neighbors + std::vector > sel_a_diff (sec_a.back()); + rij_a.resize (sec_a.back() * 3); + fill (rij_a.begin(), rij_a.end(), 0.0); + for (int ii = 0; ii < int(sec_a.size()) - 1; ++ii){ + for (int jj = sec_a[ii]; jj < sec_a[ii+1]; ++jj){ + if (fmt_nlist_a[jj] < 0) break; + sel_a_diff[jj].resize(3); + const int & j_idx = fmt_nlist_a[jj]; + if (b_pbc){ + region.diffNearestNeighbor (posi[j_idx*3+0], posi[j_idx*3+1], posi[j_idx*3+2], + posi[i_idx*3+0], posi[i_idx*3+1], posi[i_idx*3+2], + sel_a_diff[jj][0], sel_a_diff[jj][1], sel_a_diff[jj][2]); + } + else { + for (int dd = 0; dd < 3; ++dd) sel_a_diff[jj][dd] = posi[j_idx*3+dd] - posi[i_idx*3+dd]; + } + for (int dd = 0; dd < 3; ++dd) rij_a[jj*3+dd] = sel_a_diff[jj][dd]; + } + } +} + void compute_descriptor_se_r (std::vector & descrpt, std::vector & descrpt_deriv, diff --git a/source/lib/include/CustomeOperation.h b/source/lib/include/CustomeOperation.h index 98b64e44af..5871175dd7 100644 --- a/source/lib/include/CustomeOperation.h +++ b/source/lib/include/CustomeOperation.h @@ -169,7 +169,7 @@ void compute_descriptor_se_a_cpu ( } template -void DescrptSeACPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { +void DescrptSeACPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { // set & normalize coord std::vector d_coord3(nall * 3); for (int ii = 0; ii < nall; ++ii) { @@ -235,7 +235,7 @@ void DescrptSeACPULauncher(const FPTYPE * coord, const int * type, const int * i #if GOOGLE_CUDA template -void DescrptSeAGPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { +void DescrptSeAGPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { DescrptSeAGPUExecuteFunctor()(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); } #endif // GOOGLE_CUDA diff --git a/source/op/descrpt.cc b/source/op/descrpt.cc index 201169f7f1..71918b4a5a 100644 --- a/source/op/descrpt.cc +++ b/source/op/descrpt.cc @@ -602,7 +602,7 @@ class DescrptOp : public OpKernel { #define REGISTER_CPU(T) \ REGISTER_KERNEL_BUILDER( \ - Name("Descrpt").Device(DEVICE_CPU).TypeConstraint("T"), \ + Name("Descrpt").Device(DEVICE_CPU).TypeConstraint("T"), \ DescrptOp); REGISTER_CPU(float); REGISTER_CPU(double); diff --git a/source/op/env_mat_stat.cc b/source/op/env_mat_stat.cc index 58e555083c..0db739272f 100644 --- a/source/op/env_mat_stat.cc +++ b/source/op/env_mat_stat.cc @@ -22,14 +22,11 @@ REGISTER_OP("EnvMatStat") .Input("natoms: int32") //local atomic number; each type atomic number; daizheyingxiangqude atomic numbers .Input("box : T") .Input("mesh : int32") - .Input("davg: T") //average value of data - .Input("dstd: T") //standard deviation .Attr("rcut: float") //no use .Attr("rcut_smth: float") .Attr("sel: list(int)") - .Output("distance: T") - .Output("max_nbor_size: int32") - .Output("env_stat_range: T"); + .Output("min_nbor_dist: T") + .Output("max_nbor_size: int32"); template class EnvMatStatOp : public OpKernel { @@ -41,8 +38,6 @@ class EnvMatStatOp : public OpKernel { cum_sum (sec, sel); ndescrpt = sec.back() * 4; nnei = sec.back(); - fill_nei_a = true; - count_nei_idx_overflow = 0; } void Compute(OpKernelContext* context) override { @@ -54,8 +49,6 @@ class EnvMatStatOp : public OpKernel { const Tensor& natoms_tensor = context->input(context_input_index++); const Tensor& box_tensor = context->input(context_input_index++); const Tensor& mesh_tensor = context->input(context_input_index++); - const Tensor& avg_tensor = context->input(context_input_index++); - const Tensor& std_tensor = context->input(context_input_index++); // set size of the sample OP_REQUIRES (context, (coord_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of coord should be 2")); @@ -63,10 +56,6 @@ class EnvMatStatOp : public OpKernel { OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); OP_REQUIRES (context, (box_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of box should be 2")); OP_REQUIRES (context, (mesh_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of mesh should be 1")); - OP_REQUIRES (context, (avg_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of avg should be 2")); - OP_REQUIRES (context, (std_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of std should be 2")); - OP_REQUIRES (context, (fill_nei_a), errors::InvalidArgument ("Rotational free descriptor only support the case -1 < 0")); - OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); auto natoms = natoms_tensor .flat(); int nloc = natoms(0); @@ -77,14 +66,9 @@ class EnvMatStatOp : public OpKernel { // check the sizes OP_REQUIRES (context, (nsamples == type_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); OP_REQUIRES (context, (nsamples == box_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (ntypes == avg_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of avg should be ntype")); - OP_REQUIRES (context, (ntypes == std_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of std should be ntype")); - OP_REQUIRES (context, (nall * 3 == coord_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); OP_REQUIRES (context, (nall == type_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); OP_REQUIRES (context, (9 == box_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of box should be 9")); - OP_REQUIRES (context, (ndescrpt == avg_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of avg should be ndescrpt")); - OP_REQUIRES (context, (ndescrpt == std_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of std should be ndescrpt")); int nei_mode = 0; if (mesh_tensor.shape().dim_size(0) == 16) { @@ -117,83 +101,35 @@ class EnvMatStatOp : public OpKernel { b_norm_atom = true; } - // Create an output tensor - TensorShape descrpt_shape ; - descrpt_shape.AddDim (nsamples); - descrpt_shape.AddDim (nloc * ndescrpt); - TensorShape descrpt_deriv_shape ; - descrpt_deriv_shape.AddDim (nsamples); - descrpt_deriv_shape.AddDim (nloc * ndescrpt * 3); - TensorShape rij_shape ; - rij_shape.AddDim (nsamples); - rij_shape.AddDim (nloc * nnei * 3); - TensorShape nlist_shape ; - nlist_shape.AddDim (nsamples); - nlist_shape.AddDim (nloc * nnei); - TensorShape distance_shape ; - distance_shape.AddDim (nloc * nnei); + TensorShape min_nbor_dist_shape ; + min_nbor_dist_shape.AddDim (nloc * nnei); TensorShape max_nbor_size_shape ; max_nbor_size_shape.AddDim (nloc); - TensorShape table_range_shape ; - table_range_shape.AddDim (nloc * nnei); - - Tensor descrpt_tensor; - OP_REQUIRES_OK(context, context->allocate_temp(DT_DOUBLE, descrpt_shape, &descrpt_tensor)); - - Tensor descrpt_deriv_tensor; - OP_REQUIRES_OK(context, context->allocate_temp(DT_DOUBLE, descrpt_deriv_shape, &descrpt_deriv_tensor)); - - Tensor rij_tensor; - OP_REQUIRES_OK(context, context->allocate_temp(DT_DOUBLE, rij_shape, &rij_tensor)); - Tensor nlist_tensor; - OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, nlist_shape, &nlist_tensor)); - int context_output_index = 0; - Tensor* distance_tensor = NULL; + Tensor* min_nbor_dist_tensor = NULL; OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - distance_shape, - &distance_tensor)); + min_nbor_dist_shape, + &min_nbor_dist_tensor)); Tensor* max_nbor_size_tensor = NULL; OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, max_nbor_size_shape, &max_nbor_size_tensor)); - Tensor* table_range_tensor = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - table_range_shape, - &table_range_tensor)); auto coord = coord_tensor .matrix(); auto type = type_tensor .matrix(); auto box = box_tensor .matrix(); auto mesh = mesh_tensor .flat(); - auto avg = avg_tensor .matrix(); - auto std = std_tensor .matrix(); - auto descrpt = descrpt_tensor .matrix(); - auto descrpt_deriv = descrpt_deriv_tensor .matrix(); - auto rij = rij_tensor .matrix(); - auto nlist = nlist_tensor .matrix(); - auto distance = distance_tensor ->flat(); + auto min_nbor_dist = min_nbor_dist_tensor ->flat(); // find a potential bug here! auto max_nbor_size = max_nbor_size_tensor ->flat(); - auto table_range = table_range_tensor ->flat(); - for (int ii = 0; ii < static_cast(distance_tensor->NumElements()); ii++) { - distance(ii) = 10000.0; + for (int ii = 0; ii < static_cast(min_nbor_dist_tensor->NumElements()); ii++) { + min_nbor_dist(ii) = 10000.0; } for (int ii = 0; ii < static_cast(max_nbor_size_tensor->NumElements()); ii++) { max_nbor_size(ii) = 0; } - for (int ii = 0; ii < static_cast(table_range_tensor->NumElements()); ii++) { - table_range(ii) = 0.0; - } - // // check the types - // int max_type_v = 0; - // for (int ii = 0; ii < natoms; ++ii){ - // if (type(0, ii) > max_type_v) max_type_v = type(0, ii); - // } - // int ntypes = max_type_v + 1; - OP_REQUIRES (context, (ntypes == int(sel.size())), errors::InvalidArgument ("number of types should match the length of sel array")); for (int kk = 0; kk < nsamples; ++kk){ // set region @@ -293,25 +229,16 @@ class EnvMatStatOp : public OpKernel { std::vector sec_r(sec.size(), 0); int ret = -1; - if (fill_nei_a){ - if ((ret = format_nlist_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut, sec, sec_r)) != -1){ - if (count_nei_idx_overflow == 0) { - std::cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << std::endl; - flush(std::cout); - count_nei_idx_overflow ++; - } + if ((ret = format_nlist_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut, sec, sec_r)) != -1){ + if (count_nei_idx_overflow == 0) { + std::cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << std::endl; + flush(std::cout); + count_nei_idx_overflow ++; } } - std::vector d_descrpt_a; - std::vector d_descrpt_a_deriv; - std::vector d_descrpt_r; - std::vector d_descrpt_r_deriv; std::vector d_rij_a; - std::vector d_rij_r; - compute_descriptor_se_a (d_descrpt_a, - d_descrpt_a_deriv, - d_rij_a, + get_rij (d_rij_a, d_coord3, ntypes, d_type, @@ -324,37 +251,13 @@ class EnvMatStatOp : public OpKernel { rcut); // check sizes - assert (d_descrpt_a.size() == ndescrpt); - assert (d_descrpt_a_deriv.size() == ndescrpt * 3); assert (d_rij_a.size() == nnei * 3); assert (int(fmt_nlist_a.size()) == nnei); - // std::cout << "min:\t" << (0 - avg(0, 0)) / std(0, 0) << std::endl; - // if (counter % 1000 == 0) { - // std::cout << "min:\t" << (0 - avg(0, 0)) / std(0, 0) << std::endl; - // } - // record outputs - for (int jj = 0; jj < ndescrpt; ++jj) { - descrpt(kk, ii * ndescrpt + jj) = (d_descrpt_a[jj] - avg(d_type[ii], jj)) / std(d_type[ii], jj); - if (jj % 4 == 0) { - table_range(ii * nnei + jj / 4) = descrpt(kk, ii * ndescrpt + jj); - } - } - for (int jj = 0; jj < ndescrpt * 3; ++jj) { - descrpt_deriv(kk, ii * ndescrpt * 3 + jj) = d_descrpt_a_deriv[jj] / std(d_type[ii], jj/3); - } for (int jj = 0; jj < nnei * 3; ++jj){ - rij (kk, ii * nnei * 3 + jj) = d_rij_a[jj]; if (jj % 3 == 0 && d_rij_a[jj] > 0) { - distance(ii * nnei + jj / 3) = sqrt(d_rij_a[jj] * d_rij_a[jj] + d_rij_a[jj + 1] * d_rij_a[jj + 1] + d_rij_a[jj + 2] * d_rij_a[jj + 2]); + min_nbor_dist(ii * nnei + jj / 3) = sqrt(d_rij_a[jj] * d_rij_a[jj] + d_rij_a[jj + 1] * d_rij_a[jj + 1] + d_rij_a[jj + 2] * d_rij_a[jj + 2]); } } - for (int jj = 0; jj < nnei; ++jj){ - int record = fmt_nlist_a[jj]; - if (b_nlist_map && record >= 0) { - record = nlist_map[record]; - } - nlist (kk, ii * nnei + jj) = record; - } } } } diff --git a/source/train/Trainer.py b/source/train/Trainer.py index 671a69e4d0..e0a1b80c36 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -281,17 +281,17 @@ def build (self, assert hasattr(self.descrpt, 'davg'), "Model compression error: descriptor must have attr davg!" assert hasattr(self.descrpt, 'dstd'), "Model compression error: descriptor must have attr dstd!" assert hasattr(self.descrpt, 'ntypes'), "Model compression error: descriptor must have attr ntypes!" + assert hasattr(self.descrpt, 'ndescrpt'), "Model compression error: descriptor must have attr ndescrpt!" assert 'sel' in self.descrpt_param, "Model compression error: descriptor must have attr sel!" assert 'rcut' in self.descrpt_param, "Model compression error: descriptor must have attr rcut!" assert 'rcut_smth' in self.descrpt_param, "Model compression error: descriptor must have attr rcut_smth!" if self.descrpt_type == 'se_a': - stat = EnvMatStat(self.descrpt_type, self.descrpt.ntypes, self.descrpt_param['rcut'], self.descrpt_param['rcut_smth'], self.descrpt_param['sel'], self.descrpt.davg, self.descrpt.dstd) + stat = EnvMatStat(self.descrpt_type, self.descrpt.ntypes, self.descrpt.ndescrpt, self.descrpt_param['rcut'], self.descrpt_param['rcut_smth'], self.descrpt_param['sel'], self.descrpt.davg, self.descrpt.dstd) else: raise RuntimeError ("Model compression error: descriptor type must be se_a!") - - distance, max_nbor_size, env_mat_range\ - = stat.env_mat_stat(data) - self.descrpt.enable_compression(distance, max_nbor_size, env_mat_range, self.compress_param['model_file'], self.compress_param['table_config']) # send the statistics of the training data and activate the descriptor compression mode + env_mat_range\ + = stat.get_env_mat_range(data) + self.descrpt.enable_compression(env_mat_range, self.compress_param['model_file'], self.compress_param['table_config']) # send the statistics of the training data and activate the descriptor compression mode worker_device = "/job:%s/task:%d/%s" % (self.run_opt.my_job_name, self.run_opt.my_task_index, From 0a6bba2f91085d2f63581b49af0b60bc12eff6b4 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Sat, 6 Feb 2021 19:28:07 +0800 Subject: [PATCH 099/562] Update CustomeOperation.h --- source/lib/include/CustomeOperation.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/lib/include/CustomeOperation.h b/source/lib/include/CustomeOperation.h index 5871175dd7..e8669c9f28 100644 --- a/source/lib/include/CustomeOperation.h +++ b/source/lib/include/CustomeOperation.h @@ -236,7 +236,7 @@ void DescrptSeACPULauncher(const FPTYPE * coord, const int * type, const int * i #if GOOGLE_CUDA template void DescrptSeAGPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { - DescrptSeAGPUExecuteFunctor()(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); + DescrptSeAGPUExecuteFunctor()(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); } #endif // GOOGLE_CUDA // ****************************************************************************** @@ -432,7 +432,7 @@ void compute_descriptor_se_r_cpu ( } template -void DescrptSeRCPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { +void DescrptSeRCPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { // set & normalize coord std::vector d_coord3(nall * 3); for (int ii = 0; ii < nall; ++ii) { @@ -498,8 +498,8 @@ void DescrptSeRCPULauncher(const FPTYPE * coord, const int * type, const int * i #if GOOGLE_CUDA template -void DescrptSeRGPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int magic_number) { - DescrptSeRGPUExecuteFunctor()(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, magic_number); +void DescrptSeRGPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { + DescrptSeRGPUExecuteFunctor()(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); } #endif // GOOGLE_CUDA // ****************************************************************************** From 2ce5089de7303975fc31c5f742a5e7489dc9d086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Sat, 6 Feb 2021 12:33:31 +0100 Subject: [PATCH 100/562] test new liner action --- .github/workflows/lint_python.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml index 8263d523c0..4dea2ec310 100644 --- a/.github/workflows/lint_python.yml +++ b/.github/workflows/lint_python.yml @@ -5,10 +5,10 @@ name: Lint Python jobs: lintpython: name: Lint Python - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 strategy: matrix: - python-version: [3.6] + python-version: [3.8] steps: - uses: actions/checkout@v1 @@ -17,14 +17,17 @@ jobs: python-version: ${{ matrix.python }} - name: Install requirements run: pip install -r requirements.txt - - uses: marian-code/pyaction@master + - uses: marian-code/pyaction@v2.2.0 with: python-root-list: "./deepmd/*.py ./deepmd/*/*.py ./source/train/*.py ./source/tests/*.py ./source/scripts/*.py ./source/op/*.py" use-black: true use-isort: true use-mypy: true use-pycodestyle: true + use-pydocstyle: true extra-pycodestyle-options: "--max-line-length=88" use-pylint: false use-flake8: false - use-vulture: false + use-vulture: true + conda-python-version: "3.8" + From 0d148cba806b50a7ce6b05cac50ea9955c708875 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 6 Feb 2021 21:42:55 +0800 Subject: [PATCH 101/562] fix bug of missing lib file when installing python interface --- source/CMakeLists.txt | 4 ++-- source/lib/CMakeLists.txt | 16 ++++++++++------ source/op/CMakeLists.txt | 2 ++ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 75c90b6c4f..d8e5addb31 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -185,8 +185,8 @@ include_directories(${DeePMD_INCLUDE_DIRS}) include_directories(${TensorFlow_INCLUDE_DIRS}) # define names of libs +set (LIB_DEEPMD "deepmd") if (BUILD_CPP_IF) - set (LIB_DEEPMD "deepmd") set (LIB_DEEPMD_OP "deepmd_op") set (LIB_DEEPMD_CC "deepmd_cc") if (USE_CUDA_TOOLKIT) @@ -203,6 +203,7 @@ if (BUILD_CPP_IF) endif (BUILD_CPP_IF) add_subdirectory (op/) +add_subdirectory (lib/) if (BUILD_PY_IF) add_subdirectory (train/) add_subdirectory (scripts/) @@ -210,7 +211,6 @@ if (BUILD_PY_IF) endif (BUILD_PY_IF) if (BUILD_CPP_IF) add_subdirectory (api_cc/) - add_subdirectory (lib/) add_subdirectory (lmp/) if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.9) # add_subdirectory (md/) diff --git a/source/lib/CMakeLists.txt b/source/lib/CMakeLists.txt index d6a7d40ff5..bbc1237a6e 100644 --- a/source/lib/CMakeLists.txt +++ b/source/lib/CMakeLists.txt @@ -15,10 +15,14 @@ if (USE_CUDA_TOOLKIT) target_link_libraries (${libname} ${CUDA_LIBRARIES}) endif() -install(TARGETS ${libname} DESTINATION lib/) - -install( - FILES ${INC_SRC} - DESTINATION include/deepmd -) +if(BUILD_PY_IF) + install(TARGETS ${libname} DESTINATION deepmd/) +endif(BUILD_PY_IF) +if(BUILD_CPP_IF) + install(TARGETS ${libname} DESTINATION lib/) + install( + FILES ${INC_SRC} + DESTINATION include/deepmd + ) +endif(BUILD_CPP_IF) diff --git a/source/op/CMakeLists.txt b/source/op/CMakeLists.txt index 25f125d6be..72bc5df5b5 100644 --- a/source/op/CMakeLists.txt +++ b/source/op/CMakeLists.txt @@ -39,6 +39,8 @@ if (BUILD_PY_IF) add_library(op_grads SHARED ${OP_GRADS_SRC}) endif(USE_CUDA_TOOLKIT) message(STATUS ${TensorFlowFramework_LIBRARY}) + target_link_libraries(op_abi ${LIB_DEEPMD}) + target_link_libraries(op_grads ${LIB_DEEPMD}) target_link_libraries( op_abi ${TensorFlowFramework_LIBRARY} ) From d69978828d73c6c572565749a8a2846ac53f177c Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 6 Feb 2021 23:16:28 +0800 Subject: [PATCH 102/562] clean up env_mat_r, add unittests --- source/lib/include/ComputeDescriptor.h | 82 ------ source/lib/include/CustomeOperation.h | 59 ----- source/lib/include/env_mat.h | 36 ++- source/lib/src/env_mat.cc | 168 ++++++++++++- .../{test_env_mat.cc => test_env_mat_a.cc} | 33 +-- source/lib/tests/test_env_mat_r.cc | 236 ++++++++++++++++++ 6 files changed, 451 insertions(+), 163 deletions(-) rename source/lib/tests/{test_env_mat.cc => test_env_mat_a.cc} (89%) create mode 100644 source/lib/tests/test_env_mat_r.cc diff --git a/source/lib/include/ComputeDescriptor.h b/source/lib/include/ComputeDescriptor.h index 8f1fef9820..a72a8a631d 100644 --- a/source/lib/include/ComputeDescriptor.h +++ b/source/lib/include/ComputeDescriptor.h @@ -98,21 +98,6 @@ void compute_descriptor_se_a_ef_vert (std::vector & descrpt_a, const double & rmin, const double & rmax); -inline -void compute_descriptor_se_r (std::vector & descrpt_r, - std::vector & descrpt_r_deriv, - std::vector & rij_r, - const std::vector & posi, - const int & ntypes, - const std::vector & type, - const SimulationRegion & region, - const bool & b_pbc, - const int & i_idx, - const std::vector & fmt_nlist_r, - const std::vector & sec_r, - const double & rmin, - const double & rmax); - static void compute_dRdT (double (* dRdT)[9], @@ -770,73 +755,6 @@ void compute_descriptor (std::vector & descrpt_a, -void compute_descriptor_se_r (std::vector & descrpt, - std::vector & descrpt_deriv, - std::vector & rij, - const std::vector & posi, - const int & ntypes, - const std::vector & type, - const SimulationRegion & region, - const bool & b_pbc, - const int & i_idx, - const std::vector & fmt_nlist, - const std::vector & sec, - const double & rmin, - const double & rmax) -{ - // compute the diff of the neighbors - std::vector > sel_diff (sec.back()); - rij.resize (sec.back() * 3); - fill (rij.begin(), rij.end(), 0.0); - for (int ii = 0; ii < int(sec.size()) - 1; ++ii){ - for (int jj = sec[ii]; jj < sec[ii+1]; ++jj){ - if (fmt_nlist[jj] < 0) break; - sel_diff[jj].resize(3); - const int & j_idx = fmt_nlist[jj]; - if (b_pbc){ - region.diffNearestNeighbor (posi[j_idx*3+0], posi[j_idx*3+1], posi[j_idx*3+2], - posi[i_idx*3+0], posi[i_idx*3+1], posi[i_idx*3+2], - sel_diff[jj][0], sel_diff[jj][1], sel_diff[jj][2]); - } - else { - for (int dd = 0; dd < 3; ++dd) sel_diff[jj][dd] = posi[j_idx*3+dd] - posi[i_idx*3+dd]; - } - for (int dd = 0; dd < 3; ++dd) rij[jj*3+dd] = sel_diff[jj][dd]; - } - } - - // 1./rr - descrpt.resize (sec.back()); - fill (descrpt.begin(), descrpt.end(), 0.0); - // deriv wrt center: 3 - descrpt_deriv.resize (sec.back() * 3); - fill (descrpt_deriv.begin(), descrpt_deriv.end(), 0.0); - - for (int sec_iter = 0; sec_iter < int(sec.size()) - 1; ++sec_iter){ - for (int nei_iter = sec[sec_iter]; nei_iter < sec[sec_iter+1]; ++nei_iter) { - if (fmt_nlist[nei_iter] < 0) break; - const double * rr = &sel_diff[nei_iter][0]; - double nr2 = MathUtilities::dot(rr, rr); - double inr = 1./sqrt(nr2); - double nr = nr2 * inr; - double inr2 = inr * inr; - double inr4 = inr2 * inr2; - double inr3 = inr4 * nr; - double sw, dsw; - spline5_switch(sw, dsw, nr, rmin, rmax); - int idx_deriv = nei_iter * 3; // 1 components time 3 directions - int idx_value = nei_iter; // 1 components - // value components - descrpt[idx_value + 0] = 1./nr; - // deriv of component 1/r - descrpt_deriv[idx_deriv + 0] = rr[0] * inr3 * sw - descrpt[idx_value + 0] * dsw * rr[0] * inr; - descrpt_deriv[idx_deriv + 1] = rr[1] * inr3 * sw - descrpt[idx_value + 0] * dsw * rr[1] * inr; - descrpt_deriv[idx_deriv + 2] = rr[2] * inr3 * sw - descrpt[idx_value + 0] * dsw * rr[2] * inr; - // value components - descrpt[idx_value + 0] *= sw; - } - } -} // output deriv size: n_sel_a_nei x 4 x 12 diff --git a/source/lib/include/CustomeOperation.h b/source/lib/include/CustomeOperation.h index decdf7118f..329ef7d355 100644 --- a/source/lib/include/CustomeOperation.h +++ b/source/lib/include/CustomeOperation.h @@ -230,65 +230,6 @@ void GeluGradGradGPULauncher(const FPTYPE * dy, const FPTYPE * dy_, const FPTYPE // end of custome op Gelu // ****************************************************************************** -template -void compute_descriptor_se_r_cpu ( - std::vector & descrpt_a, - std::vector & descrpt_a_deriv, - std::vector & rij_a, - const std::vector & posi, - const int & ntypes, - const std::vector & type, - const int & i_idx, - const std::vector & fmt_nlist_a, - const std::vector & sec_a, - const float & rmin, - const float & rmax) -{ - // compute the diff of the neighbors - rij_a.resize (sec_a.back() * 3); - fill (rij_a.begin(), rij_a.end(), 0.0); - for (int ii = 0; ii < int(sec_a.size()) - 1; ++ii) { - for (int jj = sec_a[ii]; jj < sec_a[ii + 1]; ++jj) { - if (fmt_nlist_a[jj] < 0) break; - const int & j_idx = fmt_nlist_a[jj]; - - for (int dd = 0; dd < 3; ++dd) { - rij_a[jj * 3 + dd] = posi[j_idx * 3 + dd] - posi[i_idx * 3 + dd]; - } - } - } - // 1./rr, cos(theta), cos(phi), sin(phi) - descrpt_a.resize (sec_a.back()); - fill (descrpt_a.begin(), descrpt_a.end(), 0.0); - // deriv wrt center: 3 - descrpt_a_deriv.resize (sec_a.back() * 3); - fill (descrpt_a_deriv.begin(), descrpt_a_deriv.end(), 0.0); - - for (int sec_iter = 0; sec_iter < int(sec_a.size()) - 1; ++sec_iter) { - for (int nei_iter = sec_a[sec_iter]; nei_iter < sec_a[sec_iter+1]; ++nei_iter) { - if (fmt_nlist_a[nei_iter] < 0) break; - const FPTYPE * rr = &rij_a[nei_iter * 3]; - FPTYPE nr2 = MathUtilities::dot(rr, rr); - FPTYPE inr = 1./sqrt(nr2); - FPTYPE nr = nr2 * inr; - FPTYPE inr2 = inr * inr; - FPTYPE inr4 = inr2 * inr2; - FPTYPE inr3 = inr4 * nr; - FPTYPE sw, dsw; - spline5_switch(sw, dsw, nr, rmin, rmax); - int idx_deriv = nei_iter * 3; // 1 components time 3 directions - int idx_value = nei_iter; // 1 components - // 4 value components - descrpt_a[idx_value + 0] = 1./nr; - // deriv of component 1/r - descrpt_a_deriv[idx_deriv + 0] = rr[0] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[0] * inr; - descrpt_a_deriv[idx_deriv + 1] = rr[1] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[1] * inr; - descrpt_a_deriv[idx_deriv + 2] = rr[2] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[2] * inr; - // 4 value components - descrpt_a[idx_value + 0] *= sw; - } - } -} template void DescrptSeRCPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { diff --git a/source/lib/include/env_mat.h b/source/lib/include/env_mat.h index 3e712888c2..067c6949d6 100644 --- a/source/lib/include/env_mat.h +++ b/source/lib/include/env_mat.h @@ -13,13 +13,42 @@ void env_mat_a ( const SimulationRegion & region, const bool & b_pbc, const int & i_idx, - const std::vector & fmt_nlist_a, - const std::vector & sec_a, + const std::vector & fmt_nlist, + const std::vector & sec, const double & rmin, const double & rmax); template void env_mat_a_cpu ( + std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, + const int & ntypes, + const std::vector & type, + const int & i_idx, + const std::vector & fmt_nlist, + const std::vector & sec, + const float & rmin, + const float & rmax) ; + +void env_mat_r ( + std::vector & descrpt_r, + std::vector & descrpt_r_deriv, + std::vector & rij_r, + const std::vector & posi, + const int & ntypes, + const std::vector & type, + const SimulationRegion & region, + const bool & b_pbc, + const int & i_idx, + const std::vector & fmt_nlist, + const std::vector & sec, + const double & rmin, + const double & rmax); + +template +void env_mat_r_cpu ( std::vector & descrpt_a, std::vector & descrpt_a_deriv, std::vector & rij_a, @@ -30,4 +59,5 @@ void env_mat_a_cpu ( const std::vector & fmt_nlist_a, const std::vector & sec_a, const float & rmin, - const float & rmax) ; + const float & rmax); + diff --git a/source/lib/src/env_mat.cc b/source/lib/src/env_mat.cc index 0247e2b77a..6736320d2d 100644 --- a/source/lib/src/env_mat.cc +++ b/source/lib/src/env_mat.cc @@ -169,6 +169,136 @@ void env_mat_a_cpu ( } +void env_mat_r ( + std::vector & descrpt, + std::vector & descrpt_deriv, + std::vector & rij, + const std::vector & posi, + const int & ntypes, + const std::vector & type, + const SimulationRegion & region, + const bool & b_pbc, + const int & i_idx, + const std::vector & fmt_nlist, + const std::vector & sec, + const double & rmin, + const double & rmax) +{ + // compute the diff of the neighbors + std::vector > sel_diff (sec.back()); + rij.resize (sec.back() * 3); + fill (rij.begin(), rij.end(), 0.0); + for (int ii = 0; ii < int(sec.size()) - 1; ++ii){ + for (int jj = sec[ii]; jj < sec[ii+1]; ++jj){ + if (fmt_nlist[jj] < 0) break; + sel_diff[jj].resize(3); + const int & j_idx = fmt_nlist[jj]; + if (b_pbc){ + region.diffNearestNeighbor (posi[j_idx*3+0], posi[j_idx*3+1], posi[j_idx*3+2], + posi[i_idx*3+0], posi[i_idx*3+1], posi[i_idx*3+2], + sel_diff[jj][0], sel_diff[jj][1], sel_diff[jj][2]); + } + else { + for (int dd = 0; dd < 3; ++dd) sel_diff[jj][dd] = posi[j_idx*3+dd] - posi[i_idx*3+dd]; + } + for (int dd = 0; dd < 3; ++dd) rij[jj*3+dd] = sel_diff[jj][dd]; + } + } + + // 1./rr + descrpt.resize (sec.back()); + fill (descrpt.begin(), descrpt.end(), 0.0); + // deriv wrt center: 3 + descrpt_deriv.resize (sec.back() * 3); + fill (descrpt_deriv.begin(), descrpt_deriv.end(), 0.0); + + for (int sec_iter = 0; sec_iter < int(sec.size()) - 1; ++sec_iter){ + for (int nei_iter = sec[sec_iter]; nei_iter < sec[sec_iter+1]; ++nei_iter) { + if (fmt_nlist[nei_iter] < 0) break; + const double * rr = &sel_diff[nei_iter][0]; + double nr2 = MathUtilities::dot(rr, rr); + double inr = 1./sqrt(nr2); + double nr = nr2 * inr; + double inr2 = inr * inr; + double inr4 = inr2 * inr2; + double inr3 = inr4 * nr; + double sw, dsw; + spline5_switch(sw, dsw, nr, rmin, rmax); + int idx_deriv = nei_iter * 3; // 1 components time 3 directions + int idx_value = nei_iter; // 1 components + // value components + descrpt[idx_value + 0] = 1./nr; + // deriv of component 1/r + descrpt_deriv[idx_deriv + 0] = rr[0] * inr3 * sw - descrpt[idx_value + 0] * dsw * rr[0] * inr; + descrpt_deriv[idx_deriv + 1] = rr[1] * inr3 * sw - descrpt[idx_value + 0] * dsw * rr[1] * inr; + descrpt_deriv[idx_deriv + 2] = rr[2] * inr3 * sw - descrpt[idx_value + 0] * dsw * rr[2] * inr; + // value components + descrpt[idx_value + 0] *= sw; + } + } +} + +template +void env_mat_r_cpu ( + std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, + const int & ntypes, + const std::vector & type, + const int & i_idx, + const std::vector & fmt_nlist, + const std::vector & sec, + const float & rmin, + const float & rmax) +{ + // compute the diff of the neighbors + rij_a.resize (sec.back() * 3); + fill (rij_a.begin(), rij_a.end(), 0.0); + for (int ii = 0; ii < int(sec.size()) - 1; ++ii) { + for (int jj = sec[ii]; jj < sec[ii + 1]; ++jj) { + if (fmt_nlist[jj] < 0) break; + const int & j_idx = fmt_nlist[jj]; + + for (int dd = 0; dd < 3; ++dd) { + rij_a[jj * 3 + dd] = posi[j_idx * 3 + dd] - posi[i_idx * 3 + dd]; + } + } + } + // 1./rr, cos(theta), cos(phi), sin(phi) + descrpt_a.resize (sec.back()); + fill (descrpt_a.begin(), descrpt_a.end(), 0.0); + // deriv wrt center: 3 + descrpt_a_deriv.resize (sec.back() * 3); + fill (descrpt_a_deriv.begin(), descrpt_a_deriv.end(), 0.0); + + for (int sec_iter = 0; sec_iter < int(sec.size()) - 1; ++sec_iter) { + for (int nei_iter = sec[sec_iter]; nei_iter < sec[sec_iter+1]; ++nei_iter) { + if (fmt_nlist[nei_iter] < 0) break; + const FPTYPE * rr = &rij_a[nei_iter * 3]; + FPTYPE nr2 = MathUtilities::dot(rr, rr); + FPTYPE inr = 1./sqrt(nr2); + FPTYPE nr = nr2 * inr; + FPTYPE inr2 = inr * inr; + FPTYPE inr4 = inr2 * inr2; + FPTYPE inr3 = inr4 * nr; + FPTYPE sw, dsw; + spline5_switch(sw, dsw, nr, rmin, rmax); + int idx_deriv = nei_iter * 3; // 1 components time 3 directions + int idx_value = nei_iter; // 1 components + // 4 value components + descrpt_a[idx_value + 0] = 1./nr; + // deriv of component 1/r + descrpt_a_deriv[idx_deriv + 0] = rr[0] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[0] * inr; + descrpt_a_deriv[idx_deriv + 1] = rr[1] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[1] * inr; + descrpt_a_deriv[idx_deriv + 2] = rr[2] * inr3 * sw - descrpt_a[idx_value + 0] * dsw * rr[2] * inr; + // 4 value components + descrpt_a[idx_value + 0] *= sw; + } + } +} + + template void env_mat_a_cpu ( std::vector & descrpt_a, @@ -178,8 +308,8 @@ void env_mat_a_cpu ( const int & ntypes, const std::vector & type, const int & i_idx, - const std::vector & fmt_nlist_a, - const std::vector & sec_a, + const std::vector & fmt_nlist, + const std::vector & sec, const float & rmin, const float & rmax) ; @@ -193,8 +323,38 @@ void env_mat_a_cpu ( const int & ntypes, const std::vector & type, const int & i_idx, - const std::vector & fmt_nlist_a, - const std::vector & sec_a, + const std::vector & fmt_nlist, + const std::vector & sec, + const float & rmin, + const float & rmax) ; + + +template +void env_mat_r_cpu ( + std::vector & descrpt_r, + std::vector & descrpt_r_deriv, + std::vector & rij_r, + const std::vector & posi, + const int & ntypes, + const std::vector & type, + const int & i_idx, + const std::vector & fmt_nlist, + const std::vector & sec, + const float & rmin, + const float & rmax) ; + + +template +void env_mat_r_cpu ( + std::vector & descrpt_r, + std::vector & descrpt_r_deriv, + std::vector & rij_r, + const std::vector & posi, + const int & ntypes, + const std::vector & type, + const int & i_idx, + const std::vector & fmt_nlist, + const std::vector & sec, const float & rmin, const float & rmax) ; diff --git a/source/lib/tests/test_env_mat.cc b/source/lib/tests/test_env_mat_a.cc similarity index 89% rename from source/lib/tests/test_env_mat.cc rename to source/lib/tests/test_env_mat_a.cc index 17887323be..d00ee6e4df 100644 --- a/source/lib/tests/test_env_mat.cc +++ b/source/lib/tests/test_env_mat_a.cc @@ -4,7 +4,7 @@ #include "env_mat.h" #include "NeighborList.h" -class TestEnvMat : public ::testing::Test +class TestEnvMatA : public ::testing::Test { protected: std::vector posi = {12.83, 2.56, 2.18, @@ -57,15 +57,17 @@ class TestEnvMat : public ::testing::Test } }; -TEST_F(TestEnvMat, orig_cpy) +TEST_F(TestEnvMatA, orig_cpy) { std::vector fmt_nlist_a, fmt_nlist_r; std::vector env, env_deriv, rij_a; bool pbc = false; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi_cpy, ntypes, atype_cpy, region, pbc, ii, nlist_a_cpy[ii], nlist_r_cpy[ii], rc, sec_a, sec_r); + int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); env_mat_a(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + EXPECT_EQ(env.size(), sec_a[2]*4); + EXPECT_EQ(env.size(), env_deriv.size()/3); for (int jj = 0; jj < sec_a[2]; ++jj){ for (int dd = 0; dd < 4; ++dd){ EXPECT_LT(fabs(env[jj*4+dd] - expected_env[ii*sec_a[2]*4 + jj*4 + dd]) , 1e-5); @@ -78,7 +80,7 @@ TEST_F(TestEnvMat, orig_cpy) } } -TEST_F(TestEnvMat, orig_pbc) +TEST_F(TestEnvMatA, orig_pbc) { std::vector fmt_nlist_a, fmt_nlist_r; std::vector env, env_deriv, rij_a; @@ -96,14 +98,14 @@ TEST_F(TestEnvMat, orig_pbc) } -TEST_F(TestEnvMat, orig_cpy_equal_pbc) +TEST_F(TestEnvMatA, orig_cpy_equal_pbc) { std::vector fmt_nlist_a_0, fmt_nlist_r_0; std::vector fmt_nlist_a_1, fmt_nlist_r_1; std::vector env_0, env_deriv_0, rij_a_0; std::vector env_1, env_deriv_1, rij_a_1; for(int ii = 0; ii < nloc; ++ii){ - int ret_0 = format_nlist_fill_a(fmt_nlist_a_0, fmt_nlist_r_0, posi_cpy, ntypes, atype_cpy, region, false, ii, nlist_a_cpy[ii], nlist_r_cpy[ii], rc, sec_a, sec_r); + int ret_0 = format_nlist_cpu(fmt_nlist_a_0, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_0, -1); env_mat_a(env_0, env_deriv_0, rij_a_0, posi_cpy, ntypes, atype_cpy, region, false, ii, fmt_nlist_a_0, sec_a, rc_smth, rc); int ret_1 = format_nlist_fill_a(fmt_nlist_a_1, fmt_nlist_r_1, posi, ntypes, atype, region, true, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); @@ -125,14 +127,14 @@ TEST_F(TestEnvMat, orig_cpy_equal_pbc) } -TEST_F(TestEnvMat, orig_cpy_num_deriv) +TEST_F(TestEnvMatA, orig_cpy_num_deriv) { std::vector fmt_nlist_a, fmt_nlist_r; std::vector env, env_0, env_1, env_deriv, env_deriv_tmp, rij_a; bool pbc = false; double hh = 1e-5; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi_cpy, ntypes, atype_cpy, region, pbc, ii, nlist_a_cpy[ii], nlist_r_cpy[ii], rc, sec_a, sec_r); + int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); env_mat_a(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); @@ -161,13 +163,13 @@ TEST_F(TestEnvMat, orig_cpy_num_deriv) } -TEST_F(TestEnvMat, cpu) +TEST_F(TestEnvMatA, cpu) { std::vector fmt_nlist_a, fmt_nlist_r; std::vector env, env_deriv, rij_a; bool pbc = false; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi_cpy, ntypes, atype_cpy, region, pbc, ii, nlist_a_cpy[ii], nlist_r_cpy[ii], rc, sec_a, sec_r); + int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < sec_a[2]; ++jj){ @@ -178,18 +180,19 @@ TEST_F(TestEnvMat, cpu) } } -TEST_F(TestEnvMat, cpu_equal_orig_cpy) +TEST_F(TestEnvMatA, cpu_equal_orig_cpy) { std::vector fmt_nlist_a_0, fmt_nlist_r_0; std::vector fmt_nlist_a_1, fmt_nlist_r_1; std::vector env_0, env_deriv_0, rij_a_0; std::vector env_1, env_deriv_1, rij_a_1; for(int ii = 0; ii < nloc; ++ii){ - int ret_0 = format_nlist_fill_a(fmt_nlist_a_0, fmt_nlist_r_0, posi_cpy, ntypes, atype_cpy, region, false, ii, nlist_a_cpy[ii], nlist_r_cpy[ii], rc, sec_a, sec_r); + int ret_0 = format_nlist_cpu(fmt_nlist_a_0, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_0, -1); env_mat_a(env_0, env_deriv_0, rij_a_0, posi_cpy, ntypes, atype_cpy, region, false, ii, fmt_nlist_a_0, sec_a, rc_smth, rc); - int ret_1 = format_nlist_fill_a(fmt_nlist_a_1, fmt_nlist_r_1, posi_cpy, ntypes, atype_cpy, region, false, ii, nlist_a_cpy[ii], nlist_r_cpy[ii], rc, sec_a, sec_r); + int ret_1 = format_nlist_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + EXPECT_EQ(ret_1, -1); env_mat_a_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); @@ -208,14 +211,14 @@ TEST_F(TestEnvMat, cpu_equal_orig_cpy) } } -TEST_F(TestEnvMat, cpu_num_deriv) +TEST_F(TestEnvMatA, cpu_num_deriv) { std::vector fmt_nlist_a, fmt_nlist_r; std::vector env, env_0, env_1, env_deriv, env_deriv_tmp, rij_a; bool pbc = false; double hh = 1e-5; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi_cpy, ntypes, atype_cpy, region, pbc, ii, nlist_a_cpy[ii], nlist_r_cpy[ii], rc, sec_a, sec_r); + int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); diff --git a/source/lib/tests/test_env_mat_r.cc b/source/lib/tests/test_env_mat_r.cc new file mode 100644 index 0000000000..6f44d66371 --- /dev/null +++ b/source/lib/tests/test_env_mat_r.cc @@ -0,0 +1,236 @@ +#include +#include +#include "fmt_nlist.h" +#include "env_mat.h" +#include "NeighborList.h" + +class TestEnvMatR : public ::testing::Test +{ +protected: + std::vector posi = {12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall; + double rc = 6; + double rc_smth = 0.8; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sec_a = {0, 10, 20}; + std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector> nlist_a, nlist_r; + std::vector> nlist_a_cpy, nlist_r_cpy; + std::vector expected_env = { + 0.12206, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.02167, 0.99745, 0.10564, 0.03103, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + 1.02167, 0.04135, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.59220, 0.03694, 0.00336, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + 0.99745, 0.19078, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.59220, 0.13499, 0.07054, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + 0.12206, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.06176, 1.03163, 0.19078, 0.04135, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + 1.06176, 0.10564, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.66798, 0.13499, 0.03694, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + 1.03163, 0.03103, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.66798, 0.07054, 0.00336, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + }; + + void SetUp() override { + double box[] = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + region.reinitBox(box); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + build_nlist(nlist_a, nlist_r, posi, rc, rc, ncell, region); + build_nlist(nlist_a_cpy, nlist_r_cpy, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + } + void TearDown() override { + } +}; + +TEST_F(TestEnvMatR, orig_cpy) +{ + std::vector fmt_nlist_a, fmt_nlist_r; + std::vector env, env_deriv, rij_a; + bool pbc = false; + for(int ii = 0; ii < nloc; ++ii){ + int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + EXPECT_EQ(ret, -1); + env_mat_r(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + EXPECT_EQ(env.size(), sec_a[2]); + EXPECT_EQ(env.size(), env_deriv.size()/3); + for (int jj = 0; jj < sec_a[2]; ++jj){ + EXPECT_LT(fabs(env[jj] - expected_env[ii*sec_a[2] + jj]) , 1e-5); + } + // for (int jj = 0; jj < sec_a[2]; ++jj){ + // printf("%7.5f, ", env[jj]); + // } + // printf("\n"); + } +} + +TEST_F(TestEnvMatR, orig_pbc) +{ + std::vector fmt_nlist_a, fmt_nlist_r; + std::vector env, env_deriv, rij_a; + bool pbc = true; + for(int ii = 0; ii < nloc; ++ii){ + int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi, ntypes, atype, region, pbc, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); + EXPECT_EQ(ret, -1); + env_mat_r(env, env_deriv, rij_a, posi, ntypes, atype, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < sec_a[2]; ++jj){ + EXPECT_LT(fabs(env[jj] - expected_env[ii*sec_a[2] + jj]) , 1e-5); + } + } +} + + +TEST_F(TestEnvMatR, orig_cpy_equal_pbc) +{ + std::vector fmt_nlist_a_0, fmt_nlist_r_0; + std::vector fmt_nlist_a_1, fmt_nlist_r_1; + std::vector env_0, env_deriv_0, rij_a_0; + std::vector env_1, env_deriv_1, rij_a_1; + for(int ii = 0; ii < nloc; ++ii){ + int ret_0 = format_nlist_cpu(fmt_nlist_a_0, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + EXPECT_EQ(ret_0, -1); + env_mat_r(env_0, env_deriv_0, rij_a_0, posi_cpy, ntypes, atype_cpy, region, false, ii, fmt_nlist_a_0, sec_a, rc_smth, rc); + int ret_1 = format_nlist_fill_a(fmt_nlist_a_1, fmt_nlist_r_1, posi, ntypes, atype, region, true, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); + EXPECT_EQ(ret_1, -1); + env_mat_r(env_1, env_deriv_1, rij_a_1, posi, ntypes, atype, region, true, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + EXPECT_EQ(env_0.size(), env_1.size()); + EXPECT_EQ(env_deriv_0.size(), env_deriv_1.size()); + EXPECT_EQ(rij_a_0.size(), rij_a_1.size()); + for (unsigned jj = 0; jj < env_0.size(); ++jj){ + EXPECT_LT(fabs(env_0[jj] - env_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < env_deriv_0.size(); ++jj){ + EXPECT_LT(fabs(env_deriv_0[jj] - env_deriv_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < rij_a_0.size(); ++jj){ + EXPECT_LT(fabs(rij_a_0[jj] - rij_a_1[jj]), 1e-10); + } + } +} + + +TEST_F(TestEnvMatR, orig_cpy_num_deriv) +{ + std::vector fmt_nlist_a, fmt_nlist_r; + std::vector env, env_0, env_1, env_deriv, env_deriv_tmp, rij_a; + bool pbc = false; + double hh = 1e-5; + for(int ii = 0; ii < nloc; ++ii){ + int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + EXPECT_EQ(ret, -1); + env_mat_r(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + + for (int jj = 0; jj < sec_a[2]; ++jj){ + int j_idx = fmt_nlist_a[jj]; + if (j_idx < 0) continue; + for (int dd = 0; dd < 3; ++dd){ + std::vector posi_0 = posi_cpy; + std::vector posi_1 = posi_cpy; + posi_0[j_idx*3+dd] -= hh; + posi_1[j_idx*3+dd] += hh; + env_mat_r(env_0, env_deriv_tmp, rij_a, posi_0, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_r(env_1, env_deriv_tmp, rij_a, posi_1, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + double num_deriv = (env_1[jj] - env_0[jj])/(2.*hh); + double ana_deriv = -env_deriv[jj*3+dd]; + EXPECT_LT(fabs(num_deriv - ana_deriv), 1e-5); + } + } + // for (int jj = 0; jj < sec_a[2]; ++jj){ + // printf("%7.5f, %7.5f, %7.5f, %7.5f, ", env[jj*4+0], env[jj*4+1], env[jj*4+2], env[jj*4+3]); + // } + // printf("\n"); + } +} + + +TEST_F(TestEnvMatR, cpu) +{ + std::vector fmt_nlist_a, fmt_nlist_r; + std::vector env, env_deriv, rij_a; + bool pbc = false; + for(int ii = 0; ii < nloc; ++ii){ + int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + EXPECT_EQ(ret, -1); + env_mat_r_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < sec_a[2]; ++jj){ + EXPECT_LT(fabs(env[jj] - expected_env[ii*sec_a[2] + jj]) , 1e-5); + } + } +} + +TEST_F(TestEnvMatR, cpu_equal_orig_cpy) +{ + std::vector fmt_nlist_a_0, fmt_nlist_r_0; + std::vector fmt_nlist_a_1, fmt_nlist_r_1; + std::vector env_0, env_deriv_0, rij_a_0; + std::vector env_1, env_deriv_1, rij_a_1; + for(int ii = 0; ii < nloc; ++ii){ + int ret_0 = format_nlist_cpu(fmt_nlist_a_0, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + EXPECT_EQ(ret_0, -1); + env_mat_r(env_0, env_deriv_0, rij_a_0, posi_cpy, ntypes, atype_cpy, region, false, ii, fmt_nlist_a_0, sec_a, rc_smth, rc); + + int ret_1 = format_nlist_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + EXPECT_EQ(ret_1, -1); + env_mat_r_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + + EXPECT_EQ(env_0.size(), env_1.size()); + EXPECT_EQ(env_deriv_0.size(), env_deriv_1.size()); + EXPECT_EQ(rij_a_0.size(), rij_a_1.size()); + for (unsigned jj = 0; jj < env_0.size(); ++jj){ + EXPECT_LT(fabs(env_0[jj] - env_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < env_deriv_0.size(); ++jj){ + EXPECT_LT(fabs(env_deriv_0[jj] - env_deriv_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < rij_a_0.size(); ++jj){ + EXPECT_LT(fabs(rij_a_0[jj] - rij_a_1[jj]), 1e-10); + } + } +} + +TEST_F(TestEnvMatR, cpu_num_deriv) +{ + std::vector fmt_nlist_a, fmt_nlist_r; + std::vector env, env_0, env_1, env_deriv, env_deriv_tmp, rij_a; + bool pbc = false; + double hh = 1e-5; + for(int ii = 0; ii < nloc; ++ii){ + int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + EXPECT_EQ(ret, -1); + env_mat_r_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + + for (int jj = 0; jj < sec_a[2]; ++jj){ + int j_idx = fmt_nlist_a[jj]; + if (j_idx < 0) continue; + for (int dd = 0; dd < 3; ++dd){ + std::vector posi_0 = posi_cpy; + std::vector posi_1 = posi_cpy; + posi_0[j_idx*3+dd] -= hh; + posi_1[j_idx*3+dd] += hh; + env_mat_r(env_0, env_deriv_tmp, rij_a, posi_0, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_r(env_1, env_deriv_tmp, rij_a, posi_1, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + double num_deriv = (env_1[jj] - env_0[jj])/(2.*hh); + double ana_deriv = -env_deriv[jj*3+dd]; + EXPECT_LT(fabs(num_deriv - ana_deriv), 1e-5); + } + } + // for (int jj = 0; jj < sec_a[2]; ++jj){ + // printf("%7.5f, %7.5f, %7.5f, %7.5f, ", env[jj*4+0], env[jj*4+1], env[jj*4+2], env[jj*4+3]); + // } + // printf("\n"); + } +} From 95521b82871005f500846982b98c71945bca13ed Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 6 Feb 2021 23:24:03 +0800 Subject: [PATCH 103/562] fix bug of unchanged env_mat_r --- source/op/descrpt_se_r.cc | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/source/op/descrpt_se_r.cc b/source/op/descrpt_se_r.cc index e8777f680d..fde5f5a078 100644 --- a/source/op/descrpt_se_r.cc +++ b/source/op/descrpt_se_r.cc @@ -273,19 +273,19 @@ class DescrptSeROp : public OpKernel { std::vector d_descrpt; std::vector d_descrpt_deriv; std::vector d_rij; - compute_descriptor_se_r (d_descrpt, - d_descrpt_deriv, - d_rij, - d_coord3, - ntypes, - d_type, - region, - b_pbc, - ii, - fmt_nlist, - sec, - rcut_smth, - rcut); + env_mat_r (d_descrpt, + d_descrpt_deriv, + d_rij, + d_coord3, + ntypes, + d_type, + region, + b_pbc, + ii, + fmt_nlist, + sec, + rcut_smth, + rcut); // check sizes assert (d_descrpt_deriv.size() == ndescrpt * 3); From a6fbd52d3c154ec9c588036dec7c651330754186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Sat, 6 Feb 2021 17:14:02 +0100 Subject: [PATCH 104/562] debug lint --- .github/workflows/lint_python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml index 4dea2ec310..5d872ed8b3 100644 --- a/.github/workflows/lint_python.yml +++ b/.github/workflows/lint_python.yml @@ -17,7 +17,7 @@ jobs: python-version: ${{ matrix.python }} - name: Install requirements run: pip install -r requirements.txt - - uses: marian-code/pyaction@v2.2.0 + - uses: marian-code/pyaction@master with: python-root-list: "./deepmd/*.py ./deepmd/*/*.py ./source/train/*.py ./source/tests/*.py ./source/scripts/*.py ./source/op/*.py" use-black: true From b0526ebbd50f52d3c15c86fe833efff0ae131c21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Sat, 6 Feb 2021 17:21:52 +0100 Subject: [PATCH 105/562] debug actions lint --- .github/workflows/lint_python.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml index 5d872ed8b3..8ac70fa025 100644 --- a/.github/workflows/lint_python.yml +++ b/.github/workflows/lint_python.yml @@ -17,9 +17,9 @@ jobs: python-version: ${{ matrix.python }} - name: Install requirements run: pip install -r requirements.txt - - uses: marian-code/pyaction@master + - uses: marian-code/python-lint-annotate@master with: - python-root-list: "./deepmd/*.py ./deepmd/*/*.py ./source/train/*.py ./source/tests/*.py ./source/scripts/*.py ./source/op/*.py" + python-root-list: "./deepmd/'*'.py ./deepmd/'*'/'*'.py ./source/train/'*'.py ./source/tests/'*'.py ./source/scripts/'*'.py ./source/op/'*'.py" use-black: true use-isort: true use-mypy: true From e22fdefdc0fe237abdfc517f44f372c9ae803dc4 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Sun, 7 Feb 2021 14:16:44 +0800 Subject: [PATCH 106/562] optimize code structure of model compression --- deepmd/descriptor/se_a.py | 32 +++----- deepmd/utils/env_mat_stat.py | 105 ++++-------------------- deepmd/utils/tabulate.py | 149 ++++++++++++++++++++++------------- source/op/env_mat_stat.cc | 6 +- source/train/Trainer.py | 27 +++---- source/train/compress.py | 5 +- source/train/main.py | 22 ++++-- 7 files changed, 152 insertions(+), 194 deletions(-) diff --git a/deepmd/descriptor/se_a.py b/deepmd/descriptor/se_a.py index 3b9a4db0af..b137906a50 100644 --- a/deepmd/descriptor/se_a.py +++ b/deepmd/descriptor/se_a.py @@ -100,7 +100,6 @@ def __init__ (self, self.dstd = None self.davg = None self.compress = False - self.place_holders = {} avg_zero = np.zeros([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) std_ones = np.ones ([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) @@ -231,7 +230,7 @@ def compute_input_stats (self, self.dstd = np.array(all_dstd) def enable_compression(self, - env_mat_range, + min_nbor_dist, model_file = 'frozon_model.pb', table_config = [5, 0.01, 0.1, -1] ) -> None: @@ -240,25 +239,23 @@ def enable_compression(self, Parameters ---------- - env_mat_range - The output data range of the environment matrix - env_mat_range[0] denotes the lower boundary of environment matrix - env_mat_range[1] denotes the upper boundary of environment matrix + min_nbor_dist + The nearest distance between atoms model_file - The original frozen model, that will be compressed + The original frozen model, which will be compressed by the program table_config - The configuration of the tabulation + The configuration including: Table_config[0] denotes the scale of model extrapolation - Table_config[1] denotes the first table stride - Table_config[2] denotes the second table stride + Table_config[1] denotes the uniform stride of the first table + Table_config[2] denotes the uniform stride of the second table Table_config[3] denotes the overflow check frequency - """ + """ self.compress = True self.model_file = model_file self.table_config = table_config - self.env_mat_range = env_mat_range self.table = DeepTabulate(self.model_file, self.filter_np_precision, self.type_one_side) - + self.lower, self.upper \ + = self.table.build(min_nbor_dist, self.rcut_r, self.rcut_r_smth, self.table_config[0], self.table_config[1], self.table_config[2]) def build (self, coord_ : tf.Tensor, @@ -357,15 +354,6 @@ def build (self, self.descrpt_deriv = tf.identity(self.descrpt_deriv, name = 'o_rmat_deriv') self.rij = tf.identity(self.rij, name = 'o_rij') self.nlist = tf.identity(self.nlist, name = 'o_nlist') - - if self.compress: - self.lower = math.floor(self.env_mat_range[0]) - self.upper = math.ceil(self.env_mat_range[1]) - self.table.build(self.lower, - self.upper, - self.upper * self.table_config[0], - self.table_config[1], - self.table_config[2]) self.dout, self.qmat = self._pass_filter(self.descrpt_reshape, atype, diff --git a/deepmd/utils/env_mat_stat.py b/deepmd/utils/env_mat_stat.py index 1518207de7..b8f73959eb 100644 --- a/deepmd/utils/env_mat_stat.py +++ b/deepmd/utils/env_mat_stat.py @@ -13,51 +13,29 @@ class EnvMatStat(): It loads data from DeepmdData object, and measures the data info, including neareest nbor distance between atoms, max nbor size of atoms and the output data range of the environment matrix. """ def __init__(self, - descrpt_type : str, ntypes : int, - ndescrpt : int, rcut, rcut_smth, - sel, - davg, - dstd) -> None: + sel) -> None: """ Constructor Parameters ---------- - descrpt_type - The descrpt type of the embedding net ntypes The num of atom types - ndescrpt - The width of environment matrix rcut The cut-off radius rcut_smth From where the environment matrix should be smoothed sel : list[str] sel[i] specifies the maxmum number of type i atoms in the cut-off radius - davg - Average of training data - dstd - Standard deviation of training data """ - self.init_stat = False - self.davg = davg - self.dstd = dstd - if self.davg is None: - self.davg = np.zeros([self.ntypes, self.ndescrpt]) - if self.dstd is None: - self.dstd = np.ones ([self.ntypes, self.ndescrpt]) self.ntypes = ntypes - self.ndescrpt = ndescrpt - self.descrpt_type = descrpt_type - assert self.descrpt_type == 'se_a', 'Model compression error: descriptor type must be se_a!' self.place_holders = {} sub_graph = tf.Graph() with sub_graph.as_default(): - for ii in ['coord', 'box', 'avg', 'std']: + for ii in ['coord', 'box']: self.place_holders[ii] = tf.placeholder(global_np_float_precision, [None, None], name='t_'+ii) self.place_holders['type'] = tf.placeholder(tf.int32, [None, None], name='t_type') self.place_holders['natoms_vec'] = tf.placeholder(tf.int32, [self.ntypes+2], name='t_natoms') @@ -77,7 +55,7 @@ def __init__(self, self.sub_sess = tf.Session(graph = sub_graph, config=default_tf_session_config) def get_env_mat_stat(self, - data) -> Tuple[float, int]: + data) -> Tuple[float, List[int]]: """ get the data statistics of the training data, including nearest nbor distance between atoms, max nbor size of atoms @@ -89,12 +67,12 @@ def get_env_mat_stat(self, Returns ------- min_nbor_dist - The nearest nbor distance between atoms + The nearest distance between neighbor atoms max_nbor_size - The max nbor size of atoms + A list with ntypes integers, denotes the actual achieved max sel """ - self.max_nbor_size = 0 self.min_nbor_dist = 100.0 + self.max_nbor_size = [0] * self.ntypes for ii in tqdm(range(len(data.system_dirs)), desc = '# DEEPMD: getting data info'): for jj in data.data_systems[ii].dirs: @@ -110,68 +88,13 @@ def get_env_mat_stat(self, self.place_holders['default_mesh']: np.array(data.default_mesh[ii]), }) dt = np.min(dt) - mn = np.max(mn) - if (dt < self.min_nbor_dist): + if dt < self.min_nbor_dist: self.min_nbor_dist = dt - if (mn > self.max_nbor_size): - self.max_nbor_size = mn - self.init_stat = True - return self.min_nbor_dist, self.max_nbor_size - - def get_env_mat_range(self, - data) -> List[float]: - """ - get the data statistics of the training data, including the output data range of the environment matrix - - Parameters - ---------- - data - Class for manipulating many data systems. It is implemented with the help of DeepmdData. - - Returns - ------- - env_mat_range - The output data range of the environment matrix - env_mat_range[0] denotes the lower boundary of environment matrix - env_mat_range[1] denotes the upper boundary of environment matrix - """ - if self.init_stat: - min_nbor_dist = self.min_nbor_dist - max_nbor_size = self.max_nbor_size - else: - min_nbor_dist, max_nbor_size = self.get_env_mat_stat(data) - self.env_mat_range = self._get_internal_env_mat_range(min_nbor_dist, max_nbor_size) - print('# DEEPMD: training data with lower boundary: ' + str(self.env_mat_range[0])) - print('# DEEPMD: training data with upper boundary: ' + str(self.env_mat_range[1])) - print('# DEEPMD: training data with min distance: ' + str(self.min_nbor_dist)) - print('# DEEPMD: training data with max nborsize: ' + str(self.max_nbor_size)) - return self.env_mat_range + for ww in range(self.ntypes): + var = np.max(mn[:, ww]) + if var > self.max_nbor_size[ww]: + self.max_nbor_size[ww] = var - def _get_internal_env_mat_range(self, - min_nbor_dist, - max_nbor_size): - """ - Warning: different descrpt_type may have different method to get the mat range - """ - lower = 100.0 - upper = -10.0 - sw = self._spline5_switch(self.min_nbor_dist, self.rcut_smth, self.rcut) - for ii in range(self.ntypes): - if lower > -self.davg[ii][0] / self.dstd[ii][0]: - lower = -self.davg[ii][0] / self.dstd[ii][0] - if upper < ((1 / self.min_nbor_dist) * sw - self.davg[ii][0]) / self.dstd[ii][0]: - upper = ((1 / self.min_nbor_dist) * sw - self.davg[ii][0]) / self.dstd[ii][0] - return [lower, upper] - - def _spline5_switch(self, - xx, - rmin, - rmax): - if xx < rmin: - vv = 1 - elif xx < rmax: - uu = (xx - rmin) / (rmax - rmin) - vv = uu*uu*uu * (-6 * uu*uu + 15 * uu - 10) + 1 - else: - vv = 0 - return vv + print('# DEEPMD: training data with min nbor dist: ' + str(self.min_nbor_dist)) + print('# DEEPMD: training data with max nbor size: ' + str(self.max_nbor_size)) + return self.min_nbor_dist, self.max_nbor_size diff --git a/deepmd/utils/tabulate.py b/deepmd/utils/tabulate.py index 57ffc0cb5e..84255f6e16 100644 --- a/deepmd/utils/tabulate.py +++ b/deepmd/utils/tabulate.py @@ -2,16 +2,18 @@ import math import numpy as np from tqdm import tqdm +from typing import Tuple, List from deepmd.env import tf from deepmd.env import op_module from tensorflow.python.platform import gfile from tensorflow.python.framework import tensor_util - class DeepTabulate(): """ Class for tabulation. - It reads the trained weights and bias from the frozen model, and builds the table according to the weights and bias. + Compress a model, which including tabulating the embedding-net. + The table is composed of fifth-order polynomial coefficients and is assembled from two sub-tables. The first table takes the stride(parameter) as it\'s uniform stride, while the second table takes 10 * stride as it\s uniform stride + The range of the first table is automatically detected by deepmd-kit, while the second table ranges from the first table\'s upper boundary(upper) to the extrapolate(parameter) * upper. """ def __init__(self, model_file, @@ -43,6 +45,9 @@ def __init__(self, self.sel_a = self.graph.get_operation_by_name('DescrptSeA').get_attr('sel_a') self.ntypes = self._get_tensor_value(self.graph.get_tensor_by_name ('descrpt_attr/ntypes:0')) + self.davg = self._get_tensor_value(self.graph.get_tensor_by_name ('descrpt_attr/t_avg:0')) + self.dstd = self._get_tensor_value(self.graph.get_tensor_by_name ('descrpt_attr/t_std:0')) + self.filter_variable_nodes = self._load_matrix_node() self.layer_size = int(len(self.filter_variable_nodes) / (self.ntypes * self.ntypes * 2)) self.table_size = self.ntypes * self.ntypes @@ -62,6 +67,66 @@ def __init__(self, # TODO: Need a check function to determine if the current model is properly + def build(self, + min_nbor_dist, + rcut, + rcut_smth, + extrapolate, + stride0, + stride1) -> Tuple[int, int]: + """ + Build the tables for model compression + + Parameters + ---------- + min_nbor_dist + The nearest distance between neighbor atoms + rcut + The cut-off radius + rcut_smth + From where the environment matrix should be smoothed + extrapolate + The scale of model extrapolation + stride0 + The uniform stride of the first table + stride1 + The uniform stride of the second table + + Returns + ---------- + lower + The lower boundary of environment matrix + upper + The upper boundary of environment matrix + """ + # tabulate range [lower, upper] with stride0 'stride0' + lower, upper = self._get_env_mat_range(min_nbor_dist, rcut, rcut_smth) + xx = np.arange(lower, upper, stride0, dtype = self.data_type) + xx = np.append(xx, np.arange(upper, extrapolate * upper, stride1, dtype = self.data_type)) + xx = np.append(xx, np.array([extrapolate * upper], dtype = self.data_type)) + self.nspline = int((upper - lower) / stride0 + (extrapolate * upper - upper) / stride1) + for ii in range(self.table_size): + vv, dd, d2 = self._make_data(xx, ii) + if self.type_one_side: + net = "filter_-1_net_" + str(int(ii)) + else: + net = "filter_" + str(int(ii / self.ntypes)) + "_net_" + str(int(ii % self.ntypes)) + self.data[net] = np.zeros([self.nspline, 6 * self.last_layer_size], dtype = self.data_type) + for jj in tqdm(range(self.nspline), desc = '# DEEPMD: ' + net + ', tabulating'): + for kk in range(self.last_layer_size): + if jj < int((upper - lower) / stride0): + tt = stride0 + else: + tt = stride1 + hh = vv[jj + 1][kk] - vv[jj][kk] + self.data[net][jj][kk * 6 + 0] = vv[jj][kk] + self.data[net][jj][kk * 6 + 1] = dd[jj][kk] + self.data[net][jj][kk * 6 + 2] = 0.5 * d2[jj][kk] + self.data[net][jj][kk * 6 + 3] = (1 / (2 * tt * tt * tt)) * (20 * hh - (8 * dd[jj + 1][kk] + 12 * dd[jj][kk]) * tt - (3 * d2[jj][kk] - d2[jj + 1][kk]) * tt * tt) + self.data[net][jj][kk * 6 + 4] = (1 / (2 * tt * tt * tt * tt)) * (-30 * hh + (14 * dd[jj + 1][kk] + 16 * dd[jj][kk]) * tt + (3 * d2[jj][kk] - 2 * d2[jj + 1][kk]) * tt * tt) + self.data[net][jj][kk * 6 + 5] = (1 / (2 * tt * tt * tt * tt * tt)) * (12 * hh - 6 * (dd[jj + 1][kk] + dd[jj][kk]) * tt + (d2[jj + 1][kk] - d2[jj][kk]) * tt * tt) + return lower, upper + def _load_graph(self): graph_def = tf.GraphDef() with open(self.model_file, "rb") as f: @@ -124,57 +189,6 @@ def _get_matrix(self): matrix["layer_" + str(layer)].append(np.reshape(tensor_value, tensor_shape).astype(self.data_type)) return matrix - def build(self, - lower, - upper, - _max, - stride0, - stride1) -> None: - """ - Build the tables for model compression - - Parameters - ---------- - lower - The lower boundary of the first table - upper - The upper boundary of the first table as well as the lower boundary of the second table - _max - The upper boundary of the second table - stride0 - The stride of the first table - stride1 - The stride of the second table - """ - # tabulate range [lower, upper] with stride0 'stride0' - lower = math.floor(lower) - upper = math.ceil(upper) - xx = np.arange(lower, upper, stride0, dtype = self.data_type) - xx = np.append(xx, np.arange(upper, _max, stride1, dtype = self.data_type)) - xx = np.append(xx, np.array([_max], dtype = self.data_type)) - self.nspline = int((upper - lower) / stride0 + (_max - upper) / stride1) - - for ii in range(self.table_size): - vv, dd, d2 = self._make_data(xx, ii) - if self.type_one_side: - net = "filter_-1_net_" + str(int(ii)) - else: - net = "filter_" + str(int(ii / self.ntypes)) + "_net_" + str(int(ii % self.ntypes)) - self.data[net] = np.zeros([self.nspline, 6 * self.last_layer_size], dtype = self.data_type) - for jj in tqdm(range(self.nspline), desc = '# DEEPMD: ' + net + ', tabulating'): - for kk in range(self.last_layer_size): - if jj < int((upper - lower) / stride0): - tt = stride0 - else: - tt = stride1 - hh = vv[jj + 1][kk] - vv[jj][kk] - self.data[net][jj][kk * 6 + 0] = vv[jj][kk] - self.data[net][jj][kk * 6 + 1] = dd[jj][kk] - self.data[net][jj][kk * 6 + 2] = 0.5 * d2[jj][kk] - self.data[net][jj][kk * 6 + 3] = (1 / (2 * tt * tt * tt)) * (20 * hh - (8 * dd[jj + 1][kk] + 12 * dd[jj][kk]) * tt - (3 * d2[jj][kk] - d2[jj + 1][kk]) * tt * tt) - self.data[net][jj][kk * 6 + 4] = (1 / (2 * tt * tt * tt * tt)) * (-30 * hh + (14 * dd[jj + 1][kk] + 16 * dd[jj][kk]) * tt + (3 * d2[jj][kk] - 2 * d2[jj + 1][kk]) * tt * tt) - self.data[net][jj][kk * 6 + 5] = (1 / (2 * tt * tt * tt * tt * tt)) * (12 * hh - 6 * (dd[jj + 1][kk] + dd[jj][kk]) * tt + (d2[jj + 1][kk] - d2[jj][kk]) * tt * tt) - # one-by-one executions def _make_data(self, xx, idx): with self.sub_graph.as_default(): @@ -207,3 +221,32 @@ def _save_data(self): for ii in range(self.ntypes * self.ntypes): net = "filter_" + str(int(ii / self.ntypes)) + "_net_" + str(int(ii % self.ntypes)) np.savetxt('data_' + str(int(ii)), self.data[net]) + + def _get_env_mat_range(self, + min_nbor_dist, + rcut, + rcut_smth): + lower = 100.0 + upper = -10.0 + sw = self._spline5_switch(min_nbor_dist, rcut_smth, rcut) + for ii in range(self.ntypes): + if lower > -self.davg[ii][0] / self.dstd[ii][0]: + lower = -self.davg[ii][0] / self.dstd[ii][0] + if upper < ((1 / min_nbor_dist) * sw - self.davg[ii][0]) / self.dstd[ii][0]: + upper = ((1 / min_nbor_dist) * sw - self.davg[ii][0]) / self.dstd[ii][0] + print('# DEEPMD: training data with lower boundary: ' + str(lower)) + print('# DEEPMD: training data with upper boundary: ' + str(upper)) + return math.floor(lower), math.ceil(upper) + + def _spline5_switch(self, + xx, + rmin, + rmax): + if xx < rmin: + vv = 1 + elif xx < rmax: + uu = (xx - rmin) / (rmax - rmin) + vv = uu*uu*uu * (-6 * uu*uu + 15 * uu - 10) + 1 + else: + vv = 0 + return vv \ No newline at end of file diff --git a/source/op/env_mat_stat.cc b/source/op/env_mat_stat.cc index 0db739272f..526bf7d4f2 100644 --- a/source/op/env_mat_stat.cc +++ b/source/op/env_mat_stat.cc @@ -105,6 +105,7 @@ class EnvMatStatOp : public OpKernel { min_nbor_dist_shape.AddDim (nloc * nnei); TensorShape max_nbor_size_shape ; max_nbor_size_shape.AddDim (nloc); + max_nbor_size_shape.AddDim (ntypes); int context_output_index = 0; Tensor* min_nbor_dist_tensor = NULL; @@ -219,7 +220,10 @@ class EnvMatStatOp : public OpKernel { } for (int ii = 0; ii < nloc; ii++) { - max_nbor_size(ii) = d_nlist_r[ii].size(); + for (int jj = 0; jj < d_nlist_r[ii].size(); jj++) { + int type = d_type[d_nlist_r[ii][jj]]; + max_nbor_size(ii * ntypes + type) += 1; + } } // loop over atoms, compute descriptors for each atom #pragma omp parallel for diff --git a/source/train/Trainer.py b/source/train/Trainer.py index e0a1b80c36..8a6afcccf1 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -91,9 +91,6 @@ def _init_param(self, jdata): fitting_param = j_must_have(model_param, 'fitting_net') self.model_param = model_param self.descrpt_param = descrpt_param - self.descrpt_type = descrpt_param['type'] - if 'compress' in model_param: - self.compress_param = model_param['compress'] # descriptor try: @@ -277,21 +274,15 @@ def build (self, self.model.data_stat(data) - if 'compress' in self.model_param and self.compress_param['compress']: - assert hasattr(self.descrpt, 'davg'), "Model compression error: descriptor must have attr davg!" - assert hasattr(self.descrpt, 'dstd'), "Model compression error: descriptor must have attr dstd!" - assert hasattr(self.descrpt, 'ntypes'), "Model compression error: descriptor must have attr ntypes!" - assert hasattr(self.descrpt, 'ndescrpt'), "Model compression error: descriptor must have attr ndescrpt!" - assert 'sel' in self.descrpt_param, "Model compression error: descriptor must have attr sel!" - assert 'rcut' in self.descrpt_param, "Model compression error: descriptor must have attr rcut!" - assert 'rcut_smth' in self.descrpt_param, "Model compression error: descriptor must have attr rcut_smth!" - if self.descrpt_type == 'se_a': - stat = EnvMatStat(self.descrpt_type, self.descrpt.ntypes, self.descrpt.ndescrpt, self.descrpt_param['rcut'], self.descrpt_param['rcut_smth'], self.descrpt_param['sel'], self.descrpt.davg, self.descrpt.dstd) - else: - raise RuntimeError ("Model compression error: descriptor type must be se_a!") - env_mat_range\ - = stat.get_env_mat_range(data) - self.descrpt.enable_compression(env_mat_range, self.compress_param['model_file'], self.compress_param['table_config']) # send the statistics of the training data and activate the descriptor compression mode + if 'compress' in self.model_param and self.model_param['compress']['compress']: + assert 'sel' in self.descrpt_param, "Error: descriptor must have attr sel!" + assert 'rcut' in self.descrpt_param, "Error: descriptor must have attr rcut!" + assert 'rcut_smth' in self.descrpt_param, "Error: descriptor must have attr rcut_smth!" + self.env_mat_stat \ + = EnvMatStat(self.ntypes, self.descrpt_param['rcut'], self.descrpt_param['rcut_smth'], self.descrpt_param['sel']) + self.min_nbor_dist, self.max_nbor_size \ + = self.env_mat_stat.get_env_mat_stat(data) + self.descrpt.enable_compression(self.min_nbor_dist, self.model_param['compress']['model_file'], self.model_param['compress']['table_config']) worker_device = "/job:%s/task:%d/%s" % (self.run_opt.my_job_name, self.run_opt.my_task_index, diff --git a/source/train/compress.py b/source/train/compress.py index 1f36f8e9e1..cd1ba79466 100644 --- a/source/train/compress.py +++ b/source/train/compress.py @@ -16,13 +16,12 @@ def compress(args): jdata = convert_input_v0_v1(jdata, warning = True, dump = 'input_v1_compat.json') - jdata = normalize(jdata) jdata['model']['compress'] = {} jdata['model']['compress']['compress'] = True jdata['model']['compress']['model_file'] = args.input - jdata['model']['compress']['table_config'] = args.table_config - + jdata['model']['compress']['table_config'] = [args.extrapolate, args.stride, 10 * args.stride, args.frequency] + # check the descriptor info of the input file assert jdata['model']['descriptor']['type'] == 'se_a', 'Model compression error: descriptor type must be se_a!' assert jdata['model']['descriptor']['resnet_dt'] == False, 'Model compression error: descriptor resnet_dt must be false!' diff --git a/source/train/main.py b/source/train/main.py index 9baaffce4e..2cd262f7d7 100644 --- a/source/train/main.py +++ b/source/train/main.py @@ -63,16 +63,26 @@ def main () : help="The file containing details of energy force and virial accuracy") parser_tst.add_argument("-a", "--atomic-energy", action = 'store_true', help="Test the accuracy of atomic energy") - + + """ + Compress a model, which including tabulating the embedding-net. + The table is composed of fifth-order polynomial coefficients and is assembled from two sub-tables. The first table takes the stride(parameter) as it\'s uniform stride, while the second table takes 10 * stride as it\s uniform stride + The range of the first table is automatically detected by deepmd-kit, while the second table ranges from the first table\'s upper boundary(upper) to the extrapolate(parameter) * upper. + """ parser_compress = subparsers.add_parser('compress', help='compress a model') parser_compress.add_argument('INPUT', - help='the input parameter file in json or yaml format') + help='The input parameter file in json or yaml format, which should be consistent with the original model parameter file') parser_compress.add_argument('-i', "--input", default = "frozen_model.pb", type=str, - help = "the original model") + help = "The original frozen model, which will be compressed by the deepmd-kit") parser_compress.add_argument("-o","--output", default = "frozen_model_compress.pb", type=str, - help='the compressed model') - parser_compress.add_argument('-t', '--table-config', nargs='+', default = [5, 0.01, 0.1, 1], type=float) - parser_compress.add_argument("-d", "--folder", type=str, default = ".", + help='The compressed model') + parser_compress.add_argument('-e', '--extrapolate', default=5, type=int, + help="The scale of model extrapolation") + parser_compress.add_argument('-s', '--stride', default=0.01, type=float, + help="The uniform stride of tabulation's first table, the second table will use 10 * stride as it's uniform stride") + parser_compress.add_argument('-f', '--frequency', default=-1, type=int, + help="The frequency of tabulation overflow check(If the input environment matrix overflow the first or second table range). By default do not check the overflow") + parser_compress.add_argument("-d", "--folder", type=str, default = ".", help="path to checkpoint folder") parser_train = subparsers.add_parser('doc-train-input', From 7231fb0d8cc9a16aa4c0285dd7a9ecf375bf09fa Mon Sep 17 00:00:00 2001 From: denghuilu Date: Mon, 8 Feb 2021 12:57:16 +0800 Subject: [PATCH 107/562] optimize code structure of model compression --- deepmd/descriptor/se_a.py | 23 +- .../{env_mat_stat.py => neighbor_stat.py} | 30 +- deepmd/utils/tabulate.py | 35 +-- source/lib/include/ComputeDescriptor.h | 47 --- source/op/CMakeLists.txt | 2 +- source/op/env_mat_stat.cc | 294 ------------------ source/op/neighbor_stat.cc | 192 ++++++++++++ source/train/Trainer.py | 12 +- 8 files changed, 238 insertions(+), 397 deletions(-) rename deepmd/utils/{env_mat_stat.py => neighbor_stat.py} (81%) delete mode 100644 source/op/env_mat_stat.cc create mode 100644 source/op/neighbor_stat.cc diff --git a/deepmd/descriptor/se_a.py b/deepmd/descriptor/se_a.py index 74ea3afbf1..09adba8dcc 100644 --- a/deepmd/descriptor/se_a.py +++ b/deepmd/descriptor/se_a.py @@ -232,7 +232,10 @@ def compute_input_stats (self, def enable_compression(self, min_nbor_dist, model_file = 'frozon_model.pb', - table_config = [5, 0.01, 0.1, -1] + table_extrapolate = 5, + table_stride_1 = 0.01, + table_stride_2 = 0.1, + check_frequency = -1 ) -> None: """ Reveive the statisitcs (distance, max_nbor_size and env_mat_range) of the training data. @@ -243,19 +246,21 @@ def enable_compression(self, The nearest distance between atoms model_file The original frozen model, which will be compressed by the program - table_config - The configuration including: - Table_config[0] denotes the scale of model extrapolation - Table_config[1] denotes the uniform stride of the first table - Table_config[2] denotes the uniform stride of the second table - Table_config[3] denotes the overflow check frequency + table_extrapolate + The scale of model extrapolation + table_stride_1 + The uniform stride of the first table + table_stride_2 + The uniform stride of the second table + check_frequency + The overflow check frequency """ self.compress = True self.model_file = model_file - self.table_config = table_config + self.table_config = [table_extrapolate, table_stride_1, table_stride_2, check_frequency] self.table = DeepTabulate(self.model_file, self.filter_np_precision, self.type_one_side) self.lower, self.upper \ - = self.table.build(min_nbor_dist, self.rcut_r, self.rcut_r_smth, self.table_config[0], self.table_config[1], self.table_config[2]) + = self.table.build(min_nbor_dist, table_extrapolate, table_stride_1, table_stride_2) def build (self, coord_ : tf.Tensor, diff --git a/deepmd/utils/env_mat_stat.py b/deepmd/utils/neighbor_stat.py similarity index 81% rename from deepmd/utils/env_mat_stat.py rename to deepmd/utils/neighbor_stat.py index b8f73959eb..9ccb3a5d0e 100644 --- a/deepmd/utils/env_mat_stat.py +++ b/deepmd/utils/neighbor_stat.py @@ -7,16 +7,14 @@ from deepmd.env import default_tf_session_config from deepmd.RunOptions import global_np_float_precision -class EnvMatStat(): +class NeighborStat(): """ Class for getting training data information. It loads data from DeepmdData object, and measures the data info, including neareest nbor distance between atoms, max nbor size of atoms and the output data range of the environment matrix. """ def __init__(self, ntypes : int, - rcut, - rcut_smth, - sel) -> None: + rcut) -> None: """ Constructor @@ -26,11 +24,8 @@ def __init__(self, The num of atom types rcut The cut-off radius - rcut_smth - From where the environment matrix should be smoothed - sel : list[str] - sel[i] specifies the maxmum number of type i atoms in the cut-off radius """ + self.rcut = rcut self.ntypes = ntypes self.place_holders = {} sub_graph = tf.Graph() @@ -40,22 +35,17 @@ def __init__(self, self.place_holders['type'] = tf.placeholder(tf.int32, [None, None], name='t_type') self.place_holders['natoms_vec'] = tf.placeholder(tf.int32, [self.ntypes+2], name='t_natoms') self.place_holders['default_mesh'] = tf.placeholder(tf.int32, [None], name='t_mesh') - self.sel = sel - self.rcut = rcut - self.rcut_smth = rcut_smth - self._min_nbor_dist, self._max_nbor_size \ - = op_module.env_mat_stat(self.place_holders['coord'], + self._max_nbor_size, self._min_nbor_dist \ + = op_module.neighbor_stat(self.place_holders['coord'], self.place_holders['type'], self.place_holders['natoms_vec'], self.place_holders['box'], self.place_holders['default_mesh'], - sel = self.sel, - rcut = self.rcut, - rcut_smth = self.rcut_smth) + rcut = self.rcut) self.sub_sess = tf.Session(graph = sub_graph, config=default_tf_session_config) - def get_env_mat_stat(self, - data) -> Tuple[float, List[int]]: + def get_stat(self, + data) -> Tuple[float, List[int]]: """ get the data statistics of the training data, including nearest nbor distance between atoms, max nbor size of atoms @@ -78,8 +68,8 @@ def get_env_mat_stat(self, for jj in data.data_systems[ii].dirs: data_set = data.data_systems[ii]._load_set(jj) for kk in range(np.array(data_set['type']).shape[0]): - dt, mn \ - = self.sub_sess.run([self._min_nbor_dist, self._max_nbor_size], + mn, dt \ + = self.sub_sess.run([self._max_nbor_size, self._min_nbor_dist], feed_dict = { self.place_holders['coord']: np.array(data_set['coord'])[kk].reshape([-1, data.natoms[ii] * 3]), self.place_holders['type']: np.array(data_set['type'])[kk].reshape([-1, data.natoms[ii]]), diff --git a/deepmd/utils/tabulate.py b/deepmd/utils/tabulate.py index 84255f6e16..c7e61a380b 100644 --- a/deepmd/utils/tabulate.py +++ b/deepmd/utils/tabulate.py @@ -27,13 +27,13 @@ def __init__(self, model_file The frozen model data_type - The precision of the table. Supported options are {1} + The precision of the tables. Supported options are {1} type_one_side Try to build N_types tables. Otherwise, building N_types^2 tables """ self.model_file = model_file - self.data_type = data_type + self.np_data_type = data_type self.type_one_side = type_one_side self.graph, self.graph_def = self._load_graph() @@ -48,6 +48,10 @@ def __init__(self, self.davg = self._get_tensor_value(self.graph.get_tensor_by_name ('descrpt_attr/t_avg:0')) self.dstd = self._get_tensor_value(self.graph.get_tensor_by_name ('descrpt_attr/t_std:0')) + self.descrpt = self.graph.get_operation_by_name ('DescrptSeA') + self.rcut = self.descrpt.get_attr('rcut_r') + self.rcut_smth = self.descrpt.get_attr('rcut_r_smth') + self.filter_variable_nodes = self._load_matrix_node() self.layer_size = int(len(self.filter_variable_nodes) / (self.ntypes * self.ntypes * 2)) self.table_size = self.ntypes * self.ntypes @@ -58,8 +62,8 @@ def __init__(self, # get trained variables self.bias = self._get_bias() self.matrix = self._get_matrix() - # self.matrix_layer_3 must exist - # self.data_type = type(self.matrix["layer_1"][0][0][0]) + + self.data_type = type(self.matrix["layer_1"][0][0][0]) assert self.matrix["layer_1"][0].size > 0, "no matrix exist in matrix array!" self.last_layer_size = self.matrix["layer_" + str(self.layer_size)][0].shape[1] # define tables @@ -69,8 +73,6 @@ def __init__(self, def build(self, min_nbor_dist, - rcut, - rcut_smth, extrapolate, stride0, stride1) -> Tuple[int, int]: @@ -81,10 +83,6 @@ def build(self, ---------- min_nbor_dist The nearest distance between neighbor atoms - rcut - The cut-off radius - rcut_smth - From where the environment matrix should be smoothed extrapolate The scale of model extrapolation stride0 @@ -100,7 +98,7 @@ def build(self, The upper boundary of environment matrix """ # tabulate range [lower, upper] with stride0 'stride0' - lower, upper = self._get_env_mat_range(min_nbor_dist, rcut, rcut_smth) + lower, upper = self._get_env_mat_range(min_nbor_dist) xx = np.arange(lower, upper, stride0, dtype = self.data_type) xx = np.append(xx, np.arange(upper, extrapolate * upper, stride1, dtype = self.data_type)) xx = np.append(xx, np.array([extrapolate * upper], dtype = self.data_type)) @@ -125,6 +123,7 @@ def build(self, self.data[net][jj][kk * 6 + 3] = (1 / (2 * tt * tt * tt)) * (20 * hh - (8 * dd[jj + 1][kk] + 12 * dd[jj][kk]) * tt - (3 * d2[jj][kk] - d2[jj + 1][kk]) * tt * tt) self.data[net][jj][kk * 6 + 4] = (1 / (2 * tt * tt * tt * tt)) * (-30 * hh + (14 * dd[jj + 1][kk] + 16 * dd[jj][kk]) * tt + (3 * d2[jj][kk] - 2 * d2[jj + 1][kk]) * tt * tt) self.data[net][jj][kk * 6 + 5] = (1 / (2 * tt * tt * tt * tt * tt)) * (12 * hh - 6 * (dd[jj + 1][kk] + dd[jj][kk]) * tt + (d2[jj + 1][kk] - d2[jj][kk]) * tt * tt) + self.data[net].astype(self.np_data_type) return lower, upper def _load_graph(self): @@ -165,12 +164,12 @@ def _get_bias(self): for ii in range(0, self.ntypes): tensor_value = np.frombuffer (self.filter_variable_nodes["filter_type_all/bias_" + str(layer) + "_" + str(int(ii))].tensor_content) tensor_shape = tf.TensorShape(self.filter_variable_nodes["filter_type_all/bias_" + str(layer) + "_" + str(int(ii))].tensor_shape).as_list() - bias["layer_" + str(layer)].append(np.reshape(tensor_value, tensor_shape).astype(self.data_type)) + bias["layer_" + str(layer)].append(np.reshape(tensor_value, tensor_shape)) else: for ii in range(0, self.ntypes * self.ntypes): tensor_value = np.frombuffer(self.filter_variable_nodes["filter_type_" + str(int(ii / self.ntypes)) + "/bias_" + str(layer) + "_" + str(int(ii % self.ntypes))].tensor_content) tensor_shape = tf.TensorShape(self.filter_variable_nodes["filter_type_" + str(int(ii / self.ntypes)) + "/bias_" + str(layer) + "_" + str(int(ii % self.ntypes))].tensor_shape).as_list() - bias["layer_" + str(layer)].append(np.reshape(tensor_value, tensor_shape).astype(self.data_type)) + bias["layer_" + str(layer)].append(np.reshape(tensor_value, tensor_shape)) return bias def _get_matrix(self): @@ -181,12 +180,12 @@ def _get_matrix(self): for ii in range(0, self.ntypes): tensor_value = np.frombuffer (self.filter_variable_nodes["filter_type_all/matrix_" + str(layer) + "_" + str(int(ii))].tensor_content) tensor_shape = tf.TensorShape(self.filter_variable_nodes["filter_type_all/matrix_" + str(layer) + "_" + str(int(ii))].tensor_shape).as_list() - matrix["layer_" + str(layer)].append(np.reshape(tensor_value, tensor_shape).astype(self.data_type)) + matrix["layer_" + str(layer)].append(np.reshape(tensor_value, tensor_shape)) else: for ii in range(0, self.ntypes * self.ntypes): tensor_value = np.frombuffer(self.filter_variable_nodes["filter_type_" + str(int(ii / self.ntypes)) + "/matrix_" + str(layer) + "_" + str(int(ii % self.ntypes))].tensor_content) tensor_shape = tf.TensorShape(self.filter_variable_nodes["filter_type_" + str(int(ii / self.ntypes)) + "/matrix_" + str(layer) + "_" + str(int(ii % self.ntypes))].tensor_shape).as_list() - matrix["layer_" + str(layer)].append(np.reshape(tensor_value, tensor_shape).astype(self.data_type)) + matrix["layer_" + str(layer)].append(np.reshape(tensor_value, tensor_shape)) return matrix # one-by-one executions @@ -223,12 +222,10 @@ def _save_data(self): np.savetxt('data_' + str(int(ii)), self.data[net]) def _get_env_mat_range(self, - min_nbor_dist, - rcut, - rcut_smth): + min_nbor_dist): lower = 100.0 upper = -10.0 - sw = self._spline5_switch(min_nbor_dist, rcut_smth, rcut) + sw = self._spline5_switch(min_nbor_dist, self.rcut_smth, self.rcut) for ii in range(self.ntypes): if lower > -self.davg[ii][0] / self.dstd[ii][0]: lower = -self.davg[ii][0] / self.dstd[ii][0] diff --git a/source/lib/include/ComputeDescriptor.h b/source/lib/include/ComputeDescriptor.h index bab9032828..3b85f931dc 100644 --- a/source/lib/include/ComputeDescriptor.h +++ b/source/lib/include/ComputeDescriptor.h @@ -143,19 +143,6 @@ void compute_descriptor_se_r (std::vector & descrpt_r, const double & rmin, const double & rmax); -inline -void get_rij(std::vector & rij_a, - const std::vector & posi, - const int & ntypes, - const std::vector & type, - const SimulationRegion & region, - const bool & b_pbc, - const int & i_idx, - const std::vector & fmt_nlist_a, - const std::vector & sec_a, - const double & rmin, - const double & rmax); - struct NeighborInfo { int type; @@ -1075,40 +1062,6 @@ void compute_descriptor_se_a (std::vector & descrpt_a, } } -void get_rij(std::vector & rij_a, - const std::vector & posi, - const int & ntypes, - const std::vector & type, - const SimulationRegion & region, - const bool & b_pbc, - const int & i_idx, - const std::vector & fmt_nlist_a, - const std::vector & sec_a, - const double & rmin, - const double & rmax) -{ - // compute the diff of the neighbors - std::vector > sel_a_diff (sec_a.back()); - rij_a.resize (sec_a.back() * 3); - fill (rij_a.begin(), rij_a.end(), 0.0); - for (int ii = 0; ii < int(sec_a.size()) - 1; ++ii){ - for (int jj = sec_a[ii]; jj < sec_a[ii+1]; ++jj){ - if (fmt_nlist_a[jj] < 0) break; - sel_a_diff[jj].resize(3); - const int & j_idx = fmt_nlist_a[jj]; - if (b_pbc){ - region.diffNearestNeighbor (posi[j_idx*3+0], posi[j_idx*3+1], posi[j_idx*3+2], - posi[i_idx*3+0], posi[i_idx*3+1], posi[i_idx*3+2], - sel_a_diff[jj][0], sel_a_diff[jj][1], sel_a_diff[jj][2]); - } - else { - for (int dd = 0; dd < 3; ++dd) sel_a_diff[jj][dd] = posi[j_idx*3+dd] - posi[i_idx*3+dd]; - } - for (int dd = 0; dd < 3; ++dd) rij_a[jj*3+dd] = sel_a_diff[jj][dd]; - } - } -} - void compute_descriptor_se_r (std::vector & descrpt, std::vector & descrpt_deriv, diff --git a/source/op/CMakeLists.txt b/source/op/CMakeLists.txt index da18377683..244eab6e75 100644 --- a/source/op/CMakeLists.txt +++ b/source/op/CMakeLists.txt @@ -3,7 +3,7 @@ set(OP_LIB ${PROJECT_SOURCE_DIR}/lib/src/SimulationRegion.cpp ${PROJECT_SOURCE_DIR}/lib/src/NeighborList.cpp) set (OP_CXX_FLAG -D_GLIBCXX_USE_CXX11_ABI=${OP_CXX_ABI} ) -file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc descrpt_se_r.cc tab_inter.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc gelu.cc map_aparam.cc env_mat_stat.cc unaggregated_grad.cc tabulate.cc) +file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc descrpt_se_r.cc tab_inter.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc gelu.cc map_aparam.cc neighbor_stat.cc unaggregated_grad.cc tabulate.cc) file(GLOB OP_CUDA_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a_multi_device.cc descrpt_se_r_multi_device.cc tab_inter.cc prod_force_se_a_multi_device.cc prod_virial_se_a_multi_device.cc prod_force_se_r_multi_device.cc prod_virial_se_r_multi_device.cc soft_min.cc soft_min_force.cc soft_min_virial.cc gelu_multi_device.cc tabulate_multi_device.cc) file(GLOB OP_GRADS_SRC prod_force_grad.cc prod_force_se_a_grad.cc prod_force_se_r_grad.cc prod_virial_grad.cc prod_virial_se_a_grad.cc prod_virial_se_r_grad.cc soft_min_force_grad.cc soft_min_virial_grad.cc ) file(GLOB OP_PY *.py) diff --git a/source/op/env_mat_stat.cc b/source/op/env_mat_stat.cc deleted file mode 100644 index 526bf7d4f2..0000000000 --- a/source/op/env_mat_stat.cc +++ /dev/null @@ -1,294 +0,0 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - -#include "ComputeDescriptor.h" -#include "NeighborList.h" - -typedef double boxtensor_t ; -typedef double compute_t; - -using namespace tensorflow; -// using namespace std; - -using CPUDevice = Eigen::ThreadPoolDevice; -using GPUDevice = Eigen::GpuDevice; - -REGISTER_OP("EnvMatStat") - .Attr("T: {float, double}") - .Input("coord: T") //atomic coordinates - .Input("type: int32") //atomic type - .Input("natoms: int32") //local atomic number; each type atomic number; daizheyingxiangqude atomic numbers - .Input("box : T") - .Input("mesh : int32") - .Attr("rcut: float") //no use - .Attr("rcut_smth: float") - .Attr("sel: list(int)") - .Output("min_nbor_dist: T") - .Output("max_nbor_size: int32"); - -template -class EnvMatStatOp : public OpKernel { -public: - explicit EnvMatStatOp(OpKernelConstruction* context) : OpKernel(context) { - OP_REQUIRES_OK(context, context->GetAttr("rcut", &rcut)); - OP_REQUIRES_OK(context, context->GetAttr("rcut_smth", &rcut_smth)); - OP_REQUIRES_OK(context, context->GetAttr("sel", &sel)); - cum_sum (sec, sel); - ndescrpt = sec.back() * 4; - nnei = sec.back(); - } - - void Compute(OpKernelContext* context) override { - counter++; - // Grab the input tensor - int context_input_index = 0; - const Tensor& coord_tensor = context->input(context_input_index++); - const Tensor& type_tensor = context->input(context_input_index++); - const Tensor& natoms_tensor = context->input(context_input_index++); - const Tensor& box_tensor = context->input(context_input_index++); - const Tensor& mesh_tensor = context->input(context_input_index++); - - // set size of the sample - OP_REQUIRES (context, (coord_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of coord should be 2")); - OP_REQUIRES (context, (type_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of type should be 2")); - OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); - OP_REQUIRES (context, (box_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of box should be 2")); - OP_REQUIRES (context, (mesh_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of mesh should be 1")); - OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); - auto natoms = natoms_tensor .flat(); - int nloc = natoms(0); - int nall = natoms(1); - int ntypes = natoms_tensor.shape().dim_size(0) - 2; - int nsamples = coord_tensor.shape().dim_size(0); - - // check the sizes - OP_REQUIRES (context, (nsamples == type_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (nsamples == box_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (nall * 3 == coord_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); - OP_REQUIRES (context, (nall == type_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); - OP_REQUIRES (context, (9 == box_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of box should be 9")); - - int nei_mode = 0; - if (mesh_tensor.shape().dim_size(0) == 16) { - // lammps neighbor list - nei_mode = 3; - } - else if (mesh_tensor.shape().dim_size(0) == 12) { - // user provided extended mesh - nei_mode = 2; - } - else if (mesh_tensor.shape().dim_size(0) == 6) { - // manual copied pbc - assert (nloc == nall); - nei_mode = 1; - } - else if (mesh_tensor.shape().dim_size(0) == 0) { - // no pbc - nei_mode = -1; - } - else { - throw std::runtime_error("invalid mesh tensor"); - } - bool b_pbc = true; - // if region is given extended, do not use pbc - if (nei_mode >= 1 || nei_mode == -1) { - b_pbc = false; - } - bool b_norm_atom = false; - if (nei_mode == 1){ - b_norm_atom = true; - } - - TensorShape min_nbor_dist_shape ; - min_nbor_dist_shape.AddDim (nloc * nnei); - TensorShape max_nbor_size_shape ; - max_nbor_size_shape.AddDim (nloc); - max_nbor_size_shape.AddDim (ntypes); - - int context_output_index = 0; - Tensor* min_nbor_dist_tensor = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - min_nbor_dist_shape, - &min_nbor_dist_tensor)); - Tensor* max_nbor_size_tensor = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - max_nbor_size_shape, - &max_nbor_size_tensor)); - - auto coord = coord_tensor .matrix(); - auto type = type_tensor .matrix(); - auto box = box_tensor .matrix(); - auto mesh = mesh_tensor .flat(); - auto min_nbor_dist = min_nbor_dist_tensor ->flat(); - // find a potential bug here! - auto max_nbor_size = max_nbor_size_tensor ->flat(); - - for (int ii = 0; ii < static_cast(min_nbor_dist_tensor->NumElements()); ii++) { - min_nbor_dist(ii) = 10000.0; - } - for (int ii = 0; ii < static_cast(max_nbor_size_tensor->NumElements()); ii++) { - max_nbor_size(ii) = 0; - } - - for (int kk = 0; kk < nsamples; ++kk){ - // set region - boxtensor_t boxt [9] = {0}; - for (int dd = 0; dd < 9; ++dd) { - boxt[dd] = box(kk, dd); - } - SimulationRegion region; - region.reinitBox (boxt); - - // set & normalize coord - std::vector d_coord3 (nall*3); - for (int ii = 0; ii < nall; ++ii){ - for (int dd = 0; dd < 3; ++dd){ - d_coord3[ii*3+dd] = coord(kk, ii*3+dd); - } - if (b_norm_atom){ - compute_t inter[3]; - region.phys2Inter (inter, &d_coord3[3*ii]); - for (int dd = 0; dd < 3; ++dd){ - if (inter[dd] < 0 ) inter[dd] += 1.; - else if (inter[dd] >= 1) inter[dd] -= 1.; - } - region.inter2Phys (&d_coord3[3*ii], inter); - } - } - - // set type - std::vector d_type (nall); - for (int ii = 0; ii < nall; ++ii) d_type[ii] = type(kk, ii); - - // build nlist - std::vector > d_nlist_a; - std::vector > d_nlist_r; - std::vector nlist_map; - bool b_nlist_map = false; - if (nei_mode == 3) { - int * pilist, *pjrange, *pjlist; - memcpy (&pilist, &mesh(4), sizeof(int *)); - memcpy (&pjrange, &mesh(8), sizeof(int *)); - memcpy (&pjlist, &mesh(12), sizeof(int *)); - int inum = mesh(1); - assert (inum == nloc); - d_nlist_a.resize (inum); - d_nlist_r.resize (inum); - for (unsigned ii = 0; ii < inum; ++ii){ - d_nlist_r.reserve (pjrange[inum] / inum + 10); - } - for (unsigned ii = 0; ii < inum; ++ii){ - int i_idx = pilist[ii]; - for (unsigned jj = pjrange[ii]; jj < pjrange[ii+1]; ++jj){ - int j_idx = pjlist[jj]; - d_nlist_r[i_idx].push_back (j_idx); - } - } - } - else if (nei_mode == 2) { - // std::cout << "I'm in nei_mode 2" << std::endl; - std::vector nat_stt = {mesh(1-1), mesh(2-1), mesh(3-1)}; - std::vector nat_end = {mesh(4-1), mesh(5-1), mesh(6-1)}; - std::vector ext_stt = {mesh(7-1), mesh(8-1), mesh(9-1)}; - std::vector ext_end = {mesh(10-1), mesh(11-1), mesh(12-1)}; - std::vector global_grid (3); - for (int dd = 0; dd < 3; ++dd) global_grid[dd] = nat_end[dd] - nat_stt[dd]; - ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, -1, rcut, nat_stt, nat_end, ext_stt, ext_end, region, global_grid); - } - else if (nei_mode == 1) { - // std::cout << "I'm in nei_mode 1" << std::endl; - std::vector bk_d_coord3 = d_coord3; - std::vector bk_d_type = d_type; - std::vector ncell, ngcell; - copy_coord(d_coord3, d_type, nlist_map, ncell, ngcell, bk_d_coord3, bk_d_type, rcut, region); - b_nlist_map = true; - std::vector nat_stt(3, 0); - std::vector ext_stt(3), ext_end(3); - for (int dd = 0; dd < 3; ++dd){ - ext_stt[dd] = -ngcell[dd]; - ext_end[dd] = ncell[dd] + ngcell[dd]; - } - ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, -1, rcut, nat_stt, ncell, ext_stt, ext_end, region, ncell); - } - else if (nei_mode == -1){ - ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, -1, rcut, NULL); - } - else { - throw std::runtime_error("unknow neighbor mode"); - } - - for (int ii = 0; ii < nloc; ii++) { - for (int jj = 0; jj < d_nlist_r[ii].size(); jj++) { - int type = d_type[d_nlist_r[ii][jj]]; - max_nbor_size(ii * ntypes + type) += 1; - } - } - // loop over atoms, compute descriptors for each atom -#pragma omp parallel for - for (int ii = 0; ii < nloc; ++ii){ - std::vector fmt_nlist_a; - std::vector fmt_nlist_r; - std::vector sec_r(sec.size(), 0); - - int ret = -1; - if ((ret = format_nlist_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut, sec, sec_r)) != -1){ - if (count_nei_idx_overflow == 0) { - std::cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << std::endl; - flush(std::cout); - count_nei_idx_overflow ++; - } - } - - std::vector d_rij_a; - get_rij (d_rij_a, - d_coord3, - ntypes, - d_type, - region, - b_pbc, - ii, - fmt_nlist_a, - sec, - rcut_smth, - rcut); - - // check sizes - assert (d_rij_a.size() == nnei * 3); - assert (int(fmt_nlist_a.size()) == nnei); - for (int jj = 0; jj < nnei * 3; ++jj){ - if (jj % 3 == 0 && d_rij_a[jj] > 0) { - min_nbor_dist(ii * nnei + jj / 3) = sqrt(d_rij_a[jj] * d_rij_a[jj] + d_rij_a[jj + 1] * d_rij_a[jj + 1] + d_rij_a[jj + 2] * d_rij_a[jj + 2]); - } - } - } - } - } -private: - int counter = -1; - float rcut; - float rcut_smth; - std::vector sel; - std::vector sec; - int ndescrpt; - int nnei; - bool fill_nei_a; - int count_nei_idx_overflow; - void - cum_sum (std::vector & sec, - const std::vector & n_sel) const { - sec.resize (n_sel.size() + 1); - sec[0] = 0; - for (int ii = 1; ii < sec.size(); ++ii){ - sec[ii] = sec[ii-1] + n_sel[ii-1]; - } - } -}; - -#define REGISTER_CPU(T) \ -REGISTER_KERNEL_BUILDER( \ - Name("EnvMatStat").Device(DEVICE_CPU).TypeConstraint("T"), \ - EnvMatStatOp); -REGISTER_CPU(float); -REGISTER_CPU(double); \ No newline at end of file diff --git a/source/op/neighbor_stat.cc b/source/op/neighbor_stat.cc new file mode 100644 index 0000000000..1be0ba23d5 --- /dev/null +++ b/source/op/neighbor_stat.cc @@ -0,0 +1,192 @@ +#include "tensorflow/core/framework/op.h" +#include "tensorflow/core/framework/op_kernel.h" +#include "tensorflow/core/framework/shape_inference.h" +#include + +#include "NeighborList.h" + +typedef double boxtensor_t ; +typedef double compute_t; + +using namespace tensorflow; +// using namespace std; + +using CPUDevice = Eigen::ThreadPoolDevice; +using GPUDevice = Eigen::GpuDevice; + +REGISTER_OP("NeighborStat") + .Attr("T: {float, double}") + .Input("coord: T") + .Input("type: int32") + .Input("natoms: int32") + .Input("box : T") + .Input("mesh : int32") + .Attr("rcut: float") + .Output("max_nbor_size: int32") + .Output("min_nbor_dist: T"); + +template +class NeighborStatOp : public OpKernel { +public: + explicit NeighborStatOp(OpKernelConstruction* context) : OpKernel(context) { + OP_REQUIRES_OK(context, context->GetAttr("rcut", &rcut)); + } + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& coord_tensor = context->input(context_input_index++); + const Tensor& type_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); + const Tensor& box_tensor = context->input(context_input_index++); + const Tensor& mesh_tensor = context->input(context_input_index++); + + + OP_REQUIRES (context, (coord_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of coord should be 2")); + OP_REQUIRES (context, (type_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of type should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + OP_REQUIRES (context, (box_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of box should be 2")); + OP_REQUIRES (context, (mesh_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of mesh should be 1")); + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + int nloc = natoms_tensor.flat().data()[0]; + int nall = natoms_tensor.flat().data()[1]; + int nsamples = coord_tensor.shape().dim_size(0); + int ntypes = natoms_tensor.shape().dim_size(0) - 2; + // check the sizes + OP_REQUIRES (context, (nsamples == type_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nsamples == box_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nall * 3 == coord_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); + OP_REQUIRES (context, (nall == type_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); + OP_REQUIRES (context, (9 == box_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of box should be 9")); + + int nei_mode = 0; + if (mesh_tensor.shape().dim_size(0) == 6) { + // manual copied pbc + assert (nloc == nall); + nei_mode = 1; + } + else if (mesh_tensor.shape().dim_size(0) == 0) { + // no pbc + nei_mode = -1; + } + else { + throw std::runtime_error("invalid mesh tensor"); + } + // if region is given extended, do not use pbc + bool b_pbc = (nei_mode >= 1 || nei_mode == -1) ? false : true; + bool b_norm_atom = (nei_mode == 1) ? true : false; + + TensorShape max_nbor_size_shape ; + max_nbor_size_shape.AddDim (nloc); + max_nbor_size_shape.AddDim (ntypes); + + int context_output_index = 0; + Tensor* max_nbor_size_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + max_nbor_size_shape, + &max_nbor_size_tensor)); + + const FPTYPE* coord = coord_tensor.flat().data(); + const int* type = type_tensor .flat().data(); + const FPTYPE* box = box_tensor .flat().data(); + const int* mesh = mesh_tensor .flat().data(); + int* max_nbor_size = max_nbor_size_tensor ->flat().data(); + + for (int ii = 0; ii < static_cast(max_nbor_size_tensor->NumElements()); ii++) { + max_nbor_size[ii] = 0; + } + + // set region + boxtensor_t boxt [9] = {0}; + for (int dd = 0; dd < 9; ++dd) { + boxt[dd] = box[dd]; + } + SimulationRegion region; + region.reinitBox (boxt); + // set & normalize coord + std::vector d_coord3 (nall * 3); + for (int ii = 0; ii < nall; ++ii) { + for (int dd = 0; dd < 3; ++dd) { + d_coord3[ii * 3 + dd] = coord[ii * 3 + dd]; + } + if (b_norm_atom) { + compute_t inter[3]; + region.phys2Inter (inter, &d_coord3[3 * ii]); + for (int dd = 0; dd < 3; ++dd) { + if (inter[dd] < 0 ) inter[dd] += 1.; + else if (inter[dd] >= 1) inter[dd] -= 1.; + } + region.inter2Phys (&d_coord3[3 * ii], inter); + } + } + + // set type + std::vector d_type (nall); + for (int ii = 0; ii < nall; ++ii) d_type[ii] = type[ii]; + + // build nlist + std::vector > d_nlist_a; + std::vector > d_nlist_r; + std::vector nlist_map; + bool b_nlist_map = false; + + if (nei_mode == 1) { + // std::cout << "I'm in nei_mode 1" << std::endl; + std::vector bk_d_coord3 = d_coord3; + std::vector bk_d_type = d_type; + std::vector ncell, ngcell; + copy_coord(d_coord3, d_type, nlist_map, ncell, ngcell, bk_d_coord3, bk_d_type, rcut, region); + b_nlist_map = true; + std::vector nat_stt(3, 0); + std::vector ext_stt(3), ext_end(3); + for (int dd = 0; dd < 3; ++dd) { + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, -1, rcut, nat_stt, ncell, ext_stt, ext_end, region, ncell); + } + else if (nei_mode == -1) { + ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, -1, rcut, NULL); + } + else { + throw std::runtime_error("unknow neighbor mode"); + } + + int MAX_NNEI = 0; + for (int ii = 0; ii < nloc; ii++) { + MAX_NNEI = MAX_NNEI < d_nlist_r[ii].size() ? d_nlist_r[ii].size() : MAX_NNEI; + } + // allocate output tensor for deepmd-kit + TensorShape min_nbor_dist_shape; + min_nbor_dist_shape.AddDim (nloc * MAX_NNEI); + Tensor* min_nbor_dist_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, + min_nbor_dist_shape, + &min_nbor_dist_tensor)); + FPTYPE* min_nbor_dist = min_nbor_dist_tensor ->flat().data(); + for (int ii = 0; ii < static_cast(min_nbor_dist_tensor->NumElements()); ii++) { + min_nbor_dist[ii] = 10000.0; + } + + #pragma omp parallel for + for (int ii = 0; ii < nloc; ii++) { + for (int jj = 0; jj < d_nlist_r[ii].size(); jj++) { + int type = d_type[d_nlist_r[ii][jj]]; + max_nbor_size[ii * ntypes + type] += 1; + compute_t rij[3] = {d_coord3[d_nlist_r[ii][jj] * 3 + 0] - d_coord3[ii * 3 + 0], d_coord3[d_nlist_r[ii][jj] * 3 + 1] - d_coord3[ii * 3 + 1], d_coord3[d_nlist_r[ii][jj] * 3 + 2] - d_coord3[ii * 3 + 2]}; + min_nbor_dist[ii * MAX_NNEI + jj] = sqrt(rij[0] * rij[0] + rij[1] * rij[1] + rij[2] * rij[2]); + } + } + } + +private: + int nnei; + float rcut; +}; + +#define REGISTER_CPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("NeighborStat").Device(DEVICE_CPU).TypeConstraint("T"), \ + NeighborStatOp); +REGISTER_CPU(float); +REGISTER_CPU(double); \ No newline at end of file diff --git a/source/train/Trainer.py b/source/train/Trainer.py index 8a6afcccf1..7c95fda5bc 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -19,7 +19,7 @@ from deepmd.Model import Model, WFCModel, DipoleModel, PolarModel, GlobalPolarModel from deepmd.loss import EnerStdLoss, EnerDipoleLoss, TensorLoss from deepmd.utils.learning_rate import LearningRateExp -from deepmd.utils.env_mat_stat import EnvMatStat +from deepmd.utils.neighbor_stat import NeighborStat from tensorflow.python.client import timeline from deepmd.env import op_module @@ -275,14 +275,12 @@ def build (self, self.model.data_stat(data) if 'compress' in self.model_param and self.model_param['compress']['compress']: - assert 'sel' in self.descrpt_param, "Error: descriptor must have attr sel!" assert 'rcut' in self.descrpt_param, "Error: descriptor must have attr rcut!" - assert 'rcut_smth' in self.descrpt_param, "Error: descriptor must have attr rcut_smth!" - self.env_mat_stat \ - = EnvMatStat(self.ntypes, self.descrpt_param['rcut'], self.descrpt_param['rcut_smth'], self.descrpt_param['sel']) + self.neighbor_stat \ + = NeighborStat(self.ntypes, self.descrpt_param['rcut']) self.min_nbor_dist, self.max_nbor_size \ - = self.env_mat_stat.get_env_mat_stat(data) - self.descrpt.enable_compression(self.min_nbor_dist, self.model_param['compress']['model_file'], self.model_param['compress']['table_config']) + = self.neighbor_stat.get_stat(data) + self.descrpt.enable_compression(self.min_nbor_dist, self.model_param['compress']['model_file'], self.model_param['compress']['table_config'][0], self.model_param['compress']['table_config'][1], self.model_param['compress']['table_config'][2], self.model_param['compress']['table_config'][3]) worker_device = "/job:%s/task:%d/%s" % (self.run_opt.my_job_name, self.run_opt.my_task_index, From b4fe532c3289c25cee29c0c96d08abc18c29c282 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 8 Feb 2021 16:03:19 +0800 Subject: [PATCH 108/562] fix bug in compiling. fix bug in fmt_nlist_cpu: wrong handeling of too small sel --- source/lib/src/fmt_nlist.cc | 3 + source/lib/tests/test_env_mat_a.cc | 113 +++++++++++++++++++++++++++++ source/lib/tests/test_fmt_nlist.cc | 96 ++++++++++++++++++++++++ source/op/descrpt_se_a.cc | 2 +- source/op/descrpt_se_r.cc | 3 +- 5 files changed, 215 insertions(+), 2 deletions(-) diff --git a/source/lib/src/fmt_nlist.cc b/source/lib/src/fmt_nlist.cc index 6275a30539..1def0a8fb5 100644 --- a/source/lib/src/fmt_nlist.cc +++ b/source/lib/src/fmt_nlist.cc @@ -116,6 +116,9 @@ int format_nlist_cpu ( if (nei_iter[nei_type] < sec_a[nei_type+1]) { fmt_nei_idx_a[nei_iter[nei_type] ++] = sel_nei[kk].index; } + else{ + overflowed = nei_type; + } } return overflowed; } diff --git a/source/lib/tests/test_env_mat_a.cc b/source/lib/tests/test_env_mat_a.cc index d00ee6e4df..76f92f7c78 100644 --- a/source/lib/tests/test_env_mat_a.cc +++ b/source/lib/tests/test_env_mat_a.cc @@ -57,6 +57,61 @@ class TestEnvMatA : public ::testing::Test } }; + +class TestEnvMatAShortSel : public ::testing::Test +{ +protected: + std::vector posi = {12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall; + double rc = 6; + double rc_smth = 0.8; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sec_a = {0, 2, 4}; + std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector> nlist_a, nlist_r; + std::vector> nlist_a_cpy, nlist_r_cpy; + std::vector expected_env = { + 0.12206, 0.12047, 0.01502, -0.01263, 0.00000, 0.00000, 0.00000, 0.00000, 1.02167, -0.77271, 0.32370, 0.58475, 0.99745, 0.41810, 0.75655, -0.49773, + 1.02167, 0.77271, -0.32370, -0.58475, 0.04135, 0.04039, 0.00123, -0.00880, 0.59220, 0.42028, 0.16304, -0.38405, 0.03694, 0.03680, -0.00300, -0.00117, + 0.99745, -0.41810, -0.75655, 0.49773, 0.19078, 0.18961, -0.01951, 0.00793, 0.59220, -0.42028, -0.16304, 0.38405, 0.13499, 0.12636, -0.03140, 0.03566, + 0.12206, -0.12047, -0.01502, 0.01263, 0.00000, 0.00000, 0.00000, 0.00000, 1.06176, 0.16913, -0.55250, 0.89077, 1.03163, 0.96880, 0.23422, -0.26615, + 1.06176, -0.16913, 0.55250, -0.89077, 0.10564, -0.10495, 0.00143, -0.01198, 0.66798, 0.34516, 0.32245, -0.47232, 0.13499, -0.12636, 0.03140, -0.03566, + 1.03163, -0.96880, -0.23422, 0.26615, 0.03103, -0.03041, -0.00452, 0.00425, 0.66798, -0.34516, -0.32245, 0.47232, 0.07054, -0.07049, 0.00175, 0.00210, + }; + + void SetUp() override { + double box[] = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + region.reinitBox(box); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + build_nlist(nlist_a, nlist_r, posi, rc, rc, ncell, region); + build_nlist(nlist_a_cpy, nlist_r_cpy, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + } + void TearDown() override { + } +}; + + TEST_F(TestEnvMatA, orig_cpy) { std::vector fmt_nlist_a, fmt_nlist_r; @@ -245,3 +300,61 @@ TEST_F(TestEnvMatA, cpu_num_deriv) // printf("\n"); } } + + +TEST_F(TestEnvMatAShortSel, orig_cpy) +{ + std::vector fmt_nlist_a, fmt_nlist_r; + std::vector env, env_deriv, rij_a; + bool pbc = false; + for(int ii = 0; ii < nloc; ++ii){ + int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + EXPECT_EQ(ret, 1); + env_mat_a(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + EXPECT_EQ(env.size(), sec_a[2]*4); + EXPECT_EQ(env.size(), env_deriv.size()/3); + for (int jj = 0; jj < sec_a[2]; ++jj){ + for (int dd = 0; dd < 4; ++dd){ + EXPECT_LT(fabs(env[jj*4+dd] - expected_env[ii*sec_a[2]*4 + jj*4 + dd]) , 1e-5); + } + } + // for (int jj = 0; jj < sec_a[2]; ++jj){ + // printf("%8.5f, %8.5f, %8.5f, %8.5f, ", env[jj*4+0], env[jj*4+1], env[jj*4+2], env[jj*4+3]); + // } + // printf("\n"); + } +} + +TEST_F(TestEnvMatAShortSel, orig_pbc) +{ + std::vector fmt_nlist_a, fmt_nlist_r; + std::vector env, env_deriv, rij_a; + bool pbc = true; + for(int ii = 0; ii < nloc; ++ii){ + int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi, ntypes, atype, region, pbc, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); + EXPECT_EQ(ret, 1); + env_mat_a(env, env_deriv, rij_a, posi, ntypes, atype, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < sec_a[2]; ++jj){ + for (int dd = 0; dd < 4; ++dd){ + EXPECT_LT(fabs(env[jj*4+dd] - expected_env[ii*sec_a[2]*4 + jj*4 + dd]) , 1e-5); + } + } + } +} + +TEST_F(TestEnvMatAShortSel, cpu) +{ + std::vector fmt_nlist_a, fmt_nlist_r; + std::vector env, env_deriv, rij_a; + bool pbc = false; + for(int ii = 0; ii < nloc; ++ii){ + int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + EXPECT_EQ(ret, 1); + env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < sec_a[2]; ++jj){ + for (int dd = 0; dd < 4; ++dd){ + EXPECT_LT(fabs(env[jj*4+dd] - expected_env[ii*sec_a[2]*4 + jj*4 + dd]) , 1e-5); + } + } + } +} diff --git a/source/lib/tests/test_fmt_nlist.cc b/source/lib/tests/test_fmt_nlist.cc index ef98484396..d3320101cf 100644 --- a/source/lib/tests/test_fmt_nlist.cc +++ b/source/lib/tests/test_fmt_nlist.cc @@ -60,6 +60,64 @@ class TestFormatNlist : public ::testing::Test }; +class TestFormatNlistShortSel : public ::testing::Test +{ +protected: + std::vector posi = {12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall; + double rc = 6; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sec_a = {0, 2, 4}; + std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector expect_nlist_cpy = { + 33, -1, 1, 32, + 0, 33, 32, 34, + 6, 3, 7, 4, + 6, -1, 4, 5, + 3, 6, 5, 2, + 3, 6, 4, 2, + }; + std::vector expect_nlist; + + void SetUp() override { + double box[] = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + region.reinitBox(box); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + for (unsigned ii = 0; ii < expect_nlist_cpy.size(); ++ii){ + if (expect_nlist_cpy[ii] >= 0){ + expect_nlist.push_back(mapping[expect_nlist_cpy[ii]]); + } + else{ + expect_nlist.push_back(-1); + } + } + } + void TearDown() override { + } +}; + + // orginal implementation. copy ghost TEST_F(TestFormatNlist, orig_cpy) { @@ -145,3 +203,41 @@ TEST_F(TestFormatNlist, cpu_equal_orig) } } + +// orginal implementation. copy ghost +TEST_F(TestFormatNlistShortSel, orig_cpy) +{ + std::vector> nlist_a, nlist_r; + std::vector fmt_nlist_a, fmt_nlist_r; + build_nlist(nlist_a, nlist_r, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + + bool pbc = false; + int ii = 0; + for (ii = 0; ii < nloc; ++ii){ + int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi_cpy, ntypes, atype_cpy, region, pbc, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); + EXPECT_EQ(ret, 1); + for (int jj = 0; jj < sec_a[2]; ++jj){ + EXPECT_EQ(fmt_nlist_a[jj], expect_nlist_cpy[ii*sec_a[2]+jj]); + // printf("%2d ", fmt_nlist_a[jj]); + } + // printf("\n"); + } +} + + +TEST_F(TestFormatNlistShortSel, cpu_equal_orig) +{ + std::vector> nlist_a_0, nlist_r_0; + build_nlist(nlist_a_0, nlist_r_0, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + + std::vector fmt_nlist_a_1; + + for (int ii = 0; ii < nloc; ++ii){ + int ret_1 = format_nlist_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_0[ii], rc, sec_a); + EXPECT_EQ(ret_1, 1); + for (int jj = 0; jj < sec_a[2]; ++jj){ + EXPECT_EQ(fmt_nlist_a_1[jj], expect_nlist_cpy[ii*sec_a[2]+jj]); + } + } +} + diff --git a/source/op/descrpt_se_a.cc b/source/op/descrpt_se_a.cc index c0f49433ec..07305965e6 100644 --- a/source/op/descrpt_se_a.cc +++ b/source/op/descrpt_se_a.cc @@ -246,7 +246,7 @@ class DescrptSeAOp : public OpKernel { ::build_nlist (d_nlist_a, d_nlist_r, d_coord3, nloc, rcut_a, rcut_r, nat_stt, nat_end, ext_stt, ext_end, region, global_grid); } else if (nei_mode == 1) { - std::vector bk_d_coord3 = d_coord3; + std::vector bk_d_coord3 = d_coord3; std::vector bk_d_type = d_type; std::vector ncell, ngcell; copy_coord(d_coord3, d_type, nlist_map, ncell, ngcell, bk_d_coord3, bk_d_type, rcut_r, region); diff --git a/source/op/descrpt_se_r.cc b/source/op/descrpt_se_r.cc index fde5f5a078..495ad1a7db 100644 --- a/source/op/descrpt_se_r.cc +++ b/source/op/descrpt_se_r.cc @@ -6,6 +6,7 @@ #include "ComputeDescriptor.h" #include "NeighborList.h" #include "fmt_nlist.h" +#include "env_mat.h" typedef double boxtensor_t ; typedef double compute_t; @@ -229,7 +230,7 @@ class DescrptSeROp : public OpKernel { ::build_nlist (d_nlist_null, d_nlist, d_coord3, nloc, -1, rcut, nat_stt, nat_end, ext_stt, ext_end, region, global_grid); } else if (nei_mode == 1) { - std::vector bk_d_coord3 = d_coord3; + std::vector bk_d_coord3 = d_coord3; std::vector bk_d_type = d_type; std::vector ncell, ngcell; copy_coord(d_coord3, d_type, nlist_map, ncell, ngcell, bk_d_coord3, bk_d_type, rcut, region); From 1b9e96f395de527cea98eb31c9c5bb8e851bbc45 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 8 Feb 2021 18:20:34 +0800 Subject: [PATCH 109/562] refact the prod_force --- source/lib/include/prod_force.h | 13 ++++ source/lib/src/prod_force.cc | 79 ++++++++++++++++++++++ source/lib/tests/test_env_mat_a.cc | 20 ++++++ source/lib/tests/test_prod_force_a.cc | 96 +++++++++++++++++++++++++++ source/op/prod_force_se_a.cc | 56 +++------------- 5 files changed, 219 insertions(+), 45 deletions(-) create mode 100644 source/lib/include/prod_force.h create mode 100644 source/lib/src/prod_force.cc create mode 100644 source/lib/tests/test_prod_force_a.cc diff --git a/source/lib/include/prod_force.h b/source/lib/include/prod_force.h new file mode 100644 index 0000000000..597535dd7a --- /dev/null +++ b/source/lib/include/prod_force.h @@ -0,0 +1,13 @@ +#pragma once + +template +void prod_force_a_cpu( + FPTYPE * force, + const FPTYPE * net_deriv, + const FPTYPE * in_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei, + const int n_a_sel); + diff --git a/source/lib/src/prod_force.cc b/source/lib/src/prod_force.cc new file mode 100644 index 0000000000..33a14fd1a2 --- /dev/null +++ b/source/lib/src/prod_force.cc @@ -0,0 +1,79 @@ +#include +#include +#include "prod_force.h" + +inline void +make_descript_range (int & idx_start, + int & idx_end, + const int & nei_idx, + const int & n_a_sel) { + if (nei_idx < n_a_sel) { + idx_start = nei_idx * 4; + idx_end = nei_idx * 4 + 4; + } + else { + throw std::runtime_error("should no reach here"); + } +} + + +template +void prod_force_a_cpu( + FPTYPE * force, + const FPTYPE * net_deriv, + const FPTYPE * env_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei, + const int n_a_sel) +{ + const int ndescrpt = 4 * nnei; + + memset(force, 0.0, sizeof(FPTYPE) * nall * 3); + // compute force of a frame + for (int i_idx = 0; i_idx < nloc; ++i_idx) { + // deriv wrt center atom + for (int aa = 0; aa < ndescrpt; ++aa) { + force[i_idx * 3 + 0] -= net_deriv[i_idx * ndescrpt + aa] * env_deriv[i_idx * ndescrpt * 3 + aa * 3 + 0]; + force[i_idx * 3 + 1] -= net_deriv[i_idx * ndescrpt + aa] * env_deriv[i_idx * ndescrpt * 3 + aa * 3 + 1]; + force[i_idx * 3 + 2] -= net_deriv[i_idx * ndescrpt + aa] * env_deriv[i_idx * ndescrpt * 3 + aa * 3 + 2]; + } + // deriv wrt neighbors + for (int jj = 0; jj < nnei; ++jj) { + int j_idx = nlist[i_idx * nnei + jj]; + if (j_idx < 0) continue; + int aa_start, aa_end; + make_descript_range (aa_start, aa_end, jj, n_a_sel); + for (int aa = aa_start; aa < aa_end; ++aa) { + force[j_idx * 3 + 0] += net_deriv[i_idx * ndescrpt + aa] * env_deriv[i_idx * ndescrpt * 3 + aa * 3 + 0]; + force[j_idx * 3 + 1] += net_deriv[i_idx * ndescrpt + aa] * env_deriv[i_idx * ndescrpt * 3 + aa * 3 + 1]; + force[j_idx * 3 + 2] += net_deriv[i_idx * ndescrpt + aa] * env_deriv[i_idx * ndescrpt * 3 + aa * 3 + 2]; + } + } + } +} + + + +template +void prod_force_a_cpu( + double * force, + const double * net_deriv, + const double * env_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei, + const int n_a_sel); + +template +void prod_force_a_cpu( + float * force, + const float * net_deriv, + const float * env_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei, + const int n_a_sel); diff --git a/source/lib/tests/test_env_mat_a.cc b/source/lib/tests/test_env_mat_a.cc index 76f92f7c78..e261ee975b 100644 --- a/source/lib/tests/test_env_mat_a.cc +++ b/source/lib/tests/test_env_mat_a.cc @@ -123,6 +123,7 @@ TEST_F(TestEnvMatA, orig_cpy) env_mat_a(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]*4); EXPECT_EQ(env.size(), env_deriv.size()/3); + EXPECT_EQ(rij_a.size(), sec_a[2]*3); for (int jj = 0; jj < sec_a[2]; ++jj){ for (int dd = 0; dd < 4; ++dd){ EXPECT_LT(fabs(env[jj*4+dd] - expected_env[ii*sec_a[2]*4 + jj*4 + dd]) , 1e-5); @@ -144,6 +145,9 @@ TEST_F(TestEnvMatA, orig_pbc) int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi, ntypes, atype, region, pbc, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); EXPECT_EQ(ret, -1); env_mat_a(env, env_deriv, rij_a, posi, ntypes, atype, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + EXPECT_EQ(env.size(), sec_a[2]*4); + EXPECT_EQ(env.size(), env_deriv.size()/3); + EXPECT_EQ(rij_a.size(), sec_a[2]*3); for (int jj = 0; jj < sec_a[2]; ++jj){ for (int dd = 0; dd < 4; ++dd){ EXPECT_LT(fabs(env[jj*4+dd] - expected_env[ii*sec_a[2]*4 + jj*4 + dd]) , 1e-5); @@ -192,6 +196,9 @@ TEST_F(TestEnvMatA, orig_cpy_num_deriv) int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); env_mat_a(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + EXPECT_EQ(env.size(), sec_a[2]*4); + EXPECT_EQ(env.size(), env_deriv.size()/3); + EXPECT_EQ(rij_a.size(), sec_a[2]*3); for (int jj = 0; jj < sec_a[2]; ++jj){ int j_idx = fmt_nlist_a[jj]; @@ -227,6 +234,9 @@ TEST_F(TestEnvMatA, cpu) int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + EXPECT_EQ(env.size(), sec_a[2]*4); + EXPECT_EQ(env.size(), env_deriv.size()/3); + EXPECT_EQ(rij_a.size(), sec_a[2]*3); for (int jj = 0; jj < sec_a[2]; ++jj){ for (int dd = 0; dd < 4; ++dd){ EXPECT_LT(fabs(env[jj*4+dd] - expected_env[ii*sec_a[2]*4 + jj*4 + dd]) , 1e-5); @@ -276,6 +286,9 @@ TEST_F(TestEnvMatA, cpu_num_deriv) int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + EXPECT_EQ(env.size(), sec_a[2]*4); + EXPECT_EQ(env.size(), env_deriv.size()/3); + EXPECT_EQ(rij_a.size(), sec_a[2]*3); for (int jj = 0; jj < sec_a[2]; ++jj){ int j_idx = fmt_nlist_a[jj]; @@ -313,6 +326,7 @@ TEST_F(TestEnvMatAShortSel, orig_cpy) env_mat_a(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]*4); EXPECT_EQ(env.size(), env_deriv.size()/3); + EXPECT_EQ(rij_a.size(), sec_a[2]*3); for (int jj = 0; jj < sec_a[2]; ++jj){ for (int dd = 0; dd < 4; ++dd){ EXPECT_LT(fabs(env[jj*4+dd] - expected_env[ii*sec_a[2]*4 + jj*4 + dd]) , 1e-5); @@ -334,6 +348,9 @@ TEST_F(TestEnvMatAShortSel, orig_pbc) int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi, ntypes, atype, region, pbc, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); EXPECT_EQ(ret, 1); env_mat_a(env, env_deriv, rij_a, posi, ntypes, atype, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); + EXPECT_EQ(env.size(), sec_a[2]*4); + EXPECT_EQ(env.size(), env_deriv.size()/3); + EXPECT_EQ(rij_a.size(), sec_a[2]*3); for (int jj = 0; jj < sec_a[2]; ++jj){ for (int dd = 0; dd < 4; ++dd){ EXPECT_LT(fabs(env[jj*4+dd] - expected_env[ii*sec_a[2]*4 + jj*4 + dd]) , 1e-5); @@ -351,6 +368,9 @@ TEST_F(TestEnvMatAShortSel, cpu) int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, 1); env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + EXPECT_EQ(env.size(), sec_a[2]*4); + EXPECT_EQ(env.size(), env_deriv.size()/3); + EXPECT_EQ(rij_a.size(), sec_a[2]*3); for (int jj = 0; jj < sec_a[2]; ++jj){ for (int dd = 0; dd < 4; ++dd){ EXPECT_LT(fabs(env[jj*4+dd] - expected_env[ii*sec_a[2]*4 + jj*4 + dd]) , 1e-5); diff --git a/source/lib/tests/test_prod_force_a.cc b/source/lib/tests/test_prod_force_a.cc new file mode 100644 index 0000000000..7c840d338c --- /dev/null +++ b/source/lib/tests/test_prod_force_a.cc @@ -0,0 +1,96 @@ +#include +#include +#include "fmt_nlist.h" +#include "env_mat.h" +#include "NeighborList.h" +#include "prod_force.h" + +class TestProdForceA : public ::testing::Test +{ +protected: + std::vector posi = {12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall, nnei, ndescrpt; + double rc = 6; + double rc_smth = 0.8; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sec_a = {0, 5, 10}; + std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector> nlist_a_cpy, nlist_r_cpy; + std::vector net_deriv, in_deriv; + std::vector env, env_deriv, rij_a; + std::vector nlist; + std::vector fmt_nlist_a; + std::vector expected_force = { + 9.44498, -13.86254, 10.52884, -19.42688, 8.09273, 19.64478, 4.81771, 11.39255, 12.38830, -16.65832, 6.65153, -10.15585, 1.16660, -14.43259, 22.97076, 22.86479, 7.42726, -11.41943, -7.67893, -7.23287, -11.33442, -4.51184, -3.80588, -2.44935, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.16217, 6.16192, -28.79094, 3.81076, -0.01986, -1.01629, 3.65869, -0.49195, -0.07437, 1.35028, 0.11969, -0.29201, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + }; + + void SetUp() override { + double box[] = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + region.reinitBox(box); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nnei = sec_a.back(); + ndescrpt = nnei * 4; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + build_nlist(nlist_a_cpy, nlist_r_cpy, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + nlist.resize(nloc * nnei); + env.resize(nloc * ndescrpt); + env_deriv.resize(nloc * ndescrpt * 3); + rij_a.resize(nloc * nnei * 3); + for(int ii = 0; ii < nloc; ++ii){ + // format nlist and record + format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + for (int jj = 0; jj < nnei; ++jj){ + nlist[ii*nnei + jj] = fmt_nlist_a[jj]; + } + std::vector t_env, t_env_deriv, t_rij_a; + // compute env_mat and its deriv, record + env_mat_a_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < ndescrpt; ++jj){ + env[ii*ndescrpt+jj] = t_env[jj]; + for (int dd = 0; dd < 3; ++dd){ + env_deriv[ii*ndescrpt*3+jj*3+dd] = t_env_deriv[jj*3+dd]; + } + } + } + net_deriv.resize(nloc * ndescrpt); + for (int ii = 0; ii < nloc * ndescrpt; ++ii){ + net_deriv[ii] = 10 - ii * 0.01; + } + } + void TearDown() override { + } +}; + +TEST_F(TestProdForceA, cpu) +{ + std::vector force(nall * 3); + int n_a_sel = nnei; + prod_force_a_cpu (&force[0], &net_deriv[0], &env_deriv[0], &nlist[0], nloc, nall, nnei, n_a_sel); + for (int jj = 0; jj < nall * 3; ++jj){ + EXPECT_LT(fabs(force[jj] - expected_force[jj]) , 1e-5); + } + // for (int jj = 0; jj < nall * 3; ++jj){ + // printf("%8.5f, ", force[jj]); + // } + // printf("\n"); +} diff --git a/source/op/prod_force_se_a.cc b/source/op/prod_force_se_a.cc index 572b4be8b5..c9fe8aebc8 100644 --- a/source/op/prod_force_se_a.cc +++ b/source/op/prod_force_se_a.cc @@ -3,6 +3,8 @@ #include "tensorflow/core/framework/shape_inference.h" #include +#include "prod_force.h" + using namespace tensorflow; // using namespace std; @@ -28,7 +30,6 @@ class ProdForceSeAOp : public OpKernel { explicit ProdForceSeAOp(OpKernelConstruction* context) : OpKernel(context) { OP_REQUIRES_OK(context, context->GetAttr("n_a_sel", &n_a_sel)); OP_REQUIRES_OK(context, context->GetAttr("n_r_sel", &n_r_sel)); - n_a_shift = n_a_sel * 4; } void Compute(OpKernelContext* context) override { @@ -95,53 +96,18 @@ class ProdForceSeAOp : public OpKernel { int in_iter = kk * nloc * ndescrpt * 3; int nlist_iter = kk * nloc * nnei; - for (int ii = 0; ii < nall; ++ii){ - int i_idx = ii; - force (force_iter + i_idx * 3 + 0) = 0; - force (force_iter + i_idx * 3 + 1) = 0; - force (force_iter + i_idx * 3 + 2) = 0; - } - - // compute force of a frame - for (int ii = 0; ii < nloc; ++ii){ - int i_idx = ii; - // deriv wrt center atom - for (int aa = 0; aa < ndescrpt; ++aa){ - force (force_iter + i_idx * 3 + 0) -= net_deriv (net_iter + i_idx * ndescrpt + aa) * in_deriv (in_iter + i_idx * ndescrpt * 3 + aa * 3 + 0); - force (force_iter + i_idx * 3 + 1) -= net_deriv (net_iter + i_idx * ndescrpt + aa) * in_deriv (in_iter + i_idx * ndescrpt * 3 + aa * 3 + 1); - force (force_iter + i_idx * 3 + 2) -= net_deriv (net_iter + i_idx * ndescrpt + aa) * in_deriv (in_iter + i_idx * ndescrpt * 3 + aa * 3 + 2); - } - // deriv wrt neighbors - for (int jj = 0; jj < nnei; ++jj){ - int j_idx = nlist (nlist_iter + i_idx * nnei + jj); - // if (j_idx > nloc) j_idx = j_idx % nloc; - if (j_idx < 0) continue; - int aa_start, aa_end; - make_descript_range (aa_start, aa_end, jj); - for (int aa = aa_start; aa < aa_end; ++aa) { - force (force_iter + j_idx * 3 + 0) += net_deriv (net_iter + i_idx * ndescrpt + aa) * in_deriv (in_iter + i_idx * ndescrpt * 3 + aa * 3 + 0); - force (force_iter + j_idx * 3 + 1) += net_deriv (net_iter + i_idx * ndescrpt + aa) * in_deriv (in_iter + i_idx * ndescrpt * 3 + aa * 3 + 1); - force (force_iter + j_idx * 3 + 2) += net_deriv (net_iter + i_idx * ndescrpt + aa) * in_deriv (in_iter + i_idx * ndescrpt * 3 + aa * 3 + 2); - } - } - } + prod_force_a_cpu(&force(force_iter), + &net_deriv(net_iter), + &in_deriv(in_iter), + &nlist(nlist_iter), + nloc, + nall, + nnei, + n_a_sel); } } private: - int n_r_sel, n_a_sel, n_a_shift; - inline void - make_descript_range (int & idx_start, - int & idx_end, - const int & nei_idx) { - if (nei_idx < n_a_sel) { - idx_start = nei_idx * 4; - idx_end = nei_idx * 4 + 4; - } - else { - idx_start = n_a_shift + (nei_idx - n_a_sel); - idx_end = n_a_shift + (nei_idx - n_a_sel) + 1; - } - } + int n_r_sel, n_a_sel; }; // Register the CPU kernels. From 7dacd889e33f848bc523b3a0f97f360798248878 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Mon, 8 Feb 2021 21:03:02 +0800 Subject: [PATCH 110/562] move the table precision control into descriptor --- deepmd/descriptor/se_a.py | 6 +++--- deepmd/utils/tabulate.py | 6 +----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/deepmd/descriptor/se_a.py b/deepmd/descriptor/se_a.py index 09adba8dcc..9be99d3cd0 100644 --- a/deepmd/descriptor/se_a.py +++ b/deepmd/descriptor/se_a.py @@ -258,7 +258,7 @@ def enable_compression(self, self.compress = True self.model_file = model_file self.table_config = [table_extrapolate, table_stride_1, table_stride_2, check_frequency] - self.table = DeepTabulate(self.model_file, self.filter_np_precision, self.type_one_side) + self.table = DeepTabulate(self.model_file, self.type_one_side) self.lower, self.upper \ = self.table.build(min_nbor_dist, table_extrapolate, table_stride_1, table_stride_2) @@ -557,9 +557,9 @@ def _filter(self, else: net = 'filter_' + str(type_input) + '_net_' + str(type_i) if type_i == 0: - xyz_scatter_1 = op_module.tabulate_fusion(self.table.data[net], info, xyz_scatter, tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]), last_layer_size = outputs_size[-1]) + xyz_scatter_1 = op_module.tabulate_fusion(self.table.data[net].astype(self.filter_np_precision), info, xyz_scatter, tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]), last_layer_size = outputs_size[-1]) else: - xyz_scatter_1 += op_module.tabulate_fusion(self.table.data[net], info, xyz_scatter, tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]), last_layer_size = outputs_size[-1]) + xyz_scatter_1 += op_module.tabulate_fusion(self.table.data[net].astype(self.filter_np_precision), info, xyz_scatter, tf.reshape(inputs_i, [-1, shape_i[1]//4, 4]), last_layer_size = outputs_size[-1]) else: if (type_input, type_i) not in self.exclude_types: xyz_scatter = embedding_net(xyz_scatter, diff --git a/deepmd/utils/tabulate.py b/deepmd/utils/tabulate.py index c7e61a380b..fc0ba118fd 100644 --- a/deepmd/utils/tabulate.py +++ b/deepmd/utils/tabulate.py @@ -17,7 +17,6 @@ class DeepTabulate(): """ def __init__(self, model_file, - data_type, type_one_side = False) -> None: """ Constructor @@ -26,14 +25,11 @@ def __init__(self, ---------- model_file The frozen model - data_type - The precision of the tables. Supported options are {1} type_one_side Try to build N_types tables. Otherwise, building N_types^2 tables """ self.model_file = model_file - self.np_data_type = data_type self.type_one_side = type_one_side self.graph, self.graph_def = self._load_graph() @@ -123,7 +119,7 @@ def build(self, self.data[net][jj][kk * 6 + 3] = (1 / (2 * tt * tt * tt)) * (20 * hh - (8 * dd[jj + 1][kk] + 12 * dd[jj][kk]) * tt - (3 * d2[jj][kk] - d2[jj + 1][kk]) * tt * tt) self.data[net][jj][kk * 6 + 4] = (1 / (2 * tt * tt * tt * tt)) * (-30 * hh + (14 * dd[jj + 1][kk] + 16 * dd[jj][kk]) * tt + (3 * d2[jj][kk] - 2 * d2[jj + 1][kk]) * tt * tt) self.data[net][jj][kk * 6 + 5] = (1 / (2 * tt * tt * tt * tt * tt)) * (12 * hh - 6 * (dd[jj + 1][kk] + dd[jj][kk]) * tt + (d2[jj + 1][kk] - d2[jj][kk]) * tt * tt) - self.data[net].astype(self.np_data_type) + self.data[net] return lower, upper def _load_graph(self): From 478603b1095758571151e428bbe36dd02450e9a0 Mon Sep 17 00:00:00 2001 From: Denghui Lu Date: Tue, 9 Feb 2021 02:32:47 +0800 Subject: [PATCH 111/562] Update use-deepmd-kit.md --- doc/use-deepmd-kit.md | 56 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/doc/use-deepmd-kit.md b/doc/use-deepmd-kit.md index df942a4994..e4cfff5aa6 100644 --- a/doc/use-deepmd-kit.md +++ b/doc/use-deepmd-kit.md @@ -5,6 +5,7 @@ - [The DeepPot-SE model](#the-deeppot-se-model) - [Freeze a model](#freeze-a-model) - [Test a model](#test-a-model) + - [Compress a model](#compress-a-model) - [Model inference](#model-inference) - [Run MD with Lammps](#run-md-with-lammps) - [Include deepmd in the pair style](#include-deepmd-in-the-pair-style) @@ -19,7 +20,8 @@ In this text, we will call the deep neural network that is used to represent the 2. Train a model 3. Freeze the model 4. Test the model -5. Inference with the model +5. Compress the model +6. Inference with the model ## Prepare data One needs to provide the following information to train a model: the atom type, the simulation box, the atom coordinate, the atom force, system energy and virial. A snapshot of a system that contains these information is called a **frame**. We use the following convention of units: @@ -270,6 +272,58 @@ optional arguments: accuracy ``` +## Compress a model + +Once the frozen model is obtained from deepmd-kit, we can get the neural network structure and its parameters (weights, biases, etc.) from the trained model, and compress it in the following way: +```bash +dp compress input.json -i graph.pb -o graph-compress.pb +``` +where input.json denotes the original training input script, `-i` gives the original frozen model, `-o` gives the compressed model. Several other command line options can be passed to `dp compress`, which can be checked with +```bash +$ dp compress --help +``` +An explanation will be provided +``` +usage: dp compress [-h] [-i INPUT] [-o OUTPUT] [-e EXTRAPOLATE] [-s STRIDE] + [-f FREQUENCY] [-d FOLDER] + INPUT + +positional arguments: + INPUT The input parameter file in json or yaml format, which + should be consistent with the original model parameter + file + +optional arguments: + -h, --help show this help message and exit + -i INPUT, --input INPUT + The original frozen model, which will be compressed by + the deepmd-kit + -o OUTPUT, --output OUTPUT + The compressed model + -e EXTRAPOLATE, --extrapolate EXTRAPOLATE + The scale of model extrapolation + -s STRIDE, --stride STRIDE + The uniform stride of tabulation's first table, the + second table will use 10 * stride as it's uniform + stride + -f FREQUENCY, --frequency FREQUENCY + The frequency of tabulation overflow check(If the + input environment matrix overflow the first or second + table range). By default do not check the overflow + -d FOLDER, --folder FOLDER + path to checkpoint folder +``` +**Parameter explanation** + +Model compression, which including tabulating the embedding-net. +The table is composed of fifth-order polynomial coefficients and is assembled from two sub-tables. The first sub-table takes the stride(parameter) as it's uniform stride, while the second sub-table takes 10 * stride as it's uniform stride. +The range of the first table is automatically detected by deepmd-kit, while the second table ranges from the first table's upper boundary(upper) to the extrapolate(parameter) * upper. +Finally, we added a check frequency parameter. It indicates how often the program checks for overflow(if the input environment matrix overflow the first or second table range) during the MD inference. + +**Justification of model compression** + +Model compression, with little loss of accuracy, can greatly speed up MD inference time. According to different simulation systems and training parameters, the speedup can reach more than 10 times at both CPU and GPU devices. At the same time, model compression can greatly change the memory usage, reducing as much as 20 times under the same hardware conditions. + ## Model inference One may use the python interface of DeePMD-kit for model inference, an example is given as follows ```python From 675270dfb59aeb06ddc5cea8e93086cdeaf7ea1e Mon Sep 17 00:00:00 2001 From: Denghui Lu Date: Tue, 9 Feb 2021 02:36:25 +0800 Subject: [PATCH 112/562] add intros of model compression to the README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7f9b02b628..7d72de9bc9 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,8 @@ The typical procedure of using DeePMD-kit includes 5 steps 3. [Analyze training with Tensorboard](doc/tensorboard.md) 4. [Freeze the model](doc/use-deepmd-kit.md#freeze-a-model) 5. [Test the model](doc/use-deepmd-kit.md#test-a-model) -6. [Inference the model in python](doc/use-deepmd-kit.md#model-inference) or using the model in other molecular simulation packages like [LAMMPS](doc/use-deepmd-kit.md#run-md-with-lammps), [i-PI](doc/use-deepmd-kit.md#run-path-integral-md-with-i-pi) or [ASE](doc/use-deepmd-kit.md#use-deep-potential-with-ase). +6. [Compress the model](doc/use-deepmd-kit.md#compress-a-model) +7. [Inference the model in python](doc/use-deepmd-kit.md#model-inference) or using the model in other molecular simulation packages like [LAMMPS](doc/use-deepmd-kit.md#run-md-with-lammps), [i-PI](doc/use-deepmd-kit.md#run-path-integral-md-with-i-pi) or [ASE](doc/use-deepmd-kit.md#use-deep-potential-with-ase). A quick-start on using DeePMD-kit can be found [here](doc/use-deepmd-kit.md). From e5fa1a130faffca4b0c39e89d249ae4460a3e03f Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 9 Feb 2021 08:13:10 +0800 Subject: [PATCH 113/562] refact prod virial. improved interface of prod_force_a --- source/lib/include/CustomeOperation.h | 5 +- source/lib/include/prod_force.h | 3 +- source/lib/include/prod_virial.h | 14 ++++ source/lib/src/prod_force.cc | 23 +++--- source/lib/src/prod_virial.cc | 89 ++++++++++++++++++++ source/lib/tests/test_prod_force_a.cc | 2 +- source/lib/tests/test_prod_virial_a.cc | 109 +++++++++++++++++++++++++ source/op/prod_force_se_a.cc | 4 +- source/op/prod_virial_se_a.cc | 57 +++---------- 9 files changed, 242 insertions(+), 64 deletions(-) create mode 100644 source/lib/include/prod_virial.h create mode 100644 source/lib/src/prod_virial.cc create mode 100644 source/lib/tests/test_prod_virial_a.cc diff --git a/source/lib/include/CustomeOperation.h b/source/lib/include/CustomeOperation.h index 329ef7d355..023a2e8b95 100644 --- a/source/lib/include/CustomeOperation.h +++ b/source/lib/include/CustomeOperation.h @@ -5,6 +5,7 @@ #include #include "MathUtilities.h" #include "fmt_nlist.h" +#include "env_mat.h" #if GOOGLE_CUDA #include "DeviceFunctor.h" #endif // GOOGLE_CUDA @@ -69,7 +70,7 @@ void DescrptSeACPULauncher(const FPTYPE * coord, const int * type, const int * i std::vector d_descrpt_r; std::vector d_descrpt_r_deriv; std::vector d_rij_a; - compute_descriptor_se_a_cpu (d_descrpt_a, d_descrpt_a_deriv, d_rij_a, d_coord3, ntypes, d_type, ii, fmt_nlist_a, sec_a, rcut_r_smth, rcut_r); + env_mat_a_cpu (d_descrpt_a, d_descrpt_a_deriv, d_rij_a, d_coord3, ntypes, d_type, ii, fmt_nlist_a, sec_a, rcut_r_smth, rcut_r); // check sizes assert (d_descrpt_a.size() == ndescrpt); @@ -273,7 +274,7 @@ void DescrptSeRCPULauncher(const FPTYPE * coord, const int * type, const int * i std::vector d_descrpt_r; std::vector d_descrpt_r_deriv; std::vector d_rij_a; - compute_descriptor_se_r_cpu (d_descrpt_a, d_descrpt_a_deriv, d_rij_a, d_coord3, ntypes, d_type, ii, fmt_nlist_a, sec_a, rcut_r_smth, rcut_r); + env_mat_r_cpu (d_descrpt_a, d_descrpt_a_deriv, d_rij_a, d_coord3, ntypes, d_type, ii, fmt_nlist_a, sec_a, rcut_r_smth, rcut_r); // check sizes assert (d_descrpt_a.size() == ndescrpt); diff --git a/source/lib/include/prod_force.h b/source/lib/include/prod_force.h index 597535dd7a..f8f8a259a6 100644 --- a/source/lib/include/prod_force.h +++ b/source/lib/include/prod_force.h @@ -8,6 +8,5 @@ void prod_force_a_cpu( const int * nlist, const int nloc, const int nall, - const int nnei, - const int n_a_sel); + const int nnei); diff --git a/source/lib/include/prod_virial.h b/source/lib/include/prod_virial.h new file mode 100644 index 0000000000..0e06fa20eb --- /dev/null +++ b/source/lib/include/prod_virial.h @@ -0,0 +1,14 @@ +#pragma once + +template +void prod_virial_a_cpu( + FPTYPE * virial, + FPTYPE * atom_virial, + const FPTYPE * net_deriv, + const FPTYPE * env_deriv, + const FPTYPE * rij_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei); + diff --git a/source/lib/src/prod_force.cc b/source/lib/src/prod_force.cc index 33a14fd1a2..8403347d8c 100644 --- a/source/lib/src/prod_force.cc +++ b/source/lib/src/prod_force.cc @@ -3,11 +3,13 @@ #include "prod_force.h" inline void -make_descript_range (int & idx_start, - int & idx_end, - const int & nei_idx, - const int & n_a_sel) { - if (nei_idx < n_a_sel) { +make_index_range ( + int & idx_start, + int & idx_end, + const int & nei_idx, + const int & nnei) +{ + if (nei_idx < nnei) { idx_start = nei_idx * 4; idx_end = nei_idx * 4 + 4; } @@ -25,8 +27,7 @@ void prod_force_a_cpu( const int * nlist, const int nloc, const int nall, - const int nnei, - const int n_a_sel) + const int nnei) { const int ndescrpt = 4 * nnei; @@ -44,7 +45,7 @@ void prod_force_a_cpu( int j_idx = nlist[i_idx * nnei + jj]; if (j_idx < 0) continue; int aa_start, aa_end; - make_descript_range (aa_start, aa_end, jj, n_a_sel); + make_index_range (aa_start, aa_end, jj, nnei); for (int aa = aa_start; aa < aa_end; ++aa) { force[j_idx * 3 + 0] += net_deriv[i_idx * ndescrpt + aa] * env_deriv[i_idx * ndescrpt * 3 + aa * 3 + 0]; force[j_idx * 3 + 1] += net_deriv[i_idx * ndescrpt + aa] * env_deriv[i_idx * ndescrpt * 3 + aa * 3 + 1]; @@ -64,8 +65,7 @@ void prod_force_a_cpu( const int * nlist, const int nloc, const int nall, - const int nnei, - const int n_a_sel); + const int nnei); template void prod_force_a_cpu( @@ -75,5 +75,4 @@ void prod_force_a_cpu( const int * nlist, const int nloc, const int nall, - const int nnei, - const int n_a_sel); + const int nnei); diff --git a/source/lib/src/prod_virial.cc b/source/lib/src/prod_virial.cc new file mode 100644 index 0000000000..95a66f06d2 --- /dev/null +++ b/source/lib/src/prod_virial.cc @@ -0,0 +1,89 @@ +#include +#include +#include "prod_virial.h" + +inline void +make_index_range ( + int & idx_start, + int & idx_end, + const int & nei_idx, + const int & nnei) +{ + if (nei_idx < nnei) { + idx_start = nei_idx * 4; + idx_end = nei_idx * 4 + 4; + } + else { + throw std::runtime_error("should no reach here"); + } +} + +template +void prod_virial_a_cpu( + FPTYPE * virial, + FPTYPE * atom_virial, + const FPTYPE * net_deriv, + const FPTYPE * env_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nall, + const int nnei) +{ + const int ndescrpt = 4 * nnei; + + for (int ii = 0; ii < 9; ++ ii){ + virial[ii] = 0.; + } + for (int ii = 0; ii < 9 * nall; ++ ii){ + atom_virial[ii] = 0.; + } + + // compute virial of a frame + for (int ii = 0; ii < nloc; ++ii){ + int i_idx = ii; + + // deriv wrt neighbors + for (int jj = 0; jj < nnei; ++jj){ + int j_idx = nlist[i_idx * nnei + jj]; + if (j_idx < 0) continue; + int aa_start, aa_end; + make_index_range (aa_start, aa_end, jj, nnei); + for (int aa = aa_start; aa < aa_end; ++aa) { + FPTYPE pref = -1.0 * net_deriv[i_idx * ndescrpt + aa]; + for (int dd0 = 0; dd0 < 3; ++dd0){ + for (int dd1 = 0; dd1 < 3; ++dd1){ + FPTYPE tmp_v = pref * rij[i_idx * nnei * 3 + jj * 3 + dd1] * env_deriv[i_idx * ndescrpt * 3 + aa * 3 + dd0]; + virial[dd0 * 3 + dd1] -= tmp_v; + atom_virial[j_idx * 9 + dd0 * 3 + dd1] -= tmp_v; + } + } + } + } + } +} + +template +void prod_virial_a_cpu( + double * virial, + double * atom_virial, + const double * net_deriv, + const double * env_deriv, + const double * rij, + const int * nlist, + const int nloc, + const int nall, + const int nnei) ; + +template +void prod_virial_a_cpu( + float * virial, + float * atom_virial, + const float * net_deriv, + const float * env_deriv, + const float * rij, + const int * nlist, + const int nloc, + const int nall, + const int nnei) ; + diff --git a/source/lib/tests/test_prod_force_a.cc b/source/lib/tests/test_prod_force_a.cc index 7c840d338c..379b332487 100644 --- a/source/lib/tests/test_prod_force_a.cc +++ b/source/lib/tests/test_prod_force_a.cc @@ -85,7 +85,7 @@ TEST_F(TestProdForceA, cpu) { std::vector force(nall * 3); int n_a_sel = nnei; - prod_force_a_cpu (&force[0], &net_deriv[0], &env_deriv[0], &nlist[0], nloc, nall, nnei, n_a_sel); + prod_force_a_cpu (&force[0], &net_deriv[0], &env_deriv[0], &nlist[0], nloc, nall, nnei); for (int jj = 0; jj < nall * 3; ++jj){ EXPECT_LT(fabs(force[jj] - expected_force[jj]) , 1e-5); } diff --git a/source/lib/tests/test_prod_virial_a.cc b/source/lib/tests/test_prod_virial_a.cc new file mode 100644 index 0000000000..3301bda7ac --- /dev/null +++ b/source/lib/tests/test_prod_virial_a.cc @@ -0,0 +1,109 @@ +#include +#include +#include "fmt_nlist.h" +#include "env_mat.h" +#include "NeighborList.h" +#include "prod_virial.h" + +class TestProdVirialA : public ::testing::Test +{ +protected: + std::vector posi = {12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall, nnei, ndescrpt; + double rc = 6; + double rc_smth = 0.8; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sec_a = {0, 5, 10}; + std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector> nlist_a_cpy, nlist_r_cpy; + std::vector net_deriv, in_deriv; + std::vector env, env_deriv, rij; + std::vector nlist; + std::vector fmt_nlist_a; + std::vector expected_virial = { + 100.14628, 7.21146, -24.62874, 6.19651, 23.31547, -19.77773, -26.79150, -20.92554, 38.84203, + }; + std::vector expected_atom_virial = { + -3.24191, 1.35810, 2.45333, -9.14879, 3.83260, 6.92341, -10.54930, 4.41930, 7.98326, 14.83563, -6.21493, -11.22697, 4.51124, -1.88984, -3.41391, 2.04717, -0.85760, -1.54921, 0.84708, -0.10308, 0.07324, 3.51825, -0.49788, 0.40314, 2.91345, -0.37264, 0.27386, 12.62246, -5.19874, 7.42677, 4.80217, -2.69029, 5.41896, 9.55811, -2.42899, 5.14893, 9.90295, 4.54279, -7.75115, -2.89155, 13.50055, -20.91993, 4.00314, -1.76293, 2.92724, 20.15105, 2.86856, -3.55868, -4.22796, -1.12700, 1.46999, -21.43180, -9.30194, 12.54538, 2.86811, 5.92934, -3.94618, 4.83313, 5.21197, -3.36488, 6.67852, 8.34225, -5.44992, 5.97941, 1.92669, -4.70211, 4.91215, 1.63145, -3.96250, 3.27415, 1.02612, -2.52585, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.38833, 0.50613, -1.26233, 1.39901, 5.18116, -2.18118, -17.72748, -19.52039, 18.66001, 14.31034, 1.31715, -2.05955, -0.10872, 0.00743, 0.03656, -3.85572, -0.33481, 0.57900, 14.31190, -0.53814, 0.89498, -1.94166, 0.07960, -0.10726, -0.35985, 0.03981, 0.03397, 6.17091, 0.81760, -0.97011, 0.53923, 0.07572, -0.08012, -1.34189, -0.17373, 0.21536, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + }; + + void SetUp() override { + double box[] = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + region.reinitBox(box); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nnei = sec_a.back(); + ndescrpt = nnei * 4; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + build_nlist(nlist_a_cpy, nlist_r_cpy, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + nlist.resize(nloc * nnei); + env.resize(nloc * ndescrpt); + env_deriv.resize(nloc * ndescrpt * 3); + rij.resize(nloc * nnei * 3); + for(int ii = 0; ii < nloc; ++ii){ + // format nlist and record + format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + for (int jj = 0; jj < nnei; ++jj){ + nlist[ii*nnei + jj] = fmt_nlist_a[jj]; + } + std::vector t_env, t_env_deriv, t_rij; + // compute env_mat and its deriv, record + env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < ndescrpt; ++jj){ + env[ii*ndescrpt+jj] = t_env[jj]; + for (int dd = 0; dd < 3; ++dd){ + env_deriv[ii*ndescrpt*3+jj*3+dd] = t_env_deriv[jj*3+dd]; + } + } + for (int jj = 0; jj < nnei * 3; ++jj){ + rij[ii*nnei*3 + jj] = t_rij[jj]; + } + } + net_deriv.resize(nloc * ndescrpt); + for (int ii = 0; ii < nloc * ndescrpt; ++ii){ + net_deriv[ii] = 10 - ii * 0.01; + } + } + void TearDown() override { + } +}; + +TEST_F(TestProdVirialA, cpu) +{ + std::vector virial(9); + std::vector atom_virial(nall * 9); + int n_a_sel = nnei; + prod_virial_a_cpu (&virial[0], &atom_virial[0], &net_deriv[0], &env_deriv[0], &rij[0], &nlist[0], nloc, nall, nnei); + for (int jj = 0; jj < 9; ++jj){ + EXPECT_LT(fabs(virial[jj] - expected_virial[jj]) , 1e-5); + } + for (int jj = 0; jj < nall * 9; ++jj){ + EXPECT_LT(fabs(atom_virial[jj] - expected_atom_virial[jj]) , 1e-5); + } + // for (int jj = 0; jj < 9; ++jj){ + // printf("%8.5f, ", virial[jj]); + // } + // for (int jj = 0; jj < nall * 9; ++jj){ + // printf("%8.5f, ", atom_virial[jj]); + // } + // printf("\n"); +} diff --git a/source/op/prod_force_se_a.cc b/source/op/prod_force_se_a.cc index c9fe8aebc8..209253e98c 100644 --- a/source/op/prod_force_se_a.cc +++ b/source/op/prod_force_se_a.cc @@ -30,6 +30,7 @@ class ProdForceSeAOp : public OpKernel { explicit ProdForceSeAOp(OpKernelConstruction* context) : OpKernel(context) { OP_REQUIRES_OK(context, context->GetAttr("n_a_sel", &n_a_sel)); OP_REQUIRES_OK(context, context->GetAttr("n_r_sel", &n_r_sel)); + // n_a_shift = n_a_sel * 4; } void Compute(OpKernelContext* context) override { @@ -102,8 +103,7 @@ class ProdForceSeAOp : public OpKernel { &nlist(nlist_iter), nloc, nall, - nnei, - n_a_sel); + nnei); } } private: diff --git a/source/op/prod_virial_se_a.cc b/source/op/prod_virial_se_a.cc index 7a0ffbd20d..f55ba49510 100644 --- a/source/op/prod_virial_se_a.cc +++ b/source/op/prod_virial_se_a.cc @@ -2,6 +2,7 @@ #include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/framework/shape_inference.h" #include +#include "prod_virial.h" using namespace tensorflow; // using namespace std; @@ -30,7 +31,7 @@ class ProdVirialSeAOp : public OpKernel { explicit ProdVirialSeAOp(OpKernelConstruction* context) : OpKernel(context) { OP_REQUIRES_OK(context, context->GetAttr("n_a_sel", &n_a_sel)); OP_REQUIRES_OK(context, context->GetAttr("n_r_sel", &n_r_sel)); - n_a_shift = n_a_sel * 4; + // n_a_shift = n_a_sel * 4; } void Compute(OpKernelContext* context) override { @@ -94,56 +95,22 @@ class ProdVirialSeAOp : public OpKernel { int in_iter = kk * nloc * ndescrpt * 3; int rij_iter = kk * nloc * nnei * 3; int nlist_iter = kk * nloc * nnei; - int axis_iter = kk * nloc * 4; int virial_iter = kk * 9; int atom_virial_iter = kk * nall * 9; - for (int ii = 0; ii < 9; ++ ii){ - virial (virial_iter + ii) = 0.; - } - for (int ii = 0; ii < 9 * nall; ++ ii){ - atom_virial (atom_virial_iter + ii) = 0.; - } - - // compute virial of a frame - for (int ii = 0; ii < nloc; ++ii){ - int i_idx = ii; - - // deriv wrt neighbors - for (int jj = 0; jj < nnei; ++jj){ - int j_idx = nlist (nlist_iter + i_idx * nnei + jj); - if (j_idx < 0) continue; - int aa_start, aa_end; - make_descript_range (aa_start, aa_end, jj); - for (int aa = aa_start; aa < aa_end; ++aa) { - FPTYPE pref = -1.0 * net_deriv (net_iter + i_idx * ndescrpt + aa); - for (int dd0 = 0; dd0 < 3; ++dd0){ - for (int dd1 = 0; dd1 < 3; ++dd1){ - FPTYPE tmp_v = pref * rij (rij_iter + i_idx * nnei * 3 + jj * 3 + dd1) * in_deriv (in_iter + i_idx * ndescrpt * 3 + aa * 3 + dd0); - virial (virial_iter + dd0 * 3 + dd1) -= tmp_v; - atom_virial (atom_virial_iter + j_idx * 9 + dd0 * 3 + dd1) -= tmp_v; - } - } - } - } - } + prod_virial_a_cpu(&virial(virial_iter), + &atom_virial(atom_virial_iter), + &net_deriv(net_iter), + &in_deriv(in_iter), + &rij(rij_iter), + &nlist(nlist_iter), + nloc, + nall, + nnei); } } private: - int n_r_sel, n_a_sel, n_a_shift; - inline void - make_descript_range (int & idx_start, - int & idx_end, - const int & nei_idx) { - if (nei_idx < n_a_sel) { - idx_start = nei_idx * 4; - idx_end = nei_idx * 4 + 4; - } - else { - idx_start = n_a_shift + (nei_idx - n_a_sel); - idx_end = n_a_shift + (nei_idx - n_a_sel) + 1; - } - } + int n_r_sel, n_a_sel; }; // Register the CPU kernels. From 263a52293c27bd1a3c8cb251a6b48280b472dbb6 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 9 Feb 2021 15:37:29 +0800 Subject: [PATCH 114/562] refact prod_force_r and prod_virial_r. add unittests --- source/lib/include/prod_force.h | 10 +++ source/lib/include/prod_virial.h | 12 +++ source/lib/src/prod_force.cc | 63 +++++++++++++- source/lib/src/prod_virial.cc | 66 +++++++++++++++ source/lib/tests/test_prod_force_a.cc | 1 + source/lib/tests/test_prod_force_r.cc | 97 +++++++++++++++++++++ source/lib/tests/test_prod_virial_a.cc | 2 + source/lib/tests/test_prod_virial_r.cc | 111 +++++++++++++++++++++++++ source/op/prod_force_se_r.cc | 35 ++------ source/op/prod_virial_se_r.cc | 37 +++------ 10 files changed, 381 insertions(+), 53 deletions(-) create mode 100644 source/lib/tests/test_prod_force_r.cc create mode 100644 source/lib/tests/test_prod_virial_r.cc diff --git a/source/lib/include/prod_force.h b/source/lib/include/prod_force.h index f8f8a259a6..89d9cc4117 100644 --- a/source/lib/include/prod_force.h +++ b/source/lib/include/prod_force.h @@ -10,3 +10,13 @@ void prod_force_a_cpu( const int nall, const int nnei); +template +void prod_force_r_cpu( + FPTYPE * force, + const FPTYPE * net_deriv, + const FPTYPE * in_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei); + diff --git a/source/lib/include/prod_virial.h b/source/lib/include/prod_virial.h index 0e06fa20eb..aeb061eca1 100644 --- a/source/lib/include/prod_virial.h +++ b/source/lib/include/prod_virial.h @@ -12,3 +12,15 @@ void prod_virial_a_cpu( const int nall, const int nnei); +template +void prod_virial_r_cpu( + FPTYPE * virial, + FPTYPE * atom_virial, + const FPTYPE * net_deriv, + const FPTYPE * env_deriv, + const FPTYPE * rij_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei); + diff --git a/source/lib/src/prod_force.cc b/source/lib/src/prod_force.cc index 8403347d8c..16d153f9e1 100644 --- a/source/lib/src/prod_force.cc +++ b/source/lib/src/prod_force.cc @@ -55,8 +55,6 @@ void prod_force_a_cpu( } } - - template void prod_force_a_cpu( double * force, @@ -76,3 +74,64 @@ void prod_force_a_cpu( const int nloc, const int nall, const int nnei); + + +template +void prod_force_r_cpu( + FPTYPE * force, + const FPTYPE * net_deriv, + const FPTYPE * env_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei) +{ + const int ndescrpt = 1 * nnei; + + for (int ii = 0; ii < nall; ++ii){ + int i_idx = ii; + force[i_idx * 3 + 0] = 0; + force[i_idx * 3 + 1] = 0; + force[i_idx * 3 + 2] = 0; + } + + // compute force of a frame + for (int ii = 0; ii < nloc; ++ii){ + int i_idx = ii; + // deriv wrt center atom + for (int aa = 0; aa < ndescrpt; ++aa){ + force[i_idx * 3 + 0] -= net_deriv[i_idx * ndescrpt + aa] * env_deriv[i_idx * ndescrpt * 3 + aa * 3 + 0]; + force[i_idx * 3 + 1] -= net_deriv[i_idx * ndescrpt + aa] * env_deriv[i_idx * ndescrpt * 3 + aa * 3 + 1]; + force[i_idx * 3 + 2] -= net_deriv[i_idx * ndescrpt + aa] * env_deriv[i_idx * ndescrpt * 3 + aa * 3 + 2]; + } + // deriv wrt neighbors + for (int jj = 0; jj < nnei; ++jj){ + int j_idx = nlist[i_idx * nnei + jj]; + // if (j_idx > nloc) j_idx = j_idx % nloc; + if (j_idx < 0) continue; + force[j_idx * 3 + 0] += net_deriv[i_idx * ndescrpt + jj] * env_deriv[i_idx * ndescrpt * 3 + jj * 3 + 0]; + force[j_idx * 3 + 1] += net_deriv[i_idx * ndescrpt + jj] * env_deriv[i_idx * ndescrpt * 3 + jj * 3 + 1]; + force[j_idx * 3 + 2] += net_deriv[i_idx * ndescrpt + jj] * env_deriv[i_idx * ndescrpt * 3 + jj * 3 + 2]; + } + } +} + +template +void prod_force_r_cpu( + double * force, + const double * net_deriv, + const double * env_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei); + +template +void prod_force_r_cpu( + float * force, + const float * net_deriv, + const float * env_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei); diff --git a/source/lib/src/prod_virial.cc b/source/lib/src/prod_virial.cc index 95a66f06d2..feaf39e357 100644 --- a/source/lib/src/prod_virial.cc +++ b/source/lib/src/prod_virial.cc @@ -1,3 +1,4 @@ +#include #include #include #include "prod_virial.h" @@ -87,3 +88,68 @@ void prod_virial_a_cpu( const int nall, const int nnei) ; + +template +void prod_virial_r_cpu( + FPTYPE * virial, + FPTYPE * atom_virial, + const FPTYPE * net_deriv, + const FPTYPE * env_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nall, + const int nnei) +{ + const int ndescrpt = nnei; + + for (int ii = 0; ii < 9; ++ ii){ + virial[ii] = 0.; + } + for (int ii = 0; ii < 9 * nall; ++ ii){ + atom_virial[ii] = 0.; + } + + // compute virial of a frame + for (int ii = 0; ii < nloc; ++ii){ + int i_idx = ii; + + // deriv wrt neighbors + for (int jj = 0; jj < nnei; ++jj){ + int j_idx = nlist[i_idx * nnei + jj]; + if (j_idx < 0) continue; + FPTYPE pref = -1.0 * net_deriv[i_idx * ndescrpt + jj]; + for (int dd0 = 0; dd0 < 3; ++dd0){ + for (int dd1 = 0; dd1 < 3; ++dd1){ + FPTYPE tmp_v = pref * rij[i_idx * nnei * 3 + jj * 3 + dd1] * env_deriv[i_idx * ndescrpt * 3 + jj * 3 + dd0]; + virial[dd0 * 3 + dd1] -= tmp_v; + atom_virial[j_idx * 9 + dd0 * 3 + dd1] -= tmp_v; + } + } + } + } +} + +template +void prod_virial_r_cpu( + double * virial, + double * atom_virial, + const double * net_deriv, + const double * env_deriv, + const double * rij, + const int * nlist, + const int nloc, + const int nall, + const int nnei) ; + +template +void prod_virial_r_cpu( + float * virial, + float * atom_virial, + const float * net_deriv, + const float * env_deriv, + const float * rij, + const int * nlist, + const int nloc, + const int nall, + const int nnei) ; diff --git a/source/lib/tests/test_prod_force_a.cc b/source/lib/tests/test_prod_force_a.cc index 379b332487..20e4bbe42e 100644 --- a/source/lib/tests/test_prod_force_a.cc +++ b/source/lib/tests/test_prod_force_a.cc @@ -86,6 +86,7 @@ TEST_F(TestProdForceA, cpu) std::vector force(nall * 3); int n_a_sel = nnei; prod_force_a_cpu (&force[0], &net_deriv[0], &env_deriv[0], &nlist[0], nloc, nall, nnei); + EXPECT_EQ(force.size(), nall * 3); for (int jj = 0; jj < nall * 3; ++jj){ EXPECT_LT(fabs(force[jj] - expected_force[jj]) , 1e-5); } diff --git a/source/lib/tests/test_prod_force_r.cc b/source/lib/tests/test_prod_force_r.cc new file mode 100644 index 0000000000..a313e07c3d --- /dev/null +++ b/source/lib/tests/test_prod_force_r.cc @@ -0,0 +1,97 @@ +#include +#include +#include "fmt_nlist.h" +#include "env_mat.h" +#include "NeighborList.h" +#include "prod_force.h" + +class TestProdForceR : public ::testing::Test +{ +protected: + std::vector posi = {12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall, nnei, ndescrpt; + double rc = 6; + double rc_smth = 0.8; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sec_a = {0, 5, 10}; + std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector> nlist_a_cpy, nlist_r_cpy; + std::vector net_deriv, in_deriv; + std::vector env, env_deriv, rij_a; + std::vector nlist; + std::vector fmt_nlist_a; + std::vector expected_force = { + 8.47974, -14.40744, -6.87937, -20.21879, 5.47417, 14.86084, -0.70576, 9.63198, -8.41144, -17.41399, 6.52118, -13.13187, 2.88846, -16.66137, 25.88393, 26.73044, 9.31580, -12.21548, -7.12901, -7.68483, 4.98461, -4.37014, -1.12277, 2.89025, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 7.16157, 8.72191, -7.70101, 2.00363, 0.18561, -0.28694, 1.86052, -0.06905, 0.11829, 0.71335, 0.09481, -0.11182, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + }; + + void SetUp() override { + double box[] = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + region.reinitBox(box); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nnei = sec_a.back(); + ndescrpt = nnei * 1; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + build_nlist(nlist_a_cpy, nlist_r_cpy, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + nlist.resize(nloc * nnei); + env.resize(nloc * ndescrpt); + env_deriv.resize(nloc * ndescrpt * 3); + rij_a.resize(nloc * nnei * 3); + for(int ii = 0; ii < nloc; ++ii){ + // format nlist and record + format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + for (int jj = 0; jj < nnei; ++jj){ + nlist[ii*nnei + jj] = fmt_nlist_a[jj]; + } + std::vector t_env, t_env_deriv, t_rij_a; + // compute env_mat and its deriv, record + env_mat_r_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < ndescrpt; ++jj){ + env[ii*ndescrpt+jj] = t_env[jj]; + for (int dd = 0; dd < 3; ++dd){ + env_deriv[ii*ndescrpt*3+jj*3+dd] = t_env_deriv[jj*3+dd]; + } + } + } + net_deriv.resize(nloc * ndescrpt); + for (int ii = 0; ii < nloc * ndescrpt; ++ii){ + net_deriv[ii] = 10 - ii * 0.01; + } + } + void TearDown() override { + } +}; + +TEST_F(TestProdForceR, cpu) +{ + std::vector force(nall * 3); + int n_a_sel = nnei; + prod_force_r_cpu (&force[0], &net_deriv[0], &env_deriv[0], &nlist[0], nloc, nall, nnei); + EXPECT_EQ(force.size(), nall * 3); + for (int jj = 0; jj < nall * 3; ++jj){ + EXPECT_LT(fabs(force[jj] - expected_force[jj]) , 1e-5); + } + // for (int jj = 0; jj < nall * 3; ++jj){ + // printf("%8.5f, ", force[jj]); + // } + // printf("\n"); +} diff --git a/source/lib/tests/test_prod_virial_a.cc b/source/lib/tests/test_prod_virial_a.cc index 3301bda7ac..e17ec73ef7 100644 --- a/source/lib/tests/test_prod_virial_a.cc +++ b/source/lib/tests/test_prod_virial_a.cc @@ -93,6 +93,8 @@ TEST_F(TestProdVirialA, cpu) std::vector atom_virial(nall * 9); int n_a_sel = nnei; prod_virial_a_cpu (&virial[0], &atom_virial[0], &net_deriv[0], &env_deriv[0], &rij[0], &nlist[0], nloc, nall, nnei); + EXPECT_EQ(virial.size(), 9); + EXPECT_EQ(atom_virial.size(), nall * 9); for (int jj = 0; jj < 9; ++jj){ EXPECT_LT(fabs(virial[jj] - expected_virial[jj]) , 1e-5); } diff --git a/source/lib/tests/test_prod_virial_r.cc b/source/lib/tests/test_prod_virial_r.cc new file mode 100644 index 0000000000..4a83fd338c --- /dev/null +++ b/source/lib/tests/test_prod_virial_r.cc @@ -0,0 +1,111 @@ +#include +#include +#include "fmt_nlist.h" +#include "env_mat.h" +#include "NeighborList.h" +#include "prod_virial.h" + +class TestProdVirialR : public ::testing::Test +{ +protected: + std::vector posi = {12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall, nnei, ndescrpt; + double rc = 6; + double rc_smth = 0.8; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sec_a = {0, 5, 10}; + std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector> nlist_a_cpy, nlist_r_cpy; + std::vector net_deriv, in_deriv; + std::vector env, env_deriv, rij; + std::vector nlist; + std::vector fmt_nlist_a; + std::vector expected_virial = { + 105.83531, 8.37873, -26.31645, 8.37873, 25.29640, -22.08303, -26.31645, -22.08303, 41.52565, + }; + std::vector expected_atom_virial = { + 5.82162, -2.43879, -4.40555, -2.43879, 1.02165, 1.84557, -4.40555, 1.84557, 3.33393, 5.85102, -2.45110, -4.42780, -2.45110, 1.02681, 1.85489, -4.42780, 1.85489, 3.35077, 12.99134, -1.65136, 1.27337, -1.65136, 0.31236, -0.30952, 1.27337, -0.30952, 0.34172, 14.20717, 0.71207, -0.80046, 0.71207, 3.33417, -5.06665, -0.80046, -5.06665, 7.86673, 6.35288, -0.15554, 0.00838, -0.15554, 4.67701, -7.17573, 0.00838, -7.17573, 11.07561, 14.50559, 3.80226, -5.12103, 3.80226, 2.16638, -2.99774, -5.12103, -2.99774, 4.20621, 13.02204, 4.00163, -2.38372, 4.00163, 5.79404, -3.84611, -2.38372, -3.84611, 2.60729, 9.69976, 1.23534, -3.98748, 1.23534, 0.53911, -1.23540, -3.98748, -1.23540, 3.03034, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 5.21346, 4.51882, -5.24989, 4.51882, 6.27021, -5.00845, -5.24989, -5.00845, 5.37572, 7.57664, 0.67053, -1.12262, 0.67053, 0.07524, -0.08028, -1.12262, -0.08028, 0.18921, 7.32402, -0.29298, 0.42021, -0.29298, 0.01974, 0.00042, 0.42021, 0.00042, 0.06112, 3.26976, 0.42787, -0.51985, 0.42787, 0.05967, -0.06402, -0.51985, -0.06402, 0.08700, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + }; + + void SetUp() override { + double box[] = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + region.reinitBox(box); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nnei = sec_a.back(); + ndescrpt = nnei * 1; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + build_nlist(nlist_a_cpy, nlist_r_cpy, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + nlist.resize(nloc * nnei); + env.resize(nloc * ndescrpt); + env_deriv.resize(nloc * ndescrpt * 3); + rij.resize(nloc * nnei * 3); + for(int ii = 0; ii < nloc; ++ii){ + // format nlist and record + format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + for (int jj = 0; jj < nnei; ++jj){ + nlist[ii*nnei + jj] = fmt_nlist_a[jj]; + } + std::vector t_env, t_env_deriv, t_rij; + // compute env_mat and its deriv, record + env_mat_r_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < ndescrpt; ++jj){ + env[ii*ndescrpt+jj] = t_env[jj]; + for (int dd = 0; dd < 3; ++dd){ + env_deriv[ii*ndescrpt*3+jj*3+dd] = t_env_deriv[jj*3+dd]; + } + } + for (int jj = 0; jj < nnei * 3; ++jj){ + rij[ii*nnei*3 + jj] = t_rij[jj]; + } + } + net_deriv.resize(nloc * ndescrpt); + for (int ii = 0; ii < nloc * ndescrpt; ++ii){ + net_deriv[ii] = 10 - ii * 0.01; + } + } + void TearDown() override { + } +}; + +TEST_F(TestProdVirialR, cpu) +{ + std::vector virial(9); + std::vector atom_virial(nall * 9); + int n_a_sel = nnei; + prod_virial_r_cpu (&virial[0], &atom_virial[0], &net_deriv[0], &env_deriv[0], &rij[0], &nlist[0], nloc, nall, nnei); + EXPECT_EQ(virial.size(), 9); + EXPECT_EQ(atom_virial.size(), nall * 9); + for (int jj = 0; jj < 9; ++jj){ + EXPECT_LT(fabs(virial[jj] - expected_virial[jj]) , 1e-5); + } + for (int jj = 0; jj < nall * 9; ++jj){ + EXPECT_LT(fabs(atom_virial[jj] - expected_atom_virial[jj]) , 1e-5); + } + // for (int jj = 0; jj < 9; ++jj){ + // printf("%8.5f, ", virial[jj]); + // } + // for (int jj = 0; jj < nall * 9; ++jj){ + // printf("%8.5f, ", atom_virial[jj]); + // } + // printf("\n"); +} diff --git a/source/op/prod_force_se_r.cc b/source/op/prod_force_se_r.cc index 34b12f104c..7620bff7e0 100644 --- a/source/op/prod_force_se_r.cc +++ b/source/op/prod_force_se_r.cc @@ -3,6 +3,8 @@ #include "tensorflow/core/framework/shape_inference.h" #include +#include "prod_force.h" + using namespace tensorflow; // using namespace std; @@ -86,32 +88,13 @@ class ProdForceSeROp : public OpKernel { int in_iter = kk * nloc * ndescrpt * 3; int nlist_iter = kk * nloc * nnei; - for (int ii = 0; ii < nall; ++ii){ - int i_idx = ii; - force (force_iter + i_idx * 3 + 0) = 0; - force (force_iter + i_idx * 3 + 1) = 0; - force (force_iter + i_idx * 3 + 2) = 0; - } - - // compute force of a frame - for (int ii = 0; ii < nloc; ++ii){ - int i_idx = ii; - // deriv wrt center atom - for (int aa = 0; aa < ndescrpt; ++aa){ - force (force_iter + i_idx * 3 + 0) -= net_deriv (net_iter + i_idx * ndescrpt + aa) * in_deriv (in_iter + i_idx * ndescrpt * 3 + aa * 3 + 0); - force (force_iter + i_idx * 3 + 1) -= net_deriv (net_iter + i_idx * ndescrpt + aa) * in_deriv (in_iter + i_idx * ndescrpt * 3 + aa * 3 + 1); - force (force_iter + i_idx * 3 + 2) -= net_deriv (net_iter + i_idx * ndescrpt + aa) * in_deriv (in_iter + i_idx * ndescrpt * 3 + aa * 3 + 2); - } - // deriv wrt neighbors - for (int jj = 0; jj < nnei; ++jj){ - int j_idx = nlist (nlist_iter + i_idx * nnei + jj); - // if (j_idx > nloc) j_idx = j_idx % nloc; - if (j_idx < 0) continue; - force (force_iter + j_idx * 3 + 0) += net_deriv (net_iter + i_idx * ndescrpt + jj) * in_deriv (in_iter + i_idx * ndescrpt * 3 + jj * 3 + 0); - force (force_iter + j_idx * 3 + 1) += net_deriv (net_iter + i_idx * ndescrpt + jj) * in_deriv (in_iter + i_idx * ndescrpt * 3 + jj * 3 + 1); - force (force_iter + j_idx * 3 + 2) += net_deriv (net_iter + i_idx * ndescrpt + jj) * in_deriv (in_iter + i_idx * ndescrpt * 3 + jj * 3 + 2); - } - } + prod_force_r_cpu(&force(force_iter), + &net_deriv(net_iter), + &in_deriv(in_iter), + &nlist(nlist_iter), + nloc, + nall, + nnei); } } }; diff --git a/source/op/prod_virial_se_r.cc b/source/op/prod_virial_se_r.cc index 3bb8a0fcd1..d41fddd4c8 100644 --- a/source/op/prod_virial_se_r.cc +++ b/source/op/prod_virial_se_r.cc @@ -3,6 +3,8 @@ #include "tensorflow/core/framework/shape_inference.h" #include +#include "prod_virial.h" + using namespace tensorflow; // using namespace std; @@ -90,31 +92,16 @@ class ProdVirialSeROp : public OpKernel { int virial_iter = kk * 9; int atom_virial_iter = kk * nall * 9; - for (int ii = 0; ii < 9; ++ ii){ - virial (virial_iter + ii) = 0.; - } - for (int ii = 0; ii < 9 * nall; ++ ii){ - atom_virial (atom_virial_iter + ii) = 0.; - } - - // compute virial of a frame - for (int ii = 0; ii < nloc; ++ii){ - int i_idx = ii; - - // deriv wrt neighbors - for (int jj = 0; jj < nnei; ++jj){ - int j_idx = nlist (nlist_iter + i_idx * nnei + jj); - if (j_idx < 0) continue; - FPTYPE pref = -1.0 * net_deriv (net_iter + i_idx * ndescrpt + jj); - for (int dd0 = 0; dd0 < 3; ++dd0){ - for (int dd1 = 0; dd1 < 3; ++dd1){ - FPTYPE tmp_v = pref * rij (rij_iter + i_idx * nnei * 3 + jj * 3 + dd1) * in_deriv (in_iter + i_idx * ndescrpt * 3 + jj * 3 + dd0); - virial (virial_iter + dd0 * 3 + dd1) -= tmp_v; - atom_virial (atom_virial_iter + j_idx * 9 + dd0 * 3 + dd1) -= tmp_v; - } - } - } - } + prod_virial_r_cpu( + &virial(virial_iter), + &atom_virial(atom_virial_iter), + &net_deriv(net_iter), + &in_deriv(in_iter), + &rij(rij_iter), + &nlist(nlist_iter), + nloc, + nall, + nnei); } } }; From 6f45908897e08755f713dad9807f58aa48e0f19e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Tue, 9 Feb 2021 11:36:38 +0100 Subject: [PATCH 115/562] rework runoptions, cluster, rename modlues to camel_case and constants to UPPERCASE --- deepmd/common.py | 4 +- deepmd/descriptor/hybrid.py | 6 +- deepmd/descriptor/loc_frame.py | 16 +- deepmd/descriptor/se_a.py | 18 +- deepmd/descriptor/se_a_ebd.py | 6 +- deepmd/descriptor/se_a_ef.py | 18 +- deepmd/descriptor/se_a_t.py | 16 +- deepmd/descriptor/se_r.py | 18 +- deepmd/fit/dipole.py | 6 +- deepmd/fit/ener.py | 20 +- deepmd/fit/polar.py | 10 +- deepmd/fit/wfc.py | 6 +- deepmd/infer/data_modifier.py | 14 +- deepmd/infer/ewald_recp.py | 16 +- deepmd/loss/ener.py | 4 +- deepmd/loss/tensor.py | 4 +- deepmd/utils/data.py | 28 +- deepmd/utils/loggers.py | 50 +++ deepmd/utils/network.py | 4 +- doc/api.rst | 6 +- source/tests/common.py | 8 +- source/tests/test_data_modifier.py | 10 +- source/tests/test_data_modifier_shuffle.py | 10 +- source/tests/test_deepmd_data.py | 2 +- source/tests/test_deepmd_data_sys.py | 2 +- source/tests/test_descrpt_nonsmth.py | 6 +- source/tests/test_descrpt_se_ar.py | 6 +- source/tests/test_descrpt_se_r.py | 6 +- source/tests/test_descrpt_sea_ef.py | 6 +- source/tests/test_descrpt_sea_ef_para.py | 6 +- source/tests/test_descrpt_sea_ef_rot.py | 6 +- source/tests/test_descrpt_sea_ef_vert.py | 6 +- source/tests/test_descrpt_smooth.py | 6 +- source/tests/test_embedding_net.py | 6 +- source/tests/test_ewald.py | 6 +- source/tests/test_gen_stat_data.py | 2 +- source/tests/test_model_loc_frame.py | 4 +- source/tests/test_model_se_a.py | 4 +- source/tests/test_model_se_a_aparam.py | 4 +- source/tests/test_model_se_a_fparam.py | 4 +- source/tests/test_model_se_a_srtab.py | 4 +- source/tests/test_model_se_r.py | 4 +- source/tests/test_polar_se_a.py | 4 +- source/tests/test_wfc.py | 4 +- source/train/CMakeLists.txt | 14 +- source/train/Local.py | 13 - source/train/RunOptions.py.in | 238 ------------- source/train/Slurm.py | 55 --- source/train/Trainer.py | 10 +- source/train/calculator.py | 3 +- source/train/cluster/__init__.py | 22 ++ source/train/cluster/local.py | 26 ++ source/train/cluster/slurm.py | 84 +++++ source/train/{Model.py => model.py} | 2 +- source/train/print_old_model.py | 6 +- source/train/run_config.ini | 9 + source/train/run_options.py | 383 +++++++++++++++++++++ source/train/train.py | 11 +- 58 files changed, 772 insertions(+), 500 deletions(-) create mode 100644 deepmd/utils/loggers.py delete mode 100644 source/train/Local.py delete mode 100644 source/train/RunOptions.py.in delete mode 100644 source/train/Slurm.py create mode 100644 source/train/cluster/__init__.py create mode 100644 source/train/cluster/local.py create mode 100644 source/train/cluster/slurm.py rename source/train/{Model.py => model.py} (99%) create mode 100644 source/train/run_config.ini create mode 100644 source/train/run_options.py diff --git a/deepmd/common.py b/deepmd/common.py index 0e6db4c363..5183b62536 100644 --- a/deepmd/common.py +++ b/deepmd/common.py @@ -20,7 +20,7 @@ import yaml from deepmd.env import op_module, tf -from deepmd.RunOptions import global_tf_float_precision +from deepmd.RunOptions import GLOBAL_TF_FLOAT_PRECISION if TYPE_CHECKING: _DICT_VAL = TypeVar("_DICT_VAL") @@ -34,7 +34,7 @@ # define constants PRECISION_DICT = { - "default": global_tf_float_precision, + "default": GLOBAL_TF_FLOAT_PRECISION, "float16": tf.float16, "float32": tf.float32, "float64": tf.float64, diff --git a/deepmd/descriptor/hybrid.py b/deepmd/descriptor/hybrid.py index f16db2a280..f576e65abd 100644 --- a/deepmd/descriptor/hybrid.py +++ b/deepmd/descriptor/hybrid.py @@ -4,8 +4,8 @@ from deepmd.env import tf from deepmd.common import ClassArg from deepmd.env import op_module -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION # from deepmd.descriptor import DescrptLocFrame # from deepmd.descriptor import DescrptSeA # from deepmd.descriptor import DescrptSeAT @@ -164,7 +164,7 @@ def build (self, with tf.variable_scope('descrpt_attr' + suffix, reuse = reuse) : t_rcut = tf.constant(self.get_rcut(), name = 'rcut', - dtype = global_tf_float_precision) + dtype = GLOBAL_TF_FLOAT_PRECISION) t_ntypes = tf.constant(self.get_ntypes(), name = 'ntypes', dtype = tf.int32) diff --git a/deepmd/descriptor/loc_frame.py b/deepmd/descriptor/loc_frame.py index f841004e98..f9dab549ee 100644 --- a/deepmd/descriptor/loc_frame.py +++ b/deepmd/descriptor/loc_frame.py @@ -2,8 +2,8 @@ from typing import Tuple, List from deepmd.env import tf -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION from deepmd.env import op_module from deepmd.env import default_tf_session_config @@ -63,13 +63,13 @@ def __init__(self, self.dstd = None self.place_holders = {} - avg_zero = np.zeros([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) - std_ones = np.ones ([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) + avg_zero = np.zeros([self.ntypes,self.ndescrpt]).astype(GLOBAL_NP_FLOAT_PRECISION) + std_ones = np.ones ([self.ntypes,self.ndescrpt]).astype(GLOBAL_NP_FLOAT_PRECISION) sub_graph = tf.Graph() with sub_graph.as_default(): name_pfx = 'd_lf_' for ii in ['coord', 'box']: - self.place_holders[ii] = tf.placeholder(global_np_float_precision, [None, None], name = name_pfx+'t_'+ii) + self.place_holders[ii] = tf.placeholder(GLOBAL_NP_FLOAT_PRECISION, [None, None], name = name_pfx+'t_'+ii) self.place_holders['type'] = tf.placeholder(tf.int32, [None, None], name=name_pfx+'t_type') self.place_holders['natoms_vec'] = tf.placeholder(tf.int32, [self.ntypes+2], name=name_pfx+'t_natoms') self.place_holders['default_mesh'] = tf.placeholder(tf.int32, [None], name=name_pfx+'t_mesh') @@ -224,18 +224,18 @@ def build (self, dstd = np.ones ([self.ntypes, self.ndescrpt]) t_rcut = tf.constant(np.max([self.rcut_r, self.rcut_a]), name = 'rcut', - dtype = global_tf_float_precision) + dtype = GLOBAL_TF_FLOAT_PRECISION) t_ntypes = tf.constant(self.ntypes, name = 'ntypes', dtype = tf.int32) self.t_avg = tf.get_variable('t_avg', davg.shape, - dtype = global_tf_float_precision, + dtype = GLOBAL_TF_FLOAT_PRECISION, trainable = False, initializer = tf.constant_initializer(davg)) self.t_std = tf.get_variable('t_std', dstd.shape, - dtype = global_tf_float_precision, + dtype = GLOBAL_TF_FLOAT_PRECISION, trainable = False, initializer = tf.constant_initializer(dstd)) diff --git a/deepmd/descriptor/se_a.py b/deepmd/descriptor/se_a.py index 369a57d677..002f1bd3ab 100644 --- a/deepmd/descriptor/se_a.py +++ b/deepmd/descriptor/se_a.py @@ -4,8 +4,8 @@ from deepmd.env import tf from deepmd.common import get_activation_func, get_precision, ACTIVATION_FN_DICT, PRECISION_DICT, docstring_parameter from deepmd.utils.argcheck import list_to_doc -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION from deepmd.env import op_module from deepmd.env import default_tf_session_config from deepmd.utils.network import embedding_net @@ -98,13 +98,13 @@ def __init__ (self, self.davg = None self.place_holders = {} - avg_zero = np.zeros([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) - std_ones = np.ones ([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) + avg_zero = np.zeros([self.ntypes,self.ndescrpt]).astype(GLOBAL_NP_FLOAT_PRECISION) + std_ones = np.ones ([self.ntypes,self.ndescrpt]).astype(GLOBAL_NP_FLOAT_PRECISION) sub_graph = tf.Graph() with sub_graph.as_default(): name_pfx = 'd_sea_' for ii in ['coord', 'box']: - self.place_holders[ii] = tf.placeholder(global_np_float_precision, [None, None], name = name_pfx+'t_'+ii) + self.place_holders[ii] = tf.placeholder(GLOBAL_NP_FLOAT_PRECISION, [None, None], name = name_pfx+'t_'+ii) self.place_holders['type'] = tf.placeholder(tf.int32, [None, None], name=name_pfx+'t_type') self.place_holders['natoms_vec'] = tf.placeholder(tf.int32, [self.ntypes+2], name=name_pfx+'t_natoms') self.place_holders['default_mesh'] = tf.placeholder(tf.int32, [None], name=name_pfx+'t_mesh') @@ -276,7 +276,7 @@ def build (self, dstd = np.ones ([self.ntypes, self.ndescrpt]) t_rcut = tf.constant(np.max([self.rcut_r, self.rcut_a]), name = 'rcut', - dtype = global_tf_float_precision) + dtype = GLOBAL_TF_FLOAT_PRECISION) t_ntypes = tf.constant(self.ntypes, name = 'ntypes', dtype = tf.int32) @@ -288,12 +288,12 @@ def build (self, dtype = tf.int32) self.t_avg = tf.get_variable('t_avg', davg.shape, - dtype = global_tf_float_precision, + dtype = GLOBAL_TF_FLOAT_PRECISION, trainable = False, initializer = tf.constant_initializer(davg)) self.t_std = tf.get_variable('t_std', dstd.shape, - dtype = global_tf_float_precision, + dtype = GLOBAL_TF_FLOAT_PRECISION, trainable = False, initializer = tf.constant_initializer(dstd)) @@ -528,7 +528,7 @@ def _filter(self, seed = seed, trainable = trainable) else: - w = tf.zeros((outputs_size[0], outputs_size[-1]), dtype=global_tf_float_precision) + w = tf.zeros((outputs_size[0], outputs_size[-1]), dtype=GLOBAL_TF_FLOAT_PRECISION) xyz_scatter = tf.matmul(xyz_scatter, w) # natom x nei_type_i x out_size xyz_scatter = tf.reshape(xyz_scatter, (-1, shape_i[1]//4, outputs_size[-1])) diff --git a/deepmd/descriptor/se_a_ebd.py b/deepmd/descriptor/se_a_ebd.py index 5d3838f476..c88bc83e0b 100644 --- a/deepmd/descriptor/se_a_ebd.py +++ b/deepmd/descriptor/se_a_ebd.py @@ -4,8 +4,8 @@ from deepmd.env import tf from deepmd.common import ClassArg, get_activation_func, get_precision, add_data_requirement from deepmd.utils.network import one_layer -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION from deepmd.env import op_module from deepmd.env import default_tf_session_config from deepmd.utils.network import embedding_net @@ -139,7 +139,7 @@ def build (self, nei_type = np.append(nei_type, ii * np.ones(self.sel_a[ii])) self.nei_type = tf.get_variable('t_nei_type', [self.nnei], - dtype = global_tf_float_precision, + dtype = GLOBAL_TF_FLOAT_PRECISION, trainable = False, initializer = tf.constant_initializer(nei_type)) self.dout = DescrptSeA.build(self, coord_, atype_, natoms, box_, mesh, input_dict, suffix = suffix, reuse = reuse) diff --git a/deepmd/descriptor/se_a_ef.py b/deepmd/descriptor/se_a_ef.py index 7315f75401..3f30c52f08 100644 --- a/deepmd/descriptor/se_a_ef.py +++ b/deepmd/descriptor/se_a_ef.py @@ -4,8 +4,8 @@ from deepmd.env import tf from deepmd.common import add_data_requirement,get_activation_func, get_precision, ACTIVATION_FN_DICT, PRECISION_DICT, docstring_parameter from deepmd.utils.argcheck import list_to_doc -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION from deepmd.env import op_module from deepmd.env import default_tf_session_config from .se_a import DescrptSeA @@ -344,17 +344,17 @@ def __init__ (self, add_data_requirement('efield', 3, atomic=True, must=True, high_prec=False) self.place_holders = {} - avg_zero = np.zeros([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) - std_ones = np.ones ([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) + avg_zero = np.zeros([self.ntypes,self.ndescrpt]).astype(GLOBAL_NP_FLOAT_PRECISION) + std_ones = np.ones ([self.ntypes,self.ndescrpt]).astype(GLOBAL_NP_FLOAT_PRECISION) sub_graph = tf.Graph() with sub_graph.as_default(): name_pfx = 'd_sea_ef_' for ii in ['coord', 'box']: - self.place_holders[ii] = tf.placeholder(global_np_float_precision, [None, None], name = name_pfx+'t_'+ii) + self.place_holders[ii] = tf.placeholder(GLOBAL_NP_FLOAT_PRECISION, [None, None], name = name_pfx+'t_'+ii) self.place_holders['type'] = tf.placeholder(tf.int32, [None, None], name=name_pfx+'t_type') self.place_holders['natoms_vec'] = tf.placeholder(tf.int32, [self.ntypes+2], name=name_pfx+'t_natoms') self.place_holders['default_mesh'] = tf.placeholder(tf.int32, [None], name=name_pfx+'t_mesh') - self.place_holders['efield'] = tf.placeholder(global_np_float_precision, [None, None], name=name_pfx+'t_efield') + self.place_holders['efield'] = tf.placeholder(GLOBAL_NP_FLOAT_PRECISION, [None, None], name=name_pfx+'t_efield') self.stat_descrpt, descrpt_deriv, rij, nlist \ = self.op(self.place_holders['coord'], self.place_holders['type'], @@ -441,7 +441,7 @@ def build (self, dstd = np.ones ([self.ntypes, self.ndescrpt]) t_rcut = tf.constant(np.max([self.rcut_r, self.rcut_a]), name = 'rcut', - dtype = global_tf_float_precision) + dtype = GLOBAL_TF_FLOAT_PRECISION) t_ntypes = tf.constant(self.ntypes, name = 'ntypes', dtype = tf.int32) @@ -453,12 +453,12 @@ def build (self, dtype = tf.int32) self.t_avg = tf.get_variable('t_avg', davg.shape, - dtype = global_tf_float_precision, + dtype = GLOBAL_TF_FLOAT_PRECISION, trainable = False, initializer = tf.constant_initializer(davg)) self.t_std = tf.get_variable('t_std', dstd.shape, - dtype = global_tf_float_precision, + dtype = GLOBAL_TF_FLOAT_PRECISION, trainable = False, initializer = tf.constant_initializer(dstd)) diff --git a/deepmd/descriptor/se_a_t.py b/deepmd/descriptor/se_a_t.py index c1987e9e02..f2f44e8c2a 100644 --- a/deepmd/descriptor/se_a_t.py +++ b/deepmd/descriptor/se_a_t.py @@ -4,8 +4,8 @@ from deepmd.env import tf from deepmd.common import get_activation_func, get_precision, ACTIVATION_FN_DICT, PRECISION_DICT, docstring_parameter from deepmd.utils.argcheck import list_to_doc -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION from deepmd.env import op_module from deepmd.env import default_tf_session_config from deepmd.utils.network import embedding_net @@ -84,13 +84,13 @@ def __init__ (self, self.davg = None self.place_holders = {} - avg_zero = np.zeros([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) - std_ones = np.ones ([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) + avg_zero = np.zeros([self.ntypes,self.ndescrpt]).astype(GLOBAL_NP_FLOAT_PRECISION) + std_ones = np.ones ([self.ntypes,self.ndescrpt]).astype(GLOBAL_NP_FLOAT_PRECISION) sub_graph = tf.Graph() with sub_graph.as_default(): name_pfx = 'd_sea_' for ii in ['coord', 'box']: - self.place_holders[ii] = tf.placeholder(global_np_float_precision, [None, None], name = name_pfx+'t_'+ii) + self.place_holders[ii] = tf.placeholder(GLOBAL_NP_FLOAT_PRECISION, [None, None], name = name_pfx+'t_'+ii) self.place_holders['type'] = tf.placeholder(tf.int32, [None, None], name=name_pfx+'t_type') self.place_holders['natoms_vec'] = tf.placeholder(tf.int32, [self.ntypes+2], name=name_pfx+'t_natoms') self.place_holders['default_mesh'] = tf.placeholder(tf.int32, [None], name=name_pfx+'t_mesh') @@ -256,7 +256,7 @@ def build (self, dstd = np.ones ([self.ntypes, self.ndescrpt]) t_rcut = tf.constant(np.max([self.rcut_r, self.rcut_a]), name = 'rcut', - dtype = global_tf_float_precision) + dtype = GLOBAL_TF_FLOAT_PRECISION) t_ntypes = tf.constant(self.ntypes, name = 'ntypes', dtype = tf.int32) @@ -268,12 +268,12 @@ def build (self, dtype = tf.int32) self.t_avg = tf.get_variable('t_avg', davg.shape, - dtype = global_tf_float_precision, + dtype = GLOBAL_TF_FLOAT_PRECISION, trainable = False, initializer = tf.constant_initializer(davg)) self.t_std = tf.get_variable('t_std', dstd.shape, - dtype = global_tf_float_precision, + dtype = GLOBAL_TF_FLOAT_PRECISION, trainable = False, initializer = tf.constant_initializer(dstd)) diff --git a/deepmd/descriptor/se_r.py b/deepmd/descriptor/se_r.py index 3a7b9a3f49..4a73457299 100644 --- a/deepmd/descriptor/se_r.py +++ b/deepmd/descriptor/se_r.py @@ -4,8 +4,8 @@ from deepmd.env import tf from deepmd.common import get_activation_func, get_precision, ACTIVATION_FN_DICT, PRECISION_DICT, docstring_parameter from deepmd.utils.argcheck import list_to_doc -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION from deepmd.env import op_module from deepmd.env import default_tf_session_config from deepmd.utils.network import embedding_net @@ -101,13 +101,13 @@ def __init__ (self, self.dstd = None self.place_holders = {} - avg_zero = np.zeros([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) - std_ones = np.ones ([self.ntypes,self.ndescrpt]).astype(global_np_float_precision) + avg_zero = np.zeros([self.ntypes,self.ndescrpt]).astype(GLOBAL_NP_FLOAT_PRECISION) + std_ones = np.ones ([self.ntypes,self.ndescrpt]).astype(GLOBAL_NP_FLOAT_PRECISION) sub_graph = tf.Graph() with sub_graph.as_default(): name_pfx = 'd_ser_' for ii in ['coord', 'box']: - self.place_holders[ii] = tf.placeholder(global_np_float_precision, [None, None], name = name_pfx+'t_'+ii) + self.place_holders[ii] = tf.placeholder(GLOBAL_NP_FLOAT_PRECISION, [None, None], name = name_pfx+'t_'+ii) self.place_holders['type'] = tf.placeholder(tf.int32, [None, None], name=name_pfx+'t_type') self.place_holders['natoms_vec'] = tf.placeholder(tf.int32, [self.ntypes+2], name=name_pfx+'t_natoms') self.place_holders['default_mesh'] = tf.placeholder(tf.int32, [None], name=name_pfx+'t_mesh') @@ -259,7 +259,7 @@ def build (self, dstd = np.ones ([self.ntypes, self.ndescrpt]) t_rcut = tf.constant(self.rcut, name = 'rcut', - dtype = global_tf_float_precision) + dtype = GLOBAL_TF_FLOAT_PRECISION) t_ntypes = tf.constant(self.ntypes, name = 'ntypes', dtype = tf.int32) @@ -271,12 +271,12 @@ def build (self, dtype = tf.int32) self.t_avg = tf.get_variable('t_avg', davg.shape, - dtype = global_tf_float_precision, + dtype = GLOBAL_TF_FLOAT_PRECISION, trainable = False, initializer = tf.constant_initializer(davg)) self.t_std = tf.get_variable('t_std', dstd.shape, - dtype = global_tf_float_precision, + dtype = GLOBAL_TF_FLOAT_PRECISION, trainable = False, initializer = tf.constant_initializer(dstd)) @@ -471,7 +471,7 @@ def _filter_r(self, seed = seed, trainable = trainable) else: - w = tf.zeros((outputs_size[0], outputs_size[-1]), dtype=global_tf_float_precision) + w = tf.zeros((outputs_size[0], outputs_size[-1]), dtype=GLOBAL_TF_FLOAT_PRECISION) xyz_scatter = tf.matmul(xyz_scatter, w) # natom x nei_type_i x out_size xyz_scatter = tf.reshape(xyz_scatter, (-1, shape_i[1], outputs_size[-1])) diff --git a/deepmd/fit/dipole.py b/deepmd/fit/dipole.py index fbe3b3fcf0..f940675ac1 100644 --- a/deepmd/fit/dipole.py +++ b/deepmd/fit/dipole.py @@ -8,8 +8,8 @@ from deepmd.utils.network import one_layer from deepmd.descriptor import DescrptSeA -from deepmd.RunOptions import global_cvt_2_tf_float -from deepmd.RunOptions import global_tf_float_precision +from deepmd.run_options import global_cvt_2_tf_float +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION class DipoleFittingSeA () : """ @@ -154,5 +154,5 @@ def build (self, count += 1 tf.summary.histogram('fitting_net_output', outs) - return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) + return tf.cast(tf.reshape(outs, [-1]), GLOBAL_TF_FLOAT_PRECISION) # return tf.reshape(outs, [tf.shape(inputs)[0] * natoms[0] * 3 // 3]) diff --git a/deepmd/fit/ener.py b/deepmd/fit/ener.py index 97118d2b33..24debd43fc 100644 --- a/deepmd/fit/ener.py +++ b/deepmd/fit/ener.py @@ -9,8 +9,8 @@ from deepmd.descriptor import DescrptLocFrame from deepmd.descriptor import DescrptSeA -from deepmd.RunOptions import global_cvt_2_tf_float -from deepmd.RunOptions import global_tf_float_precision +from deepmd.run_options import global_cvt_2_tf_float +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION class EnerFitting (): @docstring_parameter(list_to_doc(ACTIVATION_FN_DICT.keys()), list_to_doc(PRECISION_DICT.keys())) @@ -94,7 +94,7 @@ def __init__ (self, self.atom_ener = [] for at, ae in enumerate(atom_ener): if ae is not None: - self.atom_ener.append(tf.constant(ae, global_tf_float_precision, name = "atom_%d_ener" % at)) + self.atom_ener.append(tf.constant(ae, GLOBAL_TF_FLOAT_PRECISION, name = "atom_%d_ener" % at)) else: self.atom_ener.append(None) self.useBN = False @@ -259,23 +259,23 @@ def build (self, if self.numb_fparam > 0: t_fparam_avg = tf.get_variable('t_fparam_avg', self.numb_fparam, - dtype = global_tf_float_precision, + dtype = GLOBAL_TF_FLOAT_PRECISION, trainable = False, initializer = tf.constant_initializer(self.fparam_avg)) t_fparam_istd = tf.get_variable('t_fparam_istd', self.numb_fparam, - dtype = global_tf_float_precision, + dtype = GLOBAL_TF_FLOAT_PRECISION, trainable = False, initializer = tf.constant_initializer(self.fparam_inv_std)) if self.numb_aparam > 0: t_aparam_avg = tf.get_variable('t_aparam_avg', self.numb_aparam, - dtype = global_tf_float_precision, + dtype = GLOBAL_TF_FLOAT_PRECISION, trainable = False, initializer = tf.constant_initializer(self.aparam_avg)) t_aparam_istd = tf.get_variable('t_aparam_istd', self.numb_aparam, - dtype = global_tf_float_precision, + dtype = GLOBAL_TF_FLOAT_PRECISION, trainable = False, initializer = tf.constant_initializer(self.aparam_inv_std)) @@ -329,7 +329,7 @@ def build (self, final_layer = one_layer(layer, 1, activation_fn = None, bavg = type_bias_ae, name='final_layer_type_'+str(type_i)+suffix, reuse=reuse, seed = self.seed, precision = self.fitting_precision, trainable = self.trainable[-1]) if type_i < len(self.atom_ener) and self.atom_ener[type_i] is not None: - inputs_zero = tf.zeros_like(inputs_i, dtype=global_tf_float_precision) + inputs_zero = tf.zeros_like(inputs_i, dtype=GLOBAL_TF_FLOAT_PRECISION) layer = inputs_zero if self.numb_fparam > 0 : layer = tf.concat([layer, ext_fparam], axis = 1) @@ -355,12 +355,12 @@ def build (self, force_tot_ener = 0.0 outs = tf.reshape(outs, [-1, natoms[0]]) outs_mean = tf.reshape(tf.reduce_mean(outs, axis = 1), [-1, 1]) - outs_mean = outs_mean - tf.ones_like(outs_mean, dtype = global_tf_float_precision) * (force_tot_ener/global_cvt_2_tf_float(natoms[0])) + outs_mean = outs_mean - tf.ones_like(outs_mean, dtype = GLOBAL_TF_FLOAT_PRECISION) * (force_tot_ener/global_cvt_2_tf_float(natoms[0])) outs = outs - outs_mean outs = tf.reshape(outs, [-1]) tf.summary.histogram('fitting_net_output', outs) - return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) + return tf.cast(tf.reshape(outs, [-1]), GLOBAL_TF_FLOAT_PRECISION) diff --git a/deepmd/fit/polar.py b/deepmd/fit/polar.py index 3a03650946..969491f484 100644 --- a/deepmd/fit/polar.py +++ b/deepmd/fit/polar.py @@ -9,8 +9,8 @@ from deepmd.descriptor import DescrptLocFrame from deepmd.descriptor import DescrptSeA -from deepmd.RunOptions import global_cvt_2_tf_float -from deepmd.RunOptions import global_tf_float_precision +from deepmd.run_options import global_cvt_2_tf_float +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION class PolarFittingLocFrame () : @@ -95,7 +95,7 @@ def build (self, count += 1 tf.summary.histogram('fitting_net_output', outs) - return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) + return tf.cast(tf.reshape(outs, [-1]), GLOBAL_TF_FLOAT_PRECISION) class PolarFittingSeA () : @@ -308,7 +308,7 @@ def build (self, # shift and scale sel_type_idx = self.sel_type.index(type_i) final_layer = final_layer * self.scale[sel_type_idx] - final_layer = final_layer + self.diag_shift[sel_type_idx] * tf.eye(3, batch_shape=[tf.shape(inputs)[0], natoms[2+type_i]], dtype = global_tf_float_precision) + final_layer = final_layer + self.diag_shift[sel_type_idx] * tf.eye(3, batch_shape=[tf.shape(inputs)[0], natoms[2+type_i]], dtype = GLOBAL_TF_FLOAT_PRECISION) # concat the results if count == 0: @@ -318,7 +318,7 @@ def build (self, count += 1 tf.summary.histogram('fitting_net_output', outs) - return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) + return tf.cast(tf.reshape(outs, [-1]), GLOBAL_TF_FLOAT_PRECISION) class GlobalPolarFittingSeA () : diff --git a/deepmd/fit/wfc.py b/deepmd/fit/wfc.py index c3a565d714..063b1a9071 100644 --- a/deepmd/fit/wfc.py +++ b/deepmd/fit/wfc.py @@ -8,8 +8,8 @@ from deepmd.utils.network import one_layer from deepmd.descriptor import DescrptLocFrame -from deepmd.RunOptions import global_cvt_2_tf_float -from deepmd.RunOptions import global_tf_float_precision +from deepmd.run_options import global_cvt_2_tf_float +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION class WFCFitting () : """ @@ -95,4 +95,4 @@ def build (self, count += 1 tf.summary.histogram('fitting_net_output', outs) - return tf.cast(tf.reshape(outs, [-1]), global_tf_float_precision) + return tf.cast(tf.reshape(outs, [-1]), GLOBAL_TF_FLOAT_PRECISION) diff --git a/deepmd/infer/data_modifier.py b/deepmd/infer/data_modifier.py index 3c02454379..1cf4446f7d 100644 --- a/deepmd/infer/data_modifier.py +++ b/deepmd/infer/data_modifier.py @@ -6,11 +6,11 @@ from deepmd.infer.ewald_recp import EwaldRecp from deepmd.env import tf from deepmd.common import select_idx_map, make_default_mesh -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision -from deepmd.RunOptions import global_ener_float_precision -from deepmd.RunOptions import global_cvt_2_tf_float -from deepmd.RunOptions import global_cvt_2_ener_float +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.run_options import global_cvt_2_tf_float +from deepmd.run_options import global_cvt_2_ener_float from deepmd.env import op_module @@ -97,7 +97,7 @@ def build_fv_graph(self) -> tf.Tensor: def _build_fv_graph_inner(self): - self.t_ef = tf.placeholder(global_tf_float_precision, [None], name = 't_ef') + self.t_ef = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name = 't_ef') nf = 10 nfxnas = 64*nf nfxna = 192*nf @@ -189,7 +189,7 @@ def _enrich(self, dipole, dof = 3): sel_start_idx += self.t_natoms[2+type_i] else: di = tf.zeros([tf.shape(dipole)[0], self.t_natoms[2+type_i] * dof], - dtype = global_tf_float_precision) + dtype = GLOBAL_TF_FLOAT_PRECISION) coll.append(di) return tf.concat(coll, axis = 1) diff --git a/deepmd/infer/ewald_recp.py b/deepmd/infer/ewald_recp.py index 300ae539e1..2554b40114 100644 --- a/deepmd/infer/ewald_recp.py +++ b/deepmd/infer/ewald_recp.py @@ -3,11 +3,11 @@ from deepmd.env import tf from deepmd.common import ClassArg -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision -from deepmd.RunOptions import global_ener_float_precision -from deepmd.RunOptions import global_cvt_2_tf_float -from deepmd.RunOptions import global_cvt_2_ener_float +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.run_options import global_cvt_2_tf_float +from deepmd.run_options import global_cvt_2_ener_float from deepmd.env import op_module from deepmd.env import default_tf_session_config @@ -33,9 +33,9 @@ def __init__(self, with tf.Graph().as_default() as graph: # place holders self.t_nloc = tf.placeholder(tf.int32, [1], name = "t_nloc") - self.t_coord = tf.placeholder(global_tf_float_precision, [None], name='t_coord') - self.t_charge = tf.placeholder(global_tf_float_precision, [None], name='t_charge') - self.t_box = tf.placeholder(global_tf_float_precision, [None], name='t_box') + self.t_coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_coord') + self.t_charge = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_charge') + self.t_box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_box') # output self.t_energy, self.t_force, self.t_virial \ = op_module.ewald_recp(self.t_coord, self.t_charge, self.t_nloc, self.t_box, diff --git a/deepmd/loss/ener.py b/deepmd/loss/ener.py index 2762634378..08e631bc0b 100644 --- a/deepmd/loss/ener.py +++ b/deepmd/loss/ener.py @@ -2,8 +2,8 @@ from deepmd.env import tf from deepmd.common import ClassArg, add_data_requirement -from deepmd.RunOptions import global_cvt_2_tf_float -from deepmd.RunOptions import global_cvt_2_ener_float +from deepmd.run_options import global_cvt_2_tf_float +from deepmd.run_options import global_cvt_2_ener_float class EnerStdLoss () : """ diff --git a/deepmd/loss/tensor.py b/deepmd/loss/tensor.py index 0b360a0d83..8784427808 100644 --- a/deepmd/loss/tensor.py +++ b/deepmd/loss/tensor.py @@ -2,8 +2,8 @@ from deepmd.env import tf from deepmd.common import ClassArg, add_data_requirement -from deepmd.RunOptions import global_cvt_2_tf_float -from deepmd.RunOptions import global_cvt_2_ener_float +from deepmd.run_options import global_cvt_2_tf_float +from deepmd.run_options import global_cvt_2_ener_float class TensorLoss () : """ diff --git a/deepmd/utils/data.py b/deepmd/utils/data.py index d2565afe46..958de14583 100644 --- a/deepmd/utils/data.py +++ b/deepmd/utils/data.py @@ -6,8 +6,8 @@ import os.path from typing import Tuple, List -from deepmd.RunOptions import global_np_float_precision -from deepmd.RunOptions import global_ener_float_precision +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION class DeepmdData() : """ @@ -157,9 +157,9 @@ def check_batch_size (self, batch_size) : """ for ii in self.train_dirs : if self.data_dict['coord']['high_prec'] : - tmpe = np.load(os.path.join(ii, "coord.npy")).astype(global_ener_float_precision) + tmpe = np.load(os.path.join(ii, "coord.npy")).astype(GLOBAL_ENER_FLOAT_PRECISION) else: - tmpe = np.load(os.path.join(ii, "coord.npy")).astype(global_np_float_precision) + tmpe = np.load(os.path.join(ii, "coord.npy")).astype(GLOBAL_NP_FLOAT_PRECISION) if tmpe.ndim == 1: tmpe = tmpe.reshape([1,-1]) if tmpe.shape[0] < batch_size : @@ -171,9 +171,9 @@ def check_test_size (self, test_size) : Check if the system can get a test dataset with `test_size` frames. """ if self.data_dict['coord']['high_prec'] : - tmpe = np.load(os.path.join(self.test_dir, "coord.npy")).astype(global_ener_float_precision) + tmpe = np.load(os.path.join(self.test_dir, "coord.npy")).astype(GLOBAL_ENER_FLOAT_PRECISION) else: - tmpe = np.load(os.path.join(self.test_dir, "coord.npy")).astype(global_np_float_precision) + tmpe = np.load(os.path.join(self.test_dir, "coord.npy")).astype(GLOBAL_NP_FLOAT_PRECISION) if tmpe.ndim == 1: tmpe = tmpe.reshape([1,-1]) if tmpe.shape[0] < test_size : @@ -403,9 +403,9 @@ def _load_set(self, set_name) : # get nframes path = os.path.join(set_name, "coord.npy") if self.data_dict['coord']['high_prec'] : - coord = np.load(path).astype(global_ener_float_precision) + coord = np.load(path).astype(GLOBAL_ENER_FLOAT_PRECISION) else: - coord = np.load(path).astype(global_np_float_precision) + coord = np.load(path).astype(GLOBAL_NP_FLOAT_PRECISION) if coord.ndim == 1: coord = coord.reshape([1,-1]) nframes = coord.shape[0] @@ -430,7 +430,7 @@ def _load_set(self, set_name) : k_in = self.data_dict[kk]['reduce'] ndof = self.data_dict[kk]['ndof'] data['find_'+kk] = data['find_'+k_in] - tmp_in = data[k_in].astype(global_ener_float_precision) + tmp_in = data[k_in].astype(GLOBAL_ENER_FLOAT_PRECISION) data[kk] = np.sum(np.reshape(tmp_in, [nframes, self.natoms, ndof]), axis = 1) return data @@ -452,9 +452,9 @@ def _load_data(self, set_name, key, nframes, ndof_, atomic = False, must = True, path = os.path.join(set_name, key+".npy") if os.path.isfile (path) : if high_prec : - data = np.load(path).astype(global_ener_float_precision) + data = np.load(path).astype(GLOBAL_ENER_FLOAT_PRECISION) else: - data = np.load(path).astype(global_np_float_precision) + data = np.load(path).astype(GLOBAL_NP_FLOAT_PRECISION) if atomic : data = data.reshape([nframes, natoms, -1]) data = data[:,idx_map,:] @@ -467,9 +467,9 @@ def _load_data(self, set_name, key, nframes, ndof_, atomic = False, must = True, raise RuntimeError("%s not found!" % path) else: if high_prec : - data = np.zeros([nframes,ndof]).astype(global_ener_float_precision) + data = np.zeros([nframes,ndof]).astype(GLOBAL_ENER_FLOAT_PRECISION) else : - data = np.zeros([nframes,ndof]).astype(global_np_float_precision) + data = np.zeros([nframes,ndof]).astype(GLOBAL_NP_FLOAT_PRECISION) if repeat != 1: data = np.repeat(data, repeat).reshape([nframes, -1]) return np.float32(0.0), data @@ -696,7 +696,7 @@ def get_set(self, data, idx = None) : if ii == "type": new_data[ii] = dd else: - new_data[ii] = dd.astype(global_np_float_precision) + new_data[ii] = dd.astype(GLOBAL_NP_FLOAT_PRECISION) return new_data def get_test (self) : diff --git a/deepmd/utils/loggers.py b/deepmd/utils/loggers.py new file mode 100644 index 0000000000..91dc7397fb --- /dev/null +++ b/deepmd/utils/loggers.py @@ -0,0 +1,50 @@ + +"""Logger initialization for package.""" + +import logging +from typing import TYPE_CHECKING +from pathlib import Path + + +if TYPE_CHECKING: + from pathlib import Path + +logging.getLogger(__name__) + +__all__ = ["set_log_handles"] + +# logger formater +FFORMATTER = logging.Formatter("[%(asctime)s] %(levelname)-7s %(name)-45s " + "%(message)s") +CFORMATTER = logging.Formatter("%(levelname)-7s |-> %(name)-45s %(message)s") + + +def set_log_handles(level: int, log_path: "Path"): + """Set desired level for package loggers and add file handlers. + + Parameters + ---------- + level: int + logging level + log_path: Path + path to log file + """ + root_log = logging.getLogger() + + # remove all old handlers + root_log.setLevel(level) + for hdlr in root_log.handlers[:]: + root_log.removeHandler(hdlr) + + # add console handler + ch = logging.StreamHandler() + ch.setLevel(level) + ch.setFormatter(CFORMATTER) + root_log.addHandler(ch) + + # add file handler + ch = logging.FileHandler(log_path, mode="w") + ch.setLevel(level) + ch.setFormatter(FFORMATTER) + root_log.addHandler(ch) + diff --git a/deepmd/utils/network.py b/deepmd/utils/network.py index e06f882291..6bebcd044e 100644 --- a/deepmd/utils/network.py +++ b/deepmd/utils/network.py @@ -1,12 +1,12 @@ import numpy as np from deepmd.env import tf -from deepmd.RunOptions import global_tf_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION def one_layer(inputs, outputs_size, activation_fn=tf.nn.tanh, - precision = global_tf_float_precision, + precision = GLOBAL_TF_FLOAT_PRECISION, stddev=1.0, bavg=0.0, name='linear', diff --git a/doc/api.rst b/doc/api.rst index 17604ae010..5163294601 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -65,7 +65,7 @@ DeePMD-kit API :members: :undoc-members: -.. automodule:: deepmd.Local +.. automodule:: deepmd.local :members: :undoc-members: @@ -73,7 +73,7 @@ DeePMD-kit API :members: :undoc-members: -.. automodule:: deepmd.Model +.. automodule:: deepmd.model :members: :undoc-members: @@ -85,7 +85,7 @@ DeePMD-kit API :members: :undoc-members: -.. automodule:: deepmd.Trainer +.. automodule:: deepmd.trainer :members: :undoc-members: diff --git a/source/tests/common.py b/source/tests/common.py index b3374cff80..c1cbb5bd65 100644 --- a/source/tests/common.py +++ b/source/tests/common.py @@ -2,11 +2,11 @@ import numpy as np from deepmd.env import tf -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision -from deepmd.RunOptions import global_ener_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION -if global_np_float_precision == np.float32 : +if GLOBAL_NP_FLOAT_PRECISION == np.float32 : global_default_fv_hh = 1e-2 global_default_dw_hh = 1e-2 global_default_places = 3 diff --git a/source/tests/test_data_modifier.py b/source/tests/test_data_modifier.py index c0091bc21c..d1104ae6c5 100644 --- a/source/tests/test_data_modifier.py +++ b/source/tests/test_data_modifier.py @@ -4,12 +4,12 @@ from deepmd.env import tf from deepmd.common import j_must_have, data_requirement, j_loader -from deepmd.RunOptions import RunOptions -from deepmd.Trainer import NNPTrainer +from deepmd.run_options import RunOptions +from deepmd.trainer import NNPTrainer from deepmd.utils.data_system import DeepmdDataSystem -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision -from deepmd.RunOptions import global_ener_float_precision +from deepmd.run_options import global_tf_float_precision +from deepmd.run_options import global_np_float_precision +from deepmd.run_options import global_ener_float_precision from deepmd.infer.ewald_recp import EwaldRecp from deepmd.infer.data_modifier import DipoleChargeModifier diff --git a/source/tests/test_data_modifier_shuffle.py b/source/tests/test_data_modifier_shuffle.py index 691589cfb4..457020c31e 100644 --- a/source/tests/test_data_modifier_shuffle.py +++ b/source/tests/test_data_modifier_shuffle.py @@ -5,12 +5,12 @@ from deepmd.env import tf from deepmd.common import j_must_have, data_requirement -from deepmd.RunOptions import RunOptions -from deepmd.Trainer import NNPTrainer +from deepmd.run_options import RunOptions +from deepmd.trainer import NNPTrainer from deepmd.utils.data_system import DeepmdDataSystem -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision -from deepmd.RunOptions import global_ener_float_precision +from deepmd.run_options import global_tf_float_precision +from deepmd.run_options import global_np_float_precision +from deepmd.run_options import global_ener_float_precision from deepmd.infer.ewald_recp import EwaldRecp from deepmd.infer.data_modifier import DipoleChargeModifier from deepmd.infer.deep_dipole import DeepDipole diff --git a/source/tests/test_deepmd_data.py b/source/tests/test_deepmd_data.py index 18a27630e3..49314faf81 100644 --- a/source/tests/test_deepmd_data.py +++ b/source/tests/test_deepmd_data.py @@ -3,7 +3,7 @@ import unittest from deepmd.utils.data import DeepmdData -from deepmd.RunOptions import global_np_float_precision +from deepmd.run_options import global_np_float_precision if global_np_float_precision == np.float32 : places = 6 diff --git a/source/tests/test_deepmd_data_sys.py b/source/tests/test_deepmd_data_sys.py index 4a706ba870..1e6c46ba10 100644 --- a/source/tests/test_deepmd_data_sys.py +++ b/source/tests/test_deepmd_data_sys.py @@ -3,7 +3,7 @@ import unittest from deepmd.utils.data_system import DeepmdDataSystem -from deepmd.RunOptions import global_np_float_precision +from deepmd.run_options import global_np_float_precision if global_np_float_precision == np.float32 : places = 6 diff --git a/source/tests/test_descrpt_nonsmth.py b/source/tests/test_descrpt_nonsmth.py index dbed5b3757..a4457f70c8 100644 --- a/source/tests/test_descrpt_nonsmth.py +++ b/source/tests/test_descrpt_nonsmth.py @@ -19,9 +19,9 @@ from deepmd.env import op_module -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision -from deepmd.RunOptions import global_ener_float_precision +from deepmd.run_options import global_tf_float_precision +from deepmd.run_options import global_np_float_precision +from deepmd.run_options import global_ener_float_precision class Inter(): def setUp (self, diff --git a/source/tests/test_descrpt_se_ar.py b/source/tests/test_descrpt_se_ar.py index ce4edad316..79153fe6c6 100644 --- a/source/tests/test_descrpt_se_ar.py +++ b/source/tests/test_descrpt_se_ar.py @@ -21,9 +21,9 @@ from deepmd.descriptor import DescrptSeAR -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision -from deepmd.RunOptions import global_ener_float_precision +from deepmd.run_options import global_tf_float_precision +from deepmd.run_options import global_np_float_precision +from deepmd.run_options import global_ener_float_precision class Inter(): def setUp (self, diff --git a/source/tests/test_descrpt_se_r.py b/source/tests/test_descrpt_se_r.py index 07e652e06d..c4a4661bc4 100644 --- a/source/tests/test_descrpt_se_r.py +++ b/source/tests/test_descrpt_se_r.py @@ -21,9 +21,9 @@ from deepmd.env import op_module -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision -from deepmd.RunOptions import global_ener_float_precision +from deepmd.run_options import global_tf_float_precision +from deepmd.run_options import global_np_float_precision +from deepmd.run_options import global_ener_float_precision class Inter(): def setUp (self, diff --git a/source/tests/test_descrpt_sea_ef.py b/source/tests/test_descrpt_sea_ef.py index ee963e22e1..76b41df617 100644 --- a/source/tests/test_descrpt_sea_ef.py +++ b/source/tests/test_descrpt_sea_ef.py @@ -21,9 +21,9 @@ from deepmd.env import op_module -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision -from deepmd.RunOptions import global_ener_float_precision +from deepmd.run_options import global_tf_float_precision +from deepmd.run_options import global_np_float_precision +from deepmd.run_options import global_ener_float_precision class Inter(): def setUp (self, diff --git a/source/tests/test_descrpt_sea_ef_para.py b/source/tests/test_descrpt_sea_ef_para.py index 6057599d10..1642fedc9a 100644 --- a/source/tests/test_descrpt_sea_ef_para.py +++ b/source/tests/test_descrpt_sea_ef_para.py @@ -21,9 +21,9 @@ from deepmd.env import op_module -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision -from deepmd.RunOptions import global_ener_float_precision +from deepmd.run_options import global_tf_float_precision +from deepmd.run_options import global_np_float_precision +from deepmd.run_options import global_ener_float_precision class Inter(): def setUp (self, diff --git a/source/tests/test_descrpt_sea_ef_rot.py b/source/tests/test_descrpt_sea_ef_rot.py index 461485150d..5dd5c35818 100644 --- a/source/tests/test_descrpt_sea_ef_rot.py +++ b/source/tests/test_descrpt_sea_ef_rot.py @@ -4,9 +4,9 @@ from deepmd.env import tf from tensorflow.python.framework import ops -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision -from deepmd.RunOptions import global_ener_float_precision +from deepmd.run_options import global_tf_float_precision +from deepmd.run_options import global_np_float_precision +from deepmd.run_options import global_ener_float_precision from deepmd.env import op_module from deepmd.descriptor import DescrptSeA diff --git a/source/tests/test_descrpt_sea_ef_vert.py b/source/tests/test_descrpt_sea_ef_vert.py index 062c4ac424..d1784754d5 100644 --- a/source/tests/test_descrpt_sea_ef_vert.py +++ b/source/tests/test_descrpt_sea_ef_vert.py @@ -21,9 +21,9 @@ from deepmd.env import op_module -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision -from deepmd.RunOptions import global_ener_float_precision +from deepmd.run_options import global_tf_float_precision +from deepmd.run_options import global_np_float_precision +from deepmd.run_options import global_ener_float_precision class Inter(): def setUp (self, diff --git a/source/tests/test_descrpt_smooth.py b/source/tests/test_descrpt_smooth.py index 2ebe049bd4..09eba2a36c 100644 --- a/source/tests/test_descrpt_smooth.py +++ b/source/tests/test_descrpt_smooth.py @@ -21,9 +21,9 @@ from deepmd.env import op_module -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision -from deepmd.RunOptions import global_ener_float_precision +from deepmd.run_options import global_tf_float_precision +from deepmd.run_options import global_np_float_precision +from deepmd.run_options import global_ener_float_precision class Inter(): def setUp (self, diff --git a/source/tests/test_embedding_net.py b/source/tests/test_embedding_net.py index 3a1a15c42e..c508b461da 100644 --- a/source/tests/test_embedding_net.py +++ b/source/tests/test_embedding_net.py @@ -7,9 +7,9 @@ from deepmd.utils.network import embedding_net -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision -from deepmd.RunOptions import global_ener_float_precision +from deepmd.run_options import global_tf_float_precision +from deepmd.run_options import global_np_float_precision +from deepmd.run_options import global_ener_float_precision class Inter(unittest.TestCase): def setUp (self) : diff --git a/source/tests/test_ewald.py b/source/tests/test_ewald.py index b8fc0731b8..02a7091a1f 100644 --- a/source/tests/test_ewald.py +++ b/source/tests/test_ewald.py @@ -3,9 +3,9 @@ import unittest from deepmd.env import tf -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_np_float_precision -from deepmd.RunOptions import global_ener_float_precision +from deepmd.run_options import global_tf_float_precision +from deepmd.run_options import global_np_float_precision +from deepmd.run_options import global_ener_float_precision from deepmd.infer.ewald_recp import op_module from deepmd.infer.ewald_recp import EwaldRecp diff --git a/source/tests/test_gen_stat_data.py b/source/tests/test_gen_stat_data.py index 1dd9300ea4..f70d63c3e9 100644 --- a/source/tests/test_gen_stat_data.py +++ b/source/tests/test_gen_stat_data.py @@ -5,7 +5,7 @@ from deepmd.utils.data_system import DeepmdDataSystem from deepmd.fit import EnerFitting -from deepmd.Model import make_stat_input, merge_sys_stat, _make_all_stat_ref +from deepmd.model import make_stat_input, merge_sys_stat, _make_all_stat_ref def gen_sys(nframes, atom_types): natoms = len(atom_types) diff --git a/source/tests/test_model_loc_frame.py b/source/tests/test_model_loc_frame.py index f18018c653..0ed30e7c00 100644 --- a/source/tests/test_model_loc_frame.py +++ b/source/tests/test_model_loc_frame.py @@ -3,11 +3,11 @@ from deepmd.env import tf from common import Data,gen_data -from deepmd.RunOptions import RunOptions +from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptLocFrame from deepmd.fit import EnerFitting -from deepmd.Model import Model +from deepmd.model import Model from deepmd.common import j_must_have, j_loader global_ener_float_precision = tf.float64 diff --git a/source/tests/test_model_se_a.py b/source/tests/test_model_se_a.py index 968d5001f1..62fedfe7a5 100644 --- a/source/tests/test_model_se_a.py +++ b/source/tests/test_model_se_a.py @@ -4,11 +4,11 @@ from deepmd.env import tf from common import Data,gen_data -from deepmd.RunOptions import RunOptions +from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting -from deepmd.Model import Model +from deepmd.model import Model from deepmd.common import j_must_have, j_loader global_ener_float_precision = tf.float64 diff --git a/source/tests/test_model_se_a_aparam.py b/source/tests/test_model_se_a_aparam.py index 725f3aea3e..29f3539505 100644 --- a/source/tests/test_model_se_a_aparam.py +++ b/source/tests/test_model_se_a_aparam.py @@ -3,11 +3,11 @@ from deepmd.env import tf from common import Data,gen_data -from deepmd.RunOptions import RunOptions +from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting -from deepmd.Model import Model +from deepmd.model import Model from deepmd.common import j_must_have, j_loader global_ener_float_precision = tf.float64 diff --git a/source/tests/test_model_se_a_fparam.py b/source/tests/test_model_se_a_fparam.py index 38d37291d0..79932d0014 100644 --- a/source/tests/test_model_se_a_fparam.py +++ b/source/tests/test_model_se_a_fparam.py @@ -3,11 +3,11 @@ from deepmd.env import tf from common import Data,gen_data -from deepmd.RunOptions import RunOptions +from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting -from deepmd.Model import Model +from deepmd.model import Model from deepmd.common import j_must_have, j_loader global_ener_float_precision = tf.float64 diff --git a/source/tests/test_model_se_a_srtab.py b/source/tests/test_model_se_a_srtab.py index 3f2649ae36..b967c78fb6 100644 --- a/source/tests/test_model_se_a_srtab.py +++ b/source/tests/test_model_se_a_srtab.py @@ -3,11 +3,11 @@ from deepmd.env import tf from common import Data,gen_data -from deepmd.RunOptions import RunOptions +from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting -from deepmd.Model import Model +from deepmd.model import Model from deepmd.common import j_must_have, j_loader global_ener_float_precision = tf.float64 diff --git a/source/tests/test_model_se_r.py b/source/tests/test_model_se_r.py index 978f27cc2e..32aa43235b 100644 --- a/source/tests/test_model_se_r.py +++ b/source/tests/test_model_se_r.py @@ -3,11 +3,11 @@ from deepmd.env import tf from common import Data,gen_data -from deepmd.RunOptions import RunOptions +from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeR from deepmd.fit import EnerFitting -from deepmd.Model import Model +from deepmd.model import Model from deepmd.common import j_must_have, j_loader global_ener_float_precision = tf.float64 diff --git a/source/tests/test_polar_se_a.py b/source/tests/test_polar_se_a.py index 1178949c4f..a36553b296 100644 --- a/source/tests/test_polar_se_a.py +++ b/source/tests/test_polar_se_a.py @@ -3,11 +3,11 @@ from deepmd.env import tf from common import Data,gen_data -from deepmd.RunOptions import RunOptions +from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeA from deepmd.fit import PolarFittingSeA -from deepmd.Model import PolarModel +from deepmd.model import PolarModel from deepmd.common import j_must_have, j_loader global_ener_float_precision = tf.float64 diff --git a/source/tests/test_wfc.py b/source/tests/test_wfc.py index 70f9968409..9319d9b9cf 100644 --- a/source/tests/test_wfc.py +++ b/source/tests/test_wfc.py @@ -3,11 +3,11 @@ from deepmd.env import tf from common import Data,gen_data -from deepmd.RunOptions import RunOptions +from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptLocFrame from deepmd.fit import WFCFitting -from deepmd.Model import WFCModel +from deepmd.model import WFCModel from deepmd.common import j_must_have, j_loader global_ener_float_precision = tf.float64 diff --git a/source/train/CMakeLists.txt b/source/train/CMakeLists.txt index 818b2f4225..72e4b8acaa 100644 --- a/source/train/CMakeLists.txt +++ b/source/train/CMakeLists.txt @@ -1,20 +1,22 @@ # train -configure_file("RunOptions.py.in" "${CMAKE_CURRENT_BINARY_DIR}/RunOptions.py" @ONLY) +configure_file("run_config.ini" "${CMAKE_CURRENT_BINARY_DIR}/run_config.ini" @ONLY) -file(GLOB LIB_PY main.py calculator.py Model*.py Trainer.py ${CMAKE_CURRENT_BINARY_DIR}/RunOptions.py transform.py doc.py) +file(GLOB LIB_PY main.py calculator.py model.py trainer.py run_options.py transform.py doc.py) -file(GLOB CLS_PY Local.py Slurm.py) - -install( +sinstall( FILES ${LIB_PY} DESTINATION deepmd ) install( - FILES ${CLS_PY} + DIRECTORY cluster DESTINATION deepmd/cluster ) install( FILES train.py test.py DESTINATION deepmd ) +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/run_config.ini + DESTINATION deepmd/config +) \ No newline at end of file diff --git a/source/train/Local.py b/source/train/Local.py deleted file mode 100644 index d2564ff17c..0000000000 --- a/source/train/Local.py +++ /dev/null @@ -1,13 +0,0 @@ -import os, socket - -def get_resource (): - nodename = socket.gethostname() - nodelist = [nodename] - gpus = os.getenv('CUDA_VISIBLE_DEVICES') - if gpus is not None : - if gpus != "" : - gpus = gpus.split(",") - gpus = [int(ii) for ii in gpus] - else : - gpus = [] - return nodename, nodelist, gpus diff --git a/source/train/RunOptions.py.in b/source/train/RunOptions.py.in deleted file mode 100644 index 63d3544ca6..0000000000 --- a/source/train/RunOptions.py.in +++ /dev/null @@ -1,238 +0,0 @@ -import os,sys -from deepmd.env import tf -from deepmd.env import get_tf_default_nthreads -import numpy as np -import deepmd.cluster.Slurm as Slurm -import deepmd.cluster.Local as Local - -if "@PREC_DEF@" == "-DHIGH_PREC" : - global_tf_float_precision = tf.float64 - global_np_float_precision = np.float64 - global_ener_float_precision = np.float64 - global_float_prec = 'double' -else : - global_tf_float_precision = tf.float32 - global_np_float_precision = np.float32 - global_ener_float_precision = np.float64 - global_float_prec = 'float' - -def global_cvt_2_tf_float(xx) : - return tf.cast(xx, global_tf_float_precision) -def global_cvt_2_ener_float(xx) : - return tf.cast(xx, global_ener_float_precision) - -global_install_prefix='@CMAKE_INSTALL_PREFIX@' -global_git_summ='@GIT_SUMM@' -global_git_hash='@GIT_HASH@' -global_git_date='@GIT_DATE@' -global_git_branch='@GIT_BRANCH@' -global_tf_include_dir='@TensorFlow_INCLUDE_DIRS@' -global_tf_libs='@TensorFlow_LIBRARY@' - -def _is_slurm() : - return "SLURM_JOB_NODELIST" in os.environ - -def _is_distributed(MPI) : - return MPI.COMM_WORLD.Get_size() > 1 - -def distributed_task_config (MPI, - node_name, - node_list_, - gpu_list = None, - default_port = 2222) : - """ - create configuration for distributed tensorflow session. - inputs: - MPI mpi4py.MPI - node_name str, the name of the this node - node_list [str], the list of nodes of the current mpirun - gpu_list [int], the list of GPUs on each node - default_port int, the default port for socket communication - outputs: - cluster map, cluster_spec - job str, the job name of this task - task_idx int, the index of this task - socket str, hostname:port socket of this task - device str, the device for this task - """ - # setup cluster - node_list = list(set(node_list_)) - node_list.sort() - node_color = node_list.index(node_name) - world_idx = MPI.COMM_WORLD.Get_rank() - node_comm = MPI.COMM_WORLD.Split(node_color, world_idx) - node_task_idx = node_comm.Get_rank() - node_numb_task = node_comm.Get_size() - socket_list = [] - for ii in node_list : - for jj in range(node_numb_task) : - socket_list.append(ii + ":" + str(default_port+jj)) - ps_map = socket_list[0:1] - worker_map = socket_list[1:] - if node_color == 0 and node_task_idx == 0 : - my_job = 'ps' - my_socket = ps_map[0] - my_task_idx = ps_map.index(my_socket) - else : - my_job = 'worker' - my_socket = node_name + ":" + str(default_port+node_task_idx) - assert(my_socket in worker_map) - my_task_idx = worker_map.index(my_socket) - # setup gpu/cpu devices - if gpu_list is not None : - numb_gpu = len(gpu_list) - gpu_idx = node_numb_task - node_task_idx - 1 - if gpu_idx >= numb_gpu : - # my_device = "cpu:%d" % node_task_idx - my_device = "cpu:0" - else : - my_device = "gpu:%d" % gpu_idx - else : - # my_device = "cpu:%d" % node_task_idx - my_device = "cpu:0" - # return results - cluster = {"worker": worker_map, "ps" : ps_map} - return cluster, my_job, my_task_idx, my_socket, my_device - - -class RunOptions (object) : - def __init__ (self, - args, - try_distrib = False): - # distributed tasks - if try_distrib : - self._try_init_mpi() - else : - self.is_distrib = False - self._init_serial() - self.verbose = self.is_chief - - # model init options - # default set - self.restart = None - self.init_model = None - self.init_mode = "init_from_scratch" - if args is not None : - if (args.init_model is not None) and (args.restart is not None) : - raise RuntimeError ("--init-model and --restart should not be set at the same time") - if args.init_model is not None : - self.init_model = os.path.abspath(args.init_model) - self.init_mode = "init_from_model" - if args.restart is not None: - self.restart = os.path.abspath(args.restart) - self.init_mode = "restart" - - def message (self, msg) : - if self.verbose : - lines = msg.split('\n') - for ii in lines : - print ("# DEEPMD: " + str(ii)) - sys.stdout.flush() - - def print_welcome(self) : - # http://patorjk.com/software/taag. Font:Big" - msg = "" - msg += " _____ _____ __ __ _____ _ _ _ \n" - msg += "| __ \ | __ \ | \/ || __ \ | | (_)| | \n" - msg += "| | | | ___ ___ | |__) || \ / || | | | ______ | | __ _ | |_ \n" - msg += "| | | | / _ \ / _ \| ___/ | |\/| || | | ||______|| |/ /| || __|\n" - msg += "| |__| || __/| __/| | | | | || |__| | | < | || |_ \n" - msg += "|_____/ \___| \___||_| |_| |_||_____/ |_|\_\|_| \__|\n" - self.message(msg) - - def print_citation(self) : - msg = "" - msg += "Please read and cite:\n" - msg += "Wang, Zhang, Han and E, Comput.Phys.Comm. 228, 178-184 (2018)\n" - self.message(msg) - - def print_build(self): - msg = '' - msg += 'source code %s at brach %s commit at %s' % (global_git_hash, global_git_branch, global_git_date) - self.message(msg) - - def print_summary(self) : - msg = "" - msg += "---Summary of the training---------------------------------------\n" - msg += 'installed to: %s\n' % global_install_prefix - msg += 'source : %s\n' % global_git_summ - msg += 'source brach: %s\n' % global_git_branch - msg += 'source commit: %s\n' % global_git_hash - msg += 'source commit at: %s\n' % global_git_date - msg += 'build float prec: %s\n' % global_float_prec - msg += 'build with tf inc: %s\n' % global_tf_include_dir - for idx,ii in enumerate(global_tf_libs.split(';')) : - if idx == 0 : - msg += 'build with tf lib: %s\n' % ii - else : - msg += ' %s\n' % ii - if self.is_distrib: - msg += "distributed\n" - msg += "ps list: %s\n" % str(self.cluster['ps']) - msg += "worker list: %s\n" % str(self.cluster['worker']) - msg += "chief on: %s\n" % self.nodename - else : - msg += "running on: %s\n" % self.nodename - if self.gpus is None: - msg += "CUDA_VISIBLE_DEVICES: unset\n" - else: - msg += "CUDA_VISIBLE_DEVICES: %s\n" % self.gpus - intra, inter = get_tf_default_nthreads() - msg += "num_intra_threads: %d\n" % intra - msg += "num_inter_threads: %d\n" % inter - msg += "-----------------------------------------------------------------\n" - self.message(msg) - - def _try_init_mpi(self): - try : - from mpi4py import MPI - except ImportError : - raise RuntimeError("cannot import mpi4py module, cannot do distributed simulation") - else : - self.is_distrib = _is_distributed(MPI) - if self.is_distrib : - self._init_distributed(MPI) - else : - self._init_serial() - - def _init_distributed(self, MPI) : - # Run options for distributed training - if _is_slurm() : - nodename, nodelist, gpus = Slurm.get_resource() - else : - nodename, nodelist, gpus = Local.get_resource() - self.nodename = nodename - self.gpus = gpus - self.cluster, \ - self.my_job_name, \ - self.my_task_index, \ - self.my_socket, \ - self.my_device \ - = distributed_task_config(MPI, nodename, nodelist, gpus) - self.is_chief = (self.my_job_name == 'worker' and self.my_task_index == 0) - self.num_ps = len(self.cluster['ps']) - self.num_workers = len(self.cluster['worker']) - self.cluster_spec = tf.train.ClusterSpec(self.cluster) - self.server = tf.train.Server(server_or_cluster_def = self.cluster_spec, - job_name = self.my_job_name, - task_index = self.my_task_index) - - def _init_serial(self) : - # Run options for serial training - nodename, nodelist, gpus = Local.get_resource() - self.nodename = nodename - self.gpus = gpus - self.cluster = None - self.my_job_name = nodename - self.my_task_index = 0 - self.my_socket = None - if gpus is not None and len(gpus) > 0: - self.my_device = "gpu:%d" % gpus[0] - # self.my_device = "gpu:0" - else : - self.my_device = "cpu:0" - self.is_chief = True - self.num_ps = None - self.num_workers = None - self.cluster_spec = None - self.server = None diff --git a/source/train/Slurm.py b/source/train/Slurm.py deleted file mode 100644 index dc9f8c49bb..0000000000 --- a/source/train/Slurm.py +++ /dev/null @@ -1,55 +0,0 @@ -#### https://github.com/deepsense-ai/tensorflow_on_slurm #### - -# from __future__ import print_function -# from __future__ import absolute_import -# from __future__ import division - -import re -import os - -def get_resource (): - nodelist = os.environ["SLURM_JOB_NODELIST"] - nodelist = _expand_nodelist(nodelist) - nodename = os.environ["SLURMD_NODENAME"] - num_nodes = int(os.getenv("SLURM_JOB_NUM_NODES")) - if len(nodelist) != num_nodes: - raise ValueError("Number of slurm nodes {} not equal to {}".format(len(nodelist), num_nodes)) - if nodename not in nodelist: - raise ValueError("Nodename({}) not in nodelist({}). This should not happen! ".format(nodename,nodelist)) - gpus = os.getenv('CUDA_VISIBLE_DEVICES') - if gpus is not None : - gpus = gpus.split(",") - gpus = [int(ii) for ii in gpus] - return nodename, nodelist, gpus - -def _pad_zeros(iterable, length): - return (str(t).rjust(length, '0') for t in iterable) - -def _expand_ids(ids): - ids = ids.split(',') - result = [] - for id in ids: - if '-' in id: - str_end = id.split('-')[1] - begin, end = [int(token) for token in id.split('-')] - result.extend(_pad_zeros(range(begin, end+1), len(str_end))) - else: - result.append(id) - return result - -def _expand_nodelist(nodelist): - result = [] - interval_list = nodelist.split(',') - for interval in interval_list: - match = re.search("(.*)\[(.*)\]", interval) - if match: - prefix = match.group(1) - ids = match.group(2) - ids = _expand_ids(ids) - result.extend([prefix + str(id) for id in ids]) - else: - result.append(interval) - return result - -def _worker_task_id(nodelist, nodename): - return nodelist.index(nodename) diff --git a/source/train/Trainer.py b/source/train/Trainer.py index 765a25d206..468aca4583 100644 --- a/source/train/Trainer.py +++ b/source/train/Trainer.py @@ -5,8 +5,8 @@ import numpy as np from deepmd.env import tf from deepmd.env import default_tf_session_config -from deepmd.RunOptions import global_tf_float_precision -from deepmd.RunOptions import global_ener_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION from deepmd.fit import EnerFitting, WFCFitting, PolarFittingLocFrame, PolarFittingSeA, GlobalPolarFittingSeA, DipoleFittingSeA from deepmd.descriptor import DescrptLocFrame from deepmd.descriptor import DescrptSeA @@ -16,7 +16,7 @@ from deepmd.descriptor import DescrptSeR from deepmd.descriptor import DescrptSeAR from deepmd.descriptor import DescrptHybrid -from deepmd.Model import Model, WFCModel, DipoleModel, PolarModel, GlobalPolarModel +from deepmd.model import Model, WFCModel, DipoleModel, PolarModel, GlobalPolarModel from deepmd.loss import EnerStdLoss, EnerDipoleLoss, TensorLoss from deepmd.utils.learning_rate import LearningRateExp @@ -294,9 +294,9 @@ def _build_network(self, data): for kk in data_dict.keys(): if kk == 'type': continue - prec = global_tf_float_precision + prec = GLOBAL_TF_FLOAT_PRECISION if data_dict[kk]['high_prec'] : - prec = global_ener_float_precision + prec = GLOBAL_ENER_FLOAT_PRECISION self.place_holders[kk] = tf.placeholder(prec, [None], name = 't_' + kk) self.place_holders['find_'+kk] = tf.placeholder(tf.float32, name = 't_find_' + kk) diff --git a/source/train/calculator.py b/source/train/calculator.py index d86de92183..8ddda75942 100644 --- a/source/train/calculator.py +++ b/source/train/calculator.py @@ -2,7 +2,7 @@ from typing import TYPE_CHECKING, Dict, List, Optional, Union -import deepmd.DeepPot as DeepPot +from deepmd import DeepPot from ase.calculators.calculator import Calculator, all_changes if TYPE_CHECKING: @@ -10,6 +10,7 @@ from ase import Atoms +__all__ = ["DP"] class DP(Calculator): """Implementation of ASE deepmd calculator. diff --git a/source/train/cluster/__init__.py b/source/train/cluster/__init__.py new file mode 100644 index 0000000000..1875b21f9b --- /dev/null +++ b/source/train/cluster/__init__.py @@ -0,0 +1,22 @@ +"""Module that reads node resources, auto detects if running local or on SLURM.""" + +from .local import get_resource as get_local_res +from .slurm import get_resource as get_slurm_res +import os +from typing import List, Tuple, Optional + +__all__ = ["get_resource"] + + +def get_resource() -> Tuple[str, List[str], Optional[List[int]]]: + """Get local or slurm resources: nodename, nodelist, and gpus. + + Returns + ------- + Tuple[str, List[str], Optional[List[int]]] + nodename, nodelist, and gpus + """ + if "SLURM_JOB_NODELIST" in os.environ: + return get_slurm_res() + else: + return get_local_res() diff --git a/source/train/cluster/local.py b/source/train/cluster/local.py new file mode 100644 index 0000000000..6737c89785 --- /dev/null +++ b/source/train/cluster/local.py @@ -0,0 +1,26 @@ +"""Get local GPU resources from `CUDA_VISIBLE_DEVICES` enviroment variable.""" + +import os +import socket +from typing import List, Tuple, Optional + +__all__ = ["get_resource"] + + +def get_resource() -> Tuple[str, List[str], Optional[List[int]]]: + """Get local resources: nodename, nodelist, and gpus. + + Returns + ------- + Tuple[str, List[str], Optional[List[int]]] + nodename, nodelist, and gpus + """ + nodename = socket.gethostname() + nodelist = [nodename] + gpus_env = os.getenv("CUDA_VISIBLE_DEVICES", None) + if not gpus_env: + gpus = None + else: + gpus = [int(gpu) for gpu in gpus_env.split(",")] + + return nodename, nodelist, gpus diff --git a/source/train/cluster/slurm.py b/source/train/cluster/slurm.py new file mode 100644 index 0000000000..df4ac3dbf9 --- /dev/null +++ b/source/train/cluster/slurm.py @@ -0,0 +1,84 @@ +"""MOdule to get resources on SLURM cluster. + +References +---------- +https://github.com/deepsense-ai/tensorflow_on_slurm #### +""" + +import re +import os +from typing import List, Tuple, Optional, Iterable + +__all__ = ["get_resource"] + + +def get_resource() -> Tuple[str, List[str], Optional[List[int]]]: + """Get SLURM resources: nodename, nodelist, and gpus. + + Returns + ------- + Tuple[str, List[str], Optional[List[int]]] + nodename, nodelist, and gpus + + Raises + ------ + RuntimeError + if number of nodes could not be retrieved + ValueError + list of nodes is not of the same length sa number of nodes + ValueError + if current nodename is not found in node list + """ + nodelist = _expand_nodelist(os.environ["SLURM_JOB_NODELIST"]) + nodename = os.environ["SLURMD_NODENAME"] + num_nodes_env = os.getenv("SLURM_JOB_NUM_NODES") + if num_nodes_env: + num_nodes = int(num_nodes_env) + else: + raise RuntimeError("Could not get SLURM number of nodes") + + if len(nodelist) != num_nodes: + raise ValueError( + f"Number of slurm nodes {len(nodelist)} not equal to {num_nodes}" + ) + if nodename not in nodelist: + raise ValueError( + f"Nodename({nodename}) not in nodelist({nodelist}). This should not happen!" + ) + gpus_env = os.getenv("CUDA_VISIBLE_DEVICES") + if not gpus_env: + gpus = None + else: + gpus = [int(gpu) for gpu in gpus_env.split(",")] + return nodename, nodelist, gpus + + +def _pad_zeros(iterable: Iterable, length: int): + return (str(t).rjust(length, "0") for t in iterable) + + +def _expand_ids(ids: str) -> List[str]: + result = [] + for _id in ids.split(","): + if "-" in _id: + str_end = _id.split("-")[1] + begin, end = [int(token) for token in _id.split("-")] + result.extend(_pad_zeros(range(begin, end + 1), len(str_end))) + else: + result.append(_id) + return result + + +def _expand_nodelist(nodelist: str) -> List[str]: + result = [] + interval_list = nodelist.split(",") + for interval in interval_list: + match = re.search(r"(.*)\[(.*)\]", interval) + if match: + prefix = match.group(1) + ids = match.group(2) + ids_list = _expand_ids(ids) + result.extend([f"{prefix}{_id}" for _id in ids_list]) + else: + result.append(interval) + return result diff --git a/source/train/Model.py b/source/train/model.py similarity index 99% rename from source/train/Model.py rename to source/train/model.py index 9c9cd7ddff..2cc9763c59 100644 --- a/source/train/Model.py +++ b/source/train/model.py @@ -4,7 +4,7 @@ from deepmd.utils.tab_inter import TabInter from deepmd.common import ClassArg -from deepmd.RunOptions import global_cvt_2_ener_float +from deepmd.run_options import global_cvt_2_ener_float from deepmd.env import op_module diff --git a/source/train/print_old_model.py b/source/train/print_old_model.py index d125e7f8b6..0e8d65eba7 100644 --- a/source/train/print_old_model.py +++ b/source/train/print_old_model.py @@ -8,10 +8,10 @@ lib_path = os.path.dirname(os.path.realpath(__file__)) + ".." sys.path.append (lib_path) -from deepmd.RunOptions import RunOptions +from deepmd.run_options import RunOptions from deepmd.DataSystem import DataSystem -from deepmd.Model import NNPModel -from deepmd.Model import LearingRate +from deepmd.model import NNPModel +from deepmd.model import LearingRate from deepmd.common import j_must_have, j_loader def gen_data() : diff --git a/source/train/run_config.ini b/source/train/run_config.ini new file mode 100644 index 0000000000..5579f13134 --- /dev/null +++ b/source/train/run_config.ini @@ -0,0 +1,9 @@ +[CONFIG] +INSTALL_PREFIX = @CMAKE_INSTALL_PREFIX@ +GIT_SUMM = @GIT_SUMM@ +GIT_HASH = @GIT_HASH@ +GIT_DATE = @GIT_DATE@ +GIT_BRANCH = @GIT_BRANCH@ +TF_INCLUDE_DIR = @TensorFlow_INCLUDE_DIRS@ +TF_LIBS = @TensorFlow_LIBRARY@ +PRECISION = @PREC_DEF@ \ No newline at end of file diff --git a/source/train/run_options.py b/source/train/run_options.py new file mode 100644 index 0000000000..4d16a76dad --- /dev/null +++ b/source/train/run_options.py @@ -0,0 +1,383 @@ +"""Module taking care of important package constants.""" + +import os +import sys +from configparser import ConfigParser +from typing import TYPE_CHECKING, Dict, List, Optional, Tuple + +import numpy as np +from deepmd.cluster import get_resource +from deepmd.env import get_tf_default_nthreads, tf + +if TYPE_CHECKING: + try: + from typing import Protocol # python >=3.8 + except ImportError: + from typing_extensions import Protocol # type: ignore + + from mpi4py import MPI + + class ArgsProto(Protocol): + """Prococol mimicking parser object.""" + + init_model: Optional[str] + restart: Optional[str] + +__all__ = [ + "GLOBAL_TF_FLOAT_PRECISION", + "GLOBAL_NP_FLOAT_PRECISION", + "GLOBAL_ENER_FLOAT_PRECISION", + "WELCOME", + "CITATION", + "BUILD", + "global_cvt_2_tf_float", + "global_cvt_2_ener_float", + "RunOptions" +] + + +def _get_package_constants( + config_file: str = "config/run_config.ini", +) -> Dict[str, str]: + """Read package constants set at compile time by CMake to dictionary. + + Parameters + ---------- + config_file : str, optional + path to CONFIG file, by default "config/run_config.ini" + + Returns + ------- + Dict[str, str] + dictionary with package constants + """ + config = ConfigParser() + config.read(config_file) + return dict(config.items("CONFIG")) + + +GLOBAL_CONFIG = _get_package_constants() + +if GLOBAL_CONFIG["PRECISION"] == "-DHIGH_PREC": + GLOBAL_TF_FLOAT_PRECISION = tf.float64 + GLOBAL_NP_FLOAT_PRECISION = np.float64 + GLOBAL_ENER_FLOAT_PRECISION = np.float64 + global_float_prec = "double" +else: + GLOBAL_TF_FLOAT_PRECISION = tf.float32 + GLOBAL_NP_FLOAT_PRECISION = np.float32 + GLOBAL_ENER_FLOAT_PRECISION = np.float64 + global_float_prec = "float" + +# http://patorjk.com/software/taag. Font:Big" +WELCOME = ( # noqa + " _____ _____ __ __ _____ _ _ _ \n" + "| __ \ | __ \ | \/ || __ \ | | (_)| | \n" + "| | | | ___ ___ | |__) || \ / || | | | ______ | | __ _ | |_ \n" + "| | | | / _ \ / _ \| ___/ | |\/| || | | ||______|| |/ /| || __|\n" + "| |__| || __/| __/| | | | | || |__| | | < | || |_ \n" + "|_____/ \___| \___||_| |_| |_||_____/ |_|\_\|_| \__|\n" +) + +CITATION = ( + "Please read and cite:\n" + "Wang, Zhang, Han and E, Comput.Phys.Comm. 228, 178-184 (2018)\n" +) + +_sep = '\n ' +BUILD = ( + f"installed to: {GLOBAL_CONFIG['INSTALL_PREFIX']}\n" + f"source : {GLOBAL_CONFIG['GIT_SUMM']}\n" + f"source brach: {GLOBAL_CONFIG['GIT_BRANCH']}\n" + f"source commit: {GLOBAL_CONFIG['GIT_HASH']}\n" + f"source commit at: {GLOBAL_CONFIG['GIT_DATE']}\n" + f"build float prec: {global_float_prec}\n" + f"build with tf inc: {GLOBAL_CONFIG['TF_INCLUDE_DIR']}\n" + f"build with tf lib: {GLOBAL_CONFIG['TF_LIBS'].replace(';', _sep)}" # noqa +) + + +def global_cvt_2_tf_float(xx: tf.Tensor) -> tf.Tensor: + """Cast tensor to globally set TF precision. + + Parameters + ---------- + xx : tf.Tensor + input tensor + + Returns + ------- + tf.Tensor + output tensor cast to `GLOBAL_TF_FLOAT_PRECISION` + """ + return tf.cast(xx, GLOBAL_TF_FLOAT_PRECISION) + + +def global_cvt_2_ener_float(xx: tf.Tensor) -> tf.Tensor: + """Cast tensor to globally set energy precision. + + Parameters + ---------- + xx : tf.Tensor + input tensor + + Returns + ------- + tf.Tensor + output tensor cast to `GLOBAL_ENER_FLOAT_PRECISION` + """ + return tf.cast(xx, GLOBAL_ENER_FLOAT_PRECISION) + + +def _is_distributed(MPI: "MPI") -> bool: + """Check if there are more than one MPI processes. + + Parameters + ---------- + MPI : MPI + MPI object + + Returns + ------- + bool + True if we have more than 1 MPI process + """ + return MPI.COMM_WORLD.Get_size() > 1 + + +def _distributed_task_config( + MPI: "MPI", + node_name: str, + node_list_: List[str], + gpu_list: Optional[List[int]] = None, + default_port: int = 2222, +) -> Tuple[Dict[str, List[str]], str, int, str, str]: + """Create configuration for distributed tensorflow session. + + Parameters + ---------- + MPI : mpi4py.MPI + MPI module + node_name : str + the name of current node + node_list_ : List[str] + the list of nodes of the current mpirun + gpu_list : Optional[List[int]], optional + the list of GPUs on each node, by default None + default_port : int, optional + the default port for socket communication, by default 2222 + + Returns + ------- + Tuple[Dict[str, List[str]], str, int, str, str] + cluster specification, job name of this task, index of this task, + hostname:port socket of this task, the device for this task + """ + # setup cluster + node_list = list(set(node_list_)) + node_list.sort() + node_color = node_list.index(node_name) + world_idx = MPI.COMM_WORLD.Get_rank() + node_comm = MPI.COMM_WORLD.Split(node_color, world_idx) + node_task_idx = node_comm.Get_rank() + node_numb_task = node_comm.Get_size() + + socket_list = [] + for ii in node_list: + for jj in range(node_numb_task): + socket_list.append(f"{ii}:{default_port + jj}") + ps_map = socket_list[0:1] + worker_map = socket_list[1:] + + if node_color == 0 and node_task_idx == 0: + my_job = "ps" + my_socket = ps_map[0] + my_task_idx = ps_map.index(my_socket) + else: + my_job = "worker" + my_socket = f"{node_name}:{default_port - node_task_idx}" + assert my_socket in worker_map + my_task_idx = worker_map.index(my_socket) + + # setup gpu/cpu devices + if gpu_list is not None: + numb_gpu = len(gpu_list) + gpu_idx = node_numb_task - node_task_idx - 1 + if gpu_idx >= numb_gpu: + my_device = "cpu:0" # "cpu:%d" % node_task_idx + else: + my_device = f"gpu:{gpu_idx:d}" + else: + my_device = "cpu:0" # "cpu:%d" % node_task_idx + + cluster = {"worker": worker_map, "ps": ps_map} + return cluster, my_job, my_task_idx, my_socket, my_device + + +class RunOptions: + """Class with inf oon how to run training (cluster, MPI and GPU config). + + Attributes + ---------- + cluster: Optional[Dict[str, List[str]]] + cluster informations as dict + cluster_spec: Optional[tf.train.ClusterSpec] + `tf.train.ClusterSpec` or None if training is serial + gpus: Optional[List[int]] + list of GPUs if any are present else None + is_chief: bool + in distribured training it is true for tha main MPI process in serail it is + always true + my_job_name: str + name of the training job + my_socket: Optional[str] + communication socket for distributed training + my_task_index: int + index of the MPI task + nodename: str + name of the node + num_ps: Optional[int] + number of ps + num_workers: Optional[int] + number of workers + server: Optional[tf.train.Server] + `tf.train.Server` or `None` for serial training + my_device: str + deviice type - gpu or cpu + """ + + cluster: Optional[Dict[str, List[str]]] + cluster_spec: Optional[tf.train.ClusterSpec] + gpus: Optional[List[int]] + is_chief: bool + my_job_name: str + my_socket: Optional[str] + my_task_index: int + nodename: str + num_ps: Optional[int] + num_workers: Optional[int] + server: Optional[tf.train.Server] + my_device: str + + def __init__(self, args: Optional["ArgsProto"], try_distrib: bool = False): + # distributed tasks + if try_distrib: + self._try_init_mpi() + else: + self.is_distrib = False + self._init_serial() + + # model init options + # default set + self.restart = None + self.init_model = None + self.init_mode = "init_from_scratch" + if args is not None: + if all((args.init_model, args.restart)): + raise RuntimeError( + "--init-model and --restart should not be set at the same time" + ) + elif args.init_model is not None: + self.init_model = os.path.abspath(args.init_model) + self.init_mode = "init_from_model" + elif args.restart is not None: + self.restart = os.path.abspath(args.restart) + self.init_mode = "restart" + + def message(self, msg: str): + """Print message if on the main process. + + Parameters + ---------- + msg : str + message to print + """ + if self.is_chief: + lines = msg.split("\n") + for ii in lines: + print(f"# DEEPMD: {ii}") + sys.stdout.flush() + + def print_run_summary(self): + """Print build and current running cluster configuration summary.""" + msg = "" + msg += "---Summary of the training---------------------------------------\n" + if self.is_distrib: + msg += "distributed\n" + msg += f"ps list: {self.cluster['ps']}\n" + msg += f"worker list: {self.cluster['worker']}\n" + msg += f"chief on: {self.nodename}\n" + else: + msg += f"running on: {self.nodename}\n" + if self.gpus is None: + msg += f"CUDA_VISIBLE_DEVICES: unset\n" + else: + msg += f"CUDA_VISIBLE_DEVICES: {self.gpus}\n" + intra, inter = get_tf_default_nthreads() + msg += f"num_intra_threads: {intra:d}\n" + msg += f"num_inter_threads: {inter:d}\n" + msg += "-----------------------------------------------------------------\n" + self.message(msg) + + def _try_init_mpi(self): + try: + from mpi4py import MPI + except ImportError: + raise RuntimeError( + "cannot import mpi4py module, cannot do distributed simulation" + ) + else: + self.is_distrib = _is_distributed(MPI) + if self.is_distrib: + self._init_distributed(MPI) + else: + self._init_serial() + + def _init_distributed(self, MPI: "MPI"): + """Initialize settings for distributed training. + + Parameters + ---------- + MPI : MPI + MPI object + """ + nodename, nodelist, gpus = get_resource() + self.nodename = nodename + self.gpus = gpus + ( + self.cluster, + self.my_job_name, + self.my_task_index, + self.my_socket, + self.my_device, + ) = _distributed_task_config(MPI, nodename, nodelist, gpus) + self.is_chief = self.my_job_name == "worker" and self.my_task_index == 0 + self.num_ps = len(self.cluster["ps"]) + self.num_workers = len(self.cluster["worker"]) + self.cluster_spec = tf.train.ClusterSpec(self.cluster) + self.server = tf.train.Server( + server_or_cluster_def=self.cluster_spec, + job_name=self.my_job_name, + task_index=self.my_task_index, + ) + + def _init_serial(self): + """Initialize setting for serial training.""" + nodename, _, gpus = get_resource() + + self.cluster = None + self.cluster_spec = None + self.gpus = gpus + self.is_chief = True + self.my_job_name = nodename + self.my_socket = None + self.my_task_index = 0 + self.nodename = nodename + self.num_ps = None + self.num_workers = None + self.server = None + + if gpus is not None: + self.my_device = f"gpu:{gpus[0]:d}" + else: + self.my_device = "cpu:0" diff --git a/source/train/train.py b/source/train/train.py index a1702998d9..6bcd3e5e7d 100755 --- a/source/train/train.py +++ b/source/train/train.py @@ -7,8 +7,8 @@ import numpy as np from deepmd.env import tf from deepmd.common import data_requirement, expand_sys_str, j_loader -from deepmd.RunOptions import RunOptions -from deepmd.Trainer import NNPTrainer +from deepmd.run_options import RunOptions, WELCOME, CITATION, BUILD_EXTENDED +from deepmd.trainer import NNPTrainer from deepmd.infer.data_modifier import DipoleChargeModifier from deepmd.utils.data_system import DeepmdDataSystem from deepmd.utils.compat import convert_input_v0_v1 @@ -66,9 +66,10 @@ def train (args) : if 'with_distrib' in jdata: with_distrib = jdata['with_distrib'] run_opt = RunOptions(args, with_distrib) - run_opt.print_welcome() - run_opt.print_citation() - run_opt.print_summary() + run_opt.message(WELCOME) + run_opt.message(CITATION) + run_opt.message(BUILD_EXTENDED) + run_opt.print_run_summary() if run_opt.is_distrib : # distributed training From 934a8bb521a5a7a1309b4ea49e20762fa920c565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Tue, 9 Feb 2021 11:41:17 +0100 Subject: [PATCH 116/562] move cluster folder to deepmd package --- {source/train => deepmd}/cluster/__init__.py | 0 {source/train => deepmd}/cluster/local.py | 0 {source/train => deepmd}/cluster/slurm.py | 0 source/train/CMakeLists.txt | 4 ---- source/train/{Trainer.py => trainer.py} | 0 5 files changed, 4 deletions(-) rename {source/train => deepmd}/cluster/__init__.py (100%) rename {source/train => deepmd}/cluster/local.py (100%) rename {source/train => deepmd}/cluster/slurm.py (100%) rename source/train/{Trainer.py => trainer.py} (100%) diff --git a/source/train/cluster/__init__.py b/deepmd/cluster/__init__.py similarity index 100% rename from source/train/cluster/__init__.py rename to deepmd/cluster/__init__.py diff --git a/source/train/cluster/local.py b/deepmd/cluster/local.py similarity index 100% rename from source/train/cluster/local.py rename to deepmd/cluster/local.py diff --git a/source/train/cluster/slurm.py b/deepmd/cluster/slurm.py similarity index 100% rename from source/train/cluster/slurm.py rename to deepmd/cluster/slurm.py diff --git a/source/train/CMakeLists.txt b/source/train/CMakeLists.txt index 72e4b8acaa..f249e42977 100644 --- a/source/train/CMakeLists.txt +++ b/source/train/CMakeLists.txt @@ -8,10 +8,6 @@ sinstall( FILES ${LIB_PY} DESTINATION deepmd ) -install( - DIRECTORY cluster - DESTINATION deepmd/cluster -) install( FILES train.py test.py DESTINATION deepmd diff --git a/source/train/Trainer.py b/source/train/trainer.py similarity index 100% rename from source/train/Trainer.py rename to source/train/trainer.py From 045402588d777f9bfd43d3b1bbf0c4ee47a34b1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Tue, 9 Feb 2021 12:06:40 +0100 Subject: [PATCH 117/562] remove readme now it is in freeze.py references --- source/scripts/freeze.py | 5 +++-- source/scripts/readme | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) delete mode 100644 source/scripts/readme diff --git a/source/scripts/freeze.py b/source/scripts/freeze.py index 7e4593bb2d..f00517c8b2 100755 --- a/source/scripts/freeze.py +++ b/source/scripts/freeze.py @@ -27,7 +27,7 @@ try: from typing import Protocol # python >=3.8 except ImportError: - from typing_extensions import Protocol + from typing_extensions import Protocol # type: ignore class ArgsProto(Protocol): """Prococol mimicking parser object.""" @@ -160,7 +160,8 @@ def freeze_graph( output_graph = abspath(output) # Before exporting our graph, we need to precise what is our output node - # This is how TF decides what part of the Graph he has to keep and what part it can dump + # This is how TF decides what part of the Graph he has to keep + # and what part it can dump # NOTE: this variable is plural, because you can have multiple output nodes # output_node_names = "energy_test,force_test,virial_test,t_rcut" diff --git a/source/scripts/readme b/source/scripts/readme deleted file mode 100644 index dedd38fdc8..0000000000 --- a/source/scripts/readme +++ /dev/null @@ -1,2 +0,0 @@ -freeze.py : -see https://blog.metaflow.fr/tensorflow-how-to-freeze-a-model-and-serve-it-with-a-python-api-d4f3596b3adc From febba934d3d18bd9e60f70a50efbf781b92c0bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Tue, 9 Feb 2021 12:07:05 +0100 Subject: [PATCH 118/562] rework entry point --- source/train/calculator.py | 1 + source/train/doc.py | 6 +- source/train/main.py | 240 ++++++++++++++++++++++++++---------- source/train/run_options.py | 4 +- 4 files changed, 181 insertions(+), 70 deletions(-) diff --git a/source/train/calculator.py b/source/train/calculator.py index 8ddda75942..e74ff2edb9 100644 --- a/source/train/calculator.py +++ b/source/train/calculator.py @@ -12,6 +12,7 @@ __all__ = ["DP"] + class DP(Calculator): """Implementation of ASE deepmd calculator. diff --git a/source/train/doc.py b/source/train/doc.py index 4973361b0f..e499e80f48 100644 --- a/source/train/doc.py +++ b/source/train/doc.py @@ -1,5 +1,9 @@ +"""Module that prints train input arguments docstrings.""" + from deepmd.utils.argcheck import gen_doc -def doc_train_input(args): + +def doc_train_input(): + """Print out trining input arguments to console.""" doc_str = gen_doc(make_anchor=True) print(doc_str) diff --git a/source/train/main.py b/source/train/main.py index b7dd0d0215..d250f3187a 100644 --- a/source/train/main.py +++ b/source/train/main.py @@ -1,87 +1,193 @@ +"""DeePMD-Kit entry point module.""" + import argparse -from .train import train -from .freeze import freeze from .config import config +from .doc import doc_train_input +from .freeze import freeze from .test import test +from .train import train from .transform import transform -from .doc import doc_train_input -def main () : + +def main(): + """DeePMD-Kit entry point. + + Raises + ------ + RuntimeError + if no command was input + """ parser = argparse.ArgumentParser( - description="DeePMD-kit: A deep learning package for many-body potential energy representation and molecular dynamics") - subparsers = parser.add_subparsers(title='Valid subcommands', dest='command') + description="DeePMD-kit: A deep learning package for many-body potential energy" + " representation and molecular dynamics", + formatter_class=argparse.ArgumentDefaultsHelpFormatter + ) + subparsers = parser.add_subparsers(title="Valid subcommands", dest="command") + + # * config script ****************************************************************** + parser_cfig = subparsers.add_parser( + "config", help="fast configuration of parameter file for smooth model" + ) + parser_cfig.add_argument( + "-o", + "--output", + type=str, + default="input.json", + help="the output json file" + ) + + # * transform script *************************************************************** + parser_transform = subparsers.add_parser( + "transform", help="pass parameters to another model" + ) + parser_transform.add_argument( + "-r", + "--raw-model", + default="raw_frozen_model.pb", + type=str, + help="the model receiving parameters", + ) + parser_transform.add_argument( + "-o", + "--old-model", + default="old_frozen_model.pb", + type=str, + help="the model providing parameters", + ) + parser_transform.add_argument( + "-n", + "--output", + default="frozen_model.pb", + type=str, + help="the model after passing parameters", + ) + + # * config parser ****************************************************************** + parser_train = subparsers.add_parser("train", help="train a model") + parser_train.add_argument( + "INPUT", help="the input parameter file in json or yaml format" + ) + parser_train.add_argument( + "-im" + "--init-model", + type=str, + default=False, + help="Initialize the model by the provided checkpoint.", + ) + parser_train.add_argument( + "-r" + "--restart", + type=str, + default=False, + help="Restart the training from the provided checkpoint." + ) + parser_train.add_argument( + "-o", + "--output", + type=str, + default="out.json", + help="The output file of the parameters used in training.", + ) - # parser_cfig = subparsers.add_parser('config', help='fast configuration of parameter file for smooth model') - # parser_cfig.add_argument("-o", "--output", type=str, default = "input.json", - # help="the output json file") - - default_num_inter_threads = 0 - parser_transform = subparsers.add_parser('transform', help='pass parameters to another model') - parser_transform.add_argument('-r', "--raw-model", default = "raw_frozen_model.pb", type=str, - help = "the model receiving parameters") - parser_transform.add_argument("-o","--old-model", default = "old_frozen_model.pb", type=str, - help='the model providing parameters') - parser_transform.add_argument("-n", "--output", default = "frozen_model.pb", type=str, - help = "the model after passing parameters") - parser_train = subparsers.add_parser('train', help='train a model') - parser_train.add_argument('INPUT', - help='the input parameter file in json or yaml format') - parser_train.add_argument('--init-model', type = str, - help= - 'Initialize the model by the provided checkpoint.') - parser_train.add_argument('--restart', type = str, - help= - 'Restart the training from the provided checkpoint.') - parser_train.add_argument('-o','--output', type = str, default = 'out.json', - help= - 'The output file of the parameters used in training.') - - parser_frz = subparsers.add_parser('freeze', help='freeze the model') - parser_frz.add_argument("-d", "--folder", type=str, default = ".", - help="path to checkpoint folder") - parser_frz.add_argument("-o", "--output", type=str, default = "frozen_model.pb", - help="name of graph, will output to the checkpoint folder") - parser_frz.add_argument("-n", "--nodes", type=str, - help="the frozen nodes, if not set, determined from the model type") + # * freeze script ****************************************************************** + parser_frz = subparsers.add_parser("freeze", help="freeze the model") + parser_frz.add_argument( + "-f", + "--folder", + type=str, + default=".", + help="path to checkpoint folder" + ) + parser_frz.add_argument( + "-o", + "--output", + type=str, + default="frozen_model.pb", + help="name of graph, will output to the checkpoint folder", + ) + parser_frz.add_argument( + "-n", + "--nodes", + type=str, + help="the frozen nodes, if not set, determined from the model type", + ) - parser_tst = subparsers.add_parser('test', help='test the model') - parser_tst.add_argument("-m", "--model", default="frozen_model.pb", type=str, - help="Frozen model file to import") - parser_tst.add_argument("-s", "--system", default=".", type=str, - help="The system dir. Recursively detect systems in this directory") - parser_tst.add_argument("-S", "--set-prefix", default="set", type=str, - help="The set prefix") - parser_tst.add_argument("-n", "--numb-test", default=100, type=int, - help="The number of data for test") - parser_tst.add_argument("-r", "--rand-seed", type=int, - help="The random seed") - parser_tst.add_argument("--shuffle-test", action = 'store_true', - help="Shuffle test data") - parser_tst.add_argument("-d", "--detail-file", type=str, - help="The file containing details of energy force and virial accuracy") - parser_tst.add_argument("-a", "--atomic-energy", action = 'store_true', - help="Test the accuracy of atomic energy") + # * test script ******************************************************************** + parser_tst = subparsers.add_parser("test", help="test the model") + parser_tst.add_argument( + "-m", + "--model", + default="frozen_model.pb", + type=str, + help="Frozen model file to import", + ) + parser_tst.add_argument( + "-s", + "--system", + default=".", + type=str, + help="The system dir. Recursively detect systems in this directory", + ) + parser_tst.add_argument( + "-S", + "--set-prefix", + default="set", + type=str, + help="The set prefix" + ) + parser_tst.add_argument( + "-n", + "--numb-test", + default=100, + type=int, + help="The number of data for test" + ) + parser_tst.add_argument( + "-r", + "--rand-seed", + type=int, + help="The random seed") + parser_tst.add_argument( + "-st", + "--shuffle-test", + action="store_true", + help="Shuffle test data" + ) + parser_tst.add_argument( + "-d", + "--detail-file", + type=str, + help="The file containing details of energy force and virial accuracy", + ) + parser_tst.add_argument( + "-a", + "--atomic-energy", + action="store_true", + help="Test the accuracy of atomic energy", + ) - parser_train = subparsers.add_parser('doc-train-input', - help='print the documentation (in rst format) of input training parameters.') + # * print docs script ************************************************************** + subparsers.add_parser( + "doc-train-input", + help="print the documentation (in rst format) of input training parameters.", + ) args = parser.parse_args() - if args.command is None : + if args.command is None: parser.print_help() - exit - if args.command == 'train' : + if args.command == "train": train(args) - elif args.command == 'freeze' : + elif args.command == "freeze": freeze(args) - elif args.command == 'config' : + elif args.command == "config": config(args) - elif args.command == 'test' : + elif args.command == "test": test(args) - elif args.command == 'transform' : + elif args.command == "transform": transform(args) - elif args.command == 'doc-train-input' : + elif args.command == "doc-train-input": doc_train_input(args) - else : - raise RuntimeError('unknown command ' + args.command) + else: + raise RuntimeError(f"unknown command {args.command}s) diff --git a/source/train/run_options.py b/source/train/run_options.py index 4d16a76dad..057ab800f9 100644 --- a/source/train/run_options.py +++ b/source/train/run_options.py @@ -277,10 +277,10 @@ def __init__(self, args: Optional["ArgsProto"], try_distrib: bool = False): raise RuntimeError( "--init-model and --restart should not be set at the same time" ) - elif args.init_model is not None: + elif args.init_model: self.init_model = os.path.abspath(args.init_model) self.init_mode = "init_from_model" - elif args.restart is not None: + elif args.restart: self.restart = os.path.abspath(args.restart) self.init_mode = "restart" From ca73062f3731bd98082114149ac98278d58e9ee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Tue, 9 Feb 2021 17:36:18 +0100 Subject: [PATCH 119/562] add new logging logic based on python logging --- deepmd/common.py | 2 +- deepmd/utils/loggers.py | 224 +++++++++++++++++++++++++++++++++--- source/train/main.py | 67 +++++++++-- source/train/run_options.py | 128 ++++++++++++++------- source/train/train.py | 15 ++- 5 files changed, 362 insertions(+), 74 deletions(-) diff --git a/deepmd/common.py b/deepmd/common.py index 5183b62536..0b1e3642b4 100644 --- a/deepmd/common.py +++ b/deepmd/common.py @@ -20,7 +20,7 @@ import yaml from deepmd.env import op_module, tf -from deepmd.RunOptions import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION if TYPE_CHECKING: _DICT_VAL = TypeVar("_DICT_VAL") diff --git a/deepmd/utils/loggers.py b/deepmd/utils/loggers.py index 91dc7397fb..089e0b12f4 100644 --- a/deepmd/utils/loggers.py +++ b/deepmd/utils/loggers.py @@ -1,34 +1,173 @@ - """Logger initialization for package.""" import logging -from typing import TYPE_CHECKING -from pathlib import Path - +from typing import TYPE_CHECKING, Optional if TYPE_CHECKING: from pathlib import Path + from mpi4py import MPI + + _MPI_APPEND_MODE = MPI.MODE_CREATE | MPI.MODE_APPEND + logging.getLogger(__name__) __all__ = ["set_log_handles"] # logger formater -FFORMATTER = logging.Formatter("[%(asctime)s] %(levelname)-7s %(name)-45s " - "%(message)s") -CFORMATTER = logging.Formatter("%(levelname)-7s |-> %(name)-45s %(message)s") +FFORMATTER = logging.Formatter( + "[%(asctime)s] %(app_name)s %(levelname)-7s %(name)-45s %(message)s" +) +CFORMATTER = logging.Formatter( + "%(app_name)s %(levelname)-7s |-> %(name)-45s %(message)s" +) +FFORMATTER_MPI = logging.Formatter( + "[%(asctime)s] %(app_name)s rank:%(rank)-2s %(levelname)-7s %(name)-45s %(message)s" +) +CFORMATTER_MPI = logging.Formatter( + "%(app_name)s rank:%(rank)-2s %(levelname)-7s |-> %(name)-45s %(message)s" +) + + +class _AppFilter(logging.Filter): + """Add field `app_name` to log messages.""" + + def filter(self, record): + record.app_name = "DEEPMD" + return True + + +class _MPIRankFilter(logging.Filter): + """Add MPI rank number to log messages, adds field `rank`.""" + + def __init__(self, rank: int) -> None: + super().__init__(name="MPI_rank_id") + self.mpi_rank = str(rank) + + def filter(self, record): + record.rank = self.mpi_rank + return True + + +class _MPIMasterFilter(logging.Filter): + """Filter that lets through only messages emited from rank==0.""" + + def __init__(self, rank: int) -> None: + super().__init__(name="MPI_master_log") + self.mpi_rank = rank + + def filter(self, record): + if self.mpi_rank == 0: + return True + else: + return False + + +class _MPIFileStream: + """Wrap MPI.File` so it has the same API as python file streams. + + Parameters + ---------- + filename : Path + disk location of the file stream + MPI : MPI + MPI communicator object + mode : str, optional + file write mode, by default _MPI_APPEND_MODE + """ + + def __init__( + self, filename: "Path", MPI: "MPI", mode: str = "_MPI_APPEND_MODE" + ) -> None: + self.stream = MPI.File.Open(MPI.COMM_WORLD, filename, mode) + self.stream.Set_atomicity(True) + self.name = "MPIfilestream" + def write(self, msg: str): + """Write to MPI shared file stream. -def set_log_handles(level: int, log_path: "Path"): + Parameters + ---------- + msg : str + message to write + """ + b = bytearray() + b.extend(map(ord, msg)) + self.stream.Write_shared(b) + + def close(self): + """Synchronize and close MPI file stream.""" + self.stream.Sync() + self.stream.Close() + + +class _MPIHandler(logging.FileHandler): + """Emulate `logging.FileHandler` with MPI shared File that all ranks can write to. + + Parameters + ---------- + filename : Path + file path + MPI : MPI + MPI communicator object + mode : str, optional + file access mode, by default "_MPI_APPEND_MODE" + """ + + def __init__( + self, + filename: "Path", + MPI: "MPI", + mode: str = "_MPI_APPEND_MODE", + ) -> None: + self.MPI = MPI + super().__init__(filename, mode=mode, encoding=None, delay=False) + + def _open(self): + return _MPIFileStream(self.baseFilename, self.MPI, self.mode) + + def setStream(self, stream): + """Stream canot be reasigned in MPI mode.""" + raise NotImplementedError("Unable to do for MPI file handler!") + + +def set_log_handles( + level: int, + log_path: Optional["Path"] = None, + mpi_log: Optional[str] = None, + MPI: Optional["MPI"] = None, +): """Set desired level for package loggers and add file handlers. Parameters ---------- level: int logging level - log_path: Path - path to log file + log_path: Optional[str] + path to log file, if None logs will be send only to console. If the parent + directory does not exist it will be automatically created, by default None + mpi_log : Optional[str], optional + mpi log type. Has three options. `master` will output logs to file and console + only from rank==0. `collect` will write messages from all ranks to one file + opened under rank==0 and to console. `workers` will open one log file for each + worker designated by its rank, console behaviour is the same as for `collect`. + If this argument is specified than also `MPI` object must be passed in. + by default None + MPI : Optional[MPI, optional] + `MPI` communicator object, must be specified if `mpi_log` is specified, + by default None + + Raises + ------ + RuntimeError + if only one of the arguments `mpi_log`, `MPI` is specified """ + # convert 0 - 3 to python logging level + # we have debug=3 -> logging.DEBUG = 10 + # we have error=0 -> logging.ERROR = 40 + level = (4 - level) * 10 + + # get root logger root_log = logging.getLogger() # remove all old handlers @@ -36,15 +175,66 @@ def set_log_handles(level: int, log_path: "Path"): for hdlr in root_log.handlers[:]: root_log.removeHandler(hdlr) - # add console handler + # check arguments + if (mpi_log and not MPI) or (not mpi_log and MPI): + raise RuntimeError("You cannot specify only one of 'mpi_log', 'MPI' arguments") + + # * add console handler ************************************************************ ch = logging.StreamHandler() - ch.setLevel(level) - ch.setFormatter(CFORMATTER) - root_log.addHandler(ch) + if MPI: + rank = MPI.COMM_WORLD.Get_rank() + if mpi_log == "master": + ch.setFormatter(CFORMATTER) + ch.addFilter(_MPIMasterFilter(rank)) + else: + ch.setFormatter(CFORMATTER_MPI) + ch.addFilter(_MPIRankFilter(rank)) + else: + ch.setFormatter(CFORMATTER) - # add file handler - ch = logging.FileHandler(log_path, mode="w") ch.setLevel(level) - ch.setFormatter(FFORMATTER) + ch.addFilter(_AppFilter()) root_log.addHandler(ch) + # * add file handler *************************************************************** + if log_path: + + # create directory + log_path.parent.mkdir(exist_ok=True, parents=True) + + fh = None + + if mpi_log == "master": + rank = MPI.COMM_WORLD.Get_rank() + if rank == 0: + fh = logging.FileHandler(log_path, mode="w") + fh.addFilter(_MPIMasterFilter(rank)) + fh.setFormatter(FFORMATTER) + elif mpi_log == "collect": + rank = MPI.COMM_WORLD.Get_rank() + fh = _MPIHandler(log_path, MPI, mode=MPI.MODE_WRONLY | MPI.MODE_CREATE) + fh.addFilter(_MPIRankFilter(rank)) + fh.setFormatter(FFORMATTER_MPI) + elif mpi_log == "workers": + rank = MPI.COMM_WORLD.Get_rank() + # if file has suffix than inser rank number before suffix + # e.g deepmd.log -> deepmd_.log + # if no suffix is present, insert rank as suffix + # e.g. deepmdlog -> deepmdlog. + if log_path.suffix: + worker_log = (log_path.parent / f"{log_path.stem}_{rank}").with_suffix( + log_path.suffix + ) + else: + worker_log = log_path.with_suffix(f".{rank}") + + fh = logging.FileHandler(worker_log, mode="w") + fh.setFormatter(FFORMATTER) + else: + fh = logging.FileHandler(log_path, mode="w") + fh.setFormatter(FFORMATTER) + + if fh: + fh.setLevel(level) + fh.addFilter(_AppFilter()) + root_log.addHandler(fh) diff --git a/source/train/main.py b/source/train/main.py index d250f3187a..106b9c239b 100644 --- a/source/train/main.py +++ b/source/train/main.py @@ -1,6 +1,9 @@ """DeePMD-Kit entry point module.""" import argparse +from pathlib import Path + +from deepmd.utils.loggers import set_log_handles from .config import config from .doc import doc_train_input @@ -25,9 +28,31 @@ def main(): ) subparsers = parser.add_subparsers(title="Valid subcommands", dest="command") + # * logging options parser ********************************************************* + # with use of the parent argument this options will be added to every parser + parser_log = argparse.ArgumentParser(add_help=False) + parser_log.add_argument( + "-v", + "--verbose", + default=2, + action="count", + dest="log_level", + help="set verbosity level 0 - 3, 0=ERROR, 1(-v)=WARNING, 2(-vv)=INFO " + "and 3(-vvv)=DEBUG" + ) + parser_log.add_argument( + "-l", + "--log-path", + default=None, + help="set log file to log messages to disk, if not specified, the logs will " + "only be output to console" + ) + # * config script ****************************************************************** parser_cfig = subparsers.add_parser( - "config", help="fast configuration of parameter file for smooth model" + "config", + parents=[parser_log], + help="fast configuration of parameter file for smooth model" ) parser_cfig.add_argument( "-o", @@ -39,7 +64,9 @@ def main(): # * transform script *************************************************************** parser_transform = subparsers.add_parser( - "transform", help="pass parameters to another model" + "transform", + parents=[parser_log], + help="pass parameters to another model" ) parser_transform.add_argument( "-r", @@ -64,7 +91,10 @@ def main(): ) # * config parser ****************************************************************** - parser_train = subparsers.add_parser("train", help="train a model") + parser_train = subparsers.add_parser( + "train", + parents=[parser_log], + help="train a model") parser_train.add_argument( "INPUT", help="the input parameter file in json or yaml format" ) @@ -89,9 +119,22 @@ def main(): default="out.json", help="The output file of the parameters used in training.", ) + parser_train.add_argument( + "-m", + "--mpi-log", + type=str, + default="master", + options=("master", "collect", "workers"), + help="Set the manner of logging when running with MPI. 'master' logs only on " + "main process, 'collect' broadcasts logs from workers to master and 'workers' " + "means each process will output its own log" + ) # * freeze script ****************************************************************** - parser_frz = subparsers.add_parser("freeze", help="freeze the model") + parser_frz = subparsers.add_parser( + "freeze", + parents=[parser_log], + help="freeze the model") parser_frz.add_argument( "-f", "--folder", @@ -114,7 +157,10 @@ def main(): ) # * test script ******************************************************************** - parser_tst = subparsers.add_parser("test", help="test the model") + parser_tst = subparsers.add_parser( + "test", + parents=[parser_log], + help="test the model") parser_tst.add_argument( "-m", "--model", @@ -170,14 +216,21 @@ def main(): # * print docs script ************************************************************** subparsers.add_parser( "doc-train-input", + parents=[parser_log], help="print the documentation (in rst format) of input training parameters.", ) args = parser.parse_args() + # do not set log handles for None it is useless + # log handles for train will be set separatelly + # when the use of MPI will be determined in `RunOptions` + if args.command not in (None, "train"): + set_log_handles(args.log_level, Path(args.log_path)) + if args.command is None: parser.print_help() - if args.command == "train": + elif args.command == "train": train(args) elif args.command == "freeze": freeze(args) @@ -190,4 +243,4 @@ def main(): elif args.command == "doc-train-input": doc_train_input(args) else: - raise RuntimeError(f"unknown command {args.command}s) + raise RuntimeError(f"unknown command {args.command}") diff --git a/source/train/run_options.py b/source/train/run_options.py index 057ab800f9..74660d8fce 100644 --- a/source/train/run_options.py +++ b/source/train/run_options.py @@ -1,13 +1,16 @@ """Module taking care of important package constants.""" +import logging import os import sys from configparser import ConfigParser +from pathlib import Path from typing import TYPE_CHECKING, Dict, List, Optional, Tuple import numpy as np from deepmd.cluster import get_resource from deepmd.env import get_tf_default_nthreads, tf +from deepmd.utils.loggers import set_log_handles if TYPE_CHECKING: try: @@ -22,6 +25,10 @@ class ArgsProto(Protocol): init_model: Optional[str] restart: Optional[str] + log_level: int + log_path: Optional[str] + mpi_log: Optional[str] + __all__ = [ "GLOBAL_TF_FLOAT_PRECISION", @@ -32,9 +39,11 @@ class ArgsProto(Protocol): "BUILD", "global_cvt_2_tf_float", "global_cvt_2_ener_float", - "RunOptions" + "RunOptions", ] +log = logging.getLogger(__name__) + def _get_package_constants( config_file: str = "config/run_config.ini", @@ -71,28 +80,28 @@ def _get_package_constants( # http://patorjk.com/software/taag. Font:Big" WELCOME = ( # noqa - " _____ _____ __ __ _____ _ _ _ \n" - "| __ \ | __ \ | \/ || __ \ | | (_)| | \n" - "| | | | ___ ___ | |__) || \ / || | | | ______ | | __ _ | |_ \n" - "| | | | / _ \ / _ \| ___/ | |\/| || | | ||______|| |/ /| || __|\n" - "| |__| || __/| __/| | | | | || |__| | | < | || |_ \n" - "|_____/ \___| \___||_| |_| |_||_____/ |_|\_\|_| \__|\n" + " _____ _____ __ __ _____ _ _ _ ", + "| __ \ | __ \ | \/ || __ \ | | (_)| | ", + "| | | | ___ ___ | |__) || \ / || | | | ______ | | __ _ | |_ ", + "| | | | / _ \ / _ \| ___/ | |\/| || | | ||______|| |/ /| || __|", + "| |__| || __/| __/| | | | | || |__| | | < | || |_ ", + "|_____/ \___| \___||_| |_| |_||_____/ |_|\_\|_| \__|", ) CITATION = ( - "Please read and cite:\n" - "Wang, Zhang, Han and E, Comput.Phys.Comm. 228, 178-184 (2018)\n" + "Please read and cite:", + "Wang, Zhang, Han and E, Comput.Phys.Comm. 228, 178-184 (2018)", ) -_sep = '\n ' +_sep = "\n " BUILD = ( - f"installed to: {GLOBAL_CONFIG['INSTALL_PREFIX']}\n" - f"source : {GLOBAL_CONFIG['GIT_SUMM']}\n" - f"source brach: {GLOBAL_CONFIG['GIT_BRANCH']}\n" - f"source commit: {GLOBAL_CONFIG['GIT_HASH']}\n" - f"source commit at: {GLOBAL_CONFIG['GIT_DATE']}\n" - f"build float prec: {global_float_prec}\n" - f"build with tf inc: {GLOBAL_CONFIG['TF_INCLUDE_DIR']}\n" + f"installed to: {GLOBAL_CONFIG['INSTALL_PREFIX']}", + f"source : {GLOBAL_CONFIG['GIT_SUMM']}", + f"source brach: {GLOBAL_CONFIG['GIT_BRANCH']}", + f"source commit: {GLOBAL_CONFIG['GIT_HASH']}", + f"source commit at: {GLOBAL_CONFIG['GIT_DATE']}", + f"build float prec: {global_float_prec}", + f"build with tf inc: {GLOBAL_CONFIG['TF_INCLUDE_DIR']}", f"build with tf lib: {GLOBAL_CONFIG['TF_LIBS'].replace(';', _sep)}" # noqa ) @@ -259,6 +268,9 @@ class RunOptions: server: Optional[tf.train.Server] my_device: str + _MPI: Optional["MPI"] + _log_handles_already_set: bool = False + def __init__(self, args: Optional["ArgsProto"], try_distrib: bool = False): # distributed tasks if try_distrib: @@ -284,40 +296,66 @@ def __init__(self, args: Optional["ArgsProto"], try_distrib: bool = False): self.restart = os.path.abspath(args.restart) self.init_mode = "restart" - def message(self, msg: str): - """Print message if on the main process. + self._setup_logger( + Path(args.log_path) if args.log_path else None, + args.log_level, + args.mpi_log, + ) - Parameters - ---------- - msg : str - message to print - """ - if self.is_chief: - lines = msg.split("\n") - for ii in lines: - print(f"# DEEPMD: {ii}") - sys.stdout.flush() - def print_run_summary(self): + def print_resource_summary(self): """Print build and current running cluster configuration summary.""" - msg = "" - msg += "---Summary of the training---------------------------------------\n" + log.info("---Summary of the training---------------------------------------\n") if self.is_distrib: - msg += "distributed\n" - msg += f"ps list: {self.cluster['ps']}\n" - msg += f"worker list: {self.cluster['worker']}\n" - msg += f"chief on: {self.nodename}\n" + log.info("distributed\n") + log.info(f"ps list: {self.cluster['ps']}\n") + log.info(f"worker list: {self.cluster['worker']}\n") + log.info(f"chief on: {self.nodename}\n") else: - msg += f"running on: {self.nodename}\n" + log.info(f"running on: {self.nodename}\n") if self.gpus is None: - msg += f"CUDA_VISIBLE_DEVICES: unset\n" + log.info(f"CUDA_VISIBLE_DEVICES: unset\n") else: - msg += f"CUDA_VISIBLE_DEVICES: {self.gpus}\n" + log.info(f"CUDA_VISIBLE_DEVICES: {self.gpus}\n") intra, inter = get_tf_default_nthreads() - msg += f"num_intra_threads: {intra:d}\n" - msg += f"num_inter_threads: {inter:d}\n" - msg += "-----------------------------------------------------------------\n" - self.message(msg) + log.info(f"num_intra_threads: {intra:d}\n") + log.info(f"num_inter_threads: {inter:d}\n") + log.info("-----------------------------------------------------------------\n") + + def _setup_logger( + self, + log_path: Optional[Path], + log_level: int, + mpi_log: Optional[str], + ): + """Set up package loggers. + + Parameters + ---------- + log_level: int + logging level + log_path: Optional[str] + path to log file, if None logs will be send only to console. If the parent + directory does not exist it will be automatically created, by default None + mpi_log : Optional[str], optional + mpi log type. Has three options. `master` will output logs to file and + console only from rank==0. `collect` will write messages from all ranks to + one file opened under rank==0 and to console. `workers` will open one log + file for each worker designated by its rank, console behaviour is the same + as for `collect`. If this argument is specified than also `MPI` object must + be passed in. by default None + """ + if not self._log_handles_already_set: + if not self._MPI: + mpi_log = None + set_log_handles(log_level, log_path, mpi_log=mpi_log, MPI=self._MPI) + self._log_handles_already_set = True + log.debug("Log handles were successfully set") + else: + log.warning( + f"Log handles have already been set. It is not advisable to " + f"reset them{', especially when runnig with MPI!' if self._MPI else ''}" + ) def _try_init_mpi(self): try: @@ -330,8 +368,10 @@ def _try_init_mpi(self): self.is_distrib = _is_distributed(MPI) if self.is_distrib: self._init_distributed(MPI) + self._MPI = MPI else: self._init_serial() + self._MPI = None def _init_distributed(self, MPI: "MPI"): """Initialize settings for distributed training. @@ -381,3 +421,5 @@ def _init_serial(self): self.my_device = f"gpu:{gpus[0]:d}" else: self.my_device = "cpu:0" + + self._MPI = None diff --git a/source/train/train.py b/source/train/train.py index 6bcd3e5e7d..f3204b795f 100755 --- a/source/train/train.py +++ b/source/train/train.py @@ -1,7 +1,5 @@ #!/usr/bin/env python3 -import os -import sys import time import json import numpy as np @@ -13,6 +11,10 @@ from deepmd.utils.data_system import DeepmdDataSystem from deepmd.utils.compat import convert_input_v0_v1 from deepmd.utils.argcheck import normalize +import logging + +log = logging.getLogger(__name__) + def create_done_queue(cluster_spec, task_index): with tf.device("/job:ps/task:%d" % (task_index)): @@ -66,10 +68,11 @@ def train (args) : if 'with_distrib' in jdata: with_distrib = jdata['with_distrib'] run_opt = RunOptions(args, with_distrib) - run_opt.message(WELCOME) - run_opt.message(CITATION) - run_opt.message(BUILD_EXTENDED) - run_opt.print_run_summary() + + for message in (WELCOME + CITATION + BUILD_EXTENDED): + log.info(message) + + run_opt.print_resource_summary() if run_opt.is_distrib : # distributed training From e21bb11fa3b2e46eb92b6daf22a4ec43a63988f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Tue, 9 Feb 2021 17:43:50 +0100 Subject: [PATCH 120/562] typo fix --- deepmd/utils/loggers.py | 2 +- source/train/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deepmd/utils/loggers.py b/deepmd/utils/loggers.py index 089e0b12f4..a7a4bc9640 100644 --- a/deepmd/utils/loggers.py +++ b/deepmd/utils/loggers.py @@ -175,7 +175,7 @@ def set_log_handles( for hdlr in root_log.handlers[:]: root_log.removeHandler(hdlr) - # check arguments + # check if arguments are present if (mpi_log and not MPI) or (not mpi_log and MPI): raise RuntimeError("You cannot specify only one of 'mpi_log', 'MPI' arguments") diff --git a/source/train/CMakeLists.txt b/source/train/CMakeLists.txt index f249e42977..34cb91c789 100644 --- a/source/train/CMakeLists.txt +++ b/source/train/CMakeLists.txt @@ -4,7 +4,7 @@ configure_file("run_config.ini" "${CMAKE_CURRENT_BINARY_DIR}/run_config.ini" @ON file(GLOB LIB_PY main.py calculator.py model.py trainer.py run_options.py transform.py doc.py) -sinstall( +install( FILES ${LIB_PY} DESTINATION deepmd ) From 736e297f823a188a7c6bbb3100a60324d1ebca1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Tue, 9 Feb 2021 18:53:20 +0100 Subject: [PATCH 121/562] fix bugs --- deepmd/loggers/__init__.py | 5 +++ deepmd/{utils => loggers}/loggers.py | 0 deepmd/utils/__init__.py | 15 ++++---- deepmd/utils/data_system.py | 7 +++- source/tests/test_data_modifier.py | 11 ++++-- source/tests/test_data_modifier_shuffle.py | 11 ++++-- source/tests/test_deepmd_data.py | 4 +- source/tests/test_deepmd_data_sys.py | 4 +- source/tests/test_descrpt_nonsmth.py | 22 +++++------ source/tests/test_descrpt_se_ar.py | 14 +++---- source/tests/test_descrpt_se_r.py | 22 +++++------ source/tests/test_descrpt_sea_ef.py | 22 +++++------ source/tests/test_descrpt_sea_ef_para.py | 22 +++++------ source/tests/test_descrpt_sea_ef_rot.py | 16 ++++---- source/tests/test_descrpt_sea_ef_vert.py | 22 +++++------ source/tests/test_descrpt_smooth.py | 22 +++++------ source/tests/test_embedding_net.py | 6 +-- source/tests/test_ewald.py | 14 +++---- source/tests/test_model_loc_frame.py | 18 ++++----- source/tests/test_model_se_a.py | 18 ++++----- source/tests/test_model_se_a_aparam.py | 20 +++++----- source/tests/test_model_se_a_fparam.py | 20 +++++----- source/tests/test_model_se_a_srtab.py | 18 ++++----- source/tests/test_model_se_r.py | 18 ++++----- source/tests/test_polar_se_a.py | 18 ++++----- source/tests/test_wfc.py | 18 ++++----- source/train/main.py | 4 +- source/train/run_options.py | 22 +++++------ source/train/train.py | 6 +-- source/train/trainer.py | 44 +++++++++++----------- 30 files changed, 238 insertions(+), 225 deletions(-) create mode 100644 deepmd/loggers/__init__.py rename deepmd/{utils => loggers}/loggers.py (100%) diff --git a/deepmd/loggers/__init__.py b/deepmd/loggers/__init__.py new file mode 100644 index 0000000000..8eb1868ae3 --- /dev/null +++ b/deepmd/loggers/__init__.py @@ -0,0 +1,5 @@ +"""Module taking care of logging duties.""" + +from .loggers import set_log_handles + +__all__ = ["set_log_handles"] diff --git a/deepmd/utils/loggers.py b/deepmd/loggers/loggers.py similarity index 100% rename from deepmd/utils/loggers.py rename to deepmd/loggers/loggers.py diff --git a/deepmd/utils/__init__.py b/deepmd/utils/__init__.py index 610df6529d..40f796926e 100644 --- a/deepmd/utils/__init__.py +++ b/deepmd/utils/__init__.py @@ -1,8 +1,9 @@ -# -from .data import DeepmdData -from .data_system import DeepmdDataSystem +# +from .data import DeepmdData +from .data_system import DeepmdDataSystem + # out-of-dated -from .data import DataSets -from .data_system import DataSystem -from .tab_inter import TabInter -from .learning_rate import LearningRateExp +from .data import DataSets +from .data_system import DataSystem +from .tab_inter import TabInter +from .learning_rate import LearningRateExp diff --git a/deepmd/utils/data_system.py b/deepmd/utils/data_system.py index af4daf3db9..31f63692a5 100644 --- a/deepmd/utils/data_system.py +++ b/deepmd/utils/data_system.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 +import logging import os import collections import warnings @@ -9,6 +10,8 @@ from deepmd.utils.data import DataSets from deepmd.utils.data import DeepmdData +log = logging.getLogger(__name__) + class DeepmdDataSystem() : """ @@ -416,7 +419,7 @@ def print_summary(self, self.test_size[ii], prob[ii]) ) tmp_msg += "------------------------------------------------------------------------\n" - run_opt.message(tmp_msg) + log.info(tmp_msg) def _make_auto_bs(self, rule) : bs = [] @@ -602,7 +605,7 @@ def print_summary(self, run_opt) : self.batch_size[ii], self.nbatches[ii]) ) tmp_msg += "-----------------------------------------------------------------\n" - run_opt.message(tmp_msg) + log.info(tmp_msg) def compute_energy_shift(self) : sys_ener = np.array([]) diff --git a/source/tests/test_data_modifier.py b/source/tests/test_data_modifier.py index d1104ae6c5..e3f1561ca9 100644 --- a/source/tests/test_data_modifier.py +++ b/source/tests/test_data_modifier.py @@ -7,15 +7,15 @@ from deepmd.run_options import RunOptions from deepmd.trainer import NNPTrainer from deepmd.utils.data_system import DeepmdDataSystem -from deepmd.run_options import global_tf_float_precision -from deepmd.run_options import global_np_float_precision -from deepmd.run_options import global_ener_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION from deepmd.infer.ewald_recp import EwaldRecp from deepmd.infer.data_modifier import DipoleChargeModifier from common import Data -if global_np_float_precision == np.float32 : +if GLOBAL_NP_FLOAT_PRECISION == np.float32 : global_default_fv_hh = 1e-2 global_default_dw_hh = 1e-2 global_default_places = 3 @@ -31,6 +31,9 @@ class Args() : restart = None init_model = None inter_threads = 0 + log_path = None + log_level = 0 + mpi_log = "master" class TestDataModifier (unittest.TestCase) : diff --git a/source/tests/test_data_modifier_shuffle.py b/source/tests/test_data_modifier_shuffle.py index 457020c31e..738d379721 100644 --- a/source/tests/test_data_modifier_shuffle.py +++ b/source/tests/test_data_modifier_shuffle.py @@ -8,16 +8,16 @@ from deepmd.run_options import RunOptions from deepmd.trainer import NNPTrainer from deepmd.utils.data_system import DeepmdDataSystem -from deepmd.run_options import global_tf_float_precision -from deepmd.run_options import global_np_float_precision -from deepmd.run_options import global_ener_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION from deepmd.infer.ewald_recp import EwaldRecp from deepmd.infer.data_modifier import DipoleChargeModifier from deepmd.infer.deep_dipole import DeepDipole from common import Data -if global_np_float_precision == np.float32 : +if GLOBAL_NP_FLOAT_PRECISION == np.float32 : global_default_fv_hh = 1e-2 global_default_dw_hh = 1e-2 global_default_places = 3 @@ -33,6 +33,9 @@ class Args() : restart = None init_model = None inter_threads = 0 + log_path = None + log_level = 0 + mpi_log = "master" class TestDataModifier (unittest.TestCase) : diff --git a/source/tests/test_deepmd_data.py b/source/tests/test_deepmd_data.py index 49314faf81..2f01099137 100644 --- a/source/tests/test_deepmd_data.py +++ b/source/tests/test_deepmd_data.py @@ -3,9 +3,9 @@ import unittest from deepmd.utils.data import DeepmdData -from deepmd.run_options import global_np_float_precision +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -if global_np_float_precision == np.float32 : +if GLOBAL_NP_FLOAT_PRECISION == np.float32 : places = 6 else: places = 12 diff --git a/source/tests/test_deepmd_data_sys.py b/source/tests/test_deepmd_data_sys.py index 1e6c46ba10..c710878f73 100644 --- a/source/tests/test_deepmd_data_sys.py +++ b/source/tests/test_deepmd_data_sys.py @@ -3,9 +3,9 @@ import unittest from deepmd.utils.data_system import DeepmdDataSystem -from deepmd.run_options import global_np_float_precision +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -if global_np_float_precision == np.float32 : +if GLOBAL_NP_FLOAT_PRECISION == np.float32 : places = 6 else: places = 12 diff --git a/source/tests/test_descrpt_nonsmth.py b/source/tests/test_descrpt_nonsmth.py index a4457f70c8..c6d283b69c 100644 --- a/source/tests/test_descrpt_nonsmth.py +++ b/source/tests/test_descrpt_nonsmth.py @@ -19,9 +19,9 @@ from deepmd.env import op_module -from deepmd.run_options import global_tf_float_precision -from deepmd.run_options import global_np_float_precision -from deepmd.run_options import global_ener_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION class Inter(): def setUp (self, @@ -45,8 +45,8 @@ def setUp (self, self.ndescrpt = self.ndescrpt_a + self.ndescrpt_r davg = np.zeros ([self.ntypes, self.ndescrpt]) dstd = np.ones ([self.ntypes, self.ndescrpt]) - self.t_avg = tf.constant(davg.astype(global_np_float_precision)) - self.t_std = tf.constant(dstd.astype(global_np_float_precision)) + self.t_avg = tf.constant(davg.astype(GLOBAL_NP_FLOAT_PRECISION)) + self.t_std = tf.constant(dstd.astype(GLOBAL_NP_FLOAT_PRECISION)) if pbc: self.default_mesh = np.zeros (6, dtype = np.int32) self.default_mesh[3] = 2 @@ -55,11 +55,11 @@ def setUp (self, else : self.default_mesh = np.array([], dtype = np.int32) # make place holder - self.coord = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_coord') - self.box = tf.placeholder(global_tf_float_precision, [None, 9], name='t_box') + self.coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, self.natoms[0] * 3], name='t_coord') + self.box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, 9], name='t_box') self.type = tf.placeholder(tf.int32, [None, self.natoms[0]], name = "t_type") self.tnatoms = tf.placeholder(tf.int32, [None], name = "t_natoms") - self.efield = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_efield') + self.efield = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, self.natoms[0] * 3], name='t_efield') def _net (self, @@ -69,7 +69,7 @@ def _net (self, with tf.variable_scope(name, reuse=reuse): net_w = tf.get_variable ('net_w', [self.ndescrpt], - global_tf_float_precision, + GLOBAL_TF_FLOAT_PRECISION, tf.constant_initializer (self.net_w_i)) dot_v = tf.matmul (tf.reshape (inputs, [-1, self.ndescrpt]), tf.reshape (net_w, [self.ndescrpt, 1])) @@ -134,7 +134,7 @@ def comp_f_dw (self, reuse = None) : energy, force, virial = self.comp_ef (dcoord, dbox, dtype, tnatoms, name, reuse) with tf.variable_scope(name, reuse=True): - net_w = tf.get_variable ('net_w', [self.ndescrpt], global_tf_float_precision, tf.constant_initializer (self.net_w_i)) + net_w = tf.get_variable ('net_w', [self.ndescrpt], GLOBAL_TF_FLOAT_PRECISION, tf.constant_initializer (self.net_w_i)) f_mag = tf.reduce_sum (tf.nn.tanh(force)) f_mag_dw = tf.gradients (f_mag, net_w) assert (len(f_mag_dw) == 1), "length of dw is wrong" @@ -150,7 +150,7 @@ def comp_v_dw (self, reuse = None) : energy, force, virial = self.comp_ef (dcoord, dbox, dtype, tnatoms, name, reuse) with tf.variable_scope(name, reuse=True): - net_w = tf.get_variable ('net_w', [self.ndescrpt], global_tf_float_precision, tf.constant_initializer (self.net_w_i)) + net_w = tf.get_variable ('net_w', [self.ndescrpt], GLOBAL_TF_FLOAT_PRECISION, tf.constant_initializer (self.net_w_i)) v_mag = tf.reduce_sum (virial) v_mag_dw = tf.gradients (v_mag, net_w) assert (len(v_mag_dw) == 1), "length of dw is wrong" diff --git a/source/tests/test_descrpt_se_ar.py b/source/tests/test_descrpt_se_ar.py index 79153fe6c6..e1d8532f5a 100644 --- a/source/tests/test_descrpt_se_ar.py +++ b/source/tests/test_descrpt_se_ar.py @@ -21,9 +21,9 @@ from deepmd.descriptor import DescrptSeAR -from deepmd.run_options import global_tf_float_precision -from deepmd.run_options import global_np_float_precision -from deepmd.run_options import global_ener_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION class Inter(): def setUp (self, @@ -64,11 +64,11 @@ def setUp (self, self.default_mesh[4] = 2 self.default_mesh[5] = 2 # make place holder - self.coord = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_coord') - self.box = tf.placeholder(global_tf_float_precision, [None, 9], name='t_box') + self.coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, self.natoms[0] * 3], name='t_coord') + self.box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, 9], name='t_box') self.type = tf.placeholder(tf.int32, [None, self.natoms[0]], name = "t_type") self.tnatoms = tf.placeholder(tf.int32, [None], name = "t_natoms") - self.efield = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_efield') + self.efield = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, self.natoms[0] * 3], name='t_efield') def _net (self, inputs, @@ -77,7 +77,7 @@ def _net (self, with tf.variable_scope(name, reuse=reuse): net_w = tf.get_variable ('net_w', [self.descrpt.get_dim_out()], - global_tf_float_precision, + GLOBAL_TF_FLOAT_PRECISION, tf.constant_initializer (self.net_w_i)) dot_v = tf.matmul (tf.reshape (inputs, [-1, self.descrpt.get_dim_out()]), tf.reshape (net_w, [self.descrpt.get_dim_out(), 1])) diff --git a/source/tests/test_descrpt_se_r.py b/source/tests/test_descrpt_se_r.py index c4a4661bc4..3a07ff4fd2 100644 --- a/source/tests/test_descrpt_se_r.py +++ b/source/tests/test_descrpt_se_r.py @@ -21,9 +21,9 @@ from deepmd.env import op_module -from deepmd.run_options import global_tf_float_precision -from deepmd.run_options import global_np_float_precision -from deepmd.run_options import global_ener_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION class Inter(): def setUp (self, @@ -41,8 +41,8 @@ def setUp (self, self.ndescrpt = self.nnei * 1 davg = np.zeros ([self.ntypes, self.ndescrpt]) dstd = np.ones ([self.ntypes, self.ndescrpt]) - self.t_avg = tf.constant(davg.astype(global_np_float_precision)) - self.t_std = tf.constant(dstd.astype(global_np_float_precision)) + self.t_avg = tf.constant(davg.astype(GLOBAL_NP_FLOAT_PRECISION)) + self.t_std = tf.constant(dstd.astype(GLOBAL_NP_FLOAT_PRECISION)) if pbc: self.default_mesh = np.zeros (6, dtype = np.int32) self.default_mesh[3] = 2 @@ -51,11 +51,11 @@ def setUp (self, else: self.default_mesh = np.array([], dtype = np.int32) # make place holder - self.coord = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_coord') - self.box = tf.placeholder(global_tf_float_precision, [None, 9], name='t_box') + self.coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, self.natoms[0] * 3], name='t_coord') + self.box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, 9], name='t_box') self.type = tf.placeholder(tf.int32, [None, self.natoms[0]], name = "t_type") self.tnatoms = tf.placeholder(tf.int32, [None], name = "t_natoms") - self.efield = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_efield') + self.efield = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, self.natoms[0] * 3], name='t_efield') def _net (self, inputs, @@ -64,7 +64,7 @@ def _net (self, with tf.variable_scope(name, reuse=reuse): net_w = tf.get_variable ('net_w', [self.ndescrpt], - global_tf_float_precision, + GLOBAL_TF_FLOAT_PRECISION, tf.constant_initializer (self.net_w_i)) dot_v = tf.matmul (tf.reshape (inputs, [-1, self.ndescrpt]), tf.reshape (net_w, [self.ndescrpt, 1])) @@ -117,7 +117,7 @@ def comp_f_dw (self, reuse = None) : energy, force, virial = self.comp_ef (dcoord, dbox, dtype, tnatoms, name, reuse) with tf.variable_scope(name, reuse=True): - net_w = tf.get_variable ('net_w', [self.ndescrpt], global_tf_float_precision, tf.constant_initializer (self.net_w_i)) + net_w = tf.get_variable ('net_w', [self.ndescrpt], GLOBAL_TF_FLOAT_PRECISION, tf.constant_initializer (self.net_w_i)) f_mag = tf.reduce_sum (tf.nn.tanh(force)) f_mag_dw = tf.gradients (f_mag, net_w) assert (len(f_mag_dw) == 1), "length of dw is wrong" @@ -133,7 +133,7 @@ def comp_v_dw (self, reuse = None) : energy, force, virial = self.comp_ef (dcoord, dbox, dtype, tnatoms, name, reuse) with tf.variable_scope(name, reuse=True): - net_w = tf.get_variable ('net_w', [self.ndescrpt], global_tf_float_precision, tf.constant_initializer (self.net_w_i)) + net_w = tf.get_variable ('net_w', [self.ndescrpt], GLOBAL_TF_FLOAT_PRECISION, tf.constant_initializer (self.net_w_i)) v_mag = tf.reduce_sum (virial) v_mag_dw = tf.gradients (v_mag, net_w) assert (len(v_mag_dw) == 1), "length of dw is wrong" diff --git a/source/tests/test_descrpt_sea_ef.py b/source/tests/test_descrpt_sea_ef.py index 76b41df617..6dc0b4b11e 100644 --- a/source/tests/test_descrpt_sea_ef.py +++ b/source/tests/test_descrpt_sea_ef.py @@ -21,9 +21,9 @@ from deepmd.env import op_module -from deepmd.run_options import global_tf_float_precision -from deepmd.run_options import global_np_float_precision -from deepmd.run_options import global_ener_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION class Inter(): def setUp (self, @@ -46,8 +46,8 @@ def setUp (self, self.ndescrpt = self.ndescrpt_a + self.ndescrpt_r davg = np.zeros ([self.ntypes, self.ndescrpt]) dstd = np.ones ([self.ntypes, self.ndescrpt]) - self.t_avg = tf.constant(davg.astype(global_np_float_precision)) - self.t_std = tf.constant(dstd.astype(global_np_float_precision)) + self.t_avg = tf.constant(davg.astype(GLOBAL_NP_FLOAT_PRECISION)) + self.t_std = tf.constant(dstd.astype(GLOBAL_NP_FLOAT_PRECISION)) if pbc: self.default_mesh = np.zeros (6, dtype = np.int32) self.default_mesh[3] = 2 @@ -56,9 +56,9 @@ def setUp (self, else: self.default_mesh = np.array([], dtype = np.int32) # make place holder - self.coord = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_coord') - self.efield = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_efield') - self.box = tf.placeholder(global_tf_float_precision, [None, 9], name='t_box') + self.coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, self.natoms[0] * 3], name='t_coord') + self.efield = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, self.natoms[0] * 3], name='t_efield') + self.box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, 9], name='t_box') self.type = tf.placeholder(tf.int32, [None, self.natoms[0]], name = "t_type") self.tnatoms = tf.placeholder(tf.int32, [None], name = "t_natoms") @@ -69,7 +69,7 @@ def _net (self, with tf.variable_scope(name, reuse=reuse): net_w = tf.get_variable ('net_w', [self.ndescrpt], - global_tf_float_precision, + GLOBAL_TF_FLOAT_PRECISION, tf.constant_initializer (self.net_w_i)) dot_v = tf.matmul (tf.reshape (inputs, [-1, self.ndescrpt]), tf.reshape (net_w, [self.ndescrpt, 1])) @@ -129,7 +129,7 @@ def comp_f_dw (self, reuse = None) : energy, force, virial = self.comp_ef (dcoord, dbox, dtype, tnatoms, name, reuse) with tf.variable_scope(name, reuse=True): - net_w = tf.get_variable ('net_w', [self.ndescrpt], global_tf_float_precision, tf.constant_initializer (self.net_w_i)) + net_w = tf.get_variable ('net_w', [self.ndescrpt], GLOBAL_TF_FLOAT_PRECISION, tf.constant_initializer (self.net_w_i)) f_mag = tf.reduce_sum (tf.nn.tanh(force)) f_mag_dw = tf.gradients (f_mag, net_w) assert (len(f_mag_dw) == 1), "length of dw is wrong" @@ -145,7 +145,7 @@ def comp_v_dw (self, reuse = None) : energy, force, virial = self.comp_ef (dcoord, dbox, dtype, tnatoms, name, reuse) with tf.variable_scope(name, reuse=True): - net_w = tf.get_variable ('net_w', [self.ndescrpt], global_tf_float_precision, tf.constant_initializer (self.net_w_i)) + net_w = tf.get_variable ('net_w', [self.ndescrpt], GLOBAL_TF_FLOAT_PRECISION, tf.constant_initializer (self.net_w_i)) v_mag = tf.reduce_sum (virial) v_mag_dw = tf.gradients (v_mag, net_w) assert (len(v_mag_dw) == 1), "length of dw is wrong" diff --git a/source/tests/test_descrpt_sea_ef_para.py b/source/tests/test_descrpt_sea_ef_para.py index 1642fedc9a..45ff7b333b 100644 --- a/source/tests/test_descrpt_sea_ef_para.py +++ b/source/tests/test_descrpt_sea_ef_para.py @@ -21,9 +21,9 @@ from deepmd.env import op_module -from deepmd.run_options import global_tf_float_precision -from deepmd.run_options import global_np_float_precision -from deepmd.run_options import global_ener_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION class Inter(): def setUp (self, @@ -46,8 +46,8 @@ def setUp (self, self.ndescrpt = self.ndescrpt_a + self.ndescrpt_r davg = np.zeros ([self.ntypes, self.ndescrpt]) dstd = np.ones ([self.ntypes, self.ndescrpt]) - self.t_avg = tf.constant(davg.astype(global_np_float_precision)) - self.t_std = tf.constant(dstd.astype(global_np_float_precision)) + self.t_avg = tf.constant(davg.astype(GLOBAL_NP_FLOAT_PRECISION)) + self.t_std = tf.constant(dstd.astype(GLOBAL_NP_FLOAT_PRECISION)) if pbc: self.default_mesh = np.zeros (6, dtype = np.int32) self.default_mesh[3] = 2 @@ -56,9 +56,9 @@ def setUp (self, else: self.default_mesh = np.array([], dtype = np.int32) # make place holder - self.coord = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_coord') - self.efield = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_efield') - self.box = tf.placeholder(global_tf_float_precision, [None, 9], name='t_box') + self.coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, self.natoms[0] * 3], name='t_coord') + self.efield = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, self.natoms[0] * 3], name='t_efield') + self.box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, 9], name='t_box') self.type = tf.placeholder(tf.int32, [None, self.natoms[0]], name = "t_type") self.tnatoms = tf.placeholder(tf.int32, [None], name = "t_natoms") @@ -69,7 +69,7 @@ def _net (self, with tf.variable_scope(name, reuse=reuse): net_w = tf.get_variable ('net_w', [self.ndescrpt], - global_tf_float_precision, + GLOBAL_TF_FLOAT_PRECISION, tf.constant_initializer (self.net_w_i)) dot_v = tf.matmul (tf.reshape (inputs, [-1, self.ndescrpt]), tf.reshape (net_w, [self.ndescrpt, 1])) @@ -129,7 +129,7 @@ def comp_f_dw (self, reuse = None) : energy, force, virial = self.comp_ef (dcoord, dbox, dtype, tnatoms, name, reuse) with tf.variable_scope(name, reuse=True): - net_w = tf.get_variable ('net_w', [self.ndescrpt], global_tf_float_precision, tf.constant_initializer (self.net_w_i)) + net_w = tf.get_variable ('net_w', [self.ndescrpt], GLOBAL_TF_FLOAT_PRECISION, tf.constant_initializer (self.net_w_i)) f_mag = tf.reduce_sum (tf.nn.tanh(force)) f_mag_dw = tf.gradients (f_mag, net_w) assert (len(f_mag_dw) == 1), "length of dw is wrong" @@ -145,7 +145,7 @@ def comp_v_dw (self, reuse = None) : energy, force, virial = self.comp_ef (dcoord, dbox, dtype, tnatoms, name, reuse) with tf.variable_scope(name, reuse=True): - net_w = tf.get_variable ('net_w', [self.ndescrpt], global_tf_float_precision, tf.constant_initializer (self.net_w_i)) + net_w = tf.get_variable ('net_w', [self.ndescrpt], GLOBAL_TF_FLOAT_PRECISION, tf.constant_initializer (self.net_w_i)) v_mag = tf.reduce_sum (virial) v_mag_dw = tf.gradients (v_mag, net_w) assert (len(v_mag_dw) == 1), "length of dw is wrong" diff --git a/source/tests/test_descrpt_sea_ef_rot.py b/source/tests/test_descrpt_sea_ef_rot.py index 5dd5c35818..904ccfd965 100644 --- a/source/tests/test_descrpt_sea_ef_rot.py +++ b/source/tests/test_descrpt_sea_ef_rot.py @@ -4,9 +4,9 @@ from deepmd.env import tf from tensorflow.python.framework import ops -from deepmd.run_options import global_tf_float_precision -from deepmd.run_options import global_np_float_precision -from deepmd.run_options import global_ener_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION from deepmd.env import op_module from deepmd.descriptor import DescrptSeA @@ -30,14 +30,14 @@ def setUp(self): self.ndescrpt = self.ndescrpt_a + self.ndescrpt_r davg = np.zeros ([self.ntypes, self.ndescrpt]) dstd = np.ones ([self.ntypes, self.ndescrpt]) - self.t_avg = tf.constant(davg.astype(global_np_float_precision)) - self.t_std = tf.constant(dstd.astype(global_np_float_precision)) + self.t_avg = tf.constant(davg.astype(GLOBAL_NP_FLOAT_PRECISION)) + self.t_std = tf.constant(dstd.astype(GLOBAL_NP_FLOAT_PRECISION)) # no pbc self.default_mesh = np.array([], dtype = np.int32) # make place holder - self.coord = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_coord') - self.efield = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_efield') - self.box = tf.placeholder(global_tf_float_precision, [None, 9], name='t_box') + self.coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, self.natoms[0] * 3], name='t_coord') + self.efield = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, self.natoms[0] * 3], name='t_efield') + self.box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, 9], name='t_box') self.type = tf.placeholder(tf.int32, [None, self.natoms[0]], name = "t_type") self.tnatoms = tf.placeholder(tf.int32, [None], name = "t_natoms") diff --git a/source/tests/test_descrpt_sea_ef_vert.py b/source/tests/test_descrpt_sea_ef_vert.py index d1784754d5..a4f180157a 100644 --- a/source/tests/test_descrpt_sea_ef_vert.py +++ b/source/tests/test_descrpt_sea_ef_vert.py @@ -21,9 +21,9 @@ from deepmd.env import op_module -from deepmd.run_options import global_tf_float_precision -from deepmd.run_options import global_np_float_precision -from deepmd.run_options import global_ener_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION class Inter(): def setUp (self, @@ -46,8 +46,8 @@ def setUp (self, self.ndescrpt = self.ndescrpt_a + self.ndescrpt_r davg = np.zeros ([self.ntypes, self.ndescrpt]) dstd = np.ones ([self.ntypes, self.ndescrpt]) - self.t_avg = tf.constant(davg.astype(global_np_float_precision)) - self.t_std = tf.constant(dstd.astype(global_np_float_precision)) + self.t_avg = tf.constant(davg.astype(GLOBAL_NP_FLOAT_PRECISION)) + self.t_std = tf.constant(dstd.astype(GLOBAL_NP_FLOAT_PRECISION)) if pbc: self.default_mesh = np.zeros (6, dtype = np.int32) self.default_mesh[3] = 2 @@ -56,9 +56,9 @@ def setUp (self, else: self.default_mesh = np.array([], dtype = np.int32) # make place holder - self.coord = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_coord') - self.efield = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_efield') - self.box = tf.placeholder(global_tf_float_precision, [None, 9], name='t_box') + self.coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, self.natoms[0] * 3], name='t_coord') + self.efield = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, self.natoms[0] * 3], name='t_efield') + self.box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, 9], name='t_box') self.type = tf.placeholder(tf.int32, [None, self.natoms[0]], name = "t_type") self.tnatoms = tf.placeholder(tf.int32, [None], name = "t_natoms") @@ -69,7 +69,7 @@ def _net (self, with tf.variable_scope(name, reuse=reuse): net_w = tf.get_variable ('net_w', [self.ndescrpt], - global_tf_float_precision, + GLOBAL_TF_FLOAT_PRECISION, tf.constant_initializer (self.net_w_i)) dot_v = tf.matmul (tf.reshape (inputs, [-1, self.ndescrpt]), tf.reshape (net_w, [self.ndescrpt, 1])) @@ -129,7 +129,7 @@ def comp_f_dw (self, reuse = None) : energy, force, virial = self.comp_ef (dcoord, dbox, dtype, tnatoms, name, reuse) with tf.variable_scope(name, reuse=True): - net_w = tf.get_variable ('net_w', [self.ndescrpt], global_tf_float_precision, tf.constant_initializer (self.net_w_i)) + net_w = tf.get_variable ('net_w', [self.ndescrpt], GLOBAL_TF_FLOAT_PRECISION, tf.constant_initializer (self.net_w_i)) f_mag = tf.reduce_sum (tf.nn.tanh(force)) f_mag_dw = tf.gradients (f_mag, net_w) assert (len(f_mag_dw) == 1), "length of dw is wrong" @@ -145,7 +145,7 @@ def comp_v_dw (self, reuse = None) : energy, force, virial = self.comp_ef (dcoord, dbox, dtype, tnatoms, name, reuse) with tf.variable_scope(name, reuse=True): - net_w = tf.get_variable ('net_w', [self.ndescrpt], global_tf_float_precision, tf.constant_initializer (self.net_w_i)) + net_w = tf.get_variable ('net_w', [self.ndescrpt], GLOBAL_TF_FLOAT_PRECISION, tf.constant_initializer (self.net_w_i)) v_mag = tf.reduce_sum (virial) v_mag_dw = tf.gradients (v_mag, net_w) assert (len(v_mag_dw) == 1), "length of dw is wrong" diff --git a/source/tests/test_descrpt_smooth.py b/source/tests/test_descrpt_smooth.py index 09eba2a36c..7dce811f1e 100644 --- a/source/tests/test_descrpt_smooth.py +++ b/source/tests/test_descrpt_smooth.py @@ -21,9 +21,9 @@ from deepmd.env import op_module -from deepmd.run_options import global_tf_float_precision -from deepmd.run_options import global_np_float_precision -from deepmd.run_options import global_ener_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION class Inter(): def setUp (self, @@ -46,8 +46,8 @@ def setUp (self, self.ndescrpt = self.ndescrpt_a + self.ndescrpt_r davg = np.zeros ([self.ntypes, self.ndescrpt]) dstd = np.ones ([self.ntypes, self.ndescrpt]) - self.t_avg = tf.constant(davg.astype(global_np_float_precision)) - self.t_std = tf.constant(dstd.astype(global_np_float_precision)) + self.t_avg = tf.constant(davg.astype(GLOBAL_NP_FLOAT_PRECISION)) + self.t_std = tf.constant(dstd.astype(GLOBAL_NP_FLOAT_PRECISION)) if pbc: self.default_mesh = np.zeros (6, dtype = np.int32) self.default_mesh[3] = 2 @@ -56,11 +56,11 @@ def setUp (self, else: self.default_mesh = np.array([], dtype = np.int32) # make place holder - self.coord = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_coord') - self.box = tf.placeholder(global_tf_float_precision, [None, 9], name='t_box') + self.coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, self.natoms[0] * 3], name='t_coord') + self.box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, 9], name='t_box') self.type = tf.placeholder(tf.int32, [None, self.natoms[0]], name = "t_type") self.tnatoms = tf.placeholder(tf.int32, [None], name = "t_natoms") - self.efield = tf.placeholder(global_tf_float_precision, [None, self.natoms[0] * 3], name='t_efield') + self.efield = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, self.natoms[0] * 3], name='t_efield') def _net (self, inputs, @@ -69,7 +69,7 @@ def _net (self, with tf.variable_scope(name, reuse=reuse): net_w = tf.get_variable ('net_w', [self.ndescrpt], - global_tf_float_precision, + GLOBAL_TF_FLOAT_PRECISION, tf.constant_initializer (self.net_w_i)) dot_v = tf.matmul (tf.reshape (inputs, [-1, self.ndescrpt]), tf.reshape (net_w, [self.ndescrpt, 1])) @@ -128,7 +128,7 @@ def comp_f_dw (self, reuse = None) : energy, force, virial = self.comp_ef (dcoord, dbox, dtype, tnatoms, name, reuse) with tf.variable_scope(name, reuse=True): - net_w = tf.get_variable ('net_w', [self.ndescrpt], global_tf_float_precision, tf.constant_initializer (self.net_w_i)) + net_w = tf.get_variable ('net_w', [self.ndescrpt], GLOBAL_TF_FLOAT_PRECISION, tf.constant_initializer (self.net_w_i)) f_mag = tf.reduce_sum (tf.nn.tanh(force)) f_mag_dw = tf.gradients (f_mag, net_w) assert (len(f_mag_dw) == 1), "length of dw is wrong" @@ -144,7 +144,7 @@ def comp_v_dw (self, reuse = None) : energy, force, virial = self.comp_ef (dcoord, dbox, dtype, tnatoms, name, reuse) with tf.variable_scope(name, reuse=True): - net_w = tf.get_variable ('net_w', [self.ndescrpt], global_tf_float_precision, tf.constant_initializer (self.net_w_i)) + net_w = tf.get_variable ('net_w', [self.ndescrpt], GLOBAL_TF_FLOAT_PRECISION, tf.constant_initializer (self.net_w_i)) v_mag = tf.reduce_sum (virial) v_mag_dw = tf.gradients (v_mag, net_w) assert (len(v_mag_dw) == 1), "length of dw is wrong" diff --git a/source/tests/test_embedding_net.py b/source/tests/test_embedding_net.py index c508b461da..f7839b6408 100644 --- a/source/tests/test_embedding_net.py +++ b/source/tests/test_embedding_net.py @@ -7,9 +7,9 @@ from deepmd.utils.network import embedding_net -from deepmd.run_options import global_tf_float_precision -from deepmd.run_options import global_np_float_precision -from deepmd.run_options import global_ener_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION class Inter(unittest.TestCase): def setUp (self) : diff --git a/source/tests/test_ewald.py b/source/tests/test_ewald.py index 02a7091a1f..2864336ca0 100644 --- a/source/tests/test_ewald.py +++ b/source/tests/test_ewald.py @@ -3,13 +3,13 @@ import unittest from deepmd.env import tf -from deepmd.run_options import global_tf_float_precision -from deepmd.run_options import global_np_float_precision -from deepmd.run_options import global_ener_float_precision +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION from deepmd.infer.ewald_recp import op_module from deepmd.infer.ewald_recp import EwaldRecp -if global_np_float_precision == np.float32 : +if GLOBAL_NP_FLOAT_PRECISION == np.float32 : global_default_fv_hh = 1e-2 global_default_dw_hh = 1e-2 global_default_places = 3 @@ -54,9 +54,9 @@ def setUp(self): self.dcoord = np.array(self.dcoord).reshape([self.nframes, 3*self.natoms]) self.dcharge = np.array(self.dcharge).reshape([self.nframes, self.natoms]) # place holders - self.coord = tf.placeholder(global_tf_float_precision, [None], name='t_coord') - self.charge = tf.placeholder(global_tf_float_precision, [None], name='t_charge') - self.box = tf.placeholder(global_tf_float_precision, [None], name='t_box') + self.coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_coord') + self.charge = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_charge') + self.box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_box') self.nloc = tf.placeholder(tf.int32, [1], name = "t_nloc") def test_py_interface(self): diff --git a/source/tests/test_model_loc_frame.py b/source/tests/test_model_loc_frame.py index 0ed30e7c00..cf8fb7417e 100644 --- a/source/tests/test_model_loc_frame.py +++ b/source/tests/test_model_loc_frame.py @@ -10,9 +10,9 @@ from deepmd.model import Model from deepmd.common import j_must_have, j_loader -global_ener_float_precision = tf.float64 -global_tf_float_precision = tf.float64 -global_np_float_precision = np.float64 +GLOBAL_ENER_FLOAT_PRECISION = tf.float64 +GLOBAL_TF_FLOAT_PRECISION = tf.float64 +GLOBAL_NP_FLOAT_PRECISION = np.float64 class TestModel(unittest.TestCase): @@ -56,14 +56,14 @@ def test_model(self): model.fitting.bias_atom_e = data.compute_energy_shift() t_prop_c = tf.placeholder(tf.float32, [5], name='t_prop_c') - t_energy = tf.placeholder(global_ener_float_precision, [None], name='t_energy') - t_force = tf.placeholder(global_tf_float_precision, [None], name='t_force') - t_virial = tf.placeholder(global_tf_float_precision, [None], name='t_virial') - t_atom_ener = tf.placeholder(global_tf_float_precision, [None], name='t_atom_ener') - t_coord = tf.placeholder(global_tf_float_precision, [None], name='i_coord') + t_energy = tf.placeholder(GLOBAL_ENER_FLOAT_PRECISION, [None], name='t_energy') + t_force = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_force') + t_virial = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_virial') + t_atom_ener = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_atom_ener') + t_coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='i_coord') t_type = tf.placeholder(tf.int32, [None], name='i_type') t_natoms = tf.placeholder(tf.int32, [model.ntypes+2], name='i_natoms') - t_box = tf.placeholder(global_tf_float_precision, [None, 9], name='i_box') + t_box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, 9], name='i_box') t_mesh = tf.placeholder(tf.int32, [None], name='i_mesh') is_training = tf.placeholder(tf.bool) t_fparam = None diff --git a/source/tests/test_model_se_a.py b/source/tests/test_model_se_a.py index 62fedfe7a5..4f0c3f0562 100644 --- a/source/tests/test_model_se_a.py +++ b/source/tests/test_model_se_a.py @@ -11,9 +11,9 @@ from deepmd.model import Model from deepmd.common import j_must_have, j_loader -global_ener_float_precision = tf.float64 -global_tf_float_precision = tf.float64 -global_np_float_precision = np.float64 +GLOBAL_ENER_FLOAT_PRECISION = tf.float64 +GLOBAL_TF_FLOAT_PRECISION = tf.float64 +GLOBAL_NP_FLOAT_PRECISION = np.float64 class TestModel(unittest.TestCase): def setUp(self) : @@ -55,14 +55,14 @@ def test_model(self): model.descrpt.bias_atom_e = data.compute_energy_shift() t_prop_c = tf.placeholder(tf.float32, [5], name='t_prop_c') - t_energy = tf.placeholder(global_ener_float_precision, [None], name='t_energy') - t_force = tf.placeholder(global_tf_float_precision, [None], name='t_force') - t_virial = tf.placeholder(global_tf_float_precision, [None], name='t_virial') - t_atom_ener = tf.placeholder(global_tf_float_precision, [None], name='t_atom_ener') - t_coord = tf.placeholder(global_tf_float_precision, [None], name='i_coord') + t_energy = tf.placeholder(GLOBAL_ENER_FLOAT_PRECISION, [None], name='t_energy') + t_force = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_force') + t_virial = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_virial') + t_atom_ener = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_atom_ener') + t_coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='i_coord') t_type = tf.placeholder(tf.int32, [None], name='i_type') t_natoms = tf.placeholder(tf.int32, [model.ntypes+2], name='i_natoms') - t_box = tf.placeholder(global_tf_float_precision, [None, 9], name='i_box') + t_box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, 9], name='i_box') t_mesh = tf.placeholder(tf.int32, [None], name='i_mesh') is_training = tf.placeholder(tf.bool) t_fparam = None diff --git a/source/tests/test_model_se_a_aparam.py b/source/tests/test_model_se_a_aparam.py index 29f3539505..352e5c7931 100644 --- a/source/tests/test_model_se_a_aparam.py +++ b/source/tests/test_model_se_a_aparam.py @@ -10,9 +10,9 @@ from deepmd.model import Model from deepmd.common import j_must_have, j_loader -global_ener_float_precision = tf.float64 -global_tf_float_precision = tf.float64 -global_np_float_precision = np.float64 +GLOBAL_ENER_FLOAT_PRECISION = tf.float64 +GLOBAL_TF_FLOAT_PRECISION = tf.float64 +GLOBAL_NP_FLOAT_PRECISION = np.float64 class TestModel(unittest.TestCase): def setUp(self) : @@ -56,16 +56,16 @@ def test_model(self): model.descrpt.bias_atom_e = data.compute_energy_shift() t_prop_c = tf.placeholder(tf.float32, [5], name='t_prop_c') - t_energy = tf.placeholder(global_ener_float_precision, [None], name='t_energy') - t_force = tf.placeholder(global_tf_float_precision, [None], name='t_force') - t_virial = tf.placeholder(global_tf_float_precision, [None], name='t_virial') - t_atom_ener = tf.placeholder(global_tf_float_precision, [None], name='t_atom_ener') - t_coord = tf.placeholder(global_tf_float_precision, [None], name='i_coord') + t_energy = tf.placeholder(GLOBAL_ENER_FLOAT_PRECISION, [None], name='t_energy') + t_force = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_force') + t_virial = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_virial') + t_atom_ener = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_atom_ener') + t_coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='i_coord') t_type = tf.placeholder(tf.int32, [None], name='i_type') t_natoms = tf.placeholder(tf.int32, [model.ntypes+2], name='i_natoms') - t_box = tf.placeholder(global_tf_float_precision, [None, 9], name='i_box') + t_box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, 9], name='i_box') t_mesh = tf.placeholder(tf.int32, [None], name='i_mesh') - t_aparam = tf.placeholder(global_tf_float_precision, [None], name='i_aparam') + t_aparam = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='i_aparam') is_training = tf.placeholder(tf.bool) input_dict = {} input_dict['aparam'] = t_aparam diff --git a/source/tests/test_model_se_a_fparam.py b/source/tests/test_model_se_a_fparam.py index 79932d0014..4235b03e5b 100644 --- a/source/tests/test_model_se_a_fparam.py +++ b/source/tests/test_model_se_a_fparam.py @@ -10,9 +10,9 @@ from deepmd.model import Model from deepmd.common import j_must_have, j_loader -global_ener_float_precision = tf.float64 -global_tf_float_precision = tf.float64 -global_np_float_precision = np.float64 +GLOBAL_ENER_FLOAT_PRECISION = tf.float64 +GLOBAL_TF_FLOAT_PRECISION = tf.float64 +GLOBAL_NP_FLOAT_PRECISION = np.float64 class TestModel(unittest.TestCase): def setUp(self) : @@ -57,16 +57,16 @@ def test_model(self): model.descrpt.bias_atom_e = data.compute_energy_shift() t_prop_c = tf.placeholder(tf.float32, [5], name='t_prop_c') - t_energy = tf.placeholder(global_ener_float_precision, [None], name='t_energy') - t_force = tf.placeholder(global_tf_float_precision, [None], name='t_force') - t_virial = tf.placeholder(global_tf_float_precision, [None], name='t_virial') - t_atom_ener = tf.placeholder(global_tf_float_precision, [None], name='t_atom_ener') - t_coord = tf.placeholder(global_tf_float_precision, [None], name='i_coord') + t_energy = tf.placeholder(GLOBAL_ENER_FLOAT_PRECISION, [None], name='t_energy') + t_force = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_force') + t_virial = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_virial') + t_atom_ener = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_atom_ener') + t_coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='i_coord') t_type = tf.placeholder(tf.int32, [None], name='i_type') t_natoms = tf.placeholder(tf.int32, [model.ntypes+2], name='i_natoms') - t_box = tf.placeholder(global_tf_float_precision, [None, 9], name='i_box') + t_box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, 9], name='i_box') t_mesh = tf.placeholder(tf.int32, [None], name='i_mesh') - t_fparam = tf.placeholder(global_tf_float_precision, [None], name='i_fparam') + t_fparam = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='i_fparam') is_training = tf.placeholder(tf.bool) input_dict = {} input_dict['fparam'] = t_fparam diff --git a/source/tests/test_model_se_a_srtab.py b/source/tests/test_model_se_a_srtab.py index b967c78fb6..3debcb97b1 100644 --- a/source/tests/test_model_se_a_srtab.py +++ b/source/tests/test_model_se_a_srtab.py @@ -10,9 +10,9 @@ from deepmd.model import Model from deepmd.common import j_must_have, j_loader -global_ener_float_precision = tf.float64 -global_tf_float_precision = tf.float64 -global_np_float_precision = np.float64 +GLOBAL_ENER_FLOAT_PRECISION = tf.float64 +GLOBAL_TF_FLOAT_PRECISION = tf.float64 +GLOBAL_NP_FLOAT_PRECISION = np.float64 def _make_tab(ntype) : xx = np.arange(0,9,0.001) @@ -66,14 +66,14 @@ def test_model(self): model.descrpt.bias_atom_e = data.compute_energy_shift() t_prop_c = tf.placeholder(tf.float32, [5], name='t_prop_c') - t_energy = tf.placeholder(global_ener_float_precision, [None], name='t_energy') - t_force = tf.placeholder(global_tf_float_precision, [None], name='t_force') - t_virial = tf.placeholder(global_tf_float_precision, [None], name='t_virial') - t_atom_ener = tf.placeholder(global_tf_float_precision, [None], name='t_atom_ener') - t_coord = tf.placeholder(global_tf_float_precision, [None], name='i_coord') + t_energy = tf.placeholder(GLOBAL_ENER_FLOAT_PRECISION, [None], name='t_energy') + t_force = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_force') + t_virial = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_virial') + t_atom_ener = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_atom_ener') + t_coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='i_coord') t_type = tf.placeholder(tf.int32, [None], name='i_type') t_natoms = tf.placeholder(tf.int32, [model.ntypes+2], name='i_natoms') - t_box = tf.placeholder(global_tf_float_precision, [None, 9], name='i_box') + t_box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, 9], name='i_box') t_mesh = tf.placeholder(tf.int32, [None], name='i_mesh') is_training = tf.placeholder(tf.bool) t_fparam = None diff --git a/source/tests/test_model_se_r.py b/source/tests/test_model_se_r.py index 32aa43235b..8b32e99125 100644 --- a/source/tests/test_model_se_r.py +++ b/source/tests/test_model_se_r.py @@ -10,9 +10,9 @@ from deepmd.model import Model from deepmd.common import j_must_have, j_loader -global_ener_float_precision = tf.float64 -global_tf_float_precision = tf.float64 -global_np_float_precision = np.float64 +GLOBAL_ENER_FLOAT_PRECISION = tf.float64 +GLOBAL_TF_FLOAT_PRECISION = tf.float64 +GLOBAL_NP_FLOAT_PRECISION = np.float64 class TestModel(unittest.TestCase): def setUp(self) : @@ -55,14 +55,14 @@ def test_model(self): model.descrpt.bias_atom_e = data.compute_energy_shift() t_prop_c = tf.placeholder(tf.float32, [5], name='t_prop_c') - t_energy = tf.placeholder(global_ener_float_precision, [None], name='t_energy') - t_force = tf.placeholder(global_tf_float_precision, [None], name='t_force') - t_virial = tf.placeholder(global_tf_float_precision, [None], name='t_virial') - t_atom_ener = tf.placeholder(global_tf_float_precision, [None], name='t_atom_ener') - t_coord = tf.placeholder(global_tf_float_precision, [None], name='i_coord') + t_energy = tf.placeholder(GLOBAL_ENER_FLOAT_PRECISION, [None], name='t_energy') + t_force = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_force') + t_virial = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_virial') + t_atom_ener = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_atom_ener') + t_coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='i_coord') t_type = tf.placeholder(tf.int32, [None], name='i_type') t_natoms = tf.placeholder(tf.int32, [model.ntypes+2], name='i_natoms') - t_box = tf.placeholder(global_tf_float_precision, [None, 9], name='i_box') + t_box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, 9], name='i_box') t_mesh = tf.placeholder(tf.int32, [None], name='i_mesh') is_training = tf.placeholder(tf.bool) t_fparam = None diff --git a/source/tests/test_polar_se_a.py b/source/tests/test_polar_se_a.py index a36553b296..468f219474 100644 --- a/source/tests/test_polar_se_a.py +++ b/source/tests/test_polar_se_a.py @@ -10,9 +10,9 @@ from deepmd.model import PolarModel from deepmd.common import j_must_have, j_loader -global_ener_float_precision = tf.float64 -global_tf_float_precision = tf.float64 -global_np_float_precision = np.float64 +GLOBAL_ENER_FLOAT_PRECISION = tf.float64 +GLOBAL_TF_FLOAT_PRECISION = tf.float64 +GLOBAL_NP_FLOAT_PRECISION = np.float64 class TestModel(unittest.TestCase): def setUp(self) : @@ -55,14 +55,14 @@ def test_model(self): model._compute_input_stat(input_data) t_prop_c = tf.placeholder(tf.float32, [5], name='t_prop_c') - t_energy = tf.placeholder(global_ener_float_precision, [None], name='t_energy') - t_force = tf.placeholder(global_tf_float_precision, [None], name='t_force') - t_virial = tf.placeholder(global_tf_float_precision, [None], name='t_virial') - t_atom_ener = tf.placeholder(global_tf_float_precision, [None], name='t_atom_ener') - t_coord = tf.placeholder(global_tf_float_precision, [None], name='i_coord') + t_energy = tf.placeholder(GLOBAL_ENER_FLOAT_PRECISION, [None], name='t_energy') + t_force = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_force') + t_virial = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_virial') + t_atom_ener = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_atom_ener') + t_coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='i_coord') t_type = tf.placeholder(tf.int32, [None], name='i_type') t_natoms = tf.placeholder(tf.int32, [model.ntypes+2], name='i_natoms') - t_box = tf.placeholder(global_tf_float_precision, [None, 9], name='i_box') + t_box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, 9], name='i_box') t_mesh = tf.placeholder(tf.int32, [None], name='i_mesh') is_training = tf.placeholder(tf.bool) t_fparam = None diff --git a/source/tests/test_wfc.py b/source/tests/test_wfc.py index 9319d9b9cf..272310effa 100644 --- a/source/tests/test_wfc.py +++ b/source/tests/test_wfc.py @@ -10,9 +10,9 @@ from deepmd.model import WFCModel from deepmd.common import j_must_have, j_loader -global_ener_float_precision = tf.float64 -global_tf_float_precision = tf.float64 -global_np_float_precision = np.float64 +GLOBAL_ENER_FLOAT_PRECISION = tf.float64 +GLOBAL_TF_FLOAT_PRECISION = tf.float64 +GLOBAL_NP_FLOAT_PRECISION = np.float64 class TestModel(unittest.TestCase): def setUp(self) : @@ -53,14 +53,14 @@ def test_model(self): model._compute_input_stat(input_data) t_prop_c = tf.placeholder(tf.float32, [5], name='t_prop_c') - t_energy = tf.placeholder(global_ener_float_precision, [None], name='t_energy') - t_force = tf.placeholder(global_tf_float_precision, [None], name='t_force') - t_virial = tf.placeholder(global_tf_float_precision, [None], name='t_virial') - t_atom_ener = tf.placeholder(global_tf_float_precision, [None], name='t_atom_ener') - t_coord = tf.placeholder(global_tf_float_precision, [None], name='i_coord') + t_energy = tf.placeholder(GLOBAL_ENER_FLOAT_PRECISION, [None], name='t_energy') + t_force = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_force') + t_virial = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_virial') + t_atom_ener = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_atom_ener') + t_coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='i_coord') t_type = tf.placeholder(tf.int32, [None], name='i_type') t_natoms = tf.placeholder(tf.int32, [model.ntypes+2], name='i_natoms') - t_box = tf.placeholder(global_tf_float_precision, [None, 9], name='i_box') + t_box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, 9], name='i_box') t_mesh = tf.placeholder(tf.int32, [None], name='i_mesh') is_training = tf.placeholder(tf.bool) t_fparam = None diff --git a/source/train/main.py b/source/train/main.py index 106b9c239b..90da030016 100644 --- a/source/train/main.py +++ b/source/train/main.py @@ -3,7 +3,7 @@ import argparse from pathlib import Path -from deepmd.utils.loggers import set_log_handles +from deepmd.loggers import set_log_handles from .config import config from .doc import doc_train_input @@ -124,7 +124,7 @@ def main(): "--mpi-log", type=str, default="master", - options=("master", "collect", "workers"), + choices=("master", "collect", "workers"), help="Set the manner of logging when running with MPI. 'master' logs only on " "main process, 'collect' broadcasts logs from workers to master and 'workers' " "means each process will output its own log" diff --git a/source/train/run_options.py b/source/train/run_options.py index 74660d8fce..ee4cc48803 100644 --- a/source/train/run_options.py +++ b/source/train/run_options.py @@ -2,7 +2,6 @@ import logging import os -import sys from configparser import ConfigParser from pathlib import Path from typing import TYPE_CHECKING, Dict, List, Optional, Tuple @@ -10,7 +9,7 @@ import numpy as np from deepmd.cluster import get_resource from deepmd.env import get_tf_default_nthreads, tf -from deepmd.utils.loggers import set_log_handles +from deepmd.loggers import set_log_handles if TYPE_CHECKING: try: @@ -46,7 +45,7 @@ class ArgsProto(Protocol): def _get_package_constants( - config_file: str = "config/run_config.ini", + config_file: Path = Path(__file__).parent / "config/run_config.ini", ) -> Dict[str, str]: """Read package constants set at compile time by CMake to dictionary. @@ -67,7 +66,7 @@ def _get_package_constants( GLOBAL_CONFIG = _get_package_constants() -if GLOBAL_CONFIG["PRECISION"] == "-DHIGH_PREC": +if GLOBAL_CONFIG["precision"] == "-DHIGH_PREC": GLOBAL_TF_FLOAT_PRECISION = tf.float64 GLOBAL_NP_FLOAT_PRECISION = np.float64 GLOBAL_ENER_FLOAT_PRECISION = np.float64 @@ -95,14 +94,14 @@ def _get_package_constants( _sep = "\n " BUILD = ( - f"installed to: {GLOBAL_CONFIG['INSTALL_PREFIX']}", - f"source : {GLOBAL_CONFIG['GIT_SUMM']}", - f"source brach: {GLOBAL_CONFIG['GIT_BRANCH']}", - f"source commit: {GLOBAL_CONFIG['GIT_HASH']}", - f"source commit at: {GLOBAL_CONFIG['GIT_DATE']}", + f"installed to: {GLOBAL_CONFIG['install_prefix']}", + f"source : {GLOBAL_CONFIG['git_summ']}", + f"source brach: {GLOBAL_CONFIG['git_branch']}", + f"source commit: {GLOBAL_CONFIG['git_hash']}", + f"source commit at: {GLOBAL_CONFIG['git_date']}", f"build float prec: {global_float_prec}", - f"build with tf inc: {GLOBAL_CONFIG['TF_INCLUDE_DIR']}", - f"build with tf lib: {GLOBAL_CONFIG['TF_LIBS'].replace(';', _sep)}" # noqa + f"build with tf inc: {GLOBAL_CONFIG['tf_include_dir']}", + f"build with tf lib: {GLOBAL_CONFIG['tf_libs'].replace(';', _sep)}" # noqa ) @@ -302,7 +301,6 @@ def __init__(self, args: Optional["ArgsProto"], try_distrib: bool = False): args.mpi_log, ) - def print_resource_summary(self): """Print build and current running cluster configuration summary.""" log.info("---Summary of the training---------------------------------------\n") diff --git a/source/train/train.py b/source/train/train.py index f3204b795f..e0cf6897ee 100755 --- a/source/train/train.py +++ b/source/train/train.py @@ -5,7 +5,7 @@ import numpy as np from deepmd.env import tf from deepmd.common import data_requirement, expand_sys_str, j_loader -from deepmd.run_options import RunOptions, WELCOME, CITATION, BUILD_EXTENDED +from deepmd.run_options import RunOptions, WELCOME, CITATION, BUILD from deepmd.trainer import NNPTrainer from deepmd.infer.data_modifier import DipoleChargeModifier from deepmd.utils.data_system import DeepmdDataSystem @@ -69,7 +69,7 @@ def train (args) : with_distrib = jdata['with_distrib'] run_opt = RunOptions(args, with_distrib) - for message in (WELCOME + CITATION + BUILD_EXTENDED): + for message in (WELCOME + CITATION + BUILD): log.info(message) run_opt.print_resource_summary() @@ -146,5 +146,5 @@ def _do_work(jdata, run_opt): start_time = time.time() model.train (data) end_time = time.time() - run_opt.message("finished training\nwall time: %.3f s" % (end_time-start_time)) + log.info("finished training\nwall time: %.3f s" % (end_time-start_time)) diff --git a/source/train/trainer.py b/source/train/trainer.py index 468aca4583..a9fbf41ed5 100644 --- a/source/train/trainer.py +++ b/source/train/trainer.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import logging import os import time import shutil @@ -36,6 +37,9 @@ from deepmd.common import j_must_have, ClassArg +log = logging.getLogger(__name__) + + def _is_subdir(path, directory): path = os.path.realpath(path) directory = os.path.realpath(directory) @@ -246,10 +250,6 @@ def _init_param(self, jdata): else : self.numb_fparam = 0 - - def _message (self, msg) : - self.run_opt.message(msg) - def build (self, data, stop_batch = 0) : @@ -263,9 +263,9 @@ def build (self, self.batch_size = data.get_batch_size() if self.numb_fparam > 0 : - self._message("training with %d frame parameter(s)" % self.numb_fparam) + log.info("training with %d frame parameter(s)" % self.numb_fparam) else: - self._message("training without frame parameter") + log.info("training without frame parameter") self.type_map = data.get_type_map() @@ -286,7 +286,7 @@ def _build_lr(self): self._extra_train_ops = [] self.global_step = tf.train.get_or_create_global_step() self.learning_rate = self.lr.build(self.global_step, self.stop_batch) - self._message("built lr") + log.info("built lr") def _build_network(self, data): self.place_holders = {} @@ -321,7 +321,7 @@ def _build_network(self, data): self.place_holders, suffix = "test") - self._message("built network") + log.info("built network") def _build_training(self): trainable_variables = tf.trainable_variables() @@ -339,20 +339,20 @@ def _build_training(self): name='train_step') train_ops = [apply_op] + self._extra_train_ops self.train_op = tf.group(*train_ops) - self._message("built training") + log.info("built training") def _init_sess_serial(self) : self.sess = tf.Session(config=default_tf_session_config) self.saver = tf.train.Saver() saver = self.saver if self.run_opt.init_mode == 'init_from_scratch' : - self._message("initialize model from scratch") + log.info("initialize model from scratch") init_op = tf.global_variables_initializer() self.sess.run(init_op) fp = open(self.disp_file, "w") fp.close () elif self.run_opt.init_mode == 'init_from_model' : - self._message("initialize from model %s" % self.run_opt.init_model) + log.info("initialize from model %s" % self.run_opt.init_model) init_op = tf.global_variables_initializer() self.sess.run(init_op) saver.restore (self.sess, self.run_opt.init_model) @@ -360,7 +360,7 @@ def _init_sess_serial(self) : fp = open(self.disp_file, "w") fp.close () elif self.run_opt.init_mode == 'restart' : - self._message("restart from model %s" % self.run_opt.restart) + log.info("restart from model %s" % self.run_opt.restart) init_op = tf.global_variables_initializer() self.sess.run(init_op) saver.restore (self.sess, self.run_opt.restart) @@ -371,7 +371,7 @@ def _init_sess_distrib(self): ckpt_dir = os.path.join(os.getcwd(), self.save_ckpt) assert(_is_subdir(ckpt_dir, os.getcwd())), "the checkpoint dir must be a subdir of the current dir" if self.run_opt.init_mode == 'init_from_scratch' : - self._message("initialize model from scratch") + log.info("initialize model from scratch") if self.run_opt.is_chief : if os.path.exists(ckpt_dir): shutil.rmtree(ckpt_dir) @@ -382,7 +382,7 @@ def _init_sess_distrib(self): elif self.run_opt.init_mode == 'init_from_model' : raise RuntimeError("distributed training does not support %s" % self.run_opt.init_mode) elif self.run_opt.init_mode == 'restart' : - self._message("restart from model %s" % ckpt_dir) + log.info("restart from model %s" % ckpt_dir) if self.run_opt.is_chief : assert(os.path.isdir(ckpt_dir)), "the checkpoint dir %s should exists" % ckpt_dir else : @@ -428,12 +428,12 @@ def train (self, cur_batch = self.sess.run(self.global_step) is_first_step = True self.cur_batch = cur_batch - self.run_opt.message("start training at lr %.2e (== %.2e), decay_step %d, decay_rate %f, final lr will be %.2e" % - (self.sess.run(self.learning_rate), - self.lr.value(cur_batch), - self.lr.decay_steps_, - self.lr.decay_rate_, - self.lr.value(stop_batch)) + log.info("start training at lr %.2e (== %.2e), decay_step %d, decay_rate %f, final lr will be %.2e" % + (self.sess.run(self.learning_rate), + self.lr.value(cur_batch), + self.lr.decay_steps_, + self.lr.decay_rate_, + self.lr.value(stop_batch)) ) prf_options = None @@ -493,13 +493,13 @@ def train (self, toc = time.time() test_time = toc - tic if self.timing_in_training : - self._message("batch %7d training time %.2f s, testing time %.2f s" + log.info("batch %7d training time %.2f s, testing time %.2f s" % (cur_batch, train_time, test_time)) train_time = 0 if self.save_freq > 0 and cur_batch % self.save_freq == 0 and self.run_opt.is_chief : if self.saver is not None : self.saver.save (self.sess, os.getcwd() + "/" + self.save_ckpt) - self._message("saved checkpoint %s" % self.save_ckpt) + log.info("saved checkpoint %s" % self.save_ckpt) if self.run_opt.is_chief: fp.close () if self.profiling and self.run_opt.is_chief : From f72d3bb414da56f8576446897c081732fe0b03ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Tue, 9 Feb 2021 20:09:19 +0100 Subject: [PATCH 122/562] small fixes --- deepmd/loggers/loggers.py | 4 ++++ doc/api.rst | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/deepmd/loggers/loggers.py b/deepmd/loggers/loggers.py index a7a4bc9640..8a27cf7797 100644 --- a/deepmd/loggers/loggers.py +++ b/deepmd/loggers/loggers.py @@ -161,6 +161,10 @@ def set_log_handles( ------ RuntimeError if only one of the arguments `mpi_log`, `MPI` is specified + + References + ---------- + https://groups.google.com/g/mpi4py/c/SaNzc8bdj6U """ # convert 0 - 3 to python logging level # we have debug=3 -> logging.DEBUG = 10 diff --git a/doc/api.rst b/doc/api.rst index 5163294601..07377d37b3 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -65,7 +65,7 @@ DeePMD-kit API :members: :undoc-members: -.. automodule:: deepmd.local +.. automodule:: deepmd.cluster.local :members: :undoc-members: From d52d8dcc75ccac90290454bb5dda60639248d68d Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 10 Feb 2021 08:33:11 +0800 Subject: [PATCH 123/562] refact prod_force_grad prod_virial_grad soft_min, add unittests --- source/lib/include/prod_force_grad.h | 11 ++ source/lib/include/prod_virial_grad.h | 12 ++ source/lib/include/soft_min_switch.h | 13 ++ source/lib/src/prod_force_grad.cc | 86 ++++++++++++ source/lib/src/prod_virial_grad.cc | 81 +++++++++++ source/lib/src/soft_min_switch.cc | 105 ++++++++++++++ source/lib/tests/test_prod_force_grad_a.cc | 96 +++++++++++++ source/lib/tests/test_prod_virial_grad_a.cc | 100 ++++++++++++++ source/lib/tests/test_soft_min_switch.cc | 143 ++++++++++++++++++++ source/op/prod_force_se_a_grad.cc | 41 ++---- source/op/prod_virial_se_a_grad.cc | 37 ++--- source/op/soft_min.cc | 72 ++-------- 12 files changed, 674 insertions(+), 123 deletions(-) create mode 100644 source/lib/include/prod_force_grad.h create mode 100644 source/lib/include/prod_virial_grad.h create mode 100644 source/lib/include/soft_min_switch.h create mode 100644 source/lib/src/prod_force_grad.cc create mode 100644 source/lib/src/prod_virial_grad.cc create mode 100644 source/lib/src/soft_min_switch.cc create mode 100644 source/lib/tests/test_prod_force_grad_a.cc create mode 100644 source/lib/tests/test_prod_virial_grad_a.cc create mode 100644 source/lib/tests/test_soft_min_switch.cc diff --git a/source/lib/include/prod_force_grad.h b/source/lib/include/prod_force_grad.h new file mode 100644 index 0000000000..6c1f9978c2 --- /dev/null +++ b/source/lib/include/prod_force_grad.h @@ -0,0 +1,11 @@ +#pragma once + +template +void prod_force_grad_a_cpu( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const int * nlist, + const int nloc, + const int nnei); + diff --git a/source/lib/include/prod_virial_grad.h b/source/lib/include/prod_virial_grad.h new file mode 100644 index 0000000000..5294b60dc3 --- /dev/null +++ b/source/lib/include/prod_virial_grad.h @@ -0,0 +1,12 @@ +#pragma once + +template +void prod_virial_grad_a_cpu( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nnei); + diff --git a/source/lib/include/soft_min_switch.h b/source/lib/include/soft_min_switch.h new file mode 100644 index 0000000000..67c88612b8 --- /dev/null +++ b/source/lib/include/soft_min_switch.h @@ -0,0 +1,13 @@ +#pragma once + +template +void soft_min_switch( + FPTYPE * sw_value, + FPTYPE * sw_deriv, + const FPTYPE * rij, + const int * nlist, + const int & nloc, + const int & nnei, + const FPTYPE & alpha, + const FPTYPE & rmin, + const FPTYPE & rmax); diff --git a/source/lib/src/prod_force_grad.cc b/source/lib/src/prod_force_grad.cc new file mode 100644 index 0000000000..8ff8c5f8b4 --- /dev/null +++ b/source/lib/src/prod_force_grad.cc @@ -0,0 +1,86 @@ +#include +#include +#include +#include "prod_force_grad.h" + +inline void +make_index_range ( + int & idx_start, + int & idx_end, + const int & nei_idx, + const int & nnei) +{ + if (nei_idx < nnei) { + idx_start = nei_idx * 4; + idx_end = nei_idx * 4 + 4; + } + else { + throw std::runtime_error("should no reach here"); + } +} + + +template +void prod_force_grad_a_cpu( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const int * nlist, + const int nloc, + const int nnei) +{ + const int ndescrpt = nnei * 4; + + // reset the frame to 0 + for (int ii = 0; ii < nloc; ++ii){ + for (int aa = 0; aa < ndescrpt; ++aa){ + grad_net[ii * ndescrpt + aa] = 0; + } + } + + // compute grad of one frame + for (int ii = 0; ii < nloc; ++ii){ + int i_idx = ii; + + // deriv wrt center atom + for (int aa = 0; aa < ndescrpt; ++aa){ + for (int dd = 0; dd < 3; ++dd){ + grad_net[i_idx * ndescrpt + aa] -= grad[i_idx * 3 + dd] * env_deriv[i_idx * ndescrpt * 3 + aa * 3 + dd]; + } + } + + // loop over neighbors + for (int jj = 0; jj < nnei; ++jj){ + int j_idx = nlist[i_idx * nnei + jj]; + if (j_idx >= nloc) j_idx = j_idx % nloc; + if (j_idx < 0) continue; + int aa_start, aa_end; + make_index_range(aa_start, aa_end, jj, nnei); + for (int aa = aa_start; aa < aa_end; ++aa){ + for (int dd = 0; dd < 3; ++dd){ + grad_net[i_idx * ndescrpt + aa] += grad[j_idx * 3 + dd] * env_deriv[i_idx * ndescrpt * 3 + aa * 3 + dd]; + } + } + } + } +} + + +template +void prod_force_grad_a_cpu( + double * grad_net, + const double * grad, + const double * env_deriv, + const int * nlist, + const int nloc, + const int nnei) ; + +template +void prod_force_grad_a_cpu( + float * grad_net, + const float * grad, + const float * env_deriv, + const int * nlist, + const int nloc, + const int nnei) ; + diff --git a/source/lib/src/prod_virial_grad.cc b/source/lib/src/prod_virial_grad.cc new file mode 100644 index 0000000000..2c14bdc85f --- /dev/null +++ b/source/lib/src/prod_virial_grad.cc @@ -0,0 +1,81 @@ +#include +#include +#include "prod_virial_grad.h" + +inline void +make_index_range ( + int & idx_start, + int & idx_end, + const int & nei_idx, + const int & nnei) +{ + if (nei_idx < nnei) { + idx_start = nei_idx * 4; + idx_end = nei_idx * 4 + 4; + } + else { + throw std::runtime_error("should no reach here"); + } +} + +template +void prod_virial_grad_a_cpu( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nnei) +{ + const int ndescrpt = nnei * 4; + + // reset the frame to 0 + for (int ii = 0; ii < nloc; ++ii){ + for (int aa = 0; aa < ndescrpt; ++aa){ + grad_net[ii * ndescrpt + aa] = 0; + } + } + + // compute grad of one frame + for (int ii = 0; ii < nloc; ++ii){ + int i_idx = ii; + + // loop over neighbors + for (int jj = 0; jj < nnei; ++jj){ + int j_idx = nlist[i_idx * nnei + jj]; + if (j_idx < 0) continue; + int aa_start, aa_end; + make_index_range (aa_start, aa_end, jj, nnei); + for (int aa = aa_start; aa < aa_end; ++aa){ + for (int dd0 = 0; dd0 < 3; ++dd0){ + for (int dd1 = 0; dd1 < 3; ++dd1){ + grad_net[i_idx * ndescrpt + aa] -= + -1.0 * grad[dd0 * 3 + dd1] * rij[i_idx * nnei * 3 + jj * 3 + dd1] * env_deriv[i_idx * ndescrpt * 3 + aa * 3 + dd0]; + } + } + } + } + } +} + + +template +void prod_virial_grad_a_cpu( + double * grad_net, + const double * grad, + const double * env_deriv, + const double * rij, + const int * nlist, + const int nloc, + const int nnei); + +template +void prod_virial_grad_a_cpu( + float * grad_net, + const float * grad, + const float * env_deriv, + const float * rij, + const int * nlist, + const int nloc, + const int nnei); diff --git a/source/lib/src/soft_min_switch.cc b/source/lib/src/soft_min_switch.cc new file mode 100644 index 0000000000..6ebfc96d67 --- /dev/null +++ b/source/lib/src/soft_min_switch.cc @@ -0,0 +1,105 @@ +#include +#include +#include "soft_min_switch.h" +#include "switcher.h" + +template +void soft_min_switch( + FPTYPE * sw_value, + FPTYPE * sw_deriv, + const FPTYPE * rij, + const int * nlist, + const int & nloc, + const int & nnei, + const FPTYPE & alpha, + const FPTYPE & rmin, + const FPTYPE & rmax) +{ + // fill results with 0 + for (int ii = 0; ii < nloc; ++ii){ + sw_value[ii] = 0; + } + for (int ii = 0; ii < nloc * nnei; ++ii){ + sw_deriv[ii * 3 + 0] = 0; + sw_deriv[ii * 3 + 1] = 0; + sw_deriv[ii * 3 + 2] = 0; + } + // compute force of a frame + for (int ii = 0; ii < nloc; ++ii){ + int i_idx = ii; + FPTYPE aa = 0; + FPTYPE bb = 0; + for (int jj = 0; jj < nnei; ++jj){ + int j_idx = nlist [i_idx * nnei + jj]; + if (j_idx < 0) continue; + int rij_idx_shift = (i_idx * nnei + jj) * 3; + FPTYPE dr[3] = { + rij[rij_idx_shift + 0], + rij[rij_idx_shift + 1], + rij[rij_idx_shift + 2] + }; + FPTYPE rr2 = dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2]; + FPTYPE rr = sqrt(rr2); + FPTYPE ee = exp(-rr / alpha); + aa += ee; + bb += rr * ee; + } + FPTYPE smin = bb / aa; + FPTYPE vv, dd; + spline5_switch(vv, dd, smin, static_cast(rmin), static_cast(rmax)); + // value of switch + sw_value[i_idx] = vv; + // deriv of switch distributed as force + for (int jj = 0; jj < nnei; ++jj){ + int j_idx = nlist [i_idx * nnei + jj]; + if (j_idx < 0) continue; + int rij_idx_shift = (ii * nnei + jj) * 3; + FPTYPE dr[3] = { + rij[rij_idx_shift + 0], + rij[rij_idx_shift + 1], + rij[rij_idx_shift + 2] + }; + FPTYPE rr2 = dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2]; + FPTYPE rr = sqrt(rr2); + FPTYPE ee = exp(-rr / alpha); + FPTYPE pref_c = (1./rr - 1./alpha) * ee ; + FPTYPE pref_d = 1./(rr * alpha) * ee; + FPTYPE ts; + ts = dd / (aa * aa) * (aa * pref_c + bb * pref_d); + sw_deriv[rij_idx_shift + 0] += ts * dr[0]; + sw_deriv[rij_idx_shift + 1] += ts * dr[1]; + sw_deriv[rij_idx_shift + 2] += ts * dr[2]; + // std::cout << ii << " " << jj << " " << j_idx << " " + // << vv << " " + // << sw_deriv[rij_idx_shift+0) << " " + // << sw_deriv[rij_idx_shift+1) << " " + // << sw_deriv[rij_idx_shift+2) << " " + // << std::endl; + } + } +} + +template +void soft_min_switch( + double * sw_value, + double * sw_deriv, + const double * rij, + const int * nlist, + const int & nloc, + const int & nnei, + const double & alpha, + const double & rmin, + const double & rmax); + +template +void soft_min_switch( + float * sw_value, + float * sw_deriv, + const float * rij, + const int * nlist, + const int & nloc, + const int & nnei, + const float & alpha, + const float & rmin, + const float & rmax); + diff --git a/source/lib/tests/test_prod_force_grad_a.cc b/source/lib/tests/test_prod_force_grad_a.cc new file mode 100644 index 0000000000..90d658fdb5 --- /dev/null +++ b/source/lib/tests/test_prod_force_grad_a.cc @@ -0,0 +1,96 @@ +#include +#include +#include "fmt_nlist.h" +#include "env_mat.h" +#include "NeighborList.h" +#include "prod_force_grad.h" + +class TestProdForceGradA : public ::testing::Test +{ +protected: + std::vector posi = {12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall, nnei, ndescrpt; + double rc = 6; + double rc_smth = 0.8; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sec_a = {0, 5, 10}; + std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector> nlist_a_cpy, nlist_r_cpy; + std::vector grad; + std::vector env, env_deriv, rij_a; + std::vector nlist; + std::vector fmt_nlist_a; + std::vector expected_grad_net = { + -0.12141, -0.11963, 0.01198, 0.04647, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.04188, 0.37642, 0.28680, 0.26547, -0.40861, 0.25610, -0.02009, 1.00344, -0.16166, -0.16355, 0.03691, 0.01165, -0.08770, -0.08561, -0.00398, 0.02366, 0.00000, 0.00000, 0.00000, 0.00000, -0.04188, -0.37642, -0.28680, -0.26547, -0.03357, -0.03151, 0.00454, 0.01377, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.04304, 0.05219, 0.08677, 0.16032, -0.05232, -0.05123, 0.01227, 0.00935, -0.01420, -0.01366, -0.00022, 0.00404, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.40861, -0.25610, 0.02009, -1.00344, -0.04863, -0.04701, 0.02501, 0.01556, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.04304, -0.05219, -0.08677, -0.16032, -0.08249, -0.07502, 0.04767, -0.00448, -0.08260, -0.08165, 0.01821, 0.01869, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.12141, 0.11963, -0.01198, -0.04647, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.16227, 0.28667, 0.50683, 0.06651, -0.58330, -0.45376, 0.37464, 0.93891, -0.04863, 0.04701, -0.02501, -0.01556, -0.03357, 0.03151, -0.00454, -0.01377, 0.00000, 0.00000, 0.00000, 0.00000, -0.16227, -0.28667, -0.50683, -0.06651, -0.16166, 0.16355, -0.03691, -0.01165, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.04418, 0.09284, 0.09569, 0.19565, -0.08249, 0.07502, -0.04767, 0.00448, -0.05232, 0.05123, -0.01227, -0.00935, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.58330, 0.45376, -0.37464, -0.93891, -0.08770, 0.08561, 0.00398, -0.02366, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.04418, -0.09284, -0.09569, -0.19565, -0.08260, 0.08165, -0.01821, -0.01869, -0.01420, 0.01366, 0.00022, -0.00404, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + }; + + void SetUp() override { + double box[] = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + region.reinitBox(box); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nnei = sec_a.back(); + ndescrpt = nnei * 4; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + build_nlist(nlist_a_cpy, nlist_r_cpy, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + nlist.resize(nloc * nnei); + env.resize(nloc * ndescrpt); + env_deriv.resize(nloc * ndescrpt * 3); + rij_a.resize(nloc * nnei * 3); + for(int ii = 0; ii < nloc; ++ii){ + // format nlist and record + format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + for (int jj = 0; jj < nnei; ++jj){ + nlist[ii*nnei + jj] = fmt_nlist_a[jj]; + } + std::vector t_env, t_env_deriv, t_rij_a; + // compute env_mat and its deriv, record + env_mat_a_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < ndescrpt; ++jj){ + env[ii*ndescrpt+jj] = t_env[jj]; + for (int dd = 0; dd < 3; ++dd){ + env_deriv[ii*ndescrpt*3+jj*3+dd] = t_env_deriv[jj*3+dd]; + } + } + } + grad.resize(nloc * 3); + for (int ii = 0; ii < nloc * 3; ++ii){ + grad[ii] = 10 - ii * 0.1; + } + } + void TearDown() override { + } +}; + +TEST_F(TestProdForceGradA, cpu) +{ + std::vector grad_net(nloc * ndescrpt); + prod_force_grad_a_cpu(&grad_net[0], &grad[0], &env_deriv[0], &nlist[0], nloc, nnei); + EXPECT_EQ(grad_net.size(), nloc * ndescrpt); + for (int jj = 0; jj < nloc * ndescrpt; ++jj){ + EXPECT_LT(fabs(grad_net[jj] - expected_grad_net[jj]) , 1e-5); + } + // for (int jj = 0; jj < nloc * ndescrpt; ++jj){ + // printf("%8.5f, ", grad_net[jj]); + // } + // printf("\n"); +} diff --git a/source/lib/tests/test_prod_virial_grad_a.cc b/source/lib/tests/test_prod_virial_grad_a.cc new file mode 100644 index 0000000000..b18589adb5 --- /dev/null +++ b/source/lib/tests/test_prod_virial_grad_a.cc @@ -0,0 +1,100 @@ +#include +#include +#include "fmt_nlist.h" +#include "env_mat.h" +#include "NeighborList.h" +#include "prod_virial_grad.h" + +class TestProdVirialGradA : public ::testing::Test +{ +protected: + std::vector posi = {12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall, nnei, ndescrpt; + double rc = 6; + double rc_smth = 0.8; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sec_a = {0, 5, 10}; + std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector> nlist_a_cpy, nlist_r_cpy; + std::vector grad; + std::vector env, env_deriv, rij; + std::vector nlist; + std::vector fmt_nlist_a; + std::vector expected_grad_net = { + 5.01828, 4.97546, -0.09569, -1.15305, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.61704, 1.06623, 0.15319, 0.24608, 5.28467, -2.59553, 3.00729, -8.19962, 5.03021, 5.02151, -0.86956, 0.26289, 2.75500, 2.70125, 0.22900, -0.54729, 0.00000, 0.00000, 0.00000, 0.00000, -0.61704, -1.06623, -0.15319, -0.24608, 2.32844, 2.23467, -0.16758, -0.70940, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.74748, -0.30379, -1.11004, -3.49833, 2.42774, 2.39284, -0.45567, -0.22216, 0.60993, 0.59054, 0.02135, -0.15332, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 5.28467, 2.59553, -3.00729, 8.19962, 4.77234, 4.62396, -1.90919, -0.44792, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.74748, 0.30379, 1.11004, 3.49833, 4.06655, 3.57849, -2.07817, 0.88468, 3.61241, 3.58881, -0.57839, -0.39969, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 5.01828, -4.97546, 0.09569, 1.15305, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.07573, -3.82089, -2.40143, -0.67375, 9.64382, 8.39638, -2.48922, -9.00792, 4.77234, -4.62396, 1.90919, 0.44792, 2.32844, -2.23467, 0.16758, 0.70940, 0.00000, 0.00000, 0.00000, 0.00000, 0.07573, 3.82089, 2.40143, 0.67375, 5.03021, -5.02151, 0.86956, -0.26289, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.44012, -1.15994, -0.66718, -3.33981, 4.06655, -3.57849, 2.07817, -0.88468, 2.42774, -2.39284, 0.45567, 0.22216, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 9.64382, -8.39638, 2.48922, 9.00792, 2.75500, -2.70125, -0.22900, 0.54729, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.44012, 1.15994, 0.66718, 3.33981, 3.61241, -3.58881, 0.57839, 0.39969, 0.60993, -0.59054, -0.02135, 0.15332, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + }; + + void SetUp() override { + double box[] = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + region.reinitBox(box); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nnei = sec_a.back(); + ndescrpt = nnei * 4; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + build_nlist(nlist_a_cpy, nlist_r_cpy, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + nlist.resize(nloc * nnei); + env.resize(nloc * ndescrpt); + env_deriv.resize(nloc * ndescrpt * 3); + rij.resize(nloc * nnei * 3); + for(int ii = 0; ii < nloc; ++ii){ + // format nlist and record + format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + for (int jj = 0; jj < nnei; ++jj){ + nlist[ii*nnei + jj] = fmt_nlist_a[jj]; + } + std::vector t_env, t_env_deriv, t_rij; + // compute env_mat and its deriv, record + env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < ndescrpt; ++jj){ + env[ii*ndescrpt+jj] = t_env[jj]; + for (int dd = 0; dd < 3; ++dd){ + env_deriv[ii*ndescrpt*3+jj*3+dd] = t_env_deriv[jj*3+dd]; + } + } + for (int jj = 0; jj < nnei * 3; ++jj){ + rij[ii*nnei*3 + jj] = t_rij[jj]; + } + } + grad.resize(9); + for (int ii = 0; ii < 9; ++ii){ + grad[ii] = 10 - ii * 1.; + } + } + void TearDown() override { + } +}; + +TEST_F(TestProdVirialGradA, cpu) +{ + std::vector grad_net(nloc * ndescrpt); + int n_a_sel = nnei; + prod_virial_grad_a_cpu (&grad_net[0], &grad[0], &env_deriv[0], &rij[0], &nlist[0], nloc, nnei); + EXPECT_EQ(grad_net.size(), nloc * ndescrpt); + for (int jj = 0; jj < nloc * ndescrpt; ++jj){ + EXPECT_LT(fabs(grad_net[jj] - expected_grad_net[jj]) , 1e-5); + } + // for (int jj = 0; jj < nloc * ndescrpt; ++jj){ + // printf("%8.5f, ", grad_net[jj]); + // } + // printf("\n"); +} diff --git a/source/lib/tests/test_soft_min_switch.cc b/source/lib/tests/test_soft_min_switch.cc new file mode 100644 index 0000000000..7780c9939e --- /dev/null +++ b/source/lib/tests/test_soft_min_switch.cc @@ -0,0 +1,143 @@ +#include +#include +#include "fmt_nlist.h" +#include "env_mat.h" +#include "NeighborList.h" +#include "soft_min_switch.h" + +class TestSoftMin : public ::testing::Test +{ +protected: + std::vector posi = {12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall, nnei, ndescrpt; + double rc = 6; + double rc_smth = 0.8; + double alpha = 0.1; + double rmin = 0.8; + double rmax = 1.5; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sec_a = {0, 5, 10}; + std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector> nlist_a_cpy, nlist_r_cpy; + std::vector net_deriv, in_deriv; + std::vector rij; + std::vector nlist; + std::vector fmt_nlist_a; + std::vector expected_value = { + 0.87457, 0.88983, 0.84966, 0.92623, 0.93726, 0.90048, + }; + + void SetUp() override { + double box[] = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + region.reinitBox(box); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nnei = sec_a.back(); + ndescrpt = nnei * 4; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + build_nlist(nlist_a_cpy, nlist_r_cpy, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + nlist.resize(nloc * nnei); + rij.resize(nloc * nnei * 3); + for(int ii = 0; ii < nloc; ++ii){ + // format nlist and record + format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + for (int jj = 0; jj < nnei; ++jj){ + nlist[ii*nnei + jj] = fmt_nlist_a[jj]; + } + std::vector t_env, t_env_deriv, t_rij; + // compute env_mat and its deriv, record + env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < nnei * 3; ++jj){ + rij[ii*nnei*3 + jj] = t_rij[jj]; + } + } + } + void TearDown() override { + } +}; + +TEST_F(TestSoftMin, cpu) +{ + std::vector sw_value(nloc); + std::vector sw_deriv(nloc * nnei * 3); + soft_min_switch (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); + EXPECT_EQ(sw_value.size(), nloc); + EXPECT_EQ(sw_deriv.size(), nloc * nnei * 3); + for (int jj = 0; jj < nloc; ++jj){ + EXPECT_LT(fabs(sw_value[jj] - expected_value[jj]) , 1e-5); + } + // for (int jj = 0; jj < nloc; ++jj){ + // printf("%8.5f, ", sw_value[jj]); + // } + // printf("\n"); +} + +TEST_F(TestSoftMin, cpu_num_deriv) +{ + std::vector sw_value(nloc); + std::vector sw_deriv(nloc * nnei * 3); + std::vector sw_value_0(nloc); + std::vector sw_deriv_0(nloc * nnei * 3); + std::vector sw_value_1(nloc); + std::vector sw_deriv_1(nloc * nnei * 3); + std::vector env, env_deriv; + std::vector t_rij_0, t_rij_1; + std::vector rij_0, rij_1; + std::vector fmt_nlist_a; + double hh = 1e-5; + + soft_min_switch (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); + EXPECT_EQ(sw_value.size(), nloc); + EXPECT_EQ(sw_deriv.size(), nloc * nnei * 3); + + for (int ii = 0; ii < nloc; ++ii){ + int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + EXPECT_EQ(ret, -1); + + int i_idx = ii; + for (int jj = 0; jj < nnei; ++jj){ + int j_idx = nlist[ii*nnei + jj]; + if (j_idx < 0) continue; + for (int dd = 0; dd < 3; ++dd){ + std::vector posi_0 = posi_cpy; + std::vector posi_1 = posi_cpy; + posi_0[j_idx*3+dd] -= hh; + posi_1[j_idx*3+dd] += hh; + env_mat_a_cpu(env, env_deriv, t_rij_0, posi_0, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a_cpu(env, env_deriv, t_rij_1, posi_1, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + EXPECT_EQ(t_rij_0.size(), nnei * 3); + EXPECT_EQ(t_rij_1.size(), nnei * 3); + rij_0 = rij; + rij_1 = rij; + for (int dd1 = 0; dd1 < 3; ++dd1){ + rij_0[ii*nnei*3 + jj*3 + dd] = t_rij_0[jj*3 + dd]; + rij_1[ii*nnei*3 + jj*3 + dd] = t_rij_1[jj*3 + dd]; + } + soft_min_switch (&sw_value_0[0], &sw_deriv_0[0], &rij_0[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); + soft_min_switch (&sw_value_1[0], &sw_deriv_1[0], &rij_1[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); + double ana_deriv = sw_deriv[ii*nnei*3 + jj*3 + dd]; + double num_deriv = (sw_value_1[ii] - sw_value_0[ii]) / (2. * hh); + EXPECT_LT(fabs(num_deriv - ana_deriv), 1e-5); + } + } + } +} diff --git a/source/op/prod_force_se_a_grad.cc b/source/op/prod_force_se_a_grad.cc index dab3819b17..15b3bbbbfd 100644 --- a/source/op/prod_force_se_a_grad.cc +++ b/source/op/prod_force_se_a_grad.cc @@ -3,6 +3,8 @@ #include "tensorflow/core/framework/shape_inference.h" #include +#include "prod_force_grad.h" + using namespace tensorflow; // using namespace std; @@ -88,43 +90,16 @@ class ProdForceSeAGradOp : public OpKernel for (int kk = 0; kk < nframes; ++kk){ int grad_iter = kk * nloc * 3; - int net_iter = kk * nloc * ndescrpt; int in_iter = kk * nloc * ndescrpt * 3; int nlist_iter = kk * nloc * nnei; int grad_net_iter = kk * nloc * ndescrpt; - // reset the frame to 0 - for (int ii = 0; ii < nloc; ++ii){ - for (int aa = 0; aa < ndescrpt; ++aa){ - grad_net (grad_net_iter + ii * ndescrpt + aa) = 0; - } - } - - // compute grad of one frame - for (int ii = 0; ii < nloc; ++ii){ - int i_idx = ii; - - // deriv wrt center atom - for (int aa = 0; aa < ndescrpt; ++aa){ - for (int dd = 0; dd < 3; ++dd){ - grad_net (grad_net_iter + i_idx * ndescrpt + aa) -= grad (grad_iter + i_idx * 3 + dd) * in_deriv (in_iter + i_idx * ndescrpt * 3 + aa * 3 + dd); - } - } - - // loop over neighbors - for (int jj = 0; jj < nnei; ++jj){ - int j_idx = nlist (nlist_iter + i_idx * nnei + jj); - if (j_idx > nloc) j_idx = j_idx % nloc; - if (j_idx < 0) continue; - int aa_start, aa_end; - make_descript_range (aa_start, aa_end, jj); - for (int aa = aa_start; aa < aa_end; ++aa){ - for (int dd = 0; dd < 3; ++dd){ - grad_net (grad_net_iter + i_idx * ndescrpt + aa) += grad (grad_iter + j_idx * 3 + dd) * in_deriv (in_iter + i_idx * ndescrpt * 3 + aa * 3 + dd); - } - } - } - } + prod_force_grad_a_cpu(&grad_net(grad_net_iter), + &grad(grad_iter), + &in_deriv(in_iter), + &nlist(nlist_iter), + nloc, + nnei); } } private: diff --git a/source/op/prod_virial_se_a_grad.cc b/source/op/prod_virial_se_a_grad.cc index 1cc02f93c4..0285a2f65a 100644 --- a/source/op/prod_virial_se_a_grad.cc +++ b/source/op/prod_virial_se_a_grad.cc @@ -3,6 +3,8 @@ #include "tensorflow/core/framework/shape_inference.h" #include +#include "prod_virial_grad.h" + using namespace tensorflow; // using namespace std; @@ -95,39 +97,18 @@ class ProdVirialSeAGradOp : public OpKernel for (int kk = 0; kk < nframes; ++kk){ int grad_iter = kk * 9; - int net_iter = kk * nloc * ndescrpt; int in_iter = kk * nloc * ndescrpt * 3; int rij_iter = kk * nloc * nnei * 3; int nlist_iter = kk * nloc * nnei; int grad_net_iter = kk * nloc * ndescrpt; - // reset the frame to 0 - for (int ii = 0; ii < nloc; ++ii){ - for (int aa = 0; aa < ndescrpt; ++aa){ - grad_net (grad_net_iter + ii * ndescrpt + aa) = 0; - } - } - - // compute grad of one frame - for (int ii = 0; ii < nloc; ++ii){ - int i_idx = ii; - - // loop over neighbors - for (int jj = 0; jj < nnei; ++jj){ - int j_idx = nlist (nlist_iter + i_idx * nnei + jj); - if (j_idx < 0) continue; - int aa_start, aa_end; - make_descript_range (aa_start, aa_end, jj); - for (int aa = aa_start; aa < aa_end; ++aa){ - for (int dd0 = 0; dd0 < 3; ++dd0){ - for (int dd1 = 0; dd1 < 3; ++dd1){ - grad_net (grad_net_iter + i_idx * ndescrpt + aa) -= - -1.0 * grad (grad_iter + dd0 * 3 + dd1) * rij (rij_iter + i_idx * nnei * 3 + jj * 3 + dd1) * in_deriv (in_iter + i_idx * ndescrpt * 3 + aa * 3 + dd0); - } - } - } - } - } + prod_virial_grad_a_cpu(&grad_net(grad_net_iter), + &grad(grad_iter), + &in_deriv(in_iter), + &rij(rij_iter), + &nlist(nlist_iter), + nloc, + nnei); } } private: diff --git a/source/op/soft_min.cc b/source/op/soft_min.cc index 786439a7bf..de0804262b 100644 --- a/source/op/soft_min.cc +++ b/source/op/soft_min.cc @@ -4,6 +4,7 @@ #include #include "ComputeDescriptor.h" +#include "soft_min_switch.h" using namespace tensorflow; // using namespace std; @@ -98,68 +99,15 @@ class SoftMinSwitchOp : public OpKernel { // loop over samples #pragma omp parallel for for (int kk = 0; kk < nframes; ++kk){ - // fill results with 0 - for (int ii = 0; ii < nloc; ++ii){ - sw_value(kk, ii) = 0; - } - for (int ii = 0; ii < nloc * nnei; ++ii){ - sw_deriv(kk, ii * 3 + 0) = 0; - sw_deriv(kk, ii * 3 + 1) = 0; - sw_deriv(kk, ii * 3 + 2) = 0; - } - // compute force of a frame - for (int ii = 0; ii < nloc; ++ii){ - int i_idx = ii; - FPTYPE aa = 0; - FPTYPE bb = 0; - for (int jj = 0; jj < nnei; ++jj){ - int j_idx = nlist (kk, i_idx * nnei + jj); - if (j_idx < 0) continue; - int rij_idx_shift = (i_idx * nnei + jj) * 3; - FPTYPE dr[3] = { - rij(kk, rij_idx_shift + 0), - rij(kk, rij_idx_shift + 1), - rij(kk, rij_idx_shift + 2) - }; - FPTYPE rr2 = dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2]; - FPTYPE rr = sqrt(rr2); - FPTYPE ee = exp(-rr / alpha); - aa += ee; - bb += rr * ee; - } - FPTYPE smin = bb / aa; - FPTYPE vv, dd; - spline5_switch(vv, dd, smin, static_cast(rmin), static_cast(rmax)); - // value of switch - sw_value(kk, i_idx) = vv; - // deriv of switch distributed as force - for (int jj = 0; jj < nnei; ++jj){ - int j_idx = nlist (kk, i_idx * nnei + jj); - if (j_idx < 0) continue; - int rij_idx_shift = (ii * nnei + jj) * 3; - FPTYPE dr[3] = { - rij(kk, rij_idx_shift + 0), - rij(kk, rij_idx_shift + 1), - rij(kk, rij_idx_shift + 2) - }; - FPTYPE rr2 = dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2]; - FPTYPE rr = sqrt(rr2); - FPTYPE ee = exp(-rr / alpha); - FPTYPE pref_c = (1./rr - 1./alpha) * ee ; - FPTYPE pref_d = 1./(rr * alpha) * ee; - FPTYPE ts; - ts = dd / (aa * aa) * (aa * pref_c + bb * pref_d); - sw_deriv(kk, rij_idx_shift + 0) += ts * dr[0]; - sw_deriv(kk, rij_idx_shift + 1) += ts * dr[1]; - sw_deriv(kk, rij_idx_shift + 2) += ts * dr[2]; - // std::cout << ii << " " << jj << " " << j_idx << " " - // << vv << " " - // << sw_deriv(kk, rij_idx_shift+0) << " " - // << sw_deriv(kk, rij_idx_shift+1) << " " - // << sw_deriv(kk, rij_idx_shift+2) << " " - // << std::endl; - } - } + soft_min_switch(&sw_value(kk, 0), + &sw_deriv(kk, 0), + &rij(kk, 0), + &nlist(kk, 0), + nloc, + nnei, + alpha, + rmin, + rmax); } } private: From f6f25bbd78ece1a2344b438bc8a93172cf9d1c89 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Wed, 10 Feb 2021 12:09:19 +0800 Subject: [PATCH 124/562] add type hint and mute warning message add type hint for class NeighborStat and DeepTabulate and mute warning message from custome op tabulate --- deepmd/descriptor/se_a.py | 17 ++++++++++------- deepmd/utils/neighbor_stat.py | 2 +- deepmd/utils/tabulate.py | 12 ++++++------ source/op/cuda/tabulate.cu | 2 +- source/op/tabulate.cc | 30 +++++++++++++++--------------- source/op/tabulate_multi_device.cc | 30 +++++++++++++++--------------- source/train/compress.py | 2 +- 7 files changed, 49 insertions(+), 46 deletions(-) diff --git a/deepmd/descriptor/se_a.py b/deepmd/descriptor/se_a.py index 9be99d3cd0..c123a4c90f 100644 --- a/deepmd/descriptor/se_a.py +++ b/deepmd/descriptor/se_a.py @@ -230,12 +230,12 @@ def compute_input_stats (self, self.dstd = np.array(all_dstd) def enable_compression(self, - min_nbor_dist, - model_file = 'frozon_model.pb', - table_extrapolate = 5, - table_stride_1 = 0.01, - table_stride_2 = 0.1, - check_frequency = -1 + min_nbor_dist : float, + model_file : str = 'frozon_model.pb', + table_extrapolate : float = 5, + table_stride_1 : float = 0.01, + table_stride_2 : float = 0.1, + check_frequency : int = -1 ) -> None: """ Reveive the statisitcs (distance, max_nbor_size and env_mat_range) of the training data. @@ -260,7 +260,10 @@ def enable_compression(self, self.table_config = [table_extrapolate, table_stride_1, table_stride_2, check_frequency] self.table = DeepTabulate(self.model_file, self.type_one_side) self.lower, self.upper \ - = self.table.build(min_nbor_dist, table_extrapolate, table_stride_1, table_stride_2) + = self.table.build(min_nbor_dist, + table_extrapolate, + table_stride_1, + table_stride_2) def build (self, coord_ : tf.Tensor, diff --git a/deepmd/utils/neighbor_stat.py b/deepmd/utils/neighbor_stat.py index 9ccb3a5d0e..606002e4d3 100644 --- a/deepmd/utils/neighbor_stat.py +++ b/deepmd/utils/neighbor_stat.py @@ -14,7 +14,7 @@ class NeighborStat(): """ def __init__(self, ntypes : int, - rcut) -> None: + rcut: float) -> None: """ Constructor diff --git a/deepmd/utils/tabulate.py b/deepmd/utils/tabulate.py index fc0ba118fd..4291a8127b 100644 --- a/deepmd/utils/tabulate.py +++ b/deepmd/utils/tabulate.py @@ -16,8 +16,8 @@ class DeepTabulate(): The range of the first table is automatically detected by deepmd-kit, while the second table ranges from the first table\'s upper boundary(upper) to the extrapolate(parameter) * upper. """ def __init__(self, - model_file, - type_one_side = False) -> None: + model_file : str, + type_one_side : bool = False) -> None: """ Constructor @@ -68,10 +68,10 @@ def __init__(self, # TODO: Need a check function to determine if the current model is properly def build(self, - min_nbor_dist, - extrapolate, - stride0, - stride1) -> Tuple[int, int]: + min_nbor_dist : float, + extrapolate : float, + stride0 : float, + stride1 : float) -> Tuple[int, int]: """ Build the tables for model compression diff --git a/source/op/cuda/tabulate.cu b/source/op/cuda/tabulate.cu index 83befeb571..db1b917f02 100644 --- a/source/op/cuda/tabulate.cu +++ b/source/op/cuda/tabulate.cu @@ -291,7 +291,7 @@ __global__ void tabulate_checker(const FPTYPE * in, int * out, const FPTYPE lowe FPTYPE xx = in[bid * nnei + ii]; if (xx < lower || xx > max) { Csub[tid] += 1; - printf("# DEEPMD: level 2 overflow, xx:\t%f\n", xx); + // printf("# DEEPMD: level 2 overflow, xx:\t%f\n", xx); } else if (xx >= upper && xx <= max) { Dsub[tid] += 1; diff --git a/source/op/tabulate.cc b/source/op/tabulate.cc index ba7cc550fe..1ca5b774ea 100644 --- a/source/op/tabulate.cc +++ b/source/op/tabulate.cc @@ -283,21 +283,21 @@ class TabulateFusionOp : public OpKernel { output_shape, &output)); - counter++; - if ((int)table_info.flat().data()[5] != -1 && counter % (int)table_info.flat().data()[5] == 0) { - Tensor int_temp; - TensorShape int_shape; - int_shape.AddDim(2 * ff.shape().dim_size(0)); - OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); - TabulateCheckerFunctor()( - context->eigen_device(), - table_info.flat().data(), - input.flat().data(), - int_temp.flat().data(), - ff.shape().dim_size(0), - ff.shape().dim_size(1) - ); - } + // counter++; + // if ((int)table_info.flat().data()[5] != -1 && counter % (int)table_info.flat().data()[5] == 0) { + // Tensor int_temp; + // TensorShape int_shape; + // int_shape.AddDim(2 * ff.shape().dim_size(0)); + // OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); + // TabulateCheckerFunctor()( + // context->eigen_device(), + // table_info.flat().data(), + // input.flat().data(), + // int_temp.flat().data(), + // ff.shape().dim_size(0), + // ff.shape().dim_size(1) + // ); + // } TabulateFusionFunctor()( context->eigen_device(), // define actually graph execution device diff --git a/source/op/tabulate_multi_device.cc b/source/op/tabulate_multi_device.cc index 1e5e8da2a7..4cce523def 100644 --- a/source/op/tabulate_multi_device.cc +++ b/source/op/tabulate_multi_device.cc @@ -92,21 +92,21 @@ class TabulateFusionOp : public OpKernel { output_shape, &output)); - counter++; - if ((int)table_info.flat().data()[5] != -1 && counter % (int)table_info.flat().data()[5] == 0) { - Tensor int_temp; - TensorShape int_shape; - int_shape.AddDim(2 * ff.shape().dim_size(0)); - OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); - TabulateCheckerFunctor()( - context->eigen_device(), - table_info.flat().data(), - input.flat().data(), - int_temp.flat().data(), - ff.shape().dim_size(0), - ff.shape().dim_size(1) - ); - } + // counter++; + // if ((int)table_info.flat().data()[5] != -1 && counter % (int)table_info.flat().data()[5] == 0) { + // Tensor int_temp; + // TensorShape int_shape; + // int_shape.AddDim(2 * ff.shape().dim_size(0)); + // OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); + // TabulateCheckerFunctor()( + // context->eigen_device(), + // table_info.flat().data(), + // input.flat().data(), + // int_temp.flat().data(), + // ff.shape().dim_size(0), + // ff.shape().dim_size(1) + // ); + // } TabulateFusionFunctor()( context->eigen_device(), // define actually graph execution device diff --git a/source/train/compress.py b/source/train/compress.py index cd1ba79466..24a3a7997a 100644 --- a/source/train/compress.py +++ b/source/train/compress.py @@ -20,7 +20,7 @@ def compress(args): jdata['model']['compress'] = {} jdata['model']['compress']['compress'] = True jdata['model']['compress']['model_file'] = args.input - jdata['model']['compress']['table_config'] = [args.extrapolate, args.stride, 10 * args.stride, args.frequency] + jdata['model']['compress']['table_config'] = [args.extrapolate, args.stride, 10 * args.stride, int(args.frequency)] # check the descriptor info of the input file assert jdata['model']['descriptor']['type'] == 'se_a', 'Model compression error: descriptor type must be se_a!' From 44aa2496b072bdc994ff4ff1fcaef46e4b35a0a8 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Wed, 10 Feb 2021 14:35:44 +0800 Subject: [PATCH 125/562] add type hint for class NrighborStat --- deepmd/utils/neighbor_stat.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/deepmd/utils/neighbor_stat.py b/deepmd/utils/neighbor_stat.py index 606002e4d3..d8fed56e03 100644 --- a/deepmd/utils/neighbor_stat.py +++ b/deepmd/utils/neighbor_stat.py @@ -6,6 +6,7 @@ from deepmd.env import op_module from deepmd.env import default_tf_session_config from deepmd.RunOptions import global_np_float_precision +from deepmd.utils.data_system import DeepmdDataSystem class NeighborStat(): """ @@ -45,7 +46,7 @@ def __init__(self, self.sub_sess = tf.Session(graph = sub_graph, config=default_tf_session_config) def get_stat(self, - data) -> Tuple[float, List[int]]: + data : DeepmdDataSystem) -> Tuple[float, List[int]]: """ get the data statistics of the training data, including nearest nbor distance between atoms, max nbor size of atoms @@ -61,6 +62,7 @@ def get_stat(self, max_nbor_size A list with ntypes integers, denotes the actual achieved max sel """ + print(type(data)) self.min_nbor_dist = 100.0 self.max_nbor_size = [0] * self.ntypes From 521ea298926e1ccf7723911dcc708941cf7fdbbb Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 10 Feb 2021 16:01:10 +0800 Subject: [PATCH 126/562] refact prod_env_mat soft_min_switch_force. fix issues in soft_min_switch --- source/lib/include/CustomeOperation.h | 64 -------- source/lib/include/prod_env_mat.h | 44 ++++++ source/lib/include/soft_min_switch.h | 2 +- source/lib/include/soft_min_switch_force.h | 11 ++ source/lib/src/env_mat.cc | 2 +- source/lib/src/prod_env_mat.cc | 132 ++++++++++++++++ source/lib/src/soft_min_switch.cc | 6 +- source/lib/src/soft_min_switch_force.cc | 61 ++++++++ source/lib/tests/test_env_mat_a.cc | 145 +++++++++++++++++- source/lib/tests/test_soft_min_switch.cc | 18 +-- .../lib/tests/test_soft_min_switch_force.cc | 106 +++++++++++++ source/op/descrpt_se_a_multi_device.cc | 36 ++++- source/op/soft_min.cc | 19 +-- source/op/soft_min_force.cc | 36 ++--- 14 files changed, 564 insertions(+), 118 deletions(-) create mode 100644 source/lib/include/prod_env_mat.h create mode 100644 source/lib/include/soft_min_switch_force.h create mode 100644 source/lib/src/prod_env_mat.cc create mode 100644 source/lib/src/soft_min_switch_force.cc create mode 100644 source/lib/tests/test_soft_min_switch_force.cc diff --git a/source/lib/include/CustomeOperation.h b/source/lib/include/CustomeOperation.h index 023a2e8b95..8e4278ad7c 100644 --- a/source/lib/include/CustomeOperation.h +++ b/source/lib/include/CustomeOperation.h @@ -28,70 +28,6 @@ struct NeighborInfo { -template -void DescrptSeACPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { - // set & normalize coord - std::vector d_coord3(nall * 3); - for (int ii = 0; ii < nall; ++ii) { - for (int dd = 0; dd < 3; ++dd) { - d_coord3[ii * 3 + dd] = coord[ii * 3 + dd]; - } - } - - // set type - std::vector d_type (nall); - for (int ii = 0; ii < nall; ++ii) { - d_type[ii] = type[ii]; - } - - // build nlist - std::vector > d_nlist_a(nloc); - - for (unsigned ii = 0; ii < nloc; ++ii) { - d_nlist_a.reserve (jrange[nloc] / nloc + 10); - } - for (unsigned ii = 0; ii < nloc; ++ii) { - int i_idx = ilist[ii]; - for (unsigned jj = jrange[ii]; jj < jrange[ii+1]; ++jj) { - int j_idx = jlist[jj]; - d_nlist_a[i_idx].push_back (j_idx); - } - } - - #pragma omp parallel for - for (int ii = 0; ii < nloc; ++ii) { - std::vector fmt_nlist_a; - int ret = -1; - if (fill_nei_a) { - format_nlist_cpu(fmt_nlist_a, d_coord3, ntypes, d_type, ii, d_nlist_a[ii], rcut_r, sec_a); - } - std::vector d_descrpt_a; - std::vector d_descrpt_a_deriv; - std::vector d_descrpt_r; - std::vector d_descrpt_r_deriv; - std::vector d_rij_a; - env_mat_a_cpu (d_descrpt_a, d_descrpt_a_deriv, d_rij_a, d_coord3, ntypes, d_type, ii, fmt_nlist_a, sec_a, rcut_r_smth, rcut_r); - - // check sizes - assert (d_descrpt_a.size() == ndescrpt); - assert (d_descrpt_a_deriv.size() == ndescrpt * 3); - assert (d_rij_a.size() == nnei * 3); - assert (fmt_nlist_a.size() == nnei); - // record outputs - for (int jj = 0; jj < ndescrpt; ++jj) { - descrpt[ii * ndescrpt + jj] = (d_descrpt_a[jj] - avg[d_type[ii] * ndescrpt + jj]) / std[d_type[ii] * ndescrpt + jj]; - } - for (int jj = 0; jj < ndescrpt * 3; ++jj) { - descrpt_deriv[ii * ndescrpt * 3 + jj] = d_descrpt_a_deriv[jj] / std[d_type[ii] * ndescrpt + jj / 3]; - } - for (int jj = 0; jj < nnei * 3; ++jj) { - rij[ii * nnei * 3 + jj] = d_rij_a[jj]; - } - for (int jj = 0; jj < nnei; ++jj) { - nlist[ii * nnei + jj] = fmt_nlist_a[jj]; - } - } -} #if GOOGLE_CUDA template diff --git a/source/lib/include/prod_env_mat.h b/source/lib/include/prod_env_mat.h new file mode 100644 index 0000000000..79e6450f0b --- /dev/null +++ b/source/lib/include/prod_env_mat.h @@ -0,0 +1,44 @@ +#pragma once +#include + +template +void prod_env_mat_a_cpu( + FPTYPE * em, + FPTYPE * em_deriv, + FPTYPE * rij, + int * nlist, + const FPTYPE * coord, + const int * type, + const int * ilist, + const int * jrange, + const int * jlist, + const int max_nbor_size, + const FPTYPE * avg, + const FPTYPE * std, + const int nloc, + const int nall, + const int ntypes, + const float rcut_r, + const float rcut_r_smth, + const std::vector sec_a); + +template +void prod_env_mat_a_gpu_nv( + FPTYPE * em, + FPTYPE * em_deriv, + FPTYPE * rij, + int * nlist, + const FPTYPE * coord, + const int * type, + const int * ilist, + const int * jrange, + const int * jlist, + const int max_nbor_size, + const FPTYPE * avg, + const FPTYPE * std, + const int nloc, + const int nall, + const int ntypes, + const float rcut_r, + const float rcut_r_smth, + const std::vector sec_a); diff --git a/source/lib/include/soft_min_switch.h b/source/lib/include/soft_min_switch.h index 67c88612b8..9d0b20a1c5 100644 --- a/source/lib/include/soft_min_switch.h +++ b/source/lib/include/soft_min_switch.h @@ -1,7 +1,7 @@ #pragma once template -void soft_min_switch( +void soft_min_switch_cpu( FPTYPE * sw_value, FPTYPE * sw_deriv, const FPTYPE * rij, diff --git a/source/lib/include/soft_min_switch_force.h b/source/lib/include/soft_min_switch_force.h new file mode 100644 index 0000000000..dfcb47ca52 --- /dev/null +++ b/source/lib/include/soft_min_switch_force.h @@ -0,0 +1,11 @@ +#pragma once + +template +void soft_min_switch_force_cpu( + FPTYPE * force, + const FPTYPE * du, + const FPTYPE * sw_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei); diff --git a/source/lib/src/env_mat.cc b/source/lib/src/env_mat.cc index 6736320d2d..aa5417b3ca 100644 --- a/source/lib/src/env_mat.cc +++ b/source/lib/src/env_mat.cc @@ -104,7 +104,7 @@ void env_mat_a_cpu ( const std::vector & sec_a, const float & rmin, const float & rmax) -{ +{ // compute the diff of the neighbors rij_a.resize (sec_a.back() * 3); fill (rij_a.begin(), rij_a.end(), 0.0); diff --git a/source/lib/src/prod_env_mat.cc b/source/lib/src/prod_env_mat.cc new file mode 100644 index 0000000000..d486a09321 --- /dev/null +++ b/source/lib/src/prod_env_mat.cc @@ -0,0 +1,132 @@ +#include +#include +#include "prod_env_mat.h" +#include "fmt_nlist.h" +#include "env_mat.h" + +template +void prod_env_mat_a_cpu( + FPTYPE * em, + FPTYPE * em_deriv, + FPTYPE * rij, + int * nlist, + const FPTYPE * coord, + const int * type, + const int * ilist, + const int * jrange, + const int * jlist, + const int max_nbor_size, + const FPTYPE * avg, + const FPTYPE * std, + const int nloc, + const int nall, + const int ntypes, + const float rcut_r, + const float rcut_r_smth, + const std::vector sec_a) +{ + const int nnei = sec_a.back(); + const int nem = nnei * 4; + + // set & normalize coord + std::vector d_coord3(nall * 3); + for (int ii = 0; ii < nall; ++ii) { + for (int dd = 0; dd < 3; ++dd) { + d_coord3[ii * 3 + dd] = coord[ii * 3 + dd]; + } + } + + // set type + std::vector d_type (nall); + for (int ii = 0; ii < nall; ++ii) { + d_type[ii] = type[ii]; + } + + // build nlist + std::vector > d_nlist_a(nloc); + + for (unsigned ii = 0; ii < nloc; ++ii) { + d_nlist_a.reserve (jrange[nloc] / nloc + 10); + } + for (unsigned ii = 0; ii < nloc; ++ii) { + int i_idx = ilist[ii]; + for (unsigned jj = jrange[ii]; jj < jrange[ii+1]; ++jj) { + int j_idx = jlist[jj]; + d_nlist_a[i_idx].push_back (j_idx); + } + } + +#pragma omp parallel for + for (int ii = 0; ii < nloc; ++ii) { + std::vector fmt_nlist_a; + int ret = format_nlist_cpu(fmt_nlist_a, d_coord3, ntypes, d_type, ii, d_nlist_a[ii], rcut_r, sec_a); + std::vector d_em_a; + std::vector d_em_a_deriv; + std::vector d_em_r; + std::vector d_em_r_deriv; + std::vector d_rij_a; + env_mat_a_cpu (d_em_a, d_em_a_deriv, d_rij_a, d_coord3, ntypes, d_type, ii, fmt_nlist_a, sec_a, rcut_r_smth, rcut_r); + + // check sizes + assert (d_em_a.size() == nem); + assert (d_em_a_deriv.size() == nem * 3); + assert (d_rij_a.size() == nnei * 3); + assert (fmt_nlist_a.size() == nnei); + // record outputs + for (int jj = 0; jj < nem; ++jj) { + em[ii * nem + jj] = (d_em_a[jj] - avg[d_type[ii] * nem + jj]) / std[d_type[ii] * nem + jj]; + } + for (int jj = 0; jj < nem * 3; ++jj) { + em_deriv[ii * nem * 3 + jj] = d_em_a_deriv[jj] / std[d_type[ii] * nem + jj / 3]; + } + for (int jj = 0; jj < nnei * 3; ++jj) { + rij[ii * nnei * 3 + jj] = d_rij_a[jj]; + } + for (int jj = 0; jj < nnei; ++jj) { + nlist[ii * nnei + jj] = fmt_nlist_a[jj]; + } + } +} + + +template +void prod_env_mat_a_cpu( + double * em, + double * em_deriv, + double * rij, + int * nlist, + const double * coord, + const int * type, + const int * ilist, + const int * jrange, + const int * jlist, + const int max_nbor_size, + const double * avg, + const double * std, + const int nloc, + const int nall, + const int ntypes, + const float rcut_r, + const float rcut_r_smth, + const std::vector sec_a); + +template +void prod_env_mat_a_cpu( + float * em, + float * em_deriv, + float * rij, + int * nlist, + const float * coord, + const int * type, + const int * ilist, + const int * jrange, + const int * jlist, + const int max_nbor_size, + const float * avg, + const float * std, + const int nloc, + const int nall, + const int ntypes, + const float rcut_r, + const float rcut_r_smth, + const std::vector sec_a); diff --git a/source/lib/src/soft_min_switch.cc b/source/lib/src/soft_min_switch.cc index 6ebfc96d67..fbbf8bbbdd 100644 --- a/source/lib/src/soft_min_switch.cc +++ b/source/lib/src/soft_min_switch.cc @@ -4,7 +4,7 @@ #include "switcher.h" template -void soft_min_switch( +void soft_min_switch_cpu( FPTYPE * sw_value, FPTYPE * sw_deriv, const FPTYPE * rij, @@ -80,7 +80,7 @@ void soft_min_switch( } template -void soft_min_switch( +void soft_min_switch_cpu( double * sw_value, double * sw_deriv, const double * rij, @@ -92,7 +92,7 @@ void soft_min_switch( const double & rmax); template -void soft_min_switch( +void soft_min_switch_cpu( float * sw_value, float * sw_deriv, const float * rij, diff --git a/source/lib/src/soft_min_switch_force.cc b/source/lib/src/soft_min_switch_force.cc new file mode 100644 index 0000000000..48f15e20fe --- /dev/null +++ b/source/lib/src/soft_min_switch_force.cc @@ -0,0 +1,61 @@ +#include "soft_min_switch_force.h" +#include + +template +void soft_min_switch_force_cpu( + FPTYPE * force, + const FPTYPE * du, + const FPTYPE * sw_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei) +// +// force : nall * 3 +// du : nloc +// sw_deriv : nloc * nnei * 3 +// +{ + // set zeros + for (int ii = 0; ii < nall; ++ii){ + int i_idx = ii; + force[i_idx * 3 + 0] = 0; + force[i_idx * 3 + 1] = 0; + force[i_idx * 3 + 2] = 0; + } + // compute force of a frame + for (int ii = 0; ii < nloc; ++ii){ + int i_idx = ii; + for (int jj = 0; jj < nnei; ++jj){ + int j_idx = nlist[i_idx * nnei + jj]; + if (j_idx < 0) continue; + int rij_idx_shift = (ii * nnei + jj) * 3; + force[i_idx * 3 + 0] += du[i_idx] * sw_deriv[rij_idx_shift + 0]; + force[i_idx * 3 + 1] += du[i_idx] * sw_deriv[rij_idx_shift + 1]; + force[i_idx * 3 + 2] += du[i_idx] * sw_deriv[rij_idx_shift + 2]; + force[j_idx * 3 + 0] -= du[i_idx] * sw_deriv[rij_idx_shift + 0]; + force[j_idx * 3 + 1] -= du[i_idx] * sw_deriv[rij_idx_shift + 1]; + force[j_idx * 3 + 2] -= du[i_idx] * sw_deriv[rij_idx_shift + 2]; + } + } +} + +template +void soft_min_switch_force_cpu( + double * force, + const double * du, + const double * sw_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei); + +template +void soft_min_switch_force_cpu( + float * force, + const float * du, + const float * sw_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei); diff --git a/source/lib/tests/test_env_mat_a.cc b/source/lib/tests/test_env_mat_a.cc index e261ee975b..2881b98cf7 100644 --- a/source/lib/tests/test_env_mat_a.cc +++ b/source/lib/tests/test_env_mat_a.cc @@ -2,6 +2,7 @@ #include #include "fmt_nlist.h" #include "env_mat.h" +#include "prod_env_mat.h" #include "NeighborList.h" class TestEnvMatA : public ::testing::Test @@ -17,7 +18,6 @@ class TestEnvMatA : public ::testing::Test std::vector atype = {0, 1, 1, 0, 1, 1}; std::vector posi_cpy; std::vector atype_cpy; - int ntypes = 2; int nloc, nall; double rc = 6; double rc_smth = 0.8; @@ -28,6 +28,9 @@ class TestEnvMatA : public ::testing::Test std::vector nat_stt, ext_stt, ext_end; std::vector> nlist_a, nlist_r; std::vector> nlist_a_cpy, nlist_r_cpy; + int ntypes = sec_a.size()-1; + int nnei = sec_a.back(); + int ndescrpt = nnei * 4; std::vector expected_env = { 0.12206, 0.12047, 0.01502, -0.01263, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.02167, -0.77271, 0.32370, 0.58475, 0.99745, 0.41810, 0.75655, -0.49773, 0.10564, 0.10495, -0.00143, 0.01198, 0.03103, 0.03041, 0.00452, -0.00425, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.02167, 0.77271, -0.32370, -0.58475, 0.04135, 0.04039, 0.00123, -0.00880, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.59220, 0.42028, 0.16304, -0.38405, 0.03694, 0.03680, -0.00300, -0.00117, 0.00336, 0.00327, 0.00022, -0.00074, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, @@ -71,7 +74,6 @@ class TestEnvMatAShortSel : public ::testing::Test std::vector atype = {0, 1, 1, 0, 1, 1}; std::vector posi_cpy; std::vector atype_cpy; - int ntypes = 2; int nloc, nall; double rc = 6; double rc_smth = 0.8; @@ -82,6 +84,9 @@ class TestEnvMatAShortSel : public ::testing::Test std::vector nat_stt, ext_stt, ext_end; std::vector> nlist_a, nlist_r; std::vector> nlist_a_cpy, nlist_r_cpy; + int ntypes = sec_a.size()-1; + int nnei = sec_a.back(); + int ndescrpt = nnei * 4; std::vector expected_env = { 0.12206, 0.12047, 0.01502, -0.01263, 0.00000, 0.00000, 0.00000, 0.00000, 1.02167, -0.77271, 0.32370, 0.58475, 0.99745, 0.41810, 0.75655, -0.49773, 1.02167, 0.77271, -0.32370, -0.58475, 0.04135, 0.04039, 0.00123, -0.00880, 0.59220, 0.42028, 0.16304, -0.38405, 0.03694, 0.03680, -0.00300, -0.00117, @@ -378,3 +383,139 @@ TEST_F(TestEnvMatAShortSel, cpu) } } } + + +TEST_F(TestEnvMatA, prod_cpu) +{ + EXPECT_EQ(nlist_r_cpy.size(), nloc); + int tot_nnei = 0; + int max_nbor_size = 0; + for(int ii = 0; ii < nlist_a_cpy.size(); ++ii){ + tot_nnei += nlist_a_cpy[ii].size(); + if (nlist_a_cpy[ii].size() > max_nbor_size){ + max_nbor_size = nlist_a_cpy[ii].size(); + } + } + std::vector ilist(nloc), jlist(tot_nnei), jrange(nloc+1, 0); + for (int ii = 0; ii < nloc; ++ii){ + ilist[ii] = ii; + jrange[ii+1] = jrange[ii] + nlist_a_cpy[ii].size(); + int jj, cc; + for (jj = jrange[ii], cc = 0; jj < jrange[ii+1]; ++jj, ++cc){ + jlist[jj] = nlist_a_cpy[ii][cc]; + } + } + std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); + std::vector nlist(nloc * nnei); + std::vector avg(ntypes * ndescrpt, 0); + std::vector std(ntypes * ndescrpt, 1); + prod_env_mat_a_cpu( + &em[0], + &em_deriv[0], + &rij[0], + &nlist[0], + &posi_cpy[0], + &atype_cpy[0], + &ilist[0], + &jrange[0], + &jlist[0], + max_nbor_size, + &avg[0], + &std[0], + nloc, + nall, + ntypes, + rc, + rc_smth, + sec_a); + + for(int ii = 0; ii < nloc; ++ii){ + for (int jj = 0; jj < nnei; ++jj){ + for (int dd = 0; dd < 4; ++dd){ + EXPECT_LT(fabs(em[ii*nnei*4 + jj*4 + dd] - + expected_env[ii*nnei*4 + jj*4 + dd]) , + 1e-5); + } + } + } +} + + +TEST_F(TestEnvMatA, prod_cpu_equal_cpu) +{ + EXPECT_EQ(nlist_r_cpy.size(), nloc); + int tot_nnei = 0; + int max_nbor_size = 0; + for(int ii = 0; ii < nlist_a_cpy.size(); ++ii){ + tot_nnei += nlist_a_cpy[ii].size(); + if (nlist_a_cpy[ii].size() > max_nbor_size){ + max_nbor_size = nlist_a_cpy[ii].size(); + } + } + std::vector ilist(nloc), jlist(tot_nnei), jrange(nloc+1, 0); + for (int ii = 0; ii < nloc; ++ii){ + ilist[ii] = ii; + jrange[ii+1] = jrange[ii] + nlist_a_cpy[ii].size(); + int jj, cc; + for (jj = jrange[ii], cc = 0; jj < jrange[ii+1]; ++jj, ++cc){ + jlist[jj] = nlist_a_cpy[ii][cc]; + } + } + std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); + std::vector nlist(nloc * nnei); + std::vector avg(ntypes * ndescrpt, 0); + std::vector std(ntypes * ndescrpt, 1); + prod_env_mat_a_cpu( + &em[0], + &em_deriv[0], + &rij[0], + &nlist[0], + &posi_cpy[0], + &atype_cpy[0], + &ilist[0], + &jrange[0], + &jlist[0], + max_nbor_size, + &avg[0], + &std[0], + nloc, + nall, + ntypes, + rc, + rc_smth, + sec_a); + + std::vector fmt_nlist_a_1, fmt_nlist_r_1; + std::vector env_1, env_deriv_1, rij_a_1; + for(int ii = 0; ii < nloc; ++ii){ + int ret_1 = format_nlist_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + EXPECT_EQ(ret_1, -1); + env_mat_a_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + EXPECT_EQ(env_1.size(), nnei * 4); + EXPECT_EQ(env_deriv_1.size(), nnei * 4 * 3); + EXPECT_EQ(rij_a_1.size(), nnei * 3); + EXPECT_EQ(fmt_nlist_a_1.size(), nnei); + for (unsigned jj = 0; jj < env_1.size(); ++jj){ + EXPECT_LT(fabs(em[ii*nnei*4+jj] - env_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < env_deriv_1.size(); ++jj){ + EXPECT_LT(fabs(em_deriv[ii*nnei*4*3+jj] - env_deriv_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < rij_a_1.size(); ++jj){ + EXPECT_LT(fabs(rij[ii*nnei*3+jj] - rij_a_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < fmt_nlist_a_1.size(); ++jj){ + EXPECT_EQ(nlist[ii*nnei+jj], fmt_nlist_a_1[jj]); + } + } + + // for(int ii = 0; ii < nloc; ++ii){ + // for (int jj = 0; jj < nnei; ++jj){ + // for (int dd = 0; dd < 4; ++dd){ + // EXPECT_LT(fabs(em[ii*nnei*4 + jj*4 + dd] - + // expected_env[ii*nnei*4 + jj*4 + dd]) , + // 1e-5); + // } + // } + // } +} diff --git a/source/lib/tests/test_soft_min_switch.cc b/source/lib/tests/test_soft_min_switch.cc index 7780c9939e..5bdf034b02 100644 --- a/source/lib/tests/test_soft_min_switch.cc +++ b/source/lib/tests/test_soft_min_switch.cc @@ -5,7 +5,7 @@ #include "NeighborList.h" #include "soft_min_switch.h" -class TestSoftMin : public ::testing::Test +class TestSoftMinSwitch : public ::testing::Test { protected: std::vector posi = {12.83, 2.56, 2.18, @@ -22,7 +22,7 @@ class TestSoftMin : public ::testing::Test int nloc, nall, nnei, ndescrpt; double rc = 6; double rc_smth = 0.8; - double alpha = 0.1; + double alpha = 0.5; double rmin = 0.8; double rmax = 1.5; SimulationRegion region; @@ -36,7 +36,7 @@ class TestSoftMin : public ::testing::Test std::vector nlist; std::vector fmt_nlist_a; std::vector expected_value = { - 0.87457, 0.88983, 0.84966, 0.92623, 0.93726, 0.90048, + 0.84693, 0.57040, 0.41834, 0.89258, 0.63482, 0.60391, }; void SetUp() override { @@ -75,11 +75,11 @@ class TestSoftMin : public ::testing::Test } }; -TEST_F(TestSoftMin, cpu) +TEST_F(TestSoftMinSwitch, cpu) { std::vector sw_value(nloc); std::vector sw_deriv(nloc * nnei * 3); - soft_min_switch (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); + soft_min_switch_cpu (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); EXPECT_EQ(sw_value.size(), nloc); EXPECT_EQ(sw_deriv.size(), nloc * nnei * 3); for (int jj = 0; jj < nloc; ++jj){ @@ -91,7 +91,7 @@ TEST_F(TestSoftMin, cpu) // printf("\n"); } -TEST_F(TestSoftMin, cpu_num_deriv) +TEST_F(TestSoftMinSwitch, cpu_num_deriv) { std::vector sw_value(nloc); std::vector sw_deriv(nloc * nnei * 3); @@ -105,7 +105,7 @@ TEST_F(TestSoftMin, cpu_num_deriv) std::vector fmt_nlist_a; double hh = 1e-5; - soft_min_switch (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); + soft_min_switch_cpu (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); EXPECT_EQ(sw_value.size(), nloc); EXPECT_EQ(sw_deriv.size(), nloc * nnei * 3); @@ -132,8 +132,8 @@ TEST_F(TestSoftMin, cpu_num_deriv) rij_0[ii*nnei*3 + jj*3 + dd] = t_rij_0[jj*3 + dd]; rij_1[ii*nnei*3 + jj*3 + dd] = t_rij_1[jj*3 + dd]; } - soft_min_switch (&sw_value_0[0], &sw_deriv_0[0], &rij_0[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); - soft_min_switch (&sw_value_1[0], &sw_deriv_1[0], &rij_1[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); + soft_min_switch_cpu (&sw_value_0[0], &sw_deriv_0[0], &rij_0[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); + soft_min_switch_cpu (&sw_value_1[0], &sw_deriv_1[0], &rij_1[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); double ana_deriv = sw_deriv[ii*nnei*3 + jj*3 + dd]; double num_deriv = (sw_value_1[ii] - sw_value_0[ii]) / (2. * hh); EXPECT_LT(fabs(num_deriv - ana_deriv), 1e-5); diff --git a/source/lib/tests/test_soft_min_switch_force.cc b/source/lib/tests/test_soft_min_switch_force.cc new file mode 100644 index 0000000000..e5d8a72c02 --- /dev/null +++ b/source/lib/tests/test_soft_min_switch_force.cc @@ -0,0 +1,106 @@ +#include +#include +#include "fmt_nlist.h" +#include "env_mat.h" +#include "NeighborList.h" +#include "soft_min_switch.h" +#include "soft_min_switch_force.h" + +class TestSoftMinSwitchForce : public ::testing::Test +{ +protected: + std::vector posi = {12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall, nnei, ndescrpt; + double rc = 6; + double rc_smth = 0.8; + double alpha = .5; + double rmin = 0.8; + double rmax = 1.5; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sec_a = {0, 5, 10}; + std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector> nlist_a_cpy, nlist_r_cpy; + std::vector sw_value, sw_deriv, du; + std::vector rij; + std::vector nlist; + std::vector fmt_nlist_a; + std::vector expected_force = { + 2.24044, -1.75363, -1.50088, -2.54065, 1.08035, 1.93630, 1.12909, 1.64972, -1.10112, -2.07854, 0.69062, -1.29217, 0.14032, -1.16008, 1.86286, 1.71311, 0.49339, -0.59049, -0.88441, -1.66176, 1.09480, -0.01957, -0.01188, 0.02612, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.36743, 0.67600, -0.43959, -0.03250, -0.00298, 0.00469, -0.02791, 0.00109, -0.00167, -0.00681, -0.00083, 0.00115, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + }; + + void SetUp() override { + double box[] = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + region.reinitBox(box); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nnei = sec_a.back(); + ndescrpt = nnei * 4; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + build_nlist(nlist_a_cpy, nlist_r_cpy, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + nlist.resize(nloc * nnei); + rij.resize(nloc * nnei * 3); + for(int ii = 0; ii < nloc; ++ii){ + // format nlist and record + format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + for (int jj = 0; jj < nnei; ++jj){ + nlist[ii*nnei + jj] = fmt_nlist_a[jj]; + } + std::vector t_env, t_env_deriv, t_rij; + // compute env_mat and its deriv, record + env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < nnei * 3; ++jj){ + rij[ii*nnei*3 + jj] = t_rij[jj]; + } + } + sw_value.resize(nloc); + sw_deriv.resize(nloc * nnei * 3); + soft_min_switch_cpu (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, + nnei, alpha, rmin, rmax); + du.resize(nloc); + for (int ii = 0; ii < nloc; ++ii){ + du[ii] = 1.0 - ii * 0.1; + } + } + void TearDown() override { + } +}; + +TEST_F(TestSoftMinSwitchForce, cpu) +{ + std::vector force(nall * 3); + soft_min_switch_force_cpu( + &force[0], + &du[0], + &sw_deriv[0], + &nlist[0], + nloc, + nall, + nnei); + for (int jj = 0; jj < nloc; ++jj){ + EXPECT_LT(fabs(force[jj] - expected_force[jj]) , 1e-5); + } + // for (int ii = 0; ii < nall * 3; ++ii){ + // printf("%8.5f, ", force[ii]); + // } + // printf("\n"); +} + diff --git a/source/op/descrpt_se_a_multi_device.cc b/source/op/descrpt_se_a_multi_device.cc index 5200ce0527..b95e77da8f 100644 --- a/source/op/descrpt_se_a_multi_device.cc +++ b/source/op/descrpt_se_a_multi_device.cc @@ -1,4 +1,5 @@ #include "common.h" +#include "prod_env_mat.h" #include "CustomeOperation.h" REGISTER_OP("DescrptSeA") @@ -34,9 +35,38 @@ struct DeviceFunctor { template struct DescrptSeAFunctor { - void operator()(const CPUDevice& d, const FPTYPE * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { - DescrptSeACPULauncher(coord, type, ilist, jrange, jlist, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ntypes, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); - } + void operator()( + const CPUDevice& d, + const FPTYPE * coord, + const int * type, + const int * mesh, + const int * ilist, + const int * jrange, + const int * jlist, + int * array_int, + unsigned long long * array_longlong, + const FPTYPE * avg, + const FPTYPE * std, + FPTYPE * descrpt, + FPTYPE * descrpt_deriv, + FPTYPE * rij, + int * nlist, + const int nloc, + const int nall, + const int nnei, + const int ntypes, + const int ndescrpt, + const float rcut_r, + const float rcut_r_smth, + const std::vector sec_a, + const bool fill_nei_a, + const int max_nbor_size + ) + { + prod_env_mat_a_cpu( + descrpt, descrpt_deriv, rij, nlist, + coord, type, ilist, jrange, jlist, max_nbor_size, avg, std, nloc, nall, ntypes, rcut_r, rcut_r_smth, sec_a); + } #if GOOGLE_CUDA void operator()(const GPUDevice& d, const FPTYPE * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { diff --git a/source/op/soft_min.cc b/source/op/soft_min.cc index de0804262b..cbcc6868fe 100644 --- a/source/op/soft_min.cc +++ b/source/op/soft_min.cc @@ -99,15 +99,16 @@ class SoftMinSwitchOp : public OpKernel { // loop over samples #pragma omp parallel for for (int kk = 0; kk < nframes; ++kk){ - soft_min_switch(&sw_value(kk, 0), - &sw_deriv(kk, 0), - &rij(kk, 0), - &nlist(kk, 0), - nloc, - nnei, - alpha, - rmin, - rmax); + soft_min_switch_cpu( + &sw_value(kk, 0), + &sw_deriv(kk, 0), + &rij(kk, 0), + &nlist(kk, 0), + nloc, + nnei, + alpha, + rmin, + rmax); } } private: diff --git a/source/op/soft_min_force.cc b/source/op/soft_min_force.cc index 916f42f60f..84c0b910fb 100644 --- a/source/op/soft_min_force.cc +++ b/source/op/soft_min_force.cc @@ -3,6 +3,8 @@ #include "tensorflow/core/framework/shape_inference.h" #include +#include "soft_min_switch_force.h" + using namespace tensorflow; // using namespace std; @@ -73,32 +75,14 @@ class SoftMinForceOp : public OpKernel { // loop over samples #pragma omp parallel for for (int kk = 0; kk < nframes; ++kk){ - // set zeros - for (int ii = 0; ii < nall; ++ii){ - int i_idx = ii; - force (kk, i_idx * 3 + 0) = 0; - force (kk, i_idx * 3 + 1) = 0; - force (kk, i_idx * 3 + 2) = 0; - } - // compute force of a frame - for (int ii = 0; ii < nloc; ++ii){ - int i_idx = ii; - for (int jj = 0; jj < nnei; ++jj){ - int j_idx = nlist (kk, i_idx * nnei + jj); - if (j_idx < 0) continue; - int rij_idx_shift = (ii * nnei + jj) * 3; - force(kk, i_idx * 3 + 0) += du(kk, i_idx) * sw_deriv(kk, rij_idx_shift + 0); - force(kk, i_idx * 3 + 1) += du(kk, i_idx) * sw_deriv(kk, rij_idx_shift + 1); - force(kk, i_idx * 3 + 2) += du(kk, i_idx) * sw_deriv(kk, rij_idx_shift + 2); - force(kk, j_idx * 3 + 0) -= du(kk, i_idx) * sw_deriv(kk, rij_idx_shift + 0); - force(kk, j_idx * 3 + 1) -= du(kk, i_idx) * sw_deriv(kk, rij_idx_shift + 1); - force(kk, j_idx * 3 + 2) -= du(kk, i_idx) * sw_deriv(kk, rij_idx_shift + 2); - // std::cout << "soft_min_force " << i_idx << " " << j_idx << " " - // << du(kk, i_idx) << " " - // << du(kk, i_idx) * sw_deriv(kk, rij_idx_shift + 0) - // << std::endl; - } - } + soft_min_switch_force_cpu( + &force(kk,0), + &du(kk,0), + &sw_deriv(kk,0), + &nlist(kk,0), + nloc, + nall, + nnei); } } private: From 934a2b970a3e8b56bcbb6ef1c97e2c969009562f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Wed, 10 Feb 2021 10:51:19 +0100 Subject: [PATCH 127/562] bugfix --- deepmd/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deepmd/__init__.py b/deepmd/__init__.py index b07ccc16c4..2a9fab14e5 100644 --- a/deepmd/__init__.py +++ b/deepmd/__init__.py @@ -4,6 +4,7 @@ from . import fit from . import loss from . import utils +from . import cluster import deepmd.utils.network as network from .infer.deep_eval import DeepEval from .infer.deep_pot import DeepPot @@ -26,6 +27,7 @@ "fit", "loss", "utils", + "cluster", "network", "DeepEval", "DeepPot", From 8cae6a33047ab371a3be1f280582fba185c843ad Mon Sep 17 00:00:00 2001 From: denghuilu Date: Wed, 10 Feb 2021 18:08:44 +0800 Subject: [PATCH 128/562] rm print in class NeighborStat --- deepmd/utils/neighbor_stat.py | 1 - 1 file changed, 1 deletion(-) diff --git a/deepmd/utils/neighbor_stat.py b/deepmd/utils/neighbor_stat.py index d8fed56e03..0ff11691b0 100644 --- a/deepmd/utils/neighbor_stat.py +++ b/deepmd/utils/neighbor_stat.py @@ -62,7 +62,6 @@ def get_stat(self, max_nbor_size A list with ntypes integers, denotes the actual achieved max sel """ - print(type(data)) self.min_nbor_dist = 100.0 self.max_nbor_size = [0] * self.ntypes From 8873dcd45e52bd92dfafe79609ed97dc7a3d3ea4 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 10 Feb 2021 22:37:47 +0800 Subject: [PATCH 129/562] refact soft_min_swich_virial, soft_min_swich_force_grad, soft_min_swich_virial_grad --- .../lib/include/soft_min_switch_force_grad.h | 10 ++ source/lib/include/soft_min_switch_virial.h | 14 ++ .../lib/include/soft_min_switch_virial_grad.h | 12 ++ source/lib/src/soft_min_switch_force.cc | 6 +- source/lib/src/soft_min_switch_force_grad.cc | 59 +++++++++ source/lib/src/soft_min_switch_virial.cc | 74 +++++++++++ source/lib/src/soft_min_switch_virial_grad.cc | 64 ++++++++++ source/lib/tests/test_env_mat_a.cc | 4 + source/lib/tests/test_prod_force_a.cc | 3 +- source/lib/tests/test_prod_force_grad_a.cc | 3 +- source/lib/tests/test_prod_force_r.cc | 3 +- source/lib/tests/test_prod_virial_a.cc | 6 +- source/lib/tests/test_prod_virial_grad_a.cc | 3 +- source/lib/tests/test_prod_virial_r.cc | 6 +- source/lib/tests/test_simulation_region.cc | 18 +-- source/lib/tests/test_soft_min_switch.cc | 1 + .../lib/tests/test_soft_min_switch_force.cc | 3 +- .../tests/test_soft_min_switch_force_grad.cc | 106 ++++++++++++++++ .../lib/tests/test_soft_min_switch_virial.cc | 120 ++++++++++++++++++ .../tests/test_soft_min_switch_virial_grad.cc | 107 ++++++++++++++++ source/op/soft_min_force_grad.cc | 31 ++--- source/op/soft_min_virial.cc | 37 ++---- source/op/soft_min_virial_grad.cc | 31 ++--- source/tests/test_tab_smooth.py | 4 +- 24 files changed, 634 insertions(+), 91 deletions(-) create mode 100644 source/lib/include/soft_min_switch_force_grad.h create mode 100644 source/lib/include/soft_min_switch_virial.h create mode 100644 source/lib/include/soft_min_switch_virial_grad.h create mode 100644 source/lib/src/soft_min_switch_force_grad.cc create mode 100644 source/lib/src/soft_min_switch_virial.cc create mode 100644 source/lib/src/soft_min_switch_virial_grad.cc create mode 100644 source/lib/tests/test_soft_min_switch_force_grad.cc create mode 100644 source/lib/tests/test_soft_min_switch_virial.cc create mode 100644 source/lib/tests/test_soft_min_switch_virial_grad.cc diff --git a/source/lib/include/soft_min_switch_force_grad.h b/source/lib/include/soft_min_switch_force_grad.h new file mode 100644 index 0000000000..329ca6e66d --- /dev/null +++ b/source/lib/include/soft_min_switch_force_grad.h @@ -0,0 +1,10 @@ +#pragma once + +template +void soft_min_switch_force_grad_cpu( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * sw_deriv, + const int * nlist, + const int nloc, + const int nnei); diff --git a/source/lib/include/soft_min_switch_virial.h b/source/lib/include/soft_min_switch_virial.h new file mode 100644 index 0000000000..8e2dd1de04 --- /dev/null +++ b/source/lib/include/soft_min_switch_virial.h @@ -0,0 +1,14 @@ +#pragma once + +template +void soft_min_switch_virial_cpu( + FPTYPE * virial, + FPTYPE * atom_virial, + const FPTYPE * du, + const FPTYPE * sw_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nall, + const int nnei); + diff --git a/source/lib/include/soft_min_switch_virial_grad.h b/source/lib/include/soft_min_switch_virial_grad.h new file mode 100644 index 0000000000..4e4ed1514e --- /dev/null +++ b/source/lib/include/soft_min_switch_virial_grad.h @@ -0,0 +1,12 @@ +#pragma once + +template +void soft_min_switch_virial_grad_cpu( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * sw_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nnei); + diff --git a/source/lib/src/soft_min_switch_force.cc b/source/lib/src/soft_min_switch_force.cc index 48f15e20fe..e189276c6e 100644 --- a/source/lib/src/soft_min_switch_force.cc +++ b/source/lib/src/soft_min_switch_force.cc @@ -11,9 +11,9 @@ void soft_min_switch_force_cpu( const int nall, const int nnei) // -// force : nall * 3 -// du : nloc -// sw_deriv : nloc * nnei * 3 +// force : nall * 3 +// du : nloc +// sw_deriv : nloc * nnei * 3 // { // set zeros diff --git a/source/lib/src/soft_min_switch_force_grad.cc b/source/lib/src/soft_min_switch_force_grad.cc new file mode 100644 index 0000000000..63d388b174 --- /dev/null +++ b/source/lib/src/soft_min_switch_force_grad.cc @@ -0,0 +1,59 @@ +#include "soft_min_switch_force_grad.h" +#include + +template +void soft_min_switch_force_grad_cpu( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * sw_deriv, + const int * nlist, + const int nloc, + const int nnei) +// +// grad_net : nloc +// grad : nloc * 3 +// sw_deriv : nloc * nnei * 3 +// nlist: nloc * nnei +// +{ + // reset the frame to 0 + for (int ii = 0; ii < nloc; ++ii){ + grad_net[ii] = 0; + } + + // compute grad of one frame + for (int ii = 0; ii < nloc; ++ii){ + int i_idx = ii; + // deriv wrt center atom + for (int jj = 0; jj < nnei; ++jj){ + int j_idx = nlist [i_idx * nnei + jj]; + if (j_idx >= nloc) j_idx = j_idx % nloc; + if (j_idx < 0) continue; + int rij_idx_shift = (ii * nnei + jj) * 3; + grad_net[i_idx] += grad[i_idx * 3 + 0] * sw_deriv[rij_idx_shift + 0]; + grad_net[i_idx] += grad[i_idx * 3 + 1] * sw_deriv[rij_idx_shift + 1]; + grad_net[i_idx] += grad[i_idx * 3 + 2] * sw_deriv[rij_idx_shift + 2]; + grad_net[i_idx] -= grad[j_idx * 3 + 0] * sw_deriv[rij_idx_shift + 0]; + grad_net[i_idx] -= grad[j_idx * 3 + 1] * sw_deriv[rij_idx_shift + 1]; + grad_net[i_idx] -= grad[j_idx * 3 + 2] * sw_deriv[rij_idx_shift + 2]; + } + } +} + +template +void soft_min_switch_force_grad_cpu( + double * grad_net, + const double * grad, + const double * sw_deriv, + const int * nlist, + const int nloc, + const int nnei); + +template +void soft_min_switch_force_grad_cpu( + float * grad_net, + const float * grad, + const float * sw_deriv, + const int * nlist, + const int nloc, + const int nnei); diff --git a/source/lib/src/soft_min_switch_virial.cc b/source/lib/src/soft_min_switch_virial.cc new file mode 100644 index 0000000000..9ceacc5d72 --- /dev/null +++ b/source/lib/src/soft_min_switch_virial.cc @@ -0,0 +1,74 @@ +#include "soft_min_switch_virial.h" +#include + +template +void soft_min_switch_virial_cpu( + FPTYPE * virial, + FPTYPE * atom_virial, + const FPTYPE * du, + const FPTYPE * sw_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nall, + const int nnei) +// +// virial : 9 +// atom_virial : nall * 9 +// du : nloc +// sw_deriv : nloc * nnei * 3 +// +{ + for (int ii = 0; ii < 9; ++ ii){ + virial[ii] = 0.; + } + for (int ii = 0; ii < 9 * nall; ++ ii){ + atom_virial[ii] = 0.; + } + + // compute virial of a frame + for (int ii = 0; ii < nloc; ++ii){ + int i_idx = ii; + // loop over neighbors + for (int jj = 0; jj < nnei; ++jj){ + int j_idx = nlist[i_idx * nnei + jj]; + if (j_idx < 0) continue; + int rij_idx_shift = (ii * nnei + jj) * 3; + for (int dd0 = 0; dd0 < 3; ++dd0){ + for (int dd1 = 0; dd1 < 3; ++dd1){ + FPTYPE tmp_v = du[i_idx] * sw_deriv[rij_idx_shift + dd0] * rij[rij_idx_shift + dd1]; + virial[dd0 * 3 + dd1] -= tmp_v; + atom_virial[j_idx * 9 + dd0 * 3 + dd1] -= tmp_v; + } + } + } + } +} + + +template +void soft_min_switch_virial_cpu( + double * virial, + double * atom_virial, + const double * du, + const double * sw_deriv, + const double * rij, + const int * nlist, + const int nloc, + const int nall, + const int nnei); + +template +void soft_min_switch_virial_cpu( + float * virial, + float * atom_virial, + const float * du, + const float * sw_deriv, + const float * rij, + const int * nlist, + const int nloc, + const int nall, + const int nnei); + + + diff --git a/source/lib/src/soft_min_switch_virial_grad.cc b/source/lib/src/soft_min_switch_virial_grad.cc new file mode 100644 index 0000000000..3718810dfd --- /dev/null +++ b/source/lib/src/soft_min_switch_virial_grad.cc @@ -0,0 +1,64 @@ +#include "soft_min_switch_virial_grad.h" + +template +void soft_min_switch_virial_grad_cpu( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * sw_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nnei) +// +// grad_net: nloc +// grad: 9 +// sw_deriv: nloc * nnei * 3 +// rij: nloc * nnei * 3 +// nlist: nloc * nnei +// +{ + // reset the frame to 0 + for (int ii = 0; ii < nloc; ++ii){ + grad_net[ii] = 0; + } + + // compute grad of one frame + for (int ii = 0; ii < nloc; ++ii){ + int i_idx = ii; + // loop over neighbors + for (int jj = 0; jj < nnei; ++jj){ + int j_idx = nlist[i_idx * nnei + jj]; + if (j_idx < 0) continue; + int rij_idx_shift = (ii * nnei + jj) * 3; + for (int dd0 = 0; dd0 < 3; ++dd0){ + for (int dd1 = 0; dd1 < 3; ++dd1){ + grad_net[i_idx] -= + grad[dd0 * 3 + dd1] * sw_deriv[rij_idx_shift + dd0] * rij[rij_idx_shift + dd1]; + } + } + } + } +} + +template +void soft_min_switch_virial_grad_cpu( + double * grad_net, + const double * grad, + const double * sw_deriv, + const double * rij, + const int * nlist, + const int nloc, + const int nnei); + +template +void soft_min_switch_virial_grad_cpu( + float * grad_net, + const float * grad, + const float * sw_deriv, + const float * rij, + const int * nlist, + const int nloc, + const int nnei); + + + diff --git a/source/lib/tests/test_env_mat_a.cc b/source/lib/tests/test_env_mat_a.cc index 2881b98cf7..b242f12c3f 100644 --- a/source/lib/tests/test_env_mat_a.cc +++ b/source/lib/tests/test_env_mat_a.cc @@ -495,6 +495,10 @@ TEST_F(TestEnvMatA, prod_cpu_equal_cpu) EXPECT_EQ(env_deriv_1.size(), nnei * 4 * 3); EXPECT_EQ(rij_a_1.size(), nnei * 3); EXPECT_EQ(fmt_nlist_a_1.size(), nnei); + EXPECT_EQ(env_1.size() * nloc, em.size()); + EXPECT_EQ(env_deriv_1.size() * nloc, em_deriv.size()); + EXPECT_EQ(rij_a_1.size() * nloc, rij.size()); + EXPECT_EQ(fmt_nlist_a_1.size() * nloc, nlist.size()); for (unsigned jj = 0; jj < env_1.size(); ++jj){ EXPECT_LT(fabs(em[ii*nnei*4+jj] - env_1[jj]), 1e-10); } diff --git a/source/lib/tests/test_prod_force_a.cc b/source/lib/tests/test_prod_force_a.cc index 20e4bbe42e..7e614ffdb6 100644 --- a/source/lib/tests/test_prod_force_a.cc +++ b/source/lib/tests/test_prod_force_a.cc @@ -87,7 +87,8 @@ TEST_F(TestProdForceA, cpu) int n_a_sel = nnei; prod_force_a_cpu (&force[0], &net_deriv[0], &env_deriv[0], &nlist[0], nloc, nall, nnei); EXPECT_EQ(force.size(), nall * 3); - for (int jj = 0; jj < nall * 3; ++jj){ + EXPECT_EQ(force.size(), expected_force.size()); + for (int jj = 0; jj < force.size(); ++jj){ EXPECT_LT(fabs(force[jj] - expected_force[jj]) , 1e-5); } // for (int jj = 0; jj < nall * 3; ++jj){ diff --git a/source/lib/tests/test_prod_force_grad_a.cc b/source/lib/tests/test_prod_force_grad_a.cc index 90d658fdb5..abe26c3997 100644 --- a/source/lib/tests/test_prod_force_grad_a.cc +++ b/source/lib/tests/test_prod_force_grad_a.cc @@ -86,7 +86,8 @@ TEST_F(TestProdForceGradA, cpu) std::vector grad_net(nloc * ndescrpt); prod_force_grad_a_cpu(&grad_net[0], &grad[0], &env_deriv[0], &nlist[0], nloc, nnei); EXPECT_EQ(grad_net.size(), nloc * ndescrpt); - for (int jj = 0; jj < nloc * ndescrpt; ++jj){ + EXPECT_EQ(grad_net.size(), expected_grad_net.size()); + for (int jj = 0; jj < grad_net.size(); ++jj){ EXPECT_LT(fabs(grad_net[jj] - expected_grad_net[jj]) , 1e-5); } // for (int jj = 0; jj < nloc * ndescrpt; ++jj){ diff --git a/source/lib/tests/test_prod_force_r.cc b/source/lib/tests/test_prod_force_r.cc index a313e07c3d..9784f2958f 100644 --- a/source/lib/tests/test_prod_force_r.cc +++ b/source/lib/tests/test_prod_force_r.cc @@ -87,7 +87,8 @@ TEST_F(TestProdForceR, cpu) int n_a_sel = nnei; prod_force_r_cpu (&force[0], &net_deriv[0], &env_deriv[0], &nlist[0], nloc, nall, nnei); EXPECT_EQ(force.size(), nall * 3); - for (int jj = 0; jj < nall * 3; ++jj){ + EXPECT_EQ(force.size(), expected_force.size()); + for (int jj = 0; jj < force.size(); ++jj){ EXPECT_LT(fabs(force[jj] - expected_force[jj]) , 1e-5); } // for (int jj = 0; jj < nall * 3; ++jj){ diff --git a/source/lib/tests/test_prod_virial_a.cc b/source/lib/tests/test_prod_virial_a.cc index e17ec73ef7..7541459da1 100644 --- a/source/lib/tests/test_prod_virial_a.cc +++ b/source/lib/tests/test_prod_virial_a.cc @@ -94,11 +94,13 @@ TEST_F(TestProdVirialA, cpu) int n_a_sel = nnei; prod_virial_a_cpu (&virial[0], &atom_virial[0], &net_deriv[0], &env_deriv[0], &rij[0], &nlist[0], nloc, nall, nnei); EXPECT_EQ(virial.size(), 9); + EXPECT_EQ(virial.size(), expected_virial.size()); EXPECT_EQ(atom_virial.size(), nall * 9); - for (int jj = 0; jj < 9; ++jj){ + EXPECT_EQ(atom_virial.size(), expected_atom_virial.size()); + for (int jj = 0; jj < virial.size(); ++jj){ EXPECT_LT(fabs(virial[jj] - expected_virial[jj]) , 1e-5); } - for (int jj = 0; jj < nall * 9; ++jj){ + for (int jj = 0; jj < atom_virial.size(); ++jj){ EXPECT_LT(fabs(atom_virial[jj] - expected_atom_virial[jj]) , 1e-5); } // for (int jj = 0; jj < 9; ++jj){ diff --git a/source/lib/tests/test_prod_virial_grad_a.cc b/source/lib/tests/test_prod_virial_grad_a.cc index b18589adb5..8833db5a2b 100644 --- a/source/lib/tests/test_prod_virial_grad_a.cc +++ b/source/lib/tests/test_prod_virial_grad_a.cc @@ -90,7 +90,8 @@ TEST_F(TestProdVirialGradA, cpu) int n_a_sel = nnei; prod_virial_grad_a_cpu (&grad_net[0], &grad[0], &env_deriv[0], &rij[0], &nlist[0], nloc, nnei); EXPECT_EQ(grad_net.size(), nloc * ndescrpt); - for (int jj = 0; jj < nloc * ndescrpt; ++jj){ + EXPECT_EQ(grad_net.size(), expected_grad_net.size()); + for (int jj = 0; jj < grad_net.size(); ++jj){ EXPECT_LT(fabs(grad_net[jj] - expected_grad_net[jj]) , 1e-5); } // for (int jj = 0; jj < nloc * ndescrpt; ++jj){ diff --git a/source/lib/tests/test_prod_virial_r.cc b/source/lib/tests/test_prod_virial_r.cc index 4a83fd338c..5f3b7b40f3 100644 --- a/source/lib/tests/test_prod_virial_r.cc +++ b/source/lib/tests/test_prod_virial_r.cc @@ -95,10 +95,12 @@ TEST_F(TestProdVirialR, cpu) prod_virial_r_cpu (&virial[0], &atom_virial[0], &net_deriv[0], &env_deriv[0], &rij[0], &nlist[0], nloc, nall, nnei); EXPECT_EQ(virial.size(), 9); EXPECT_EQ(atom_virial.size(), nall * 9); - for (int jj = 0; jj < 9; ++jj){ + EXPECT_EQ(virial.size(), expected_virial.size()); + EXPECT_EQ(atom_virial.size(), expected_atom_virial.size()); + for (int jj = 0; jj < virial.size(); ++jj){ EXPECT_LT(fabs(virial[jj] - expected_virial[jj]) , 1e-5); } - for (int jj = 0; jj < nall * 9; ++jj){ + for (int jj = 0; jj < atom_virial.size(); ++jj){ EXPECT_LT(fabs(atom_virial[jj] - expected_atom_virial[jj]) , 1e-5); } // for (int jj = 0; jj < 9; ++jj){ diff --git a/source/lib/tests/test_simulation_region.cc b/source/lib/tests/test_simulation_region.cc index 4803fddef2..0e55d9a13c 100644 --- a/source/lib/tests/test_simulation_region.cc +++ b/source/lib/tests/test_simulation_region.cc @@ -3,15 +3,15 @@ #include #include "SimulationRegion.h" -double square_root (const double xx) -{ - return sqrt(xx); -} +// double square_root (const double xx) +// { +// return sqrt(xx); +// } -TEST (SquareRootTest, PositiveNos) { - EXPECT_EQ (18.0, square_root (324.0)); - EXPECT_EQ (25.4, square_root (645.16)); - EXPECT_EQ (50.332, square_root (2533.310224)); -} +// TEST (SquareRootTest, PositiveNos) { +// EXPECT_EQ (18.0, square_root (324.0)); +// EXPECT_EQ (25.4, square_root (645.16)); +// EXPECT_EQ (50.332, square_root (2533.310224)); +// } diff --git a/source/lib/tests/test_soft_min_switch.cc b/source/lib/tests/test_soft_min_switch.cc index 5bdf034b02..156ede66cc 100644 --- a/source/lib/tests/test_soft_min_switch.cc +++ b/source/lib/tests/test_soft_min_switch.cc @@ -81,6 +81,7 @@ TEST_F(TestSoftMinSwitch, cpu) std::vector sw_deriv(nloc * nnei * 3); soft_min_switch_cpu (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); EXPECT_EQ(sw_value.size(), nloc); + EXPECT_EQ(sw_value.size(), expected_value.size()); EXPECT_EQ(sw_deriv.size(), nloc * nnei * 3); for (int jj = 0; jj < nloc; ++jj){ EXPECT_LT(fabs(sw_value[jj] - expected_value[jj]) , 1e-5); diff --git a/source/lib/tests/test_soft_min_switch_force.cc b/source/lib/tests/test_soft_min_switch_force.cc index e5d8a72c02..2eb47bff22 100644 --- a/source/lib/tests/test_soft_min_switch_force.cc +++ b/source/lib/tests/test_soft_min_switch_force.cc @@ -95,7 +95,8 @@ TEST_F(TestSoftMinSwitchForce, cpu) nloc, nall, nnei); - for (int jj = 0; jj < nloc; ++jj){ + EXPECT_EQ(force.size(), expected_force.size()); + for (int jj = 0; jj < force.size(); ++jj){ EXPECT_LT(fabs(force[jj] - expected_force[jj]) , 1e-5); } // for (int ii = 0; ii < nall * 3; ++ii){ diff --git a/source/lib/tests/test_soft_min_switch_force_grad.cc b/source/lib/tests/test_soft_min_switch_force_grad.cc new file mode 100644 index 0000000000..508e7dea86 --- /dev/null +++ b/source/lib/tests/test_soft_min_switch_force_grad.cc @@ -0,0 +1,106 @@ +#include +#include +#include "fmt_nlist.h" +#include "env_mat.h" +#include "NeighborList.h" +#include "soft_min_switch.h" +#include "soft_min_switch_force_grad.h" + +class TestSoftMinSwitchForceGrad : public ::testing::Test +{ +protected: + std::vector posi = {12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall, nnei, ndescrpt; + double rc = 6; + double rc_smth = 0.8; + double alpha = .5; + double rmin = 0.8; + double rmax = 1.5; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sec_a = {0, 5, 10}; + std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector> nlist_a_cpy, nlist_r_cpy; + std::vector sw_value, sw_deriv, grad; + std::vector rij; + std::vector nlist; + std::vector fmt_nlist_a; + std::vector expected_grad_net = { + -0.62289, -0.08638, -1.94404, 0.01995, 0.04023, 0.01040, + }; + + void SetUp() override { + double box[] = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + region.reinitBox(box); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nnei = sec_a.back(); + ndescrpt = nnei * 4; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + build_nlist(nlist_a_cpy, nlist_r_cpy, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + nlist.resize(nloc * nnei); + rij.resize(nloc * nnei * 3); + for(int ii = 0; ii < nloc; ++ii){ + // format nlist and record + format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + for (int jj = 0; jj < nnei; ++jj){ + nlist[ii*nnei + jj] = fmt_nlist_a[jj]; + } + std::vector t_env, t_env_deriv, t_rij; + // compute env_mat and its deriv, record + env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < nnei * 3; ++jj){ + rij[ii*nnei*3 + jj] = t_rij[jj]; + } + } + sw_value.resize(nloc); + sw_deriv.resize(nloc * nnei * 3); + soft_min_switch_cpu (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, + nnei, alpha, rmin, rmax); + grad.resize(nloc * 3); + for (int ii = 0; ii < nloc; ++ii){ + grad[ii] = 1.0 - ii * 0.1; + } + } + void TearDown() override { + } +}; + +TEST_F(TestSoftMinSwitchForceGrad, cpu) +{ + std::vector grad_net(nloc); + soft_min_switch_force_grad_cpu( + &grad_net[0], + &grad[0], + &sw_deriv[0], + &nlist[0], + nloc, + nnei); + EXPECT_EQ(grad_net.size(), expected_grad_net.size()); + for (int jj = 0; jj < grad_net.size(); ++jj){ + EXPECT_LT(fabs(grad_net[jj] - expected_grad_net[jj]) , 1e-5); + } + // for (int ii = 0; ii < nloc; ++ii){ + // printf("%8.5f, ", grad_net[ii]); + // } + // printf("\n"); +} + diff --git a/source/lib/tests/test_soft_min_switch_virial.cc b/source/lib/tests/test_soft_min_switch_virial.cc new file mode 100644 index 0000000000..57314af786 --- /dev/null +++ b/source/lib/tests/test_soft_min_switch_virial.cc @@ -0,0 +1,120 @@ +#include +#include +#include "fmt_nlist.h" +#include "env_mat.h" +#include "NeighborList.h" +#include "soft_min_switch.h" +#include "soft_min_switch_virial.h" + +class TestSoftMinSwitchVirial : public ::testing::Test +{ +protected: + std::vector posi = {12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall, nnei, ndescrpt; + double rc = 6; + double rc_smth = 0.8; + double alpha = .5; + double rmin = 0.8; + double rmax = 1.5; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sec_a = {0, 5, 10}; + std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector> nlist_a_cpy, nlist_r_cpy; + std::vector sw_value, sw_deriv, du; + std::vector rij; + std::vector nlist; + std::vector fmt_nlist_a; + std::vector expected_virial = { + 3.06079, 0.53537, -2.41160, 0.53537, 2.78437, -1.61110, -2.41160, -1.61110, 3.49276, + }; + std::vector expected_atom_virial = { + 1.35376, -0.56712, -1.02447, -0.56712, 0.23758, 0.42917, -1.02447, 0.42917, 0.77527, 0.54989, -0.23036, -0.41613, -0.23036, 0.09650, 0.17433, -0.41613, 0.17433, 0.31491, -0.19229, 0.02835, -0.02453, 0.02835, -0.00576, 0.00594, -0.02453, 0.00594, -0.00660, 0.87609, 0.15772, -0.10844, 0.15772, 0.43891, -0.68116, -0.10844, -0.68116, 1.06620, -0.07197, 0.02107, -0.01394, 0.02107, 0.17539, -0.28148, -0.01394, -0.28148, 0.45073, 0.41749, 0.14761, -0.17569, 0.14761, 0.06082, -0.08056, -0.17569, -0.08056, 0.10804, 0.25593, 0.69163, -0.46058, 0.69163, 1.26326, -0.83076, -0.46058, -0.83076, 0.54550, -0.01118, 0.01474, -0.02646, 0.01474, 0.00500, -0.01216, -0.02646, -0.01216, 0.02792, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.14854, 0.28167, -0.17934, 0.28167, 0.51470, -0.33630, -0.17934, -0.33630, 0.21579, -0.12311, -0.01078, 0.01838, -0.01078, -0.00120, 0.00130, 0.01838, 0.00130, -0.00312, -0.11042, 0.00462, -0.00589, 0.00462, -0.00032, -0.00002, -0.00589, -0.00002, -0.00089, -0.03191, -0.00379, 0.00549, -0.00379, -0.00050, 0.00060, 0.00549, 0.00060, -0.00100, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + }; + + void SetUp() override { + double box[] = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + region.reinitBox(box); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nnei = sec_a.back(); + ndescrpt = nnei * 4; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + build_nlist(nlist_a_cpy, nlist_r_cpy, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + nlist.resize(nloc * nnei); + rij.resize(nloc * nnei * 3); + for(int ii = 0; ii < nloc; ++ii){ + // format nlist and record + format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + for (int jj = 0; jj < nnei; ++jj){ + nlist[ii*nnei + jj] = fmt_nlist_a[jj]; + } + std::vector t_env, t_env_deriv, t_rij; + // compute env_mat and its deriv, record + env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < nnei * 3; ++jj){ + rij[ii*nnei*3 + jj] = t_rij[jj]; + } + } + sw_value.resize(nloc); + sw_deriv.resize(nloc * nnei * 3); + soft_min_switch_cpu (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, + nnei, alpha, rmin, rmax); + du.resize(nloc); + for (int ii = 0; ii < nloc; ++ii){ + du[ii] = 1.0 - ii * 0.1; + } + } + void TearDown() override { + } +}; + +TEST_F(TestSoftMinSwitchVirial, cpu) +{ + std::vector virial(9); + std::vector atom_virial(nall * 9); + soft_min_switch_virial_cpu( + &virial[0], + &atom_virial[0], + &du[0], + &sw_deriv[0], + &rij[0], + &nlist[0], + nloc, + nall, + nnei); + EXPECT_EQ(virial.size(), expected_virial.size()); + for (int jj = 0; jj < virial.size(); ++jj){ + EXPECT_LT(fabs(virial[jj] - expected_virial[jj]) , 1e-5); + } + EXPECT_EQ(atom_virial.size(), expected_atom_virial.size()); + for (int jj = 0; jj < atom_virial.size(); ++jj){ + EXPECT_LT(fabs(atom_virial[jj] - expected_atom_virial[jj]) , 1e-5); + } + // for (int ii = 0; ii < 9; ++ii){ + // printf("%8.5f, ", virial[ii]); + // } + // for (int ii = 0; ii < 9 * nall; ++ii){ + // printf("%8.5f, ", atom_virial[ii]); + // } + // printf("\n"); +} + diff --git a/source/lib/tests/test_soft_min_switch_virial_grad.cc b/source/lib/tests/test_soft_min_switch_virial_grad.cc new file mode 100644 index 0000000000..a6147191ce --- /dev/null +++ b/source/lib/tests/test_soft_min_switch_virial_grad.cc @@ -0,0 +1,107 @@ +#include +#include +#include "fmt_nlist.h" +#include "env_mat.h" +#include "NeighborList.h" +#include "soft_min_switch.h" +#include "soft_min_switch_virial_grad.h" + +class TestSoftMinSwitchVirialGrad : public ::testing::Test +{ +protected: + std::vector posi = {12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall, nnei, ndescrpt; + double rc = 6; + double rc_smth = 0.8; + double alpha = .5; + double rmin = 0.8; + double rmax = 1.5; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sec_a = {0, 5, 10}; + std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector> nlist_a_cpy, nlist_r_cpy; + std::vector sw_value, sw_deriv, grad; + std::vector rij; + std::vector nlist; + std::vector fmt_nlist_a; + std::vector expected_grad_net = { + 0.42208, -0.12835, 1.44546, 0.53673, -0.31928, 2.41220, + }; + + void SetUp() override { + double box[] = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + region.reinitBox(box); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nnei = sec_a.back(); + ndescrpt = nnei * 4; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + build_nlist(nlist_a_cpy, nlist_r_cpy, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + nlist.resize(nloc * nnei); + rij.resize(nloc * nnei * 3); + for(int ii = 0; ii < nloc; ++ii){ + // format nlist and record + format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + for (int jj = 0; jj < nnei; ++jj){ + nlist[ii*nnei + jj] = fmt_nlist_a[jj]; + } + std::vector t_env, t_env_deriv, t_rij; + // compute env_mat and its deriv, record + env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < nnei * 3; ++jj){ + rij[ii*nnei*3 + jj] = t_rij[jj]; + } + } + sw_value.resize(nloc); + sw_deriv.resize(nloc * nnei * 3); + soft_min_switch_cpu (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, + nnei, alpha, rmin, rmax); + grad.resize(nloc * 3); + for (int ii = 0; ii < nloc; ++ii){ + grad[ii] = 1.0 - ii * 0.1; + } + } + void TearDown() override { + } +}; + +TEST_F(TestSoftMinSwitchVirialGrad, cpu) +{ + std::vector grad_net(nloc); + soft_min_switch_virial_grad_cpu( + &grad_net[0], + &grad[0], + &sw_deriv[0], + &rij[0], + &nlist[0], + nloc, + nnei); + EXPECT_EQ(grad_net.size(), expected_grad_net.size()); + for (int jj = 0; jj < grad_net.size(); ++jj){ + EXPECT_LT(fabs(grad_net[jj] - expected_grad_net[jj]) , 1e-5); + } + // for (int ii = 0; ii < nloc; ++ii){ + // printf("%8.5f, ", grad_net[ii]); + // } + // printf("\n"); +} + diff --git a/source/op/soft_min_force_grad.cc b/source/op/soft_min_force_grad.cc index 53d17d42a9..82d7817738 100644 --- a/source/op/soft_min_force_grad.cc +++ b/source/op/soft_min_force_grad.cc @@ -3,6 +3,8 @@ #include "tensorflow/core/framework/shape_inference.h" #include +#include "soft_min_switch_force_grad.h" + using namespace tensorflow; // using namespace std; @@ -61,6 +63,7 @@ class SoftMinForceGradOp : public OpKernel OP_REQUIRES (context, (nframes == sw_deriv_shape.dim_size(0)), errors::InvalidArgument ("number of frames should match")); OP_REQUIRES (context, (nframes == nlist_shape.dim_size(0)), errors::InvalidArgument ("number of frames should match")); + OP_REQUIRES (context, (nloc == du_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of du should match")); OP_REQUIRES (context, (nloc * 3 == grad_shape.dim_size(1)), errors::InvalidArgument ("input grad shape should be 3 x natoms")); OP_REQUIRES (context, (nloc * nnei * 3 == sw_deriv_shape.dim_size(1)),errors::InvalidArgument ("number of sw deriv should match")); OP_REQUIRES (context, (nnei == n_a_sel + n_r_sel), errors::InvalidArgument ("number of neighbors should match")); @@ -84,27 +87,13 @@ class SoftMinForceGradOp : public OpKernel // loop over frames #pragma omp parallel for for (int kk = 0; kk < nframes; ++kk){ - // reset the frame to 0 - for (int ii = 0; ii < nloc; ++ii){ - grad_net (kk, ii) = 0; - } - - // compute grad of one frame - for (int ii = 0; ii < nloc; ++ii){ - int i_idx = ii; - // deriv wrt center atom - for (int jj = 0; jj < nnei; ++jj){ - int j_idx = nlist (kk, i_idx * nnei + jj); - if (j_idx < 0) continue; - int rij_idx_shift = (ii * nnei + jj) * 3; - grad_net(kk, i_idx) += grad(kk, i_idx * 3 + 0) * sw_deriv(kk, rij_idx_shift + 0); - grad_net(kk, i_idx) += grad(kk, i_idx * 3 + 1) * sw_deriv(kk, rij_idx_shift + 1); - grad_net(kk, i_idx) += grad(kk, i_idx * 3 + 2) * sw_deriv(kk, rij_idx_shift + 2); - grad_net(kk, i_idx) -= grad(kk, j_idx * 3 + 0) * sw_deriv(kk, rij_idx_shift + 0); - grad_net(kk, i_idx) -= grad(kk, j_idx * 3 + 1) * sw_deriv(kk, rij_idx_shift + 1); - grad_net(kk, i_idx) -= grad(kk, j_idx * 3 + 2) * sw_deriv(kk, rij_idx_shift + 2); - } - } + soft_min_switch_force_grad_cpu( + &grad_net(kk,0), + &grad(kk,0), + &sw_deriv(kk,0), + &nlist(kk,0), + nloc, + nnei); } } private: diff --git a/source/op/soft_min_virial.cc b/source/op/soft_min_virial.cc index 88016dbfd2..b083427912 100644 --- a/source/op/soft_min_virial.cc +++ b/source/op/soft_min_virial.cc @@ -3,6 +3,8 @@ #include "tensorflow/core/framework/shape_inference.h" #include +#include "soft_min_switch_virial.h" + using namespace tensorflow; // using namespace std; @@ -87,31 +89,16 @@ class SoftMinVirialOp : public OpKernel { // loop over samples #pragma omp parallel for for (int kk = 0; kk < nframes; ++kk){ - - for (int ii = 0; ii < 9; ++ ii){ - virial (kk, ii) = 0.; - } - for (int ii = 0; ii < 9 * nall; ++ ii){ - atom_virial (kk, ii) = 0.; - } - - // compute virial of a frame - for (int ii = 0; ii < nloc; ++ii){ - int i_idx = ii; - // loop over neighbors - for (int jj = 0; jj < nnei; ++jj){ - int j_idx = nlist (kk, i_idx * nnei + jj); - if (j_idx < 0) continue; - int rij_idx_shift = (ii * nnei + jj) * 3; - for (int dd0 = 0; dd0 < 3; ++dd0){ - for (int dd1 = 0; dd1 < 3; ++dd1){ - FPTYPE tmp_v = du(kk, i_idx) * sw_deriv(kk, rij_idx_shift + dd0) * rij(kk, rij_idx_shift + dd1); - virial(kk, dd0 * 3 + dd1) -= tmp_v; - atom_virial(kk, j_idx * 9 + dd0 * 3 + dd1) -= tmp_v; - } - } - } - } + soft_min_switch_virial_cpu( + &virial(kk,0), + &atom_virial(kk,0), + &du(kk,0), + &sw_deriv(kk,0), + &rij(kk,0), + &nlist(kk,0), + nloc, + nall, + nnei); } } private: diff --git a/source/op/soft_min_virial_grad.cc b/source/op/soft_min_virial_grad.cc index b3cefef771..8294b74144 100644 --- a/source/op/soft_min_virial_grad.cc +++ b/source/op/soft_min_virial_grad.cc @@ -6,6 +6,7 @@ using namespace tensorflow; // using namespace std; +#include "soft_min_switch_virial_grad.h" REGISTER_OP("SoftMinVirialGrad") .Attr("T: {float, double}") @@ -93,28 +94,14 @@ class SoftMinVirialGradOp : public OpKernel // loop over frames #pragma omp parallel for for (int kk = 0; kk < nframes; ++kk){ - - // reset the frame to 0 - for (int ii = 0; ii < nloc; ++ii){ - grad_net (kk, ii) = 0; - } - - // compute grad of one frame - for (int ii = 0; ii < nloc; ++ii){ - int i_idx = ii; - // loop over neighbors - for (int jj = 0; jj < nnei; ++jj){ - int j_idx = nlist (kk, i_idx * nnei + jj); - if (j_idx < 0) continue; - int rij_idx_shift = (ii * nnei + jj) * 3; - for (int dd0 = 0; dd0 < 3; ++dd0){ - for (int dd1 = 0; dd1 < 3; ++dd1){ - grad_net (kk, i_idx) -= - grad (kk, dd0 * 3 + dd1) * sw_deriv(kk, rij_idx_shift + dd0) * rij(kk, rij_idx_shift + dd1); - } - } - } - } + soft_min_switch_virial_grad_cpu( + &grad_net(kk, 0), + &grad(kk, 0), + &sw_deriv(kk, 0), + &rij(kk, 0), + &nlist(kk, 0), + nloc, + nnei); } } private: diff --git a/source/tests/test_tab_smooth.py b/source/tests/test_tab_smooth.py index ccb14bb09b..5e46229d71 100644 --- a/source/tests/test_tab_smooth.py +++ b/source/tests/test_tab_smooth.py @@ -170,10 +170,10 @@ def test_virial (self) : virial_test(self, self, places=5, suffix = '_tab_smth') def test_force_dw (self) : - force_dw_test(self, self, places=5, suffix = '_tab_smth') + force_dw_test(self, self, places=8, suffix = '_tab_smth') def test_virial_dw (self) : - virial_dw_test(self, self, places=5, suffix = '_tab_smth') + virial_dw_test(self, self, places=8, suffix = '_tab_smth') if __name__ == '__main__': From 4764b057bf26d9c101ee4aa916320386077f5036 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 10 Feb 2021 22:57:52 +0800 Subject: [PATCH 130/562] changed NeighborList to neighbor_list. changed some miss leading names in prod_env_mat --- .../{NeighborList.h => neighbor_list.h} | 0 source/lib/include/prod_env_mat.h | 12 +++++----- .../{NeighborList.cpp => neighbor_list.cc} | 2 +- source/lib/src/prod_env_mat.cc | 24 +++++++++---------- source/lib/tests/test_env_mat_a.cc | 2 +- source/lib/tests/test_env_mat_r.cc | 2 +- source/lib/tests/test_fmt_nlist.cc | 2 +- source/lib/tests/test_prod_force_a.cc | 2 +- source/lib/tests/test_prod_force_grad_a.cc | 2 +- source/lib/tests/test_prod_force_r.cc | 2 +- source/lib/tests/test_prod_virial_a.cc | 2 +- source/lib/tests/test_prod_virial_grad_a.cc | 2 +- source/lib/tests/test_prod_virial_r.cc | 2 +- source/lib/tests/test_soft_min_switch.cc | 2 +- .../lib/tests/test_soft_min_switch_force.cc | 2 +- .../tests/test_soft_min_switch_force_grad.cc | 2 +- .../lib/tests/test_soft_min_switch_virial.cc | 2 +- .../tests/test_soft_min_switch_virial_grad.cc | 2 +- source/op/CMakeLists.txt | 2 -- source/op/descrpt.cc | 2 +- source/op/descrpt_se_a.cc | 2 +- source/op/descrpt_se_a_ef.cc | 2 +- source/op/descrpt_se_a_ef_para.cc | 2 +- source/op/descrpt_se_a_ef_vert.cc | 2 +- source/op/descrpt_se_r.cc | 2 +- 25 files changed, 39 insertions(+), 41 deletions(-) rename source/lib/include/{NeighborList.h => neighbor_list.h} (100%) rename source/lib/src/{NeighborList.cpp => neighbor_list.cc} (99%) diff --git a/source/lib/include/NeighborList.h b/source/lib/include/neighbor_list.h similarity index 100% rename from source/lib/include/NeighborList.h rename to source/lib/include/neighbor_list.h diff --git a/source/lib/include/prod_env_mat.h b/source/lib/include/prod_env_mat.h index 79e6450f0b..dd28ff1c6b 100644 --- a/source/lib/include/prod_env_mat.h +++ b/source/lib/include/prod_env_mat.h @@ -18,9 +18,9 @@ void prod_env_mat_a_cpu( const int nloc, const int nall, const int ntypes, - const float rcut_r, - const float rcut_r_smth, - const std::vector sec_a); + const float rcut, + const float rcut_smth, + const std::vector sec); template void prod_env_mat_a_gpu_nv( @@ -39,6 +39,6 @@ void prod_env_mat_a_gpu_nv( const int nloc, const int nall, const int ntypes, - const float rcut_r, - const float rcut_r_smth, - const std::vector sec_a); + const float rcut, + const float rcut_smth, + const std::vector sec); diff --git a/source/lib/src/NeighborList.cpp b/source/lib/src/neighbor_list.cc similarity index 99% rename from source/lib/src/NeighborList.cpp rename to source/lib/src/neighbor_list.cc index bd509c15c8..11a5dcccdb 100644 --- a/source/lib/src/NeighborList.cpp +++ b/source/lib/src/neighbor_list.cc @@ -1,4 +1,4 @@ -#include "NeighborList.h" +#include "neighbor_list.h" #include // #include diff --git a/source/lib/src/prod_env_mat.cc b/source/lib/src/prod_env_mat.cc index d486a09321..a1c9492829 100644 --- a/source/lib/src/prod_env_mat.cc +++ b/source/lib/src/prod_env_mat.cc @@ -21,11 +21,11 @@ void prod_env_mat_a_cpu( const int nloc, const int nall, const int ntypes, - const float rcut_r, - const float rcut_r_smth, - const std::vector sec_a) + const float rcut, + const float rcut_smth, + const std::vector sec) { - const int nnei = sec_a.back(); + const int nnei = sec.back(); const int nem = nnei * 4; // set & normalize coord @@ -59,13 +59,13 @@ void prod_env_mat_a_cpu( #pragma omp parallel for for (int ii = 0; ii < nloc; ++ii) { std::vector fmt_nlist_a; - int ret = format_nlist_cpu(fmt_nlist_a, d_coord3, ntypes, d_type, ii, d_nlist_a[ii], rcut_r, sec_a); + int ret = format_nlist_cpu(fmt_nlist_a, d_coord3, ntypes, d_type, ii, d_nlist_a[ii], rcut, sec); std::vector d_em_a; std::vector d_em_a_deriv; std::vector d_em_r; std::vector d_em_r_deriv; std::vector d_rij_a; - env_mat_a_cpu (d_em_a, d_em_a_deriv, d_rij_a, d_coord3, ntypes, d_type, ii, fmt_nlist_a, sec_a, rcut_r_smth, rcut_r); + env_mat_a_cpu (d_em_a, d_em_a_deriv, d_rij_a, d_coord3, ntypes, d_type, ii, fmt_nlist_a, sec, rcut_smth, rcut); // check sizes assert (d_em_a.size() == nem); @@ -106,9 +106,9 @@ void prod_env_mat_a_cpu( const int nloc, const int nall, const int ntypes, - const float rcut_r, - const float rcut_r_smth, - const std::vector sec_a); + const float rcut, + const float rcut_smth, + const std::vector sec); template void prod_env_mat_a_cpu( @@ -127,6 +127,6 @@ void prod_env_mat_a_cpu( const int nloc, const int nall, const int ntypes, - const float rcut_r, - const float rcut_r_smth, - const std::vector sec_a); + const float rcut, + const float rcut_smth, + const std::vector sec); diff --git a/source/lib/tests/test_env_mat_a.cc b/source/lib/tests/test_env_mat_a.cc index b242f12c3f..56f13f83ac 100644 --- a/source/lib/tests/test_env_mat_a.cc +++ b/source/lib/tests/test_env_mat_a.cc @@ -3,7 +3,7 @@ #include "fmt_nlist.h" #include "env_mat.h" #include "prod_env_mat.h" -#include "NeighborList.h" +#include "neighbor_list.h" class TestEnvMatA : public ::testing::Test { diff --git a/source/lib/tests/test_env_mat_r.cc b/source/lib/tests/test_env_mat_r.cc index 6f44d66371..9f8e5c62bc 100644 --- a/source/lib/tests/test_env_mat_r.cc +++ b/source/lib/tests/test_env_mat_r.cc @@ -2,7 +2,7 @@ #include #include "fmt_nlist.h" #include "env_mat.h" -#include "NeighborList.h" +#include "neighbor_list.h" class TestEnvMatR : public ::testing::Test { diff --git a/source/lib/tests/test_fmt_nlist.cc b/source/lib/tests/test_fmt_nlist.cc index d3320101cf..87588b635d 100644 --- a/source/lib/tests/test_fmt_nlist.cc +++ b/source/lib/tests/test_fmt_nlist.cc @@ -1,6 +1,6 @@ #include #include "fmt_nlist.h" -#include "NeighborList.h" +#include "neighbor_list.h" class TestFormatNlist : public ::testing::Test { diff --git a/source/lib/tests/test_prod_force_a.cc b/source/lib/tests/test_prod_force_a.cc index 7e614ffdb6..93766e1b78 100644 --- a/source/lib/tests/test_prod_force_a.cc +++ b/source/lib/tests/test_prod_force_a.cc @@ -2,7 +2,7 @@ #include #include "fmt_nlist.h" #include "env_mat.h" -#include "NeighborList.h" +#include "neighbor_list.h" #include "prod_force.h" class TestProdForceA : public ::testing::Test diff --git a/source/lib/tests/test_prod_force_grad_a.cc b/source/lib/tests/test_prod_force_grad_a.cc index abe26c3997..ec7afc5d86 100644 --- a/source/lib/tests/test_prod_force_grad_a.cc +++ b/source/lib/tests/test_prod_force_grad_a.cc @@ -2,7 +2,7 @@ #include #include "fmt_nlist.h" #include "env_mat.h" -#include "NeighborList.h" +#include "neighbor_list.h" #include "prod_force_grad.h" class TestProdForceGradA : public ::testing::Test diff --git a/source/lib/tests/test_prod_force_r.cc b/source/lib/tests/test_prod_force_r.cc index 9784f2958f..93247b2d86 100644 --- a/source/lib/tests/test_prod_force_r.cc +++ b/source/lib/tests/test_prod_force_r.cc @@ -2,7 +2,7 @@ #include #include "fmt_nlist.h" #include "env_mat.h" -#include "NeighborList.h" +#include "neighbor_list.h" #include "prod_force.h" class TestProdForceR : public ::testing::Test diff --git a/source/lib/tests/test_prod_virial_a.cc b/source/lib/tests/test_prod_virial_a.cc index 7541459da1..a8fb5fb914 100644 --- a/source/lib/tests/test_prod_virial_a.cc +++ b/source/lib/tests/test_prod_virial_a.cc @@ -2,7 +2,7 @@ #include #include "fmt_nlist.h" #include "env_mat.h" -#include "NeighborList.h" +#include "neighbor_list.h" #include "prod_virial.h" class TestProdVirialA : public ::testing::Test diff --git a/source/lib/tests/test_prod_virial_grad_a.cc b/source/lib/tests/test_prod_virial_grad_a.cc index 8833db5a2b..75475fc2a6 100644 --- a/source/lib/tests/test_prod_virial_grad_a.cc +++ b/source/lib/tests/test_prod_virial_grad_a.cc @@ -2,7 +2,7 @@ #include #include "fmt_nlist.h" #include "env_mat.h" -#include "NeighborList.h" +#include "neighbor_list.h" #include "prod_virial_grad.h" class TestProdVirialGradA : public ::testing::Test diff --git a/source/lib/tests/test_prod_virial_r.cc b/source/lib/tests/test_prod_virial_r.cc index 5f3b7b40f3..359eda8345 100644 --- a/source/lib/tests/test_prod_virial_r.cc +++ b/source/lib/tests/test_prod_virial_r.cc @@ -2,7 +2,7 @@ #include #include "fmt_nlist.h" #include "env_mat.h" -#include "NeighborList.h" +#include "neighbor_list.h" #include "prod_virial.h" class TestProdVirialR : public ::testing::Test diff --git a/source/lib/tests/test_soft_min_switch.cc b/source/lib/tests/test_soft_min_switch.cc index 156ede66cc..f8aacccf34 100644 --- a/source/lib/tests/test_soft_min_switch.cc +++ b/source/lib/tests/test_soft_min_switch.cc @@ -2,7 +2,7 @@ #include #include "fmt_nlist.h" #include "env_mat.h" -#include "NeighborList.h" +#include "neighbor_list.h" #include "soft_min_switch.h" class TestSoftMinSwitch : public ::testing::Test diff --git a/source/lib/tests/test_soft_min_switch_force.cc b/source/lib/tests/test_soft_min_switch_force.cc index 2eb47bff22..202e633402 100644 --- a/source/lib/tests/test_soft_min_switch_force.cc +++ b/source/lib/tests/test_soft_min_switch_force.cc @@ -2,7 +2,7 @@ #include #include "fmt_nlist.h" #include "env_mat.h" -#include "NeighborList.h" +#include "neighbor_list.h" #include "soft_min_switch.h" #include "soft_min_switch_force.h" diff --git a/source/lib/tests/test_soft_min_switch_force_grad.cc b/source/lib/tests/test_soft_min_switch_force_grad.cc index 508e7dea86..216767d267 100644 --- a/source/lib/tests/test_soft_min_switch_force_grad.cc +++ b/source/lib/tests/test_soft_min_switch_force_grad.cc @@ -2,7 +2,7 @@ #include #include "fmt_nlist.h" #include "env_mat.h" -#include "NeighborList.h" +#include "neighbor_list.h" #include "soft_min_switch.h" #include "soft_min_switch_force_grad.h" diff --git a/source/lib/tests/test_soft_min_switch_virial.cc b/source/lib/tests/test_soft_min_switch_virial.cc index 57314af786..7ef06c739b 100644 --- a/source/lib/tests/test_soft_min_switch_virial.cc +++ b/source/lib/tests/test_soft_min_switch_virial.cc @@ -2,7 +2,7 @@ #include #include "fmt_nlist.h" #include "env_mat.h" -#include "NeighborList.h" +#include "neighbor_list.h" #include "soft_min_switch.h" #include "soft_min_switch_virial.h" diff --git a/source/lib/tests/test_soft_min_switch_virial_grad.cc b/source/lib/tests/test_soft_min_switch_virial_grad.cc index a6147191ce..15545ccde5 100644 --- a/source/lib/tests/test_soft_min_switch_virial_grad.cc +++ b/source/lib/tests/test_soft_min_switch_virial_grad.cc @@ -2,7 +2,7 @@ #include #include "fmt_nlist.h" #include "env_mat.h" -#include "NeighborList.h" +#include "neighbor_list.h" #include "soft_min_switch.h" #include "soft_min_switch_virial_grad.h" diff --git a/source/op/CMakeLists.txt b/source/op/CMakeLists.txt index 72bc5df5b5..0a27b4c54d 100644 --- a/source/op/CMakeLists.txt +++ b/source/op/CMakeLists.txt @@ -1,7 +1,5 @@ # libop -set(OP_LIB ${PROJECT_SOURCE_DIR}/lib/src/SimulationRegion.cpp ${PROJECT_SOURCE_DIR}/lib/src/NeighborList.cpp) - set (OP_CXX_FLAG -D_GLIBCXX_USE_CXX11_ABI=${OP_CXX_ABI} ) file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc descrpt_se_r.cc tab_inter.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc gelu.cc map_aparam.cc) file(GLOB OP_CUDA_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a_multi_device.cc descrpt_se_r_multi_device.cc tab_inter.cc prod_force_se_a_multi_device.cc prod_virial_se_a_multi_device.cc prod_force_se_r_multi_device.cc prod_virial_se_r_multi_device.cc soft_min.cc soft_min_force.cc soft_min_virial.cc gelu_multi_device.cc) diff --git a/source/op/descrpt.cc b/source/op/descrpt.cc index 0e15e75d43..a9e08e5d6d 100644 --- a/source/op/descrpt.cc +++ b/source/op/descrpt.cc @@ -4,7 +4,7 @@ #include #include "ComputeDescriptor.h" -#include "NeighborList.h" +#include "neighbor_list.h" #include "fmt_nlist.h" typedef double boxtensor_t ; diff --git a/source/op/descrpt_se_a.cc b/source/op/descrpt_se_a.cc index 07305965e6..306724851b 100644 --- a/source/op/descrpt_se_a.cc +++ b/source/op/descrpt_se_a.cc @@ -4,7 +4,7 @@ #include #include "ComputeDescriptor.h" -#include "NeighborList.h" +#include "neighbor_list.h" #include "fmt_nlist.h" #include "env_mat.h" diff --git a/source/op/descrpt_se_a_ef.cc b/source/op/descrpt_se_a_ef.cc index 8cd081434c..85d355b176 100644 --- a/source/op/descrpt_se_a_ef.cc +++ b/source/op/descrpt_se_a_ef.cc @@ -4,7 +4,7 @@ #include #include "ComputeDescriptor.h" -#include "NeighborList.h" +#include "neighbor_list.h" #include "fmt_nlist.h" typedef double boxtensor_t ; diff --git a/source/op/descrpt_se_a_ef_para.cc b/source/op/descrpt_se_a_ef_para.cc index 97c836dcc8..de7113395d 100644 --- a/source/op/descrpt_se_a_ef_para.cc +++ b/source/op/descrpt_se_a_ef_para.cc @@ -4,7 +4,7 @@ #include #include "ComputeDescriptor.h" -#include "NeighborList.h" +#include "neighbor_list.h" #include "fmt_nlist.h" typedef double boxtensor_t ; diff --git a/source/op/descrpt_se_a_ef_vert.cc b/source/op/descrpt_se_a_ef_vert.cc index ea02156acf..3630fb7a28 100644 --- a/source/op/descrpt_se_a_ef_vert.cc +++ b/source/op/descrpt_se_a_ef_vert.cc @@ -4,7 +4,7 @@ #include #include "ComputeDescriptor.h" -#include "NeighborList.h" +#include "neighbor_list.h" #include "fmt_nlist.h" typedef double boxtensor_t ; diff --git a/source/op/descrpt_se_r.cc b/source/op/descrpt_se_r.cc index 495ad1a7db..37b22df698 100644 --- a/source/op/descrpt_se_r.cc +++ b/source/op/descrpt_se_r.cc @@ -4,7 +4,7 @@ #include #include "ComputeDescriptor.h" -#include "NeighborList.h" +#include "neighbor_list.h" #include "fmt_nlist.h" #include "env_mat.h" From fc7034da00975f513989baeac22f8f019b9595d5 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Thu, 11 Feb 2021 09:16:55 +0800 Subject: [PATCH 131/562] send model file through mpi bcast --- source/lib/CMakeLists.txt | 5 +++ source/lib/src/NNPInter.cc | 65 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/source/lib/CMakeLists.txt b/source/lib/CMakeLists.txt index 231b0a5ae8..448305c697 100644 --- a/source/lib/CMakeLists.txt +++ b/source/lib/CMakeLists.txt @@ -8,6 +8,9 @@ configure_file( @ONLY ) +find_package(MPI REQUIRED) +include_directories(SYSTEM ${MPI_INCLUDE_PATH}) + if (USE_CUDA_TOOLKIT) include_directories("${CUDA_INCLUDE_DIRS}") endif() @@ -21,6 +24,8 @@ if (USE_CUDA_TOOLKIT) target_link_libraries (${libname} ${CUDA_LIBRARIES}) endif() +target_link_libraries (${libname} ${MPI_C_LIBRARIES}) + install(TARGETS ${libname} DESTINATION lib/) install( diff --git a/source/lib/src/NNPInter.cc b/source/lib/src/NNPInter.cc index 67c75fa69b..642e5c0108 100644 --- a/source/lib/src/NNPInter.cc +++ b/source/lib/src/NNPInter.cc @@ -2,6 +2,7 @@ #include "NNPAtomMap.h" #include "SimulationRegion.h" #include +#include #if GOOGLE_CUDA @@ -195,7 +196,35 @@ init (const std::string & model, const int & gpu_rank) options.config.set_inter_op_parallelism_threads(num_inter_nthreads); options.config.set_intra_op_parallelism_threads(num_intra_nthreads); - checkStatus (ReadBinaryProto(Env::Default(), model, &graph_def)); +///////////////////////////////////////////////////////////////// +// new implementation +// bcast file_content to all MPI processors +///////////////////////////////////////////////////////////////// + int myrank = 0, root = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &myrank); + unsigned nchar = 0; + std::string file_content; + if (myrank == root) { + checkStatus (ReadFileToString(Env::Default(), model, &file_content)); + nchar = file_content.size(); + } + MPI_Bcast(&nchar, 1, MPI_UNSIGNED, root, MPI_COMM_WORLD); + char * buff = (char *)malloc(sizeof(char) * nchar); + if (myrank == root) { + memcpy(buff, file_content.c_str(), sizeof(char) * nchar); + } + MPI_Bcast(buff, nchar, MPI_CHAR, root, MPI_COMM_WORLD); + file_content.resize(nchar); + for (unsigned ii = 0; ii < nchar; ++ii) { + file_content[ii] = buff[ii]; + } + graph_def.ParseFromString(file_content); + free(buff); +///////////////////////////////////////////////////////////////// +// old implementation +// checkStatus (ReadBinaryProto(Env::Default(), model, &graph_def)); +///////////////////////////////////////////////////////////////// + int gpu_num = -1; #if GOOGLE_CUDA cudaGetDeviceCount(&gpu_num); // check current device environment @@ -510,9 +539,39 @@ init (const std::vector & models, const int & gpu_rank) SessionOptions options; options.config.set_inter_op_parallelism_threads(num_inter_nthreads); options.config.set_intra_op_parallelism_threads(num_intra_nthreads); - for (unsigned ii = 0; ii < numb_models; ++ii){ - checkStatus (ReadBinaryProto(Env::Default(), models[ii], &graph_defs[ii])); +///////////////////////////////////////////////////////////////// +// new implementation +// bcast file_content to all MPI processors +///////////////////////////////////////////////////////////////// + int myrank = 0, root = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &myrank); + unsigned nchar = 0; + std::string file_content; + for (unsigned ii = 0; ii < numb_models; ++ii) { + if (myrank == root) { + checkStatus (ReadFileToString(Env::Default(), models[ii], &file_content)); + nchar = file_content.size(); + } + MPI_Bcast(&nchar, 1, MPI_UNSIGNED, root, MPI_COMM_WORLD); + char * buff = (char *)malloc(sizeof(char) * nchar); + if (myrank == root) { + memcpy(buff, file_content.c_str(), sizeof(char) * nchar); + } + MPI_Bcast(buff, nchar, MPI_CHAR, root, MPI_COMM_WORLD); + file_content.resize(nchar); + for (unsigned ii = 0; ii < nchar; ++ii) { + file_content[ii] = buff[ii]; + } + graph_defs[ii].ParseFromString(file_content); + free(buff); } +///////////////////////////////////////////////////////////////// +// old implementation +// for (unsigned ii = 0; ii < numb_models; ++ii){ +// checkStatus (ReadBinaryProto(Env::Default(), models[ii], &graph_defs[ii])); +// } +///////////////////////////////////////////////////////////////// + #if GOOGLE_CUDA if (gpu_num > 0) { options.config.set_allow_soft_placement(true); From 344fdab59b9cb90eb5b32567e44b88099ade1db4 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Thu, 11 Feb 2021 09:28:14 +0800 Subject: [PATCH 132/562] fix a bug, change the default memory size of temporary tensor change the default memory size of temporary tensor(used in descrpt_se_a.cu)to nloc * GPU_MAX_NBOR_SIZE(4096) to avoid a potential GPU memory access error. --- source/lib/include/DeviceFunctor.h | 1 + source/op/descrpt_se_a_multi_device.cc | 4 ++-- source/op/descrpt_se_r_multi_device.cc | 6 ++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/source/lib/include/DeviceFunctor.h b/source/lib/include/DeviceFunctor.h index f482545df3..447f0cacd7 100644 --- a/source/lib/include/DeviceFunctor.h +++ b/source/lib/include/DeviceFunctor.h @@ -8,6 +8,7 @@ typedef unsigned long long int_64; #define SQRT_2_PI 0.7978845608028654 #define TPB 256 +#define GPU_MAX_NBOR_SIZE 4096 #define cudaErrcheck(res) {cudaAssert((res), __FILE__, __LINE__);} inline void cudaAssert(cudaError_t code, const char *file, int line, bool abort=true) { diff --git a/source/op/descrpt_se_a_multi_device.cc b/source/op/descrpt_se_a_multi_device.cc index 5200ce0527..44f68d9de6 100644 --- a/source/op/descrpt_se_a_multi_device.cc +++ b/source/op/descrpt_se_a_multi_device.cc @@ -158,14 +158,14 @@ class DescrptSeAOp : public OpKernel { OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); Tensor uint64_temp; TensorShape uint64_shape; - uint64_shape.AddDim(nloc * max_nbor_size * 2); + uint64_shape.AddDim(nloc * GPU_MAX_NBOR_SIZE * 2); OP_REQUIRES_OK(context, context->allocate_temp(DT_UINT64, uint64_shape, &uint64_temp)); array_int = int_temp.flat().data(); array_longlong = uint64_temp.flat().data(); nbor_update(mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); - OP_REQUIRES (context, (max_nbor_size <= 4096), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than 4096, which currently is not supported by deepmd-kit.")); + OP_REQUIRES (context, (max_nbor_size <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than " + std::to_string(GPU_MAX_NBOR_SIZE) + ", which currently is not supported by deepmd-kit.")); } else if (device == "CPU") { memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); diff --git a/source/op/descrpt_se_r_multi_device.cc b/source/op/descrpt_se_r_multi_device.cc index 36d4357cfa..fb04b50066 100644 --- a/source/op/descrpt_se_r_multi_device.cc +++ b/source/op/descrpt_se_r_multi_device.cc @@ -104,8 +104,6 @@ class DescrptSeROp : public OpKernel { OP_REQUIRES (context, (9 == box_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of box should be 9")); OP_REQUIRES (context, (ndescrpt == avg_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of avg should be ndescrpt")); OP_REQUIRES (context, (ndescrpt == std_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of std should be ndescrpt")); - - OP_REQUIRES (context, (nnei <= 4096), errors::InvalidArgument ("Assert failed, max neighbor size of atom(nnei) " + std::to_string(nnei) + " is larger than 4096, which currently is not supported by deepmd-kit.")); // Create an output tensor TensorShape descrpt_shape ; @@ -147,14 +145,14 @@ class DescrptSeROp : public OpKernel { OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); Tensor uint64_temp; TensorShape uint64_shape; - uint64_shape.AddDim(nloc * max_nbor_size * 2); + uint64_shape.AddDim(nloc * GPU_MAX_NBOR_SIZE * 2); OP_REQUIRES_OK(context, context->allocate_temp(DT_UINT64, uint64_shape, &uint64_temp)); array_int = int_temp.flat().data(); array_longlong = uint64_temp.flat().data(); nbor_update(mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); - OP_REQUIRES (context, (max_nbor_size <= 4096), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than 4096, which currently is not supported by deepmd-kit.")); + OP_REQUIRES (context, (max_nbor_size <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than " + std::to_string(GPU_MAX_NBOR_SIZE) + ", which currently is not supported by deepmd-kit.")); } else if (device == "CPU") { memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); From b5289e8ac4c8864653ee67bb89c9527c29c09bb1 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Thu, 11 Feb 2021 17:05:14 +0800 Subject: [PATCH 133/562] rename tab_inter -> pair_tab ; fix bug introduced by changing NeighborList -> neighbor_list --- deepmd/utils/__init__.py | 2 +- deepmd/utils/{tab_inter.py => pair_tab.py} | 2 +- source/op/CMakeLists.txt | 4 ++-- source/op/neighbor_stat.cc | 4 ++-- source/op/{tab_inter.cc => pair_tab.cc} | 12 +++++------ source/op/unaggregated_grad.cc | 4 ++-- source/tests/test_tab_nonsmth.py | 23 +++++++++++----------- source/tests/test_tab_smooth.py | 23 +++++++++++----------- source/train/Model.py | 6 +++--- 9 files changed, 40 insertions(+), 40 deletions(-) rename deepmd/utils/{tab_inter.py => pair_tab.py} (99%) rename source/op/{tab_inter.cc => pair_tab.cc} (97%) diff --git a/deepmd/utils/__init__.py b/deepmd/utils/__init__.py index 610df6529d..d14dcd008d 100644 --- a/deepmd/utils/__init__.py +++ b/deepmd/utils/__init__.py @@ -4,5 +4,5 @@ # out-of-dated from .data import DataSets from .data_system import DataSystem -from .tab_inter import TabInter +from .pair_tab import PairTab from .learning_rate import LearningRateExp diff --git a/deepmd/utils/tab_inter.py b/deepmd/utils/pair_tab.py similarity index 99% rename from deepmd/utils/tab_inter.py rename to deepmd/utils/pair_tab.py index 1a028a6820..4e22033a3b 100644 --- a/deepmd/utils/tab_inter.py +++ b/deepmd/utils/pair_tab.py @@ -5,7 +5,7 @@ from scipy.interpolate import CubicSpline -class TabInter (object): +class PairTab (object): def __init__(self, filename : str ) -> None: diff --git a/source/op/CMakeLists.txt b/source/op/CMakeLists.txt index 0cbc54bbae..21a26e48ac 100644 --- a/source/op/CMakeLists.txt +++ b/source/op/CMakeLists.txt @@ -1,8 +1,8 @@ # libop set (OP_CXX_FLAG -D_GLIBCXX_USE_CXX11_ABI=${OP_CXX_ABI} ) -file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc descrpt_se_r.cc tab_inter.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc gelu.cc map_aparam.cc neighbor_stat.cc unaggregated_grad.cc tabulate.cc) -file(GLOB OP_CUDA_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a_multi_device.cc descrpt_se_r_multi_device.cc tab_inter.cc prod_force_se_a_multi_device.cc prod_virial_se_a_multi_device.cc prod_force_se_r_multi_device.cc prod_virial_se_r_multi_device.cc soft_min.cc soft_min_force.cc soft_min_virial.cc gelu_multi_device.cc tabulate_multi_device.cc) +file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc descrpt_se_r.cc pair_tab.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc gelu.cc map_aparam.cc neighbor_stat.cc unaggregated_grad.cc tabulate.cc) +file(GLOB OP_CUDA_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a_multi_device.cc descrpt_se_r_multi_device.cc pair_tab.cc prod_force_se_a_multi_device.cc prod_virial_se_a_multi_device.cc prod_force_se_r_multi_device.cc prod_virial_se_r_multi_device.cc soft_min.cc soft_min_force.cc soft_min_virial.cc gelu_multi_device.cc tabulate_multi_device.cc) file(GLOB OP_GRADS_SRC prod_force_grad.cc prod_force_se_a_grad.cc prod_force_se_r_grad.cc prod_virial_grad.cc prod_virial_se_a_grad.cc prod_virial_se_r_grad.cc soft_min_force_grad.cc soft_min_virial_grad.cc ) file(GLOB OP_PY *.py) diff --git a/source/op/neighbor_stat.cc b/source/op/neighbor_stat.cc index 1be0ba23d5..bbc82e9d98 100644 --- a/source/op/neighbor_stat.cc +++ b/source/op/neighbor_stat.cc @@ -3,7 +3,7 @@ #include "tensorflow/core/framework/shape_inference.h" #include -#include "NeighborList.h" +#include "neighbor_list.h" typedef double boxtensor_t ; typedef double compute_t; @@ -189,4 +189,4 @@ REGISTER_KERNEL_BUILDER( Name("NeighborStat").Device(DEVICE_CPU).TypeConstraint("T"), \ NeighborStatOp); REGISTER_CPU(float); -REGISTER_CPU(double); \ No newline at end of file +REGISTER_CPU(double); diff --git a/source/op/tab_inter.cc b/source/op/pair_tab.cc similarity index 97% rename from source/op/tab_inter.cc rename to source/op/pair_tab.cc index 7cef2ea5d7..0962596f42 100644 --- a/source/op/tab_inter.cc +++ b/source/op/pair_tab.cc @@ -7,7 +7,7 @@ using namespace tensorflow; //using namespace std; -REGISTER_OP("TabInter") +REGISTER_OP("PairTab") .Attr("T: {float, double}") .Input("table_info: double") .Input("table_data: double") @@ -69,9 +69,9 @@ void tabulated_inter (double & ener, } template -class TabInterOp : public OpKernel { +class PairTabOp : public OpKernel { public: - explicit TabInterOp(OpKernelConstruction* context) : OpKernel(context) { + explicit PairTabOp(OpKernelConstruction* context) : OpKernel(context) { OP_REQUIRES_OK(context, context->GetAttr("sel_a", &sel_a)); OP_REQUIRES_OK(context, context->GetAttr("sel_r", &sel_r)); cum_sum (sec_a, sel_a); @@ -304,10 +304,8 @@ class TabInterOp : public OpKernel { // Register the CPU kernels. #define REGISTER_CPU(T) \ REGISTER_KERNEL_BUILDER( \ - Name("TabInter").Device(DEVICE_CPU).TypeConstraint("T"), \ - TabInterOp); + Name("PairTab").Device(DEVICE_CPU).TypeConstraint("T"), \ + PairTabOp); REGISTER_CPU(float); REGISTER_CPU(double); - - diff --git a/source/op/unaggregated_grad.cc b/source/op/unaggregated_grad.cc index bc489c61ff..39b70ceee0 100644 --- a/source/op/unaggregated_grad.cc +++ b/source/op/unaggregated_grad.cc @@ -4,7 +4,7 @@ #include #include "ComputeDescriptor.h" -#include "NeighborList.h" +#include "neighbor_list.h" using namespace tensorflow; // using namespace std; @@ -317,4 +317,4 @@ REGISTER_CPU(double); // UnaggregatedDyDxOp); // REGISTER_GPU(float); // REGISTER_GPU(double); -// #endif // GOOGLE_CUDA \ No newline at end of file +// #endif // GOOGLE_CUDA diff --git a/source/tests/test_tab_nonsmth.py b/source/tests/test_tab_nonsmth.py index c626b7d634..a12a00b4d7 100644 --- a/source/tests/test_tab_nonsmth.py +++ b/source/tests/test_tab_nonsmth.py @@ -12,7 +12,7 @@ import deepmd._prod_virial_se_a_grad import deepmd._soft_min_force_grad import deepmd._soft_min_virial_grad -from deepmd.utils.tab_inter import TabInter +from deepmd.utils.pair_tab import PairTab from common import force_test from common import virial_test @@ -40,7 +40,7 @@ def setUp (self, # tabulated Inter.setUp(self, data) _make_tab(data.get_ntypes()) - self.srtab = TabInter('tab.xvg') + self.srtab = PairTab('tab.xvg') self.smin_alpha = 0.3 self.sw_rmin = 1 self.sw_rmax = 3.45 @@ -92,15 +92,16 @@ def comp_interpl_ef (self, rmax = self.sw_rmax) inv_sw_lambda = 1.0 - sw_lambda tab_atom_ener, tab_force, tab_atom_virial \ - = op_module.tab_inter(self.tab_info, - self.tab_data, - dtype, - rij, - nlist, - tnatoms, - sw_lambda, - sel_a = self.sel_a, - sel_r = self.sel_r) + = op_module.pair_tab( + self.tab_info, + self.tab_data, + dtype, + rij, + nlist, + tnatoms, + sw_lambda, + sel_a = self.sel_a, + sel_r = self.sel_r) energy_diff = tab_atom_ener - tf.reshape(atom_ener, [-1, self.natoms[0]]) tab_atom_ener = tf.reshape(sw_lambda, [-1]) * tf.reshape(tab_atom_ener, [-1]) atom_ener = tf.reshape(inv_sw_lambda, [-1]) * atom_ener diff --git a/source/tests/test_tab_smooth.py b/source/tests/test_tab_smooth.py index 5e46229d71..f5950ec8fe 100644 --- a/source/tests/test_tab_smooth.py +++ b/source/tests/test_tab_smooth.py @@ -12,7 +12,7 @@ import deepmd._prod_virial_se_a_grad import deepmd._soft_min_force_grad import deepmd._soft_min_virial_grad -from deepmd.utils.tab_inter import TabInter +from deepmd.utils.pair_tab import PairTab from common import force_test from common import virial_test @@ -40,7 +40,7 @@ def setUp (self, # tabulated Inter.setUp(self, data) _make_tab(data.get_ntypes()) - self.srtab = TabInter('tab.xvg') + self.srtab = PairTab('tab.xvg') self.smin_alpha = 0.3 self.sw_rmin = 1 self.sw_rmax = 3.45 @@ -92,15 +92,16 @@ def comp_ef (self, rmax = self.sw_rmax) inv_sw_lambda = 1.0 - sw_lambda tab_atom_ener, tab_force, tab_atom_virial \ - = op_module.tab_inter(self.tab_info, - self.tab_data, - dtype, - rij, - nlist, - tnatoms, - sw_lambda, - sel_a = self.sel_a, - sel_r = self.sel_r) + = op_module.pair_tab( + self.tab_info, + self.tab_data, + dtype, + rij, + nlist, + tnatoms, + sw_lambda, + sel_a = self.sel_a, + sel_r = self.sel_r) energy_diff = tab_atom_ener - tf.reshape(atom_ener, [-1, self.natoms[0]]) tab_atom_ener = tf.reshape(sw_lambda, [-1]) * tf.reshape(tab_atom_ener, [-1]) atom_ener = tf.reshape(inv_sw_lambda, [-1]) * atom_ener diff --git a/source/train/Model.py b/source/train/Model.py index 9c9cd7ddff..d8e5d00574 100644 --- a/source/train/Model.py +++ b/source/train/Model.py @@ -1,7 +1,7 @@ import numpy as np from deepmd.env import tf from collections import defaultdict -from deepmd.utils.tab_inter import TabInter +from deepmd.utils.pair_tab import PairTab from deepmd.common import ClassArg from deepmd.RunOptions import global_cvt_2_ener_float @@ -88,7 +88,7 @@ def __init__ (self, jdata, descrpt, fitting): self.data_stat_nbatch = class_data['data_stat_nbatch'] self.data_stat_protect = class_data['data_stat_protect'] if self.srtab_name is not None : - self.srtab = TabInter(self.srtab_name) + self.srtab = PairTab(self.srtab_name) args.add('smin_alpha', float, must = True)\ .add('sw_rmin', float, must = True)\ .add('sw_rmax', float, must = True) @@ -201,7 +201,7 @@ def build (self, # atom energy is not scaled, # force and virial are scaled tab_atom_ener, tab_force, tab_atom_virial \ - = op_module.tab_inter(self.tab_info, + = op_module.pair_tab(self.tab_info, self.tab_data, atype, rij, From 527c8d233ca2fb902e3ac6a9136c073f84a276e9 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Thu, 11 Feb 2021 20:59:26 +0800 Subject: [PATCH 134/562] print verbose debug info --- .github/workflows/test_python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index 84534996d3..5d8cb14afb 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -70,4 +70,4 @@ jobs: CC: gcc-${{ matrix.gcc }} CXX: g++-${{ matrix.gcc }} TENSORFLOW_VERSION: ${{ matrix.tf }} - - run: cd source/tests && python -m unittest + - run: cd source/tests && python -m unittest -v -f From 04c7799763321cd58927aca09432385dd43ad3a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 11 Feb 2021 14:02:43 +0100 Subject: [PATCH 135/562] small bugfixes --- deepmd/common.py | 26 ++++++++++++++++++++++---- deepmd/utils/neighbor_stat.py | 2 +- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/deepmd/common.py b/deepmd/common.py index cf9886b715..04cf73e28f 100644 --- a/deepmd/common.py +++ b/deepmd/common.py @@ -20,7 +20,7 @@ import yaml from deepmd.env import op_module, tf -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION, GLOBAL_NP_FLOAT_PRECISION if TYPE_CHECKING: _DICT_VAL = TypeVar("_DICT_VAL") @@ -452,9 +452,27 @@ def dec(obj: "_OBJ") -> "_OBJ": return dec -def get_np_precision(precision): + +def get_np_precision(precision: "_PRECISION") -> np.dtype: + """Get numpy precision constant from string. + + Parameters + ---------- + precision : _PRECISION + string name of numpy constant or default + + Returns + ------- + np.dtype + numpy presicion constant + + Raises + ------ + RuntimeError + if string is invalid + """ if precision == "default": - return global_np_float_precision + return GLOBAL_NP_FLOAT_PRECISION elif precision == "float16": return np.float16 elif precision == "float32": @@ -462,4 +480,4 @@ def get_np_precision(precision): elif precision == "float64": return np.float64 else: - raise RuntimeError("%d is not a valid precision" % precision) \ No newline at end of file + raise RuntimeError(f"{precision} is not a valid precision") diff --git a/deepmd/utils/neighbor_stat.py b/deepmd/utils/neighbor_stat.py index d8fed56e03..3b2a820a1e 100644 --- a/deepmd/utils/neighbor_stat.py +++ b/deepmd/utils/neighbor_stat.py @@ -5,7 +5,7 @@ from typing import Tuple, List from deepmd.env import op_module from deepmd.env import default_tf_session_config -from deepmd.RunOptions import global_np_float_precision +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION from deepmd.utils.data_system import DeepmdDataSystem class NeighborStat(): From 3584edb104c61ec3613c298c5f7e7c884f46b3d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 11 Feb 2021 14:40:37 +0100 Subject: [PATCH 136/562] workflow fix after deps moved to requirements.txt file --- .github/workflows/test_python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index 84534996d3..c36593b4fc 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -59,7 +59,7 @@ jobs: with: path: ~/.cache/pip key: - ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }} + ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }-${{ hashFiles('**/requirements.txt') }} restore-keys: | ${{ runner.os }}-pip- - run: | From e6bb77cd557cf42df1507db24638990b34b9ef36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 11 Feb 2021 14:51:35 +0100 Subject: [PATCH 137/562] test file bugfix --- .github/workflows/test_python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index c36593b4fc..7a67fb23b6 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -59,7 +59,7 @@ jobs: with: path: ~/.cache/pip key: - ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }-${{ hashFiles('**/requirements.txt') }} + ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }}-${{ hashFiles('**/requirements.txt') }} restore-keys: | ${{ runner.os }}-pip- - run: | From fb97248de184fd9f0c8213d591aaef6b55c31542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 11 Feb 2021 15:59:39 +0100 Subject: [PATCH 138/562] fix lintner action --- .github/workflows/lint_python.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml index 8ac70fa025..f503840bae 100644 --- a/.github/workflows/lint_python.yml +++ b/.github/workflows/lint_python.yml @@ -17,9 +17,9 @@ jobs: python-version: ${{ matrix.python }} - name: Install requirements run: pip install -r requirements.txt - - uses: marian-code/python-lint-annotate@master + - uses: marian-code/python-lint-annotate@v2.4.0 with: - python-root-list: "./deepmd/'*'.py ./deepmd/'*'/'*'.py ./source/train/'*'.py ./source/tests/'*'.py ./source/scripts/'*'.py ./source/op/'*'.py" + python-root-list: "'./deepmd/*.py ./deepmd/*/*.py ./source/train/*.py ./source/tests/*.py ./source/scripts/*.py ./source/op/*.py'" use-black: true use-isort: true use-mypy: true From 057c56c70175b3fde5f2b6bf4c42e292cd37a397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 11 Feb 2021 16:17:24 +0100 Subject: [PATCH 139/562] debug weird actions fail --- .github/workflows/lint_python.yml | 2 +- source/train/run_options.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml index f503840bae..04fd844cd7 100644 --- a/.github/workflows/lint_python.yml +++ b/.github/workflows/lint_python.yml @@ -17,7 +17,7 @@ jobs: python-version: ${{ matrix.python }} - name: Install requirements run: pip install -r requirements.txt - - uses: marian-code/python-lint-annotate@v2.4.0 + - uses: marian-code/python-lint-annotate@v2.5.0 with: python-root-list: "'./deepmd/*.py ./deepmd/*/*.py ./source/train/*.py ./source/tests/*.py ./source/scripts/*.py ./source/op/*.py'" use-black: true diff --git a/source/train/run_options.py b/source/train/run_options.py index ee4cc48803..dcfca30dbb 100644 --- a/source/train/run_options.py +++ b/source/train/run_options.py @@ -7,6 +7,8 @@ from typing import TYPE_CHECKING, Dict, List, Optional, Tuple import numpy as np +for p in Path(__file__).parent.glob("*"): + print(p) from deepmd.cluster import get_resource from deepmd.env import get_tf_default_nthreads, tf from deepmd.loggers import set_log_handles From 9dc752639dcc5d4aac4a884518c12345979dc690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 11 Feb 2021 16:44:38 +0100 Subject: [PATCH 140/562] debug failing build --- .github/workflows/test_python.yml | 2 -- source/train/CMakeLists.txt | 2 +- source/train/run_options.py | 6 ++++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index 7a67fb23b6..a1dffff256 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -60,8 +60,6 @@ jobs: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }}-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - run: | sudo apt update sudo apt install gcc-${{ matrix.gcc }} g++-${{ matrix.gcc }} diff --git a/source/train/CMakeLists.txt b/source/train/CMakeLists.txt index 57a6900802..748c21f121 100644 --- a/source/train/CMakeLists.txt +++ b/source/train/CMakeLists.txt @@ -14,5 +14,5 @@ install( ) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/run_config.ini - DESTINATION deepmd/config + DESTINATION deepmd/pkg_config ) \ No newline at end of file diff --git a/source/train/run_options.py b/source/train/run_options.py index dcfca30dbb..419241ef5d 100644 --- a/source/train/run_options.py +++ b/source/train/run_options.py @@ -8,7 +8,9 @@ import numpy as np for p in Path(__file__).parent.glob("*"): - print(p) + if p.is_dir(): + print(p) +print("----------------") from deepmd.cluster import get_resource from deepmd.env import get_tf_default_nthreads, tf from deepmd.loggers import set_log_handles @@ -47,7 +49,7 @@ class ArgsProto(Protocol): def _get_package_constants( - config_file: Path = Path(__file__).parent / "config/run_config.ini", + config_file: Path = Path(__file__).parent / "pkg_config/run_config.ini", ) -> Dict[str, str]: """Read package constants set at compile time by CMake to dictionary. From be7b2fabf156d288818fffe9871e2de3277f1575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 11 Feb 2021 16:53:11 +0100 Subject: [PATCH 141/562] debug failing tests --- .github/workflows/test_python.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index a1dffff256..e735dc315a 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -54,12 +54,6 @@ jobs: - uses: actions/setup-python@v2 with: python-version: ${{ matrix.python }} - - name: pip cache - uses: actions/cache@v2 - with: - path: ~/.cache/pip - key: - ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }}-${{ hashFiles('**/requirements.txt') }} - run: | sudo apt update sudo apt install gcc-${{ matrix.gcc }} g++-${{ matrix.gcc }} From 6958e1a603894ea88a1bbb96e553c96356552097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 11 Feb 2021 17:19:17 +0100 Subject: [PATCH 142/562] fix cluster subpackage not included --- .github/workflows/test_python.yml | 8 ++++++++ setup.py | 1 + 2 files changed, 9 insertions(+) diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index e735dc315a..7a67fb23b6 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -54,6 +54,14 @@ jobs: - uses: actions/setup-python@v2 with: python-version: ${{ matrix.python }} + - name: pip cache + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: + ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }}-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- - run: | sudo apt update sudo apt install gcc-${{ matrix.gcc }} g++-${{ matrix.gcc }} diff --git a/setup.py b/setup.py index 41b4e048a7..73066e6ca8 100644 --- a/setup.py +++ b/setup.py @@ -83,6 +83,7 @@ "deepmd/infer", "deepmd/loss", "deepmd/utils", + "deepmd/cluster" ], python_requires=">=3.6", classifiers=[ From 50dc8734051f2b0267dfe788e1b50aec24576a9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 11 Feb 2021 17:25:55 +0100 Subject: [PATCH 143/562] bugfix --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 73066e6ca8..ca4d13834e 100644 --- a/setup.py +++ b/setup.py @@ -83,6 +83,7 @@ "deepmd/infer", "deepmd/loss", "deepmd/utils", + "deepmd/loggers", "deepmd/cluster" ], python_requires=">=3.6", From 35f644d04e9ed0170248f5d3a7200c91cfbbc167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 11 Feb 2021 19:10:45 +0100 Subject: [PATCH 144/562] update lint action --- .github/workflows/lint_python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml index 04fd844cd7..dcb1e4bf0d 100644 --- a/.github/workflows/lint_python.yml +++ b/.github/workflows/lint_python.yml @@ -19,7 +19,7 @@ jobs: run: pip install -r requirements.txt - uses: marian-code/python-lint-annotate@v2.5.0 with: - python-root-list: "'./deepmd/*.py ./deepmd/*/*.py ./source/train/*.py ./source/tests/*.py ./source/scripts/*.py ./source/op/*.py'" + python-root-list: "./deepmd/*.py ./deepmd/*/*.py ./source/train/*.py ./source/tests/*.py ./source/scripts/*.py ./source/op/*.py" use-black: true use-isort: true use-mypy: true From b396f8c56a3dbf7598648f588dce9e781ecae7ba Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 12 Feb 2021 15:02:46 +0800 Subject: [PATCH 145/562] try to recover the old setting of building libop --- source/op/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/op/CMakeLists.txt b/source/op/CMakeLists.txt index 21a26e48ac..ef2c57f8ea 100644 --- a/source/op/CMakeLists.txt +++ b/source/op/CMakeLists.txt @@ -1,5 +1,7 @@ # libop +set(OP_LIB ${PROJECT_SOURCE_DIR}/lib/src/SimulationRegion.cpp ${PROJECT_SOURCE_DIR}/lib/src/neighbor_list.cc) + set (OP_CXX_FLAG -D_GLIBCXX_USE_CXX11_ABI=${OP_CXX_ABI} ) file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc descrpt_se_r.cc pair_tab.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc gelu.cc map_aparam.cc neighbor_stat.cc unaggregated_grad.cc tabulate.cc) file(GLOB OP_CUDA_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a_multi_device.cc descrpt_se_r_multi_device.cc pair_tab.cc prod_force_se_a_multi_device.cc prod_virial_se_a_multi_device.cc prod_force_se_r_multi_device.cc prod_virial_se_r_multi_device.cc soft_min.cc soft_min_force.cc soft_min_virial.cc gelu_multi_device.cc tabulate_multi_device.cc) From fc1e70e354955bdf4cb5680be38302b62de02574 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Fri, 12 Feb 2021 16:24:17 +0800 Subject: [PATCH 146/562] mv the mpi API to the lammps package --- source/lib/CMakeLists.txt | 5 --- source/lib/include/NNPInter.h | 8 ++-- source/lib/src/NNPInter.cc | 83 +++++++---------------------------- source/lmp/pair_nnp.cpp | 54 +++++++++++++++++++++-- source/lmp/pair_nnp.h.in | 2 + 5 files changed, 72 insertions(+), 80 deletions(-) diff --git a/source/lib/CMakeLists.txt b/source/lib/CMakeLists.txt index 448305c697..231b0a5ae8 100644 --- a/source/lib/CMakeLists.txt +++ b/source/lib/CMakeLists.txt @@ -8,9 +8,6 @@ configure_file( @ONLY ) -find_package(MPI REQUIRED) -include_directories(SYSTEM ${MPI_INCLUDE_PATH}) - if (USE_CUDA_TOOLKIT) include_directories("${CUDA_INCLUDE_DIRS}") endif() @@ -24,8 +21,6 @@ if (USE_CUDA_TOOLKIT) target_link_libraries (${libname} ${CUDA_LIBRARIES}) endif() -target_link_libraries (${libname} ${MPI_C_LIBRARIES}) - install(TARGETS ${libname} DESTINATION lib/) install( diff --git a/source/lib/include/NNPInter.h b/source/lib/include/NNPInter.h index 6793431e34..11bfad9c27 100644 --- a/source/lib/include/NNPInter.h +++ b/source/lib/include/NNPInter.h @@ -8,8 +8,8 @@ class NNPInter public: NNPInter () ; ~NNPInter() ; - NNPInter (const std::string & model, const int & gpu_rank = 0); - void init (const std::string & model, const int & gpu_rank = 0); + NNPInter (const std::string & model, const int & gpu_rank = 0, const std::string & file_content = ""); + void init (const std::string & model, const int & gpu_rank = 0, const std::string & file_content = ""); void print_summary(const std::string &pre) const; public: void compute (ENERGYTYPE & ener, @@ -105,8 +105,8 @@ class NNPInterModelDevi public: NNPInterModelDevi () ; ~NNPInterModelDevi() ; - NNPInterModelDevi (const std::vector & models, const int & gpu_rank = 0); - void init (const std::vector & models, const int & gpu_rank = 0); + NNPInterModelDevi (const std::vector & models, const int & gpu_rank = 0, const std::vector & file_contents = std::vector()); + void init (const std::vector & models, const int & gpu_rank = 0, const std::vector & file_contents = std::vector()); public: void compute (ENERGYTYPE & ener, std::vector & force, diff --git a/source/lib/src/NNPInter.cc b/source/lib/src/NNPInter.cc index 642e5c0108..f4f3ff0a33 100644 --- a/source/lib/src/NNPInter.cc +++ b/source/lib/src/NNPInter.cc @@ -2,7 +2,6 @@ #include "NNPAtomMap.h" #include "SimulationRegion.h" #include -#include #if GOOGLE_CUDA @@ -178,53 +177,28 @@ NNPInter () } NNPInter:: -NNPInter (const std::string & model, const int & gpu_rank) +NNPInter (const std::string & model, const int & gpu_rank, const std::string & file_content) : inited (false), init_nbor (false) { get_env_nthreads(num_intra_nthreads, num_inter_nthreads); - init(model, gpu_rank); + init(model, gpu_rank, file_content); } NNPInter::~NNPInter() {} void NNPInter:: -init (const std::string & model, const int & gpu_rank) +init (const std::string & model, const int & gpu_rank, const std::string & file_content) { assert (!inited); SessionOptions options; options.config.set_inter_op_parallelism_threads(num_inter_nthreads); options.config.set_intra_op_parallelism_threads(num_intra_nthreads); -///////////////////////////////////////////////////////////////// -// new implementation -// bcast file_content to all MPI processors -///////////////////////////////////////////////////////////////// - int myrank = 0, root = 0; - MPI_Comm_rank(MPI_COMM_WORLD, &myrank); - unsigned nchar = 0; - std::string file_content; - if (myrank == root) { - checkStatus (ReadFileToString(Env::Default(), model, &file_content)); - nchar = file_content.size(); - } - MPI_Bcast(&nchar, 1, MPI_UNSIGNED, root, MPI_COMM_WORLD); - char * buff = (char *)malloc(sizeof(char) * nchar); - if (myrank == root) { - memcpy(buff, file_content.c_str(), sizeof(char) * nchar); - } - MPI_Bcast(buff, nchar, MPI_CHAR, root, MPI_COMM_WORLD); - file_content.resize(nchar); - for (unsigned ii = 0; ii < nchar; ++ii) { - file_content[ii] = buff[ii]; - } - graph_def.ParseFromString(file_content); - free(buff); -///////////////////////////////////////////////////////////////// -// old implementation -// checkStatus (ReadBinaryProto(Env::Default(), model, &graph_def)); -///////////////////////////////////////////////////////////////// - + if(file_content.size() == 0) + checkStatus (ReadBinaryProto(Env::Default(), model, &graph_def)); + else + graph_def.ParseFromString(file_content); int gpu_num = -1; #if GOOGLE_CUDA cudaGetDeviceCount(&gpu_num); // check current device environment @@ -511,20 +485,20 @@ NNPInterModelDevi () } NNPInterModelDevi:: -NNPInterModelDevi (const std::vector & models, const int & gpu_rank) +NNPInterModelDevi (const std::vector & models, const int & gpu_rank, const std::vector & file_contents) : inited (false), init_nbor(false), numb_models (0) { get_env_nthreads(num_intra_nthreads, num_inter_nthreads); - init(models, gpu_rank); + init(models, gpu_rank, file_contents); } NNPInterModelDevi::~NNPInterModelDevi() {} void NNPInterModelDevi:: -init (const std::vector & models, const int & gpu_rank) +init (const std::vector & models, const int & gpu_rank, const std::vector & file_contents) { assert (!inited); numb_models = models.size(); @@ -539,39 +513,12 @@ init (const std::vector & models, const int & gpu_rank) SessionOptions options; options.config.set_inter_op_parallelism_threads(num_inter_nthreads); options.config.set_intra_op_parallelism_threads(num_intra_nthreads); -///////////////////////////////////////////////////////////////// -// new implementation -// bcast file_content to all MPI processors -///////////////////////////////////////////////////////////////// - int myrank = 0, root = 0; - MPI_Comm_rank(MPI_COMM_WORLD, &myrank); - unsigned nchar = 0; - std::string file_content; - for (unsigned ii = 0; ii < numb_models; ++ii) { - if (myrank == root) { - checkStatus (ReadFileToString(Env::Default(), models[ii], &file_content)); - nchar = file_content.size(); - } - MPI_Bcast(&nchar, 1, MPI_UNSIGNED, root, MPI_COMM_WORLD); - char * buff = (char *)malloc(sizeof(char) * nchar); - if (myrank == root) { - memcpy(buff, file_content.c_str(), sizeof(char) * nchar); - } - MPI_Bcast(buff, nchar, MPI_CHAR, root, MPI_COMM_WORLD); - file_content.resize(nchar); - for (unsigned ii = 0; ii < nchar; ++ii) { - file_content[ii] = buff[ii]; - } - graph_defs[ii].ParseFromString(file_content); - free(buff); + for (unsigned ii = 0; ii < numb_models; ++ii){ + if (file_contents.size() == 0) + checkStatus (ReadBinaryProto(Env::Default(), models[ii], &graph_defs[ii])); + else + graph_defs[ii].ParseFromString(file_contents[ii]); } -///////////////////////////////////////////////////////////////// -// old implementation -// for (unsigned ii = 0; ii < numb_models; ++ii){ -// checkStatus (ReadBinaryProto(Env::Default(), models[ii], &graph_defs[ii])); -// } -///////////////////////////////////////////////////////////////// - #if GOOGLE_CUDA if (gpu_num > 0) { options.config.set_allow_soft_placement(true); diff --git a/source/lmp/pair_nnp.cpp b/source/lmp/pair_nnp.cpp index e8cff008f5..fd18a63c71 100644 --- a/source/lmp/pair_nnp.cpp +++ b/source/lmp/pair_nnp.cpp @@ -105,6 +105,54 @@ int PairNNP::get_node_rank() { return looprank; } +std::string PairNNP::get_file_content(const std::string & model) { + int myrank = 0, root = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &myrank); + unsigned nchar = 0; + std::string file_content; + if (myrank == root) { + checkStatus (ReadFileToString(Env::Default(), model, &file_content)); + nchar = file_content.size(); + } + MPI_Bcast(&nchar, 1, MPI_UNSIGNED, root, MPI_COMM_WORLD); + char * buff = (char *)malloc(sizeof(char) * nchar); + if (myrank == root) { + memcpy(buff, file_content.c_str(), sizeof(char) * nchar); + } + MPI_Bcast(buff, nchar, MPI_CHAR, root, MPI_COMM_WORLD); + file_content.resize(nchar); + for (unsigned ii = 0; ii < nchar; ++ii) { + file_content[ii] = buff[ii]; + } + return file_content; + free(buff); +} + +std::vector PairNNP::get_file_content(const std::vector & models) { + int myrank = 0, root = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &myrank); + unsigned nchar = 0; + std::vector file_contents(models.size()); + for (unsigned ii = 0; ii < models.size(); ++ii) { + if (myrank == root) { + checkStatus (ReadFileToString(Env::Default(), models[ii], &file_contents[ii])); + nchar = file_contents[ii].size(); + } + MPI_Bcast(&nchar, 1, MPI_UNSIGNED, root, MPI_COMM_WORLD); + char * buff = (char *)malloc(sizeof(char) * nchar); + if (myrank == root) { + memcpy(buff, file_contents[ii].c_str(), sizeof(char) * nchar); + } + MPI_Bcast(buff, nchar, MPI_CHAR, root, MPI_COMM_WORLD); + file_contents[ii].resize(nchar); + for (unsigned jj = 0; jj < nchar; ++jj) { + file_contents[ii][jj] = buff[jj]; + } + free(buff); + } + return file_contents; +} + static void ana_st (double & max, double & min, @@ -656,15 +704,15 @@ void PairNNP::settings(int narg, char **arg) } numb_models = models.size(); if (numb_models == 1) { - nnp_inter.init (arg[0], get_node_rank()); + nnp_inter.init (arg[0], get_node_rank(), get_file_content(arg[0])); cutoff = nnp_inter.cutoff (); numb_types = nnp_inter.numb_types(); dim_fparam = nnp_inter.dim_fparam(); dim_aparam = nnp_inter.dim_aparam(); } else { - nnp_inter.init (arg[0], get_node_rank()); - nnp_inter_model_devi.init(models, get_node_rank()); + nnp_inter.init (arg[0], get_node_rank(), get_file_content(arg[0])); + nnp_inter_model_devi.init(models, get_node_rank(), get_file_content(models)); cutoff = nnp_inter_model_devi.cutoff(); numb_types = nnp_inter_model_devi.numb_types(); dim_fparam = nnp_inter_model_devi.dim_fparam(); diff --git a/source/lmp/pair_nnp.h.in b/source/lmp/pair_nnp.h.in index 4d1a995a3a..7b190525e0 100644 --- a/source/lmp/pair_nnp.h.in +++ b/source/lmp/pair_nnp.h.in @@ -64,6 +64,8 @@ class PairNNP : public Pair { void unpack_reverse_comm(int, int *, double *); void print_summary(const std::string pre) const; int get_node_rank(); + std::string get_file_content(const std::string & model); + std::vector get_file_content(const std::vector & models); protected: virtual void allocate(); double **scale; From 328ace54a9c71cc753b9916c14967a6db639e0b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 11 Feb 2021 18:39:26 +0100 Subject: [PATCH 147/562] propose coding guidelines --- doc/developement.rst | 169 +++++++++++++++++++++++++++++++++++++++++++ doc/index.rst | 1 + 2 files changed, 170 insertions(+) create mode 100644 doc/developement.rst diff --git a/doc/developement.rst b/doc/developement.rst new file mode 100644 index 0000000000..62fabdf81f --- /dev/null +++ b/doc/developement.rst @@ -0,0 +1,169 @@ +.. _coding conventions: + +================== +Coding Conventions +================== + +Preface +======= + +The aim of these coding standards is to help create a codebase with defined and +consistent coding style that every contributor can get easily familiar with. This +will in enhance code readability as there will be no different coding styles from +different contributors and everything will be documented. Also PR diffs will be smaller +because of unified coding style. Finally static typing will help in hunting down +potential bugs before the code is even run. + +Contributed code will not be refused merely because it does not +strictly adhere to these conditions; as long as it's internally +consistent, clean, and correct, it probably will be accepted. But +don't be surprised if the "offending" code gets fiddled over time to +conform to these conventions. + +There are also github actions CI checks for python code style which will annotate the +PR diff for you to see the areas where your code is lacking compared to the set standard. + +Rules +===== + +The code must be compatible with the oldest supported version of python +which is 3.6 + +The project follows the generic coding conventions as +specified in the `Style Guide for Python Code`_, `Docstring +Conventions`_ and `Typing Conventions`_ PEPs, clarified and extended as follows: + +* Do not use "``*``" imports such as ``from module import *``. Instead, + list imports explicitly. + +* Use 4 spaces per indentation level. No tabs. + +* Read the *Whitespace in Expressions and Statements* + section of PEP8_. + +* Avoid `trailing whitespaces`_. + +* No one-liner compound statements (i.e., no ``if x: return``: use two + lines). + +* Maximum line length is 88 characters as recomended by + `black `_ wich is less strict than + `Docstring Conventions`_ suggests. + +* Use "StudlyCaps" for class names. + +* Use "lowercase" or "lowercase_with_underscores" for function, + method, variable names and module names. For short names, + joined lowercase may be used (e.g. "tagname"). Choose what is most + readable. + +* No single-character variable names, except indices in loops + that encompass a very small number of lines + (``for i in range(5): ...``). + +* Avoid lambda expressions. Use named functions instead. + +* Avoid functional constructs (filter, map, etc.). Use list + comprehensions instead. + +* Use ``"double quotes"`` for string literals, and ``"""triple double + quotes"""`` for docstring's. Single quotes are OK for + something like + + .. code-block:: python + + f"something {'this' if x else 'that'}" + +.. _Style Guide for Python Code: +.. _PEP8: https://www.python.org/dev/peps/pep-0008/ +.. _Docstring Conventions: https://www.python.org/dev/peps/pep-0257/ +.. _Typing Conventions: https://www.python.org/dev/peps/pep-0484/ +.. _Docutils project: http://docutils.sourceforge.net/docs/dev/policies.html + #python-coding-conventions +.. _trailing whitespaces: http://www.gnu.org/software/emacs/manual/html_node/ + emacs/Useless-Whitespace.html + +.. attention:: + + Thus spake the Lord: Thou shalt indent with four spaces. No more, no less. + Four shall be the number of spaces thou shalt indent, and the number of thy + indenting shall be four. Eight shalt thou not indent, nor either indent thou + two, excepting that thou then proceed to four. Tabs are right out. + + Georg Brandl + + +General advice +============== + + * Get rid of as many ``break`` and ``continue`` statements as possible. + + * Write short functions. All functions should fit within a standard screen. + + * Use descriptive variable names. + +Writing documentation in the code +================================= + +Here is an example of how to write good docstrings: + + https://github.com/numpy/numpy/blob/master/doc/example.py + +The numpy doctring documentation can be found `here `_ + +It is a good practice to run `pydocstyle `_ +check on your code or use a text editor that does it automatically): + +.. code-block:: bash + + $ pydocstyle filename.py + +.. _stylecheck: + +Run pycodestyle on your code +============================ + +It's a good idea to run `pycodestyle `_ +on your code (or use a text editor that does it automatically): + +.. code-block:: bash + + $ pycodestyle filename.py + +.. _typing: + +Run mypy on your code +===================== + +It's a good idea to run `mypy `_ +on your code (or use a text editor that does it automatically): + +.. code-block:: bash + + $ mypy filename.py + +.. _docstyle: + +Run pydocstyle on your code +=========================== + +It's a good idea to run `pycodestyle `_ +on your code (or use a text editor that does it automatically): + +.. code-block:: bash + + $ pycodestyle filename.py --max-line-length=88 + +.. _autoformat: + +Run black on your code +====================== + +Another method of enforcing PEP8_ is using a tool such as +`black `_. These tools tend to be +very effective at cleaning up code, but should be used carefully and code +should be retested after cleaning it. Try: + +.. code-block:: bash + + $ black --help diff --git a/doc/index.rst b/doc/index.rst index 9969d8372d..c5b2a2af22 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -17,6 +17,7 @@ DeePMD-kit's documentation lammps-pair-style-deepmd tensorboard api + developement Indices and tables From 3ca656f06d6741e10b33494089f25a45366186ed Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 13 Feb 2021 13:45:15 +0800 Subject: [PATCH 148/562] refact pair_tab --- source/lib/include/pair_tab.h | 18 + source/lib/src/pair_tab.cc | 257 ++++++++++ source/lib/tests/test_pair_tab.cc | 780 ++++++++++++++++++++++++++++++ source/op/pair_tab.cc | 179 +------ 4 files changed, 1077 insertions(+), 157 deletions(-) create mode 100644 source/lib/include/pair_tab.h create mode 100644 source/lib/src/pair_tab.cc create mode 100644 source/lib/tests/test_pair_tab.cc diff --git a/source/lib/include/pair_tab.h b/source/lib/include/pair_tab.h new file mode 100644 index 0000000000..3437139e2e --- /dev/null +++ b/source/lib/include/pair_tab.h @@ -0,0 +1,18 @@ +#pragma once + +template +void pair_tab( + FPTYPE * energy, + FPTYPE * force, + FPTYPE * virial, + const double * table_info, + const double * table_data, + const FPTYPE * rij, + const FPTYPE * scale, + const int * type, + const int * nlist, + const int * natoms, + const std::vector & sel_a, + const std::vector & sel_r + ); + diff --git a/source/lib/src/pair_tab.cc b/source/lib/src/pair_tab.cc new file mode 100644 index 0000000000..3e825133e9 --- /dev/null +++ b/source/lib/src/pair_tab.cc @@ -0,0 +1,257 @@ +#include +#include +#include +#include +#include "pair_tab.h" + +inline +void _pair_tabulated_inter ( + double & ener, + double & fscale, + const double * table_info, + const double * table_data, + const double * dr) +{ + // info size: 3 + const double & rmin = table_info[0]; + const double & hh = table_info[1]; + const double hi = 1./hh; + const unsigned nspline = unsigned(table_info[2] + 0.1); + const unsigned ndata = nspline * 4; + + double r2 = dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2]; + double rr = sqrt(r2); + double uu = (rr - rmin) * hi; + // std::cout << rr << " " << rmin << " " << hh << " " << uu << std::endl; + if (uu < 0) { + std::cerr << "coord go beyond table lower boundary" << std::endl; + exit(1); + } + int idx = uu; + if (idx >= nspline) { + fscale = ener = 0; + return; + } + uu -= idx; + assert(idx >= 0); + assert(uu >= 0 && uu < 1); + + const double & a3 = table_data[4 * idx + 0]; + const double & a2 = table_data[4 * idx + 1]; + const double & a1 = table_data[4 * idx + 2]; + const double & a0 = table_data[4 * idx + 3]; + + double etmp = (a3 * uu + a2) * uu + a1; + ener = etmp * uu + a0; + fscale = (2. * a3 * uu + a2) * uu + etmp; + fscale *= -hi; +} + +template +void _pair_tab_jloop( + FPTYPE * energy, + FPTYPE * force, + FPTYPE * virial, + const double * table_info, + const double * table_data, + const FPTYPE * rij, + const FPTYPE * scale, + const int * type, + const int * nlist, + const int * natoms, + const std::vector & sel_a, + const std::vector & sel_r + ) +{ +} + +inline void +_cum_sum ( + std::vector & sec, + const std::vector & n_sel) { + sec.resize (n_sel.size() + 1); + sec[0] = 0; + for (int ii = 1; ii < sec.size(); ++ii){ + sec[ii] = sec[ii-1] + n_sel[ii-1]; + } +} + +template +void pair_tab( + FPTYPE * energy, + FPTYPE * force, + FPTYPE * virial, + const double * p_table_info, + const double * p_table_data, + const FPTYPE * rij, + const FPTYPE * scale, + const int * type, + const int * nlist, + const int * natoms, + const std::vector & sel_a, + const std::vector & sel_r + ) +{ + std::vector sec_a; + std::vector sec_r; + _cum_sum(sec_a, sel_a); + _cum_sum(sec_r, sel_r); + const int nloc = natoms[0]; + const int nall = natoms[1]; + const int nnei = sec_a.back() + sec_r.back(); + const int ntypes = int(p_table_info[3]+0.1); + const int nspline = p_table_info[2]+0.1; + const int tab_stride = 4 * nspline; + + // fill results with 0 + for (int ii = 0; ii < nloc; ++ii){ + int i_idx = ii; + energy[i_idx] = 0; + } + for (int ii = 0; ii < nall; ++ii){ + int i_idx = ii; + force[i_idx * 3 + 0] = 0; + force[i_idx * 3 + 1] = 0; + force[i_idx * 3 + 2] = 0; + for (int dd = 0; dd < 9; ++dd) { + virial[i_idx * 9 + dd] = 0; + } + } + // compute force of a frame + int i_idx = 0; + for (int tt = 0; tt < ntypes; ++tt) { + for (int ii = 0; ii < natoms[2+tt]; ++ii){ + int i_type = type[i_idx]; + FPTYPE i_scale = scale[i_idx]; + assert(i_type == tt) ; + int jiter = 0; + // a neighbor + for (int ss = 0; ss < sel_a.size(); ++ss){ + int j_type = ss; + const double * cur_table_data = + p_table_data + (i_type * ntypes + j_type) * tab_stride; + for (int jj = 0; jj < sel_a[ss]; ++jj){ + int j_idx = nlist[i_idx * nnei + jiter]; + if (j_idx < 0){ + jiter++; + continue; + } + assert(j_type == type[j_idx]); + double dr[3]; + for (int dd = 0; dd < 3; ++dd){ + dr[dd] = rij[(i_idx * nnei + jiter) * 3 + dd]; + } + double r2 = dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2]; + double ri = 1./sqrt(r2); + double ener, fscale; + _pair_tabulated_inter( + ener, + fscale, + p_table_info, + cur_table_data, + dr); + // printf("tabforce %d %d r: %12.8f ener: %12.8f %12.8f %8.5f fj: %8.5f %8.5f %8.5f dr: %9.6f %9.6f %9.6f\n", + // i_idx, j_idx, + // 1/ri, + // ener, fscale, i_scale, + // -fscale * dr[00] * ri * 0.5 * i_scale, -fscale * dr[01] * ri * 0.5 * i_scale, -fscale * dr[02] * ri * 0.5 * i_scale, + // dr[0], dr[1], dr[2] + // ); + energy[i_idx] += 0.5 * ener; + for (int dd = 0; dd < 3; ++dd) { + force[i_idx * 3 + dd] -= fscale * dr[dd] * ri * 0.5 * i_scale; + force[j_idx * 3 + dd] += fscale * dr[dd] * ri * 0.5 * i_scale; + } + for (int dd0 = 0; dd0 < 3; ++dd0) { + for (int dd1 = 0; dd1 < 3; ++dd1) { + virial[i_idx * 9 + dd0 * 3 + dd1] + += 0.5 * fscale * dr[dd0] * dr[dd1] * ri * 0.5 * i_scale; + virial[j_idx * 9 + dd0 * 3 + dd1] + += 0.5 * fscale * dr[dd0] * dr[dd1] * ri * 0.5 * i_scale; + } + } + jiter++; + } + } + // r neighbor + for (int ss = 0; ss < sel_r.size(); ++ss){ + int j_type = ss; + const double * cur_table_data = + p_table_data + (i_type * ntypes + j_type) * tab_stride; + for (int jj = 0; jj < sel_r[ss]; ++jj){ + int j_idx = nlist[i_idx * nnei + jiter]; + if (j_idx < 0){ + jiter ++; + continue; + } + assert(j_type == type[j_idx]); + double dr[3]; + for (int dd = 0; dd < 3; ++dd){ + dr[dd] = rij[(i_idx * nnei + jiter) * 3 + dd]; + } + double r2 = dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2]; + double ri = 1./sqrt(r2); + double ener, fscale; + _pair_tabulated_inter( + ener, + fscale, + p_table_info, + cur_table_data, + dr); + // printf("tabforce %d %d %8.5f %12.8f %12.8f %8.5f fj: %8.5f %8.5f %8.5f\n", + // i_idx, j_idx, + // 1/ri, + // ener, fscale, i_scale, + // -fscale * dr[00] * ri * 0.5 * i_scale, -fscale * dr[01] * ri * 0.5 * i_scale, -fscale * dr[02] * ri * 0.5 * i_scale); + energy[i_idx] += 0.5 * ener; + for (int dd = 0; dd < 3; ++dd) { + force[i_idx * 3 + dd] -= fscale * dr[dd] * ri * 0.5 * i_scale; + force[j_idx * 3 + dd] += fscale * dr[dd] * ri * 0.5 * i_scale; + } + for (int dd0 = 0; dd0 < 3; ++dd0) { + for (int dd1 = 0; dd1 < 3; ++dd1) { + virial[j_idx * 9 + dd0 * 3 + dd1] + += fscale * dr[dd0] * dr[dd1] * ri * 0.5 * i_scale; + } + } + jiter++; + } + } + i_idx ++; + } + } +} + + +template +void pair_tab( + float * energy, + float * force, + float * virial, + const double * table_info, + const double * table_data, + const float * rij, + const float * scale, + const int * type, + const int * nlist, + const int * natoms, + const std::vector & sel_a, + const std::vector & sel_r + ); + +template +void pair_tab( + double * energy, + double * force, + double * virial, + const double * table_info, + const double * table_data, + const double * rij, + const double * scale, + const int * type, + const int * nlist, + const int * natoms, + const std::vector & sel_a, + const std::vector & sel_r + ); + diff --git a/source/lib/tests/test_pair_tab.cc b/source/lib/tests/test_pair_tab.cc new file mode 100644 index 0000000000..424f5571c2 --- /dev/null +++ b/source/lib/tests/test_pair_tab.cc @@ -0,0 +1,780 @@ +#include +#include +#include +#include "fmt_nlist.h" +#include "env_mat.h" +#include "prod_env_mat.h" +#include "neighbor_list.h" +#include "pair_tab.h" + +inline void +_cum_sum ( + std::vector & sec, + const std::vector & n_sel) { + sec.resize (n_sel.size() + 1); + sec[0] = 0; + for (int ii = 1; ii < sec.size(); ++ii){ + sec[ii] = sec[ii-1] + n_sel[ii-1]; + } +} + +class TestPairTab : public ::testing::Test +{ +protected: + std::vector posi = { + 12.83, 2.56, 2.18, + 3.36, 3.00, 1.81, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector box = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + std::vector atype = {0, 0, 1, 1, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall, nnei, ndescrpt; + std::vector natoms; + double rc = 6; + double rc_smth = 0.8; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sel_a = {5, 5}; + std::vector sel_r = {0, 0}; + std::vector sec_a, sec_r; + // std::vector sec_a = {0, 5, 10}; + // std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector> nlist_a_cpy, nlist_r_cpy; + std::vector env, env_deriv, rij; + std::vector nlist; + std::vector fmt_nlist_a; + std::vector tab_info = { + 0.000000000000000000e+00,5.000000000000000000e-01,1.900000000000000000e+01,2.000000000000000000e+00, + }; + std::vector tab_data = { + -1.645731450145992980e-02,-9.318102695874852515e-03,5.052009558015377877e-01,0.000000000000000000e+00,-1.645731450146042940e-02,-5.869004620025458641e-02,4.371928069054082933e-01,4.794255386042030054e-01,-6.354779499724752534e-03,-1.080619897046354722e-01,2.704407710005182763e-01,8.414709848078965049e-01,3.676315333364321702e-03,-1.271263282038100351e-01,3.525245309207285238e-02,9.974949866040544455e-01,1.324335679744598204e-02,-1.160973822037167924e-01,-2.079712573154540167e-01,9.092974268256817094e-01,1.945112709784019289e-02,-7.636731181137940139e-02,-4.004359513305503215e-01,5.984721441039565493e-01,2.092788842815984651e-02,-1.801393051785876720e-02,-4.948171936597881015e-01,1.411200080598672135e-01,1.727238702609701360e-02,4.476973476662088336e-02,-4.680613894110260964e-01,-3.507832276896198365e-01,9.390240597413182511e-03,9.658689584491141067e-02,-3.267047587994936220e-01,-7.568024953079282025e-01,-7.915293177619131537e-04,1.247576176371514023e-01,-1.053602453174308090e-01,-9.775301176650970092e-01,-1.077948259470512538e-02,1.223830296838656073e-01,1.417804020035860202e-01,-9.589242746631384540e-01,-1.812776811548627576e-02,9.004458189975028670e-02,3.542080135872019420e-01,-7.055403255703919241e-01,-2.103966430679454769e-02,3.566127755329190352e-02,4.799138730402439101e-01,-2.794154981989258602e-01,-1.879310922837906794e-02,-2.745771536709157301e-02,4.881174352264442962e-01,2.151199880878155168e-01,-1.197225569894497244e-02,-8.383704305222891562e-02,3.768226768071237243e-01,6.569865987187890610e-01,-2.119743608124211032e-03,-1.197538101490639856e-01,1.732318236058309757e-01,9.379999767747388972e-01,7.876934490214426710e-03,-1.261130409734364521e-01,-7.263502751666940649e-02,9.893582466233817874e-01,1.734391611395907917e-02,-1.024822375027934496e-01,-3.012303059928992388e-01,7.984871126234902583e-01,1.734391611395902366e-02,-5.045048916091599001e-02,-4.541630326566090115e-01,4.121184852417565936e-01,-2.857038556912050442e-03,-1.088944917710427673e-01,3.641943791261976759e-01,7.071067811865474617e-01,-2.857038556912189220e-03,-1.174656074417785578e-01,1.378342799133762120e-01,9.595496299847904309e-01,9.997734062661967069e-03,-1.260367231125156806e-01,-1.056680506409179154e-01,9.770612638994756738e-01,1.714771792589186994e-02,-9.604352092452944634e-02,-3.277482946779627926e-01,7.553542242087043501e-01,2.097205155371145713e-02,-4.460036714685383652e-02,-4.683921827493462975e-01,3.487101265321038701e-01,1.942785366828164717e-02,1.831578751428042384e-02,-4.946767623819197657e-01,-1.433103718103848900e-01,1.318969794248442406e-02,7.659934851912514331e-02,-3.997616263485141985e-01,-6.002434930097426680e-01,3.705452789754024034e-03,1.161684423465786514e-01,-2.069938354828104177e-01,-9.102160728966471881e-01,-6.681509290541898238e-03,1.272848007158404737e-01,3.645940757960873524e-02,-9.973360132431250413e-01,-1.543384209711462507e-02,1.072402728442147790e-01,2.709844811396642239e-01,-8.402733142382176057e-01,-2.040699032626563936e-02,6.093874655287040421e-02,4.391635005367497957e-01,-4.774824023514532834e-01,-2.038432541044177260e-02,-2.822244259263473332e-04,4.998200226636939081e-01,2.212854411901365656e-03,-1.536918924167118838e-02,-6.143520065725210921e-02,4.381025975805153405e-01,4.813663272392268988e-01,-6.597319578834796860e-03,-1.075427683822652303e-01,2.691246285409980010e-01,8.426645349208191638e-01,3.812846748232762151e-03,-1.273347271187698360e-01,3.424713303996269192e-02,9.976490755007169087e-01,1.320350429809030723e-02,-1.158961868740716050e-01,-2.089837809528787005e-01,9.083743281701425198e-01,1.968240442794899625e-02,-7.628567397980012821e-02,-4.011656418067505725e-01,5.966978646412827159e-01,2.014467273961967342e-02,-1.723846069595319497e-02,-4.946897764825041177e-01,1.389289532826809004e-01,2.014467273961895177e-02,4.319555752290565875e-02,-4.687326796555513764e-01,-3.528546111561566834e-01,-2.857038556912050442e-03,-1.088944917710427673e-01,3.641943791261976759e-01,7.071067811865474617e-01,-2.857038556912189220e-03,-1.174656074417785578e-01,1.378342799133762120e-01,9.595496299847904309e-01,9.997734062661967069e-03,-1.260367231125156806e-01,-1.056680506409179154e-01,9.770612638994756738e-01,1.714771792589186994e-02,-9.604352092452944634e-02,-3.277482946779627926e-01,7.553542242087043501e-01,2.097205155371145713e-02,-4.460036714685383652e-02,-4.683921827493462975e-01,3.487101265321038701e-01,1.942785366828164717e-02,1.831578751428042384e-02,-4.946767623819197657e-01,-1.433103718103848900e-01,1.318969794248442406e-02,7.659934851912514331e-02,-3.997616263485141985e-01,-6.002434930097426680e-01,3.705452789754024034e-03,1.161684423465786514e-01,-2.069938354828104177e-01,-9.102160728966471881e-01,-6.681509290541898238e-03,1.272848007158404737e-01,3.645940757960873524e-02,-9.973360132431250413e-01,-1.543384209711462507e-02,1.072402728442147790e-01,2.709844811396642239e-01,-8.402733142382176057e-01,-2.040699032626563936e-02,6.093874655287040421e-02,4.391635005367497957e-01,-4.774824023514532834e-01,-2.038432541044177260e-02,-2.822244259263473332e-04,4.998200226636939081e-01,2.212854411901365656e-03,-1.536918924167118838e-02,-6.143520065725210921e-02,4.381025975805153405e-01,4.813663272392268988e-01,-6.597319578834796860e-03,-1.075427683822652303e-01,2.691246285409980010e-01,8.426645349208191638e-01,3.812846748232762151e-03,-1.273347271187698360e-01,3.424713303996269192e-02,9.976490755007169087e-01,1.320350429809030723e-02,-1.158961868740716050e-01,-2.089837809528787005e-01,9.083743281701425198e-01,1.968240442794899625e-02,-7.628567397980012821e-02,-4.011656418067505725e-01,5.966978646412827159e-01,2.014467273961967342e-02,-1.723846069595319497e-02,-4.946897764825041177e-01,1.389289532826809004e-01,2.014467273961895177e-02,4.319555752290565875e-02,-4.687326796555513764e-01,-3.528546111561566834e-01,1.241685182605223314e-02,-1.446819644344595757e-01,9.847674498780101260e-03,1.000000000000000000e+00,1.241685182605223314e-02,-1.074314089563028762e-01,-2.422656988919823506e-01,8.775825618903727587e-01,2.049371060414068024e-02,-7.018085347814612129e-02,-4.198779613264314037e-01,5.403023058681397650e-01,2.057421992118041443e-02,-8.699721665724191588e-03,-4.987585364703014945e-01,7.073720166770297579e-02,1.641560294060040448e-02,5.302293809781688516e-02,-4.544353200382087454e-01,-4.161468365471423514e-01,8.024007047643694213e-03,1.022697469196180153e-01,-2.991426350207735396e-01,-8.011436155469336962e-01,-2.274838714293875297e-03,1.263417680625494866e-01,-7.053112003860620427e-02,-9.899924966004454152e-01,-1.203208543609352033e-02,1.195172519196672223e-01,1.753278999436104768e-01,-9.364566872907963413e-01,-1.883932165321944296e-02,8.342099561138682784e-02,3.782661474746648045e-01,-6.536436208636119405e-01,-2.103521949550246628e-02,2.690303065172838792e-02,4.885901737377801313e-01,-2.107957994307797789e-01,-1.808035989191653092e-02,-3.620262783477895541e-02,4.792905765547292862e-01,2.836621854632261908e-01,-1.070002133978709136e-02,-9.044370751052860369e-02,3.526442412094217826e-01,7.086697742912599907e-01,-6.956515614555680571e-04,-1.225437715298900998e-01,1.396567621690030792e-01,9.601702866503659672e-01,9.463090404681517853e-03,-1.246307262142566930e-01,-1.075177355751436026e-01,9.765876257280234896e-01,1.736443528154563154e-02,-9.624145500021202837e-02,-3.283899167896124349e-01,7.539022543433047119e-01,2.079231845733497952e-02,-4.414814915557463415e-02,-4.687795209453995970e-01,3.466353178350258801e-01,1.995818879190347506e-02,1.822880621643041543e-02,-4.946988638845440933e-01,-1.455000338086134548e-01,1.114495328397846485e-02,7.810337259214095162e-02,-3.983666850759726152e-01,-6.020119026848235189e-01,1.114495328397829832e-02,1.115382324440758466e-01,-2.087250800397557615e-01,-9.111302618846769397e-01, + }; + std::vector expected_energy = { + -0.1306167788188060, -0.0255597250848064, 0.1587325724681873, -0.6817885971798407, -0.5510062343672764, 0.0991809936197377, + }; + + void SetUp() override { + do_setup(); + }; + void do_setup(){ + _cum_sum(sec_a, sel_a); + _cum_sum(sec_r, sel_r); + region.reinitBox(&box[0]); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nnei = sec_a.back(); + ndescrpt = nnei * 4; + natoms.resize(ntypes+2, 0); + natoms[0] = nloc; + natoms[1] = nall; + for (int ii = 0; ii < nloc; ++ii){ + natoms[atype[ii]+2] ++; + } + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + build_nlist(nlist_a_cpy, nlist_r_cpy, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + nlist.resize(nloc * nnei); + env.resize(nloc * ndescrpt); + env_deriv.resize(nloc * ndescrpt * 3); + rij.resize(nloc * nnei * 3); + for(int ii = 0; ii < nloc; ++ii){ + // format nlist and record + format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + for (int jj = 0; jj < nnei; ++jj){ + nlist[ii*nnei + jj] = fmt_nlist_a[jj]; + } + std::vector t_env, t_env_deriv, t_rij; + // compute env_mat and its deriv, record + env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < ndescrpt; ++jj){ + env[ii*ndescrpt+jj] = t_env[jj]; + for (int dd = 0; dd < 3; ++dd){ + env_deriv[ii*ndescrpt*3+jj*3+dd] = t_env_deriv[jj*3+dd]; + } + } + for (int jj = 0; jj < nnei * 3; ++jj){ + rij[ii*nnei*3 + jj] = t_rij[jj]; + } + } + } + void TearDown() override { + } +}; + + +class TestPairTabTriBox : public TestPairTab +{ +protected: + void SetUp() override { + box = std::vector({13., 0.3, 0.1, 0., 13., 0.2, 0., 0., 13.}); + do_setup(); + } + void TearDown() override { + } +}; + + +TEST_F(TestPairTab, cpu) +{ + std::vector energy(nloc); + std::vector force(nall * 3); + std::vector virial(nall * 9); + std::vector scale(nloc, 1.0); + + pair_tab( + &energy[0], + &force[0], + &virial[0], + &tab_info[0], + &tab_data[0], + &rij[0], + &scale[0], + &atype_cpy[0], + &nlist[0], + &natoms[0], + sel_a, + sel_r); + + EXPECT_EQ(energy.size(), expected_energy.size()); + EXPECT_EQ(energy.size(), nloc); + for (int ii = 0; ii < nloc; ++ii){ + EXPECT_LT(fabs(energy[ii] - expected_energy[ii]), 1e-8); + } + // for (int ii = 0; ii < nloc; ++ii){ + // printf("%.16f, ", energy[ii]); + // } + // printf("\n"); +} + + +int make_inter_nlist( + std::vector &ilist, + std::vector &jrange, + std::vector &jlist, + const int & nloc, + const std::vector> & nlist_cpy) +{ + ilist.resize(nloc); + jrange.resize(nloc+1); + int tot_nnei = 0; + int max_nbor_size = 0; + for(int ii = 0; ii < nlist_cpy.size(); ++ii){ + tot_nnei += nlist_cpy[ii].size(); + if (nlist_cpy[ii].size() > max_nbor_size){ + max_nbor_size = nlist_cpy[ii].size(); + } + } + jlist.resize(tot_nnei); + for (int ii = 0; ii < nloc; ++ii){ + ilist[ii] = ii; + jrange[ii+1] = jrange[ii] + nlist_cpy[ii].size(); + int jj, cc; + for (jj = jrange[ii], cc = 0; jj < jrange[ii+1]; ++jj, ++cc){ + jlist[jj] = nlist_cpy[ii][cc]; + } + } + return max_nbor_size; +} + + +TEST_F(TestPairTab, cpu_f_num_deriv) +{ + std::vector energy(nloc); + std::vector force(nall * 3); + std::vector virial(9, 0.); + std::vector atom_virial(nall * 9); + std::vector scale(nloc, 1.0); + pair_tab( + &energy[0], + &force[0], + &atom_virial[0], + &tab_info[0], + &tab_data[0], + &rij[0], + &scale[0], + &atype_cpy[0], + &nlist[0], + &natoms[0], + sel_a, + sel_r); + for (int ii = nloc; ii < nall; ++ii){ + for (int dd = 0; dd < 3; ++dd){ + int orig_idx = mapping[ii]; + force[orig_idx*3+dd] += force[ii*3+dd]; + } + } + for (int ii = 0; ii < nall; ++ii){ + for (int dd = 0; dd < 9; ++dd){ + virial[dd] += atom_virial[ii*9+dd]; + } + } + double hh = 1e-4; + for(int ii = 0; ii < nloc; ++ii){ + for(int dd = 0; dd < 3; ++dd){ + std::vector posi_0(posi); + std::vector posi_1(posi); + posi_0[ii*3+dd] -= hh; + posi_1[ii*3+dd] += hh; + std::vector posi_cpy_0, posi_cpy_1; + std::vector atype_cpy_0, atype_cpy_1; + std::vector t_mapping; + copy_coord(posi_cpy_0, atype_cpy_0, t_mapping, ncell, ngcell, posi_0, atype, rc, region); + copy_coord(posi_cpy_1, atype_cpy_1, t_mapping, ncell, ngcell, posi_1, atype, rc, region); + EXPECT_EQ(atype_cpy_0, atype_cpy_1); + for (int jj = 0; jj < atype_cpy_0.size(); ++jj){ + EXPECT_EQ(atype_cpy_0[jj], atype_cpy_1[jj]); + } + std::vector> nlist_cpy_0, nlist_cpy_1, t_nlist; + build_nlist(nlist_cpy_0, t_nlist, posi_cpy_0, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + build_nlist(nlist_cpy_1, t_nlist, posi_cpy_1, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + std::vector ilist_0, jlist_0, jrange_0; + std::vector ilist_1, jlist_1, jrange_1; + int max_nnei_0 = make_inter_nlist(ilist_0, jrange_0, jlist_0, nloc, nlist_cpy_0); + int max_nnei_1 = make_inter_nlist(ilist_1, jrange_1, jlist_1, nloc, nlist_cpy_1); + EXPECT_EQ(max_nnei_0, max_nnei_1); + std::vector t_em(nloc * ndescrpt), t_em_deriv(nloc * ndescrpt * 3); + std::vector rij_0(nloc * nnei * 3), rij_1(nloc * nnei * 3); + std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); + std::vector avg(ntypes * ndescrpt, 0); + std::vector std(ntypes * ndescrpt, 1); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); + std::vector energy_0(nloc), energy_1(nloc); + std::vector t_force(nall * 3), t_virial(nall * 9); + pair_tab( + &energy_0[0], + &t_force[0], + &t_virial[0], + &tab_info[0], + &tab_data[0], + &rij_0[0], + &scale[0], + &atype_cpy_0[0], + &nlist_0[0], + &natoms[0], + sel_a, + sel_r); + pair_tab( + &energy_1[0], + &t_force[0], + &t_virial[0], + &tab_info[0], + &tab_data[0], + &rij_1[0], + &scale[0], + &atype_cpy_1[0], + &nlist_1[0], + &natoms[0], + sel_a, + sel_r); + double tot_e_0(0), tot_e_1(0); + for(int ii = 0; ii < nloc; ++ii){ + tot_e_0 += energy_0[ii]; + tot_e_1 += energy_1[ii]; + } + double num_deriv = - (tot_e_1 - tot_e_0) / (2. * hh); + double ana_deriv = force[ii*3+dd]; + EXPECT_LT(fabs(num_deriv - ana_deriv), 1e-8); + } + } +} + + +TEST_F(TestPairTab, cpu_f_num_deriv_scale) +{ + double new_scale = 0.3; + std::vector energy(nloc); + std::vector force(nall * 3); + std::vector virial(9, 0.); + std::vector atom_virial(nall * 9); + std::vector scale(nloc, new_scale); + pair_tab( + &energy[0], + &force[0], + &atom_virial[0], + &tab_info[0], + &tab_data[0], + &rij[0], + &scale[0], + &atype_cpy[0], + &nlist[0], + &natoms[0], + sel_a, + sel_r); + for (int ii = nloc; ii < nall; ++ii){ + for (int dd = 0; dd < 3; ++dd){ + int orig_idx = mapping[ii]; + force[orig_idx*3+dd] += force[ii*3+dd]; + } + } + for (int ii = 0; ii < nall; ++ii){ + for (int dd = 0; dd < 9; ++dd){ + virial[dd] += atom_virial[ii*9+dd]; + } + } + double hh = 1e-4; + for(int ii = 0; ii < nloc; ++ii){ + for(int dd = 0; dd < 3; ++dd){ + std::vector posi_0(posi); + std::vector posi_1(posi); + posi_0[ii*3+dd] -= hh; + posi_1[ii*3+dd] += hh; + std::vector posi_cpy_0, posi_cpy_1; + std::vector atype_cpy_0, atype_cpy_1; + std::vector t_mapping; + copy_coord(posi_cpy_0, atype_cpy_0, t_mapping, ncell, ngcell, posi_0, atype, rc, region); + copy_coord(posi_cpy_1, atype_cpy_1, t_mapping, ncell, ngcell, posi_1, atype, rc, region); + EXPECT_EQ(atype_cpy_0, atype_cpy_1); + for (int jj = 0; jj < atype_cpy_0.size(); ++jj){ + EXPECT_EQ(atype_cpy_0[jj], atype_cpy_1[jj]); + } + std::vector> nlist_cpy_0, nlist_cpy_1, t_nlist; + build_nlist(nlist_cpy_0, t_nlist, posi_cpy_0, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + build_nlist(nlist_cpy_1, t_nlist, posi_cpy_1, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + std::vector ilist_0, jlist_0, jrange_0; + std::vector ilist_1, jlist_1, jrange_1; + int max_nnei_0 = make_inter_nlist(ilist_0, jrange_0, jlist_0, nloc, nlist_cpy_0); + int max_nnei_1 = make_inter_nlist(ilist_1, jrange_1, jlist_1, nloc, nlist_cpy_1); + EXPECT_EQ(max_nnei_0, max_nnei_1); + std::vector t_em(nloc * ndescrpt), t_em_deriv(nloc * ndescrpt * 3); + std::vector rij_0(nloc * nnei * 3), rij_1(nloc * nnei * 3); + std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); + std::vector avg(ntypes * ndescrpt, 0); + std::vector std(ntypes * ndescrpt, 1); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); + std::vector energy_0(nloc), energy_1(nloc); + std::vector t_force(nall * 3), t_virial(nall * 9); + pair_tab( + &energy_0[0], + &t_force[0], + &t_virial[0], + &tab_info[0], + &tab_data[0], + &rij_0[0], + &scale[0], + &atype_cpy_0[0], + &nlist_0[0], + &natoms[0], + sel_a, + sel_r); + pair_tab( + &energy_1[0], + &t_force[0], + &t_virial[0], + &tab_info[0], + &tab_data[0], + &rij_1[0], + &scale[0], + &atype_cpy_1[0], + &nlist_1[0], + &natoms[0], + sel_a, + sel_r); + double tot_e_0(0), tot_e_1(0); + for(int ii = 0; ii < nloc; ++ii){ + tot_e_0 += energy_0[ii]; + tot_e_1 += energy_1[ii]; + } + double num_deriv = - (tot_e_1 - tot_e_0) / (2. * hh); + double ana_deriv = force[ii*3+dd]; + EXPECT_LT(fabs(new_scale * num_deriv - ana_deriv), 1e-8); + } + } +} + +TEST_F(TestPairTab, cpu_v_num_deriv) +{ + std::vector energy(nloc); + std::vector force(nall * 3); + std::vector virial(9, 0.); + std::vector atom_virial(nall * 9); + std::vector scale(nloc, 1.0); + pair_tab( + &energy[0], + &force[0], + &atom_virial[0], + &tab_info[0], + &tab_data[0], + &rij[0], + &scale[0], + &atype_cpy[0], + &nlist[0], + &natoms[0], + sel_a, + sel_r); + for (int ii = nloc; ii < nall; ++ii){ + for (int dd = 0; dd < 3; ++dd){ + int orig_idx = mapping[ii]; + force[orig_idx*3+dd] += force[ii*3+dd]; + } + } + for (int ii = 0; ii < nall; ++ii){ + for (int dd = 0; dd < 9; ++dd){ + virial[dd] += atom_virial[ii*9+dd]; + } + } + double hh = 1e-4; + std::vector num_deriv(9); + for(int dd0 = 0; dd0 < 3; ++dd0){ + for(int dd1 = 0; dd1 < 3; ++dd1){ + std::vector box_0(9); + std::vector box_1(9); + std::copy(box.begin(), box.end(), box_0.begin()); + std::copy(box.begin(), box.end(), box_1.begin()); + box_0[dd0*3+dd1] -= hh; + box_1[dd0*3+dd1] += hh; + SimulationRegion region_0, region_1; + region_0.reinitBox(&box_0[0]); + region_1.reinitBox(&box_1[0]); + std::vector posi_0(nloc * 3), posi_1(nloc * 3); + for(int jj = 0; jj < nloc; ++jj){ + double ci[3], co[3]; + region.phys2Inter(ci, &posi[jj*3]); + region_0.inter2Phys(co, ci); + std::copy(co, co+3, posi_0.begin() + jj*3); + region_1.inter2Phys(co, ci); + std::copy(co, co+3, posi_1.begin() + jj*3); + } + std::vector posi_cpy_0, posi_cpy_1; + std::vector atype_cpy_0, atype_cpy_1; + std::vector t_mapping; + copy_coord(posi_cpy_0, atype_cpy_0, t_mapping, ncell, ngcell, posi_0, atype, rc, region_0); + copy_coord(posi_cpy_1, atype_cpy_1, t_mapping, ncell, ngcell, posi_1, atype, rc, region_1); + EXPECT_EQ(atype_cpy_0, atype_cpy_1); + for (int jj = 0; jj < atype_cpy_0.size(); ++jj){ + EXPECT_EQ(atype_cpy_0[jj], atype_cpy_1[jj]); + } + std::vector> nlist_cpy_0, nlist_cpy_1, t_nlist; + build_nlist(nlist_cpy_0, t_nlist, posi_cpy_0, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region_0, ncell); + build_nlist(nlist_cpy_1, t_nlist, posi_cpy_1, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region_1, ncell); + std::vector ilist_0, jlist_0, jrange_0; + std::vector ilist_1, jlist_1, jrange_1; + int max_nnei_0 = make_inter_nlist(ilist_0, jrange_0, jlist_0, nloc, nlist_cpy_0); + int max_nnei_1 = make_inter_nlist(ilist_1, jrange_1, jlist_1, nloc, nlist_cpy_1); + EXPECT_EQ(max_nnei_0, max_nnei_1); + std::vector t_em(nloc * ndescrpt), t_em_deriv(nloc * ndescrpt * 3); + std::vector rij_0(nloc * nnei * 3), rij_1(nloc * nnei * 3); + std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); + std::vector avg(ntypes * ndescrpt, 0); + std::vector std(ntypes * ndescrpt, 1); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); + std::vector energy_0(nloc), energy_1(nloc); + std::vector t_force(nall * 3), t_virial(nall * 9); + pair_tab( + &energy_0[0], + &t_force[0], + &t_virial[0], + &tab_info[0], + &tab_data[0], + &rij_0[0], + &scale[0], + &atype_cpy_0[0], + &nlist_0[0], + &natoms[0], + sel_a, + sel_r); + pair_tab( + &energy_1[0], + &t_force[0], + &t_virial[0], + &tab_info[0], + &tab_data[0], + &rij_1[0], + &scale[0], + &atype_cpy_1[0], + &nlist_1[0], + &natoms[0], + sel_a, + sel_r); + double tot_e_0(0), tot_e_1(0); + for(int ii = 0; ii < nloc; ++ii){ + tot_e_0 += energy_0[ii]; + tot_e_1 += energy_1[ii]; + } + num_deriv[dd0*3+dd1] = - (tot_e_1 - tot_e_0) / (2. * hh); + // std::cout << num_deriv[dd0*3+dd1] << std::endl; + } + } + std::vector num_vir(9, 0); + for (int dd0 = 0; dd0 < 3; ++dd0){ + for (int dd1 = 0; dd1 < 3; ++dd1){ + num_vir[dd0*3+dd1] = 0; + for (int dd = 0; dd < 3; ++dd){ + num_vir[dd0*3+dd1] += num_deriv[dd*3+dd0] * box[dd*3+dd1]; + } + // std::cout << num_vir[dd0*3+dd1] << " " << virial[dd0*3+dd1] << std::endl; + EXPECT_LT(fabs(num_vir[dd0*3+dd1] - virial[dd0*3+dd1]), 1e-8); + } + } +} + +TEST_F(TestPairTab, cpu_v_num_deriv_scale) +{ + double new_scale = 0.3; + std::vector energy(nloc); + std::vector force(nall * 3); + std::vector virial(9, 0.); + std::vector atom_virial(nall * 9); + std::vector scale(nloc, new_scale); + pair_tab( + &energy[0], + &force[0], + &atom_virial[0], + &tab_info[0], + &tab_data[0], + &rij[0], + &scale[0], + &atype_cpy[0], + &nlist[0], + &natoms[0], + sel_a, + sel_r); + for (int ii = nloc; ii < nall; ++ii){ + for (int dd = 0; dd < 3; ++dd){ + int orig_idx = mapping[ii]; + force[orig_idx*3+dd] += force[ii*3+dd]; + } + } + for (int ii = 0; ii < nall; ++ii){ + for (int dd = 0; dd < 9; ++dd){ + virial[dd] += atom_virial[ii*9+dd]; + } + } + double hh = 1e-4; + std::vector num_deriv(9); + for(int dd0 = 0; dd0 < 3; ++dd0){ + for(int dd1 = 0; dd1 < 3; ++dd1){ + std::vector box_0(9); + std::vector box_1(9); + std::copy(box.begin(), box.end(), box_0.begin()); + std::copy(box.begin(), box.end(), box_1.begin()); + box_0[dd0*3+dd1] -= hh; + box_1[dd0*3+dd1] += hh; + SimulationRegion region_0, region_1; + region_0.reinitBox(&box_0[0]); + region_1.reinitBox(&box_1[0]); + std::vector posi_0(nloc * 3), posi_1(nloc * 3); + for(int jj = 0; jj < nloc; ++jj){ + double ci[3], co[3]; + region.phys2Inter(ci, &posi[jj*3]); + region_0.inter2Phys(co, ci); + std::copy(co, co+3, posi_0.begin() + jj*3); + region_1.inter2Phys(co, ci); + std::copy(co, co+3, posi_1.begin() + jj*3); + } + std::vector posi_cpy_0, posi_cpy_1; + std::vector atype_cpy_0, atype_cpy_1; + std::vector t_mapping; + copy_coord(posi_cpy_0, atype_cpy_0, t_mapping, ncell, ngcell, posi_0, atype, rc, region_0); + copy_coord(posi_cpy_1, atype_cpy_1, t_mapping, ncell, ngcell, posi_1, atype, rc, region_1); + EXPECT_EQ(atype_cpy_0, atype_cpy_1); + for (int jj = 0; jj < atype_cpy_0.size(); ++jj){ + EXPECT_EQ(atype_cpy_0[jj], atype_cpy_1[jj]); + } + std::vector> nlist_cpy_0, nlist_cpy_1, t_nlist; + build_nlist(nlist_cpy_0, t_nlist, posi_cpy_0, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region_0, ncell); + build_nlist(nlist_cpy_1, t_nlist, posi_cpy_1, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region_1, ncell); + std::vector ilist_0, jlist_0, jrange_0; + std::vector ilist_1, jlist_1, jrange_1; + int max_nnei_0 = make_inter_nlist(ilist_0, jrange_0, jlist_0, nloc, nlist_cpy_0); + int max_nnei_1 = make_inter_nlist(ilist_1, jrange_1, jlist_1, nloc, nlist_cpy_1); + EXPECT_EQ(max_nnei_0, max_nnei_1); + std::vector t_em(nloc * ndescrpt), t_em_deriv(nloc * ndescrpt * 3); + std::vector rij_0(nloc * nnei * 3), rij_1(nloc * nnei * 3); + std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); + std::vector avg(ntypes * ndescrpt, 0); + std::vector std(ntypes * ndescrpt, 1); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); + std::vector energy_0(nloc), energy_1(nloc); + std::vector t_force(nall * 3), t_virial(nall * 9); + pair_tab( + &energy_0[0], + &t_force[0], + &t_virial[0], + &tab_info[0], + &tab_data[0], + &rij_0[0], + &scale[0], + &atype_cpy_0[0], + &nlist_0[0], + &natoms[0], + sel_a, + sel_r); + pair_tab( + &energy_1[0], + &t_force[0], + &t_virial[0], + &tab_info[0], + &tab_data[0], + &rij_1[0], + &scale[0], + &atype_cpy_1[0], + &nlist_1[0], + &natoms[0], + sel_a, + sel_r); + double tot_e_0(0), tot_e_1(0); + for(int ii = 0; ii < nloc; ++ii){ + tot_e_0 += energy_0[ii]; + tot_e_1 += energy_1[ii]; + } + num_deriv[dd0*3+dd1] = - (tot_e_1 - tot_e_0) / (2. * hh); + // std::cout << num_deriv[dd0*3+dd1] << std::endl; + } + } + std::vector num_vir(9, 0); + for (int dd0 = 0; dd0 < 3; ++dd0){ + for (int dd1 = 0; dd1 < 3; ++dd1){ + num_vir[dd0*3+dd1] = 0; + for (int dd = 0; dd < 3; ++dd){ + num_vir[dd0*3+dd1] += num_deriv[dd*3+dd0] * box[dd*3+dd1]; + } + // std::cout << num_vir[dd0*3+dd1] << " " << virial[dd0*3+dd1] << std::endl; + EXPECT_LT(fabs(new_scale * num_vir[dd0*3+dd1] - virial[dd0*3+dd1]), 1e-8); + } + } +} + + +TEST_F(TestPairTabTriBox, cpu_v_num_deriv) +{ + std::vector energy(nloc); + std::vector force(nall * 3); + std::vector virial(9, 0.); + std::vector atom_virial(nall * 9); + std::vector scale(nloc, 1.0); + pair_tab( + &energy[0], + &force[0], + &atom_virial[0], + &tab_info[0], + &tab_data[0], + &rij[0], + &scale[0], + &atype_cpy[0], + &nlist[0], + &natoms[0], + sel_a, + sel_r); + for (int ii = nloc; ii < nall; ++ii){ + for (int dd = 0; dd < 3; ++dd){ + int orig_idx = mapping[ii]; + force[orig_idx*3+dd] += force[ii*3+dd]; + } + } + for (int ii = 0; ii < nall; ++ii){ + for (int dd = 0; dd < 9; ++dd){ + virial[dd] += atom_virial[ii*9+dd]; + } + } + double hh = 1e-4; + std::vector num_deriv(9); + for(int dd0 = 0; dd0 < 3; ++dd0){ + for(int dd1 = 0; dd1 < 3; ++dd1){ + std::vector box_0(9); + std::vector box_1(9); + std::copy(box.begin(), box.end(), box_0.begin()); + std::copy(box.begin(), box.end(), box_1.begin()); + box_0[dd0*3+dd1] -= hh; + box_1[dd0*3+dd1] += hh; + SimulationRegion region_0, region_1; + region_0.reinitBox(&box_0[0]); + region_1.reinitBox(&box_1[0]); + std::vector posi_0(nloc * 3), posi_1(nloc * 3); + for(int jj = 0; jj < nloc; ++jj){ + double ci[3], co[3]; + region.phys2Inter(ci, &posi[jj*3]); + region_0.inter2Phys(co, ci); + std::copy(co, co+3, posi_0.begin() + jj*3); + region_1.inter2Phys(co, ci); + std::copy(co, co+3, posi_1.begin() + jj*3); + } + std::vector posi_cpy_0, posi_cpy_1; + std::vector atype_cpy_0, atype_cpy_1; + std::vector t_mapping; + copy_coord(posi_cpy_0, atype_cpy_0, t_mapping, ncell, ngcell, posi_0, atype, rc, region_0); + copy_coord(posi_cpy_1, atype_cpy_1, t_mapping, ncell, ngcell, posi_1, atype, rc, region_1); + EXPECT_EQ(atype_cpy_0, atype_cpy_1); + for (int jj = 0; jj < atype_cpy_0.size(); ++jj){ + EXPECT_EQ(atype_cpy_0[jj], atype_cpy_1[jj]); + } + std::vector> nlist_cpy_0, nlist_cpy_1, t_nlist; + build_nlist(nlist_cpy_0, t_nlist, posi_cpy_0, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region_0, ncell); + build_nlist(nlist_cpy_1, t_nlist, posi_cpy_1, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region_1, ncell); + std::vector ilist_0, jlist_0, jrange_0; + std::vector ilist_1, jlist_1, jrange_1; + int max_nnei_0 = make_inter_nlist(ilist_0, jrange_0, jlist_0, nloc, nlist_cpy_0); + int max_nnei_1 = make_inter_nlist(ilist_1, jrange_1, jlist_1, nloc, nlist_cpy_1); + EXPECT_EQ(max_nnei_0, max_nnei_1); + std::vector t_em(nloc * ndescrpt), t_em_deriv(nloc * ndescrpt * 3); + std::vector rij_0(nloc * nnei * 3), rij_1(nloc * nnei * 3); + std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); + std::vector avg(ntypes * ndescrpt, 0); + std::vector std(ntypes * ndescrpt, 1); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); + std::vector energy_0(nloc), energy_1(nloc); + std::vector t_force(nall * 3), t_virial(nall * 9); + pair_tab( + &energy_0[0], + &t_force[0], + &t_virial[0], + &tab_info[0], + &tab_data[0], + &rij_0[0], + &scale[0], + &atype_cpy_0[0], + &nlist_0[0], + &natoms[0], + sel_a, + sel_r); + pair_tab( + &energy_1[0], + &t_force[0], + &t_virial[0], + &tab_info[0], + &tab_data[0], + &rij_1[0], + &scale[0], + &atype_cpy_1[0], + &nlist_1[0], + &natoms[0], + sel_a, + sel_r); + double tot_e_0(0), tot_e_1(0); + for(int ii = 0; ii < nloc; ++ii){ + tot_e_0 += energy_0[ii]; + tot_e_1 += energy_1[ii]; + } + num_deriv[dd0*3+dd1] = - (tot_e_1 - tot_e_0) / (2. * hh); + // std::cout << num_deriv[dd0*3+dd1] << std::endl; + } + } + std::vector num_vir(9, 0); + for (int dd0 = 0; dd0 < 3; ++dd0){ + for (int dd1 = 0; dd1 < 3; ++dd1){ + num_vir[dd0*3+dd1] = 0; + for (int dd = 0; dd < 3; ++dd){ + num_vir[dd0*3+dd1] += num_deriv[dd*3+dd0] * box[dd*3+dd1]; + } + // std::cout << num_vir[dd0*3+dd1] << " " << virial[dd0*3+dd1] << std::endl; + EXPECT_LT(fabs(num_vir[dd0*3+dd1] - virial[dd0*3+dd1]), 1e-8); + } + } +} diff --git a/source/op/pair_tab.cc b/source/op/pair_tab.cc index 0962596f42..caa69694ce 100644 --- a/source/op/pair_tab.cc +++ b/source/op/pair_tab.cc @@ -3,6 +3,8 @@ #include "tensorflow/core/framework/shape_inference.h" #include +#include "pair_tab.h" + using namespace tensorflow; //using namespace std; @@ -26,48 +28,6 @@ using namespace tensorflow; using CPUDevice = Eigen::ThreadPoolDevice; -inline -void tabulated_inter (double & ener, - double & fscale, - const double * table_info, - const double * table_data, - const double * dr) -{ - // info size: 3 - const double & rmin = table_info[0]; - const double & hh = table_info[1]; - const double hi = 1./hh; - const unsigned nspline = unsigned(table_info[2] + 0.1); - const unsigned ndata = nspline * 4; - - double r2 = dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2]; - double rr = sqrt(r2); - double uu = (rr - rmin) * hi; - // std::cout << rr << " " << rmin << " " << hh << " " << uu << std::endl; - if (uu < 0) { - std::cerr << "coord go beyond table lower boundary" << std::endl; - exit(1); - } - int idx = uu; - if (idx >= nspline) { - fscale = ener = 0; - return; - } - uu -= idx; - assert(idx >= 0); - assert(uu >= 0 && uu < 1); - - const double & a3 = table_data[4 * idx + 0]; - const double & a2 = table_data[4 * idx + 1]; - const double & a1 = table_data[4 * idx + 2]; - const double & a0 = table_data[4 * idx + 3]; - - double etmp = (a3 * uu + a2) * uu + a1; - ener = etmp * uu + a0; - fscale = (2. * a3 * uu + a2) * uu + etmp; - fscale *= -hi; -} - template class PairTabOp : public OpKernel { public: @@ -164,124 +124,29 @@ class PairTabOp : public OpKernel { const double * p_table_info = &(d_table_info[0]); const double * p_table_data = &(d_table_data[0]); + std::vector t_sel_a(sel_a.size()), t_sel_r(sel_r.size()); + for (int ii = 0; ii < sel_a.size(); ++ii){ + t_sel_a[ii] = sel_a[ii]; + } + for (int ii = 0; ii < sel_r.size(); ++ii){ + t_sel_r[ii] = sel_r[ii]; + } // loop over samples #pragma omp parallel for for (int kk = 0; kk < nframes; ++kk){ - // fill results with 0 - for (int ii = 0; ii < nloc; ++ii){ - int i_idx = ii; - energy(kk, i_idx) = 0; - } - for (int ii = 0; ii < nall; ++ii){ - int i_idx = ii; - force(kk, i_idx * 3 + 0) = 0; - force(kk, i_idx * 3 + 1) = 0; - force(kk, i_idx * 3 + 2) = 0; - for (int dd = 0; dd < 9; ++dd) { - virial(kk, i_idx * 9 + dd) = 0; - } - } - // compute force of a frame - int i_idx = 0; - for (int tt = 0; tt < ntypes; ++tt) { - for (int ii = 0; ii < natoms(2+tt); ++ii){ - int i_type = type(kk, i_idx); - FPTYPE i_scale = scale(kk, i_idx); - assert(i_type == tt) ; - int jiter = 0; - // a neighbor - for (int ss = 0; ss < sel_a.size(); ++ss){ - int j_type = ss; - const double * cur_table_data = - p_table_data + (i_type * ntypes + j_type) * tab_stride; - for (int jj = 0; jj < sel_a[ss]; ++jj){ - int j_idx = nlist(kk, i_idx * nnei + jiter); - if (j_idx < 0){ - jiter++; - continue; - } - assert(j_type == type(kk, j_idx)); - double dr[3]; - for (int dd = 0; dd < 3; ++dd){ - dr[dd] = rij(kk, (i_idx * nnei + jiter) * 3 + dd); - } - double r2 = dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2]; - double ri = 1./sqrt(r2); - double ener, fscale; - tabulated_inter(ener, - fscale, - p_table_info, - cur_table_data, - dr); - // printf("tabforce %d %d r: %12.8f ener: %12.8f %12.8f %8.5f fj: %8.5f %8.5f %8.5f dr: %9.6f %9.6f %9.6f\n", - // i_idx, j_idx, - // 1/ri, - // ener, fscale, i_scale, - // -fscale * dr[00] * ri * 0.5 * i_scale, -fscale * dr[01] * ri * 0.5 * i_scale, -fscale * dr[02] * ri * 0.5 * i_scale, - // dr[0], dr[1], dr[2] - // ); - energy(kk, i_idx) += 0.5 * ener; - for (int dd = 0; dd < 3; ++dd) { - force(kk, i_idx * 3 + dd) -= fscale * dr[dd] * ri * 0.5 * i_scale; - force(kk, j_idx * 3 + dd) += fscale * dr[dd] * ri * 0.5 * i_scale; - } - for (int dd0 = 0; dd0 < 3; ++dd0) { - for (int dd1 = 0; dd1 < 3; ++dd1) { - virial(kk, i_idx * 9 + dd0 * 3 + dd1) - += 0.5 * fscale * dr[dd0] * dr[dd1] * ri * 0.5 * i_scale; - virial(kk, j_idx * 9 + dd0 * 3 + dd1) - += 0.5 * fscale * dr[dd0] * dr[dd1] * ri * 0.5 * i_scale; - } - } - jiter++; - } - } - // r neighbor - for (int ss = 0; ss < sel_r.size(); ++ss){ - int j_type = ss; - const double * cur_table_data = - p_table_data + (i_type * ntypes + j_type) * tab_stride; - for (int jj = 0; jj < sel_r[ss]; ++jj){ - int j_idx = nlist(kk, i_idx * nnei + jiter); - if (j_idx < 0){ - jiter ++; - continue; - } - assert(j_type == type(kk, j_idx)); - double dr[3]; - for (int dd = 0; dd < 3; ++dd){ - dr[dd] = rij(kk, (i_idx * nnei + jiter) * 3 + dd); - } - double r2 = dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2]; - double ri = 1./sqrt(r2); - double ener, fscale; - tabulated_inter(ener, - fscale, - p_table_info, - cur_table_data, - dr); - // printf("tabforce %d %d %8.5f %12.8f %12.8f %8.5f fj: %8.5f %8.5f %8.5f\n", - // i_idx, j_idx, - // 1/ri, - // ener, fscale, i_scale, - // -fscale * dr[00] * ri * 0.5 * i_scale, -fscale * dr[01] * ri * 0.5 * i_scale, -fscale * dr[02] * ri * 0.5 * i_scale); - energy(kk, i_idx) += 0.5 * ener; - for (int dd = 0; dd < 3; ++dd) { - force(kk, i_idx * 3 + dd) -= fscale * dr[dd] * ri * 0.5 * i_scale; - force(kk, j_idx * 3 + dd) += fscale * dr[dd] * ri * 0.5 * i_scale; - } - for (int dd0 = 0; dd0 < 3; ++dd0) { - for (int dd1 = 0; dd1 < 3; ++dd1) { - virial(kk, j_idx * 9 + dd0 * 3 + dd1) - += fscale * dr[dd0] * dr[dd1] * ri * 0.5 * i_scale; - } - } - jiter++; - } - } - i_idx ++; - } - } + pair_tab( + &energy(kk,0), + &force(kk,0), + &virial(kk,0), + p_table_info, + p_table_data, + &rij(kk,0), + &scale(kk,0), + &type(kk,0), + &nlist(kk,0), + &natoms(0), + t_sel_a, + t_sel_r); } } private: From e43b7af732fe11fb5aa9dd39d2136f3d557501aa Mon Sep 17 00:00:00 2001 From: denghuilu Date: Sat, 13 Feb 2021 14:55:31 +0800 Subject: [PATCH 149/562] reuse function get_file_content --- source/lmp/pair_nnp.cpp | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/source/lmp/pair_nnp.cpp b/source/lmp/pair_nnp.cpp index fd18a63c71..8418992562 100644 --- a/source/lmp/pair_nnp.cpp +++ b/source/lmp/pair_nnp.cpp @@ -129,26 +129,9 @@ std::string PairNNP::get_file_content(const std::string & model) { } std::vector PairNNP::get_file_content(const std::vector & models) { - int myrank = 0, root = 0; - MPI_Comm_rank(MPI_COMM_WORLD, &myrank); - unsigned nchar = 0; std::vector file_contents(models.size()); for (unsigned ii = 0; ii < models.size(); ++ii) { - if (myrank == root) { - checkStatus (ReadFileToString(Env::Default(), models[ii], &file_contents[ii])); - nchar = file_contents[ii].size(); - } - MPI_Bcast(&nchar, 1, MPI_UNSIGNED, root, MPI_COMM_WORLD); - char * buff = (char *)malloc(sizeof(char) * nchar); - if (myrank == root) { - memcpy(buff, file_contents[ii].c_str(), sizeof(char) * nchar); - } - MPI_Bcast(buff, nchar, MPI_CHAR, root, MPI_COMM_WORLD); - file_contents[ii].resize(nchar); - for (unsigned jj = 0; jj < nchar; ++jj) { - file_contents[ii][jj] = buff[jj]; - } - free(buff); + file_contents[ii] = get_file_content(models[ii]); } return file_contents; } From e64847101c9d98ef360d4c95aa5899abe97d88c7 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Sat, 13 Feb 2021 17:31:19 +0800 Subject: [PATCH 150/562] fix bug of free memory --- source/lmp/pair_nnp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/lmp/pair_nnp.cpp b/source/lmp/pair_nnp.cpp index 8418992562..60fab41bff 100644 --- a/source/lmp/pair_nnp.cpp +++ b/source/lmp/pair_nnp.cpp @@ -124,8 +124,8 @@ std::string PairNNP::get_file_content(const std::string & model) { for (unsigned ii = 0; ii < nchar; ++ii) { file_content[ii] = buff[ii]; } - return file_content; free(buff); + return file_content; } std::vector PairNNP::get_file_content(const std::vector & models) { From 63f489e82b5fdbb4e384a7071c233ed30d51ebbf Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 13 Feb 2021 18:56:41 +0800 Subject: [PATCH 151/562] avoid copied code in pair_tab --- source/lib/src/pair_tab.cc | 177 +++++++++++++++++-------------------- 1 file changed, 82 insertions(+), 95 deletions(-) diff --git a/source/lib/src/pair_tab.cc b/source/lib/src/pair_tab.cc index 3e825133e9..beb8ff6293 100644 --- a/source/lib/src/pair_tab.cc +++ b/source/lib/src/pair_tab.cc @@ -52,17 +52,62 @@ void _pair_tab_jloop( FPTYPE * energy, FPTYPE * force, FPTYPE * virial, - const double * table_info, - const double * table_data, + int & jiter, + const int & i_idx, + const int & nnei, + const int & i_type_shift, + const double * p_table_info, + const double * p_table_data, + const int & tab_stride, const FPTYPE * rij, const FPTYPE * scale, const int * type, const int * nlist, const int * natoms, - const std::vector & sel_a, - const std::vector & sel_r + const std::vector & sel ) { + const FPTYPE i_scale = scale[i_idx]; + for (int ss = 0; ss < sel.size(); ++ss){ + int j_type = ss; + const double * cur_table_data = + p_table_data + (i_type_shift + j_type) * tab_stride; + for (int jj = 0; jj < sel[ss]; ++jj){ + int j_idx = nlist[i_idx * nnei + jiter]; + if (j_idx < 0){ + jiter++; + continue; + } + assert(j_type == type[j_idx]); + double dr[3]; + for (int dd = 0; dd < 3; ++dd){ + dr[dd] = rij[(i_idx * nnei + jiter) * 3 + dd]; + } + double r2 = dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2]; + double ri = 1./sqrt(r2); + double ener, fscale; + _pair_tabulated_inter( + ener, + fscale, + p_table_info, + cur_table_data, + dr); + energy[i_idx] += 0.5 * ener; + for (int dd = 0; dd < 3; ++dd) { + force[i_idx * 3 + dd] -= fscale * dr[dd] * ri * 0.5 * i_scale; + force[j_idx * 3 + dd] += fscale * dr[dd] * ri * 0.5 * i_scale; + } + for (int dd0 = 0; dd0 < 3; ++dd0) { + for (int dd1 = 0; dd1 < 3; ++dd1) { + virial[i_idx * 9 + dd0 * 3 + dd1] + += 0.5 * fscale * dr[dd0] * dr[dd1] * ri * 0.5 * i_scale; + virial[j_idx * 9 + dd0 * 3 + dd1] + += 0.5 * fscale * dr[dd0] * dr[dd1] * ri * 0.5 * i_scale; + } + } + jiter++; + } + } } inline void @@ -122,101 +167,43 @@ void pair_tab( for (int tt = 0; tt < ntypes; ++tt) { for (int ii = 0; ii < natoms[2+tt]; ++ii){ int i_type = type[i_idx]; - FPTYPE i_scale = scale[i_idx]; assert(i_type == tt) ; + const int i_type_shift = i_type * ntypes; int jiter = 0; // a neighbor - for (int ss = 0; ss < sel_a.size(); ++ss){ - int j_type = ss; - const double * cur_table_data = - p_table_data + (i_type * ntypes + j_type) * tab_stride; - for (int jj = 0; jj < sel_a[ss]; ++jj){ - int j_idx = nlist[i_idx * nnei + jiter]; - if (j_idx < 0){ - jiter++; - continue; - } - assert(j_type == type[j_idx]); - double dr[3]; - for (int dd = 0; dd < 3; ++dd){ - dr[dd] = rij[(i_idx * nnei + jiter) * 3 + dd]; - } - double r2 = dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2]; - double ri = 1./sqrt(r2); - double ener, fscale; - _pair_tabulated_inter( - ener, - fscale, - p_table_info, - cur_table_data, - dr); - // printf("tabforce %d %d r: %12.8f ener: %12.8f %12.8f %8.5f fj: %8.5f %8.5f %8.5f dr: %9.6f %9.6f %9.6f\n", - // i_idx, j_idx, - // 1/ri, - // ener, fscale, i_scale, - // -fscale * dr[00] * ri * 0.5 * i_scale, -fscale * dr[01] * ri * 0.5 * i_scale, -fscale * dr[02] * ri * 0.5 * i_scale, - // dr[0], dr[1], dr[2] - // ); - energy[i_idx] += 0.5 * ener; - for (int dd = 0; dd < 3; ++dd) { - force[i_idx * 3 + dd] -= fscale * dr[dd] * ri * 0.5 * i_scale; - force[j_idx * 3 + dd] += fscale * dr[dd] * ri * 0.5 * i_scale; - } - for (int dd0 = 0; dd0 < 3; ++dd0) { - for (int dd1 = 0; dd1 < 3; ++dd1) { - virial[i_idx * 9 + dd0 * 3 + dd1] - += 0.5 * fscale * dr[dd0] * dr[dd1] * ri * 0.5 * i_scale; - virial[j_idx * 9 + dd0 * 3 + dd1] - += 0.5 * fscale * dr[dd0] * dr[dd1] * ri * 0.5 * i_scale; - } - } - jiter++; - } - } + _pair_tab_jloop(energy, + force, + virial, + jiter, + i_idx, + nnei, + i_type_shift, + p_table_info, + p_table_data, + tab_stride, + rij, + scale, + type, + nlist, + natoms, + sel_a); // r neighbor - for (int ss = 0; ss < sel_r.size(); ++ss){ - int j_type = ss; - const double * cur_table_data = - p_table_data + (i_type * ntypes + j_type) * tab_stride; - for (int jj = 0; jj < sel_r[ss]; ++jj){ - int j_idx = nlist[i_idx * nnei + jiter]; - if (j_idx < 0){ - jiter ++; - continue; - } - assert(j_type == type[j_idx]); - double dr[3]; - for (int dd = 0; dd < 3; ++dd){ - dr[dd] = rij[(i_idx * nnei + jiter) * 3 + dd]; - } - double r2 = dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2]; - double ri = 1./sqrt(r2); - double ener, fscale; - _pair_tabulated_inter( - ener, - fscale, - p_table_info, - cur_table_data, - dr); - // printf("tabforce %d %d %8.5f %12.8f %12.8f %8.5f fj: %8.5f %8.5f %8.5f\n", - // i_idx, j_idx, - // 1/ri, - // ener, fscale, i_scale, - // -fscale * dr[00] * ri * 0.5 * i_scale, -fscale * dr[01] * ri * 0.5 * i_scale, -fscale * dr[02] * ri * 0.5 * i_scale); - energy[i_idx] += 0.5 * ener; - for (int dd = 0; dd < 3; ++dd) { - force[i_idx * 3 + dd] -= fscale * dr[dd] * ri * 0.5 * i_scale; - force[j_idx * 3 + dd] += fscale * dr[dd] * ri * 0.5 * i_scale; - } - for (int dd0 = 0; dd0 < 3; ++dd0) { - for (int dd1 = 0; dd1 < 3; ++dd1) { - virial[j_idx * 9 + dd0 * 3 + dd1] - += fscale * dr[dd0] * dr[dd1] * ri * 0.5 * i_scale; - } - } - jiter++; - } - } + _pair_tab_jloop(energy, + force, + virial, + jiter, + i_idx, + nnei, + i_type_shift, + p_table_info, + p_table_data, + tab_stride, + rij, + scale, + type, + nlist, + natoms, + sel_r); i_idx ++; } } From 79fb40be02ec6254860bdfdb4f13fa0bf6155ce7 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Sat, 13 Feb 2021 19:55:05 +0800 Subject: [PATCH 152/562] fix bug of lammps make serial error MPI_UNSIGNED was not recognized by lammps make serial compiler command --- source/lmp/pair_nnp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/lmp/pair_nnp.cpp b/source/lmp/pair_nnp.cpp index 60fab41bff..fd2adb2729 100644 --- a/source/lmp/pair_nnp.cpp +++ b/source/lmp/pair_nnp.cpp @@ -108,13 +108,13 @@ int PairNNP::get_node_rank() { std::string PairNNP::get_file_content(const std::string & model) { int myrank = 0, root = 0; MPI_Comm_rank(MPI_COMM_WORLD, &myrank); - unsigned nchar = 0; + int nchar = 0; std::string file_content; if (myrank == root) { checkStatus (ReadFileToString(Env::Default(), model, &file_content)); nchar = file_content.size(); } - MPI_Bcast(&nchar, 1, MPI_UNSIGNED, root, MPI_COMM_WORLD); + MPI_Bcast(&nchar, 1, MPI_INT, root, MPI_COMM_WORLD); char * buff = (char *)malloc(sizeof(char) * nchar); if (myrank == root) { memcpy(buff, file_content.c_str(), sizeof(char) * nchar); From d9147049dfb1fecce9279a996a4cdf92092956ce Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 13 Feb 2021 20:19:48 +0800 Subject: [PATCH 153/562] change name pair_tab -> pair_tab_cpu --- source/lib/include/pair_tab.h | 2 +- source/lib/src/pair_tab.cc | 6 +++--- source/lib/tests/test_pair_tab.cc | 32 +++++++++++++++---------------- source/op/pair_tab.cc | 2 +- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/source/lib/include/pair_tab.h b/source/lib/include/pair_tab.h index 3437139e2e..9176b43c0c 100644 --- a/source/lib/include/pair_tab.h +++ b/source/lib/include/pair_tab.h @@ -1,7 +1,7 @@ #pragma once template -void pair_tab( +void pair_tab_cpu( FPTYPE * energy, FPTYPE * force, FPTYPE * virial, diff --git a/source/lib/src/pair_tab.cc b/source/lib/src/pair_tab.cc index beb8ff6293..d0a435b1b1 100644 --- a/source/lib/src/pair_tab.cc +++ b/source/lib/src/pair_tab.cc @@ -122,7 +122,7 @@ _cum_sum ( } template -void pair_tab( +void pair_tab_cpu( FPTYPE * energy, FPTYPE * force, FPTYPE * virial, @@ -211,7 +211,7 @@ void pair_tab( template -void pair_tab( +void pair_tab_cpu( float * energy, float * force, float * virial, @@ -227,7 +227,7 @@ void pair_tab( ); template -void pair_tab( +void pair_tab_cpu( double * energy, double * force, double * virial, diff --git a/source/lib/tests/test_pair_tab.cc b/source/lib/tests/test_pair_tab.cc index 424f5571c2..97a87120e3 100644 --- a/source/lib/tests/test_pair_tab.cc +++ b/source/lib/tests/test_pair_tab.cc @@ -134,7 +134,7 @@ TEST_F(TestPairTab, cpu) std::vector virial(nall * 9); std::vector scale(nloc, 1.0); - pair_tab( + pair_tab_cpu( &energy[0], &force[0], &virial[0], @@ -197,7 +197,7 @@ TEST_F(TestPairTab, cpu_f_num_deriv) std::vector virial(9, 0.); std::vector atom_virial(nall * 9); std::vector scale(nloc, 1.0); - pair_tab( + pair_tab_cpu( &energy[0], &force[0], &atom_virial[0], @@ -254,7 +254,7 @@ TEST_F(TestPairTab, cpu_f_num_deriv) prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); - pair_tab( + pair_tab_cpu( &energy_0[0], &t_force[0], &t_virial[0], @@ -267,7 +267,7 @@ TEST_F(TestPairTab, cpu_f_num_deriv) &natoms[0], sel_a, sel_r); - pair_tab( + pair_tab_cpu( &energy_1[0], &t_force[0], &t_virial[0], @@ -301,7 +301,7 @@ TEST_F(TestPairTab, cpu_f_num_deriv_scale) std::vector virial(9, 0.); std::vector atom_virial(nall * 9); std::vector scale(nloc, new_scale); - pair_tab( + pair_tab_cpu( &energy[0], &force[0], &atom_virial[0], @@ -358,7 +358,7 @@ TEST_F(TestPairTab, cpu_f_num_deriv_scale) prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); - pair_tab( + pair_tab_cpu( &energy_0[0], &t_force[0], &t_virial[0], @@ -371,7 +371,7 @@ TEST_F(TestPairTab, cpu_f_num_deriv_scale) &natoms[0], sel_a, sel_r); - pair_tab( + pair_tab_cpu( &energy_1[0], &t_force[0], &t_virial[0], @@ -403,7 +403,7 @@ TEST_F(TestPairTab, cpu_v_num_deriv) std::vector virial(9, 0.); std::vector atom_virial(nall * 9); std::vector scale(nloc, 1.0); - pair_tab( + pair_tab_cpu( &energy[0], &force[0], &atom_virial[0], @@ -475,7 +475,7 @@ TEST_F(TestPairTab, cpu_v_num_deriv) prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); - pair_tab( + pair_tab_cpu( &energy_0[0], &t_force[0], &t_virial[0], @@ -488,7 +488,7 @@ TEST_F(TestPairTab, cpu_v_num_deriv) &natoms[0], sel_a, sel_r); - pair_tab( + pair_tab_cpu( &energy_1[0], &t_force[0], &t_virial[0], @@ -531,7 +531,7 @@ TEST_F(TestPairTab, cpu_v_num_deriv_scale) std::vector virial(9, 0.); std::vector atom_virial(nall * 9); std::vector scale(nloc, new_scale); - pair_tab( + pair_tab_cpu( &energy[0], &force[0], &atom_virial[0], @@ -603,7 +603,7 @@ TEST_F(TestPairTab, cpu_v_num_deriv_scale) prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); - pair_tab( + pair_tab_cpu( &energy_0[0], &t_force[0], &t_virial[0], @@ -616,7 +616,7 @@ TEST_F(TestPairTab, cpu_v_num_deriv_scale) &natoms[0], sel_a, sel_r); - pair_tab( + pair_tab_cpu( &energy_1[0], &t_force[0], &t_virial[0], @@ -659,7 +659,7 @@ TEST_F(TestPairTabTriBox, cpu_v_num_deriv) std::vector virial(9, 0.); std::vector atom_virial(nall * 9); std::vector scale(nloc, 1.0); - pair_tab( + pair_tab_cpu( &energy[0], &force[0], &atom_virial[0], @@ -731,7 +731,7 @@ TEST_F(TestPairTabTriBox, cpu_v_num_deriv) prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); - pair_tab( + pair_tab_cpu( &energy_0[0], &t_force[0], &t_virial[0], @@ -744,7 +744,7 @@ TEST_F(TestPairTabTriBox, cpu_v_num_deriv) &natoms[0], sel_a, sel_r); - pair_tab( + pair_tab_cpu( &energy_1[0], &t_force[0], &t_virial[0], diff --git a/source/op/pair_tab.cc b/source/op/pair_tab.cc index caa69694ce..0bfac34de1 100644 --- a/source/op/pair_tab.cc +++ b/source/op/pair_tab.cc @@ -134,7 +134,7 @@ class PairTabOp : public OpKernel { // loop over samples #pragma omp parallel for for (int kk = 0; kk < nframes; ++kk){ - pair_tab( + pair_tab_cpu( &energy(kk,0), &force(kk,0), &virial(kk,0), From 92a4ed9683bf584e756e0cadb439471d6af30fe4 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 13 Feb 2021 20:20:41 +0800 Subject: [PATCH 154/562] refact map_aparam --- source/lib/include/map_aparam.h | 12 ++++ source/lib/src/map_aparam.cc | 59 +++++++++++++++++++ source/lib/tests/test_map_aparam.cc | 88 +++++++++++++++++++++++++++++ source/op/map_aparam.cc | 28 +++------ 4 files changed, 166 insertions(+), 21 deletions(-) create mode 100644 source/lib/include/map_aparam.h create mode 100644 source/lib/src/map_aparam.cc create mode 100644 source/lib/tests/test_map_aparam.cc diff --git a/source/lib/include/map_aparam.h b/source/lib/include/map_aparam.h new file mode 100644 index 0000000000..b209d8314a --- /dev/null +++ b/source/lib/include/map_aparam.h @@ -0,0 +1,12 @@ +#pragma once + +template +void map_aparam_cpu ( + FPTYPE * output, + const FPTYPE * aparam, + const int * nlist, + const int & nloc, + const int & nnei, + const int & numb_aparam + ); + diff --git a/source/lib/src/map_aparam.cc b/source/lib/src/map_aparam.cc new file mode 100644 index 0000000000..b7e9973d5f --- /dev/null +++ b/source/lib/src/map_aparam.cc @@ -0,0 +1,59 @@ +#include "map_aparam.h" + +template +void map_aparam_cpu ( + FPTYPE * output, + const FPTYPE * aparam, + const int * nlist, + const int & nloc, + const int & nnei, + const int & numb_aparam + ) +// +// output: nloc x nnei x numb_aparam +// aparam: nall x numb_aparam +// nlist: nloc x nnei +// +{ + for (int ii = 0; ii < nloc; ++ii){ + int i_idx = ii; + for (int dd = 0; dd < nnei * numb_aparam; ++dd) { + output[i_idx * nnei * numb_aparam + dd] = 0.; + } + } + + // loop over loc atoms + for (int ii = 0; ii < nloc; ++ii){ + int i_idx = ii; + // loop over neighbor atoms + for (int jj = 0; jj < nnei; ++jj){ + int j_idx = nlist[i_idx * nnei + jj]; + if (j_idx < 0) continue; + // loop over elements of aparam + for (int dd = 0; dd < numb_aparam; ++dd){ + output[ii * nnei * numb_aparam + jj * numb_aparam + dd] = aparam[j_idx * numb_aparam + dd]; + } + } + } +} + +template +void map_aparam_cpu ( + double * output, + const double * aparam, + const int * nlist, + const int & nloc, + const int & nnei, + const int & numb_aparam + ); + +template +void map_aparam_cpu ( + float * output, + const float * aparam, + const int * nlist, + const int & nloc, + const int & nnei, + const int & numb_aparam + ); + diff --git a/source/lib/tests/test_map_aparam.cc b/source/lib/tests/test_map_aparam.cc new file mode 100644 index 0000000000..3bee6d4f63 --- /dev/null +++ b/source/lib/tests/test_map_aparam.cc @@ -0,0 +1,88 @@ +#include +#include +#include "fmt_nlist.h" +#include "neighbor_list.h" +#include "map_aparam.h" + +class TestMapAparam : public ::testing::Test +{ +protected: + std::vector posi = {12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall, nnei, ndescrpt; + int numb_aparam = 2; + double rc = 6; + double rc_smth = 0.8; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sec_a = {0, 5, 10}; + std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector> nlist_a_cpy, nlist_r_cpy; + std::vector nlist; + std::vector fmt_nlist_a; + std::vector aparam; + std::vector expected_output = { + 3.40000, 3.30000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 9.80000, 9.70000, 3.60000, 3.50000, 3.20000, 3.10000, 3.00000, 2.90000, 0.00000, 0.00000, 10.00000, 9.90000, 3.40000, 3.30000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 3.60000, 3.50000, 3.20000, 3.10000, 3.00000, 2.90000, 0.00000, 0.00000, 0.00000, 0.00000, 8.80000, 8.70000, 9.40000, 9.30000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 8.60000, 8.50000, 9.20000, 9.10000, 9.00000, 8.90000, 0.00000, 0.00000, 0.00000, 0.00000, 8.80000, 8.70000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 9.20000, 9.10000, 9.00000, 8.90000, 9.60000, 9.50000, 8.60000, 8.50000, 0.00000, 0.00000, 9.40000, 9.30000, 8.80000, 8.70000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 9.00000, 8.90000, 9.60000, 9.50000, 8.60000, 8.50000, 0.00000, 0.00000, 0.00000, 0.00000, 9.40000, 9.30000, 8.80000, 8.70000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 9.20000, 9.10000, 9.60000, 9.50000, 8.60000, 8.50000, 0.00000, 0.00000, 0.00000, 0.00000, + }; + + void SetUp() override { + double box[] = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + region.reinitBox(box); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nnei = sec_a.back(); + ndescrpt = nnei * 4; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + build_nlist(nlist_a_cpy, nlist_r_cpy, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + nlist.resize(nloc * nnei); + for(int ii = 0; ii < nloc; ++ii){ + // format nlist and record + format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + for (int jj = 0; jj < nnei; ++jj){ + nlist[ii*nnei + jj] = fmt_nlist_a[jj]; + } + } + aparam.resize(nall * numb_aparam); + for(int ii = 0; ii < nall * numb_aparam; ++ii){ + aparam[ii] = 10 - 0.1 * ii; + } + } + void TearDown() override { + } +}; + +TEST_F(TestMapAparam, cpu) +{ + std::vector output(nloc * nnei * numb_aparam); + map_aparam_cpu( + &output[0], + &aparam[0], + &nlist[0], + nloc, + nnei, + numb_aparam); + for (int jj = 0; jj < nloc * nnei * numb_aparam; ++jj){ + EXPECT_LT(fabs(output[jj] - expected_output[jj]), 1e-10); + } + // for (int jj = 0; jj < nloc * nnei * numb_aparam; ++jj){ + // printf("%8.5f, ", output[jj]); + // } + // printf("\n"); +} diff --git a/source/op/map_aparam.cc b/source/op/map_aparam.cc index 608f5f614b..05297c2118 100644 --- a/source/op/map_aparam.cc +++ b/source/op/map_aparam.cc @@ -70,27 +70,13 @@ class MapAparamOp : public OpKernel { int output_iter = kk * nloc * nnei * numb_aparam; int aparam_iter = kk * nall * numb_aparam; int nlist_iter = kk * nloc * nnei; - - for (int ii = 0; ii < nloc; ++ii){ - int i_idx = ii; - for (int dd = 0; dd < nnei * numb_aparam; ++dd) { - output(output_iter + i_idx * nnei * numb_aparam + dd) = 0.; - } - } - - // loop over loc atoms - for (int ii = 0; ii < nloc; ++ii){ - int i_idx = ii; - // loop over neighbor atoms - for (int jj = 0; jj < nnei; ++jj){ - int j_idx = nlist (nlist_iter + i_idx * nnei + jj); - if (j_idx < 0) continue; - // loop over elements of aparam - for (int dd = 0; dd < numb_aparam; ++dd){ - output(output_iter + ii * nnei * numb_aparam + jj * numb_aparam + dd) = aparam(aparam_iter + j_idx * numb_aparam + dd); - } - } - } + map_aparam_cpu( + &ouput(output_iter), + &aparam(aparam_iter), + &nlist(nlist_iter), + nloc, + nnei, + numb_aparam); } } private: From fccd35ee6f220cd7ebd26641da6aa22b647a879f Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 13 Feb 2021 22:10:09 +0800 Subject: [PATCH 155/562] fix bug: missing include file --- source/op/map_aparam.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/op/map_aparam.cc b/source/op/map_aparam.cc index 05297c2118..06f4c5dfeb 100644 --- a/source/op/map_aparam.cc +++ b/source/op/map_aparam.cc @@ -3,6 +3,8 @@ #include "tensorflow/core/framework/shape_inference.h" #include +#include "map_aparam.h" + using namespace tensorflow; // using namespace std; From 9757a56c30c7406a7293471327a7edd408ae4651 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 13 Feb 2021 22:20:57 +0800 Subject: [PATCH 156/562] fix bug typo of variable name --- source/op/map_aparam.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/op/map_aparam.cc b/source/op/map_aparam.cc index 06f4c5dfeb..cd6543c401 100644 --- a/source/op/map_aparam.cc +++ b/source/op/map_aparam.cc @@ -73,7 +73,7 @@ class MapAparamOp : public OpKernel { int aparam_iter = kk * nall * numb_aparam; int nlist_iter = kk * nloc * nnei; map_aparam_cpu( - &ouput(output_iter), + &output(output_iter), &aparam(aparam_iter), &nlist(nlist_iter), nloc, From d529ff667a923803c33e7c3c0d3a018b69ee46d6 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 13 Feb 2021 22:22:56 +0800 Subject: [PATCH 157/562] refact prod_force_grad_se_r_grad and prod_virial_se_r_grad --- source/lib/include/prod_force_grad.h | 9 ++ source/lib/include/prod_virial_grad.h | 10 ++ source/lib/src/prod_force_grad.cc | 69 +++++++++++++ source/lib/src/prod_virial_grad.cc | 67 +++++++++++++ source/lib/tests/test_prod_force_grad_r.cc | 97 +++++++++++++++++++ source/lib/tests/test_prod_virial_grad_r.cc | 101 ++++++++++++++++++++ source/op/prod_force_se_r_grad.cc | 40 ++------ source/op/prod_virial_se_r_grad.cc | 34 ++----- 8 files changed, 373 insertions(+), 54 deletions(-) create mode 100644 source/lib/tests/test_prod_force_grad_r.cc create mode 100644 source/lib/tests/test_prod_virial_grad_r.cc diff --git a/source/lib/include/prod_force_grad.h b/source/lib/include/prod_force_grad.h index 6c1f9978c2..d191fe76fa 100644 --- a/source/lib/include/prod_force_grad.h +++ b/source/lib/include/prod_force_grad.h @@ -9,3 +9,12 @@ void prod_force_grad_a_cpu( const int nloc, const int nnei); +template +void prod_force_grad_r_cpu( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const int * nlist, + const int nloc, + const int nnei); + diff --git a/source/lib/include/prod_virial_grad.h b/source/lib/include/prod_virial_grad.h index 5294b60dc3..2ba8c01a44 100644 --- a/source/lib/include/prod_virial_grad.h +++ b/source/lib/include/prod_virial_grad.h @@ -10,3 +10,13 @@ void prod_virial_grad_a_cpu( const int nloc, const int nnei); +template +void prod_virial_grad_r_cpu( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nnei); + diff --git a/source/lib/src/prod_force_grad.cc b/source/lib/src/prod_force_grad.cc index 8ff8c5f8b4..49c510c8b5 100644 --- a/source/lib/src/prod_force_grad.cc +++ b/source/lib/src/prod_force_grad.cc @@ -84,3 +84,72 @@ void prod_force_grad_a_cpu( const int nloc, const int nnei) ; + + +template +void prod_force_grad_r_cpu( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const int * nlist, + const int nloc, + const int nnei) +// +// grad_net: nloc x ndescrpt +// grad: nloc x 3 +// env_deriv: nloc x ndescrpt x 3 +// nlist: nloc x nnei +// +{ + const int ndescrpt = nnei * 1; + + // reset the frame to 0 + for (int ii = 0; ii < nloc; ++ii){ + for (int aa = 0; aa < ndescrpt; ++aa){ + grad_net[ii * ndescrpt + aa] = 0; + } + } + + // compute grad of one frame + for (int ii = 0; ii < nloc; ++ii){ + int i_idx = ii; + + // deriv wrt center atom + for (int aa = 0; aa < ndescrpt; ++aa){ + for (int dd = 0; dd < 3; ++dd){ + grad_net[i_idx * ndescrpt + aa] -= grad[i_idx * 3 + dd] * env_deriv[i_idx * ndescrpt * 3 + aa * 3 + dd]; + } + } + + // loop over neighbors + for (int jj = 0; jj < nnei; ++jj){ + int j_idx = nlist[i_idx * nnei + jj]; + if (j_idx >= nloc) j_idx = j_idx % nloc; + if (j_idx < 0) continue; + for (int dd = 0; dd < 3; ++dd){ + grad_net[i_idx * ndescrpt + jj] += grad[j_idx * 3 + dd] * env_deriv[i_idx * ndescrpt * 3 + jj * 3 + dd]; + } + } + } +} + +template +void prod_force_grad_r_cpu( + double * grad_net, + const double * grad, + const double * env_deriv, + const int * nlist, + const int nloc, + const int nnei) ; + +template +void prod_force_grad_r_cpu( + float * grad_net, + const float * grad, + const float * env_deriv, + const int * nlist, + const int nloc, + const int nnei) ; + + + diff --git a/source/lib/src/prod_virial_grad.cc b/source/lib/src/prod_virial_grad.cc index 2c14bdc85f..3a53692417 100644 --- a/source/lib/src/prod_virial_grad.cc +++ b/source/lib/src/prod_virial_grad.cc @@ -79,3 +79,70 @@ void prod_virial_grad_a_cpu( const int * nlist, const int nloc, const int nnei); + + +template +void prod_virial_grad_r_cpu( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nnei) +// +// grad_net: nloc x ndescrpt +// grad: 9 +// env_deriv: nloc x ndescrpt x 3 +// rij: nloc x nnei x 3 +// nlist: nloc x nnei +// +{ + const int ndescrpt = nnei * 1; + + // reset the frame to 0 + for (int ii = 0; ii < nloc; ++ii){ + for (int aa = 0; aa < ndescrpt; ++aa){ + grad_net[ii * ndescrpt + aa] = 0; + } + } + + // compute grad of one frame + for (int ii = 0; ii < nloc; ++ii){ + int i_idx = ii; + + // loop over neighbors + for (int jj = 0; jj < nnei; ++jj){ + int j_idx = nlist[i_idx * nnei + jj]; + if (j_idx < 0) continue; + for (int dd0 = 0; dd0 < 3; ++dd0){ + for (int dd1 = 0; dd1 < 3; ++dd1){ + grad_net[i_idx * ndescrpt + jj] -= + -1.0 * grad[dd0 * 3 + dd1] * rij[i_idx * nnei * 3 + jj * 3 + dd1] * env_deriv[i_idx * ndescrpt * 3 + jj * 3 + dd0]; + } + } + } + } +} + + +template +void prod_virial_grad_r_cpu( + double * grad_net, + const double * grad, + const double * env_deriv, + const double * rij, + const int * nlist, + const int nloc, + const int nnei); + +template +void prod_virial_grad_r_cpu( + float * grad_net, + const float * grad, + const float * env_deriv, + const float * rij, + const int * nlist, + const int nloc, + const int nnei); + diff --git a/source/lib/tests/test_prod_force_grad_r.cc b/source/lib/tests/test_prod_force_grad_r.cc new file mode 100644 index 0000000000..80a5978c0c --- /dev/null +++ b/source/lib/tests/test_prod_force_grad_r.cc @@ -0,0 +1,97 @@ +#include +#include +#include "fmt_nlist.h" +#include "env_mat.h" +#include "neighbor_list.h" +#include "prod_force_grad.h" + +class TestProdForceGradR : public ::testing::Test +{ +protected: + std::vector posi = {12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall, nnei, ndescrpt; + double rc = 6; + double rc_smth = 0.8; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sec_a = {0, 5, 10}; + std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector> nlist_a_cpy, nlist_r_cpy; + std::vector grad; + std::vector env, env_deriv, rij_a; + std::vector nlist; + std::vector fmt_nlist_a; + std::vector expected_grad_net = { + -0.12141, -1.33062, 0.12948, 0.50970, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.04188, 0.75283, 9.26593, 8.54987, -0.54546, -0.01575, 0.00681, 0.02755, 0.00000, 0.00000, -0.40861, 0.12805, -0.45057, 15.54539, -1.52411, 0.04701, 0.05002, 0.04668, 0.00000, 0.00000, -0.12141, -1.21099, 0.11750, 0.46323, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.16227, -1.14667, 14.61804, 1.94488, 1.18285, -0.04089, -0.01845, -0.00874, 0.00000, 0.00000, -0.58330, 1.13439, 5.18696, 13.10426, 0.49773, 0.01712, 0.00239, -0.01893, 0.00000, 0.00000, + }; + + void SetUp() override { + double box[] = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + region.reinitBox(box); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nnei = sec_a.back(); + ndescrpt = nnei * 1; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + build_nlist(nlist_a_cpy, nlist_r_cpy, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + nlist.resize(nloc * nnei); + env.resize(nloc * ndescrpt); + env_deriv.resize(nloc * ndescrpt * 3); + rij_a.resize(nloc * nnei * 3); + for(int ii = 0; ii < nloc; ++ii){ + // format nlist and record + format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + for (int jj = 0; jj < nnei; ++jj){ + nlist[ii*nnei + jj] = fmt_nlist_a[jj]; + } + std::vector t_env, t_env_deriv, t_rij_a; + // compute env_mat and its deriv, record + env_mat_a_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < ndescrpt; ++jj){ + env[ii*ndescrpt+jj] = t_env[jj]; + for (int dd = 0; dd < 3; ++dd){ + env_deriv[ii*ndescrpt*3+jj*3+dd] = t_env_deriv[jj*3+dd]; + } + } + } + grad.resize(nloc * 3); + for (int ii = 0; ii < nloc * 3; ++ii){ + grad[ii] = 10 - ii * 0.1; + } + } + void TearDown() override { + } +}; + +TEST_F(TestProdForceGradR, cpu) +{ + std::vector grad_net(nloc * ndescrpt); + prod_force_grad_r_cpu(&grad_net[0], &grad[0], &env_deriv[0], &nlist[0], nloc, nnei); + EXPECT_EQ(grad_net.size(), nloc * ndescrpt); + EXPECT_EQ(grad_net.size(), expected_grad_net.size()); + for (int jj = 0; jj < grad_net.size(); ++jj){ + EXPECT_LT(fabs(grad_net[jj] - expected_grad_net[jj]) , 1e-5); + } + // for (int jj = 0; jj < nloc * ndescrpt; ++jj){ + // printf("%8.5f, ", grad_net[jj]); + // } + // printf("\n"); +} diff --git a/source/lib/tests/test_prod_virial_grad_r.cc b/source/lib/tests/test_prod_virial_grad_r.cc new file mode 100644 index 0000000000..5951b634d8 --- /dev/null +++ b/source/lib/tests/test_prod_virial_grad_r.cc @@ -0,0 +1,101 @@ +#include +#include +#include "fmt_nlist.h" +#include "env_mat.h" +#include "neighbor_list.h" +#include "prod_virial_grad.h" + +class TestProdVirialGradR : public ::testing::Test +{ +protected: + std::vector posi = {12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall, nnei, ndescrpt; + double rc = 6; + double rc_smth = 0.8; + SimulationRegion region; + std::vector mapping, ncell, ngcell; + std::vector sec_a = {0, 5, 10}; + std::vector sec_r = {0, 0, 0}; + std::vector nat_stt, ext_stt, ext_end; + std::vector> nlist_a_cpy, nlist_r_cpy; + std::vector grad; + std::vector env, env_deriv, rij; + std::vector nlist; + std::vector fmt_nlist_a; + std::vector expected_grad_net = { + 5.01828, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.61704, -21.60321, 0.00000, 0.00000, 0.00000, 0.42750, -0.17937, -0.88567, 0.00000, 0.00000, 5.28467, -10.73121, 0.00000, 0.00000, 0.00000, -1.13085, -2.11178, -0.59649, 0.00000, 0.00000, 5.01828, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.07573, 43.00720, 0.00000, 0.00000, 0.00000, 0.73130, 0.71210, -0.24082, 0.00000, 0.00000, 9.64382, -42.10583, 0.00000, 0.00000, 0.00000, -0.33429, -0.19384, 0.55423, 0.00000, 0.00000, + }; + + void SetUp() override { + double box[] = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + region.reinitBox(box); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + nnei = sec_a.back(); + ndescrpt = nnei * 1; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + build_nlist(nlist_a_cpy, nlist_r_cpy, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + nlist.resize(nloc * nnei); + env.resize(nloc * ndescrpt); + env_deriv.resize(nloc * ndescrpt * 3); + rij.resize(nloc * nnei * 3); + for(int ii = 0; ii < nloc; ++ii){ + // format nlist and record + format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + for (int jj = 0; jj < nnei; ++jj){ + nlist[ii*nnei + jj] = fmt_nlist_a[jj]; + } + std::vector t_env, t_env_deriv, t_rij; + // compute env_mat and its deriv, record + env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + for (int jj = 0; jj < ndescrpt; ++jj){ + env[ii*ndescrpt+jj] = t_env[jj]; + for (int dd = 0; dd < 3; ++dd){ + env_deriv[ii*ndescrpt*3+jj*3+dd] = t_env_deriv[jj*3+dd]; + } + } + for (int jj = 0; jj < nnei * 3; ++jj){ + rij[ii*nnei*3 + jj] = t_rij[jj]; + } + } + grad.resize(9); + for (int ii = 0; ii < 9; ++ii){ + grad[ii] = 10 - ii * 1.; + } + } + void TearDown() override { + } +}; + +TEST_F(TestProdVirialGradR, cpu) +{ + std::vector grad_net(nloc * ndescrpt); + int n_a_sel = nnei; + prod_virial_grad_r_cpu (&grad_net[0], &grad[0], &env_deriv[0], &rij[0], &nlist[0], nloc, nnei); + EXPECT_EQ(grad_net.size(), nloc * ndescrpt); + EXPECT_EQ(grad_net.size(), expected_grad_net.size()); + for (int jj = 0; jj < grad_net.size(); ++jj){ + EXPECT_LT(fabs(grad_net[jj] - expected_grad_net[jj]) , 1e-5); + } + // for (int jj = 0; jj < nloc * ndescrpt; ++jj){ + // printf("%8.5f, ", grad_net[jj]); + // } + // printf("\n"); +} diff --git a/source/op/prod_force_se_r_grad.cc b/source/op/prod_force_se_r_grad.cc index 3c2ff96827..c2417b1804 100644 --- a/source/op/prod_force_se_r_grad.cc +++ b/source/op/prod_force_se_r_grad.cc @@ -3,6 +3,8 @@ #include "tensorflow/core/framework/shape_inference.h" #include +#include "prod_force_grad.h" + using namespace tensorflow; // using namespace std; @@ -82,39 +84,17 @@ class ProdForceSeRGradOp : public OpKernel for (int kk = 0; kk < nframes; ++kk){ int grad_iter = kk * nloc * 3; - int net_iter = kk * nloc * ndescrpt; int in_iter = kk * nloc * ndescrpt * 3; int nlist_iter = kk * nloc * nnei; int grad_net_iter = kk * nloc * ndescrpt; - - // reset the frame to 0 - for (int ii = 0; ii < nloc; ++ii){ - for (int aa = 0; aa < ndescrpt; ++aa){ - grad_net (grad_net_iter + ii * ndescrpt + aa) = 0; - } - } - - // compute grad of one frame - for (int ii = 0; ii < nloc; ++ii){ - int i_idx = ii; - - // deriv wrt center atom - for (int aa = 0; aa < ndescrpt; ++aa){ - for (int dd = 0; dd < 3; ++dd){ - grad_net (grad_net_iter + i_idx * ndescrpt + aa) -= grad (grad_iter + i_idx * 3 + dd) * in_deriv (in_iter + i_idx * ndescrpt * 3 + aa * 3 + dd); - } - } - - // loop over neighbors - for (int jj = 0; jj < nnei; ++jj){ - int j_idx = nlist (nlist_iter + i_idx * nnei + jj); - if (j_idx > nloc) j_idx = j_idx % nloc; - if (j_idx < 0) continue; - for (int dd = 0; dd < 3; ++dd){ - grad_net (grad_net_iter + i_idx * ndescrpt + jj) += grad (grad_iter + j_idx * 3 + dd) * in_deriv (in_iter + i_idx * ndescrpt * 3 + jj * 3 + dd); - } - } - } + + prod_force_grad_r_cpu( + &grad_net(grad_net_iter), + &grad(grad_iter), + &in_deriv(in_iter), + &nlist(nlist_iter), + nloc, + nnei); } } }; diff --git a/source/op/prod_virial_se_r_grad.cc b/source/op/prod_virial_se_r_grad.cc index fa15b3a671..94847b9880 100644 --- a/source/op/prod_virial_se_r_grad.cc +++ b/source/op/prod_virial_se_r_grad.cc @@ -3,6 +3,8 @@ #include "tensorflow/core/framework/shape_inference.h" #include +#include "prod_virial_grad.h" + using namespace tensorflow; //using namespace std; @@ -89,35 +91,19 @@ class ProdVirialSeRGradOp : public OpKernel for (int kk = 0; kk < nframes; ++kk){ int grad_iter = kk * 9; - int net_iter = kk * nloc * ndescrpt; int in_iter = kk * nloc * ndescrpt * 3; int rij_iter = kk * nloc * nnei * 3; int nlist_iter = kk * nloc * nnei; int grad_net_iter = kk * nloc * ndescrpt; - // reset the frame to 0 - for (int ii = 0; ii < nloc; ++ii){ - for (int aa = 0; aa < ndescrpt; ++aa){ - grad_net (grad_net_iter + ii * ndescrpt + aa) = 0; - } - } - - // compute grad of one frame - for (int ii = 0; ii < nloc; ++ii){ - int i_idx = ii; - - // loop over neighbors - for (int jj = 0; jj < nnei; ++jj){ - int j_idx = nlist (nlist_iter + i_idx * nnei + jj); - if (j_idx < 0) continue; - for (int dd0 = 0; dd0 < 3; ++dd0){ - for (int dd1 = 0; dd1 < 3; ++dd1){ - grad_net (grad_net_iter + i_idx * ndescrpt + jj) -= - -1.0 * grad (grad_iter + dd0 * 3 + dd1) * rij (rij_iter + i_idx * nnei * 3 + jj * 3 + dd1) * in_deriv (in_iter + i_idx * ndescrpt * 3 + jj * 3 + dd0); - } - } - } - } + prod_virial_grad_r_cpu( + &grad_net(grad_net_iter), + &grad(grad_iter), + &in_deriv(in_iter), + &rij(rij_iter), + &nlist(nlist_iter), + nloc, + nnei); } } }; From 07c413ca9359ad16fe2eba950ec9391827b6dd4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Mon, 15 Feb 2021 21:15:59 +0100 Subject: [PATCH 158/562] move entrypoint scripts to one submodule --- deepmd/entrypoints/__init__.py | 20 ++++ deepmd/entrypoints/compress.py | 108 ++++++++++++++++++ .../scripts => deepmd/entrypoints}/config.py | 2 + {source/train => deepmd/entrypoints}/doc.py | 0 .../scripts => deepmd/entrypoints}/freeze.py | 4 +- .../entrypoints}/print_old_model.py | 0 {source/train => deepmd/entrypoints}/test.py | 0 {source/train => deepmd/entrypoints}/train.py | 0 .../train => deepmd/entrypoints}/transform.py | 0 source/scripts/CMakeLists.txt | 5 - source/train/CMakeLists.txt | 6 +- source/train/compress.py | 53 --------- source/train/main.py | 11 +- 13 files changed, 136 insertions(+), 73 deletions(-) create mode 100644 deepmd/entrypoints/__init__.py create mode 100644 deepmd/entrypoints/compress.py rename {source/scripts => deepmd/entrypoints}/config.py (99%) rename {source/train => deepmd/entrypoints}/doc.py (100%) rename {source/scripts => deepmd/entrypoints}/freeze.py (99%) rename {source/train => deepmd/entrypoints}/print_old_model.py (100%) rename {source/train => deepmd/entrypoints}/test.py (100%) rename {source/train => deepmd/entrypoints}/train.py (100%) rename {source/train => deepmd/entrypoints}/transform.py (100%) delete mode 100644 source/scripts/CMakeLists.txt delete mode 100644 source/train/compress.py diff --git a/deepmd/entrypoints/__init__.py b/deepmd/entrypoints/__init__.py new file mode 100644 index 0000000000..a93259a78a --- /dev/null +++ b/deepmd/entrypoints/__init__.py @@ -0,0 +1,20 @@ +"""Submodule that contains all the DeePMD-Kit entry point scripts.""" + +from .compress import compress +from .config import config +from .doc import doc_train_input +from .freeze import freeze +from .test import test +from .train import train +from .transform import transform + +__all__ = [ + "config", + "doc_train_input", + "freeze", + "test", + "train", + "transform", + "compress", + "doc_train_input", +] diff --git a/deepmd/entrypoints/compress.py b/deepmd/entrypoints/compress.py new file mode 100644 index 0000000000..61c798f453 --- /dev/null +++ b/deepmd/entrypoints/compress.py @@ -0,0 +1,108 @@ +"""Compress a model, which including tabulating the embedding-net.""" + +import copy +import json +import logging +from typing import TYPE_CHECKING, Optional + +from deepmd.common import j_loader +from deepmd.utils.argcheck import normalize +from deepmd.utils.compat import convert_input_v0_v1 + +from .freeze import freeze +from .train import train +from .transform import transform + +if TYPE_CHECKING: + try: + from typing import Protocol # python >=3.8 + except ImportError: + from typing_extensions import Protocol # type: ignore + + class ArgsProto(Protocol): + """Prococol mimicking parser object.""" + + INPUT: str + input: str + output: str + extrapolate: str + stride: float + frequency: str + checkpoint_folder: str + init_model: Optional[str] + restart: Optional[str] + nodes: Optional[str] + old_model: str + raw_model: str + +__all__ = ["compress"] + +log = logging.getLogger(__name__) + + +def compress(args: "ArgsProto"): + """Compress model. + + The table is composed of fifth-order polynomial coefficients and is assembled from + two sub-tables. The first table takes the stride(parameter) as it's uniform stride, + while the second table takes 10 * stride as it's uniform stride. The range of the + first table is automatically detected by deepmd-kit, while the second table ranges + from the first table's upper boundary(upper) to the extrapolate(parameter) * upper. + + Parameters + ---------- + args : ArgsProto + arguments object + """ + jdata = j_loader(args.INPUT) + if "model" not in jdata.keys(): + jdata = convert_input_v0_v1(jdata, warning=True, dump="input_v1_compat.json") + jdata = normalize(jdata) + jdata["model"]["compress"] = {} + jdata["model"]["compress"]["compress"] = True + jdata["model"]["compress"]["model_file"] = args.input + jdata["model"]["compress"]["table_config"] = [ + args.extrapolate, + args.stride, + 10 * args.stride, + int(args.frequency), + ] + + # check the descriptor info of the input file + assert ( + jdata["model"]["descriptor"]["type"] == "se_a" + ), "Model compression error: descriptor type must be se_a!" + assert ( + jdata["model"]["descriptor"]["resnet_dt"] is False + ), "Model compression error: descriptor resnet_dt must be false!" + + # stage 1: training or refining the model with tabulation + log.info("\n\n") + log.info("stage 1: train or refine the model with tabulation") + args_train = copy.deepcopy(args) + args_train.INPUT = "compress.json" + args_train.output = "compress.json" + args_train.init_model = None + args_train.restart = None + jdata["training"]["stop_batch"] = jdata["training"][ + "save_freq" + ] # be careful here, if one want to refine the model + with open(args_train.INPUT, "w") as fp: + json.dump(jdata, fp, indent=4) + train(args_train) + + # stage 2: freeze the model + log.info("\n\n") + log.info("stage 2: freeze the model") + args_frz = copy.deepcopy(args) + args_frz.nodes = None + freeze(args_frz) + + # stage 3: transform the model + log.info("\n\n") + log.info("stage 3: transform the model") + args_transform = copy.deepcopy(args) + args_transform.old_model = args.input + args_transform.raw_model = args.output + args_transform.output = args.output + transform(args_transform) diff --git a/source/scripts/config.py b/deepmd/entrypoints/config.py similarity index 99% rename from source/scripts/config.py rename to deepmd/entrypoints/config.py index ea8de980d9..55bea33566 100644 --- a/source/scripts/config.py +++ b/deepmd/entrypoints/config.py @@ -19,6 +19,8 @@ class ArgsProto(Protocol): output: str +__all__ = ["config"] + DEFAULT_DATA: Dict[str, Any] = { "use_smooth": True, diff --git a/source/train/doc.py b/deepmd/entrypoints/doc.py similarity index 100% rename from source/train/doc.py rename to deepmd/entrypoints/doc.py diff --git a/source/scripts/freeze.py b/deepmd/entrypoints/freeze.py similarity index 99% rename from source/scripts/freeze.py rename to deepmd/entrypoints/freeze.py index 06338f9eea..51193b17cc 100755 --- a/source/scripts/freeze.py +++ b/deepmd/entrypoints/freeze.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""This script freezes TF trained graph so it can be used with LAMMPS ain i-PI. +"""This script freezes TF trained graph so it can be used with LAMMPS and i-PI. References ---------- @@ -36,6 +36,8 @@ class ArgsProto(Protocol): output: str nodes: str +__all__ = ["freeze"] + def _make_node_names(model_type: str, modifier_type: Optional[str] = None) -> List[str]: """Get node names based on model type. diff --git a/source/train/print_old_model.py b/deepmd/entrypoints/print_old_model.py similarity index 100% rename from source/train/print_old_model.py rename to deepmd/entrypoints/print_old_model.py diff --git a/source/train/test.py b/deepmd/entrypoints/test.py similarity index 100% rename from source/train/test.py rename to deepmd/entrypoints/test.py diff --git a/source/train/train.py b/deepmd/entrypoints/train.py similarity index 100% rename from source/train/train.py rename to deepmd/entrypoints/train.py diff --git a/source/train/transform.py b/deepmd/entrypoints/transform.py similarity index 100% rename from source/train/transform.py rename to deepmd/entrypoints/transform.py diff --git a/source/scripts/CMakeLists.txt b/source/scripts/CMakeLists.txt deleted file mode 100644 index c78bbc8d5a..0000000000 --- a/source/scripts/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -install( - FILES freeze.py config.py - DESTINATION deepmd/ -) - diff --git a/source/train/CMakeLists.txt b/source/train/CMakeLists.txt index 748c21f121..8a5317a1d0 100644 --- a/source/train/CMakeLists.txt +++ b/source/train/CMakeLists.txt @@ -2,16 +2,12 @@ configure_file("run_config.ini" "${CMAKE_CURRENT_BINARY_DIR}/run_config.ini" @ONLY) -file(GLOB LIB_PY main.py calculator.py model.py trainer.py run_options.py transform.py doc.py compress.py) +file(GLOB LIB_PY main.py calculator.py model.py trainer.py run_options.py ) install( FILES ${LIB_PY} DESTINATION deepmd ) -install( - FILES train.py test.py - DESTINATION deepmd -) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/run_config.ini DESTINATION deepmd/pkg_config diff --git a/source/train/compress.py b/source/train/compress.py deleted file mode 100644 index 24a3a7997a..0000000000 --- a/source/train/compress.py +++ /dev/null @@ -1,53 +0,0 @@ -import re -import json -import copy -import argparse -import numpy as np -from deepmd.env import tf -from .train import train -from .freeze import freeze -from .transform import transform -from deepmd.common import j_loader -from deepmd.utils.argcheck import normalize - -def compress(args): - jdata = j_loader(args.INPUT) - if not 'model' in jdata.keys(): - jdata = convert_input_v0_v1(jdata, - warning = True, - dump = 'input_v1_compat.json') - jdata = normalize(jdata) - jdata['model']['compress'] = {} - jdata['model']['compress']['compress'] = True - jdata['model']['compress']['model_file'] = args.input - jdata['model']['compress']['table_config'] = [args.extrapolate, args.stride, 10 * args.stride, int(args.frequency)] - - # check the descriptor info of the input file - assert jdata['model']['descriptor']['type'] == 'se_a', 'Model compression error: descriptor type must be se_a!' - assert jdata['model']['descriptor']['resnet_dt'] == False, 'Model compression error: descriptor resnet_dt must be false!' - - # stage 1: training or refining the model with tabulation - print('\n\n# DEEPMD: stage 1: train or refine the model with tabulation') - args_train = copy.deepcopy(args) - args_train.INPUT = 'compress.json' - args_train.output = 'compress.json' - args_train.init_model = None - args_train.restart = None - jdata['training']['stop_batch'] = jdata['training']['save_freq'] # be careful here, if one want to refine the model - with open(args_train.INPUT, 'w') as fp: - json.dump(jdata, fp, indent=4) - train(args_train) - - # stage 2: freeze the model - print('\n\n# DEEPMD: stage 2: freeze the model') - args_frz = copy.deepcopy(args) - args_frz.nodes = None - freeze(args_frz) - - # stage 3: transform the model - print('\n\n# DEEPMD: stage 3: transform the model') - args_transform = copy.deepcopy(args) - args_transform.old_model = args.input - args_transform.raw_model = args.output - args_transform.output = args.output - transform(args_transform) diff --git a/source/train/main.py b/source/train/main.py index 42bd8c4a1d..a48e5e7473 100644 --- a/source/train/main.py +++ b/source/train/main.py @@ -3,17 +3,10 @@ import argparse from pathlib import Path +from deepmd.entrypoints import (compress, config, doc_train_input, freeze, + test, train, transform) from deepmd.loggers import set_log_handles -from .config import config -from .doc import doc_train_input -from .freeze import freeze -from .test import test -from .train import train -from .transform import transform -from .compress import compress -from .doc import doc_train_input - def main(): """DeePMD-Kit entry point. From f9030be870948760b35ff8c837b58d2395cde8f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Mon, 15 Feb 2021 21:39:23 +0100 Subject: [PATCH 159/562] install ops to specific module --- deepmd/entrypoints/freeze.py | 9 +-------- deepmd/env.py | 4 +++- deepmd/op/__init__.py | 18 ++++++++++++++++++ source/op/CMakeLists.txt | 4 ++-- source/tests/test_descrpt_nonsmth.py | 5 +---- source/tests/test_descrpt_se_ar.py | 7 +------ source/tests/test_descrpt_se_r.py | 7 +------ source/tests/test_descrpt_sea_ef.py | 7 +------ source/tests/test_descrpt_sea_ef_para.py | 7 +------ source/tests/test_descrpt_sea_ef_vert.py | 7 +------ source/tests/test_descrpt_smooth.py | 7 +------ source/tests/test_tab_nonsmth.py | 7 +------ source/tests/test_tab_smooth.py | 7 +------ source/train/trainer.py | 11 +---------- 14 files changed, 34 insertions(+), 73 deletions(-) create mode 100644 deepmd/op/__init__.py diff --git a/deepmd/entrypoints/freeze.py b/deepmd/entrypoints/freeze.py index 51193b17cc..9f2d409c4b 100755 --- a/deepmd/entrypoints/freeze.py +++ b/deepmd/entrypoints/freeze.py @@ -11,14 +11,7 @@ from os.path import abspath # load grad of force module -import deepmd._prod_force_grad -import deepmd._prod_virial_grad -import deepmd._prod_force_se_a_grad -import deepmd._prod_virial_se_a_grad -import deepmd._prod_force_se_r_grad -import deepmd._prod_virial_se_r_grad -import deepmd._soft_min_force_grad -import deepmd._soft_min_virial_grad +import deepmd.op from typing import List, Optional, TYPE_CHECKING diff --git a/deepmd/env.py b/deepmd/env.py index b76016e44d..75703d60d3 100644 --- a/deepmd/env.py +++ b/deepmd/env.py @@ -122,7 +122,9 @@ def get_module(module_name: str) -> "ModuleType": else: ext = ".so" - module_file = (Path(__file__).parent / module_name).with_suffix(ext).resolve() + module_file = ( + (Path(__file__).parent / "op" / module_name).with_suffix(ext).resolve() + ) if not module_file.is_file(): raise FileNotFoundError(f"module {module_name} does not exist") diff --git a/deepmd/op/__init__.py b/deepmd/op/__init__.py new file mode 100644 index 0000000000..01fc25b62c --- /dev/null +++ b/deepmd/op/__init__.py @@ -0,0 +1,18 @@ +"""This module will house cust Tf OPs after CMake installation.""" + +from pathlib import Path +import importlib + +NOT_LOADABLE = ("__init__.py") +PACKAGE_BASE = "deepmd.op" + + +def import_ops(): + """Import all custom TF ops that are present in this submodule.""" + for module_file in Path(__file__).parent.glob("*.py"): + if module_file.name not in NOT_LOADABLE: + module_name = module_file.stem + importlib.import_module(module_name, PACKAGE_BASE) + + +import_ops() diff --git a/source/op/CMakeLists.txt b/source/op/CMakeLists.txt index ef2c57f8ea..78cacf83be 100644 --- a/source/op/CMakeLists.txt +++ b/source/op/CMakeLists.txt @@ -63,7 +63,7 @@ if (BUILD_CPP_IF) install(TARGETS ${LIB_DEEPMD_OP} DESTINATION lib/) endif (BUILD_CPP_IF) if (BUILD_PY_IF) - install(TARGETS op_abi DESTINATION deepmd) - install(TARGETS op_grads DESTINATION deepmd) + install(TARGETS op_abi DESTINATION deepmd/op) + install(TARGETS op_grads DESTINATION deepmd/op) install(FILES ${OP_PY} DESTINATION deepmd) endif (BUILD_PY_IF) diff --git a/source/tests/test_descrpt_nonsmth.py b/source/tests/test_descrpt_nonsmth.py index c6d283b69c..ee336f8fe4 100644 --- a/source/tests/test_descrpt_nonsmth.py +++ b/source/tests/test_descrpt_nonsmth.py @@ -6,10 +6,7 @@ from tensorflow.python.framework import ops # load grad of force module -import deepmd._prod_force_grad -import deepmd._prod_virial_grad -import deepmd._soft_min_force_grad -import deepmd._soft_min_virial_grad +import deepmd.op from common import force_test from common import virial_test diff --git a/source/tests/test_descrpt_se_ar.py b/source/tests/test_descrpt_se_ar.py index e1d8532f5a..f2ec7bc8aa 100644 --- a/source/tests/test_descrpt_se_ar.py +++ b/source/tests/test_descrpt_se_ar.py @@ -6,12 +6,7 @@ from tensorflow.python.framework import ops # load grad of force module -import deepmd._prod_force_grad -import deepmd._prod_virial_grad -import deepmd._prod_force_se_r_grad -import deepmd._prod_virial_se_r_grad -import deepmd._soft_min_force_grad -import deepmd._soft_min_virial_grad +import deepmd.op from common import force_test from common import virial_test diff --git a/source/tests/test_descrpt_se_r.py b/source/tests/test_descrpt_se_r.py index 3a07ff4fd2..b2fa7ab3e5 100644 --- a/source/tests/test_descrpt_se_r.py +++ b/source/tests/test_descrpt_se_r.py @@ -6,12 +6,7 @@ from tensorflow.python.framework import ops # load grad of force module -import deepmd._prod_force_grad -import deepmd._prod_virial_grad -import deepmd._prod_force_se_r_grad -import deepmd._prod_virial_se_r_grad -import deepmd._soft_min_force_grad -import deepmd._soft_min_virial_grad +import deepmd.op from common import force_test from common import virial_test diff --git a/source/tests/test_descrpt_sea_ef.py b/source/tests/test_descrpt_sea_ef.py index 6dc0b4b11e..a75bd6d436 100644 --- a/source/tests/test_descrpt_sea_ef.py +++ b/source/tests/test_descrpt_sea_ef.py @@ -6,12 +6,7 @@ from tensorflow.python.framework import ops # load grad of force module -import deepmd._prod_force_grad -import deepmd._prod_virial_grad -import deepmd._prod_force_se_a_grad -import deepmd._prod_virial_se_a_grad -import deepmd._soft_min_force_grad -import deepmd._soft_min_virial_grad +import deepmd.op from common import force_test from common import virial_test diff --git a/source/tests/test_descrpt_sea_ef_para.py b/source/tests/test_descrpt_sea_ef_para.py index 45ff7b333b..602eafb54d 100644 --- a/source/tests/test_descrpt_sea_ef_para.py +++ b/source/tests/test_descrpt_sea_ef_para.py @@ -6,12 +6,7 @@ from tensorflow.python.framework import ops # load grad of force module -import deepmd._prod_force_grad -import deepmd._prod_virial_grad -import deepmd._prod_force_se_a_grad -import deepmd._prod_virial_se_a_grad -import deepmd._soft_min_force_grad -import deepmd._soft_min_virial_grad +import deepmd.op from common import force_test from common import virial_test diff --git a/source/tests/test_descrpt_sea_ef_vert.py b/source/tests/test_descrpt_sea_ef_vert.py index a4f180157a..3f44e4d15b 100644 --- a/source/tests/test_descrpt_sea_ef_vert.py +++ b/source/tests/test_descrpt_sea_ef_vert.py @@ -6,12 +6,7 @@ from tensorflow.python.framework import ops # load grad of force module -import deepmd._prod_force_grad -import deepmd._prod_virial_grad -import deepmd._prod_force_se_a_grad -import deepmd._prod_virial_se_a_grad -import deepmd._soft_min_force_grad -import deepmd._soft_min_virial_grad +import deepmd.op from common import force_test from common import virial_test diff --git a/source/tests/test_descrpt_smooth.py b/source/tests/test_descrpt_smooth.py index 7dce811f1e..c9c796799a 100644 --- a/source/tests/test_descrpt_smooth.py +++ b/source/tests/test_descrpt_smooth.py @@ -6,12 +6,7 @@ from tensorflow.python.framework import ops # load grad of force module -import deepmd._prod_force_grad -import deepmd._prod_virial_grad -import deepmd._prod_force_se_a_grad -import deepmd._prod_virial_se_a_grad -import deepmd._soft_min_force_grad -import deepmd._soft_min_virial_grad +import deepmd.op from common import force_test from common import virial_test diff --git a/source/tests/test_tab_nonsmth.py b/source/tests/test_tab_nonsmth.py index a12a00b4d7..9181ba5977 100644 --- a/source/tests/test_tab_nonsmth.py +++ b/source/tests/test_tab_nonsmth.py @@ -6,12 +6,7 @@ from tensorflow.python.framework import ops # load grad of force module -import deepmd._prod_force_grad -import deepmd._prod_virial_grad -import deepmd._prod_force_se_a_grad -import deepmd._prod_virial_se_a_grad -import deepmd._soft_min_force_grad -import deepmd._soft_min_virial_grad +import deepmd.op from deepmd.utils.pair_tab import PairTab from common import force_test diff --git a/source/tests/test_tab_smooth.py b/source/tests/test_tab_smooth.py index f5950ec8fe..2917582446 100644 --- a/source/tests/test_tab_smooth.py +++ b/source/tests/test_tab_smooth.py @@ -6,12 +6,7 @@ from tensorflow.python.framework import ops # load grad of force module -import deepmd._prod_force_grad -import deepmd._prod_virial_grad -import deepmd._prod_force_se_a_grad -import deepmd._prod_virial_se_a_grad -import deepmd._soft_min_force_grad -import deepmd._soft_min_virial_grad +import deepmd.op from deepmd.utils.pair_tab import PairTab from common import force_test diff --git a/source/train/trainer.py b/source/train/trainer.py index bef7441200..d730a2980a 100644 --- a/source/train/trainer.py +++ b/source/train/trainer.py @@ -26,16 +26,7 @@ from deepmd.env import op_module # load grad of force module -import deepmd._prod_force_grad -import deepmd._prod_virial_grad -import deepmd._prod_force_se_a_grad -import deepmd._prod_virial_se_a_grad -import deepmd._prod_force_se_r_grad -import deepmd._prod_virial_se_r_grad -import deepmd._soft_min_force_grad -import deepmd._soft_min_virial_grad -import deepmd._tabulate_grad -import deepmd._gelu +import deepmd.op from deepmd.common import j_must_have, ClassArg From ae73f41489d12d97253e171d824318a2723dc260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Mon, 15 Feb 2021 22:26:00 +0100 Subject: [PATCH 160/562] fix bugs after ops move --- .github/workflows/lint_python.yml | 2 +- README.md | 2 -- deepmd/op/__init__.py | 7 +++++-- source/CMakeLists.txt | 1 - source/lib/CMakeLists.txt | 2 +- source/op/CMakeLists.txt | 6 +++--- source/tests/system/set.000/aparam.npy | Bin 0 -> 224 bytes source/tests/system/set.000/box.npy | Bin 0 -> 200 bytes source/tests/system/set.000/coord.npy | Bin 0 -> 272 bytes source/tests/system/set.000/energy.npy | Bin 0 -> 136 bytes source/tests/system/set.000/force.npy | Bin 0 -> 272 bytes source/tests/system/set.000/fparam.npy | Bin 0 -> 144 bytes source/tests/system/type.raw | 6 ++++++ source/tests/system/type_map.raw | 2 ++ 14 files changed, 18 insertions(+), 10 deletions(-) create mode 100644 source/tests/system/set.000/aparam.npy create mode 100644 source/tests/system/set.000/box.npy create mode 100644 source/tests/system/set.000/coord.npy create mode 100644 source/tests/system/set.000/energy.npy create mode 100644 source/tests/system/set.000/force.npy create mode 100644 source/tests/system/set.000/fparam.npy create mode 100644 source/tests/system/type.raw create mode 100644 source/tests/system/type_map.raw diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml index dcb1e4bf0d..92a609edc1 100644 --- a/.github/workflows/lint_python.yml +++ b/.github/workflows/lint_python.yml @@ -19,7 +19,7 @@ jobs: run: pip install -r requirements.txt - uses: marian-code/python-lint-annotate@v2.5.0 with: - python-root-list: "./deepmd/*.py ./deepmd/*/*.py ./source/train/*.py ./source/tests/*.py ./source/scripts/*.py ./source/op/*.py" + python-root-list: "./deepmd/*.py ./deepmd/*/*.py ./source/train/*.py ./source/tests/*.py ./source/op/*.py" use-black: true use-isort: true use-mypy: true diff --git a/README.md b/README.md index 7d72de9bc9..e32df9eb70 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,6 @@ The code is organized as follows: * `source/op`: tensorflow op implementation. working with library. -* `source/scripts`: Python script for model freezing. - * `source/train`: Python modules and scripts for training and testing. diff --git a/deepmd/op/__init__.py b/deepmd/op/__init__.py index 01fc25b62c..e4e40126a4 100644 --- a/deepmd/op/__init__.py +++ b/deepmd/op/__init__.py @@ -2,17 +2,20 @@ from pathlib import Path import importlib +import logging NOT_LOADABLE = ("__init__.py") PACKAGE_BASE = "deepmd.op" +log = logging.getLogger(__name__) + def import_ops(): """Import all custom TF ops that are present in this submodule.""" for module_file in Path(__file__).parent.glob("*.py"): if module_file.name not in NOT_LOADABLE: - module_name = module_file.stem + module_name = f".{module_file.stem}" + log.debug(f"importing op module: {module_name}") importlib.import_module(module_name, PACKAGE_BASE) - import_ops() diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index d8e5addb31..e1d66e207c 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -206,7 +206,6 @@ add_subdirectory (op/) add_subdirectory (lib/) if (BUILD_PY_IF) add_subdirectory (train/) - add_subdirectory (scripts/) add_subdirectory (tests/) endif (BUILD_PY_IF) if (BUILD_CPP_IF) diff --git a/source/lib/CMakeLists.txt b/source/lib/CMakeLists.txt index bbc1237a6e..ea4c894fe1 100644 --- a/source/lib/CMakeLists.txt +++ b/source/lib/CMakeLists.txt @@ -16,7 +16,7 @@ if (USE_CUDA_TOOLKIT) endif() if(BUILD_PY_IF) - install(TARGETS ${libname} DESTINATION deepmd/) + install(TARGETS ${libname} DESTINATION deepmd/op/) endif(BUILD_PY_IF) if(BUILD_CPP_IF) install(TARGETS ${libname} DESTINATION lib/) diff --git a/source/op/CMakeLists.txt b/source/op/CMakeLists.txt index 78cacf83be..3151a28482 100644 --- a/source/op/CMakeLists.txt +++ b/source/op/CMakeLists.txt @@ -63,7 +63,7 @@ if (BUILD_CPP_IF) install(TARGETS ${LIB_DEEPMD_OP} DESTINATION lib/) endif (BUILD_CPP_IF) if (BUILD_PY_IF) - install(TARGETS op_abi DESTINATION deepmd/op) - install(TARGETS op_grads DESTINATION deepmd/op) - install(FILES ${OP_PY} DESTINATION deepmd) + install(TARGETS op_abi DESTINATION deepmd/op/) + install(TARGETS op_grads DESTINATION deepmd/op/) + install(FILES ${OP_PY} DESTINATION deepmd/op/) endif (BUILD_PY_IF) diff --git a/source/tests/system/set.000/aparam.npy b/source/tests/system/set.000/aparam.npy new file mode 100644 index 0000000000000000000000000000000000000000..b3544695fa75af4593fe8b9c0fb99c6dffd39758 GIT binary patch literal 224 zcmbR27wQ`j$;eQ~P_3SlTAW;@Zl$1ZlV+i=qoAIaUsO_*m=~X4l#&V(cT3DEP6dh= nXCxM+0{I$-Itpew3Pzeb3bhL40j^myL13pnggyzSsmBKZExl5t literal 0 HcmV?d00001 diff --git a/source/tests/system/set.000/box.npy b/source/tests/system/set.000/box.npy new file mode 100644 index 0000000000000000000000000000000000000000..f70e95b6e772550e087d1aba097f26b3b380704e GIT binary patch literal 200 zcmbR27wQ`j$;eQ~P_3SlTAW;@Zl$1ZlV+i=qoAIaUsO_*m=~X4l#&V(cT3DEP6dh= hXCxM+0{I$-ItrGWItsN4WCJb+Ffeg|(6~s#@&G_89MJ#( literal 0 HcmV?d00001 diff --git a/source/tests/system/set.000/coord.npy b/source/tests/system/set.000/coord.npy new file mode 100644 index 0000000000000000000000000000000000000000..27a06e944251c351ad110c8c69cc764c2fcd84db GIT binary patch literal 272 zcmbR27wQ`j$;eQ~P_3SlTAW;@Zl$1ZlV+i=qoAIaUsO_*m=~X4l#&V(cT3DEP6dh= zXCxM+0{I$-ItqpsnmP)#3giN=`6m;X{f%5|zg$iK+xCJ@_C<$GYa?gvv_GBq Date: Mon, 15 Feb 2021 22:26:48 +0100 Subject: [PATCH 161/562] remove forgoten debug prints --- source/train/run_options.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/source/train/run_options.py b/source/train/run_options.py index 419241ef5d..a5f69edef1 100644 --- a/source/train/run_options.py +++ b/source/train/run_options.py @@ -7,10 +7,6 @@ from typing import TYPE_CHECKING, Dict, List, Optional, Tuple import numpy as np -for p in Path(__file__).parent.glob("*"): - if p.is_dir(): - print(p) -print("----------------") from deepmd.cluster import get_resource from deepmd.env import get_tf_default_nthreads, tf from deepmd.loggers import set_log_handles From b42cc935eedb8adf3feb867a1290c707af7a279f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Mon, 15 Feb 2021 22:47:42 +0100 Subject: [PATCH 162/562] add setup cfg and scilence some lintner errors --- deepmd/env.py | 6 +++++- deepmd/op/__init__.py | 9 ++++++++- setup.cfg | 20 ++++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 setup.cfg diff --git a/deepmd/env.py b/deepmd/env.py index 75703d60d3..282310673e 100644 --- a/deepmd/env.py +++ b/deepmd/env.py @@ -19,6 +19,8 @@ except ImportError: import tensorflow as tf +SHARED_LIB_MODULE = "op" + def set_env_if_empty(key: str, value: str, verbose: bool = True): """Set environment variable only if it is empty. @@ -123,7 +125,9 @@ def get_module(module_name: str) -> "ModuleType": ext = ".so" module_file = ( - (Path(__file__).parent / "op" / module_name).with_suffix(ext).resolve() + (Path(__file__).parent / SHARED_LIB_MODULE / module_name) + .with_suffix(ext) + .resolve() ) if not module_file.is_file(): diff --git a/deepmd/op/__init__.py b/deepmd/op/__init__.py index e4e40126a4..1771422a40 100644 --- a/deepmd/op/__init__.py +++ b/deepmd/op/__init__.py @@ -11,11 +11,18 @@ def import_ops(): - """Import all custom TF ops that are present in this submodule.""" + """Import all custom TF ops that are present in this submodule. + + Note + ---- + Initialy this subdir is unpopulated. CMake will install all the op module python + files and shared libs. + """ for module_file in Path(__file__).parent.glob("*.py"): if module_file.name not in NOT_LOADABLE: module_name = f".{module_file.stem}" log.debug(f"importing op module: {module_name}") importlib.import_module(module_name, PACKAGE_BASE) + import_ops() diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000000..c055f387b0 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,20 @@ +# selectively turn of lintner warnings, always include reasoning why any warning should +# be silenced + +# W504 - line break after binary operator - there is conflict between W503 and W504 in +# some lintners. One recomends line bread after and one before binary operator so we +# swith W504 off and recomend this coding style: +# a = (b + -> instead of -> a = (b +# c) + c) +[pep8] +ignore = W504 + +# D413 - Missing blank line after last section - makes no sense only adds empy lines in +# docstrings +# D416 - Section name should end with a colon - only applicable to RST type docstrings, +# we are using numpy style +# D203 - 1 blank line required before class docstring - only adds unnecessary empty space +# D107 - Missing docstring in __init__ - Nupmy style documents __init__ parameters in +# class docstring +[pydocstyle] +ignore = D413, D416, D203, D107 \ No newline at end of file From b71eed8eaf582d8f2793f1c28f0c44d4fbe6d3b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Mon, 15 Feb 2021 23:00:33 +0100 Subject: [PATCH 163/562] small style fixes --- deepmd/entrypoints/config.py | 2 +- deepmd/entrypoints/doc.py | 2 ++ deepmd/entrypoints/freeze.py | 44 +++++++++++++----------------------- setup.cfg | 4 +++- 4 files changed, 22 insertions(+), 30 deletions(-) diff --git a/deepmd/entrypoints/config.py b/deepmd/entrypoints/config.py index 55bea33566..8ffb2e2199 100644 --- a/deepmd/entrypoints/config.py +++ b/deepmd/entrypoints/config.py @@ -12,7 +12,7 @@ try: from typing import Protocol # python >=3.8 except ImportError: - from typing_extensions import Protocol + from typing_extensions import Protocol # type: ignore class ArgsProto(Protocol): """Prococol mimicking parser object.""" diff --git a/deepmd/entrypoints/doc.py b/deepmd/entrypoints/doc.py index e499e80f48..941efd61c2 100644 --- a/deepmd/entrypoints/doc.py +++ b/deepmd/entrypoints/doc.py @@ -2,6 +2,8 @@ from deepmd.utils.argcheck import gen_doc +__all__ = ["doc_train_input"] + def doc_train_input(): """Print out trining input arguments to console.""" diff --git a/deepmd/entrypoints/freeze.py b/deepmd/entrypoints/freeze.py index 9f2d409c4b..f4c742be1e 100755 --- a/deepmd/entrypoints/freeze.py +++ b/deepmd/entrypoints/freeze.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""This script freezes TF trained graph so it can be used with LAMMPS and i-PI. +"""Script for freezing TF trained graph so it can be used with LAMMPS and i-PI. References ---------- @@ -25,10 +25,11 @@ class ArgsProto(Protocol): """Prococol mimicking parser object.""" - folder: str + checkpoint_folder: str output: str nodes: str + __all__ = ["freeze"] @@ -52,65 +53,52 @@ def _make_node_names(model_type: str, modifier_type: Optional[str] = None) -> Li RuntimeError if unknown model type """ + nodes = [ + "descrpt_attr/rcut", + "descrpt_attr/ntypes", + "model_attr/tmap", + "model_attr/model_type", + ] + if model_type == "ener": - nodes = [ + nodes += [ "o_energy", "o_force", "o_virial", "o_atom_energy", "o_atom_virial", - "descrpt_attr/rcut", - "descrpt_attr/ntypes", "fitting_attr/dfparam", "fitting_attr/daparam", - "model_attr/tmap", - "model_attr/model_type", ] elif model_type == "wfc": - nodes = [ + nodes += [ "o_wfc", - "descrpt_attr/rcut", - "descrpt_attr/ntypes", - "model_attr/tmap", "model_attr/sel_type", - "model_attr/model_type", ] elif model_type == "dipole": - nodes = [ + nodes += [ "o_dipole", "o_rmat", "o_rmat_deriv", "o_nlist", "o_rij", - "descrpt_attr/rcut", - "descrpt_attr/ntypes", "descrpt_attr/sel", "descrpt_attr/ndescrpt", - "model_attr/tmap", "model_attr/sel_type", - "model_attr/model_type", "model_attr/output_dim", ] elif model_type == "polar": - nodes = [ + nodes += [ "o_polar", - "descrpt_attr/rcut", - "descrpt_attr/ntypes", - "model_attr/tmap", "model_attr/sel_type", - "model_attr/model_type", ] elif model_type == "global_polar": - nodes = [ + nodes += [ "o_global_polar", - "descrpt_attr/rcut", - "descrpt_attr/ntypes", - "model_attr/tmap", "model_attr/sel_type", - "model_attr/model_type", ] else: - raise RuntimeError("unknow model type " + model_type) + raise RuntimeError(f"unknow model type {model_type}") if modifier_type == "dipole_charge": nodes += [ "modifier_attr/type", diff --git a/setup.cfg b/setup.cfg index c055f387b0..0ae74b314d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -16,5 +16,7 @@ ignore = W504 # D203 - 1 blank line required before class docstring - only adds unnecessary empty space # D107 - Missing docstring in __init__ - Nupmy style documents __init__ parameters in # class docstring +# D213 - Multi-line docstring summary should start at the second line - unnecessary waste +# of space, start on the first line [pydocstyle] -ignore = D413, D416, D203, D107 \ No newline at end of file +ignore = D413, D416, D203, D107, D213 \ No newline at end of file From 6e39bb04d69515cdfe54925a8e8ef58329f6e869 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Tue, 16 Feb 2021 12:04:39 +0100 Subject: [PATCH 164/562] add strings formating suggestions --- doc/developement.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/developement.rst b/doc/developement.rst index 62fabdf81f..e20789f40e 100644 --- a/doc/developement.rst +++ b/doc/developement.rst @@ -69,6 +69,10 @@ Conventions`_ and `Typing Conventions`_ PEPs, clarified and extended as follows: * Use ``"double quotes"`` for string literals, and ``"""triple double quotes"""`` for docstring's. Single quotes are OK for something like + +* Use f-strings ``s = f"{x:.2f}"`` instead of old style formating with ``"%f" % x``. + string format method ``"{x:.2f}".format()`` may be used sparsely where it is more + convenient than f-strings. .. code-block:: python From 428c9f4de0591d65921baddb2b92e1a62cef4492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Tue, 16 Feb 2021 12:36:00 +0100 Subject: [PATCH 165/562] whitespace formating guidelines --- doc/developement.rst | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/doc/developement.rst b/doc/developement.rst index e20789f40e..fbbd3edda1 100644 --- a/doc/developement.rst +++ b/doc/developement.rst @@ -38,11 +38,6 @@ Conventions`_ and `Typing Conventions`_ PEPs, clarified and extended as follows: * Use 4 spaces per indentation level. No tabs. -* Read the *Whitespace in Expressions and Statements* - section of PEP8_. - -* Avoid `trailing whitespaces`_. - * No one-liner compound statements (i.e., no ``if x: return``: use two lines). @@ -74,6 +69,36 @@ Conventions`_ and `Typing Conventions`_ PEPs, clarified and extended as follows: string format method ``"{x:.2f}".format()`` may be used sparsely where it is more convenient than f-strings. +Whitespace +========== + +Python is not C/C++ so whitespace should be used sparingly to maintain code readability + +* Read the *Whitespace in Expressions and Statements* + section of PEP8_. + +* Avoid `trailing whitespaces`_. + +* Do not use excessive whitespace in your expressions and statements. + +* You should have blank spaces after commas, colons, and semi-colons if it isn’t + trailing next to the end of a bracket, brace, or parentheses. +* With any operators you should use a space in on both sides of the operator. + +* Colons for slicing are considered a binary operator, and should not have any spaces + between them. + +* You should have parentheses with no space, directly next to the function when calling + functions ``function()``. + +* When indexing or slicing the brackets should be directly next to the collection with + no space ``collection["index"]``. + +* Whitespace used to line up variable values is not recommended. + +* Make sure you are consistent with the formats you choose when optional choices are + available. + .. code-block:: python f"something {'this' if x else 'that'}" From 3368a60a69d8c1db248f0c3e58b7e74351634b53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Tue, 16 Feb 2021 17:14:58 +0100 Subject: [PATCH 166/562] implements factory pattern for Deep potentials --- deepmd/__init__.py | 23 +- deepmd/infer/__init__.py | 72 ++++++ deepmd/infer/deep_dipole.py | 60 +++-- deepmd/infer/deep_eval.py | 459 +++++++++++++++++++----------------- deepmd/infer/deep_polar.py | 157 ++++++++---- deepmd/infer/deep_pot.py | 292 +++++++++++------------ deepmd/infer/deep_wfc.py | 46 +++- source/train/calculator.py | 2 +- 8 files changed, 656 insertions(+), 455 deletions(-) diff --git a/deepmd/__init__.py b/deepmd/__init__.py index 2a9fab14e5..c9a24bb04a 100644 --- a/deepmd/__init__.py +++ b/deepmd/__init__.py @@ -1,19 +1,12 @@ """Root of the deepmd package, exposes all public classes and submodules.""" -from . import descriptor -from . import fit -from . import loss -from . import utils -from . import cluster import deepmd.utils.network as network -from .infer.deep_eval import DeepEval -from .infer.deep_pot import DeepPot -from .infer.deep_dipole import DeepDipole -from .infer.deep_polar import DeepPolar -from .infer.deep_polar import DeepGlobalPolar -from .infer.deep_wfc import DeepWFC -from .infer.data_modifier import DipoleChargeModifier + +from . import cluster, descriptor, fit, loss, utils from .env import set_mkl +from .infer import DeepPotential +from .infer.data_modifier import DipoleChargeModifier +from .infer.deep_eval import DeepEval set_mkl() @@ -30,10 +23,6 @@ "cluster", "network", "DeepEval", - "DeepPot", - "DeepDipole", - "DeepPolar", - "DeepGlobalPolar", - "DeepWFC", + "DeepPotential", "DipoleChargeModifier", ] diff --git a/deepmd/infer/__init__.py b/deepmd/infer/__init__.py index e69de29bb2..a9c8bc6e67 100644 --- a/deepmd/infer/__init__.py +++ b/deepmd/infer/__init__.py @@ -0,0 +1,72 @@ +"""Submodule containing all the implemented potentials.""" + +from typing import Union +from .deep_dipole import DeepDipole +from .deep_eval import DeepEval +from .deep_polar import DeepGlobalPolar, DeepPolar +from .deep_pot import DeepPot +from .deep_wfc import DeepWFC +from .data_modifier import DipoleChargeModifier +from .ewald_recp import EwaldRecp + +__all__ = [ + "DeepPotential", + "DeepDipole", + "DeepEval", + "DeepGlobalPolar", + "DeepPolar", + "DeepPot", + "DeepWFC", + "DipoleChargeModifier", + "EwaldRecp", +] + + +def DeepPotential( + model_file: str, load_prefix: str = "load", default_tf_graph: bool = False +) -> Union[DeepDipole, DeepGlobalPolar, DeepPolar, DeepPot, DeepWFC]: + """Factory function that will inialize appropriate potential read from `model_file`. + + Parameters + ---------- + model_file: str + The name of the frozen model file. + load_prefix: str + The prefix in the load computational graph + default_tf_graph : bool + If uses the default tf graph, otherwise build a new tf graph for evaluation + + Returns + ------- + Union[DeepDipole, DeepGlobalPolar, DeepPolar, DeepPot, DeepWFC] + one of the available potentials + + Raises + ------ + RuntimeError + if model file does not correspond to any implementd potential + """ + model_type = DeepEval( + model_file, load_prefix=load_prefix, default_tf_graph=default_tf_graph + ).model_type + + if model_type == "ener": + dp = DeepPot(model_file, prefix=load_prefix, default_tf_graph=default_tf_graph) + elif model_type == "dipole": + dp = DeepDipole( + model_file, prefix=load_prefix, default_tf_graph=default_tf_graph + ) + elif model_type == "polar": + dp = DeepPolar( + model_file, prefix=load_prefix, default_tf_graph=default_tf_graph + ) + elif model_type == "global_polar": + dp = DeepGlobalPolar( + model_file, prefix=load_prefix, default_tf_graph=default_tf_graph + ) + elif model_type == "wfc": + dp = DeepWFC(model_file, prefix=load_prefix, default_tf_graph=default_tf_graph) + else: + raise RuntimeError(f"unknow model type {model_type}") + + return dp diff --git a/deepmd/infer/deep_dipole.py b/deepmd/infer/deep_dipole.py index 078306eadc..e3eb62a6b4 100644 --- a/deepmd/infer/deep_dipole.py +++ b/deepmd/infer/deep_dipole.py @@ -1,25 +1,43 @@ -#!/usr/bin/env python3 - -from typing import Tuple, List from deepmd.infer.deep_eval import DeepTensor -class DeepDipole (DeepTensor) : - def __init__(self, - model_file : str, - load_prefix : str = 'load', - default_tf_graph : bool = False + +class DeepDipole(DeepTensor): + """Constructor. + + Parameters + ---------- + model_file : str + The name of the frozen model file. + load_prefix: str + The prefix in the load computational graph + default_tf_graph : bool + If uses the default tf graph, otherwise build a new tf graph for evaluation + """ + + def __init__( + self, model_file: str, load_prefix: str = "load", default_tf_graph: bool = False ) -> None: - """ - Constructor - - Parameters - ---------- - model_file : str - The name of the frozen model file. - load_prefix: str - The prefix in the load computational graph - default_tf_graph : bool - If uses the default tf graph, otherwise build a new tf graph for evaluation - """ - DeepTensor.__init__(self, model_file, 'dipole', 3, load_prefix = load_prefix, default_tf_graph = default_tf_graph) + self.tensors.update( + { + "t_sel_type": "model_attr/sel_type:0", + # output tensor + "t_tensor": "o_dipole:0", + } + ) + + DeepTensor.__init__( + self, + model_file, + 3, + load_prefix=load_prefix, + default_tf_graph=default_tf_graph, + ) + + def get_dim_fparam(self) -> int: + """Unsupported in this model.""" + raise NotImplementedError("This model type does not support this attribute") + + def get_dim_aparam(self) -> int: + """Unsupported in this model.""" + raise NotImplementedError("This model type does not support this attribute") diff --git a/deepmd/infer/deep_eval.py b/deepmd/infer/deep_eval.py index f80e59c9b8..b51d9248ec 100644 --- a/deepmd/infer/deep_eval.py +++ b/deepmd/infer/deep_eval.py @@ -1,68 +1,261 @@ -#!/usr/bin/env python3 -import platform import os -import numpy as np -from typing import Tuple, List +from typing import List, Optional -from deepmd.env import tf -from deepmd.env import default_tf_session_config +import numpy as np from deepmd.common import make_default_mesh +from deepmd.env import default_tf_session_config, tf -class DeepEval(): - """ - common methods for DeepPot, DeepWFC, DeepPolar, ... - """ - def __init__(self, - model_file, - load_prefix = 'load', - default_tf_graph = False) : - self.graph = self._load_graph (model_file, prefix = load_prefix, default_tf_graph = default_tf_graph) - t_mt = self.graph.get_tensor_by_name(os.path.join(load_prefix, 'model_attr/model_type:0')) - sess = tf.Session (graph = self.graph, config=default_tf_session_config) - [mt] = sess.run([t_mt], feed_dict = {}) - self.model_type = mt.decode('utf-8') - - def _load_graph(self, - frozen_graph_filename, - prefix = 'load', - default_tf_graph = False): - # We load the protobuf file from the disk and parse it to retrieve the + +class DeepEval: + """Common methods for DeepPot, DeepWFC, DeepPolar, ...""" + + _model_type: Optional[str] + + def __init__( + self, model_file: str, load_prefix: str = "load", default_tf_graph: bool = False + ): + self.graph = self._load_graph( + model_file, prefix=load_prefix, default_tf_graph=default_tf_graph + ) + + @property + def model_type(self) -> str: + + if not self._model_type: + t_mt = self._get_tensor("model_attr/model_type:0") + sess = tf.Session(graph=self.graph, config=default_tf_session_config) + [mt] = sess.run([t_mt], feed_dict={}) + self._model_type = mt.decode("utf-8") + + return self._model_type + + def _get_tensor( + self, tensor_name: str, attr_name: Optional[str] = None + ) -> tf.Tensor: + """Get TF graph tensor and assign it to class namespace. + + Parameters + ---------- + tensor_name : str + name of tensor to get + attr_name : Optional[str], optional + if specified, class attribute with this name will be created and tensor will + be assigned to it, by default None + + Returns + ------- + tf.Tensor + loaded tensor + """ + tensor_path = os.path.join(self.load_prefix, tensor_name) + tensor = self.graph.get_tensor_by_name(tensor_path) + if attr_name: + setattr(self, attr_name, tensor) + return tensor + else: + return tensor + + @staticmethod + def _load_graph( + frozen_graph_filename: str, prefix: str = "load", default_tf_graph: bool = False + ): + # We load the protobuf file from the disk and parse it to retrieve the # unserialized graph_def with tf.gfile.GFile(frozen_graph_filename, "rb") as f: graph_def = tf.GraphDef() graph_def.ParseFromString(f.read()) - if default_tf_graph: - tf.import_graph_def( - graph_def, - input_map=None, - return_elements=None, - name=prefix, - producer_op_list=None - ) - graph = tf.get_default_graph() - else : - # Then, we can use again a convenient built-in function to import a graph_def into the - # current default Graph - with tf.Graph().as_default() as graph: + if default_tf_graph: tf.import_graph_def( - graph_def, - input_map=None, - return_elements=None, - name=prefix, + graph_def, + input_map=None, + return_elements=None, + name=prefix, producer_op_list=None ) - # for ii in graph.as_graph_def().node: - # print(ii.name) + graph = tf.get_default_graph() + else : + # Then, we can use again a convenient built-in function to import + # a graph_def into the current default Graph + with tf.Graph().as_default() as graph: + tf.import_graph_def( + graph_def, + input_map=None, + return_elements=None, + name=prefix, + producer_op_list=None + ) + + return graph + +class DeepTensor(DeepEval): + """Evaluates a tensor model. + + Constructor + + Parameters + ---------- + model_file: str + The name of the frozen model file. + variable_dof: int + The DOF of the variable to evaluate. + load_prefix: str + The prefix in the load computational graph + default_tf_graph : bool + If uses the default tf graph, otherwise build a new tf graph for evaluation + """ - return graph + tensors = { + "t_ntypes": "descrpt_attr/ntypes:0", + "t_rcut": "descrpt_attr/rcut:0", + "t_tmap": "model_attr/tmap:0", + # inputs + "t_coord": "t_coord:0", + "t_type": "t_type:0", + "t_natoms": "t_natoms:0", + "t_box": "t_box:0", + "t_mesh": "t_mesh:0", + } + + def __init__( + self, + model_file: str, + variable_dof: Optional[int], + load_prefix: str = 'load', + default_tf_graph: bool = False + ) -> None: + DeepEval.__init__( + self, + model_file, + load_prefix=load_prefix, + default_tf_graph=default_tf_graph + ) + self.variable_dof = variable_dof + self.load_prefix = load_prefix + + # now load tensors to object attributes + for attr_name, tensor_name in self.tensors.items(): + self._get_tensor(tensor_name, attr_name) + + # start a tf session associated to the graph + self.sess = tf.Session(graph=self.graph, config=default_tf_session_config) + self._run_default_sess() + self.tmap = self.tmap.decode('UTF-8').split() + def _run_default_sess(self): + [self.ntypes, self.rcut, self.tmap, self.tselt] = self.sess.run( + [self.t_ntypes, self.t_rcut, self.t_tmap, self.t_sel_type] + ) + + def get_ntypes(self) -> int: + """Get the number of atom types of this model.""" + return self.ntypes + + def get_rcut(self) -> float: + """Get the cut-off radius of this model.""" + return self.rcut + + def get_type_map(self) -> List[int]: + """Get the type map (element name of the atom types) of this model.""" + return self.tmap + + def get_sel_type(self) -> List[int]: + """Get the selected atom types of this model.""" + return self.tselt + + def get_dim_fparam(self) -> int: + """Get the number (dimension) of frame parameters of this DP.""" + return self.dfparam + + def get_dim_aparam(self) -> int: + """Get the number (dimension) of atomic parameters of this DP.""" + return self.daparam + + def eval( + self, + coords: np.array, + cells: np.array, + atom_types: List[int], + atomic: bool = True, + fparam: Optional[np.array] = None, + aparam: Optional[np.array] = None, + efield: Optional[np.array] = None + ) -> np.array: + """Evaluate the model. + + Parameters + ---------- + coords + The coordinates of atoms. + The array should be of size nframes x natoms x 3 + cells + The cell of the region. + If None then non-PBC is assumed, otherwise using PBC. + The array should be of size nframes x 9 + atom_types + The atom types + The list should contain natoms ints + atomic + Calculate the atomic energy and virial + fparam + Not used in this model + aparam + Not used in this model + efield + Not used in this model + + Returns + ------- + tensor + The returned tensor + If atomic == False then of size nframes x variable_dof + else of size nframes x natoms x variable_dof + """ + # standarize the shape of inputs + coords = np.array(coords) + cells = np.array(cells) + atom_types = np.array(atom_types, dtype = int) + + # reshape the inputs + cells = np.reshape(cells, [-1, 9]) + nframes = cells.shape[0] + coords = np.reshape(coords, [nframes, -1]) + natoms = coords.shape[1] // 3 + + # sort inputs + coords, atom_types, imap, sel_at, sel_imap = self.sort_input(coords, atom_types, sel_atoms = self.get_sel_type()) + + # make natoms_vec and default_mesh + natoms_vec = self.make_natoms_vec(atom_types) + assert(natoms_vec[0] == natoms) + + # evaluate + tensor = [] + feed_dict_test = {} + feed_dict_test[self.t_natoms] = natoms_vec + feed_dict_test[self.t_type ] = atom_types + t_out = [self.t_tensor] + for ii in range(nframes) : + feed_dict_test[self.t_coord] = np.reshape(coords[ii:ii+1, :], [-1]) + feed_dict_test[self.t_box ] = np.reshape(cells [ii:ii+1, :], [-1]) + feed_dict_test[self.t_mesh ] = make_default_mesh(cells[ii:ii+1, :]) + v_out = self.sess.run (t_out, feed_dict = feed_dict_test) + tensor.append(v_out[0]) + + # reverse map of the outputs + if atomic: + tensor = np.array(tensor) + tensor = self.reverse_map(np.reshape(tensor, [nframes,-1,self.variable_dof]), sel_imap) + tensor = np.reshape(tensor, [nframes, len(sel_at), self.variable_dof]) + else: + tensor = np.reshape(tensor, [nframes, self.variable_dof]) + + return tensor - def sort_input(self, - coord : np.array, - atom_type : np.array, - sel_atoms : List[int] = None - ) : + @staticmethod + def sort_input( + coord : np.array, atom_type : np.array, sel_atoms : List[int] = None + ): """ Sort atoms in the system according their types. @@ -114,13 +307,9 @@ def sort_input(self, else: return coord, atom_type, idx_map - - def reverse_map(self, - vec : np.array, - imap : List[int] - ) -> np.array: - """ - Reverse mapping of a vector according to the index map + @staticmethod + def reverse_map(vec : np.ndarray, imap : List[int]) -> np.ndarray: + """Reverse mapping of a vector according to the index map Parameters ---------- @@ -138,13 +327,9 @@ def reverse_map(self, for idx,ii in enumerate(imap) : ret[:,ii,:] = vec[:,idx,:] return ret - - def make_natoms_vec(self, - atom_types : np.array - ) -> np.array : - """ - Make the natom vector used by deepmd-kit + def make_natoms_vec(self, atom_types : np.ndarray) -> np.ndarray : + """Make the natom vector used by deepmd-kit. Parameters ---------- @@ -168,151 +353,3 @@ def make_natoms_vec(self, natoms_vec[ii+2] = np.count_nonzero(atom_types == ii) return natoms_vec - -class DeepTensor(DeepEval) : - """ - Evaluates a tensor model - """ - def __init__(self, - model_file : str, - variable_name : str, - variable_dof : int, - load_prefix : str = 'load', - default_tf_graph : bool = False - ) -> None : - """ - Constructor - - Parameters - ---------- - model_file : str - The name of the frozen model file. - variable_name : str - The name of the variable to evaluate. - variable_dof : - The DOF of the variable to evaluate. - load_prefix: str - The prefix in the load computational graph - default_tf_graph : bool - If uses the default tf graph, otherwise build a new tf graph for evaluation - """ - DeepEval.__init__(self, model_file, load_prefix = load_prefix, default_tf_graph = default_tf_graph) - # self.model_file = model_file - # self.graph = self.load_graph (self.model_file) - self.variable_name = variable_name - self.variable_dof = variable_dof - # checkout input/output tensors from graph - self.t_ntypes = self.graph.get_tensor_by_name (os.path.join(load_prefix, 'descrpt_attr/ntypes:0')) - self.t_rcut = self.graph.get_tensor_by_name (os.path.join(load_prefix, 'descrpt_attr/rcut:0')) - self.t_tmap = self.graph.get_tensor_by_name (os.path.join(load_prefix, 'model_attr/tmap:0')) - self.t_sel_type= self.graph.get_tensor_by_name (os.path.join(load_prefix, 'model_attr/sel_type:0')) - # inputs - self.t_coord = self.graph.get_tensor_by_name (os.path.join(load_prefix, 't_coord:0')) - self.t_type = self.graph.get_tensor_by_name (os.path.join(load_prefix, 't_type:0')) - self.t_natoms = self.graph.get_tensor_by_name (os.path.join(load_prefix, 't_natoms:0')) - self.t_box = self.graph.get_tensor_by_name (os.path.join(load_prefix, 't_box:0')) - self.t_mesh = self.graph.get_tensor_by_name (os.path.join(load_prefix, 't_mesh:0')) - # outputs - self.t_tensor = self.graph.get_tensor_by_name (os.path.join(load_prefix, 'o_%s:0' % self.variable_name)) - # start a tf session associated to the graph - self.sess = tf.Session (graph = self.graph, config=default_tf_session_config) - [self.ntypes, self.rcut, self.tmap, self.tselt] = self.sess.run([self.t_ntypes, self.t_rcut, self.t_tmap, self.t_sel_type]) - self.tmap = self.tmap.decode('UTF-8').split() - - def get_ntypes(self) -> int: - """ - Get the number of atom types of this model - """ - return self.ntypes - - def get_rcut(self) -> float: - """ - Get the cut-off radius of this model - """ - return self.rcut - - def get_type_map(self) -> List[int]: - """ - Get the type map (element name of the atom types) of this model - """ - return self.tmap - - def get_sel_type(self) -> List[int]: - """ - Get the selected atom types of this model - """ - return self.tselt - - def eval(self, - coords : np.array, - cells : np.array, - atom_types : List[int], - atomic : bool = True - ) -> np.array: - """ - Evaluate the model - - Parameters - ---------- - coords - The coordinates of atoms. - The array should be of size nframes x natoms x 3 - cells - The cell of the region. - If None then non-PBC is assumed, otherwise using PBC. - The array should be of size nframes x 9 - atom_types - The atom types - The list should contain natoms ints - atomic - Calculate the atomic energy and virial - - Returns - ------- - tensor - The returned tensor - If atomic == False then of size nframes x variable_dof - else of size nframes x natoms x variable_dof - """ - # standarize the shape of inputs - coords = np.array(coords) - cells = np.array(cells) - atom_types = np.array(atom_types, dtype = int) - - # reshape the inputs - cells = np.reshape(cells, [-1, 9]) - nframes = cells.shape[0] - coords = np.reshape(coords, [nframes, -1]) - natoms = coords.shape[1] // 3 - - # sort inputs - coords, atom_types, imap, sel_at, sel_imap = self.sort_input(coords, atom_types, sel_atoms = self.get_sel_type()) - - # make natoms_vec and default_mesh - natoms_vec = self.make_natoms_vec(atom_types) - assert(natoms_vec[0] == natoms) - - # evaluate - tensor = [] - feed_dict_test = {} - feed_dict_test[self.t_natoms] = natoms_vec - feed_dict_test[self.t_type ] = atom_types - t_out = [self.t_tensor] - for ii in range(nframes) : - feed_dict_test[self.t_coord] = np.reshape(coords[ii:ii+1, :], [-1]) - feed_dict_test[self.t_box ] = np.reshape(cells [ii:ii+1, :], [-1]) - feed_dict_test[self.t_mesh ] = make_default_mesh(cells[ii:ii+1, :]) - v_out = self.sess.run (t_out, feed_dict = feed_dict_test) - tensor.append(v_out[0]) - - # reverse map of the outputs - if atomic: - tensor = np.array(tensor) - tensor = self.reverse_map(np.reshape(tensor, [nframes,-1,self.variable_dof]), sel_imap) - tensor = np.reshape(tensor, [nframes, len(sel_at), self.variable_dof]) - else: - tensor = np.reshape(tensor, [nframes, self.variable_dof]) - - return tensor - - diff --git a/deepmd/infer/deep_polar.py b/deepmd/infer/deep_polar.py index e9cb54fa77..8e7dcec017 100644 --- a/deepmd/infer/deep_polar.py +++ b/deepmd/infer/deep_polar.py @@ -1,68 +1,129 @@ -#!/usr/bin/env python3 - import numpy as np -from typing import Tuple, List +from typing import Optional, List from deepmd.infer.deep_eval import DeepTensor -class DeepPolar (DeepTensor) : - def __init__(self, - model_file : str, - default_tf_graph : bool = False + +class DeepPolar(DeepTensor): + """Constructor. + + Parameters + ---------- + model_file : str + The name of the frozen model file. + load_prefix: str + The prefix in the load computational graph + default_tf_graph : bool + If uses the default tf graph, otherwise build a new tf graph for evaluation + """ + + def __init__( + self, model_file: str, load_prefix: str = "load", default_tf_graph: bool = False ) -> None: - """ - Constructor - Parameters - ---------- - model_file : str - The name of the frozen model file. - default_tf_graph : bool - If uses the default tf graph, otherwise build a new tf graph for evaluation - """ - DeepTensor.__init__(self, model_file, 'polar', 9, default_tf_graph = default_tf_graph) + self.tensors.update( + { + "t_sel_type": "model_attr/sel_type:0", + # output tensor + "t_tensor": "o_polar:0", + } + ) + + DeepTensor.__init__( + self, + model_file, + 9, + load_prefix=load_prefix, + default_tf_graph=default_tf_graph, + ) + + def get_dim_fparam(self) -> int: + """Unsupported in this model.""" + raise NotImplementedError("This model type does not support this attribute") + + def get_dim_aparam(self) -> int: + """Unsupported in this model.""" + raise NotImplementedError("This model type does not support this attribute") - -class DeepGlobalPolar (DeepTensor) : - def __init__(self, - model_file : str, - default_tf_graph : bool = False + +class DeepGlobalPolar(DeepTensor): + """Constructor. + + Parameters + ---------- + model_file : str + The name of the frozen model file. + load_prefix: str + The prefix in the load computational graph + default_tf_graph : bool + If uses the default tf graph, otherwise build a new tf graph for evaluation + """ + + def __init__( + self, model_file: str, load_prefix: str = "load", default_tf_graph: bool = False ) -> None: - """ - Constructor - Parameters - ---------- - model_file : str - The name of the frozen model file. - default_tf_graph : bool - If uses the default tf graph, otherwise build a new tf graph for evaluation - """ - DeepTensor.__init__(self, model_file, 'global_polar', 9, default_tf_graph = default_tf_graph) + self.tensors.update( + { + "t_sel_type": "model_attr/sel_type:0", + # output tensor + "t_tensor": "o_global_polar:0", + } + ) + + DeepTensor.__init__( + self, + model_file, + 9, + load_prefix=load_prefix, + default_tf_graph=default_tf_graph, + ) - def eval(self, - coords : np.array, - cells : np.array, - atom_types : List[int], + def eval( + self, + coords: np.array, + cells: np.array, + atom_types: List[int], + atomic: bool = True, + fparam: Optional[np.array] = None, + aparam: Optional[np.array] = None, + efield: Optional[np.array] = None, ) -> np.array: - """ - Evaluate the model + """Evaluate the model. Parameters ---------- coords - The coordinates of atoms. - The array should be of size nframes x natoms x 3 + The coordinates of atoms. + The array should be of size nframes x natoms x 3 cells - The cell of the region. - If None then non-PBC is assumed, otherwise using PBC. - The array should be of size nframes x 9 + The cell of the region. + If None then non-PBC is assumed, otherwise using PBC. + The array should be of size nframes x 9 atom_types - The atom types - The list should contain natoms ints + The atom types + The list should contain natoms ints + atomic + Calculate the atomic energy and virial + fparam + Not used in this model + aparam + Not used in this model + efield + Not used in this model Returns ------- - polar - The system polarizability + tensor + The returned tensor + If atomic == False then of size nframes x variable_dof + else of size nframes x natoms x variable_dof """ - return DeepTensor.eval(self, coords, cells, atom_types, atomic = False) + return DeepTensor.eval(self, coords, cells, atom_types, atomic=False) + + def get_dim_fparam(self) -> int: + """Unsupported in this model.""" + raise NotImplementedError("This model type does not support this attribute") + + def get_dim_aparam(self) -> int: + """Unsupported in this model.""" + raise NotImplementedError("This model type does not support this attribute") diff --git a/deepmd/infer/deep_pot.py b/deepmd/infer/deep_pot.py index b051a66a5f..07b2116770 100644 --- a/deepmd/infer/deep_pot.py +++ b/deepmd/infer/deep_pot.py @@ -1,182 +1,174 @@ -#!/usr/bin/env python3 - import numpy as np -from typing import Tuple, List - -from deepmd.env import tf -from deepmd.env import default_tf_session_config +from typing import List, Optional, Tuple from deepmd.common import make_default_mesh from deepmd.infer.data_modifier import DipoleChargeModifier -from deepmd.infer.deep_eval import DeepEval +from deepmd.infer.deep_eval import DeepTensor +import logging + +log = logging.getLogger(__name__) + + +class DeepPot(DeepTensor): + """Constructor. + + Parameters + ---------- + model_file : str + The name of the frozen model file. + load_prefix: str + The prefix in the load computational graph + default_tf_graph : bool + If uses the default tf graph, otherwise build a new tf graph for evaluation + """ -class DeepPot (DeepEval) : - def __init__(self, - model_file : str, - default_tf_graph : bool = False + def __init__( + self, + model_file: str, + load_prefix: str = "load", + default_tf_graph: bool = False ) -> None: - """ - Constructor - Parameters - ---------- - model_file : str - The name of the frozen model file. - default_tf_graph : bool - If uses the default tf graph, otherwise build a new tf graph for evaluation - """ - DeepEval.__init__(self, model_file, default_tf_graph = default_tf_graph) - # self.model_file = model_file - # self.graph = self.load_graph (self.model_file) - # checkout input/output tensors from graph - self.t_ntypes = self.graph.get_tensor_by_name ('load/descrpt_attr/ntypes:0') - self.t_rcut = self.graph.get_tensor_by_name ('load/descrpt_attr/rcut:0') - self.t_dfparam= self.graph.get_tensor_by_name ('load/fitting_attr/dfparam:0') - self.t_daparam= self.graph.get_tensor_by_name ('load/fitting_attr/daparam:0') - self.t_tmap = self.graph.get_tensor_by_name ('load/model_attr/tmap:0') - # inputs - self.t_coord = self.graph.get_tensor_by_name ('load/t_coord:0') - self.t_type = self.graph.get_tensor_by_name ('load/t_type:0') - self.t_natoms = self.graph.get_tensor_by_name ('load/t_natoms:0') - self.t_box = self.graph.get_tensor_by_name ('load/t_box:0') - self.t_mesh = self.graph.get_tensor_by_name ('load/t_mesh:0') + # this tensor does not apply here so delete it + self.tensors.pop("t_sel_type") + + # add these tensors on top of what is defined by DeepTensor Class + self.tensors.update({ + # general + "t_dfparam": "fitting_attr/dfparam:0", + "t_daparam": "fitting_attr/daparam:0", + # add output tensors + "t_energy": "o_energy:0", + "t_force": "o_force:0", + "t_virial": "o_virial:0", + "t_ae": "o_atom_energy:0", + "t_av": "o_atom_virial:0" + }) + try: - self.t_efield = self.graph.get_tensor_by_name ('load/t_efield:0') + self._get_tensor("t_efield:0", "t_efield") self.has_efield = True - except: + except KeyError: + log.debug(f"Could not get tensor 't_efield:0'") self.t_efield = None self.has_efield = False - # outputs - self.t_energy = self.graph.get_tensor_by_name ('load/o_energy:0') - self.t_force = self.graph.get_tensor_by_name ('load/o_force:0') - self.t_virial = self.graph.get_tensor_by_name ('load/o_virial:0') - self.t_ae = self.graph.get_tensor_by_name ('load/o_atom_energy:0') - self.t_av = self.graph.get_tensor_by_name ('load/o_atom_virial:0') - self.t_fparam = None - self.t_aparam = None - # check if the graph has fparam - for op in self.graph.get_operations(): - if op.name == 'load/t_fparam' : - self.t_fparam = self.graph.get_tensor_by_name ('load/t_fparam:0') - self.has_fparam = self.t_fparam is not None + + # load optional tensors + operations = [op.name for op in self.graph.get_operations()] + + if 'load/t_fparam' in operations: + self.tensors.update({"t_fparam": "t_fparam:0"}) + self.has_fparam = True + else: + log.debug(f"Could not get tensor 't_fparam:0'") + self.t_fparam = None + self.has_fparam = False + # check if the graph has aparam - for op in self.graph.get_operations(): - if op.name == 'load/t_aparam' : - self.t_aparam = self.graph.get_tensor_by_name ('load/t_aparam:0') - self.has_aparam = self.t_aparam is not None - # start a tf session associated to the graph - self.sess = tf.Session (graph = self.graph, config=default_tf_session_config) - [self.ntypes, self.rcut, self.dfparam, self.daparam, self.tmap] = self.sess.run([self.t_ntypes, self.t_rcut, self.t_dfparam, self.t_daparam, self.t_tmap]) - self.tmap = self.tmap.decode('UTF-8').split() + if 'load/t_aparam' in operations: + self.tensors.update({"t_aparam": "t_aparam:0"}) + self.has_aparam = True + else: + log.debug(f"Could not get tensor 't_aparam:0'") + self.t_aparam = None + self.has_aparam = False + + # now when tensors are set initialize DeepTensor which will load them all + # to class attributes, the run session assciated with the graph + DeepTensor.__init__( + self, + model_file, + None, + load_prefix=load_prefix, + default_tf_graph=default_tf_graph + ) + # setup modifier try: - t_modifier_type = self.graph.get_tensor_by_name('load/modifier_attr/type:0') - self.modifier_type = self.sess.run(t_modifier_type).decode('UTF-8') - except ValueError: - self.modifier_type = None - except KeyError: + t_modifier_type = self._get_tensor("modifier_attr/type:0") + self.modifier_type = self.sess.run(t_modifier_type).decode("UTF-8") + except (ValueError, KeyError): self.modifier_type = None - if self.modifier_type == 'dipole_charge': - t_mdl_name = self.graph.get_tensor_by_name('load/modifier_attr/mdl_name:0') - t_mdl_charge_map = self.graph.get_tensor_by_name('load/modifier_attr/mdl_charge_map:0') - t_sys_charge_map = self.graph.get_tensor_by_name('load/modifier_attr/sys_charge_map:0') - t_ewald_h = self.graph.get_tensor_by_name('load/modifier_attr/ewald_h:0') - t_ewald_beta = self.graph.get_tensor_by_name('load/modifier_attr/ewald_beta:0') + + if self.modifier_type == "dipole_charge": + t_mdl_name = self._get_tensor("modifier_attr/mdl_name:0") + t_mdl_charge_map = self._get_tensor("modifier_attr/mdl_charge_map:0") + t_sys_charge_map = self._get_tensor("modifier_attr/sys_charge_map:0") + t_ewald_h = self._get_tensor("modifier_attr/ewald_h:0") + t_ewald_beta = self._get_tensor("modifier_attr/ewald_beta:0") [mdl_name, mdl_charge_map, sys_charge_map, ewald_h, ewald_beta] = self.sess.run([t_mdl_name, t_mdl_charge_map, t_sys_charge_map, t_ewald_h, t_ewald_beta]) - mdl_charge_map = [int(ii) for ii in mdl_charge_map.decode('UTF-8').split()] - sys_charge_map = [int(ii) for ii in sys_charge_map.decode('UTF-8').split()] + mdl_charge_map = [int(ii) for ii in mdl_charge_map.decode("UTF-8").split()] + sys_charge_map = [int(ii) for ii in sys_charge_map.decode("UTF-8").split()] self.dm = DipoleChargeModifier(mdl_name, mdl_charge_map, sys_charge_map, ewald_h = ewald_h, ewald_beta = ewald_beta) + def _run_default_sess(self): + [self.ntypes, self.rcut, self.dfparam, self.daparam, self.tmap] = self.sess.run( + [self.t_ntypes, self.t_rcut, self.t_dfparam, self.t_daparam, self.t_tmap] + ) - def get_ntypes(self) -> int: - """ - Get the number of atom types of this DP - """ - return self.ntypes - - def get_rcut(self) -> float: - """ - Get the cut-off radius of this DP - """ - return self.rcut - - def get_dim_fparam(self) -> int: - """ - Get the number (dimension) of frame parameters of this DP - """ - return self.dfparam - - def get_dim_aparam(self) -> int: - """ - Get the number (dimension) of atomic parameters of this DP - """ - return self.daparam - - def get_type_map(self) -> List[int]: - """ - Get the type map (element name of the atom types) of this DP - """ - return self.tmap + def get_sel_type(self) -> List[int]: + """Unsupported in this model.""" + raise NotImplementedError("This model type does not support this attribute") - def eval(self, - coords : np.array, - cells : np.array, - atom_types : List[int], - fparam : np.array = None, - aparam : np.array = None, - atomic : bool = False, - efield : np.array = None - ) : - """ - Evaluate the energy, force and virial by using this DP. + def eval( + self, + coords: np.array, + cells: np.array, + atom_types: List[int], + atomic: bool = False, + fparam: Optional[np.array] = None, + aparam: Optional[np.array] = None, + efield: Optional[np.array] = None + ) -> Tuple[np.ndarray, ...]: + """Evaluate the energy, force and virial by using this DP. Parameters ---------- coords - The coordinates of atoms. - The array should be of size nframes x natoms x 3 + The coordinates of atoms. + The array should be of size nframes x natoms x 3 cells - The cell of the region. - If None then non-PBC is assumed, otherwise using PBC. - The array should be of size nframes x 9 + The cell of the region. + If None then non-PBC is assumed, otherwise using PBC. + The array should be of size nframes x 9 atom_types - The atom types - The list should contain natoms ints + The atom types + The list should contain natoms ints + atomic + Calculate the atomic energy and virial fparam - The frame parameter. - The array can be of size : - - nframes x dim_fparam. - - dim_fparam. Then all frames are assumed to be provided with the same fparam. + The frame parameter. + The array can be of size : + - nframes x dim_fparam. + - dim_fparam. Then all frames are assumed to be provided with the same fparam. aparam - The atomic parameter - The array can be of size : - - nframes x natoms x dim_aparam. - - natoms x dim_aparam. Then all frames are assumed to be provided with the same aparam. - - dim_aparam. Then all frames and atoms are provided with the same aparam. - atomic - Calculate the atomic energy and virial + The atomic parameter + The array can be of size : + - nframes x natoms x dim_aparam. + - natoms x dim_aparam. Then all frames are assumed to be provided with the same aparam. + - dim_aparam. Then all frames and atoms are provided with the same aparam. efield - The external field on atoms. - The array should be of size nframes x natoms x 3 + The external field on atoms. + The array should be of size nframes x natoms x 3 Returns ------- - energy - The system energy. + energy + The system energy. force - The force on each atom + The force on each atom virial - The virial + The virial atom_energy - The atomic energy. Only returned when atomic == True + The atomic energy. Only returned when atomic == True atom_virial - The atomic virial. Only returned when atomic == True + The atomic virial. Only returned when atomic == True """ - if atomic : + if atomic: if self.modifier_type is not None: raise RuntimeError('modifier does not support atomic modification') - return self.eval_inner(coords, cells, atom_types, fparam = fparam, aparam = aparam, atomic = atomic, efield = efield) + return self._eval_inner(coords, cells, atom_types, fparam = fparam, aparam = aparam, atomic = atomic, efield = efield) else : - e, f, v = self.eval_inner(coords, cells, atom_types, fparam = fparam, aparam = aparam, atomic = atomic, efield = efield) + e, f, v = self._eval_inner(coords, cells, atom_types, fparam = fparam, aparam = aparam, atomic = atomic, efield = efield) if self.modifier_type is not None: me, mf, mv = self.dm.eval(coords, cells, atom_types) e += me.reshape(e.shape) @@ -184,14 +176,16 @@ def eval(self, v += mv.reshape(v.shape) return e, f, v - def eval_inner(self, - coords, - cells, - atom_types, - fparam = None, - aparam = None, - atomic = False, - efield = None) : + def _eval_inner( + self, + coords, + cells, + atom_types, + fparam=None, + aparam=None, + atomic=False, + efield=None + ): # standarize the shape of inputs atom_types = np.array(atom_types, dtype = int).reshape([-1]) natoms = atom_types.size @@ -297,5 +291,3 @@ def eval_inner(self, return energy, force, virial, ae, av else : return energy, force, virial - - diff --git a/deepmd/infer/deep_wfc.py b/deepmd/infer/deep_wfc.py index 98f443a027..bc097378fb 100644 --- a/deepmd/infer/deep_wfc.py +++ b/deepmd/infer/deep_wfc.py @@ -1,10 +1,42 @@ -#!/usr/bin/env python3 - from deepmd.infer.deep_eval import DeepTensor -class DeepWFC (DeepTensor) : - def __init__(self, - model_file, - default_tf_graph = False) : - DeepTensor.__init__(self, model_file, 'wfc', 12, default_tf_graph = default_tf_graph) +class DeepWFC(DeepTensor): + """Constructor. + + Parameters + ---------- + model_file : str + The name of the frozen model file. + load_prefix: str + The prefix in the load computational graph + default_tf_graph : bool + If uses the default tf graph, otherwise build a new tf graph for evaluation + """ + + def __init__( + self, model_file: str, load_prefix: str = "load", default_tf_graph: bool = False + ) -> None: + + self.tensors.update( + { + "t_sel_type": "model_attr/sel_type:0", + # output tensor + "t_tensor": "o_wfc:0", + } + ) + DeepTensor.__init__( + self, + model_file, + 12, + load_prefix=load_prefix, + default_tf_graph=default_tf_graph, + ) + + def get_dim_fparam(self) -> int: + """Unsupported in this model.""" + raise NotImplementedError("This model type does not support this attribute") + + def get_dim_aparam(self) -> int: + """Unsupported in this model.""" + raise NotImplementedError("This model type does not support this attribute") diff --git a/source/train/calculator.py b/source/train/calculator.py index e74ff2edb9..e9c8e63c7d 100644 --- a/source/train/calculator.py +++ b/source/train/calculator.py @@ -2,7 +2,7 @@ from typing import TYPE_CHECKING, Dict, List, Optional, Union -from deepmd import DeepPot +from deepmd import DeepPotential from ase.calculators.calculator import Calculator, all_changes if TYPE_CHECKING: From a371dcfadcc1db25ba08f41cf28d51735be2b2fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Tue, 16 Feb 2021 19:01:35 +0100 Subject: [PATCH 167/562] bugfix in for log hnadles --- source/train/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/train/main.py b/source/train/main.py index a48e5e7473..5c3f417731 100644 --- a/source/train/main.py +++ b/source/train/main.py @@ -257,7 +257,7 @@ def main(): # log handles for train will be set separatelly # when the use of MPI will be determined in `RunOptions` if args.command not in (None, "train"): - set_log_handles(args.log_level, Path(args.log_path)) + set_log_handles(args.log_level, Path(args.log_path) if args.log_path else None) if args.command is None: parser.print_help() From bc74e10353a1ebe8073847fb3776d0cb718c7e87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Tue, 16 Feb 2021 21:01:25 +0100 Subject: [PATCH 168/562] add pathlib option to potential factory --- deepmd/infer/__init__.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/deepmd/infer/__init__.py b/deepmd/infer/__init__.py index a9c8bc6e67..b76fbf1b7e 100644 --- a/deepmd/infer/__init__.py +++ b/deepmd/infer/__init__.py @@ -1,12 +1,14 @@ """Submodule containing all the implemented potentials.""" +from pathlib import Path from typing import Union + +from .data_modifier import DipoleChargeModifier from .deep_dipole import DeepDipole from .deep_eval import DeepEval from .deep_polar import DeepGlobalPolar, DeepPolar from .deep_pot import DeepPot from .deep_wfc import DeepWFC -from .data_modifier import DipoleChargeModifier from .ewald_recp import EwaldRecp __all__ = [ @@ -23,7 +25,9 @@ def DeepPotential( - model_file: str, load_prefix: str = "load", default_tf_graph: bool = False + model_file: Union[str, Path], + load_prefix: str = "load", + default_tf_graph: bool = False, ) -> Union[DeepDipole, DeepGlobalPolar, DeepPolar, DeepPot, DeepWFC]: """Factory function that will inialize appropriate potential read from `model_file`. @@ -47,7 +51,7 @@ def DeepPotential( if model file does not correspond to any implementd potential """ model_type = DeepEval( - model_file, load_prefix=load_prefix, default_tf_graph=default_tf_graph + str(model_file), load_prefix=load_prefix, default_tf_graph=default_tf_graph ).model_type if model_type == "ener": From faa6b0bea33fab6ace5fe62ad6ea060a538ee367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Wed, 17 Feb 2021 20:04:10 +0100 Subject: [PATCH 169/562] get rid of args object passed to entrypoint scripts, it is not transparent. Unpack arguments instead and send them as keywords. Rewrite entrypoint scripts to reflect that --- deepmd/entrypoints/compress.py | 107 +-- deepmd/entrypoints/config.py | 29 +- deepmd/entrypoints/freeze.py | 44 +- deepmd/entrypoints/print_old_model.py | 2 +- deepmd/entrypoints/test.py | 751 ++++++++++++++------- deepmd/entrypoints/train.py | 26 +- deepmd/entrypoints/transform.py | 10 +- source/tests/test_data_modifier.py | 19 +- source/tests/test_data_modifier_shuffle.py | 19 +- source/tests/test_get_potential.py | 35 + source/tests/test_model_loc_frame.py | 2 - source/tests/test_model_se_a.py | 2 - source/tests/test_model_se_a_aparam.py | 2 - source/tests/test_model_se_a_fparam.py | 2 - source/tests/test_model_se_a_srtab.py | 2 - source/tests/test_model_se_r.py | 2 - source/tests/test_polar_se_a.py | 2 - source/tests/test_wfc.py | 2 - source/train/main.py | 66 +- source/train/run_options.py | 61 +- 20 files changed, 735 insertions(+), 450 deletions(-) create mode 100644 source/tests/test_get_potential.py diff --git a/deepmd/entrypoints/compress.py b/deepmd/entrypoints/compress.py index 61c798f453..369553473f 100644 --- a/deepmd/entrypoints/compress.py +++ b/deepmd/entrypoints/compress.py @@ -1,9 +1,8 @@ """Compress a model, which including tabulating the embedding-net.""" -import copy import json import logging -from typing import TYPE_CHECKING, Optional +from typing import Optional from deepmd.common import j_loader from deepmd.utils.argcheck import normalize @@ -13,34 +12,25 @@ from .train import train from .transform import transform -if TYPE_CHECKING: - try: - from typing import Protocol # python >=3.8 - except ImportError: - from typing_extensions import Protocol # type: ignore - - class ArgsProto(Protocol): - """Prococol mimicking parser object.""" - - INPUT: str - input: str - output: str - extrapolate: str - stride: float - frequency: str - checkpoint_folder: str - init_model: Optional[str] - restart: Optional[str] - nodes: Optional[str] - old_model: str - raw_model: str - __all__ = ["compress"] log = logging.getLogger(__name__) -def compress(args: "ArgsProto"): +def compress( + *, + INPUT: str, + input: str, + output: str, + extrapolate: int, + stride: float, + frequency: str, + checkpoint_folder: str, + mpi_log: str, + log_path: Optional[str], + log_level: int, + **kwargs +): """Compress model. The table is composed of fifth-order polynomial coefficients and is assembled from @@ -51,21 +41,39 @@ def compress(args: "ArgsProto"): Parameters ---------- - args : ArgsProto - arguments object + INPUT : str + input json/yaml control file + input : str + frozen model file to compress + output : str + compressed model filename + extrapolate : int + scale of model extrapolation + stride : float + uniform stride of tabulation's first table + frequency : str + frequency of tabulation overflow check + checkpoint_folder : str + trining checkpoint folder for freezing + mpi_log : str + mpi logging mode for training + log_path : Optional[str] + if speccified log will be written to this file + log_level : int + logging level """ - jdata = j_loader(args.INPUT) + jdata = j_loader(INPUT) if "model" not in jdata.keys(): jdata = convert_input_v0_v1(jdata, warning=True, dump="input_v1_compat.json") jdata = normalize(jdata) jdata["model"]["compress"] = {} jdata["model"]["compress"]["compress"] = True - jdata["model"]["compress"]["model_file"] = args.input + jdata["model"]["compress"]["model_file"] = input jdata["model"]["compress"]["table_config"] = [ - args.extrapolate, - args.stride, - 10 * args.stride, - int(args.frequency), + extrapolate, + stride, + 10 * stride, + int(frequency), ] # check the descriptor info of the input file @@ -79,30 +87,27 @@ def compress(args: "ArgsProto"): # stage 1: training or refining the model with tabulation log.info("\n\n") log.info("stage 1: train or refine the model with tabulation") - args_train = copy.deepcopy(args) - args_train.INPUT = "compress.json" - args_train.output = "compress.json" - args_train.init_model = None - args_train.restart = None - jdata["training"]["stop_batch"] = jdata["training"][ - "save_freq" - ] # be careful here, if one want to refine the model - with open(args_train.INPUT, "w") as fp: + # be careful here, if one want to refine the model + jdata["training"]["stop_batch"] = jdata["training"]["save_freq"] + control_file = "compress.json" + with open(control_file, "w") as fp: json.dump(jdata, fp, indent=4) - train(args_train) + train( + INPUT=control_file, + init_model=None, + restart=None, + output=control_file, + mpi_log=mpi_log, + log_level=log_level, + log_path=log_path, + ) # stage 2: freeze the model log.info("\n\n") log.info("stage 2: freeze the model") - args_frz = copy.deepcopy(args) - args_frz.nodes = None - freeze(args_frz) + freeze(checkpoint_folder=checkpoint_folder, output=output, node_names=None) # stage 3: transform the model log.info("\n\n") log.info("stage 3: transform the model") - args_transform = copy.deepcopy(args) - args_transform.old_model = args.input - args_transform.raw_model = args.output - args_transform.output = args.output - transform(args_transform) + transform(old_model=input, raw_model=output, output=output) diff --git a/deepmd/entrypoints/config.py b/deepmd/entrypoints/config.py index 8ffb2e2199..d5b2044d25 100644 --- a/deepmd/entrypoints/config.py +++ b/deepmd/entrypoints/config.py @@ -4,21 +4,10 @@ import json import yaml from pathlib import Path -from typing import Any, Dict, List, Tuple, TYPE_CHECKING +from typing import Any, Dict, List, Tuple import numpy as np -if TYPE_CHECKING: - try: - from typing import Protocol # python >=3.8 - except ImportError: - from typing_extensions import Protocol # type: ignore - - class ArgsProto(Protocol): - """Prococol mimicking parser object.""" - - output: str - __all__ = ["config"] @@ -81,9 +70,7 @@ def valid_dir(path: Path): raise OSError -def load_systems( - dirs: List[Path], -) -> Tuple[List[np.ndarray], List[np.ndarray]]: +def load_systems(dirs: List[Path]) -> Tuple[List[np.ndarray], List[np.ndarray]]: """Load systems to memory for disk. Parameters @@ -321,13 +308,13 @@ def suggest_decay(stop_batch: int) -> Tuple[int, float]: return decay_steps, decay_rate -def config(args: "ArgsProto"): +def config(*, output: str, **kwargs): """Auto config file generator. Parameters ---------- - args : ArgsProto - argparse:parser instance with output attribute + output: str + file to write config file Raises ------ @@ -358,10 +345,10 @@ def config(args: "ArgsProto"): jdata["decay_steps"] = decay_steps jdata["decay_rate"] = decay_rate - with open(args.output, "w") as fp: - if args.output.endswith("json"): + with open(output, "w") as fp: + if output.endswith("json"): json.dump(jdata, fp, indent=4) - elif args.output.endswith(("yml", "yaml")): + elif output.endswith(("yml", "yaml")): yaml.safe_dump(jdata, fp, default_flow_style=False) else: raise ValueError("output file must be of type json or yaml") diff --git a/deepmd/entrypoints/freeze.py b/deepmd/entrypoints/freeze.py index f4c742be1e..c42ae2f968 100755 --- a/deepmd/entrypoints/freeze.py +++ b/deepmd/entrypoints/freeze.py @@ -13,22 +13,7 @@ # load grad of force module import deepmd.op -from typing import List, Optional, TYPE_CHECKING - - -if TYPE_CHECKING: - try: - from typing import Protocol # python >=3.8 - except ImportError: - from typing_extensions import Protocol # type: ignore - - class ArgsProto(Protocol): - """Prococol mimicking parser object.""" - - checkpoint_folder: str - output: str - nodes: str - +from typing import List, Optional __all__ = ["freeze"] @@ -121,22 +106,22 @@ def _make_node_names(model_type: str, modifier_type: Optional[str] = None) -> Li return nodes -def freeze_graph( - model_folder: str, output: str, output_node_names: Optional[str] = None +def freeze( + *, checkpoint_folder: str, output: str, node_names: Optional[str] = None, **kwargs ): """Freeze the graph in supplied folder. Parameters ---------- - model_folder : str + checkpoint_folder : str location of the folder with model output : str output file name - output_node_names : Optional[str], optional + node_names : Optional[str], optional names of nodes to output, by default None """ # We retrieve our checkpoint fullpath - checkpoint = tf.train.get_checkpoint_state(model_folder) + checkpoint = tf.train.get_checkpoint_state(checkpoint_folder) input_checkpoint = checkpoint.model_checkpoint_path # expand the output file to full path @@ -146,7 +131,7 @@ def freeze_graph( # This is how TF decides what part of the Graph he has to keep # and what part it can dump # NOTE: this variable is plural, because you can have multiple output nodes - # output_node_names = "energy_test,force_test,virial_test,t_rcut" + # node_names = "energy_test,force_test,virial_test,t_rcut" # We clear devices to allow TensorFlow to control # on which device it will load operations @@ -172,10 +157,10 @@ def freeze_graph( ) else: modifier_type = None - if output_node_names is None: + if node_names is None: output_node_list = _make_node_names(model_type, modifier_type) else: - output_node_list = output_node_names.split(",") + output_node_list = node_names.split(",") print(f"The following nodes will be frozen: {output_node_list}") # We use a built-in TF helper to export variables to constants @@ -189,14 +174,3 @@ def freeze_graph( with tf.gfile.GFile(output_graph, "wb") as f: f.write(output_graph_def.SerializeToString()) print(f"{len(output_graph_def.node):d} ops in the final graph.") - - -def freeze(args: "ArgsProto"): - """Graph freeze script entry point. - - Parameters - ---------- - args : ArgsProto - parser instance - """ - freeze_graph(args.checkpoint_folder, args.output, args.nodes) diff --git a/deepmd/entrypoints/print_old_model.py b/deepmd/entrypoints/print_old_model.py index 0e8d65eba7..cf941b8e25 100644 --- a/deepmd/entrypoints/print_old_model.py +++ b/deepmd/entrypoints/print_old_model.py @@ -33,7 +33,7 @@ def gen_data() : def compute_efv(jfile): jdata = j_loader(jfile) - run_opt = RunOptions(None) + run_opt = RunOptions() systems = j_must_have(jdata, 'systems') set_pfx = j_must_have(jdata, 'set_prefix') batch_size = j_must_have(jdata, 'batch_size') diff --git a/deepmd/entrypoints/test.py b/deepmd/entrypoints/test.py index b8c5e450cc..a547725150 100644 --- a/deepmd/entrypoints/test.py +++ b/deepmd/entrypoints/test.py @@ -1,94 +1,165 @@ -#!/usr/bin/env python3 +"""Test trained DeePMD model.""" +import logging +from pathlib import Path +from typing import TYPE_CHECKING, List, Optional, Tuple -import re -import os -import sys -import argparse import numpy as np - -from deepmd.utils.data import DeepmdData +from deepmd import DeepPotential from deepmd.common import expand_sys_str -from deepmd import DeepEval -from deepmd import DeepPot -from deepmd import DeepDipole -from deepmd import DeepPolar -from deepmd import DeepGlobalPolar -from deepmd import DeepWFC -from tensorflow.python.framework import ops - -def test (args): - de = DeepEval(args.model) - all_sys = expand_sys_str(args.system) +from deepmd.utils.data import DeepmdData + +if TYPE_CHECKING: + from deepmd.infer import DeepDipole, DeepPolar, DeepPot, DeepWFC + from deepmd.infer.deep_eval import DeepTensor + + +log = logging.getLogger(__name__) + + +def test( + *, + model: str, + system: str, + set_prefix: str, + numb_test: int, + rand_seed: Optional[int], + shuffle_test: bool, + detail_file: str, + atomic_energy: bool, + **kwargs, +): + """Test model predictions. + + Parameters + ---------- + model : str + path where model is stored + system : str + system directory + set_prefix : str + string prefix of set + numb_test : int + munber of tests to do + rand_seed : Optional[int] + seed for random generator + shuffle_test : bool + whether to shuffle tests + detail_file : Optional[str] + file where test details will be output + atomic_energy : bool + whether per atom quantities should be computed + + Raises + ------ + RuntimeError + if no valid system was found + """ + all_sys = expand_sys_str(system) if len(all_sys) == 0: - print('Did not find valid system') + raise RuntimeError("Did not find valid system") err_coll = [] siz_coll = [] - if de.model_type == 'ener': - dp = DeepPot(args.model) - elif de.model_type == 'dipole': - dp = DeepDipole(args.model) - elif de.model_type == 'polar': - dp = DeepPolar(args.model) - elif de.model_type == 'global_polar': - dp = DeepGlobalPolar(args.model) - elif de.model_type == 'wfc': - dp = DeepWFC(args.model) - else : - raise RuntimeError('unknow model type '+de.model_type) - for cc,ii in enumerate(all_sys): - args.system = ii - print ("# ---------------output of dp test--------------- ") - print ("# testing system : " + ii) - if de.model_type == 'ener': - err, siz = test_ener(dp, args, append_detail = (cc!=0)) - elif de.model_type == 'dipole': - err, siz = test_dipole(dp, args) - elif de.model_type == 'polar': - err, siz = test_polar(dp, args, global_polar=False) - elif de.model_type == 'global_polar': - err, siz = test_polar(dp, args, global_polar=True) - elif de.model_type == 'wfc': - err, siz = test_wfc(dp, args) - else : - raise RuntimeError('unknow model type '+de.model_type) - print ("# ----------------------------------------------- ") + + # init random seed + if rand_seed is not None: + np.random.seed(rand_seed % (2 ** 32)) + + # init model + dp = DeepPotential(model) + + for cc, system in enumerate(all_sys): + log.info("# ---------------output of dp test--------------- ") + log.info(f"# testing system : {system}") + + # create data class + tmap = dp.get_type_map() if dp.model_type == "ener" else None + data = DeepmdData(system, set_prefix, shuffle_test=shuffle_test, type_map=tmap) + + if dp.model_type == "ener": + err, siz = test_ener( + dp, + data, + system, + numb_test, + detail_file, + atomic_energy, + append_detail=(cc != 0), + ) + elif dp.model_type == "dipole": + err, siz = test_dipole(dp, data, numb_test, detail_file) + elif dp.model_type == "polar": + err, siz = test_polar(dp, data, numb_test, detail_file, global_polar=False) + elif dp.model_type == "global_polar": + err, siz = test_polar(dp, data, numb_test, detail_file, global_polar=True) + elif dp.model_type == "wfc": + err, siz = test_wfc(dp, data, numb_test, detail_file) + log.info("# ----------------------------------------------- ") err_coll.append(err) siz_coll.append(siz) + avg_err = weighted_average(err_coll, siz_coll) + if len(all_sys) != len(err_coll): - print('Not all systems are tested! Check if the systems are valid') + log.warning("Not all systems are tested! Check if the systems are valid") + if len(all_sys) > 1: - print ("# ----------weighted average of errors----------- ") - print ("# number of systems : %d" % len(all_sys)) - if de.model_type == 'ener': + log.info("# ----------weighted average of errors----------- ") + log.info(f"# number of systems : {len(all_sys)}") + if dp.model_type == "ener": print_ener_sys_avg(avg_err) - elif de.model_type == 'dipole': + elif dp.model_type == "dipole": print_dipole_sys_avg(avg_err) - elif de.model_type == 'polar': + elif dp.model_type == "polar": print_polar_sys_avg(avg_err) - elif de.model_type == 'global_polar': + elif dp.model_type == "global_polar": print_polar_sys_avg(avg_err) - elif de.model_type == 'wfc': + elif dp.model_type == "wfc": print_wfc_sys_avg(avg_err) - else : - raise RuntimeError('unknow model type '+de.model_type) - print ("# ----------------------------------------------- ") + log.info("# ----------------------------------------------- ") + + +def l2err(diff: np.ndarray) -> np.ndarray: + """Calculate average l2 norm error. + + Parameters + ---------- + diff: np.ndarray + difference + + Returns + ------- + np.ndarray + array with normalized difference + """ + return np.sqrt(np.average(diff * diff)) -def l2err (diff) : - return np.sqrt(np.average (diff*diff)) +def weighted_average( + err_coll: List[List[np.ndarray]], siz_coll: List[List[int]] +) -> np.ndarray: + """Compute wighted average of prediction errors for model. + Parameters + ---------- + err_coll : List[List[np.ndarray]] + each item in list represents erros for one model + siz_coll : List[List[int]] + weight for each model errors + + Returns + ------- + np.ndarray + weighted averages + """ + assert len(err_coll) == len(siz_coll) -def weighted_average(err_coll, siz_coll): - nsys = len(err_coll) nitems = len(err_coll[0]) - assert(len(err_coll) == len(siz_coll)) sum_err = np.zeros(nitems) sum_siz = np.zeros(nitems) for sys_error, sys_size in zip(err_coll, siz_coll): for ii in range(nitems): ee = sys_error[ii] - ss = sys_size [ii] + ss = sys_size[ii] sum_err[ii] += ee * ee * ss sum_siz[ii] += ss for ii in range(nitems): @@ -96,233 +167,441 @@ def weighted_average(err_coll, siz_coll): return sum_err -def save_txt_file(fname, data, header = "", append = False): - fp = fname - if append : fp = open(fp, 'ab') - np.savetxt(fp, data, header = header) - if append : fp.close() - - -def test_ener (dp, args, append_detail = False) : - if args.rand_seed is not None : - np.random.seed(args.rand_seed % (2**32)) - has_atom_ener = args.atomic_energy - data = DeepmdData(args.system, args.set_prefix, shuffle_test = args.shuffle_test, type_map = dp.get_type_map()) - data.add('energy', 1, atomic=False, must=False, high_prec=True) - data.add('force', 3, atomic=True, must=False, high_prec=False) - data.add('virial', 9, atomic=False, must=False, high_prec=False) +def save_txt_file( + fname: Path, data: np.ndarray, header: str = "", append: bool = False +): + """Save numpy array to test file. + + Parameters + ---------- + fname : str + filename + data : np.ndarray + data to save to disk + header : str, optional + header string to use in file, by default "" + append : bool, optional + if true file will be appended insted of overwriting, by default False + """ + flags = "ab" if append else "w" + with fname.open(flags) as fp: + np.savetxt(fp, data, header=header) + + +def test_ener( + dp: "DeepPot", + data: DeepmdData, + system: str, + numb_test: int, + detail_file: Optional[str], + has_atom_ener: bool, + append_detail: bool = False, +) -> Tuple[List[np.ndarray], List[int]]: + """Test energy type model. + + Parameters + ---------- + dp : DeepPot + instance of deep potential + data: DeepmdData + data container object + system : str + system directory + numb_test : int + munber of tests to do + detail_file : Optional[str] + file where test details will be output + has_atom_ener : bool + whether per atom quantities should be computed + append_detail : bool, optional + if true append output detail file, by default False + + Returns + ------- + Tuple[List[np.ndarray], List[int]] + arrays with results and their shapes + """ + data.add("energy", 1, atomic=False, must=False, high_prec=True) + data.add("force", 3, atomic=True, must=False, high_prec=False) + data.add("virial", 9, atomic=False, must=False, high_prec=False) if dp.has_efield: - data.add('efield', 3, atomic=True, must=True, high_prec=False) + data.add("efield", 3, atomic=True, must=True, high_prec=False) if has_atom_ener: - data.add('atom_ener', 1, atomic=True, must=True, high_prec=False) + data.add("atom_ener", 1, atomic=True, must=True, high_prec=False) if dp.get_dim_fparam() > 0: - data.add('fparam', dp.get_dim_fparam(), atomic=False, must=True, high_prec=False) + data.add( + "fparam", dp.get_dim_fparam(), atomic=False, must=True, high_prec=False + ) if dp.get_dim_aparam() > 0: - data.add('aparam', dp.get_dim_aparam(), atomic=True, must=True, high_prec=False) + data.add("aparam", dp.get_dim_aparam(), atomic=True, must=True, high_prec=False) - test_data = data.get_test () + test_data = data.get_test() natoms = len(test_data["type"][0]) nframes = test_data["box"].shape[0] - numb_test = args.numb_test numb_test = min(nframes, numb_test) coord = test_data["coord"][:numb_test].reshape([numb_test, -1]) box = test_data["box"][:numb_test] if dp.has_efield: efield = test_data["efield"][:numb_test].reshape([numb_test, -1]) - else : + else: efield = None if not data.pbc: box = None atype = test_data["type"][0] if dp.get_dim_fparam() > 0: - fparam = test_data["fparam"][:numb_test] - else : + fparam = test_data["fparam"][:numb_test] + else: fparam = None if dp.get_dim_aparam() > 0: - aparam = test_data["aparam"][:numb_test] - else : + aparam = test_data["aparam"][:numb_test] + else: aparam = None - detail_file = args.detail_file - atomic = has_atom_ener - ret = dp.eval(coord, box, atype, fparam = fparam, aparam = aparam, atomic = atomic, efield = efield) + ret = dp.eval( + coord, + box, + atype, + fparam=fparam, + aparam=aparam, + atomic=has_atom_ener, + efield=efield, + ) energy = ret[0] - force = ret[1] + force = ret[1] virial = ret[2] - energy = energy.reshape([numb_test,1]) - force = force.reshape([numb_test,-1]) - virial = virial.reshape([numb_test,9]) - if atomic: + energy = energy.reshape([numb_test, 1]) + force = force.reshape([numb_test, -1]) + virial = virial.reshape([numb_test, 9]) + if has_atom_ener: ae = ret[3] av = ret[4] - ae = ae.reshape([numb_test,-1]) - av = av.reshape([numb_test,-1]) - - l2e = (l2err (energy - test_data["energy"][:numb_test].reshape([-1,1]))) - l2f = (l2err (force - test_data["force"] [:numb_test])) - l2v = (l2err (virial - test_data["virial"][:numb_test])) - l2ea= l2e/natoms - l2va= l2v/natoms + ae = ae.reshape([numb_test, -1]) + av = av.reshape([numb_test, -1]) + + l2e = l2err(energy - test_data["energy"][:numb_test].reshape([-1, 1])) + l2f = l2err(force - test_data["force"][:numb_test]) + l2v = l2err(virial - test_data["virial"][:numb_test]) + l2ea = l2e / natoms + l2va = l2v / natoms if has_atom_ener: - l2ae = (l2err(test_data['atom_ener'][:numb_test].reshape([-1]) - ae.reshape([-1]))) + l2ae = l2err( + test_data["atom_ener"][:numb_test].reshape([-1]) - ae.reshape([-1]) + ) # print ("# energies: %s" % energy) - print ("# number of test data : %d " % numb_test) - print ("Energy L2err : %e eV" % l2e) - print ("Energy L2err/Natoms : %e eV" % l2ea) - print ("Force L2err : %e eV/A" % l2f) - print ("Virial L2err : %e eV" % l2v) - print ("Virial L2err/Natoms : %e eV" % l2va) + log.info(f"# number of test data : {numb_test:d} ") + log.info(f"Energy L2err : {l2e:e} eV") + log.info(f"Energy L2err/Natoms : {l2ea:e} eV") + log.info(f"Force L2err : {l2f:e} eV/A") + log.info(f"Virial L2err : {l2v:e} eV") + log.info(f"Virial L2err/Natoms : {l2va:e} eV") if has_atom_ener: - print ("Atomic ener L2err : %e eV" % l2ae) - - if detail_file is not None : - pe = np.concatenate((np.reshape(test_data["energy"][:numb_test], [-1,1]), - np.reshape(energy, [-1,1])), - axis = 1) - save_txt_file(detail_file+".e.out", pe, - header = '%s: data_e pred_e' % args.system, - append = append_detail) - pf = np.concatenate((np.reshape(test_data["force"] [:numb_test], [-1,3]), - np.reshape(force, [-1,3])), - axis = 1) - save_txt_file(detail_file+".f.out", pf, - header = '%s: data_fx data_fy data_fz pred_fx pred_fy pred_fz' % args.system, - append = append_detail) - pv = np.concatenate((np.reshape(test_data["virial"][:numb_test], [-1,9]), - np.reshape(virial, [-1,9])), - axis = 1) - save_txt_file(detail_file+".v.out", pv, - header = '%s: data_vxx data_vxy data_vxz data_vyx data_vyy data_vyz data_vzx data_vzy data_vzz pred_vxx pred_vxy pred_vxz pred_vyx pred_vyy pred_vyz pred_vzx pred_vzy pred_vzz' % args.system, - append = append_detail) + log.info(f"Atomic ener L2err : {l2ae:e} eV") + + if detail_file is not None: + detail_path = Path(detail_file) + + pe = np.concatenate( + ( + np.reshape(test_data["energy"][:numb_test], [-1, 1]), + np.reshape(energy, [-1, 1]), + ), + axis=1, + ) + save_txt_file( + detail_path.with_suffix(".e.out"), + pe, + header="%s: data_e pred_e" % system, + append=append_detail, + ) + pf = np.concatenate( + ( + np.reshape(test_data["force"][:numb_test], [-1, 3]), + np.reshape(force, [-1, 3]), + ), + axis=1, + ) + save_txt_file( + detail_path.with_suffix(".f.out"), + pf, + header="%s: data_fx data_fy data_fz pred_fx pred_fy pred_fz" % system, + append=append_detail, + ) + pv = np.concatenate( + ( + np.reshape(test_data["virial"][:numb_test], [-1, 9]), + np.reshape(virial, [-1, 9]), + ), + axis=1, + ) + save_txt_file( + detail_path.with_suffix(".v.out"), + pv, + header=f"{system}: data_vxx data_vxy data_vxz data_vyx data_vyy " + "data_vyz data_vzx data_vzy data_vzz pred_vxx pred_vxy pred_vxz pred_vyx " + "pred_vyy pred_vyz pred_vzx pred_vzy pred_vzz", + append=append_detail, + ) return [l2ea, l2f, l2va], [energy.size, force.size, virial.size] -def print_ener_sys_avg(avg): - print ("Energy L2err/Natoms : %e eV" % avg[0]) - print ("Force L2err : %e eV/A" % avg[1]) - print ("Virial L2err/Natoms : %e eV" % avg[2]) - - -def test_wfc (dp, args) : - if args.rand_seed is not None : - np.random.seed(args.rand_seed % (2**32)) - - data = DeepmdData(args.system, args.set_prefix, shuffle_test = args.shuffle_test) - data.add('wfc', 12, atomic=True, must=True, high_prec=False, type_sel = dp.get_sel_type()) - test_data = data.get_test () - numb_test = args.numb_test - natoms = len(test_data["type"][0]) +def print_ener_sys_avg(avg: np.ndarray): + """Print errors summary for energy type potential. + + Parameters + ---------- + avg : np.ndarray + array with summaries + """ + log.info(f"Energy L2err/Natoms : {avg[0]:e} eV") + log.info(f"Force L2err : {avg[1]:e} eV/A") + log.info(f"Virial L2err/Natoms : {avg[2]:e} eV") + + +def run_test(dp: "DeepTensor", test_data: dict, numb_test: int): + """Run tests. + + Parameters + ---------- + dp : DeepTensor + instance of deep potential + test_data : dict + dictionary with test data + numb_test : int + munber of tests to do + + Returns + ------- + [type] + [description] + """ nframes = test_data["box"].shape[0] numb_test = min(nframes, numb_test) - + coord = test_data["coord"][:numb_test].reshape([numb_test, -1]) box = test_data["box"][:numb_test] atype = test_data["type"][0] - wfc = dp.eval(coord, box, atype) - - wfc = wfc.reshape([numb_test,-1]) - l2f = (l2err (wfc - test_data["wfc"] [:numb_test])) - - print ("# number of test data : %d " % numb_test) - print ("WFC L2err : %e eV/A" % l2f) - - detail_file = args.detail_file - if detail_file is not None : - pe = np.concatenate((np.reshape(test_data["wfc"][:numb_test], [-1,12]), - np.reshape(wfc, [-1,12])), - axis = 1) - np.savetxt(detail_file+".out", pe, - header = 'ref_wfc(12 dofs) predicted_wfc(12 dofs)') + prediction = dp.eval(coord, box, atype) + + return prediction.reshape([numb_test, -1]), numb_test, atype + + +def test_wfc( + dp: "DeepWFC", + data: DeepmdData, + numb_test: int, + detail_file: Optional[str], +) -> Tuple[List[np.ndarray], List[int]]: + """Test energy type model. + + Parameters + ---------- + dp : DeepPot + instance of deep potential + data: DeepmdData + data container object + numb_test : int + munber of tests to do + detail_file : Optional[str] + file where test details will be output + + Returns + ------- + Tuple[List[np.ndarray], List[int]] + arrays with results and their shapes + """ + data.add( + "wfc", 12, atomic=True, must=True, high_prec=False, type_sel=dp.get_sel_type() + ) + test_data = data.get_test() + wfc, numb_test, _ = run_test(dp, test_data, numb_test) + l2f = l2err(wfc - test_data["wfc"][:numb_test]) + + log.info("# number of test data : {numb_test:d} ") + log.info("WFC L2err : {l2f:e} eV/A") + + if detail_file is not None: + detail_path = Path(detail_file) + pe = np.concatenate( + ( + np.reshape(test_data["wfc"][:numb_test], [-1, 12]), + np.reshape(wfc, [-1, 12]), + ), + axis=1, + ) + np.savetxt( + detail_path.with_suffix(".out"), + pe, + header="ref_wfc(12 dofs) predicted_wfc(12 dofs)", + ) return [l2f], [wfc.size] def print_wfc_sys_avg(avg): - print ("WFC L2err : %e eV/A" % avg[0]) - - -def test_polar (dp, args, global_polar = False) : - if args.rand_seed is not None : - np.random.seed(args.rand_seed % (2**32)) - - data = DeepmdData(args.system, args.set_prefix, shuffle_test = args.shuffle_test) + """Print errors summary for wfc type potential. + + Parameters + ---------- + avg : np.ndarray + array with summaries + """ + log.info(f"WFC L2err : {avg[0]:e} eV/A") + + +def test_polar( + dp: "DeepPolar", + data: DeepmdData, + numb_test: int, + detail_file: Optional[str], + *, + global_polar: bool, +) -> Tuple[List[np.ndarray], List[int]]: + """Test energy type model. + + Parameters + ---------- + dp : DeepPot + instance of deep potential + data: DeepmdData + data container object + numb_test : int + munber of tests to do + detail_file : Optional[str] + file where test details will be output + global_polar : bool + wheter to use glovbal version of polar potential + + Returns + ------- + Tuple[List[np.ndarray], List[int]] + arrays with results and their shapes + """ if not global_polar: - data.add('polarizability', 9, atomic=True, must=True, high_prec=False, type_sel = dp.get_sel_type()) + data.add( + "polarizability", + 9, + atomic=True, + must=True, + high_prec=False, + type_sel=dp.get_sel_type(), + ) else: - data.add('polarizability', 9, atomic=False, must=True, high_prec=False, type_sel = dp.get_sel_type()) - test_data = data.get_test () - numb_test = args.numb_test - natoms = len(test_data["type"][0]) - nframes = test_data["box"].shape[0] - numb_test = min(nframes, numb_test) - - coord = test_data["coord"][:numb_test].reshape([numb_test, -1]) - box = test_data["box"][:numb_test] - atype = test_data["type"][0] - polar = dp.eval(coord, box, atype) + data.add( + "polarizability", + 9, + atomic=False, + must=True, + high_prec=False, + type_sel=dp.get_sel_type(), + ) + test_data = data.get_test() + polar, numb_test, atype = run_test(dp, test_data, numb_test) + sel_type = dp.get_sel_type() sel_natoms = 0 for ii in sel_type: sel_natoms += sum(atype == ii) - polar = polar.reshape([numb_test,-1]) - l2f = (l2err (polar - test_data["polarizability"] [:numb_test])) - l2fs = l2f/np.sqrt(sel_natoms) - l2fa = l2f/sel_natoms + l2f = l2err(polar - test_data["polarizability"][:numb_test]) + l2fs = l2f / np.sqrt(sel_natoms) + l2fa = l2f / sel_natoms - print ("# number of test data : %d " % numb_test) - print ("Polarizability L2err : %e eV/A" % l2f) + log.info(f"# number of test data : {numb_test:d} ") + log.info(f"Polarizability L2err : {l2f:e} eV/A") if global_polar: - print ("Polarizability L2err/sqrtN : %e eV/A" % l2fs) - print ("Polarizability L2err/N : %e eV/A" % l2fa) - - detail_file = args.detail_file - if detail_file is not None : - pe = np.concatenate((np.reshape(test_data["polarizability"][:numb_test], [-1,9]), - np.reshape(polar, [-1,9])), - axis = 1) - np.savetxt(detail_file+".out", pe, - header = 'data_pxx data_pxy data_pxz data_pyx data_pyy data_pyz data_pzx data_pzy data_pzz pred_pxx pred_pxy pred_pxz pred_pyx pred_pyy pred_pyz pred_pzx pred_pzy pred_pzz') + log.info(f"Polarizability L2err/sqrtN : {l2fs:e} eV/A") + log.info(f"Polarizability L2err/N : {l2fa:e} eV/A") + + if detail_file is not None: + detail_path = Path(detail_file) + + pe = np.concatenate( + ( + np.reshape(test_data["polarizability"][:numb_test], [-1, 9]), + np.reshape(polar, [-1, 9]), + ), + axis=1, + ) + np.savetxt( + detail_path.with_suffix(".out"), + pe, + header="data_pxx data_pxy data_pxz data_pyx data_pyy data_pyz data_pzx " + "data_pzy data_pzz pred_pxx pred_pxy pred_pxz pred_pyx pred_pyy pred_pyz " + "pred_pzx pred_pzy pred_pzz", + ) return [l2f], [polar.size] def print_polar_sys_avg(avg): - print ("Polarizability L2err : %e eV/A" % avg[0]) - - -def test_dipole (dp, args) : - if args.rand_seed is not None : - np.random.seed(args.rand_seed % (2**32)) - - data = DeepmdData(args.system, args.set_prefix, shuffle_test = args.shuffle_test) - data.add('dipole', 3, atomic=True, must=True, high_prec=False, type_sel = dp.get_sel_type()) - test_data = data.get_test () - numb_test = args.numb_test - natoms = len(test_data["type"][0]) - nframes = test_data["box"].shape[0] - numb_test = min(nframes, numb_test) - - coord = test_data["coord"][:numb_test].reshape([numb_test, -1]) - box = test_data["box"][:numb_test] - atype = test_data["type"][0] - dipole = dp.eval(coord, box, atype) - - dipole = dipole.reshape([numb_test,-1]) - l2f = (l2err (dipole - test_data["dipole"] [:numb_test])) - - print ("# number of test data : %d " % numb_test) - print ("Dipole L2err : %e eV/A" % l2f) - - detail_file = args.detail_file - if detail_file is not None : - pe = np.concatenate((np.reshape(test_data["dipole"][:numb_test], [-1,3]), - np.reshape(dipole, [-1,3])), - axis = 1) - np.savetxt(detail_file+".out", pe, - header = 'data_x data_y data_z pred_x pred_y pred_z') + """Print errors summary for polar type potential. + + Parameters + ---------- + avg : np.ndarray + array with summaries + """ + log.info(f"Polarizability L2err : {avg[0]:e} eV/A") + + +def test_dipole( + dp: "DeepDipole", + data: DeepmdData, + numb_test: int, + detail_file: Optional[str], +) -> Tuple[List[np.ndarray], List[int]]: + """Test energy type model. + + Parameters + ---------- + dp : DeepPot + instance of deep potential + data: DeepmdData + data container object + numb_test : int + munber of tests to do + detail_file : Optional[str] + file where test details will be output + + Returns + ------- + Tuple[List[np.ndarray], List[int]] + arrays with results and their shapes + """ + data.add( + "dipole", 3, atomic=True, must=True, high_prec=False, type_sel=dp.get_sel_type() + ) + test_data = data.get_test() + dipole, numb_test, _ = run_test(dp, test_data, numb_test) + l2f = l2err(dipole - test_data["dipole"][:numb_test]) + + log.info(f"# number of test data : {numb_test:d}") + log.info(f"Dipole L2err : {l2f:e} eV/A") + + if detail_file is not None: + detail_path = Path(detail_file) + + pe = np.concatenate( + ( + np.reshape(test_data["dipole"][:numb_test], [-1, 3]), + np.reshape(dipole, [-1, 3]), + ), + axis=1, + ) + np.savetxt( + detail_path.with_suffix(".out"), + pe, + header="data_x data_y data_z pred_x pred_y pred_z", + ) return [l2f], [dipole.size] def print_dipole_sys_avg(avg): - print ("Dipole L2err : %e eV/A" % avg[0]) + """Print errors summary for dipole type potential. + + Parameters + ---------- + avg : np.ndarray + array with summaries + """ + log.info(f"Dipole L2err : {avg[0]:e} eV/A") diff --git a/deepmd/entrypoints/train.py b/deepmd/entrypoints/train.py index e0cf6897ee..6d4362dd02 100755 --- a/deepmd/entrypoints/train.py +++ b/deepmd/entrypoints/train.py @@ -2,6 +2,7 @@ import time import json +from typing import Optional import numpy as np from deepmd.env import tf from deepmd.common import data_requirement, expand_sys_str, j_loader @@ -50,9 +51,19 @@ def j_must_have (jdata, key) : else : return jdata[key] -def train (args) : +def train( + *, + INPUT: str, + init_model: Optional[str], + restart: Optional[str], + output: str, + mpi_log: str, + log_level: int, + log_path: Optional[str], + **kwargs +): # load json database - jdata = j_loader(args.INPUT) + jdata = j_loader(INPUT) if not 'model' in jdata.keys(): jdata = convert_input_v0_v1(jdata, @@ -60,14 +71,21 @@ def train (args) : dump = 'input_v1_compat.json') jdata = normalize(jdata) - with open(args.output, 'w') as fp: + with open(output, 'w') as fp: json.dump(jdata, fp, indent=4) # run options with_distrib = False if 'with_distrib' in jdata: with_distrib = jdata['with_distrib'] - run_opt = RunOptions(args, with_distrib) + run_opt = RunOptions( + init_model=init_model, + restart=restart, + log_path=log_path, + log_level=log_level, + mpi_log=mpi_log, + try_distrib=with_distrib + ) for message in (WELCOME + CITATION + BUILD): log.info(message) diff --git a/deepmd/entrypoints/transform.py b/deepmd/entrypoints/transform.py index 19efd42976..93e1eb5d51 100644 --- a/deepmd/entrypoints/transform.py +++ b/deepmd/entrypoints/transform.py @@ -16,14 +16,14 @@ def convertMatrix(matrix, shape): return tmp.reshape(shape) -def transform(args): - raw_graph = load_graph(args.raw_model) - old_graph = load_graph(args.old_model) +def transform(*, old_model: str, raw_model: str, output: str, **kwargs): + raw_graph = load_graph(raw_model) + old_graph = load_graph(old_model) print("%d ops in the raw graph\n%d ops in the old graph" %(len(raw_graph.as_graph_def().node),len(old_graph.as_graph_def().node))) new_graph_def = transform_graph(raw_graph,old_graph) - with tf.gfile.GFile(args.output, mode='wb') as f: + with tf.gfile.GFile(output, mode='wb') as f: f.write(new_graph_def.SerializeToString()) - print("the output model is saved in %s" % args.output) + print("the output model is saved in %s" % output) def load_graph(graphName): graph_def = tf.GraphDef() diff --git a/source/tests/test_data_modifier.py b/source/tests/test_data_modifier.py index e3f1561ca9..9d2098dff5 100644 --- a/source/tests/test_data_modifier.py +++ b/source/tests/test_data_modifier.py @@ -26,14 +26,6 @@ modifier_datapath = 'data_modifier' -class Args() : - INPUT = os.path.join(modifier_datapath, 'dipole.json') - restart = None - init_model = None - inter_threads = 0 - log_path = None - log_level = 0 - mpi_log = "master" class TestDataModifier (unittest.TestCase) : @@ -46,8 +38,15 @@ def tearDown(self): tf.reset_default_graph() def _setUp(self): - args = Args() - run_opt = RunOptions(args, False) + run_opt = RunOptions( + INPUT=os.path.join(modifier_datapath, 'dipole.json'), + restart=None, + init_model=None, + log_path=None, + log_level=0, + mpi_log="master", + try_distrib=False + ) jdata = j_loader(args.INPUT) # init model diff --git a/source/tests/test_data_modifier_shuffle.py b/source/tests/test_data_modifier_shuffle.py index 738d379721..dc96782bd6 100644 --- a/source/tests/test_data_modifier_shuffle.py +++ b/source/tests/test_data_modifier_shuffle.py @@ -28,14 +28,6 @@ modifier_datapath = 'data_modifier' -class Args() : - # INPUT = os.path.join(modifier_datapath, 'dipole.json') - restart = None - init_model = None - inter_threads = 0 - log_path = None - log_level = 0 - mpi_log = "master" class TestDataModifier (unittest.TestCase) : @@ -52,8 +44,15 @@ def tearDown(self): os.remove(os.path.join(modifier_datapath, 'dipole.pb')) def _setUp(self): - args = Args() - run_opt = RunOptions(args, False) + run_opt = RunOptions( + restart=None, + init_model=None, + inter_threads=0, + log_path=None, + log_level=0, + mpi_log="master", + try_distrib=False + ) jdata = self._setUp_jdata() self._setUp_data() diff --git a/source/tests/test_get_potential.py b/source/tests/test_get_potential.py new file mode 100644 index 0000000000..2bb801968f --- /dev/null +++ b/source/tests/test_get_potential.py @@ -0,0 +1,35 @@ +import unittest +from pathlib import Path +from shutil import rmtree + +from deepmd.infer import DeepPotential, DeepDipole, DeepGlobalPolar, DeepPolar, DeepPot, DeepWFC +from deepmd.env import tf + + +class TestGetPotential(unittest.TestCase): + + def setUp(self): + self.work_dir = Path(__file__).parent / "test_get_potential" + self.work_dir.mkdir(exist_ok=True) + # TODO create all types of graphs + ... + + def tearDown(self): + rmtree(self.work_dir) + + def test_merge_all_stat(self): + + dp = DeepPotential(self.work_dir / "deep_pot_model.pb") + self.assertIsInstance(dp, DeepPot, "Returned wrong type of potential") + + dp = DeepPotential(self.work_dir / "deep_polar_model.pb") + self.assertIsInstance(dp, DeepPolar, "Returned wrong type of potential") + + dp = DeepPotential(self.work_dir / "deep_global_polar_model.pb") + self.assertIsInstance(dp, DeepGlobalPolar, "Returned wrong type of potential") + + dp = DeepPotential(self.work_dir / "deep_wfc_model.pb") + self.assertIsInstance(dp, DeepWFC, "Returned wrong type of potential") + + dp = DeepPotential(self.work_dir / "deep_dipole_model.pb") + self.assertIsInstance(dp, DeepDipole, "Returned wrong type of potential") diff --git a/source/tests/test_model_loc_frame.py b/source/tests/test_model_loc_frame.py index cf8fb7417e..858734bde6 100644 --- a/source/tests/test_model_loc_frame.py +++ b/source/tests/test_model_loc_frame.py @@ -3,7 +3,6 @@ from deepmd.env import tf from common import Data,gen_data -from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptLocFrame from deepmd.fit import EnerFitting @@ -22,7 +21,6 @@ def setUp(self) : def test_model(self): jfile = 'water.json' jdata = j_loader(jfile) - run_opt = RunOptions(None) systems = j_must_have(jdata, 'systems') set_pfx = j_must_have(jdata, 'set_prefix') batch_size = j_must_have(jdata, 'batch_size') diff --git a/source/tests/test_model_se_a.py b/source/tests/test_model_se_a.py index 4f0c3f0562..a2b6dcdfa8 100644 --- a/source/tests/test_model_se_a.py +++ b/source/tests/test_model_se_a.py @@ -4,7 +4,6 @@ from deepmd.env import tf from common import Data,gen_data -from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting @@ -23,7 +22,6 @@ def test_model(self): jfile = 'water_se_a.json' jdata = j_loader(jfile) - run_opt = RunOptions(None) systems = j_must_have(jdata, 'systems') set_pfx = j_must_have(jdata, 'set_prefix') batch_size = j_must_have(jdata, 'batch_size') diff --git a/source/tests/test_model_se_a_aparam.py b/source/tests/test_model_se_a_aparam.py index 352e5c7931..3c984e8412 100644 --- a/source/tests/test_model_se_a_aparam.py +++ b/source/tests/test_model_se_a_aparam.py @@ -3,7 +3,6 @@ from deepmd.env import tf from common import Data,gen_data -from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting @@ -21,7 +20,6 @@ def setUp(self) : def test_model(self): jfile = 'water_se_a_aparam.json' jdata = j_loader(jfile) - run_opt = RunOptions(None) systems = j_must_have(jdata, 'systems') set_pfx = j_must_have(jdata, 'set_prefix') batch_size = j_must_have(jdata, 'batch_size') diff --git a/source/tests/test_model_se_a_fparam.py b/source/tests/test_model_se_a_fparam.py index 4235b03e5b..b66e0ddd4e 100644 --- a/source/tests/test_model_se_a_fparam.py +++ b/source/tests/test_model_se_a_fparam.py @@ -3,7 +3,6 @@ from deepmd.env import tf from common import Data,gen_data -from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting @@ -22,7 +21,6 @@ def test_model(self): jfile = 'water_se_a_fparam.json' jdata = j_loader(jfile) - run_opt = RunOptions(None) systems = j_must_have(jdata, 'systems') set_pfx = j_must_have(jdata, 'set_prefix') batch_size = j_must_have(jdata, 'batch_size') diff --git a/source/tests/test_model_se_a_srtab.py b/source/tests/test_model_se_a_srtab.py index 3debcb97b1..bbc7b706e9 100644 --- a/source/tests/test_model_se_a_srtab.py +++ b/source/tests/test_model_se_a_srtab.py @@ -3,7 +3,6 @@ from deepmd.env import tf from common import Data,gen_data -from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting @@ -32,7 +31,6 @@ def test_model(self): jfile = 'water_se_a.json' jdata = j_loader(jfile) - run_opt = RunOptions(None) systems = j_must_have(jdata, 'systems') set_pfx = j_must_have(jdata, 'set_prefix') batch_size = j_must_have(jdata, 'batch_size') diff --git a/source/tests/test_model_se_r.py b/source/tests/test_model_se_r.py index 8b32e99125..baa28864f6 100644 --- a/source/tests/test_model_se_r.py +++ b/source/tests/test_model_se_r.py @@ -3,7 +3,6 @@ from deepmd.env import tf from common import Data,gen_data -from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeR from deepmd.fit import EnerFitting @@ -22,7 +21,6 @@ def test_model(self): jfile = 'water_se_r.json' jdata = j_loader(jfile) - run_opt = RunOptions(None) systems = j_must_have(jdata, 'systems') set_pfx = j_must_have(jdata, 'set_prefix') batch_size = j_must_have(jdata, 'batch_size') diff --git a/source/tests/test_polar_se_a.py b/source/tests/test_polar_se_a.py index 468f219474..f5a1afcbae 100644 --- a/source/tests/test_polar_se_a.py +++ b/source/tests/test_polar_se_a.py @@ -3,7 +3,6 @@ from deepmd.env import tf from common import Data,gen_data -from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeA from deepmd.fit import PolarFittingSeA @@ -22,7 +21,6 @@ def test_model(self): jfile = 'polar_se_a.json' jdata = j_loader(jfile) - run_opt = RunOptions(None) systems = j_must_have(jdata, 'systems') set_pfx = j_must_have(jdata, 'set_prefix') batch_size = j_must_have(jdata, 'batch_size') diff --git a/source/tests/test_wfc.py b/source/tests/test_wfc.py index 272310effa..55f26d8a4a 100644 --- a/source/tests/test_wfc.py +++ b/source/tests/test_wfc.py @@ -3,7 +3,6 @@ from deepmd.env import tf from common import Data,gen_data -from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptLocFrame from deepmd.fit import WFCFitting @@ -22,7 +21,6 @@ def test_model(self): jfile = 'wfc.json' jdata = j_loader(jfile) - run_opt = RunOptions(None) systems = j_must_have(jdata, 'systems') set_pfx = j_must_have(jdata, 'set_prefix') batch_size = j_must_have(jdata, 'batch_size') diff --git a/source/train/main.py b/source/train/main.py index 5c3f417731..c5e2e4c731 100644 --- a/source/train/main.py +++ b/source/train/main.py @@ -3,8 +3,15 @@ import argparse from pathlib import Path -from deepmd.entrypoints import (compress, config, doc_train_input, freeze, - test, train, transform) +from deepmd.entrypoints import ( + compress, + config, + doc_train_input, + freeze, + test, + train, + transform, +) from deepmd.loggers import set_log_handles @@ -42,6 +49,18 @@ def main(): help="set log file to log messages to disk, if not specified, the logs will " "only be output to console", ) + # * mpi logging parser ************************************************************* + parser_mpi_log = argparse.ArgumentParser(add_help=False) + parser_mpi_log.add_argument( + "-m", + "--mpi-log", + type=str, + default="master", + choices=("master", "collect", "workers"), + help="Set the manner of logging when running with MPI. 'master' logs only on " + "main process, 'collect' broadcasts logs from workers to master and 'workers' " + "means each process will output its own log", + ) # * config script ****************************************************************** parser_cfig = subparsers.add_parser( @@ -81,7 +100,7 @@ def main(): # * config parser ****************************************************************** parser_train = subparsers.add_parser( - "train", parents=[parser_log], help="train a model" + "train", parents=[parser_log, parser_mpi_log], help="train a model" ) parser_train.add_argument( "INPUT", help="the input parameter file in json or yaml format" @@ -107,16 +126,6 @@ def main(): default="out.json", help="The output file of the parameters used in training.", ) - parser_train.add_argument( - "-m", - "--mpi-log", - type=str, - default="master", - choices=("master", "collect", "workers"), - help="Set the manner of logging when running with MPI. 'master' logs only on " - "main process, 'collect' broadcasts logs from workers to master and 'workers' " - "means each process will output its own log", - ) # * freeze script ****************************************************************** parser_frz = subparsers.add_parser( @@ -138,8 +147,9 @@ def main(): ) parser_frz.add_argument( "-n", - "--nodes", + "--node-names", type=str, + default=None, help="the frozen nodes, if not set, determined from the model type", ) @@ -167,15 +177,17 @@ def main(): parser_tst.add_argument( "-n", "--numb-test", default=100, type=int, help="The number of data for test" ) - parser_tst.add_argument("-r", "--rand-seed", type=int, help="The random seed") parser_tst.add_argument( - "--shuffle-test", action="store_true", help="Shuffle test data" + "-r", "--rand-seed", type=int, default=None, help="The random seed" + ) + parser_tst.add_argument( + "--shuffle-test", action="store_true", default=False, help="Shuffle test data" ) parser_tst.add_argument( "-d", "--detail-file", type=str, - help="The file containing details of energy force and virial accuracy", + help="File where details of energy force and virial accuracy will be written", ) parser_tst.add_argument( "-a", @@ -192,7 +204,9 @@ def main(): #  The range of the first table is automatically detected by deepmd-kit, while the # second table ranges from the first table's upper boundary(upper) to the # extrapolate(parameter) * upper. - parser_compress = subparsers.add_parser("compress", help="compress a model") + parser_compress = subparsers.add_parser( + "compress", parents=[parser_log, parser_mpi_log], help="compress a model" + ) parser_compress.add_argument( "INPUT", help="The input parameter file in json or yaml format, which should be " @@ -259,21 +273,23 @@ def main(): if args.command not in (None, "train"): set_log_handles(args.log_level, Path(args.log_path) if args.log_path else None) + dict_args = vars(args) + if args.command is None: parser.print_help() elif args.command == "train": - train(args) + train(**dict_args) elif args.command == "freeze": - freeze(args) + freeze(**dict_args) elif args.command == "config": - config(args) + config(**dict_args) elif args.command == "test": - test(args) + test(**dict_args) elif args.command == "transform": - transform(args) + transform(**dict_args) elif args.command == "compress": - compress(args) + compress(**dict_args) elif args.command == "doc-train-input": - doc_train_input(args) + doc_train_input() else: raise RuntimeError(f"unknown command {args.command}") diff --git a/source/train/run_options.py b/source/train/run_options.py index a5f69edef1..c771de87af 100644 --- a/source/train/run_options.py +++ b/source/train/run_options.py @@ -12,23 +12,8 @@ from deepmd.loggers import set_log_handles if TYPE_CHECKING: - try: - from typing import Protocol # python >=3.8 - except ImportError: - from typing_extensions import Protocol # type: ignore - from mpi4py import MPI - class ArgsProto(Protocol): - """Prococol mimicking parser object.""" - - init_model: Optional[str] - restart: Optional[str] - log_level: int - log_path: Optional[str] - mpi_log: Optional[str] - - __all__ = [ "GLOBAL_TF_FLOAT_PRECISION", "GLOBAL_NP_FLOAT_PRECISION", @@ -270,7 +255,15 @@ class RunOptions: _MPI: Optional["MPI"] _log_handles_already_set: bool = False - def __init__(self, args: Optional["ArgsProto"], try_distrib: bool = False): + def __init__( + self, + init_model: Optional[str] = None, + restart: Optional[str] = None, + log_path: Optional[str] = None, + log_level: int = 0, + mpi_log: str = "master", + try_distrib: bool = False + ): # distributed tasks if try_distrib: self._try_init_mpi() @@ -278,28 +271,24 @@ def __init__(self, args: Optional["ArgsProto"], try_distrib: bool = False): self.is_distrib = False self._init_serial() + if all((init_model, restart)): + raise RuntimeError( + "--init-model and --restart should not be set at the same time" + ) + # model init options - # default set - self.restart = None - self.init_model = None + self.restart = restart + self.init_model = init_model self.init_mode = "init_from_scratch" - if args is not None: - if all((args.init_model, args.restart)): - raise RuntimeError( - "--init-model and --restart should not be set at the same time" - ) - elif args.init_model: - self.init_model = os.path.abspath(args.init_model) - self.init_mode = "init_from_model" - elif args.restart: - self.restart = os.path.abspath(args.restart) - self.init_mode = "restart" - - self._setup_logger( - Path(args.log_path) if args.log_path else None, - args.log_level, - args.mpi_log, - ) + + if restart is not None: + self.restart = os.path.abspath(restart) + self.init_mode = "restart" + elif init_model is not None: + self.init_model = os.path.abspath(init_model) + self.init_mode = "init_from_model" + + self._setup_logger(Path(log_path) if log_path else None, log_level, mpi_log) def print_resource_summary(self): """Print build and current running cluster configuration summary.""" From f98547a85d07d97bfb2f01f2461c259628b508cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 18 Feb 2021 16:33:40 +0100 Subject: [PATCH 170/562] rewrite transform and train enrtrypoints --- deepmd/entrypoints/__init__.py | 4 +- deepmd/entrypoints/compress.py | 4 +- deepmd/entrypoints/test.py | 1 + deepmd/entrypoints/train.py | 340 ++++++++++++++------- deepmd/entrypoints/transfer.py | 262 ++++++++++++++++ deepmd/entrypoints/transform.py | 137 --------- deepmd/env.py | 2 +- source/tests/test_data_modifier.py | 4 +- source/tests/test_data_modifier_shuffle.py | 1 - source/train/main.py | 20 +- source/train/run_options.py | 14 +- 11 files changed, 529 insertions(+), 260 deletions(-) create mode 100644 deepmd/entrypoints/transfer.py delete mode 100644 deepmd/entrypoints/transform.py diff --git a/deepmd/entrypoints/__init__.py b/deepmd/entrypoints/__init__.py index a93259a78a..2f8bae9bbd 100644 --- a/deepmd/entrypoints/__init__.py +++ b/deepmd/entrypoints/__init__.py @@ -6,7 +6,7 @@ from .freeze import freeze from .test import test from .train import train -from .transform import transform +from .transfer import transfer __all__ = [ "config", @@ -14,7 +14,7 @@ "freeze", "test", "train", - "transform", + "transfer", "compress", "doc_train_input", ] diff --git a/deepmd/entrypoints/compress.py b/deepmd/entrypoints/compress.py index 369553473f..0487451360 100644 --- a/deepmd/entrypoints/compress.py +++ b/deepmd/entrypoints/compress.py @@ -10,7 +10,7 @@ from .freeze import freeze from .train import train -from .transform import transform +from .transfer import transfer __all__ = ["compress"] @@ -110,4 +110,4 @@ def compress( # stage 3: transform the model log.info("\n\n") log.info("stage 3: transform the model") - transform(old_model=input, raw_model=output, output=output) + transfer(old_model=input, raw_model=output, output=output) diff --git a/deepmd/entrypoints/test.py b/deepmd/entrypoints/test.py index a547725150..6d4a2c4ad8 100644 --- a/deepmd/entrypoints/test.py +++ b/deepmd/entrypoints/test.py @@ -12,6 +12,7 @@ from deepmd.infer import DeepDipole, DeepPolar, DeepPot, DeepWFC from deepmd.infer.deep_eval import DeepTensor +__all__ = ["test"] log = logging.getLogger(__name__) diff --git a/deepmd/entrypoints/train.py b/deepmd/entrypoints/train.py index 6d4362dd02..3bc629ae4e 100755 --- a/deepmd/entrypoints/train.py +++ b/deepmd/entrypoints/train.py @@ -1,55 +1,134 @@ -#!/usr/bin/env python3 +"""DeePMD training entrypoint script. + +Can handle local or distributed training. +""" -import time import json -from typing import Optional +import logging +import time +from typing import Dict, TYPE_CHECKING, List, Optional, Any + import numpy as np +from deepmd.common import data_requirement, expand_sys_str, j_loader, j_must_have from deepmd.env import tf -from deepmd.common import data_requirement, expand_sys_str, j_loader -from deepmd.run_options import RunOptions, WELCOME, CITATION, BUILD -from deepmd.trainer import NNPTrainer from deepmd.infer.data_modifier import DipoleChargeModifier -from deepmd.utils.data_system import DeepmdDataSystem -from deepmd.utils.compat import convert_input_v0_v1 +from deepmd.run_options import BUILD, CITATION, WELCOME, RunOptions +from deepmd.trainer import NNPTrainer from deepmd.utils.argcheck import normalize -import logging +from deepmd.utils.compat import convert_input_v0_v1 +from deepmd.utils.data_system import DeepmdDataSystem + +if TYPE_CHECKING: + from deepmd.run_options import TFServerV1 + +__all__ = ["train"] log = logging.getLogger(__name__) -def create_done_queue(cluster_spec, task_index): - with tf.device("/job:ps/task:%d" % (task_index)): - queue = tf.FIFOQueue(cluster_spec.num_tasks("worker"), tf.int32, - shared_name = "done_queue" + str(task_index)) - return queue +def create_done_queue( + cluster_spec: tf.train.ClusterSpec, task_index: int +) -> tf.FIFOQueue: + """Create FIFO queue for distributed tasks. + + Parameters + ---------- + cluster_spec : tf.train.ClusterSpec + tf cluster specification object + task_index : int + identifying index of a task + + Returns + ------- + tf.FIFOQueue + tf distributed FIFI queue + """ + with tf.device(f"/job:ps/task:{task_index:d}"): + queue = tf.FIFOQueue( + cluster_spec.num_tasks("worker"), + tf.int32, + shared_name=f"done_queue{task_index}", + ) + return queue + + +def wait_done_queue( + cluster_spec: tf.train.ClusterSpec, + server: "TFServerV1", + queue: tf.FIFOQueue, + task_index: int, +): + """Wait until all enqued operation in tf distributed queue are finished. + + Parameters + ---------- + cluster_spec : tf.train.ClusterSpec + tf cluster specification object + server : TFServerV1 + tf server specification object + queue : tf.FIFOQueue + tf distributed queue + task_index : int + identifying index of a task + """ + with tf.Session(server.target) as sess: + for i in range(cluster_spec.num_tasks("worker")): + sess.run(queue.dequeue()) + log.debug(f"ps:{task_index:d} received done from worker:{i:d}") + log.debug(f"ps:{task_index:f} quitting") + + +def connect_done_queue( + cluster_spec: tf.train.ClusterSpec, task_index: int +) -> List[tf.Operation]: + """Create tf FIFO queue filling operations. + + Parameters + ---------- + cluster_spec : tf.train.ClusterSpec + tf cluster specification object + task_index : int + identifying index of a task + + Returns + ------- + List[tf.Operation] + list of tf operations that will populate the queue + """ + done_ops = [] + for i in range(cluster_spec.num_tasks("ps")): + with tf.device(f"/job:ps/task:{i:d}"): + queue = tf.FIFOQueue( + cluster_spec.num_tasks("worker"), tf.int32, shared_name=f"done_queue{i}" + ) + done_ops.append(queue.enqueue(task_index)) + return done_ops + -def wait_done_queue(cluster_spec, server, queue, task_index): +def fill_done_queue( + cluster_spec: tf.train.ClusterSpec, + server: "TFServerV1", + done_ops: List[tf.Operation], + task_index: int, +): + """Run specified operations that will fill the tf distributed FIFO queue. + + Parameters + ---------- + cluster_spec : tf.train.ClusterSpec + tf cluster specification object + server : TFServerV1 + tf server specification object + done_ops : List[tf.Operation] + a list of tf operations that will fill the queue + task_index : int + identifying index of a task + """ with tf.Session(server.target) as sess: - for i in range(cluster_spec.num_tasks("worker")): - sess.run(queue.dequeue()) - # print("ps:%d received done from worker:%d" % (task_index, i)) - # print("ps:%d quitting" % task_index) - -def connect_done_queue(cluster_spec, task_index): - done_ops = [] - for i in range(cluster_spec.num_tasks("ps")): - with tf.device("/job:ps/task:%d" % i): - queue = tf.FIFOQueue(cluster_spec.num_tasks('worker'), tf.int32, - shared_name='done_queue' + str(i)) - done_ops.append(queue.enqueue(task_index)) - return done_ops - -def fill_done_queue(cluster_spec, server, done_ops, task_index): - with tf.Session(server.target) as sess: - for i in range(cluster_spec.num_tasks("ps")): - sess.run(done_ops[i]) - # print("worker:%d sending done to ps:%d" % (task_index, i)) - -def j_must_have (jdata, key) : - if not key in jdata.keys() : - raise RuntimeError ("json data base must provide key " + key ) - else : - return jdata[key] + for i in range(cluster_spec.num_tasks("ps")): + sess.run(done_ops[i]) + log.debug(f"worker:{task_index:d} sending done to ps:{i:d}") + def train( *, @@ -60,109 +139,160 @@ def train( mpi_log: str, log_level: int, log_path: Optional[str], - **kwargs + **kwargs, ): + """Run DeePMD model training. + + Parameters + ---------- + INPUT : str + json/yaml control file + init_model : Optional[str] + path to checkpoint folder or None + restart : Optional[str] + path to checkpoint folder or None + output : str + path for dump file with arguments + mpi_log : str + mpi logging mode + log_level : int + logging level defined by int 0-3 + log_path : Optional[str] + logging file path or None if logs are to be output only to stdout + + Raises + ------ + RuntimeError + if distributed training job nem is wrong + """ # load json database jdata = j_loader(INPUT) - if not 'model' in jdata.keys(): - jdata = convert_input_v0_v1(jdata, - warning = True, - dump = 'input_v1_compat.json') - + if "model" not in jdata.keys(): + jdata = convert_input_v0_v1(jdata, warning=True, dump="input_v1_compat.json") + jdata = normalize(jdata) - with open(output, 'w') as fp: + with open(output, "w") as fp: json.dump(jdata, fp, indent=4) # run options - with_distrib = False - if 'with_distrib' in jdata: - with_distrib = jdata['with_distrib'] run_opt = RunOptions( init_model=init_model, restart=restart, log_path=log_path, log_level=log_level, mpi_log=mpi_log, - try_distrib=with_distrib + try_distrib=jdata.get("with_distrib", False), ) - for message in (WELCOME + CITATION + BUILD): + for message in WELCOME + CITATION + BUILD: log.info(message) - + run_opt.print_resource_summary() - if run_opt.is_distrib : + if run_opt.is_distrib: # distributed training if run_opt.my_job_name == "ps": queue = create_done_queue(run_opt.cluster_spec, run_opt.my_task_index) - wait_done_queue(run_opt.cluster_spec, run_opt.server, queue, run_opt.my_task_index) - #server.join() + wait_done_queue( + run_opt.cluster_spec, run_opt.server, queue, run_opt.my_task_index + ) + # server.join() elif run_opt.my_job_name == "worker": done_ops = connect_done_queue(run_opt.cluster_spec, run_opt.my_task_index) _do_work(jdata, run_opt) - fill_done_queue(run_opt.cluster_spec, run_opt.server, done_ops, run_opt.my_task_index) - else : + fill_done_queue( + run_opt.cluster_spec, run_opt.server, done_ops, run_opt.my_task_index + ) + else: raise RuntimeError("unknown job name") - else : + else: # serial training _do_work(jdata, run_opt) -def _do_work(jdata, run_opt): + +def _do_work(jdata: Dict[str, Any], run_opt: RunOptions): + """Run serial model training. + + Parameters + ---------- + jdata : Dict[str, Any] + arguments read form json/yaml control file + run_opt : RunOptions + object with run configuration + + Raises + ------ + RuntimeError + If unsupported modifier type is selected for model + """ + # make necessary checks + assert "training" in jdata + # init the model - model = NNPTrainer (jdata, run_opt = run_opt) + model = NNPTrainer(jdata, run_opt=run_opt) rcut = model.model.get_rcut() type_map = model.model.get_type_map() - # init params and run options - assert('training' in jdata) - systems = j_must_have(jdata['training'], 'systems') - if type(systems) == str: - systems = expand_sys_str(systems) - set_pfx = j_must_have(jdata['training'], 'set_prefix') - seed = None - if 'seed' in jdata['training'].keys() : seed = jdata['training']['seed'] - if seed is not None: - seed = seed % (2**32) - np.random.seed (seed) - batch_size = j_must_have(jdata['training'], 'batch_size') - test_size = j_must_have(jdata['training'], 'numb_test') - stop_batch = j_must_have(jdata['training'], 'stop_batch') - sys_probs = jdata['training'].get('sys_probs') - auto_prob_style = jdata['training'].get('auto_prob_style', 'prob_sys_size') if len(type_map) == 0: - # empty type_map - ipt_type_map = None + ipt_type_map = None else: - ipt_type_map = type_map - # data modifier - modifier = None - modi_data = jdata['model'].get("modifier", None) + ipt_type_map = type_map + + # init params and run options + systems = j_must_have(jdata["training"], "systems") + if isinstance(systems, str): + systems = expand_sys_str(systems) + set_pfx = j_must_have(jdata["training"], "set_prefix") + + #  init random seed + seed = jdata["training"].get("seed", None) + if seed is not None: + seed = seed % (2 ** 32) + np.random.seed(seed) + + # get batch sizes + batch_size = j_must_have(jdata["training"], "batch_size") + test_size = j_must_have(jdata["training"], "numb_test") + stop_batch = j_must_have(jdata["training"], "stop_batch") + sys_probs = jdata["training"].get("sys_probs") + auto_prob_style = jdata["training"].get("auto_prob_style", "prob_sys_size") + + # setup data modifier + modifier: Optional[DipoleChargeModifier] + modi_data = jdata["model"].get("modifier", None) if modi_data is not None: - if modi_data['type'] == 'dipole_charge': - modifier = DipoleChargeModifier(modi_data['model_name'], - modi_data['model_charge_map'], - modi_data['sys_charge_map'], - modi_data['ewald_h'], - modi_data['ewald_beta']) - else: - raise RuntimeError('unknown modifier type ' + str(modi_data['type'])) + if modi_data["type"] == "dipole_charge": + modifier = DipoleChargeModifier( + modi_data["model_name"], + modi_data["model_charge_map"], + modi_data["sys_charge_map"], + modi_data["ewald_h"], + modi_data["ewald_beta"], + ) + else: + raise RuntimeError("unknown modifier type " + str(modi_data["type"])) + else: + modifier = None + # init data - data = DeepmdDataSystem(systems, - batch_size, - test_size, - rcut, - set_prefix=set_pfx, - type_map = ipt_type_map, - modifier = modifier) - data.print_summary(run_opt, - sys_probs = sys_probs, - auto_prob_style = auto_prob_style) + data = DeepmdDataSystem( + systems, + batch_size, + test_size, + rcut, + set_prefix=set_pfx, + type_map=ipt_type_map, + modifier=modifier, + ) + data.print_summary(run_opt, sys_probs=sys_probs, auto_prob_style=auto_prob_style) data.add_dict(data_requirement) + # build the model with stats from the first system - model.build (data, stop_batch) + model.build(data, stop_batch) + # train the model with the provided systems in a cyclic way start_time = time.time() - model.train (data) + model.train(data) end_time = time.time() - log.info("finished training\nwall time: %.3f s" % (end_time-start_time)) - + log.info("finished training") + log.info(f"wall time: {(end_time - start_time):.3f} s") diff --git a/deepmd/entrypoints/transfer.py b/deepmd/entrypoints/transfer.py new file mode 100644 index 0000000000..d2d583fdb2 --- /dev/null +++ b/deepmd/entrypoints/transfer.py @@ -0,0 +1,262 @@ +"""Module used for transfering parameters between models.""" + +from typing import Dict, Optional, Sequence, Tuple +from deepmd.env import tf +import re +import numpy as np +import logging + +__all__ = ["transfer"] + +log = logging.getLogger(__name__) + +PRECISION_MAPPING: Dict[int, type] = { + 1: np.float32, + 2: np.float64, + 19: np.float16, +} + + +@np.vectorize +def convert_number(number: int) -> float: + binary = bin(number).replace("0b", "").zfill(16) + sign = int(binary[0]) * -2 + 1 + exp = int(binary[1:6], 2) + frac = (int(binary[6:], 2) + 2 ** 10) * (2 ** -10) + return sign * (2 ** (exp - 15)) * frac + + +def convert_matrix( + matrix: np.ndarray, shape: Sequence[int], dtype: Optional[type] = None +) -> np.ndarray: + """Convert matrix of integers to self defined binary format. + + Parameters + ---------- + matrix : np.ndarray + array of ints + shape : Sequence[int] + shape to cast resulting array to + dtype : Optional[type] + type that finall array will be cast to, If None no casting will take place + + Returns + ------- + np.ndarray + array cast to required format + """ + conv = convert_number(matrix.flatten()).reshape(shape) + if dtype: + conv = conv.astype(dtype) + + return conv + + +def transfer(*, old_model: str, raw_model: str, output: str, **kwargs): + """Transfer operation from old fron graph to new prepared raw graph. + + Parameters + ---------- + old_model : str + frozen old graph model + raw_model : str + new model that will accept ops from old model + output : str + new model with transfered parameters will be saved to this location + """ + raw_graph = load_graph(raw_model) + old_graph = load_graph(old_model) + log.info(f"{len(raw_graph.as_graph_def().node)} ops in the raw graph") + log.info(f"{len(old_graph.as_graph_def().node)} ops in the old graph") + + new_graph_def = transform_graph(raw_graph, old_graph) + with tf.gfile.GFile(output, mode="wb") as f: + f.write(new_graph_def.SerializeToString()) + log.info("the output model is saved in {output:s}") + + +def load_graph(graph_name: str) -> tf.Graph: + """Load graph from passed in path. + + Parameters + ---------- + graph_name : str + path to frozen graph on disk + + Returns + ------- + tf.Graph + tf graph object + """ + graph_def = tf.GraphDef() + with open(graph_name, "rb") as f: + graph_def.ParseFromString(f.read()) + with tf.Graph().as_default() as graph: + tf.import_graph_def(graph_def, name="") + return graph + + +def transform_graph(raw_graph: tf.Graph, old_graph: tf.Graph) -> tf.Graph: + """Trasform old graph into new. + + Parameters + ---------- + raw_graph : tf.Graph + graph receiving parameters from the old one + old_graph : tf.Graph + graph providing parameters + + Returns + ------- + tf.Graph + new graph with parameters transfered form the old one + """ + old_graph_def = old_graph.as_graph_def() + raw_graph_def = raw_graph.as_graph_def() + raw_graph_node = load_transform_node(raw_graph_def) + old_graph_node = load_transform_node(old_graph_def) + + for node in raw_graph_def.node: + if node.name not in raw_graph_node.keys(): + continue + + old_node = old_graph_node[node.name] + cp_attr = CopyNodeAttr(node) + + check_dim(raw_graph_node, old_graph_node, node.name) + tensor_shape = [dim.size for dim in node.tensor_shape.dim] + old_graph_dtype = PRECISION_MAPPING[old_node.dtype] + raw_graph_dtype = PRECISION_MAPPING[node.dtype] + log.info( + f"{node.name:s} is passed from old graph({old_graph_dtype:s}) " + f"to raw graph({raw_graph_dtype:s})" + ) + + if raw_graph_dtype == np.float16: + if old_graph_dtype == np.float64 or old_graph_dtype == np.float32: + if (len(tensor_shape) != 1) or (tensor_shape[0] != 1): + tensor = np.frombuffer(old_node.tensor_content, dtype=np.float16) + cp_attr.from_array(tensor, tf.float16, shape=tensor_shape) + else: + tensor = load_tensor(old_node, old_graph_dtype, np.float16) + cp_attr.from_array(tensor, tf.float16, [1]) + + elif old_graph_dtype == np.float16: + tensor = convert_matrix(np.array(old_node.half_val), tensor_shape) + cp_attr.from_array(tensor, tf.float16) + + elif raw_graph_dtype == np.float64 or raw_graph_dtype == np.float32: + if old_graph_dtype == np.float64 or old_graph_dtype == np.float32: + if (len(tensor_shape) != 1) or (tensor_shape[0] != 1): + tensor = np.frombuffer( + old_node.tensor_content, dtype=raw_graph_dtype + ) + cp_attr.from_str(tensor) + else: + tensor = load_tensor(old_node, old_graph_dtype, raw_graph_dtype) + cp_attr.from_array(tensor, raw_graph_dtype, shape=[1]) + + elif old_graph_dtype == np.float16: + if (len(tensor_shape) != 1) or (tensor_shape[0] != 1): + tensor = convert_matrix( + np.array(old_node.half_val), tensor_shape, dtype=raw_graph_dtype + ) + cp_attr.from_str(tensor) + else: + tensor = convert_matrix( + np.array(old_node.half_val), tensor_shape, dtype=raw_graph_dtype + ) + cp_attr.from_array(tensor, raw_graph_dtype) + + return raw_graph_def + + +class CopyNodeAttr: + def __init__(self, node) -> None: + self.node = node + + def from_array( + self, tensor: np.ndarray, dtype: type, shape: Optional[Sequence[int]] = None + ): + if shape is None: + shape = tensor.shape + self.node.attr["value"].CopyFrom( + tf.AttrValue(tensor=tf.make_tensor_proto(tensor, dtype, shape)) + ) + + def from_str(self, tensor: np.ndarray): + self.node.attr["value"].tensor.tensor_content = tensor.tostring() + + +def load_tensor(node: tf.Tensor, dtype_old: type, dtype_new: type) -> np.ndarray: + if dtype_old == np.float64: + tensor = np.array(node.double_val, dtype=dtype_new) + elif dtype_old == np.float32: + tensor = np.array(node.float_val, dtype=dtype_new) + + return tensor + + +def check_dim(raw_graph_node: tf.Tensor, old_graph_node: tf.Tensor, node_name: str): + """Check if dimensions of tensor in old and new graph is equal. + + Parameters + ---------- + raw_graph_node : tf.Tensor + node of the receiving graph + old_graph_node : tf.Tensor + node of the graph from which will node be extracted + node_name : str + name of the node + + Raises + ------ + RuntimeError + if node dimension do not match + """ + raw_graph_dim = raw_graph_node[node_name].tensor_shape + old_graph_dim = old_graph_node[node_name].tensor_shape + if raw_graph_dim != old_graph_dim: + raise RuntimeError( + f"old graph {old_graph_dim} and raw graph {raw_graph_dim} " + f"has different {node_name} dim" + ) + + +def load_transform_node(graph: tf.Graph) -> Dict[str, tf.Tensor]: + """Load nodes and their names from graph to dict. + + Parameters + ---------- + graph : tf.Graph + tensforflow graph + + Returns + ------- + Dict[str, tf.Tensor] + mapping on graph node names and corresponding tensors + """ + transform_node_pattern = re.compile( + r"filter_type_\d+/matrix_\d+_\d+|" + r"filter_type_\d+/bias_\d+_\d+|" + r"filter_type_\d+/idt_\d+_\d+|" + r"layer_\d+_type_\d+/matrix|" + r"layer_\d+_type_\d+/bias|" + r"layer_\d+_type_\d+/idt|" + r"final_layer_type_\d+/matrix|" + r"descrpt_attr/t_avg|" + r"descrpt_attr/t_std|" + r"final_layer_type_\d+/bias|" + r"fitting_attr/t_fparam_avg|" + r"fitting_attr/t_fparam_istd|" + r"fitting_attr/t_aparam_avg|" + r"fitting_attr/t_aparam_istd|" + r"model_attr/t_tab_info|" + r"model_attr/t_tab_data|" + ) + + transform_node = {} + for node in graph.node: + if transform_node_pattern.fullmatch(node.name) is not None: + transform_node[node.name] = node.attr["value"].tensor + return transform_node diff --git a/deepmd/entrypoints/transform.py b/deepmd/entrypoints/transform.py deleted file mode 100644 index 93e1eb5d51..0000000000 --- a/deepmd/entrypoints/transform.py +++ /dev/null @@ -1,137 +0,0 @@ -from deepmd.env import tf -import re -import numpy as np - -def convertNumber(number): - binary = bin(number).replace("0b", "").zfill(16) - sign = int(binary[0]) * (-2) + 1 - exp = int(binary[1:6], 2) - frac = (int(binary[6:], 2) + 2 ** 10) * (2 ** -10) - return sign * (2 ** (exp - 15)) * frac - - -def convertMatrix(matrix, shape): - matrix = matrix.flatten() - tmp = np.array([convertNumber(matrix[i]) for i in range(len(matrix))]) - return tmp.reshape(shape) - - -def transform(*, old_model: str, raw_model: str, output: str, **kwargs): - raw_graph = load_graph(raw_model) - old_graph = load_graph(old_model) - print("%d ops in the raw graph\n%d ops in the old graph" %(len(raw_graph.as_graph_def().node),len(old_graph.as_graph_def().node))) - new_graph_def = transform_graph(raw_graph,old_graph) - with tf.gfile.GFile(output, mode='wb') as f: - f.write(new_graph_def.SerializeToString()) - print("the output model is saved in %s" % output) - -def load_graph(graphName): - graph_def = tf.GraphDef() - with open(graphName,"rb") as f: - graph_def.ParseFromString(f.read()) - with tf.Graph().as_default() as graph: - tf.import_graph_def(graph_def,name = "") - return graph - -def transform_graph(raw_graph,old_graph): - precision_dict = {\ - 1:(np.float32, "float32"),\ - 2:(np.float64, "float64"),\ - 19:(np.float16, "float16")\ - } - old_graph_def = old_graph.as_graph_def() - raw_graph_def = raw_graph.as_graph_def() - raw_graph_node = load_transform_node(raw_graph_def) - old_graph_node = load_transform_node(old_graph_def) - - # if len(raw_graph_node) != len(old_graph_node): - # raise RuntimeError("raw graph and old graph has different network structure") - - for node in raw_graph_def.node: - if node.name in raw_graph_node.keys(): - - check_dim(raw_graph_node, old_graph_node, node.name) - tensor_shape = [dim.size for dim in raw_graph_node[node.name].tensor_shape.dim] - old_graph_dtype = precision_dict[old_graph_node[node.name].dtype] - raw_graph_dtype = precision_dict[raw_graph_node[node.name].dtype] - print("%s is passed from old graph(%s) to raw graph(%s)" % (node.name, old_graph_dtype[1],raw_graph_dtype[1])) - - if raw_graph_dtype[1] == "float16": - if old_graph_dtype[1] == "float64" or old_graph_dtype[1] == "float32": - if (len(tensor_shape) != 1) or (tensor_shape[0] != 1): - tensor_value = np.frombuffer(old_graph_node[node.name].tensor_content, dtype=old_graph_dtype[0]) - tensor_value = tensor_value.astype(np.float16) - node.attr["value"].CopyFrom(tf.AttrValue(tensor=tf.make_tensor_proto(tensor_value, tf.float16, tensor_shape))) - - else: - if old_graph_dtype[1] == "float64": - tensor_value = (np.array(old_graph_node[node.name].double_val)).astype(np.float16) - node.attr["value"].CopyFrom(tf.AttrValue(tensor=tf.make_tensor_proto(tensor_value,tf.float16, [1]))) - - elif old_graph_dtype[1] == "float32": - tensor_value = (np.array(old_graph_node[node.name].float_val)).astype(np.float16) - node.attr["value"].CopyFrom(tf.AttrValue(tensor=tf.make_tensor_proto(tensor_value,tf.float16, [1]))) - - elif old_graph_dtype[1] == "float16": - tensor_value = convertMatrix(np.array(old_graph_node[node.name].half_val), tensor_shape) - node.attr["value"].CopyFrom(tf.AttrValue(tensor=tf.make_tensor_proto(tensor_value, tf.float16, tensor_value.shape))) - - elif raw_graph_dtype[1] == "float64" or raw_graph_dtype[1] == "float32": - if old_graph_dtype[1] == "float64" or old_graph_dtype[1] == "float32": - if (len(tensor_shape) != 1) or (tensor_shape[0] != 1): - tensor_value = np.frombuffer(old_graph_node[node.name].tensor_content,dtype = old_graph_dtype[0]) - tensor_value = tensor_value.astype(dtype=raw_graph_dtype[0]) - node.attr["value"].tensor.tensor_content = tensor_value.tostring() - - else: - if old_graph_dtype[1] == "float64": - tensor_value = (np.array(old_graph_node[node.name].double_val)).astype(raw_graph_dtype[0]) - node.attr["value"].CopyFrom(tf.AttrValue(tensor=tf.make_tensor_proto(tensor_value,raw_graph_dtype[0], [1]))) - - elif old_graph_dtype[1] == "float32": - tensor_value = (np.array(old_graph_node[node.name].float_val)).astype(raw_graph_dtype[0]) - node.attr["value"].CopyFrom(tf.AttrValue(tensor=tf.make_tensor_proto(tensor_value,raw_graph_dtype[0], [1]))) - - elif old_graph_dtype[1] == "float16": - if (len(tensor_shape) != 1) or (tensor_shape[0] != 1): - tensor_value = convertMatrix(np.array(old_graph_node[node.name].half_val), tensor_shape) - tensor_value = tensor_value.astype(raw_graph_dtype[0]) - node.attr["value"].tensor.tensor_content = tensor_value.tostring() - else: - tensor_value = convertMatrix(np.array(old_graph_node[node.name].half_val), tensor_shape) - tensor_value = tensor_value.astype(raw_graph_dtype[0]) - node.attr["value"].CopyFrom(tf.AttrValue(tensor=tf.make_tensor_proto(tensor_value,raw_graph_dtype[0], tensor_value.shape))) - - return raw_graph_def - -def check_dim(raw_graph_node, old_graph_node, node_name): - raw_graph_dim = raw_graph_node[node_name].tensor_shape - old_graph_dim = old_graph_node[node_name].tensor_shape - if raw_graph_dim != old_graph_dim: - raise RuntimeError("old graph " + str(old_graph_dim) + " and raw graph " + str(raw_graph_dim) + " has different " + str(node_name) + " dim") - - -def load_transform_node(graph): - transform_node = {} - transform_node_pattern = "\ -filter_type_\d+/matrix_\d+_\d+|\ -filter_type_\d+/bias_\d+_\d+|\ -filter_type_\d+/idt_\d+_\d+|\ -layer_\d+_type_\d+/matrix|\ -layer_\d+_type_\d+/bias|\ -layer_\d+_type_\d+/idt|\ -final_layer_type_\d+/matrix|\ -descrpt_attr/t_avg|\ -descrpt_attr/t_std|\ -final_layer_type_\d+/bias|\ -fitting_attr/t_fparam_avg|\ -fitting_attr/t_fparam_istd|\ -fitting_attr/t_aparam_avg|\ -fitting_attr/t_aparam_istd|\ -model_attr/t_tab_info|\ -model_attr/t_tab_data|\ -" - for node in graph.node: - if re.fullmatch(transform_node_pattern,node.name) != None: - transform_node[node.name] = node.attr["value"].tensor - return transform_node diff --git a/deepmd/env.py b/deepmd/env.py index 282310673e..b39b3fe6e0 100644 --- a/deepmd/env.py +++ b/deepmd/env.py @@ -1,4 +1,4 @@ -"""This module sets tensorflow working environment.""" +"""Module that sets tensorflow working environment and exports inportant constants.""" import os from pathlib import Path diff --git a/source/tests/test_data_modifier.py b/source/tests/test_data_modifier.py index 9d2098dff5..fa4eb691fe 100644 --- a/source/tests/test_data_modifier.py +++ b/source/tests/test_data_modifier.py @@ -25,6 +25,7 @@ global_default_places = 5 modifier_datapath = 'data_modifier' +INPUT = os.path.join(modifier_datapath, 'dipole.json') class TestDataModifier (unittest.TestCase) : @@ -39,7 +40,6 @@ def tearDown(self): def _setUp(self): run_opt = RunOptions( - INPUT=os.path.join(modifier_datapath, 'dipole.json'), restart=None, init_model=None, log_path=None, @@ -47,7 +47,7 @@ def _setUp(self): mpi_log="master", try_distrib=False ) - jdata = j_loader(args.INPUT) + jdata = j_loader(INPUT) # init model model = NNPTrainer (jdata, run_opt = run_opt) diff --git a/source/tests/test_data_modifier_shuffle.py b/source/tests/test_data_modifier_shuffle.py index dc96782bd6..9057ba5836 100644 --- a/source/tests/test_data_modifier_shuffle.py +++ b/source/tests/test_data_modifier_shuffle.py @@ -47,7 +47,6 @@ def _setUp(self): run_opt = RunOptions( restart=None, init_model=None, - inter_threads=0, log_path=None, log_level=0, mpi_log="master", diff --git a/source/train/main.py b/source/train/main.py index c5e2e4c731..4bfffe6881 100644 --- a/source/train/main.py +++ b/source/train/main.py @@ -10,10 +10,12 @@ freeze, test, train, - transform, + transfer ) from deepmd.loggers import set_log_handles +__all__ = ["main"] + def main(): """DeePMD-Kit entry point. @@ -72,25 +74,25 @@ def main(): "-o", "--output", type=str, default="input.json", help="the output json file" ) - # * transform script *************************************************************** - parser_transform = subparsers.add_parser( - "transform", parents=[parser_log], help="pass parameters to another model" + # * transfer script **************************************************************** + parser_transfer = subparsers.add_parser( + "transfer", parents=[parser_log], help="pass parameters to another model" ) - parser_transform.add_argument( + parser_transfer.add_argument( "-r", "--raw-model", default="raw_frozen_model.pb", type=str, help="the model receiving parameters", ) - parser_transform.add_argument( + parser_transfer.add_argument( "-O", "--old-model", default="old_frozen_model.pb", type=str, help="the model providing parameters", ) - parser_transform.add_argument( + parser_transfer.add_argument( "-o", "--output", default="frozen_model.pb", @@ -285,8 +287,8 @@ def main(): config(**dict_args) elif args.command == "test": test(**dict_args) - elif args.command == "transform": - transform(**dict_args) + elif args.command == "transfer": + transfer(**dict_args) elif args.command == "compress": compress(**dict_args) elif args.command == "doc-train-input": diff --git a/source/train/run_options.py b/source/train/run_options.py index c771de87af..94edf15d9b 100644 --- a/source/train/run_options.py +++ b/source/train/run_options.py @@ -14,6 +14,18 @@ if TYPE_CHECKING: from mpi4py import MPI + try: + from typing import Protocol # python >=3.8 + except ImportError: + from typing_extensions import Protocol # type: ignore + + class TFServerV1(Protocol): + """Prococol mimicking parser object.""" + + server_def: tf.train.ServerDef + target: str + + __all__ = [ "GLOBAL_TF_FLOAT_PRECISION", "GLOBAL_NP_FLOAT_PRECISION", @@ -249,7 +261,7 @@ class RunOptions: nodename: str num_ps: Optional[int] num_workers: Optional[int] - server: Optional[tf.train.Server] + server: Optional["TFServerV1"] my_device: str _MPI: Optional["MPI"] From b46dcc95e79d808b549427403d55bde945bc44b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 18 Feb 2021 17:17:41 +0100 Subject: [PATCH 171/562] remove eaccidentally commited files --- deepmd/entrypoints/compress.py | 4 ++-- source/tests/system/set.000/aparam.npy | Bin 224 -> 0 bytes source/tests/system/set.000/box.npy | Bin 200 -> 0 bytes source/tests/system/set.000/coord.npy | Bin 272 -> 0 bytes source/tests/system/set.000/energy.npy | Bin 136 -> 0 bytes source/tests/system/set.000/force.npy | Bin 272 -> 0 bytes source/tests/system/set.000/fparam.npy | Bin 144 -> 0 bytes source/tests/system/type.raw | 6 ------ source/tests/system/type_map.raw | 2 -- 9 files changed, 2 insertions(+), 10 deletions(-) delete mode 100644 source/tests/system/set.000/aparam.npy delete mode 100644 source/tests/system/set.000/box.npy delete mode 100644 source/tests/system/set.000/coord.npy delete mode 100644 source/tests/system/set.000/energy.npy delete mode 100644 source/tests/system/set.000/force.npy delete mode 100644 source/tests/system/set.000/fparam.npy delete mode 100644 source/tests/system/type.raw delete mode 100644 source/tests/system/type_map.raw diff --git a/deepmd/entrypoints/compress.py b/deepmd/entrypoints/compress.py index 0487451360..acfeae5dee 100644 --- a/deepmd/entrypoints/compress.py +++ b/deepmd/entrypoints/compress.py @@ -107,7 +107,7 @@ def compress( log.info("stage 2: freeze the model") freeze(checkpoint_folder=checkpoint_folder, output=output, node_names=None) - # stage 3: transform the model + # stage 3: transfer the model log.info("\n\n") - log.info("stage 3: transform the model") + log.info("stage 3: transfer the model") transfer(old_model=input, raw_model=output, output=output) diff --git a/source/tests/system/set.000/aparam.npy b/source/tests/system/set.000/aparam.npy deleted file mode 100644 index b3544695fa75af4593fe8b9c0fb99c6dffd39758..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 224 zcmbR27wQ`j$;eQ~P_3SlTAW;@Zl$1ZlV+i=qoAIaUsO_*m=~X4l#&V(cT3DEP6dh= nXCxM+0{I$-Itpew3Pzeb3bhL40j^myL13pnggyzSsmBKZExl5t diff --git a/source/tests/system/set.000/box.npy b/source/tests/system/set.000/box.npy deleted file mode 100644 index f70e95b6e772550e087d1aba097f26b3b380704e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 200 zcmbR27wQ`j$;eQ~P_3SlTAW;@Zl$1ZlV+i=qoAIaUsO_*m=~X4l#&V(cT3DEP6dh= hXCxM+0{I$-ItrGWItsN4WCJb+Ffeg|(6~s#@&G_89MJ#( diff --git a/source/tests/system/set.000/coord.npy b/source/tests/system/set.000/coord.npy deleted file mode 100644 index 27a06e944251c351ad110c8c69cc764c2fcd84db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 272 zcmbR27wQ`j$;eQ~P_3SlTAW;@Zl$1ZlV+i=qoAIaUsO_*m=~X4l#&V(cT3DEP6dh= zXCxM+0{I$-ItqpsnmP)#3giN=`6m;X{f%5|zg$iK+xCJ@_C<$GYa?gvv_GBq Date: Sat, 20 Feb 2021 19:42:17 -0500 Subject: [PATCH 172/562] migrate to pytest this is a first step... --- .github/workflows/test_python.yml | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index cd36b67887..d7f0e7a80a 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -70,4 +70,4 @@ jobs: CC: gcc-${{ matrix.gcc }} CXX: g++-${{ matrix.gcc }} TENSORFLOW_VERSION: ${{ matrix.tf }} - - run: cd source/tests && python -m unittest -v -f + - run: cd source/tests && pytest diff --git a/setup.py b/setup.py index ca4d13834e..79a17160b7 100644 --- a/setup.py +++ b/setup.py @@ -102,7 +102,7 @@ cmake_source_dir="source", cmake_minimum_required_version="3.0", extras_require={ - "test": ["dpdata>=0.1.9"], + "test": ["dpdata>=0.1.9", "pytest", "pytest-cov"], "docs": ["sphinx", "recommonmark", "sphinx_rtd_theme"], **extras_require, }, From f16a60c3be3da4ff5961a012a3172c6c5dbb3729 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sat, 20 Feb 2021 20:50:30 -0500 Subject: [PATCH 173/562] remove failed tests and report coverage --- .github/workflows/test_python.yml | 3 ++- setup.py | 2 +- source/tests/test_class_arg.py | 3 --- source/tests/test_sel_idx.py | 2 -- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index d7f0e7a80a..0ab95f8c0d 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -65,9 +65,10 @@ jobs: - run: | sudo apt update sudo apt install gcc-${{ matrix.gcc }} g++-${{ matrix.gcc }} - - run: pip install .[cpu,test] + - run: pip install .[cpu,test] codecov env: CC: gcc-${{ matrix.gcc }} CXX: g++-${{ matrix.gcc }} TENSORFLOW_VERSION: ${{ matrix.tf }} - run: cd source/tests && pytest + - run: codecov diff --git a/setup.py b/setup.py index 79a17160b7..390b18834e 100644 --- a/setup.py +++ b/setup.py @@ -102,7 +102,7 @@ cmake_source_dir="source", cmake_minimum_required_version="3.0", extras_require={ - "test": ["dpdata>=0.1.9", "pytest", "pytest-cov"], + "test": ["dpdata>=0.1.9", "pytest", "pytest-cov", "pytest-sugar"], "docs": ["sphinx", "recommonmark", "sphinx_rtd_theme"], **extras_require, }, diff --git a/source/tests/test_class_arg.py b/source/tests/test_class_arg.py index ec6e7a9934..e573dff0bd 100644 --- a/source/tests/test_class_arg.py +++ b/source/tests/test_class_arg.py @@ -4,9 +4,6 @@ from deepmd.common import ClassArg -def test(): - raise RuntimeError - class TestClassArg (unittest.TestCase) : def test_add (self) : ca = ClassArg().add('test', int) diff --git a/source/tests/test_sel_idx.py b/source/tests/test_sel_idx.py index 47ef9c8496..23d0869b61 100644 --- a/source/tests/test_sel_idx.py +++ b/source/tests/test_sel_idx.py @@ -4,8 +4,6 @@ from deepmd.common import select_idx_map -def test(): - raise RuntimeError class TestSelIdx (unittest.TestCase) : def test_add (self) : From 7db9d8c2f92bbdf9d81fee48ed86aede3c990def Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sat, 20 Feb 2021 21:03:03 -0500 Subject: [PATCH 174/562] set cov path --- .github/workflows/test_python.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index 0ab95f8c0d..2e036710db 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -70,5 +70,4 @@ jobs: CC: gcc-${{ matrix.gcc }} CXX: g++-${{ matrix.gcc }} TENSORFLOW_VERSION: ${{ matrix.tf }} - - run: cd source/tests && pytest - - run: codecov + - run: cd source/tests && pytest --cov=deepmd && codecov From b3b0e2cfe64bf6f6bb7cbc4d3bec2ec247099d71 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sat, 20 Feb 2021 21:23:40 -0500 Subject: [PATCH 175/562] change cov dir --- .github/workflows/test_python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index 2e036710db..37bd2d000a 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -70,4 +70,4 @@ jobs: CC: gcc-${{ matrix.gcc }} CXX: g++-${{ matrix.gcc }} TENSORFLOW_VERSION: ${{ matrix.tf }} - - run: cd source/tests && pytest --cov=deepmd && codecov + - run: cd source/tests && pytest --cov=../train --cov=../../deepmd && codecov From 3313beb1998958fcce395bec90a9c911ecfcf6d9 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sat, 20 Feb 2021 21:45:29 -0500 Subject: [PATCH 176/562] use develop mode --- .github/workflows/test_python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index 37bd2d000a..a93f997e31 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -65,7 +65,7 @@ jobs: - run: | sudo apt update sudo apt install gcc-${{ matrix.gcc }} g++-${{ matrix.gcc }} - - run: pip install .[cpu,test] codecov + - run: pip install -e .[cpu,test] codecov env: CC: gcc-${{ matrix.gcc }} CXX: g++-${{ matrix.gcc }} From eb02e5b09fcee41d03ac812f48aa9f97b982a662 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sat, 20 Feb 2021 22:15:33 -0500 Subject: [PATCH 177/562] running tests in the root directory --- .github/workflows/test_python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index a93f997e31..469dcd869b 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -70,4 +70,4 @@ jobs: CC: gcc-${{ matrix.gcc }} CXX: g++-${{ matrix.gcc }} TENSORFLOW_VERSION: ${{ matrix.tf }} - - run: cd source/tests && pytest --cov=../train --cov=../../deepmd && codecov + - run: pytest --cov=deepmd source/tests && codecov From bfecaf6112c05d4a8f209c919bdeff4559128b8c Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sat, 20 Feb 2021 22:40:09 -0500 Subject: [PATCH 178/562] fix errors --- source/tests/common.py | 7 +++++++ source/tests/test_compat_input.py | 2 +- source/tests/test_data_modifier.py | 4 ++-- source/tests/test_fitting_stat.py | 2 +- source/tests/test_model_loc_frame.py | 4 ++-- source/tests/test_model_se_a.py | 4 ++-- source/tests/test_model_se_a_aparam.py | 4 ++-- source/tests/test_model_se_a_fparam.py | 4 ++-- source/tests/test_model_se_a_srtab.py | 4 ++-- source/tests/test_model_se_r.py | 4 ++-- source/tests/test_polar_se_a.py | 4 ++-- source/tests/test_wfc.py | 4 ++-- 12 files changed, 27 insertions(+), 20 deletions(-) diff --git a/source/tests/common.py b/source/tests/common.py index c1cbb5bd65..89f1e32714 100644 --- a/source/tests/common.py +++ b/source/tests/common.py @@ -1,10 +1,12 @@ import os, sys, dpdata import numpy as np +import pathlib from deepmd.env import tf from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.common import j_loader as dp_j_loader if GLOBAL_NP_FLOAT_PRECISION == np.float32 : global_default_fv_hh = 1e-2 @@ -347,3 +349,8 @@ def virial_dw_test (inter, num_v = (ll_1 - ll_2) / (2. * hh) ana_v = dw_0[ii] testCase.assertAlmostEqual(num_v, ana_v, places = places) + +tests_path = pathlib.Path(__file__).parent.absolute() + +def j_loader(filename): + return dp_j_loader(tests_path/filename) \ No newline at end of file diff --git a/source/tests/test_compat_input.py b/source/tests/test_compat_input.py index a7c2c7f083..dbdfc555d4 100644 --- a/source/tests/test_compat_input.py +++ b/source/tests/test_compat_input.py @@ -3,7 +3,7 @@ import unittest from deepmd.utils.compat import convert_input_v0_v1 -from deepmd.common import j_loader +from common import j_loader class TestConvertInput (unittest.TestCase) : def test_convert_smth(self): diff --git a/source/tests/test_data_modifier.py b/source/tests/test_data_modifier.py index e3f1561ca9..8423f26dee 100644 --- a/source/tests/test_data_modifier.py +++ b/source/tests/test_data_modifier.py @@ -3,7 +3,7 @@ import unittest from deepmd.env import tf -from deepmd.common import j_must_have, data_requirement, j_loader +from deepmd.common import j_must_have, data_requirement from deepmd.run_options import RunOptions from deepmd.trainer import NNPTrainer from deepmd.utils.data_system import DeepmdDataSystem @@ -13,7 +13,7 @@ from deepmd.infer.ewald_recp import EwaldRecp from deepmd.infer.data_modifier import DipoleChargeModifier -from common import Data +from common import Data, j_loader if GLOBAL_NP_FLOAT_PRECISION == np.float32 : global_default_fv_hh = 1e-2 diff --git a/source/tests/test_fitting_stat.py b/source/tests/test_fitting_stat.py index b56e72cc88..a17bef6453 100644 --- a/source/tests/test_fitting_stat.py +++ b/source/tests/test_fitting_stat.py @@ -5,7 +5,7 @@ from collections import defaultdict from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting -from deepmd.common import j_loader +from common import j_loader input_json = 'water_se_a_afparam.json' diff --git a/source/tests/test_model_loc_frame.py b/source/tests/test_model_loc_frame.py index cf8fb7417e..7845b2b6f8 100644 --- a/source/tests/test_model_loc_frame.py +++ b/source/tests/test_model_loc_frame.py @@ -1,14 +1,14 @@ import dpdata,os,sys,unittest import numpy as np from deepmd.env import tf -from common import Data,gen_data +from common import Data,gen_data, j_loader from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptLocFrame from deepmd.fit import EnerFitting from deepmd.model import Model -from deepmd.common import j_must_have, j_loader +from deepmd.common import j_must_have GLOBAL_ENER_FLOAT_PRECISION = tf.float64 GLOBAL_TF_FLOAT_PRECISION = tf.float64 diff --git a/source/tests/test_model_se_a.py b/source/tests/test_model_se_a.py index 4f0c3f0562..c26e134b86 100644 --- a/source/tests/test_model_se_a.py +++ b/source/tests/test_model_se_a.py @@ -2,14 +2,14 @@ import dpdata,os,sys,unittest import numpy as np from deepmd.env import tf -from common import Data,gen_data +from common import Data,gen_data, j_loader from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting from deepmd.model import Model -from deepmd.common import j_must_have, j_loader +from deepmd.common import j_must_have GLOBAL_ENER_FLOAT_PRECISION = tf.float64 GLOBAL_TF_FLOAT_PRECISION = tf.float64 diff --git a/source/tests/test_model_se_a_aparam.py b/source/tests/test_model_se_a_aparam.py index 352e5c7931..79f9bfbbb0 100644 --- a/source/tests/test_model_se_a_aparam.py +++ b/source/tests/test_model_se_a_aparam.py @@ -1,14 +1,14 @@ import dpdata,os,sys,unittest import numpy as np from deepmd.env import tf -from common import Data,gen_data +from common import Data,gen_data, j_loader from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting from deepmd.model import Model -from deepmd.common import j_must_have, j_loader +from deepmd.common import j_must_have GLOBAL_ENER_FLOAT_PRECISION = tf.float64 GLOBAL_TF_FLOAT_PRECISION = tf.float64 diff --git a/source/tests/test_model_se_a_fparam.py b/source/tests/test_model_se_a_fparam.py index 4235b03e5b..3f5321a49e 100644 --- a/source/tests/test_model_se_a_fparam.py +++ b/source/tests/test_model_se_a_fparam.py @@ -1,14 +1,14 @@ import dpdata,os,sys,unittest import numpy as np from deepmd.env import tf -from common import Data,gen_data +from common import Data,gen_data, j_loader from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting from deepmd.model import Model -from deepmd.common import j_must_have, j_loader +from deepmd.common import j_must_have GLOBAL_ENER_FLOAT_PRECISION = tf.float64 GLOBAL_TF_FLOAT_PRECISION = tf.float64 diff --git a/source/tests/test_model_se_a_srtab.py b/source/tests/test_model_se_a_srtab.py index 3debcb97b1..8c39d9a6b8 100644 --- a/source/tests/test_model_se_a_srtab.py +++ b/source/tests/test_model_se_a_srtab.py @@ -1,14 +1,14 @@ import dpdata,os,sys,unittest import numpy as np from deepmd.env import tf -from common import Data,gen_data +from common import Data,gen_data, j_loader from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting from deepmd.model import Model -from deepmd.common import j_must_have, j_loader +from deepmd.common import j_must_have GLOBAL_ENER_FLOAT_PRECISION = tf.float64 GLOBAL_TF_FLOAT_PRECISION = tf.float64 diff --git a/source/tests/test_model_se_r.py b/source/tests/test_model_se_r.py index 8b32e99125..bce63f5b20 100644 --- a/source/tests/test_model_se_r.py +++ b/source/tests/test_model_se_r.py @@ -1,14 +1,14 @@ import dpdata,os,sys,unittest import numpy as np from deepmd.env import tf -from common import Data,gen_data +from common import Data,gen_data, j_loader from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeR from deepmd.fit import EnerFitting from deepmd.model import Model -from deepmd.common import j_must_have, j_loader +from deepmd.common import j_must_have GLOBAL_ENER_FLOAT_PRECISION = tf.float64 GLOBAL_TF_FLOAT_PRECISION = tf.float64 diff --git a/source/tests/test_polar_se_a.py b/source/tests/test_polar_se_a.py index 468f219474..bfa91ab554 100644 --- a/source/tests/test_polar_se_a.py +++ b/source/tests/test_polar_se_a.py @@ -1,14 +1,14 @@ import dpdata,os,sys,unittest import numpy as np from deepmd.env import tf -from common import Data,gen_data +from common import Data,gen_data, j_loader from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeA from deepmd.fit import PolarFittingSeA from deepmd.model import PolarModel -from deepmd.common import j_must_have, j_loader +from deepmd.common import j_must_have GLOBAL_ENER_FLOAT_PRECISION = tf.float64 GLOBAL_TF_FLOAT_PRECISION = tf.float64 diff --git a/source/tests/test_wfc.py b/source/tests/test_wfc.py index 272310effa..6c92fab5fd 100644 --- a/source/tests/test_wfc.py +++ b/source/tests/test_wfc.py @@ -1,14 +1,14 @@ import dpdata,os,sys,unittest import numpy as np from deepmd.env import tf -from common import Data,gen_data +from common import Data,gen_data, j_loader from deepmd.run_options import RunOptions from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptLocFrame from deepmd.fit import WFCFitting from deepmd.model import WFCModel -from deepmd.common import j_must_have, j_loader +from deepmd.common import j_must_have GLOBAL_ENER_FLOAT_PRECISION = tf.float64 GLOBAL_TF_FLOAT_PRECISION = tf.float64 From ff9a5fde57d21188775c18b03efa7ac918bc8279 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sat, 20 Feb 2021 23:16:35 -0500 Subject: [PATCH 179/562] fix bug --- source/tests/test_data_modifier.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/tests/test_data_modifier.py b/source/tests/test_data_modifier.py index 8423f26dee..dfa7b65754 100644 --- a/source/tests/test_data_modifier.py +++ b/source/tests/test_data_modifier.py @@ -13,7 +13,7 @@ from deepmd.infer.ewald_recp import EwaldRecp from deepmd.infer.data_modifier import DipoleChargeModifier -from common import Data, j_loader +from common import Data, j_loader, tests_path if GLOBAL_NP_FLOAT_PRECISION == np.float32 : global_default_fv_hh = 1e-2 @@ -56,6 +56,7 @@ def _setUp(self): # init data system systems = j_must_have(jdata['training'], 'systems') + systems[0] = tests_path / systems[0] set_pfx = j_must_have(jdata['training'], 'set_prefix') batch_size = j_must_have(jdata['training'], 'batch_size') test_size = j_must_have(jdata['training'], 'numb_test') From 39cebeb1dabebc9568681bb06d085a23111e4c48 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sat, 20 Feb 2021 23:28:39 -0500 Subject: [PATCH 180/562] fix bug --- source/tests/test_data_modifier.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/tests/test_data_modifier.py b/source/tests/test_data_modifier.py index dfa7b65754..2fb5008852 100644 --- a/source/tests/test_data_modifier.py +++ b/source/tests/test_data_modifier.py @@ -85,7 +85,7 @@ def _setUp(self): input_graph_def, nodes.split(",") ) - output_graph = os.path.join(modifier_datapath, 'dipole.pb') + output_graph = tests_path / os.path.join(modifier_datapath, 'dipole.pb') with tf.gfile.GFile(output_graph, "wb") as f: f.write(output_graph_def.SerializeToString()) @@ -94,7 +94,7 @@ def test_fv(self): self._test_fv() def _test_fv (self): - dcm = DipoleChargeModifier(os.path.join(modifier_datapath, "dipole.pb"), + dcm = DipoleChargeModifier(tests_path / os.path.join(modifier_datapath, "dipole.pb"), [-8], [6, 1], 1, From 2f030b1f4fb34b64a9e65bde0c2cd588d4e153d1 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sat, 20 Feb 2021 23:39:51 -0500 Subject: [PATCH 181/562] convert PosixPath to string --- source/tests/test_data_modifier.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/tests/test_data_modifier.py b/source/tests/test_data_modifier.py index 2fb5008852..8a89f0bd8e 100644 --- a/source/tests/test_data_modifier.py +++ b/source/tests/test_data_modifier.py @@ -85,7 +85,7 @@ def _setUp(self): input_graph_def, nodes.split(",") ) - output_graph = tests_path / os.path.join(modifier_datapath, 'dipole.pb') + output_graph = str(tests_path / os.path.join(modifier_datapath, 'dipole.pb')) with tf.gfile.GFile(output_graph, "wb") as f: f.write(output_graph_def.SerializeToString()) From 15e93aa034131ba75c6a6bd9c043f9f14976a7da Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sat, 20 Feb 2021 23:49:56 -0500 Subject: [PATCH 182/562] +1 --- source/tests/test_data_modifier.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/tests/test_data_modifier.py b/source/tests/test_data_modifier.py index 8a89f0bd8e..50d0211399 100644 --- a/source/tests/test_data_modifier.py +++ b/source/tests/test_data_modifier.py @@ -94,7 +94,7 @@ def test_fv(self): self._test_fv() def _test_fv (self): - dcm = DipoleChargeModifier(tests_path / os.path.join(modifier_datapath, "dipole.pb"), + dcm = DipoleChargeModifier(str(tests_path / os.path.join(modifier_datapath, "dipole.pb")), [-8], [6, 1], 1, From fb81ee81772a60d94164da1a4d945210d22c5bc1 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Sun, 21 Feb 2021 15:02:30 +0800 Subject: [PATCH 183/562] adjust the interface of custome op --- source/lib/include/CustomeOperation.h | 25 ---- source/lib/include/DeviceFunctor.h | 4 +- source/lib/include/prod_env_mat.h | 8 +- source/lib/src/prod_env_mat.cc | 76 ++++++++++++- source/op/cuda/descrpt_se_a.cu | 152 ++++++++++++++----------- source/op/descrpt_se_a_multi_device.cc | 91 ++++----------- 6 files changed, 188 insertions(+), 168 deletions(-) diff --git a/source/lib/include/CustomeOperation.h b/source/lib/include/CustomeOperation.h index ad38173a2c..f7cd8e1b01 100644 --- a/source/lib/include/CustomeOperation.h +++ b/source/lib/include/CustomeOperation.h @@ -13,31 +13,6 @@ using CPUDevice = Eigen::ThreadPoolDevice; using GPUDevice = Eigen::GpuDevice; -struct NeighborInfo { - int type; - double dist; - int index; - NeighborInfo () : type (0), dist(0), index(0) {} - NeighborInfo (int tt, double dd, int ii) : type (tt), dist(dd), index(ii) {} - - bool operator < (const NeighborInfo & b) const { - return (type < b.type || (type == b.type && (dist < b.dist || (dist == b.dist && index < b.index)))); - } -}; - - - - - -#if GOOGLE_CUDA -template -void DescrptSeAGPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { - DescrptSeAGPUExecuteFunctor()(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); -} -#endif // GOOGLE_CUDA -// ****************************************************************************** -// end of custome op DescrptSeA -// ****************************************************************************** inline void make_descript_range (int & idx_start, int & idx_end, const int & nei_idx, const int& n_a_sel, const int n_a_shift) { if (nei_idx < n_a_sel) { diff --git a/source/lib/include/DeviceFunctor.h b/source/lib/include/DeviceFunctor.h index 447f0cacd7..82b6cf62fb 100644 --- a/source/lib/include/DeviceFunctor.h +++ b/source/lib/include/DeviceFunctor.h @@ -19,8 +19,8 @@ inline void cudaAssert(cudaError_t code, const char *file, int line, bool abort= } template -struct DescrptSeAGPUExecuteFunctor { - void operator()(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descript, FPTYPE * descript_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int MAGIC_NUMBER); +struct DescrptSeAFunctor { + void operator()(FPTYPE * descript, FPTYPE * descript_deriv, FPTYPE * rij, int * nlist, const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec, const int max_nbor_size); }; template diff --git a/source/lib/include/prod_env_mat.h b/source/lib/include/prod_env_mat.h index dd28ff1c6b..1348ee02cf 100644 --- a/source/lib/include/prod_env_mat.h +++ b/source/lib/include/prod_env_mat.h @@ -1,5 +1,8 @@ #pragma once #include +#if GOOGLE_CUDA +#include "DeviceFunctor.h" +#endif template void prod_env_mat_a_cpu( @@ -12,7 +15,6 @@ void prod_env_mat_a_cpu( const int * ilist, const int * jrange, const int * jlist, - const int max_nbor_size, const FPTYPE * avg, const FPTYPE * std, const int nloc, @@ -22,6 +24,7 @@ void prod_env_mat_a_cpu( const float rcut_smth, const std::vector sec); +#if GOOGLE_CUDA template void prod_env_mat_a_gpu_nv( FPTYPE * em, @@ -33,6 +36,8 @@ void prod_env_mat_a_gpu_nv( const int * ilist, const int * jrange, const int * jlist, + int * array_int, + unsigned long long * array_longlong, const int max_nbor_size, const FPTYPE * avg, const FPTYPE * std, @@ -42,3 +47,4 @@ void prod_env_mat_a_gpu_nv( const float rcut, const float rcut_smth, const std::vector sec); +#endif \ No newline at end of file diff --git a/source/lib/src/prod_env_mat.cc b/source/lib/src/prod_env_mat.cc index a1c9492829..3a8c49c1ff 100644 --- a/source/lib/src/prod_env_mat.cc +++ b/source/lib/src/prod_env_mat.cc @@ -15,7 +15,6 @@ void prod_env_mat_a_cpu( const int * ilist, const int * jrange, const int * jlist, - const int max_nbor_size, const FPTYPE * avg, const FPTYPE * std, const int nloc, @@ -100,7 +99,6 @@ void prod_env_mat_a_cpu( const int * ilist, const int * jrange, const int * jlist, - const int max_nbor_size, const double * avg, const double * std, const int nloc, @@ -121,6 +119,79 @@ void prod_env_mat_a_cpu( const int * ilist, const int * jrange, const int * jlist, + const float * avg, + const float * std, + const int nloc, + const int nall, + const int ntypes, + const float rcut, + const float rcut_smth, + const std::vector sec); + +#if GOOGLE_CUDA +template +void prod_env_mat_a_gpu_nv( + FPTYPE * em, + FPTYPE * em_deriv, + FPTYPE * rij, + int * nlist, + const FPTYPE * coord, + const int * type, + const int * ilist, + const int * jrange, + const int * jlist, + int * array_int, + unsigned long long * array_longlong, + const int max_nbor_size, + const FPTYPE * avg, + const FPTYPE * std, + const int nloc, + const int nall, + const int ntypes, + const float rcut, + const float rcut_smth, + const std::vector sec) { + DescrptSeAFunctor()( + em, em_deriv, rij, nlist, + coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, nloc, nall, rcut, rcut_smth, sec, max_nbor_size); +} + +template +void prod_env_mat_a_gpu_nv( + double * em, + double * em_deriv, + double * rij, + int * nlist, + const double * coord, + const int * type, + const int * ilist, + const int * jrange, + const int * jlist, + int * array_int, + unsigned long long * array_longlong, + const int max_nbor_size, + const double * avg, + const double * std, + const int nloc, + const int nall, + const int ntypes, + const float rcut, + const float rcut_smth, + const std::vector sec); + +template +void prod_env_mat_a_gpu_nv( + float * em, + float * em_deriv, + float * rij, + int * nlist, + const float * coord, + const int * type, + const int * ilist, + const int * jrange, + const int * jlist, + int * array_int, + unsigned long long * array_longlong, const int max_nbor_size, const float * avg, const float * std, @@ -130,3 +201,4 @@ void prod_env_mat_a_cpu( const float rcut, const float rcut_smth, const std::vector sec); +#endif diff --git a/source/op/cuda/descrpt_se_a.cu b/source/op/cuda/descrpt_se_a.cu index 999d4c2b39..dc6d7aa2b8 100644 --- a/source/op/cuda/descrpt_se_a.cu +++ b/source/op/cuda/descrpt_se_a.cu @@ -118,7 +118,7 @@ __global__ void format_nlist_fill_b_se_a(int * nlist, const int * jrange, const int * jlist, int_64 * key, - const int * sec_a, + const int * sec, const int sec_a_size, int * nei_iter_dev, const int MAX_NBOR_SIZE) @@ -135,12 +135,12 @@ __global__ void format_nlist_fill_b_se_a(int * nlist, int_64 * key_out = key + nloc * MAX_NBOR_SIZE + idy * MAX_NBOR_SIZE; for (int ii = 0; ii < sec_a_size; ii++) { - nei_iter[ii] = sec_a[ii]; + nei_iter[ii] = sec[ii]; } for (unsigned int kk = 0; key_out[kk] != key_out[MAX_NBOR_SIZE - 1]; kk++) { const int & nei_type = key_out[kk] / 1E15; - if (nei_iter[nei_type] < sec_a[nei_type + 1]) { + if (nei_iter[nei_type] < sec[nei_type + 1]) { row_nlist[nei_iter[nei_type]++] = key_out[kk] % 100000; } } @@ -248,7 +248,7 @@ void format_nbor_list_1024 ( const int* jrange, const int* jlist, const int& nloc, - const float& rcut_r, + const float& rcut, int * i_idx, int_64 * key ) @@ -264,7 +264,7 @@ void format_nbor_list_1024 ( type, jrange, jlist, - rcut_r, + rcut, key, i_idx, MAX_NBOR_SIZE @@ -282,7 +282,7 @@ void format_nbor_list_2048 ( const int* jrange, const int* jlist, const int& nloc, - const float& rcut_r, + const float& rcut, int * i_idx, int_64 * key ) @@ -298,7 +298,7 @@ void format_nbor_list_2048 ( type, jrange, jlist, - rcut_r, + rcut, key, i_idx, MAX_NBOR_SIZE @@ -316,7 +316,7 @@ void format_nbor_list_4096 ( const int* jrange, const int* jlist, const int& nloc, - const float& rcut_r, + const float& rcut, int * i_idx, int_64 * key ) @@ -332,7 +332,7 @@ void format_nbor_list_4096 ( type, jrange, jlist, - rcut_r, + rcut, key, i_idx, MAX_NBOR_SIZE @@ -343,78 +343,96 @@ void format_nbor_list_4096 ( BlockSortKernel <<>> (key, key + nloc * MAX_NBOR_SIZE); } + template -void DescrptSeAGPUExecuteFunctor::operator()(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descript, FPTYPE * descript_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { +void DescrptSeAFunctor::operator()( + FPTYPE * descript, + FPTYPE * descript_deriv, + FPTYPE * rij, + int * nlist, + const FPTYPE * coord, + const int * type, + const int * ilist, + const int * jrange, + const int * jlist, + int * array_int, + unsigned long long * array_longlong, + const FPTYPE * avg, + const FPTYPE * std, + const int nloc, + const int nall, + const float rcut, + const float rcut_smth, + const std::vector sec, + const int max_nbor_size) +{ const int LEN = 256; + const int nnei = sec.back(); + const int ndescrpt = nnei * 4; int nblock = (nloc + LEN -1) / LEN; int * sec_a_dev = array_int; - int * nei_iter = array_int + sec_a.size(); // = new int[sec_a_size]; - int * i_idx = array_int + sec_a.size() + nloc * sec_a.size(); + int * nei_iter = array_int + sec.size(); // = new int[sec_a_size]; + int * i_idx = array_int + sec.size() + nloc * sec.size(); int_64 * key = array_longlong; cudaError_t res = cudaSuccess; - res = cudaMemcpy(sec_a_dev, &sec_a[0], sizeof(int) * sec_a.size(), cudaMemcpyHostToDevice); cudaErrcheck(res); + res = cudaMemcpy(sec_a_dev, &sec[0], sizeof(int) * sec.size(), cudaMemcpyHostToDevice); cudaErrcheck(res); res = cudaMemset(key, 0xffffffff, sizeof(int_64) * nloc * max_nbor_size); cudaErrcheck(res); res = cudaMemset(nlist, -1, sizeof(int) * nloc * nnei); cudaErrcheck(res); res = cudaMemset(descript, 0.0, sizeof(FPTYPE) * nloc * ndescrpt); cudaErrcheck(res); res = cudaMemset(descript_deriv, 0.0, sizeof(FPTYPE) * nloc * ndescrpt * 3); cudaErrcheck(res); - if (fill_nei_a) { - // ~~~ - // cudaProfilerStart(); - get_i_idx_se_a<<>> (nloc, ilist, i_idx); + get_i_idx_se_a<<>> (nloc, ilist, i_idx); - if (max_nbor_size <= 1024) { - format_nbor_list_1024 ( - coord, - type, - jrange, - jlist, - nloc, - rcut_r, - i_idx, - key - ); - } else if (max_nbor_size <= 2048) { - format_nbor_list_2048 ( - coord, - type, - jrange, - jlist, - nloc, - rcut_r, - i_idx, - key - ); - } else if (max_nbor_size <= 4096) { - format_nbor_list_4096 ( - coord, - type, - jrange, - jlist, - nloc, - rcut_r, - i_idx, - key - ); - } - - format_nlist_fill_b_se_a<<>> ( - nlist, - nnei, - nloc, - jrange, - jlist, - key, - sec_a_dev, - sec_a.size(), - nei_iter, - max_nbor_size - ); + if (max_nbor_size <= 1024) { + format_nbor_list_1024 ( + coord, + type, + jrange, + jlist, + nloc, + rcut, + i_idx, + key + ); + } else if (max_nbor_size <= 2048) { + format_nbor_list_2048 ( + coord, + type, + jrange, + jlist, + nloc, + rcut, + i_idx, + key + ); + } else if (max_nbor_size <= 4096) { + format_nbor_list_4096 ( + coord, + type, + jrange, + jlist, + nloc, + rcut, + i_idx, + key + ); } + format_nlist_fill_b_se_a<<>> ( + nlist, + nnei, + nloc, + jrange, + jlist, + key, + sec_a_dev, + sec.size(), + nei_iter, + max_nbor_size + ); - compute_descriptor_se_a <<>> (descript, ndescrpt, descript_deriv, ndescrpt * 3, rij, nnei * 3, type, avg, std, nlist, nnei, coord, rcut_r_smth, rcut_r, sec_a.back()); + compute_descriptor_se_a <<>> (descript, ndescrpt, descript_deriv, ndescrpt * 3, rij, nnei * 3, type, avg, std, nlist, nnei, coord, rcut_smth, rcut, sec.back()); } -template struct DescrptSeAGPUExecuteFunctor; -template struct DescrptSeAGPUExecuteFunctor; \ No newline at end of file +template struct DescrptSeAFunctor; +template struct DescrptSeAFunctor; \ No newline at end of file diff --git a/source/op/descrpt_se_a_multi_device.cc b/source/op/descrpt_se_a_multi_device.cc index 83251b241c..1daf11fd20 100644 --- a/source/op/descrpt_se_a_multi_device.cc +++ b/source/op/descrpt_se_a_multi_device.cc @@ -1,6 +1,5 @@ #include "common.h" #include "prod_env_mat.h" -#include "CustomeOperation.h" REGISTER_OP("DescrptSeA") .Attr("T: {float, double}") @@ -33,47 +32,6 @@ struct DeviceFunctor { #endif // GOOGLE_CUDA }; -template -struct DescrptSeAFunctor { - void operator()( - const CPUDevice& d, - const FPTYPE * coord, - const int * type, - const int * mesh, - const int * ilist, - const int * jrange, - const int * jlist, - int * array_int, - unsigned long long * array_longlong, - const FPTYPE * avg, - const FPTYPE * std, - FPTYPE * descrpt, - FPTYPE * descrpt_deriv, - FPTYPE * rij, - int * nlist, - const int nloc, - const int nall, - const int nnei, - const int ntypes, - const int ndescrpt, - const float rcut_r, - const float rcut_r_smth, - const std::vector sec_a, - const bool fill_nei_a, - const int max_nbor_size - ) - { - prod_env_mat_a_cpu( - descrpt, descrpt_deriv, rij, nlist, - coord, type, ilist, jrange, jlist, max_nbor_size, avg, std, nloc, nall, ntypes, rcut_r, rcut_r_smth, sec_a); - } - - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const FPTYPE * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { - DescrptSeAGPULauncher(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); - } - #endif // GOOGLE_CUDA -}; template class DescrptSeAOp : public OpKernel { @@ -180,6 +138,16 @@ class DescrptSeAOp : public OpKernel { nlist_shape, &nlist_tensor)); + FPTYPE * descrpt = descrpt_tensor->flat().data(); + FPTYPE * descrpt_deriv = descrpt_deriv_tensor->flat().data(); + FPTYPE * rij = rij_tensor->flat().data(); + int * nlist = nlist_tensor->flat().data(); + + const FPTYPE * coord = coord_tensor.flat().data(); + const FPTYPE * avg = avg_tensor.flat().data(); + const FPTYPE * std = std_tensor.flat().data(); + const int * type = type_tensor.flat().data(); + if(device == "GPU") { // allocate temp memory, temp memory must not be used after this operation! Tensor int_temp; @@ -196,40 +164,22 @@ class DescrptSeAOp : public OpKernel { nbor_update(mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); OP_REQUIRES (context, (max_nbor_size <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than " + std::to_string(GPU_MAX_NBOR_SIZE) + ", which currently is not supported by deepmd-kit.")); + + // launch gpu compute function + prod_env_mat_a_gpu_nv( + descrpt, descrpt_deriv, rij, nlist, + coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, ntypes, rcut_r, rcut_r_smth, sec_a); } else if (device == "CPU") { memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); memcpy (&jrange, 8 + mesh_tensor.flat().data(), sizeof(int *)); memcpy (&jlist, 12 + mesh_tensor.flat().data(), sizeof(int *)); - } - DescrptSeAFunctor()( - context->eigen_device(), // define actually graph execution device - coord_tensor.matrix().data(), // related to the kk argument - type_tensor.matrix().data(), // also related to the kk argument - mesh_tensor.flat().data(), - ilist, - jrange, - jlist, - array_int, - array_longlong, - avg_tensor.matrix().data(), - std_tensor.matrix().data(), - descrpt_tensor->matrix().data(), - descrpt_deriv_tensor->matrix().data(), - rij_tensor->matrix().data(), - nlist_tensor->matrix().data(), - nloc, - nall, - nnei, - ntypes, - ndescrpt, - rcut_r, - rcut_r_smth, - sec_a, - fill_nei_a, - max_nbor_size - ); + // launch cpu compute function + prod_env_mat_a_cpu( + descrpt, descrpt_deriv, rij, nlist, + coord, type, ilist, jrange, jlist, avg, std, nloc, nall, ntypes, rcut_r, rcut_r_smth, sec_a); + } } ///////////////////////////////////////////////////////////////////////////////////////////// @@ -304,7 +254,6 @@ class DescrptSeAOp : public OpKernel { } delete [] mesh_host; } - }; // Register the CPU kernels. From 9af159fb91a6f5de51f58d1469f6a74815be38c4 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 21 Feb 2021 19:37:11 +0800 Subject: [PATCH 184/562] better format and implementation --- source/tests/common.py | 9 +++++---- source/tests/test_data_modifier.py | 3 ++- source/tests/test_data_modifier_shuffle.py | 3 ++- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/source/tests/common.py b/source/tests/common.py index 89f1e32714..d1e23c89ea 100644 --- a/source/tests/common.py +++ b/source/tests/common.py @@ -17,6 +17,11 @@ global_default_dw_hh = 1e-4 global_default_places = 5 +tests_path = pathlib.Path(__file__).parent.absolute() + +def j_loader(filename): + return dp_j_loader(tests_path/filename) + def gen_data() : tmpdata = Data(rand_pert = 0.1, seed = 1) sys = dpdata.LabeledSystem() @@ -350,7 +355,3 @@ def virial_dw_test (inter, ana_v = dw_0[ii] testCase.assertAlmostEqual(num_v, ana_v, places = places) -tests_path = pathlib.Path(__file__).parent.absolute() - -def j_loader(filename): - return dp_j_loader(tests_path/filename) \ No newline at end of file diff --git a/source/tests/test_data_modifier.py b/source/tests/test_data_modifier.py index 50d0211399..dc1a5420e6 100644 --- a/source/tests/test_data_modifier.py +++ b/source/tests/test_data_modifier.py @@ -56,7 +56,8 @@ def _setUp(self): # init data system systems = j_must_have(jdata['training'], 'systems') - systems[0] = tests_path / systems[0] + #systems[0] = tests_path / systems[0] + systems = [tests_path / ii for ii in systems] set_pfx = j_must_have(jdata['training'], 'set_prefix') batch_size = j_must_have(jdata['training'], 'batch_size') test_size = j_must_have(jdata['training'], 'numb_test') diff --git a/source/tests/test_data_modifier_shuffle.py b/source/tests/test_data_modifier_shuffle.py index 738d379721..e2e875c544 100644 --- a/source/tests/test_data_modifier_shuffle.py +++ b/source/tests/test_data_modifier_shuffle.py @@ -15,7 +15,7 @@ from deepmd.infer.data_modifier import DipoleChargeModifier from deepmd.infer.deep_dipole import DeepDipole -from common import Data +from common import Data, tests_path if GLOBAL_NP_FLOAT_PRECISION == np.float32 : global_default_fv_hh = 1e-2 @@ -63,6 +63,7 @@ def _setUp(self): # init data system systems = j_must_have(jdata['training'], 'systems') + systems = [tests_path / ii for ii in systems] set_pfx = j_must_have(jdata['training'], 'set_prefix') batch_size = j_must_have(jdata['training'], 'batch_size') test_size = j_must_have(jdata['training'], 'numb_test') From 408e0b896265629345f52a942551108b957ba688 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 21 Feb 2021 19:38:07 +0800 Subject: [PATCH 185/562] add unittests for deepmd.infer --- source/tests/infer/convert2pb.py | 13 + source/tests/infer/deepdipole.pbtxt | 10778 ++++++++++++ source/tests/infer/deeppolar.pbtxt | 11214 ++++++++++++ source/tests/infer/deeppot.pbtxt | 24313 ++++++++++++++++++++++++++ source/tests/test_deepdipole.py | 63 + source/tests/test_deeppolar.py | 63 + source/tests/test_deeppot.py | 266 + 7 files changed, 46710 insertions(+) create mode 100644 source/tests/infer/convert2pb.py create mode 100644 source/tests/infer/deepdipole.pbtxt create mode 100644 source/tests/infer/deeppolar.pbtxt create mode 100644 source/tests/infer/deeppot.pbtxt create mode 100644 source/tests/test_deepdipole.py create mode 100644 source/tests/test_deeppolar.py create mode 100644 source/tests/test_deeppot.py diff --git a/source/tests/infer/convert2pb.py b/source/tests/infer/convert2pb.py new file mode 100644 index 0000000000..bf77800613 --- /dev/null +++ b/source/tests/infer/convert2pb.py @@ -0,0 +1,13 @@ +from deepmd.env import tf +from google.protobuf import text_format +from tensorflow.python.platform import gfile +from tensorflow.python import pywrap_tensorflow +from tensorflow.python.framework import graph_util + +def convert_pbtxt_to_pb(pbtxtfile, pbfile): + with tf.gfile.FastGFile(pbtxtfile, 'r') as f: + graph_def = tf.GraphDef() + file_content = f.read() + # Merges the human-readable string in `file_content` into `graph_def`. + text_format.Merge(file_content, graph_def) + tf.train.write_graph(graph_def, './', pbfile, as_text=False) diff --git a/source/tests/infer/deepdipole.pbtxt b/source/tests/infer/deepdipole.pbtxt new file mode 100644 index 0000000000..354de0cb98 --- /dev/null +++ b/source/tests/infer/deepdipole.pbtxt @@ -0,0 +1,10778 @@ +node { + name: "Reshape_19/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: -1 + } + } + } +} +node { + name: "Reshape_16/shape/2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_23/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_23/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_23/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_22/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_22/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_22/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_15/shape/2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "Reshape_15/shape/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_21/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_21/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_21/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_20/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_20/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_20/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "final_layer_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "\210\212\326;n\025\322?._\212d\211\305\323\277n\275\017c\263S\351\277\001zs\376@H\311\277<\277\206\212\3604\377?\364Y]\307\256\257\324\277\0238r\333\020\314\331?_|\330\367\014\263\372\277" + } + } + } +} +node { + name: "final_layer_type_0/bias/read" + op: "Identity" + input: "final_layer_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_0/bias" + } + } + } +} +node { + name: "final_layer_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + dim { + size: 8 + } + } + tensor_content: "+\320w!\202=\267?Ln\020\000\0258\262\277 f_\241\301\331\311\277\234\233-^\252r\246\277P\024F.e+\341?L \241\\\360\n\264\277\013\227sP5\227\276?\316\024[\215\264\030\334\277\206R\232\300U\304\312?\2520\026gU\235\304\277\204\016^m\017\353\265?\3106)\237\264\031\315\277\374\000\240\344\315p\254?V\377\327\204\262\277\334?Kh\257g\"\376\316?\031\276\205\323\031n\262\277\374;\365H\354&\317\277N8\033\205\3615\346?[\006\207\240\251\273\250\277_\352\027\254S+\307?\332O\243\324wS\314?W\211~\352?,\312?R\025\201\r6,\271?\317\321\005\254\323\211\251\27749\201N\001a\303\277\212\3204\037H\263\201?\274\223\377\3365\333\241\277\243\036#\241\312r\343\277\217\274\335\253\225\030\325\277*\334h\235\353Z\307\277\254?\022cA\267\320\277}\232t%\235\263\307\277|4,\350\326\263\201?\030\2623\013\027\271\315\277\342\366\3036\330\007\305\277\354\245\025\372\3216\235\277,\301\347P\177^\325?\262\005\306\341s\221\276?\206s}r\2418\233?\001\201Z\315\352\356\304\277r\311\t\251!\"\313\277H,\222\367\220\202\335?\317\014v\234S&\330\277\t\330\030V\334A\301\277\267\312\206\n\304K\303?-\n\316*f\254\311\277\207\350\315`M\001\332\277\321\352\353fX\304\257\277" + } + } + } +} +node { + name: "final_layer_type_0/matrix/read" + op: "Identity" + input: "final_layer_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_0/matrix" + } + } + } +} +node { + name: "layer_2_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\006\000\000\000" + } + } + } +} +node { + name: "layer_2_type_0/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\003\243\034K7\"\261?\334\2536\336\210\305\255?\251.\307\242K\000\253?\267\377\354\005\257v\302?\317\271\367\342\352\016\247?\350-\327.\242|\274?" + } + } + } +} +node { + name: "layer_2_type_0/idt/read" + op: "Identity" + input: "layer_2_type_0/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_0/idt" + } + } + } +} +node { + name: "layer_2_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\311$y\251eg\314?G[I\357G\345\323\277\033\032E\016}c\351\277\316\007\245~\342\224\321\277j\035\010#t\275\375?\014,\007\177\0300\332\277" + } + } + } +} +node { + name: "layer_2_type_0/bias/read" + op: "Identity" + input: "layer_2_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_0/bias" + } + } + } +} +node { + name: "layer_2_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + dim { + size: 6 + } + } + tensor_content: ":\347\304\372Y|\251?\244\224R\371\260\322\264\277\302\272ub\301\\\314\277Z\237\222\302\373\307\267\277N^\213@\n\315\341?\252\356f\366\2053\300\277\227\345\224\274^\n\262?\"\214\267\211\305K\335\277\\.\022\216\3721\315?\3078\t1c\025\317\2774\355:\030\262\222\202\277\264\021j\351W\352\324\277\'\213\256\226}\334r\277\2514\343\202e\251\336?\372\032\370\273d\271\320?Y\036\313ak\331\303\277P\037|\347v\316\326\277\316\335\371\236\337P\345?4;\203\332\265\216\263\277K\t5\223\206\376\272?\032\r\300\264+\344\303?\034\222\001\262&\365\311?\250\370j\377\356)\275?\023\220J\326\266\236\260\277w\005G\366\365\235\271\277\323\344\252\027)\312\273?C\340\326H\263\017\260?\210t\3412\221\t\345\2778#$\210\027\014\327\277\335\236~\272ee\311\277\357\010*\035b\231\312\277c\016F\301P1\310\277Y\321\020\353\255Z\266\2778\317(\022\256\320\321\277pf\361\344\216\336\306\277(\017]\372\264\035\251\277" + } + } + } +} +node { + name: "layer_2_type_0/matrix/read" + op: "Identity" + input: "layer_2_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_0/matrix" + } + } + } +} +node { + name: "layer_1_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\006\000\000\000" + } + } + } +} +node { + name: "layer_1_type_0/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\3234e\246\215\303\257?\200\354Q\036#\002\256?\216U\230\257n\352\252?\017L!\337z{\302?pI\027tr-\245?G\024\375\331^\225\262?" + } + } + } +} +node { + name: "layer_1_type_0/idt/read" + op: "Identity" + input: "layer_1_type_0/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_0/idt" + } + } + } +} +node { + name: "layer_1_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\214\251\310\303A\245\313?\367\316M\201x\351\323\277\254\314\3467Zb\351\277\323\326\377\325\261\230\321\2774UIXK\264\375?>\255h\375\354p\332\277" + } + } + } +} +node { + name: "layer_1_type_0/bias/read" + op: "Identity" + input: "layer_1_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_0/bias" + } + } + } +} +node { + name: "layer_1_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + dim { + size: 6 + } + } + tensor_content: "\305\030\2675\377{\254?\000V-]\204~\266\277\203@M\267]@\315\277\2711\033\215\366\\\266\277\373q2\267\256c\342?\315\"\371bt_\276\277O\245\350\037\r\311\260?:U\325\334-L\335\277\316=c\'\354A\315?\213^a\023\326%\317\277\264\000\036\032\226\357\211\277>WX\231\010C\325\277\367\363\360\357\024,\203\277b\335\315\333W\254\336?d\254\035\305\014\303\320?\016\031\001\341\217\364\303\277\365C\013\351\227\365\326\277\355\322Bm8(\345?\333\344)j\214\370\261\277l\017\250d}\026\273?o\345\345\030\376\341\303?f\271\244\236\007\372\311?yf\006\343\351\315\275?N.\250\253\211\032\257\277\331\221\033\335kr\272\277\200\007\016\307\221\360\273?\311\202\305\336\3729\260?\016{\217\310\204\025\345\277N\3674>\265\002\327\277\331\256\213gE\216\311\277\345\235m\254\223\344\311\277\023\344\037\210%\'\310\277WQv\334\315e\266\277\260\2455U\340\314\321\277K\261\327Ii{\306\277\251\2358\252\265\265\246\277" + } + } + } +} +node { + name: "layer_1_type_0/matrix/read" + op: "Identity" + input: "layer_1_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_0/matrix" + } + } + } +} +node { + name: "layer_0_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\006\000\000\000" + } + } + } +} +node { + name: "layer_0_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\304d+\024\232\367\312?S59K\245p\323\277\305\320\373X\210@\351\277\001\30679\222\222\322\277uh\315\317?N\375?:N\264\014\233\306\332\277" + } + } + } +} +node { + name: "layer_0_type_0/bias/read" + op: "Identity" + input: "layer_0_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_0/bias" + } + } + } +} +node { + name: "layer_0_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 32 + } + dim { + size: 6 + } + } + tensor_content: "\022z\211b\003~k?\273+\311\260h\027\200\277&>\302\311\344}\266\277Q\213w\2346(\266\277\344%\333\247\022\201\315?B\020\345e\021\371\273\277\341~\365\2747z\227?\232\252\017\2266Q\315\277ID\026\232\034\264\303?\331\244X\017\003\246\305\277\321\006d\240(\347\252\277\300\r\272z\037Q\313\2776\355\310e\343~\227\277n\201\330\310\350\356\322?\200\344C\324h\350\305?hP0=A4\276\277\013=\355\031%\361\317\277\0001\372z#*\326?I\350\211\374\240\207\267\277d\230)7\022\343\300?\2036\240\006\220[\304?D\010\n\324c\232\251?\336r[~\017\346\246\277\317\276w\365\245\223\273\277\200\277N\241\016}\272\277\036\031\326F\230\312\264?\037\353R\276A\203\253?\031r\362+\206\325\330\277\025\320TA\372Q\320\277qU\254y^\355\300\277&S\302\223Hq\305\277U\271<4\375\235\241\277\332\230\253\247k>\226?\007\355!\340\306\010\314\2774F\211\2424\340\312\277\267\244\210FW\005\271\2772\300\022g\317~\301?\224\333\001\216\227;\267?\376\341\252\274\025\270\240?KC\316\245&\256\306\277\032\302\034\020\254\265\307\277x\265\332\314\266j\320?>l\217\336\364|\316\277\225\310\251\354|\371u\277B\"\356\024\020\304\304?\301\002\2604)\026\302\277\311G\300\242;C\323\277\t\327\301\264Z\365\255\277\367\250s\247\217\274z\277e|\317\227[\'\316?\"D\245\0275\274\200\277vx8!\010x\273\277\375\355W\207\323\350\312?.\242\035\034\210\340\264\277?\362\371\025\007=\333\277t\317\252<\006K\301?\367\256\277\020\372|\262?AQ\004\360$\n\274\277\327\250\0316,F\264\277\016\227\204\200\251\341\246\277k,^\t6\344\301?\014\210\034\264\204\357\257?\365:Eal\026\305\277\340A\260\307JhX\277\257\2333TG\215\306\277\323E\324\234\240\301\245\277}\327\345\'2\355\277\277`\3738g\303,\322?o\001\254\300\212\236\264?m\260\203\275S=\322?e=\231\333\315\023\271\277&\225H\013\021\245\235\277i\310\252\276\tx\272\277\177o+\212\313\274\247\277~\277\213\002\253\345\312?\232\305\276\235\331$\227\277\003\272b\001\002\000\325\277\254\244\203\236t\311\320\277\373!\325\231\230\235\307?%\031b\364\233]\311?\332Z\025\027\036j\311?)\241\274|\207\274\242\277\017\220\000\025\327n\305\277\351=\377J\014\276\305\277\212\023\207T\247\256\310\277}\222\217\303\326&\333?&\331\370\244\026\314\302?\306?\325\343\263n\211\277\233\223M\nN\350\316?\365$N\373V\366\310?\032nS\241(\210\306\277\004\t\274\235\316\266\267\277\020^\326\355c\225z\277\005S:h$\346\232\277]\013f\340sj\275\277\017>\243\220\331}\312\277&\226\017\001\357\003\246\277f\241Xio\335\312?\350%\307\271;A\320?=\034W\252X\300\313\277\021\031V\254\361]\305\277\354\n\263\335I\273\315\277;\227\357\016\245\006\256?\024\277\355k\227\302\266?i\376E\223\203\363\247?9\023^\260\303\247\305\277\026\351\023\330$L\261?\0365j\3168\214\321\277\2661\331\366\255\006\301\277\314\0170\215u\272\323?&\013\274?@\"\314?Z\221\200M\276)\240\277X\013\252\320\037F\203\277|\336\321>\377K\264?\217\264\355\201\0046\315\277B\377E\rJ\326\320\277\310^p\032\274wh?\250\035\006\217\250\335\265\277;&\227TZ\201\306\277w\376\320f\225C\306\277\006\264\367;\233\331\260?\341\2077\300\272O\240\2771S\331\342Q\"\304?\335/\242\203W\233\264\277\206\213\375\243\327\357\272?\317%\226\263b\210\241?\375n$,\247K\262\277\350\235\352\230\301\212\306?\240\343F\274\305^ \277\366\264k\261\341\204\271\277\315%_\322 \037\300\277J\340/\315\216\336\272\277\371\350|\226\260J\250?\263\235*~\231\016t\277\t]\3405\224\271\252\277\344M(vq\205N?\370\030\360\004\260\021\330\277\326C,\261G\341\301\277\301K)r\030\376\320\277\244\243\236@\t\t\212?^\330\330H\342c\312?\203\2701_\360\346\022\306?\316\004B\330\226\253\257?\254Z\315g;\251\272\277|\346,\201\241\370\276\2779a\2703}\005\255?\252\232\213-S\343\205?\307\004\230\337Tl\343\277e)\261\256\362\003\324\277\351\263^\252\037\345\302\277NG\241\266J4\316\277\254\035\260\030\355\021\303\277" + } + } + } +} +node { + name: "filter_type_1/matrix_3_1/read" + op: "Identity" + input: "filter_type_1/matrix_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_3_1" + } + } + } +} +node { + name: "filter_type_1/concat_4/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_1/Reshape_10/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "HpI\030\371\024\317?h\007\225\326\205\227\326\277O\217\351\374\253\304\352\277\315[\376\006E-\317\277" + } + } + } +} +node { + name: "filter_type_1/bias_2_1/read" + op: "Identity" + input: "filter_type_1/bias_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_2_1" + } + } + } +} +node { + name: "filter_type_1/matrix_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\311f\210]\327`\271?\352\0229\002:r\302\277|\004\315\340.\333\325\277\357\247?\353\255t\271\277\335S\265\236\371\363\350?\347\326\276-DL\303\277\016\344\311e\355\320\302?&\360\312\354\233k\346\277" + } + } + } +} +node { + name: "filter_type_1/matrix_2_1/read" + op: "Identity" + input: "filter_type_1/matrix_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_2_1" + } + } + } +} +node { + name: "filter_type_1/concat_3/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_1/Reshape_9/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "HpI\030\371\024\317?h\007\225\326\205\227\326\277" + } + } + } +} +node { + name: "filter_type_1/bias_1_1/read" + op: "Identity" + input: "filter_type_1/bias_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_1_1" + } + } + } +} +node { + name: "filter_type_1/matrix_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\273d\222\344\365\361\301?\036lL\245<\026\312\277" + } + } + } +} +node { + name: "filter_type_1/matrix_1_1/read" + op: "Identity" + input: "filter_type_1/matrix_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_1_1" + } + } + } +} +node { + name: "filter_type_1/Reshape_8/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_3/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_3/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Reshape_7/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_2/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377p\001\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_2/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\270\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Reshape_6/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_1/Reshape_4/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "HpI\030\371\024\317?h\007\225\326\205\227\326\277O\217\351\374\253\304\352\277\315[\376\006E-\317\277\276\243a\304\243\217\376?M\242\014\333\220\242\327\277p\211\361\315\201\013\327?\215\250\225\211\216u\373\277" + } + } + } +} +node { + name: "filter_type_1/bias_3_0/read" + op: "Identity" + input: "filter_type_1/bias_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_3_0" + } + } + } +} +node { + name: "filter_type_1/matrix_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\273d\222\344\365\361\261?\036lL\245<\026\272\277\214\354S\252\310\350\316\277H\334\367\370\374\377\261\277}\226\303\001\373\244\341?\277\307pu\227J\273\277\275S\241\371)\234\272?\340\005\033s\010\265\337\277\020q\t\352\3400\310?\241\203c\207\320\324\313\277\013\321\202|\300V\250?\2003\336a\030\261\322\277\212\214\254DZ\257\226?Q\310\236\207\337\022\334?\267\364\270%\374\036\314?\232\3322\204O0\300\277I\344\227\310\363b\323\277\335\330\235\"\251\206\346?\334\360+E\342e\271\277\326\262!F\271\325\302?{\346\0031\301\\\311?>1_\360\346\022\306?\316\004B\330\226\253\257?\254Z\315g;\251\272\277|\346,\201\241\370\276\2779a\2703}\005\255?\252\232\213-S\343\205?\307\004\230\337Tl\343\277e)\261\256\362\003\324\277\351\263^\252\037\345\302\277NG\241\266J4\316\277\254\035\260\030\355\021\303\277" + } + } + } +} +node { + name: "filter_type_1/matrix_3_0/read" + op: "Identity" + input: "filter_type_1/matrix_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_3_0" + } + } + } +} +node { + name: "filter_type_1/concat_1/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_1/Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "HpI\030\371\024\317?h\007\225\326\205\227\326\277O\217\351\374\253\304\352\277\315[\376\006E-\317\277" + } + } + } +} +node { + name: "filter_type_1/bias_2_0/read" + op: "Identity" + input: "filter_type_1/bias_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_2_0" + } + } + } +} +node { + name: "filter_type_1/matrix_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\311f\210]\327`\271?\352\0229\002:r\302\277|\004\315\340.\333\325\277\357\247?\353\255t\271\277\335S\265\236\371\363\350?\347\326\276-DL\303\277\016\344\311e\355\320\302?&\360\312\354\233k\346\277" + } + } + } +} +node { + name: "filter_type_1/matrix_2_0/read" + op: "Identity" + input: "filter_type_1/matrix_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_2_0" + } + } + } +} +node { + name: "filter_type_1/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_1/Reshape_2/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "HpI\030\371\024\317?h\007\225\326\205\227\326\277" + } + } + } +} +node { + name: "filter_type_1/bias_1_0/read" + op: "Identity" + input: "filter_type_1/bias_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_1_0" + } + } + } +} +node { + name: "filter_type_1/matrix_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\273d\222\344\365\361\301?\036lL\245<\026\312\277" + } + } + } +} +node { + name: "filter_type_1/matrix_1_0/read" + op: "Identity" + input: "filter_type_1/matrix_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_1_0" + } + } + } +} +node { + name: "filter_type_1/Reshape_1/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_1/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_1/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\270\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "Reshape_8/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377(\002\000\000" + } + } + } +} +node { + name: "Slice_1/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_1/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_7/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 552 + } + } + } +} +node { + name: "strided_slice_9/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_9/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_9/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "mul_6/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 552 + } + } + } +} +node { + name: "add/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "strided_slice_8/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_8/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_8/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "mul_5/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "mul_4/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "strided_slice_7/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_7/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_7/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_6/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_6/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_6/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "mul_3/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_5/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_5/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_5/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_4/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_4/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_4/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "filter_type_0/Reshape_14/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "filter_type_0/transpose/perm" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\000\000\000\000\002\000\000\000\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_5/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\003\000\000\000\377\377\377\377" + } + } + } +} +node { + name: "filter_type_0/Slice_5/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\000\000\000\000\001\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_4/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_4/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\000\000\000\000\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_0/mul/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.007246376811594203 + } + } + } +} +node { + name: "filter_type_0/Reshape_13/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\\\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Reshape_12/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\\\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/concat_5/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_0/Reshape_11/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\372\032%&xH\321?\002\207\272\366X\267\322\2777)\232\376?\214\354\277;\227 0\226\036\325\277\207E\247\001F\300\375?\264\232q\317N%\333\277@.\246Z~\223\322?\370\270;x\277K\374\277" + } + } + } +} +node { + name: "filter_type_0/bias_3_1/read" + op: "Identity" + input: "filter_type_0/bias_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_3_1" + } + } + } +} +node { + name: "filter_type_0/matrix_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\311\033\2213\000\367\273?Y\227\255\231\016U\245\277\316*v\345\214\006\307\277\332\250\204\207%\373\252\277m~;\232_\236\343?\326\024\247\001n=\301\277\334\003\351\t9\274\277?\263i_~#E\340\277\222\254\013l\024O\315?\321Q\222a\365W\304\2771v\340\262\037f\273?\210\253M$L\006\314\277\007\210\032\026\306Y\263?\226\003\366\376\204N\340?\342\206|\3661\332\320?\253\007\254\253\231\302\263\277\307S\'\3138\325\320\277<\353\235|\337i\350?\316]z\304k/\244\277\236U\276\253@Q\313?C4*\027+/\320?\037\320\363\224\353\256\316?\364\001c\232_o\271?\366\021\374\240%\220\255\277\220\213?w6\262\264\277\n\276\212K1\320\274?$\357\327\204\002<\262?)\003\000\027pG\341\277\265\331\376\022\036\251\320\277T\314d\252\201]\263\277O\037\243\211B#\310\277P\236\274\223\033\320\270\277" + } + } + } +} +node { + name: "filter_type_0/matrix_3_1/read" + op: "Identity" + input: "filter_type_0/matrix_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_3_1" + } + } + } +} +node { + name: "filter_type_0/concat_4/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_0/Reshape_10/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "j|)\362@\260\313?\375\225\2668j\244\332\277\"\201\0073\341\364\354\277\201\347\353ZV\"\324\277" + } + } + } +} +node { + name: "filter_type_0/bias_2_1/read" + op: "Identity" + input: "filter_type_0/bias_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_2_1" + } + } + } +} +node { + name: "filter_type_0/matrix_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\350\027\370\263\254o\264?\002\2119\316B\'\267\277\235\003\'\317\035\010\322\277\357&\374\343r0\222\277\001da\225\303\371\350?\243\r2>\255\272\267\277\3207\367\313\347\302\312?\303b\202\334\223\341\343\277" + } + } + } +} +node { + name: "filter_type_0/matrix_2_1/read" + op: "Identity" + input: "filter_type_0/matrix_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_2_1" + } + } + } +} +node { + name: "filter_type_0/concat_3/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_0/Reshape_9/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\202\334`\230W\342\304?\265`\340\272\244>\326\277" + } + } + } +} +node { + name: "filter_type_0/bias_1_1/read" + op: "Identity" + input: "filter_type_0/bias_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_1_1" + } + } + } +} +node { + name: "filter_type_0/matrix_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\321(\206\250\232\025\310?e\361Mf\363\214\301\277" + } + } + } +} +node { + name: "filter_type_0/matrix_1_1/read" + op: "Identity" + input: "filter_type_0/matrix_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_1_1" + } + } + } +} +node { + name: "filter_type_0/Reshape_8/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_3/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_3/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Reshape_7/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_2/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377p\001\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_2/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\270\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Reshape_6/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_0/Reshape_4/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\255\352\350sZ+\306?\301\025\035iB\304\321\277D\253=\345N\177\354\277\037U9\340\340\200\325\277`\363\266\204\022@\376?qS\272-\211\373\335\277XH)Y<\214\320?\227\367\351*G\215\374\277" + } + } + } +} +node { + name: "filter_type_0/bias_3_0/read" + op: "Identity" + input: "filter_type_0/bias_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_3_0" + } + } + } +} +node { + name: "filter_type_0/matrix_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "p[\352\'4\\\260?\0322\337\272$\225\237\277\3626\3573\2445\306\277\2673)\276\330D\243\277\275\273+\335\233\r\343?\262\007\222=\260\212\312\2778\312\220\375\250\341%\277=\237\221\277a\367\332\277_U\266\203O\352\313?j\350\321\214\250;\303\277N?X.\026\344\273?Y\245\376?\240\036\314\277!\005(`\230\005\247?\332\\\323\010\255\246\325?f\261\304+\231C\305?\263\224\374\tK}\254\277W\262\020\354+R\322\277\236%\257\373A\274\350?~\204a6}|\242\277\276cJ\036\022\316\312?@\324n>\233\333\314?\347b\222\256\230M\262?\313\210\\\370\006\222\220\277_\\\223\027\021\014\241\277\275T\nMD\363\267\277US{M\022\003\300?z(\356\236\n\200\262?\3418\346\323\221%\341\277\255\336\331c\303\272\322\277\177s\313\274Z\003\320\277\274k\272\334\336.\322\277.<\266\000C\347\263\277" + } + } + } +} +node { + name: "filter_type_0/matrix_3_0/read" + op: "Identity" + input: "filter_type_0/matrix_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_3_0" + } + } + } +} +node { + name: "filter_type_0/concat_1/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_0/Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\256\243\315\021\333t\307?]\337R\277\247l\333\277\224\234dy\0247\355\277\274u\234l\205\303\307\277" + } + } + } +} +node { + name: "filter_type_0/bias_2_0/read" + op: "Identity" + input: "filter_type_0/bias_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_2_0" + } + } + } +} +node { + name: "filter_type_0/matrix_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\340\323\203\347r?\311\241\026\373\021\216\301\277\007\256mw\215\003F?\023\276\334#\244\035\305?\304\211\334\237\351I\264?]\325\266B\352\030\262\277&b\014v\323D\301\277\027|\206\032\277\255\321?\212\340h/\374\352\254\277r\242\256\r\377\313\246?\033=\360W\243\301\262?\205\213rGq\362\253?j+\034\347\203\377\213?\354\r\265`\002\206\257\277\272m\250\301r\016\257\277\027{~\363|\254}?9W\223\205&\206\210\277\235\231\035\336\3463\321\277\r#V\211\304\325\301\277A\377\344#\2674\264\277\306\024\327\366\341U\274\2774\001,]}\303\264\277\372\026Q\246\024\305\226\277\243\272\017iRS\301\277\nL\200~\213\353\272\277}Y\300\034\360X\247\2773\366\261\304\305\267\277?\3753\320g)\244\224?\205\374Q\352\360\325\220\277\303\353W\246_\234\273\277\034\003\352\300\270\325\266\277\315\325\331q\317\262\312?N\305\024{\251@\305\277\313\0023\257\213\265\255\277\376uf\222\346\365\262?,\344\276\206~t\266\277\231U\370\271\252\237\306\277\237\272\030\341\371O\233\277\270\326\377(\247\366\216?\250\255\241s\324\020\300?\375n\363 P0\253\277Ml\376\337\253m\255\277UpDr\177\234\312?\242\231\360Y:\025\243\277\245\n3a\347\370\322\277\244k.\240w\262\250?\302\\{\215s\nw?\357C,\rD\205\260\277\010\213$\333w\340\222\277\273\221 .\246\177\220\2771\271\':\221\345\275?\010\274\263\2633\261\204\277\365\350\305\026\004\361\305\277\256\335\275\344\254m\210?0q\366M\233V\261\277\312?D\234\017>y?\315\367\034\004\022:\260\277Ms\373\303\211\212\306??(\275z^]\235?\324\237\224\200\355d\317?\342\3123\377b7\204\277;k\374\256\366\323\220?\031-\310Tl\270\250\277\272E\316Uf\323\262\277\243\314-Z\241\'\276?w\302\270\347\325&\221?\356\202+|\0240\307\277\255F\333\027\266|\304\2779\356KL\200\324\304?\026\204Gg\324?\273?\213?\227:\206\r\275?\202u\252\016\314\036w?p\267\267\275@\310\260\277\037e\317\006>\275\266\277\374\347\232\222\026\341\274\277[@\363i[\221\321?9O\354b~$\263?9uk\230.\343\227?G\"\315\315\220\251\316?\320\301T\034\217\340\306?\344\031rf\032\276\277\207\254N\031\263\327X\277bs2+=\317\276?R\264\262\345\272\330\303?\003\247Q\265\277\016\277\277$=\355\355\377e\256\277\307\233\265l\330\021\301\277\344\365\200\265D\264\262?\356\326\374\237\324\'\240?F\016\365\313\314\240/?\367\205e\256\005\336\267\277A\370\347\353\347;\273?w\311\352m\265Z\305\277\227\324\330\304\233<\262\277\317\204\361\230 \023\310?\355Ezn\250G\300?\306r\'y\370\306\200?\351\204\340CxS\254?K\301\250\025\225Z\270?\317v\344\210\216\001\302\277m?d\270\327!\315\277h\232\324-O\366\234\277\204\307\242\332a\352\234\277\272;l\256y?\261\277\n\261\\\267\265g\267\277\n\024\033\235\016~\263?\037\013\216\341\227)\260\277\365\317\001|((\264?\361k\245\373\320\247\232\277\207\032\361\272>\262\301?\033\205\237\022\226\370\255?\314\014A\337o\016\233\277\241\217\230\236\271\001\267?\334\272w\003\232\346\236\277]\013$\346\2234\241\277\035]\034\377\272\324\234\277\331\277\265`\312#\241\277:\221\313\201a\322\260?\366s\214\363\247s\241\277\033\261\331u\360G\261\277y\255\316=V\267\245?\277p\233&\317P\313\277\311\177\223L\330\370\257\277<\272\356\373\377\374\304\2772~\004\033,\310\224\277]\346_X\"T\277?\231\224>e\013m\303?\3529\364\0347\021\306\277\226fZNw\t\306?\246@\303\030fw\207?\021q\362\222SU\214\277\327\235J\346\312\361\271?\221\275\303~\307\275\237\277\004W\0222\227/\212\277\300\221h\206\003c\271\277XV\326\320\232\341\265\277\236\244\016Z6\234\275?\016\276\304\002\210\327\306?zg\021\343\221\264\252?\025\240\2229F\223|?\374\355\310$\021Q\202?\235\177\227;\355V\307\277\037^`>\020\"\303?\334\211[\034a\332\302\277(<\033\302\222\351\301?X30\3749\305\255\277\262\205\304|\353\364\261\277\221\206\\\275\223\256\305?\260\030\031\203\377\272\241\277\261d_q\233\211\313\277\010X\251\267u(\203\277\002\307\271\360\321\332\217\277Sw\203\272\273\216\302\277W~N\273_\364\233\277A$0\t;\371\301?q\225\3756[B\244\277\335\337]/u\326\232?K\227\364\341$<\304\277f\246/\354w\310\246?7\270\r>;\230\303\277\322Fz\024\270\n\277\277\223\264\315\2068\346\207?\345\233\216s\232\003\254\277?\014\334\367\215N\303?4\324\'\0037f\305\277\265\257d\314\360.\301\277\203\277\202\205\344\210\265\277\331\017\372\220_\264\301\277\023\016\270[-\342\247?|\323\242\225\222\237\204\277\3020\234\372\213\332\266\277\006f9\005\377\261\264?Q\345\214<\302Q\270?\260_y\371N\021\231?\215\303\327N\235&\301\277e^F\225B\017\306?W\201\013T\347\252\277?5#\036\306\370v\300\277\347\374(b\357)\262?<\235\367B*\225\271?\253\017\257\377R1\306?\257\272yO\023\322\253\277\203.Rd\253\006\303?\210\277\251\222\252G\202?Ne\203F\215\341\205\277_\016u\201W\214\262\277\362>\036\030\2323\276?\247-~K\261\'\260?~\323b\222\363\323\230?\235\365\300\257\327\312\303\277a&\242|\211\237\232?\203ZlR\355\354\266\27769\246p\235\\\231\277\315+-\275\"\340\263\277\023\201\201`\250\345\271\277&\211\306\002T\246\262?e\334\345Y%.\265\277\000`\364\265\222\311\262\277\225\302\312\354\211\241\323\277}p|F\360\215\265?xZ\235\270u\301\277?\206\037\262\216\324\020\267?p\343\023\250\272\346\265?)\346m\345\217`\271\277&\035\223(\230\346\305\2778T\014\340\006)\273?B!\365\327\230\303\305\277N\246\261\217@\204\310?)qH$\036\354\302\277\332\306\367\215\350w\264\277\307\323g\231\315E\256?*\325\323\313\032\250\240\277\353\016_\201B}\244?\033\354\333o\010(\230\277E\"\374\321\024|\232?(\005\273\013\333&\242\277\371e\006\243]\032\266?\033M\013?o\360\242?\230i\266A\303\027\273\277\230\315\3326\035\357\305\2773\366\302\302p4\251?\326\023Ni\005\035\243\277\305\020\232B\217k\272?P]O\n\224\200\227\277\322!\204o\227\214\261?M%\246\255\373\256v\277\263o\234ZX\353\264?\000\244*\314G\371\301?\035\2461I\021\364\257\277\022L\007\227\345\220\241\277\217zh\274\264\251\301\277j\317B\331&\221\240\277\024W]+\353\270\274?\336\207\323\034\0313\201\277\315Rh\373\361 \300?\343M.tK_\224?u\221c\334\353\321H?\347\006O\236\3105q\277UC\rS\333\376\227?\351S\'\234l\342\257?\265\n-\013\263\256\242\277\236\251\205\014\274\355\277\277\353\252\214h\013l\235?c\260 .\212\305\302\277\262\311\307\242\226\374\261\277H\202yFW\351\261\277u\037=\342\326\237\232?\036\244\223qxU\305?f\330\235\371\017\232\304? \273=14@\301\277 \250\223\344\013\227\304\277\037\275G!<\314\242?Q\231\270\306\016\255\320?[E\304\362 )\260?\274\235\256_\335\270\270?#\370\377\\\301\323\247\277h*@\303\346\226\202\277\307^\010\220\027K\254?\315Kh\242\313\232\256\277\310\363$\020\205Y\265?3\204\237\256\037v\226\277\251x\360\034\236\256\274?\320\275\252\272\277\306\215\277\036\245\203\025\301V\261?\244\rG\275s#\304\277\005\002D\267\306\003\322?\266\030\252\323\006\034\313?5\023\257z\356\255\272\277l\235\367\214\200\025\264?\331f\036\n&\"\264?T\260V\334\361\365q?\276\351\216h\220\341\244?\361\265\342\007}K\257\277@\242l\2651+\257?\2176\3344\312\014\263?\033|\351\365c\026\317\277\003\001k\323K\311\253?EC\221\014\232l\307?\226\023`\362\235\322\243\277\247*\203G\253K\272?\251!I\377\371\303|\277}\333\326&\267B\236\277\213\245n$\333\354\204\277*W\3165\315-\234?\017;\243\236\220\246\304\277^\324\226\372\005n\277?\0332\210\312\266\252\224?\323\003\304\202\201\231\315\277\376\265]\231\351\355\237\277h\030L^\036\363\264\277\357\363\035\375\274{\303?\037\255\354\031\tV\272?\325\264x8LG\265?D\027c\241E\'\317\277`\364|\r\257\361\206?\253f\361\241\2448\243\277\371aB,\304$\271\277\215\177\317}hZ\262?D\003\201\016Oi\256\277q\322\003\325E\035\260\277\304\r*\030\"<\215\277(\337$\001&\345q?\231\354o\023\024t\254?T\272V\353\217\022\324\277\r\007H\364\262S\303?\323\262\323\007\276\214\261\277\334\024\016g\217h\304\277\377\215L\354\240\227\264\277\362\204\t\362\234\363\254?{\'\312\372\244p\255\277\344\030M\227\031M\304\277\232wL>\253\020\251\277\246\231\016M]&\'\277@\216`\356\022W\321?\226\340\250\364x\210\255?\211\007l\341h\252\266\277+\257\'\250\271\363\243?e\323\353\256l\357V\277\274+\021\363\341\031\273\277^E-\264F`\300?oM\"\326&=\276\277\364\203\234\366\"\366\265?=\030\321K(_\312\277\255\301S\325\341{\302\2770\215\355\217\034\025\252\277\377\026\203\367\210\227\264?NSt\306c\242\304\277D\372X\005\260\233\275\277\242\336\376zCo\247\277\"\217O\371>\204\254\277\177\364\212\017\212\252\235\277\272\261\226l/$\276?w2\311GV\375\272\277\316\207w\367\207;\262\277\331&\'\243,\233\310\277m\251G\277\362a\253\277\356;47\030\230\220?\251h\354\241\353\201\254\277\237\343\0035sV\314\277" + } + } + } +} +node { + name: "final_layer_type_0/matrix/read" + op: "Identity" + input: "final_layer_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_0/matrix" + } + } + } +} +node { + name: "layer_2_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\006\000\000\000" + } + } + } +} +node { + name: "layer_2_type_0/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\273\213h\300Wz\271?\'\300ra\030\336\276?\354gU\233\032q\302?\226\222-cGO\266?\005j\325\t\316\037\262?c\2169y\216\244\265?" + } + } + } +} +node { + name: "layer_2_type_0/idt/read" + op: "Identity" + input: "layer_2_type_0/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_0/idt" + } + } + } +} +node { + name: "layer_2_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\264T\352N2*\317?\224\304\265\335\374\354\327\277\224\330>\227\271[\354\277\323\365h\033\r\371\316\277\356\302PI;\t\376?\346T\241\362\365n\327\277" + } + } + } +} +node { + name: "layer_2_type_0/bias/read" + op: "Identity" + input: "layer_2_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_0/bias" + } + } + } +} +node { + name: "layer_2_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + dim { + size: 6 + } + } + tensor_content: "\030\032p\352\177}\250?\263\303\255\373\256u\254\277\261\005u\330\"\230\307\277\320\357\363\326\027\354\267\277f\305\003\230@c\342?\355\375\347\352\274\221\271\277\315]\244d\3457\300?\235\311\301d\300\362\341\277\315\340\357`\261%\304?`\226\242o2a\307\277_T\253Q\335\363\230?\272\254\255kA\251\322\277\033\221\266\370v\233\252?\224Y\245{\266\360\327?\235\213{\343\303\361\305?)\220\353~YK\265\277\257,\2129\351E\325\277:\272\317!\376u\346?\002~\000\\\366v\272\277\224\346\372\315\345\354\305?\255\355\202\251\004\371\317?\377\226:+\377r\305?\262\327c\335\254S\270?An\377\301Me\273\277^\025\037w\213\206\276\277\250\237\264+xC\241?\201\036\226%(\261\244\277\353J\273YgO\343\277\273\331\257O\215C\326\277\265Z\036\331u1\302\277\2150\317\014~\265\315\277\206a\033pfx\300\277\350\"\277\021\312\216v?\347\344\312e\274\213\323\277\336\215\020\330s\245\310\277FC\274)\033\364\271\277" + } + } + } +} +node { + name: "layer_2_type_0/matrix/read" + op: "Identity" + input: "layer_2_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_0/matrix" + } + } + } +} +node { + name: "layer_1_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\006\000\000\000" + } + } + } +} +node { + name: "layer_1_type_0/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "`V_\316\017\211\271?\227\324\223\025W^\277?\214\016>\2119\223\303?\332\344\371\363\001\223\266?\343\004;\331\202Y\262?\332\004Z\222\371\323\266?" + } + } + } +} +node { + name: "layer_1_type_0/idt/read" + op: "Identity" + input: "layer_1_type_0/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_0/idt" + } + } + } +} +node { + name: "layer_1_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\2317\001\335\025,\317?\375\026\017\276\357\004\330\277\001\307\211\346G\246\354\277di\331-\r\007\317\277\312\233\270\370\276\n\376?\326PvB|i\327\277" + } + } + } +} +node { + name: "layer_1_type_0/bias/read" + op: "Identity" + input: "layer_1_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_0/bias" + } + } + } +} +node { + name: "layer_1_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + dim { + size: 6 + } + } + tensor_content: "\306\344\376K\235\202\251?\023\203\013c2\377\254\277\301\362R\303\253\006\306\277.!\263W\031!\267\277\214\267\374\265\362r\342?\032w\362\240\016\010\272\277{lS\257\315<\300?k\007\326zT\326\341\277\370*Vt\022\025\303?\312S\310\322\016p\307\277\3753\031\334\'\246\227?\376H\227\256G\234\322\277\226\250\025\331\324\262\251?}DH\221O\370\327?r\256H_\245>\304?\362\354\276O\264B\266\277\031(d\030\223e\325\277R\272\244n\275\202\346?g\000\374c4f\272\277+;\027\030\261\026\306?M\2534R\343\230\320?Cw\243P\251\214\305?3\356^\260\006M\270?\337\210\257\316\347\226\273\277\341\204n\206\033}\276\277\033\234\360\235\240V\240?\342b\241<2-\251\2771W\213\341\340R\343\2772\376c\222<>\326\277\315(\343\225s&\302\2771\317N;V\316\315\277\374A\033\254N.\300\277\253\021\177\345\360E\211?\344\205\014\023\326\207\323\277\367\271\316\222\010\276\310\277\221Bv\224\335\323\271\277" + } + } + } +} +node { + name: "layer_1_type_0/matrix/read" + op: "Identity" + input: "layer_1_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_0/matrix" + } + } + } +} +node { + name: "layer_0_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\006\000\000\000" + } + } + } +} +node { + name: "layer_0_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\343\255\017h\303\216\316?\006\252\266}+\344\327\277\031\361\002\336\257\220\354\277\375\017Bx\353e\320\277\257\222\\\377r[\376?\3069\233S\345\221\330\277" + } + } + } +} +node { + name: "layer_0_type_0/bias/read" + op: "Identity" + input: "layer_0_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_0/bias" + } + } + } +} +node { + name: "layer_0_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 32 + } + dim { + size: 6 + } + } + tensor_content: "\240\207\252\263\201\313\243?\035\371\210w\211\306\265\277\310R\366G8-\311\277\035\227c\342\324\037\251\2772\337Q\031\376}\322?\315\344\360\316\367=\262\277K\000\351P\210;\255?g\227T!\003x\323\277\333 \010c\252\347\247?\371\276L\2679\355\300\277\374#\033\273\3203\201?\353\376\231\022\227\233\306\277\016\265\257$\347\235\206?\261\360Y?\345F\314?\230\251\0235\356e\260?\013\001\241/J\314\264\277\033\2337\332<\033\310\277\352a\202\223\376\202\330?trQ\271\037\t\255\277\3629\273\037\022\310\254?\267\323`m\352L\252?\223\342\374\337\032I\266?\307\016T\006\313p\217?\026\265m\250o\002\262\277\016\237\027h\330\275\261\277B\0141\332\216\317x?/\005\376F\206e\253\277$\177\354\177!y\326\277?\354\336N\355\326\310\277-\215\030#\254o\270\277\202h\224\034\371=\301\277\215u\343\004\222\202\273\277\2306\313\276\266\205\265\277\027v\311\205bj\307\277|\214\273\026\257\307\302\277\321\305\035\202h\301\257\277\362X\273\223\005\255\305?-.\366\230\256W\222?\210wk\025\275\260\262\277\342\212\317\274\254\023\302\277g\330&\262\321)\277\277x\372\3628\377\261\322?\016\343o\305\274/\312\277#\006{OA\r\264\277\205\271C\263M\347\254?\272:\354\212&\366\272\277dUu\214\363p\316\277\210\216\240S\014\"\227\277|\335C\016\263\036\234?>jxEo\220\304?\355\307h\026j\202\275\277\031)\251\023\021\020\262\277\360\307\206\343]_\321?\310\274\371s7\372\246\277\350\245\245\377\353%\331\277\276\235\"#\301\340\257?(s\002\306\233\037\241\277z\340\006\0361\325\262\277G\364\033 \227\022\220\277v\273\t\177\230\235\202\277\217\350\202\334H\r\306?S\362\366+;\377\204\277\335\370\232XBL\321\277\201\2251J\261\226\241?\242\200\260.\250\310\274\277\' D\244|\262|\277\3051\354aYY\267\277^l\253D\005\010\313??\342\322\313O\303\231\277\345j\377\304J\211\324?\343/2\327\210\265\241\277S\274\rVW\032|?W\231\311\236\370t\261\277\231K\213#\201@\277\277\327{\207.\253:\272?IhAt\224\225\215?.\253d\271\271\'\321\277rD\202\026N\312\314\277+\253\364\262\320\352\313?U\344\t4\307\006\300?\356M\360\335\302\277\267?\205\354B\365\357\013D\277\271\253\352\267\246\262\272\277\373\331B(\367$\301\277\255@\212\361\272d\304\277PM\254\376\025~\326?\206\360\241,\235\021\245?\032\007\321\205\026\010\230?/\323&ai\202\323?\200\245g\327\313\213\315?Q\313\326\302k \302\277\314R\223\357L1\305\277\001Pp\203\013\305\274\277d\017_\205\274\322\203?\006=\247R{w\252\277\204\311\353\016\220\342\305\277\261O,\254\261t\201\277\016Dg.\341\371\300?md\324\221\322\225\302?\000\360^\000\304\364\306\277\274\360\277\356\026\326\273\277A\300\\\335\352\333\310\277>\000\254\0178\207\267?\325\007\\e\177=\214?\377\307S}.\344\256\277\343\305f\203\351\357\300\277T\312\347`\251n\300?\242?Ln\257c\316\277\025\246\260Y\236\225\271\277\360\320)\027F\337\315?rrs@\352\341\274?\310\262C~\323\023u?\371_\314\223\005t\252?\003E\221@\370\255\275?F?\372\302y\317\310\277\2353coF\260\325\277c\214/\010\250\311\272\277\354\310u\316\204\277\250\277S\362\036\254\031\260\275\277\373\375\243\264Vy\301\277\034\026\314\263\335\236\271?@\343Ik\231q\273\277f\363A\236\320\272\251?\'\207\'\326Y\035\246\277i\337\245x\000J\305?\352\211\340\237)(\262?\221\217\022\277@\276\243\277JO\264>/X\272?\257w1\357\354\022\273\277\007\225h\231\3110\260\277.\220kz\337\002\260\277\236\342\023\204\217\300\261\277\207\330\210\332V\210\264?\357\374K*\240\360\263\277\2743\337k\256/\304\277\001)\371>\017\023\243?5*P\214\312\376\323\2779\267\245\354\003\254\272\277\252\254\013\260$\255\315\277\207\020\314\2536\333\256\277(e\321\220\341\302\271??\370\205(\\\033\310?\006\024{\250\234}\320\277x\310\233Y\2474\313?\343\027z\003\201\230x?\3668r\336\002\r\253\277F\351\305\205\033\200\261?\'1/\007\305\374\257\277\250f\277H5F\240\277\261\206CS\271\302\276\277\017\325/\267\007\032\204?%\343\263M\307\363\256\277\310m\036{\213^\304?\327\211nm\311\007\301?\364\002\336\227xz\320\277\023\366\331Y\325e\227\277{\006\232A\004j\234\277UT\257\321p\365\244\277z\024xR\t\225\314?O\325\263[ Ko\277\"\372\3508\255\271\316?\014j\236y\005\360\300?J\357U\356\000z\253?\314\213\353\310%/\316\277\346\017\233\352\310\204\307?j\224~\273\006\037\226?(\244\306l\260=\323\277\204\302\334\276O\023\275\277\205\3178\274\'8\301?\250\307n\355\202\306\322?\375\315\206\367 r\234\277j\214\271\331\240s\250?MH\322(\315\017\321?\365\235\035f\026\240\261?<\376\207t\301\024\260?\024\rv\334\006\204\325\277&\202\035\017\206q\247\277\2500\030G\371\344\243?\277j\343\030\350(\245\277\002I\255w\361h\304\277v\0222\210\265J\300\277\263*`\005\240\037\300?\336\336\366}N~\306?\267\t\032\037\237*\251?\276r7\325\327{\216\277\331\222\211\310\215\210\203\277$\276\325\256\223\236\320\277:\254\2669\221\274\305?\026\354\013\341+\031\321\277\\\346\264-\001\241\305?\344\310\324\325\223\202\272\277\353\362\016\225MX\276\277" + } + } + } +} +node { + name: "layer_0_type_0/matrix/read" + op: "Identity" + input: "layer_0_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_0/matrix" + } + } + } +} +node { + name: "Reshape_14/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\010\000\000\000\003\000\000\000" + } + } + } +} +node { + name: "Slice_3/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_3/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "mul_14/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 24 + } + } + } +} +node { + name: "strided_slice_18/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_18/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_18/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "Reshape_13/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "Slice_2/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_2/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "mul_13/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_17/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_17/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_17/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "Reshape_12/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_12/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 24 + } + } + } +} +node { + name: "strided_slice_16/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_16/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_16/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_11/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_11/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_15/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_15/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_15/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "concat_1/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "mul_10/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "mul_9/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "strided_slice_13/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_13/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_13/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_12/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_12/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_12/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "mul_8/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_11/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_11/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_11/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_10/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_10/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_10/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "filter_type_1/Reshape_14/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "filter_type_1/transpose/perm" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\000\000\000\000\002\000\000\000\001\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_5/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\003\000\000\000\377\377\377\377" + } + } + } +} +node { + name: "filter_type_1/Slice_5/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\000\000\000\000\001\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_4/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_4/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\000\000\000\000\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_1/mul/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.007246376811594203 + } + } + } +} +node { + name: "filter_type_1/Reshape_13/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\\\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Reshape_12/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\\\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/concat_5/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_1/Reshape_11/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "HpI\030\371\024\317?h\007\225\326\205\227\326\277O\217\351\374\253\304\352\277\315[\376\006E-\317\277\276\243a\304\243\217\376?M\242\014\333\220\242\327\277p\211\361\315\201\013\327?\215\250\225\211\216u\373\277" + } + } + } +} +node { + name: "filter_type_1/bias_3_1/read" + op: "Identity" + input: "filter_type_1/bias_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_3_1" + } + } + } +} +node { + name: "filter_type_1/matrix_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\273d\222\344\365\361\261?\036lL\245<\026\272\277\214\354S\252\310\350\316\277H\334\367\370\374\377\261\277}\226\303\001\373\244\341?\277\307pu\227J\273\277\275S\241\371)\234\272?\340\005\033s\010\265\337\277\020q\t\352\3400\310?\241\203c\207\320\324\313\277\013\321\202|\300V\250?\2003\336a\030\261\322\277\212\214\254DZ\257\226?Q\310\236\207\337\022\334?\267\364\270%\374\036\314?\232\3322\204O0\300\277I\344\227\310\363b\323\277\335\330\235\"\251\206\346?\334\360+E\342e\271\277\326\262!F\271\325\302?{\346\0031\301\\\311?>1_\360\346\022\306?\316\004B\330\226\253\257?\254Z\315g;\251\272\277|\346,\201\241\370\276\2779a\2703}\005\255?\252\232\213-S\343\205?\307\004\230\337Tl\343\277e)\261\256\362\003\324\277\351\263^\252\037\345\302\277NG\241\266J4\316\277\254\035\260\030\355\021\303\277" + } + } + } +} +node { + name: "filter_type_1/matrix_3_1/read" + op: "Identity" + input: "filter_type_1/matrix_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_3_1" + } + } + } +} +node { + name: "filter_type_1/concat_4/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_1/Reshape_10/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "HpI\030\371\024\317?h\007\225\326\205\227\326\277O\217\351\374\253\304\352\277\315[\376\006E-\317\277" + } + } + } +} +node { + name: "filter_type_1/bias_2_1/read" + op: "Identity" + input: "filter_type_1/bias_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_2_1" + } + } + } +} +node { + name: "filter_type_1/matrix_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\311f\210]\327`\271?\352\0229\002:r\302\277|\004\315\340.\333\325\277\357\247?\353\255t\271\277\335S\265\236\371\363\350?\347\326\276-DL\303\277\016\344\311e\355\320\302?&\360\312\354\233k\346\277" + } + } + } +} +node { + name: "filter_type_1/matrix_2_1/read" + op: "Identity" + input: "filter_type_1/matrix_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_2_1" + } + } + } +} +node { + name: "filter_type_1/concat_3/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_1/Reshape_9/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "HpI\030\371\024\317?h\007\225\326\205\227\326\277" + } + } + } +} +node { + name: "filter_type_1/bias_1_1/read" + op: "Identity" + input: "filter_type_1/bias_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_1_1" + } + } + } +} +node { + name: "filter_type_1/matrix_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\273d\222\344\365\361\301?\036lL\245<\026\312\277" + } + } + } +} +node { + name: "filter_type_1/matrix_1_1/read" + op: "Identity" + input: "filter_type_1/matrix_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_1_1" + } + } + } +} +node { + name: "filter_type_1/Reshape_8/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_3/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_3/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Reshape_7/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_2/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377p\001\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_2/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\270\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Reshape_6/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_1/Reshape_4/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "HpI\030\371\024\317?h\007\225\326\205\227\326\277O\217\351\374\253\304\352\277\315[\376\006E-\317\277\276\243a\304\243\217\376?M\242\014\333\220\242\327\277p\211\361\315\201\013\327?\215\250\225\211\216u\373\277" + } + } + } +} +node { + name: "filter_type_1/bias_3_0/read" + op: "Identity" + input: "filter_type_1/bias_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_3_0" + } + } + } +} +node { + name: "filter_type_1/matrix_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\273d\222\344\365\361\261?\036lL\245<\026\272\277\214\354S\252\310\350\316\277H\334\367\370\374\377\261\277}\226\303\001\373\244\341?\277\307pu\227J\273\277\275S\241\371)\234\272?\340\005\033s\010\265\337\277\020q\t\352\3400\310?\241\203c\207\320\324\313\277\013\321\202|\300V\250?\2003\336a\030\261\322\277\212\214\254DZ\257\226?Q\310\236\207\337\022\334?\267\364\270%\374\036\314?\232\3322\204O0\300\277I\344\227\310\363b\323\277\335\330\235\"\251\206\346?\334\360+E\342e\271\277\326\262!F\271\325\302?{\346\0031\301\\\311?>1_\360\346\022\306?\316\004B\330\226\253\257?\254Z\315g;\251\272\277|\346,\201\241\370\276\2779a\2703}\005\255?\252\232\213-S\343\205?\307\004\230\337Tl\343\277e)\261\256\362\003\324\277\351\263^\252\037\345\302\277NG\241\266J4\316\277\254\035\260\030\355\021\303\277" + } + } + } +} +node { + name: "filter_type_1/matrix_3_0/read" + op: "Identity" + input: "filter_type_1/matrix_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_3_0" + } + } + } +} +node { + name: "filter_type_1/concat_1/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_1/Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "HpI\030\371\024\317?h\007\225\326\205\227\326\277O\217\351\374\253\304\352\277\315[\376\006E-\317\277" + } + } + } +} +node { + name: "filter_type_1/bias_2_0/read" + op: "Identity" + input: "filter_type_1/bias_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_2_0" + } + } + } +} +node { + name: "filter_type_1/matrix_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\311f\210]\327`\271?\352\0229\002:r\302\277|\004\315\340.\333\325\277\357\247?\353\255t\271\277\335S\265\236\371\363\350?\347\326\276-DL\303\277\016\344\311e\355\320\302?&\360\312\354\233k\346\277" + } + } + } +} +node { + name: "filter_type_1/matrix_2_0/read" + op: "Identity" + input: "filter_type_1/matrix_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_2_0" + } + } + } +} +node { + name: "filter_type_1/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_1/Reshape_2/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "HpI\030\371\024\317?h\007\225\326\205\227\326\277" + } + } + } +} +node { + name: "filter_type_1/bias_1_0/read" + op: "Identity" + input: "filter_type_1/bias_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_1_0" + } + } + } +} +node { + name: "filter_type_1/matrix_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\273d\222\344\365\361\301?\036lL\245<\026\312\277" + } + } + } +} +node { + name: "filter_type_1/matrix_1_0/read" + op: "Identity" + input: "filter_type_1/matrix_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_1_0" + } + } + } +} +node { + name: "filter_type_1/Reshape_1/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_1/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_1/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\270\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "Reshape_8/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377(\002\000\000" + } + } + } +} +node { + name: "Slice_1/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_1/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_7/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 552 + } + } + } +} +node { + name: "strided_slice_9/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_9/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_9/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "mul_6/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 552 + } + } + } +} +node { + name: "add/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "strided_slice_8/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_8/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_8/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "mul_5/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "mul_4/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "strided_slice_7/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_7/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_7/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_6/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_6/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_6/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "mul_3/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_5/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_5/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_5/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_4/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_4/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_4/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "filter_type_0/Reshape_14/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "filter_type_0/transpose/perm" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\000\000\000\000\002\000\000\000\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_5/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\003\000\000\000\377\377\377\377" + } + } + } +} +node { + name: "filter_type_0/Slice_5/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\000\000\000\000\001\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_4/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_4/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\000\000\000\000\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_0/mul/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.007246376811594203 + } + } + } +} +node { + name: "filter_type_0/Reshape_13/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\\\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Reshape_12/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\\\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/concat_5/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_0/Reshape_11/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\216\000\014-XA\323?\351d\364]v\277\334\277\037k\320;\306P\352\277`\252u\375\273\304\302\277g\375\2778\372^\376?\254\000\016\316\345\300\333\277o\276M+{G\335?;\344\023U\240\007\373\277" + } + } + } +} +node { + name: "filter_type_0/bias_3_1/read" + op: "Identity" + input: "filter_type_0/bias_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_3_1" + } + } + } +} +node { + name: "filter_type_0/matrix_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\232\257!\005\001\261\252?\312\261\203|\205\276\307\277\031\317\007>\330\340\320\277_\345>\212\247\204\222?\337Kn\367\230%\340?\247\272\234\020\'\344\305\277\333\301[\006\335\220\305?\216\037\200\363\274W\332\277W\237\373\277\025\010\301?\316\266\266#\010y\321\277N\304~\207\360,\237?\374\301\324\352V5\314\277\256?\241\373NB\223?f\246\305\213\345[\330?\265I\023q6D\312?\257\372\206\037\321?\301\2778W\302\372\030\006\326\277`\346N\377\356F\344?\312\314\327\024^)\276\277\264c\203\264\310k\315?m\273&\204\375\234\307?\326\205\207\363\273o\274?\001\235\345m\023\255\263?.\000\263\310\320\217\270\277\352\224`\320\334\270\306\277b\265\307XN\333R?\216\266\234\345F\004\177\277\237@\366D\'\224\341\277@I4N\251W\324\277\0106[\231]\024\312\277a=\202\317\371\256\317\277.va\257\245\353\303\277" + } + } + } +} +node { + name: "filter_type_0/matrix_3_1/read" + op: "Identity" + input: "filter_type_0/matrix_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_3_1" + } + } + } +} +node { + name: "filter_type_0/concat_4/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_0/Reshape_10/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\254\224\326\002\252\223\304?P\202\266\221\2533\334\277p\377\243g\222\t\352\277\354,\344V\335\372\302\277" + } + } + } +} +node { + name: "filter_type_0/bias_2_1/read" + op: "Identity" + input: "filter_type_0/bias_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_2_1" + } + } + } +} +node { + name: "filter_type_0/matrix_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "4\354R\232\247Y\241?\242\213s\200\253\305\315\277\235N\267]`T\327\277\301Rti\375\313\203\277\035\232w?@\357\347?\251G#\303ZN\316\277\263\320\377\267\014\270\277?\276\247\237\312\344\324\343\277" + } + } + } +} +node { + name: "filter_type_0/matrix_2_1/read" + op: "Identity" + input: "filter_type_0/matrix_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_2_1" + } + } + } +} +node { + name: "filter_type_0/concat_3/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_0/Reshape_9/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\354v!\322Uy\303?\002Pg\265\233\352\333\277" + } + } + } +} +node { + name: "filter_type_0/bias_1_1/read" + op: "Identity" + input: "filter_type_0/bias_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_1_1" + } + } + } +} +node { + name: "filter_type_0/matrix_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "^j\351}9i\257?\235F\206\264>U\314\277" + } + } + } +} +node { + name: "filter_type_0/matrix_1_1/read" + op: "Identity" + input: "filter_type_0/matrix_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_1_1" + } + } + } +} +node { + name: "filter_type_0/Reshape_8/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_3/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_3/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Reshape_7/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_2/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377p\001\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_2/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\270\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Reshape_6/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_0/Reshape_4/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "D\310E\235~\347\325?\330\214\215\220\336\361\334\277\177\\\372\032\204P\352\277\0250r\023\220h\302\277-\336\021;\356|\376?\324\215\263O\353\241\332\277T\355GV\337:\335?\017\316{\2733\"\373\277" + } + } + } +} +node { + name: "filter_type_0/bias_3_0/read" + op: "Identity" + input: "filter_type_0/bias_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_3_0" + } + } + } +} +node { + name: "filter_type_0/matrix_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\037\002\236\350\260\237\274?u\217\364L\201t\311\277\351_g\264\342\326\320\277Z\213\343P\242`\236?m\222,0\337$\340?\202v8y\231f\305\277V$@\252\371Q\311?\210S\260\251\236\263\332\277\333\323\030\315\230\225\310?\214\213\361\300J\222\321\277|\331\324\301Z\356\237?\364m\014\027\034[\313\277\324\267~\013\301\340\214?S%{S\310\327\330?]\361.\376\3642\316?\3619\203\252\304\374\277\277\234\271\000t\365\215\321\277\357|\354\227-\177\343?6J\357v\035\005\276\277\203u\334\332\352\236\317?h\250\225\231\202B\307?C\376-\340\016\331\273?\261\001\307Qr;\303?#\366cb\325H\266\277}Tn\r\n\305\272\277\237\250IBm\216\227\277\316l\362.0gz\277\"<\336\330\3763\340\277.\r\355\\<\251\324\277Q\240\347\221^\305\311\277&\335\337A\210\257\307\277He!T9\177\302\277" + } + } + } +} +node { + name: "filter_type_0/matrix_3_0/read" + op: "Identity" + input: "filter_type_0/matrix_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_3_0" + } + } + } +} +node { + name: "filter_type_0/concat_1/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_0/Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "sq\336\345\220\245\304?\2319\2608\263D\334\2771y\374\000,\367\351\277h\206\006\233\244\217\302\277" + } + } + } +} +node { + name: "filter_type_0/bias_2_0/read" + op: "Identity" + input: "filter_type_0/bias_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_2_0" + } + } + } +} +node { + name: "filter_type_0/matrix_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\312\232X\317\257\262\241?GM]\341\004\365\315\277\342\225\202\206\306\231\326\277\010\257\305ZM\346V?\336v\207h.\250\347?v\370\312\n\206\250\316\277\377.0\312t_\300?G\303\216\023V.\343\277" + } + } + } +} +node { + name: "filter_type_0/matrix_2_0/read" + op: "Identity" + input: "filter_type_0/matrix_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_2_0" + } + } + } +} +node { + name: "filter_type_0/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_0/Reshape_2/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\373\357\2167\357\305\305?\036=\324[&H\334\277" + } + } + } +} +node { + name: "filter_type_0/bias_1_0/read" + op: "Identity" + input: "filter_type_0/bias_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_1_0" + } + } + } +} +node { + name: "filter_type_0/matrix_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "L\033O\017\326\247\260?\235\343\375d\374\'\321\277" + } + } + } +} +node { + name: "filter_type_0/matrix_1_0/read" + op: "Identity" + input: "filter_type_0/matrix_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_1_0" + } + } + } +} +node { + name: "filter_type_0/Reshape_1/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_1/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_1/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\270\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377(\002\000\000" + } + } + } +} +node { + name: "Slice/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "mul_2/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 552 + } + } + } +} +node { + name: "strided_slice_3/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_3/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_3/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "Reshape_4/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_1/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 552 + } + } + } +} +node { + name: "strided_slice_2/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_2/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_2/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377(\002\000\000" + } + } + } +} +node { + name: "Reshape_2/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "strided_slice_1/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_1/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_1/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "Reshape_1/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\t\000\000\000" + } + } + } +} +node { + name: "Reshape/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "descrpt_attr/t_std" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 552 + } + } + tensor_content: "\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?\316\313p\023\352\333\301?V\263r\222\014\360\265?V\263r\222\014\360\265?V\263r\222\014\360\265?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?Z\004\240\307\306\266\277?\273\311\344z\367\250\263?\273\311\344z\367\250\263?\273\311\344z\367\250\263?" + } + } + } +} +node { + name: "descrpt_attr/t_std/read" + op: "Identity" + input: "descrpt_attr/t_std" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@descrpt_attr/t_std" + } + } + } +} +node { + name: "descrpt_attr/t_avg" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 552 + } + } + tensor_content: "}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}8\262\217i\354\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:$V\020\030\315\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "descrpt_attr/t_avg/read" + op: "Identity" + input: "descrpt_attr/t_avg" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@descrpt_attr/t_avg" + } + } + } +} +node { + name: "descrpt_attr/ntypes" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "descrpt_attr/rcut" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 6.0 + } + } + } +} +node { + name: "model_attr/model_type" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "polar" + } + } + } +} +node { + name: "model_attr/sel_type" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "model_attr/tmap" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "O H" + } + } + } +} +node { + name: "t_mesh" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "t_natoms" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: 4 + } + } + } + } +} +node { + name: "strided_slice_25" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_25/stack" + input: "strided_slice_25/stack_1" + input: "strided_slice_25/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_23" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_23/stack" + input: "strided_slice_23/stack_1" + input: "strided_slice_23/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_21" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_21/stack" + input: "strided_slice_21/stack_1" + input: "strided_slice_21/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_18" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_18/stack" + input: "strided_slice_18/stack_1" + input: "strided_slice_18/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_14" + op: "Mul" + input: "strided_slice_18" + input: "mul_14/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_3/size" + op: "Pack" + input: "Slice_3/size/0" + input: "mul_14" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_17" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_17/stack" + input: "strided_slice_17/stack_1" + input: "strided_slice_17/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_13" + op: "Mul" + input: "strided_slice_17" + input: "mul_13/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_2/size" + op: "Pack" + input: "Slice_2/size/0" + input: "mul_13" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_16" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_16/stack" + input: "strided_slice_16/stack_1" + input: "strided_slice_16/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_12" + op: "Mul" + input: "mul_12/x" + input: "strided_slice_16" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_12/shape" + op: "Pack" + input: "Reshape_12/shape/0" + input: "mul_12" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_15" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_15/stack" + input: "strided_slice_15/stack_1" + input: "strided_slice_15/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_11" + op: "Mul" + input: "mul_11/x" + input: "strided_slice_15" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_11/shape" + op: "Pack" + input: "Reshape_11/shape/0" + input: "mul_11" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_13" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_13/stack" + input: "strided_slice_13/stack_1" + input: "strided_slice_13/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_9" + op: "Mul" + input: "strided_slice_13" + input: "mul_9/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_10" + op: "Mul" + input: "mul_9" + input: "mul_10/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_11" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_11/stack" + input: "strided_slice_11/stack_1" + input: "strided_slice_11/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_8" + op: "Mul" + input: "strided_slice_11" + input: "mul_8/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_9" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_9/stack" + input: "strided_slice_9/stack_1" + input: "strided_slice_9/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_7" + op: "Mul" + input: "strided_slice_9" + input: "mul_7/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_1/size" + op: "Pack" + input: "Slice_1/size/0" + input: "mul_7" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_8" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_8/stack" + input: "strided_slice_8/stack_1" + input: "strided_slice_8/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "add" + op: "Add" + input: "add/x" + input: "strided_slice_8" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_6" + op: "Mul" + input: "add" + input: "mul_6/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_1/begin" + op: "Pack" + input: "Slice_1/begin/0" + input: "mul_6" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_7" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_7/stack" + input: "strided_slice_7/stack_1" + input: "strided_slice_7/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_4" + op: "Mul" + input: "strided_slice_7" + input: "mul_4/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_5" + op: "Mul" + input: "mul_4" + input: "mul_5/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_5" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_5/stack" + input: "strided_slice_5/stack_1" + input: "strided_slice_5/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_3" + op: "Mul" + input: "strided_slice_5" + input: "mul_3/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_3" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_3/stack" + input: "strided_slice_3/stack_1" + input: "strided_slice_3/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_2" + op: "Mul" + input: "strided_slice_3" + input: "mul_2/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice/size" + op: "Pack" + input: "Slice/size/0" + input: "mul_2" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_2" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_2/stack" + input: "strided_slice_2/stack_1" + input: "strided_slice_2/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_1" + op: "Mul" + input: "mul_1/x" + input: "strided_slice_2" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_4/shape" + op: "Pack" + input: "Reshape_4/shape/0" + input: "mul_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_1" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_1/stack" + input: "strided_slice_1/stack_1" + input: "strided_slice_1/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_2/shape" + op: "Pack" + input: "Reshape_2/shape/0" + input: "strided_slice_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice/stack" + input: "strided_slice/stack_1" + input: "strided_slice/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul" + op: "Mul" + input: "strided_slice" + input: "mul/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape/shape" + op: "Pack" + input: "Reshape/shape/0" + input: "mul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "t_type" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_2" + op: "Reshape" + input: "t_type" + input: "Reshape_2/shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "t_coord" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape" + op: "Reshape" + input: "t_coord" + input: "Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "t_box" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_1" + op: "Reshape" + input: "t_box" + input: "Reshape_1/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "DescrptSeA" + op: "DescrptSeA" + input: "Reshape" + input: "Reshape_2" + input: "t_natoms" + input: "Reshape_1" + input: "t_mesh" + input: "descrpt_attr/t_avg/read" + input: "descrpt_attr/t_std/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "rcut_a" + value { + f: -1.0 + } + } + attr { + key: "rcut_r" + value { + f: 6.0 + } + } + attr { + key: "rcut_r_smth" + value { + f: 0.5 + } + } + attr { + key: "sel_a" + value { + list { + i: 46 + i: 92 + } + } + } + attr { + key: "sel_r" + value { + list { + i: 0 + i: 0 + } + } + } +} +node { + name: "Reshape_3" + op: "Reshape" + input: "DescrptSeA" + input: "Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_rmat" + op: "Identity" + input: "Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_4" + op: "Reshape" + input: "o_rmat" + input: "Reshape_4/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_3" + op: "Shape" + input: "Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_12" + op: "StridedSlice" + input: "Shape_3" + input: "strided_slice_12/stack" + input: "strided_slice_12/stack_1" + input: "strided_slice_12/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_10/shape" + op: "Pack" + input: "strided_slice_12" + input: "mul_10" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Shape_2" + op: "Shape" + input: "Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_10" + op: "StridedSlice" + input: "Shape_2" + input: "strided_slice_10/stack" + input: "strided_slice_10/stack_1" + input: "strided_slice_10/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_9/shape" + op: "Pack" + input: "strided_slice_10" + input: "mul_8" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_1" + op: "Slice" + input: "Reshape_4" + input: "Slice_1/begin" + input: "Slice_1/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_8" + op: "Reshape" + input: "Slice_1" + input: "Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Slice_2" + op: "Slice" + input: "Reshape_8" + input: "filter_type_1/Slice_2/begin" + input: "filter_type_1/Slice_2/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Reshape_13" + op: "Reshape" + input: "filter_type_1/Slice_2" + input: "filter_type_1/Reshape_13/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_7" + op: "Reshape" + input: "filter_type_1/Slice_2" + input: "filter_type_1/Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Slice_3" + op: "Slice" + input: "filter_type_1/Reshape_7" + input: "filter_type_1/Slice_3/begin" + input: "filter_type_1/Slice_3/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Reshape_8" + op: "Reshape" + input: "filter_type_1/Slice_3" + input: "filter_type_1/Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/concat_3" + op: "ConcatV2" + input: "filter_type_1/Reshape_8" + input: "filter_type_1/Reshape_8" + input: "filter_type_1/concat_3/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_4" + op: "MatMul" + input: "filter_type_1/Reshape_8" + input: "filter_type_1/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_1/add_6" + op: "Add" + input: "filter_type_1/MatMul_4" + input: "filter_type_1/bias_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_3" + op: "Tanh" + input: "filter_type_1/add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Reshape_9" + op: "Reshape" + input: "filter_type_1/Tanh_3" + input: "filter_type_1/Reshape_9/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_7" + op: "Add" + input: "filter_type_1/concat_3" + input: "filter_type_1/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/concat_4" + op: "ConcatV2" + input: "filter_type_1/add_7" + input: "filter_type_1/add_7" + input: "filter_type_1/concat_4/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_5" + op: "MatMul" + input: "filter_type_1/add_7" + input: "filter_type_1/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_1/add_8" + op: "Add" + input: "filter_type_1/MatMul_5" + input: "filter_type_1/bias_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_4" + op: "Tanh" + input: "filter_type_1/add_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Reshape_10" + op: "Reshape" + input: "filter_type_1/Tanh_4" + input: "filter_type_1/Reshape_10/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_9" + op: "Add" + input: "filter_type_1/concat_4" + input: "filter_type_1/Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/concat_5" + op: "ConcatV2" + input: "filter_type_1/add_9" + input: "filter_type_1/add_9" + input: "filter_type_1/concat_5/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_6" + op: "MatMul" + input: "filter_type_1/add_9" + input: "filter_type_1/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_1/add_10" + op: "Add" + input: "filter_type_1/MatMul_6" + input: "filter_type_1/bias_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_5" + op: "Tanh" + input: "filter_type_1/add_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Reshape_11" + op: "Reshape" + input: "filter_type_1/Tanh_5" + input: "filter_type_1/Reshape_11/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_11" + op: "Add" + input: "filter_type_1/concat_5" + input: "filter_type_1/Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Reshape_12" + op: "Reshape" + input: "filter_type_1/add_11" + input: "filter_type_1/Reshape_12/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_7" + op: "BatchMatMul" + input: "filter_type_1/Reshape_13" + input: "filter_type_1/Reshape_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "filter_type_1/Slice" + op: "Slice" + input: "Reshape_8" + input: "filter_type_1/Slice/begin" + input: "filter_type_1/Slice/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Reshape_6" + op: "Reshape" + input: "filter_type_1/Slice" + input: "filter_type_1/Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape" + op: "Reshape" + input: "filter_type_1/Slice" + input: "filter_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Slice_1" + op: "Slice" + input: "filter_type_1/Reshape" + input: "filter_type_1/Slice_1/begin" + input: "filter_type_1/Slice_1/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Reshape_1" + op: "Reshape" + input: "filter_type_1/Slice_1" + input: "filter_type_1/Reshape_1/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/concat" + op: "ConcatV2" + input: "filter_type_1/Reshape_1" + input: "filter_type_1/Reshape_1" + input: "filter_type_1/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul" + op: "MatMul" + input: "filter_type_1/Reshape_1" + input: "filter_type_1/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_1/add" + op: "Add" + input: "filter_type_1/MatMul" + input: "filter_type_1/bias_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh" + op: "Tanh" + input: "filter_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Reshape_2" + op: "Reshape" + input: "filter_type_1/Tanh" + input: "filter_type_1/Reshape_2/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_1" + op: "Add" + input: "filter_type_1/concat" + input: "filter_type_1/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/concat_1" + op: "ConcatV2" + input: "filter_type_1/add_1" + input: "filter_type_1/add_1" + input: "filter_type_1/concat_1/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_1" + op: "MatMul" + input: "filter_type_1/add_1" + input: "filter_type_1/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_1/add_2" + op: "Add" + input: "filter_type_1/MatMul_1" + input: "filter_type_1/bias_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_1" + op: "Tanh" + input: "filter_type_1/add_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Reshape_3" + op: "Reshape" + input: "filter_type_1/Tanh_1" + input: "filter_type_1/Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_3" + op: "Add" + input: "filter_type_1/concat_1" + input: "filter_type_1/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/concat_2" + op: "ConcatV2" + input: "filter_type_1/add_3" + input: "filter_type_1/add_3" + input: "filter_type_1/concat_2/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_2" + op: "MatMul" + input: "filter_type_1/add_3" + input: "filter_type_1/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_1/add_4" + op: "Add" + input: "filter_type_1/MatMul_2" + input: "filter_type_1/bias_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_2" + op: "Tanh" + input: "filter_type_1/add_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Reshape_4" + op: "Reshape" + input: "filter_type_1/Tanh_2" + input: "filter_type_1/Reshape_4/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_5" + op: "Add" + input: "filter_type_1/concat_2" + input: "filter_type_1/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Reshape_5" + op: "Reshape" + input: "filter_type_1/add_5" + input: "filter_type_1/Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_3" + op: "BatchMatMul" + input: "filter_type_1/Reshape_6" + input: "filter_type_1/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "filter_type_1/add_12" + op: "Add" + input: "filter_type_1/MatMul_3" + input: "filter_type_1/MatMul_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/mul" + op: "Mul" + input: "filter_type_1/add_12" + input: "filter_type_1/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Slice_5" + op: "Slice" + input: "filter_type_1/mul" + input: "filter_type_1/Slice_5/begin" + input: "filter_type_1/Slice_5/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/transpose" + op: "Transpose" + input: "filter_type_1/Slice_5" + input: "filter_type_1/transpose/perm" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tperm" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_10" + op: "Reshape" + input: "filter_type_1/transpose" + input: "Reshape_10/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Slice_4" + op: "Slice" + input: "filter_type_1/mul" + input: "filter_type_1/Slice_4/begin" + input: "filter_type_1/Slice_4/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/MatMul_8" + op: "BatchMatMul" + input: "filter_type_1/mul" + input: "filter_type_1/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "filter_type_1/Reshape_14" + op: "Reshape" + input: "filter_type_1/MatMul_8" + input: "filter_type_1/Reshape_14/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_9" + op: "Reshape" + input: "filter_type_1/Reshape_14" + input: "Reshape_9/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_1" + op: "Shape" + input: "Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_6" + op: "StridedSlice" + input: "Shape_1" + input: "strided_slice_6/stack" + input: "strided_slice_6/stack_1" + input: "strided_slice_6/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_7/shape" + op: "Pack" + input: "strided_slice_6" + input: "mul_5" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Shape" + op: "Shape" + input: "Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_4" + op: "StridedSlice" + input: "Shape" + input: "strided_slice_4/stack" + input: "strided_slice_4/stack_1" + input: "strided_slice_4/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_6/shape" + op: "Pack" + input: "strided_slice_4" + input: "mul_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice" + op: "Slice" + input: "Reshape_4" + input: "Slice/begin" + input: "Slice/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_5" + op: "Reshape" + input: "Slice" + input: "Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Slice_2" + op: "Slice" + input: "Reshape_5" + input: "filter_type_0/Slice_2/begin" + input: "filter_type_0/Slice_2/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Reshape_13" + op: "Reshape" + input: "filter_type_0/Slice_2" + input: "filter_type_0/Reshape_13/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_7" + op: "Reshape" + input: "filter_type_0/Slice_2" + input: "filter_type_0/Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Slice_3" + op: "Slice" + input: "filter_type_0/Reshape_7" + input: "filter_type_0/Slice_3/begin" + input: "filter_type_0/Slice_3/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Reshape_8" + op: "Reshape" + input: "filter_type_0/Slice_3" + input: "filter_type_0/Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/concat_3" + op: "ConcatV2" + input: "filter_type_0/Reshape_8" + input: "filter_type_0/Reshape_8" + input: "filter_type_0/concat_3/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_4" + op: "MatMul" + input: "filter_type_0/Reshape_8" + input: "filter_type_0/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_0/add_6" + op: "Add" + input: "filter_type_0/MatMul_4" + input: "filter_type_0/bias_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_3" + op: "Tanh" + input: "filter_type_0/add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Reshape_9" + op: "Reshape" + input: "filter_type_0/Tanh_3" + input: "filter_type_0/Reshape_9/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_7" + op: "Add" + input: "filter_type_0/concat_3" + input: "filter_type_0/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/concat_4" + op: "ConcatV2" + input: "filter_type_0/add_7" + input: "filter_type_0/add_7" + input: "filter_type_0/concat_4/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_5" + op: "MatMul" + input: "filter_type_0/add_7" + input: "filter_type_0/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_0/add_8" + op: "Add" + input: "filter_type_0/MatMul_5" + input: "filter_type_0/bias_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_4" + op: "Tanh" + input: "filter_type_0/add_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Reshape_10" + op: "Reshape" + input: "filter_type_0/Tanh_4" + input: "filter_type_0/Reshape_10/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_9" + op: "Add" + input: "filter_type_0/concat_4" + input: "filter_type_0/Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/concat_5" + op: "ConcatV2" + input: "filter_type_0/add_9" + input: "filter_type_0/add_9" + input: "filter_type_0/concat_5/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_6" + op: "MatMul" + input: "filter_type_0/add_9" + input: "filter_type_0/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_0/add_10" + op: "Add" + input: "filter_type_0/MatMul_6" + input: "filter_type_0/bias_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_5" + op: "Tanh" + input: "filter_type_0/add_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Reshape_11" + op: "Reshape" + input: "filter_type_0/Tanh_5" + input: "filter_type_0/Reshape_11/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_11" + op: "Add" + input: "filter_type_0/concat_5" + input: "filter_type_0/Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Reshape_12" + op: "Reshape" + input: "filter_type_0/add_11" + input: "filter_type_0/Reshape_12/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_7" + op: "BatchMatMul" + input: "filter_type_0/Reshape_13" + input: "filter_type_0/Reshape_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "filter_type_0/Slice" + op: "Slice" + input: "Reshape_5" + input: "filter_type_0/Slice/begin" + input: "filter_type_0/Slice/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Reshape_6" + op: "Reshape" + input: "filter_type_0/Slice" + input: "filter_type_0/Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape" + op: "Reshape" + input: "filter_type_0/Slice" + input: "filter_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Slice_1" + op: "Slice" + input: "filter_type_0/Reshape" + input: "filter_type_0/Slice_1/begin" + input: "filter_type_0/Slice_1/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Reshape_1" + op: "Reshape" + input: "filter_type_0/Slice_1" + input: "filter_type_0/Reshape_1/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/concat" + op: "ConcatV2" + input: "filter_type_0/Reshape_1" + input: "filter_type_0/Reshape_1" + input: "filter_type_0/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul" + op: "MatMul" + input: "filter_type_0/Reshape_1" + input: "filter_type_0/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_0/add" + op: "Add" + input: "filter_type_0/MatMul" + input: "filter_type_0/bias_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh" + op: "Tanh" + input: "filter_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Reshape_2" + op: "Reshape" + input: "filter_type_0/Tanh" + input: "filter_type_0/Reshape_2/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_1" + op: "Add" + input: "filter_type_0/concat" + input: "filter_type_0/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/concat_1" + op: "ConcatV2" + input: "filter_type_0/add_1" + input: "filter_type_0/add_1" + input: "filter_type_0/concat_1/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_1" + op: "MatMul" + input: "filter_type_0/add_1" + input: "filter_type_0/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_0/add_2" + op: "Add" + input: "filter_type_0/MatMul_1" + input: "filter_type_0/bias_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_1" + op: "Tanh" + input: "filter_type_0/add_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Reshape_3" + op: "Reshape" + input: "filter_type_0/Tanh_1" + input: "filter_type_0/Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_3" + op: "Add" + input: "filter_type_0/concat_1" + input: "filter_type_0/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/concat_2" + op: "ConcatV2" + input: "filter_type_0/add_3" + input: "filter_type_0/add_3" + input: "filter_type_0/concat_2/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_2" + op: "MatMul" + input: "filter_type_0/add_3" + input: "filter_type_0/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_0/add_4" + op: "Add" + input: "filter_type_0/MatMul_2" + input: "filter_type_0/bias_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_2" + op: "Tanh" + input: "filter_type_0/add_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Reshape_4" + op: "Reshape" + input: "filter_type_0/Tanh_2" + input: "filter_type_0/Reshape_4/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_5" + op: "Add" + input: "filter_type_0/concat_2" + input: "filter_type_0/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Reshape_5" + op: "Reshape" + input: "filter_type_0/add_5" + input: "filter_type_0/Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_3" + op: "BatchMatMul" + input: "filter_type_0/Reshape_6" + input: "filter_type_0/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "filter_type_0/add_12" + op: "Add" + input: "filter_type_0/MatMul_3" + input: "filter_type_0/MatMul_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/mul" + op: "Mul" + input: "filter_type_0/add_12" + input: "filter_type_0/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Slice_5" + op: "Slice" + input: "filter_type_0/mul" + input: "filter_type_0/Slice_5/begin" + input: "filter_type_0/Slice_5/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/transpose" + op: "Transpose" + input: "filter_type_0/Slice_5" + input: "filter_type_0/transpose/perm" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tperm" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_7" + op: "Reshape" + input: "filter_type_0/transpose" + input: "Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "concat_1" + op: "ConcatV2" + input: "Reshape_7" + input: "Reshape_10" + input: "concat_1/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "o_rot_mat" + op: "Identity" + input: "concat_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_12" + op: "Reshape" + input: "o_rot_mat" + input: "Reshape_12/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_3" + op: "Slice" + input: "Reshape_12" + input: "Slice_3/begin" + input: "Slice_3/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_14" + op: "Reshape" + input: "Slice_3" + input: "Reshape_14/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Slice_4" + op: "Slice" + input: "filter_type_0/mul" + input: "filter_type_0/Slice_4/begin" + input: "filter_type_0/Slice_4/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/MatMul_8" + op: "BatchMatMul" + input: "filter_type_0/mul" + input: "filter_type_0/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "filter_type_0/Reshape_14" + op: "Reshape" + input: "filter_type_0/MatMul_8" + input: "filter_type_0/Reshape_14/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_6" + op: "Reshape" + input: "filter_type_0/Reshape_14" + input: "Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "concat" + op: "ConcatV2" + input: "Reshape_6" + input: "Reshape_9" + input: "concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "o_descriptor" + op: "Identity" + input: "concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_11" + op: "Reshape" + input: "o_descriptor" + input: "Reshape_11/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_6" + op: "Shape" + input: "Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_24" + op: "StridedSlice" + input: "Shape_6" + input: "strided_slice_24/stack" + input: "strided_slice_24/stack_1" + input: "strided_slice_24/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "eye/ones/packed" + op: "Pack" + input: "strided_slice_24" + input: "strided_slice_25" + input: "eye/ones/packed/2" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "eye/ones" + op: "Fill" + input: "eye/ones/packed" + input: "eye/ones/Const" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "index_type" + value { + type: DT_INT32 + } + } +} +node { + name: "eye/MatrixDiag" + op: "MatrixDiag" + input: "eye/ones" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "mul_17" + op: "Mul" + input: "mul_17/x" + input: "eye/MatrixDiag" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Shape_5" + op: "Shape" + input: "Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_22" + op: "StridedSlice" + input: "Shape_5" + input: "strided_slice_22/stack" + input: "strided_slice_22/stack_1" + input: "strided_slice_22/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_16/shape" + op: "Pack" + input: "strided_slice_22" + input: "strided_slice_23" + input: "Reshape_16/shape/2" + input: "Reshape_16/shape/3" + attr { + key: "N" + value { + i: 4 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Shape_4" + op: "Shape" + input: "Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_20" + op: "StridedSlice" + input: "Shape_4" + input: "strided_slice_20/stack" + input: "strided_slice_20/stack_1" + input: "strided_slice_20/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_15" + op: "Mul" + input: "strided_slice_20" + input: "strided_slice_21" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_15/shape" + op: "Pack" + input: "mul_15" + input: "Reshape_15/shape/1" + input: "Reshape_15/shape/2" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_2" + op: "Slice" + input: "Reshape_11" + input: "Slice_2/begin" + input: "Slice_2/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_13" + op: "Reshape" + input: "Slice_2" + input: "Reshape_13/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_0/MatMul" + op: "MatMul" + input: "Reshape_13" + input: "layer_0_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "layer_0_type_0/add" + op: "Add" + input: "layer_0_type_0/MatMul" + input: "layer_0_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_0_type_0/Tanh" + op: "Tanh" + input: "layer_0_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_0_type_0/Reshape" + op: "Reshape" + input: "layer_0_type_0/Tanh" + input: "layer_0_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/MatMul" + op: "MatMul" + input: "layer_0_type_0/Reshape" + input: "layer_1_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "layer_1_type_0/add" + op: "Add" + input: "layer_1_type_0/MatMul" + input: "layer_1_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_1_type_0/Tanh" + op: "Tanh" + input: "layer_1_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_1_type_0/Reshape" + op: "Reshape" + input: "layer_1_type_0/Tanh" + input: "layer_1_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/mul" + op: "Mul" + input: "layer_1_type_0/Reshape" + input: "layer_1_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "add_3" + op: "Add" + input: "layer_0_type_0/Reshape" + input: "layer_1_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_0/MatMul" + op: "MatMul" + input: "add_3" + input: "layer_2_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "layer_2_type_0/add" + op: "Add" + input: "layer_2_type_0/MatMul" + input: "layer_2_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_0/Tanh" + op: "Tanh" + input: "layer_2_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_0/Reshape" + op: "Reshape" + input: "layer_2_type_0/Tanh" + input: "layer_2_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/mul" + op: "Mul" + input: "layer_2_type_0/Reshape" + input: "layer_2_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "add_4" + op: "Add" + input: "add_3" + input: "layer_2_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "final_layer_type_0/MatMul" + op: "MatMul" + input: "add_4" + input: "final_layer_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "final_layer_type_0/add" + op: "Add" + input: "final_layer_type_0/MatMul" + input: "final_layer_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_15" + op: "Reshape" + input: "final_layer_type_0/add" + input: "Reshape_15/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "transpose" + op: "Transpose" + input: "Reshape_15" + input: "transpose/perm" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tperm" + value { + type: DT_INT32 + } + } +} +node { + name: "add_5" + op: "Add" + input: "Reshape_15" + input: "transpose" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "MatMul" + op: "BatchMatMul" + input: "add_5" + input: "Reshape_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "MatMul_1" + op: "BatchMatMul" + input: "Reshape_14" + input: "MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "Reshape_16" + op: "Reshape" + input: "MatMul_1" + input: "Reshape_16/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_16" + op: "Mul" + input: "Reshape_16" + input: "mul_16/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "add_6" + op: "Add" + input: "mul_16" + input: "mul_17" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_19" + op: "Reshape" + input: "add_6" + input: "Reshape_19/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_polar" + op: "Identity" + input: "Reshape_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +library { +} diff --git a/source/tests/infer/deeppot.pbtxt b/source/tests/infer/deeppot.pbtxt new file mode 100644 index 0000000000..5ca6c76d70 --- /dev/null +++ b/source/tests/infer/deeppot.pbtxt @@ -0,0 +1,24313 @@ +node { + name: "o_atom_virial/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_18/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 9 + } + } + } +} +node { + name: "strided_slice_29/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_29/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_29/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "o_virial/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\t\000\000\000" + } + } + } +} +node { + name: "o_force/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_17/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_28/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_28/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_28/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "Reshape_19/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_16/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 552 + } + } + } +} +node { + name: "strided_slice_27/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_27/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_27/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "gradients/Slice_1_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_1_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_1_grad/stack" + op: "Pack" + input: "gradients/Slice_1_grad/Rank" + input: "gradients/Slice_1_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/Slice_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_grad/stack" + op: "Pack" + input: "gradients/Slice_grad/Rank" + input: "gradients/Slice_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/stack" + op: "Pack" + input: "gradients/filter_type_1/Slice_2_grad/Rank" + input: "gradients/filter_type_1/Slice_2_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/stack" + op: "Pack" + input: "gradients/filter_type_1/Slice_grad/Rank" + input: "gradients/filter_type_1/Slice_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/stack" + op: "Pack" + input: "gradients/filter_type_0/Slice_2_grad/Rank" + input: "gradients/filter_type_0/Slice_2_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/stack" + op: "Pack" + input: "gradients/filter_type_0/Slice_grad/Rank" + input: "gradients/filter_type_0/Slice_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/stack" + op: "Pack" + input: "gradients/filter_type_1/Slice_3_grad/Rank" + input: "gradients/filter_type_1/Slice_3_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/stack" + op: "Pack" + input: "gradients/filter_type_1/Slice_1_grad/Rank" + input: "gradients/filter_type_1/Slice_1_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/stack" + op: "Pack" + input: "gradients/filter_type_0/Slice_3_grad/Rank" + input: "gradients/filter_type_0/Slice_3_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/stack" + op: "Pack" + input: "gradients/filter_type_0/Slice_1_grad/Rank" + input: "gradients/filter_type_0/Slice_1_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + } + } + } + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + } + } + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/stack" + op: "Pack" + input: "gradients/filter_type_1/Slice_4_grad/Rank" + input: "gradients/filter_type_1/Slice_4_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/stack" + op: "Pack" + input: "gradients/filter_type_0/Slice_4_grad/Rank" + input: "gradients/filter_type_0/Slice_4_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/concat_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_3_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_3_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_3_grad/stack" + op: "Pack" + input: "gradients/Slice_3_grad/Rank" + input: "gradients/Slice_3_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/Slice_2_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_2_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_2_grad/stack" + op: "Pack" + input: "gradients/Slice_2_grad/Rank" + input: "gradients/Slice_2_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "gradients/concat_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/grad_ys_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 1.0 + } + } + } +} +node { + name: "o_energy/reduction_indices" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "o_atom_energy/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "strided_slice_26/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_26/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_26/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_18/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: -1 + } + } + } +} +node { + name: "concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/concat_2_grad/mod" + op: "FloorMod" + input: "concat_2/axis" + input: "gradients/concat_2_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_25/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_25/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_25/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_24/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_24/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_24/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "final_layer_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + } + double_val: -186.9132831671284 + } + } + } +} +node { + name: "final_layer_type_1/bias/read" + op: "Identity" + input: "final_layer_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_1/bias" + } + } + } +} +node { + name: "final_layer_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + dim { + size: 1 + } + } + tensor_content: "\310\021\257\314\217b\265?\323 \344\347L)\300\277\325\212\340\032W\340\323\277\017\372\236\252A\302\270\277\362\357\034\371\252\310\346?\3156\213\036\266\321\302\277" + } + } + } +} +node { + name: "final_layer_type_1/matrix/read" + op: "Identity" + input: "final_layer_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_1/matrix" + } + } + } +} +node { + name: "layer_2_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\006\000\000\000" + } + } + } +} +node { + name: "layer_2_type_1/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\241\t<\031-\022\273?\343\001\r\351r\353\272?\232\273.u%%\267?0\351\227R\207\257\266?\321`*\303\221\206\267?o \245v\336\221\267?" + } + } + } +} +node { + name: "layer_2_type_1/idt/read" + op: "Identity" + input: "layer_2_type_1/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_1/idt" + } + } + } +} +node { + name: "layer_2_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\200\370\345\"Y\274\315?W*\222\025\030\343\325\277\024\372\001\313_\374\352\277Y\252\275\307\017\235\317\277\226qA\227\337\255\376?4\251\nX\230\355\326\277" + } + } + } +} +node { + name: "layer_2_type_1/bias/read" + op: "Identity" + input: "layer_2_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_1/bias" + } + } + } +} +node { + name: "layer_2_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + dim { + size: 6 + } + } + tensor_content: "\001\t\032?M\257\257?>d\364\326L\375\267\277\2460\nX\260\344\315\277\347F\240\003\251\346\257\277E\343\327\304Rf\341?\\DD+\032/\271\277\217\027I..a\274?\rg*7B\024\340\277\245\366\252[\032=\307?\023vf\230\353\300\314\277P\346\353m]0\254?\362\266\301k\363%\323\277\332L\277\270ET\232?q\036\332TQ\306\333?\355\323\000\215j9\313?\010\212\203\212\317\370\300\277l\260t\001\210\352\322\277\273\274Td\324]\346?\344\177\277qbl\271\277g\223\367\"ZP\303?{\306EZAI\312?\030r\242\343\007\342\306?\321.\250\366\316\326\253?\\{n\351\363\203\271\277Xpe0\261\262\300\277\002\377Ms\001\372\260?Q@\271\207nlp?\227\213\345\017\330\030\343\277=\202\020\"v\211\323\277\374\031\201\231n\252\301\277\271\"y\357f\037\317\277\322?A\307\345 \302\277}\236\306I\014\260\243\277\023\365(\030| \323\277\'^\304[\263\305\316\277882\000C1\264\277" + } + } + } +} +node { + name: "layer_2_type_1/matrix/read" + op: "Identity" + input: "layer_2_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_1/matrix" + } + } + } +} +node { + name: "layer_1_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\006\000\000\000" + } + } + } +} +node { + name: "layer_1_type_1/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\022\360K\230\252D\273?^\205p\234\236\013\273?\2325\261\341N(\267?\217\243t\024~\261\266?3\000\311|J\211\267? w\222*\237\240\267?" + } + } + } +} +node { + name: "layer_1_type_1/idt/read" + op: "Identity" + input: "layer_1_type_1/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_1/idt" + } + } + } +} +node { + name: "layer_1_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "t@\177\254\357@\316?\\\220=\222\321\341\325\277SJ\244\336\'\374\352\277\\\004\324\334X\241\317\277\262k\3218\352\255\376?\327G(\017E\353\326\277" + } + } + } +} +node { + name: "layer_1_type_1/bias/read" + op: "Identity" + input: "layer_1_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_1/bias" + } + } + } +} +node { + name: "layer_1_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + dim { + size: 6 + } + } + tensor_content: "\034CS\300\026\274\257?\226\035\256\225[\377\267\277YS\0141$\345\315\277\24174\257=\352\257\277\255\245\263\2149f\341?O\002p\301\3270\271\277/\200\352\3216h\274?<\321\367K\031\024\340\277\333\\?\272f=\307?W8\306m\220\300\314\277\255\305m\212#2\254?.\261\354\031\357%\323\277\240\364U\214>d\233?\217\330T\363S\317\333?\200bz\355Q;\313?\252-\321\317\302\362\300\277\333\357\343qk\352\322\277\014L\207\014i`\346?m\007\356\2708\252\272\277\0069H2ae\303?X\346m\336\271I\312?\236\252E\272q\346\306?\356\351\257&5\324\253?\r\315\2614\017W\271\277/\355\235A0\303\300\277\364\n\312\273@\375\260?5\316\2015\216yp?\251\263\3471N\031\343\277e\342\361\202\031\211\323\277\007\313DO\263\246\301\277\205\215u\343\252#\317\277\274Mic/!\302\277\022X)R\337\261\243\277\226\020\314\271\262 \323\277c\335\346k\322\305\316\277\224\007\200}\0261\264\277" + } + } + } +} +node { + name: "layer_1_type_1/matrix/read" + op: "Identity" + input: "layer_1_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_1/matrix" + } + } + } +} +node { + name: "layer_0_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\006\000\000\000" + } + } + } +} +node { + name: "layer_0_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\rD#\222\262\026\316?\007\016&\n\343\022\326\277\r\263\217T\360\207\352\277w6\265i\314\n\316\277\007\025\035\370G\254\376?\246\306$\233\201\021\327\277" + } + } + } +} +node { + name: "layer_0_type_1/bias/read" + op: "Identity" + input: "layer_0_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_1/bias" + } + } + } +} +node { + name: "layer_0_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 32 + } + dim { + size: 6 + } + } + tensor_content: "\375\251\231\317\304\274\250?\313\233\374\3757\370\250\277\336\271\257\310\304e\300\277\364\251\026&\230N\237\277\002\334L\223qM\324?)g3k\317\356\251\277\2215\235\216/>\261?\355\366K^]F\321\277$\340D\255\265 \275?\202\320\032\2077\001\275\277bi\026\204\372r\241?\346\207\220\265w\324\303\277\253s\351\333x\346\225?:\254?K\023t\2618.\323\277\244.@\355A \235?\254!\242\231x\246\333?%\3062<\276-\313?\016q\214\2125\007\301\277\353[i\236;\352\322\277\276\351\241\356\016O\346?:t\275\302m-\272\277\273i\330\374\270\203\303?A8*\227\244N\312?*lA\215\301\251\306?\232\314S\300\313\340\253?\374M\271\217\367-\271\277Vp\370\226]\271\300\277\243\032\245]m!\261?|\213\246\014\225Io?\204\374\226\204\352\033\343\277\355\2274M\215\214\323\277\036\261\243\211\337\243\301\277\224w\177 \377\023\317\277\\\350\307q\373\'\302\277\362\247\034\343~\252\243\277\310\267\203B\014\'\323\277\257(\266F}\304\316\277\000\277\3336|7\264\277" + } + } + } +} +node { + name: "layer_2_type_0/matrix/read" + op: "Identity" + input: "layer_2_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_0/matrix" + } + } + } +} +node { + name: "layer_1_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\006\000\000\000" + } + } + } +} +node { + name: "layer_1_type_0/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\330\014[\'\202a\273?\247\335\027\251\257U\273?lc[M)$\267?\350\356A\332\334\177\271?\274\326i\360;\204\267?Q\002l\260t\223\267?" + } + } + } +} +node { + name: "layer_1_type_0/idt/read" + op: "Identity" + input: "layer_1_type_0/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_0/idt" + } + } + } +} +node { + name: "layer_1_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "L\026\314_k\253\315?\357\270(#\350\342\325\277\002\013\361\201C\375\352\277g\356\272\006\322\310\315\277\355V\263eW\255\376?D\022\277d2\357\326\277" + } + } + } +} +node { + name: "layer_1_type_0/bias/read" + op: "Identity" + input: "layer_1_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_0/bias" + } + } + } +} +node { + name: "layer_1_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + dim { + size: 6 + } + } + tensor_content: "sF\370\211\t\303\257?\330\206\350~\250\002\270\277\243NPo\247\346\315\277L\207l-F\324\257\277:\002\234\377\307f\341?~(\203*i4\271\277\334o\351\347\267\205\274?\300}P\216F\030\340\277\036\214l!\2323\307?w0UJ\264\314\314\277O>?\270^@\254?\006\333lw(.\323\277\266?\200/K7\235?\373\227\000\236\217\250\333?\004\002\265\022\330.\313?\243\254\343|\271\002\301\277\030\341\237\2678\352\322\277\247)\034T1P\346?v\341|1\341\313\272\277\253\231\212\3231\221\303?\2412\177\317\004O\312?\211\355}\031^\301\306?\332\370\317\313|\336\253?\265\335\322\014\257\033\271\2771`U \331\315\300\277x\215P\010\322(\261?Q\223 m\002fo?\273.\240/\213\032\343\277fE?\353H\214\323\277\017%\2548\\\242\301\277a\326`\224\002\034\317\277\205\227lR|&\302\277\031j\013\314\266\254\243\277\307^\207Z\022&\323\2777\177\212\365\202\304\316\277>\230\212\300\2406\264\277" + } + } + } +} +node { + name: "layer_1_type_0/matrix/read" + op: "Identity" + input: "layer_1_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_0/matrix" + } + } + } +} +node { + name: "layer_0_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\006\000\000\000" + } + } + } +} +node { + name: "layer_0_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "d\261\354T\340\016\316?\206l^\351z\014\326\277\326\200\243\353\351\203\352\277\314`\234\350p\n\316\277g\324\213xi\254\376?m\374\331)\323\017\327\277" + } + } + } +} +node { + name: "layer_0_type_0/bias/read" + op: "Identity" + input: "layer_0_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_0/bias" + } + } + } +} +node { + name: "layer_0_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 32 + } + dim { + size: 6 + } + } + tensor_content: "~\271\215\354\303\202\250?O\021]\202\016\242\250\277`\240X\\\353V\300\277Z\213\222\275\254L\237\277\017\r_\006eO\324?E\312\005\022\327n\251\277\327\317v\243\034 \261?B<\225aP;\321\277\355\326U,\302=\275?\231Q\ro\273\001\275\277l\214\325\010\216\202\241?S\3513\376\303\007\304\277P%5\261ro\225?S?\342\202\325]\320?\251\032&b\310\324\300?n\3000GR\325\257\277\325\323z\010%\324\304\277\254\016\032\344r\254\331?\227;\353\250\3631\250\277E\316c\r\213\261\267?\332\322Xw\275\222\276?\241\246hR \004\273?\243O\303\310\334\253\245?\213kbS\201\236\260\277\266\236*\332\377v\256\277q\372@\331\207\377\244?E\037\226\272N\271\214?\rt\t\200\363B\325\277a;[\330\206\211\305\277\006bL\372\005H\263\277~\0262\200Z\306\277\277\242d#2_\026\263\277,h\270\322pU\222\277\356\307\310\233\031\351\304\277\241\350V2*\223\277\277|\005\224\216X\251\245\277\026\\_I\350\t\307?/\323\272\321\231\365\251?\\\372\345\335\035]|\277[\3771j\261\035\277\277\211\n\371\210\3508\271\277\247\206\200\264,\310\323?j({e8\326\310\277.ae\024y\337\246\277\000\375t\000~h\277?$\352YY\317\t\266\277\352SNi\255e\313\2773\020p\330\001i\220\277&\224\220\026\231\037\243?(\370\342\0135\005\311?sx`\016\217}\250\277\210\020A\017\340\\\252\277\232+e\314\351\002\323?\364\255x\336)]\233\277L\244\323\244zw\330\277\355,1\324AU\270?\240\274\027\251:\266\240?#\2243\035\022\227\253\277\323\014m\0226\304~?\377\311\247\362\026(\200?\3129CQ\206l\307?\322\253\202\361_\366\226?\356\350\023\212\342%\312\277[\321\326\345\261\270\253?\367L\222\203]\343\266\277\215\214\027\3452\317}?Y\226\261\202V\243\264\277\345H\267Q\331S\317?\221\030\210\023\370\001\245?\004\017\347S\244\303\325?9\205v\221\314s\206\277\211\306C6.]\213?\327\373,-\305\022\256\277E\032\005&\377\362\265\277i\362\227\267y\323\305?1\342\347\001p\333\240?e\303\375\360\210\333\316\277\261\237\374\353V\030\314\277\317e\351\022UD\315?$\017\256\226\211U\304?\023\267a\002MZ\304?\364*\237F\375\020\223?\304\250\234q\032\234\264\2770\312\334\330\325M\300\277\364\362\354\201\271\t\303\277\226;2\005\000\244\330?\026\275\t\223\236z\273?\200\244%\272\327\326\245?\376d\201\027|\005\325?\004t\033\000\314`\316?q\261\242\033k\314\300\277\277\033\022\371f\375\301\277\317\374\256\322\335\215\247\277O\020\031\332P\363\220?\017\005\201T\333a\234\277ByM\364\265-\305\2770{f%oB>?\370\025\000:C\271\305?\347\326d\0145p\313?\302\267Q\327\331\233\304\277?\365b|\310|\264\277e\353\240\232\216 \306\277eZ\274\217\020\374\271?\004G\320~d\374\250?&\304\034\001\243\254}?\322E/y\211\021\275\277\267H\010\260\275\301\303?\353\346i\242\242\333\313\277[\272\234\357\365\032\267\277!U\337\320\373*\321?W\000\215XQ\024\307?2\263\3369\267\241\230?\325i\364L\226\323\263?\"\3210|q\027\301?\242\217\321P\276\242\307\277\021\300\306L\024Z\323\277\321j,]q\253\242\277\360G\032\225\200\320\236\277\360\214\253d\006\266\266\277P\215\303\177#\316\300\277\367b\263\370\213\025\274?\0337\333q\363m\262\277d\227\311Y\215\033\276?=\031\323\313)Q\231\277 V\211\322\010\222\310?\025\362x\t(\243\266?\'d\025\220\014\324\234\277\260\373)\361ti\301?n.B.\322W\244\277\231\333\250\005\364\221\246\277\030 )n\237#\244\277\037\022\270X-<\253\277\303<#|\2126\267?e\361\200w\302\371\246\277\364\010\361\216\247}\267\277\215\355F\313o\360\254?\375\321\242\254c\205\322\277\222\033[5C6\267\277\3062\364A9W\314\277\354fL\\\214.\233\277HU\3245\373S\305?P\030\323\263\023~\312?\372\272\204\245=\374\315\277~\211\255\366\017\013\314?\\\335@\243p\227\217?qa\035%\314Z\221\277m\017\004\256r~\301?U\362S\216\364c\246\277\255_2D\216)s\277/\023)\234\271\277\271\277\377\361N\364Tb\224?\377\334\364{\325=\233\277l\314B7\337\354\314?^\251\0038\230~\303?n\317\271\262v\320\315\2775\246\316Y1Cn\277\316s\344\354\271\376\221\277HA\342\343<\214}\277\257\361G\343+\220\322?\331\306\375Z\254\334\217?\336\375\310\346\004\354\320?\3777\322\200G\r\303?!\326\005t\026B\260?\201\025L\032u\263\311\277\351\305.\203\304\017\320?IX\201?\025\257\244?\013M8\367\332\234\321\277\227&#\032G\217\273\277\206\010\375\277\373\212\302?!K]\013\202\367\324?~\024X\321\374\372\243?bh\032\255\327.\261?S\214\346\201\003\246\322?\022|\345\367\250\351\263?`\337\244I\t\373\262?\325\344\304\232\220x\323\277\243\004&_\273\010\224?4L\302KE8\256?\3608o\303\225\222\223\277\300H\335\037\334:\303\277\263\213a%\002\254\275\277\253\037\345JE4\304?h\217S\022\255\331\316?\266b\303\320\325\303\261?\270\370\005\262\315\\}?\355\364\013OPbK\277\264\035\365\020\225\311\317\277g\355i\2224i\311?&\241\213\200\320\330\311\277P\370O\345V\310\307?\031\251\263\223d\331\264\277\307\001\316\360\224\251\274\277" + } + } + } +} +node { + name: "layer_0_type_0/matrix/read" + op: "Identity" + input: "layer_0_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_0/matrix" + } + } + } +} +node { + name: "add_2/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "strided_slice_19/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_19/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_19/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "Reshape_14/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "Slice_2/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_2/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/Slice_2_grad/Reshape" + op: "Reshape" + input: "Slice_2/begin" + input: "gradients/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_13/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_18/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_18/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_18/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "Reshape_13/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_12/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_17/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_17/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_17/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "fitting_attr/daparam" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "fitting_attr/dfparam" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/concat_grad/mod" + op: "FloorMod" + input: "concat/axis" + input: "gradients/concat_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_9/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_13/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_13/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_13/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_12/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_12/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_12/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "filter_type_1/Reshape_14/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_4/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_4/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\000\000\000\000\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/Reshape" + op: "Reshape" + input: "filter_type_1/Slice_4/begin" + input: "gradients/filter_type_1/Slice_4_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/mul/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.007246376811594203 + } + } + } +} +node { + name: "filter_type_1/Reshape_13/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\\\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Reshape_12/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\\\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/concat_5/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_5/axis" + input: "gradients/filter_type_1/concat_5_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_11/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\006/U.p\335\317?\003\243\246\010\251\"\326\277\376\261\215\005\252\010\353\277\224\033\277zzF\316\277F\303\016\313\270q\376?\372\236\256\250\347\027\330\277\337\0101\320^\216\326?\347\243\241\021\336\224\373\277" + } + } + } +} +node { + name: "filter_type_1/bias_3_1/read" + op: "Identity" + input: "filter_type_1/bias_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_3_1" + } + } + } +} +node { + name: "filter_type_1/matrix_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "(,@\340d\333\263?k\000lr\307%\274\277\361\357\254E\303\325\315\277\010f\340V\311w\261\277\227\346;\203\n\341\341?X\017\314v\345\037\275\277\220\331\320Q\346\213\274?\222\307\013@\0317\337\277|\355\026\375w\'\311?\313]y%j\331\314\277M7\300\221d\230\254?\027d\1778v\016\323\277\020\362/@\215\'\236?\255\327$\353(\235\333?\304O\351_i\027\315?\362\322h&Rl\276\277\262+/\250\t\350\322\277\037lCa\005E\346?\352\022j\223\201B\267\277~\201Q\236\273=\302?\r{\342\357dL\312?-\372\254j\263\'\305?\224G\372\361\373\306\261?\337\376\306KN\263\270\2775-Y}d\006\275\277I\202\"\235b\352\250?\r\374\365\352l\202\223?\231\3532Y\036f\343\277\274\261\200\r\365\213\323\277\211n\257\372}\321\303\277\034\203 \273\302:\315\277m\037`\221\214\026\302\277" + } + } + } +} +node { + name: "filter_type_1/matrix_3_1/read" + op: "Identity" + input: "filter_type_1/matrix_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_3_1" + } + } + } +} +node { + name: "filter_type_1/concat_4/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_4/axis" + input: "gradients/filter_type_1/concat_4_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_10/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "{\205\343\2610/\316?\272I[!\240\031\326\277\'\007\242\262\330\n\353\277Y\"|\020\000\036\320\277" + } + } + } +} +node { + name: "filter_type_1/bias_2_1/read" + op: "Identity" + input: "filter_type_1/bias_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_2_1" + } + } + } +} +node { + name: "filter_type_1/matrix_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\336i\0024\3646\273?\361:\235\250do\303\2777\261\271e\253N\325\277\235\264/8\333a\267\277\346\304x\024\r.\351?,$\010Z\245H\304\277FM^\337\232\351\303?\256U\313+\312(\346\277" + } + } + } +} +node { + name: "filter_type_1/matrix_2_1/read" + op: "Identity" + input: "filter_type_1/matrix_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_2_1" + } + } + } +} +node { + name: "filter_type_1/concat_3/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_3/axis" + input: "gradients/filter_type_1/concat_3_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_9/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\370\215\022\247\275!\316?h.\003\272\037\007\327\277" + } + } + } +} +node { + name: "filter_type_1/bias_1_1/read" + op: "Identity" + input: "filter_type_1/bias_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_1_1" + } + } + } +} +node { + name: "filter_type_1/matrix_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\273\".J\265\360\302?\223lE,\313\020\313\277" + } + } + } +} +node { + name: "filter_type_1/matrix_1_1/read" + op: "Identity" + input: "filter_type_1/matrix_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_1_1" + } + } + } +} +node { + name: "filter_type_1/Reshape_8/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_3/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_3/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/Reshape" + op: "Reshape" + input: "filter_type_1/Slice_3/begin" + input: "gradients/filter_type_1/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_7/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_2/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377p\001\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_2/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\270\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/Reshape" + op: "Reshape" + input: "filter_type_1/Slice_2/begin" + input: "gradients/filter_type_1/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_6/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_2/axis" + input: "gradients/filter_type_1/concat_2_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_4/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "?\311:\366/\035\317?\0244\322\247\223\032\326\277{\307\377\234\264\010\353\277\0220\370Y\000m\316\2777\013\207\356\264q\376?)\220\221\004D,\327\277\013\274\033.\274\214\326?\201<\037\305\344\224\373\277" + } + } + } +} +node { + name: "filter_type_1/bias_3_0/read" + op: "Identity" + input: "filter_type_1/bias_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_3_0" + } + } + } +} +node { + name: "filter_type_1/matrix_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "[ \320\360\251\351\263?\035L_Z\221*\274\277;&\252QM\325\315\277\370\332\232\303\313\347\263\277\315\022=\350\017\341\341?A\354QZB\n\275\277\270\300\274l\265\201\274?Cv#\342\3646\337\277\334\034\333\306>0\311?\'\276\"\223\201\334\314\2777\257C\"5\232\254?\021d\332\210\325\037\323\277-x.\022\330(\236?~Z\032\272n\241\333?\'\313ut\342\023\315?\241\326b\202\304k\276\277\231l\363\2574\344\322\277^\265\317\264DD\346?\274\"\210\252\341A\267\277\024\0074\363n\355\301?\245\267w}~L\312?P^\261\367]1\305?\204\333\024\361,\276\261?\267\341j\267\337\262\270\277\345\336s~\376\366\274\277d\352P0,\255\250?\037\020\241|\014\210\223?\373\3643\376\374\217\343\277\340\311;\347\335\213\323\277\323&[(v\306\303\277\225\"\013MR@\315\277(zm\273G\026\302\277" + } + } + } +} +node { + name: "filter_type_1/matrix_3_0/read" + op: "Identity" + input: "filter_type_1/matrix_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_3_0" + } + } + } +} +node { + name: "filter_type_1/concat_1/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_1/axis" + input: "gradients/filter_type_1/concat_1_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "l\330=W\217/\316?\n\211$3\007\032\326\277\t\364\311\336\272\n\353\277%\203K\354\312\035\320\277" + } + } + } +} +node { + name: "filter_type_1/bias_2_0/read" + op: "Identity" + input: "filter_type_1/bias_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_2_0" + } + } + } +} +node { + name: "filter_type_1/matrix_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\021\363U\317u;\273?\321\274\274\213\'u\303\277\036\220\226\213\303O\325\277\016a\245p\271_\267\277w\2562Jr.\351?)JVR\226K\304\277\241\346D-\352\347\303?\025\027\262@\222(\346\277" + } + } + } +} +node { + name: "filter_type_1/matrix_2_0/read" + op: "Identity" + input: "filter_type_1/matrix_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_2_0" + } + } + } +} +node { + name: "filter_type_1/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat/axis" + input: "gradients/filter_type_1/concat_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_2/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\351zg[\374\034\316?\021=\325\031~\375\326\277" + } + } + } +} +node { + name: "filter_type_1/bias_1_0/read" + op: "Identity" + input: "filter_type_1/bias_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_1_0" + } + } + } +} +node { + name: "filter_type_1/matrix_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "NP\215[A\357\302?m\245Db\334+\312\277" + } + } + } +} +node { + name: "filter_type_1/matrix_1_0/read" + op: "Identity" + input: "filter_type_1/matrix_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_1_0" + } + } + } +} +node { + name: "filter_type_1/Reshape_1/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_1/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_1/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Reshape" + op: "Reshape" + input: "filter_type_1/Slice_1/begin" + input: "gradients/filter_type_1/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\270\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Reshape" + op: "Reshape" + input: "filter_type_1/Slice/begin" + input: "gradients/filter_type_1/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_10/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377(\002\000\000" + } + } + } +} +node { + name: "Slice_1/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_1/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_8/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 552 + } + } + } +} +node { + name: "strided_slice_11/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_11/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_11/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "mul_7/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 552 + } + } + } +} +node { + name: "add/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "strided_slice_10/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_10/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_10/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "mul_4/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_7/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_7/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_7/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_6/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_6/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_6/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "filter_type_0/Reshape_14/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_4/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_4/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\000\000\000\000\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/Reshape" + op: "Reshape" + input: "filter_type_0/Slice_4/begin" + input: "gradients/filter_type_0/Slice_4_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/mul/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.007246376811594203 + } + } + } +} +node { + name: "filter_type_0/Reshape_13/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\\\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Reshape_12/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\\\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/concat_5/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat_5/axis" + input: "gradients/filter_type_0/concat_5_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_11/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\275k\312q\317\030\320?\347tv9*\034\326\277\231L\260$Q\013\353\277\232\330pg\222\'\320\277u\303\364\005\350n\376?jC]\2425 \327\277\207\264l!\316\205\326?\027\265\246\215d\226\373\277" + } + } + } +} +node { + name: "filter_type_0/bias_3_1/read" + op: "Identity" + input: "filter_type_0/bias_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_3_1" + } + } + } +} +node { + name: "filter_type_0/matrix_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "RX\366S\240\376\263?\3670t\232\301&\274\277P\027H7\312\312\315\277)\314\247\350{=\257\277\316\331\332_\313\346\341?{\245\213\301\320`\274\277\342\320\030\270\333\242\274?\374\365\377\257\3040\337\277U\000d\365\2738\311?\007Rk\264\032\334\314\277\201\362\301<\003\304\254?\355\007-\351\241\036\322\277\205\313\351\tR\334\236?K\246X\375\335\300\333?\31193\271&#\315?z\333g\004\230S\276\277\020\267:}r\337\322\277\262U\226\263\234D\346?\017-\003->-\267\277\330v\320\322\367\375\303?\355\226\024H\001c\312?\023K-|\230{\305?\232h{\n\334\335\261?\257\320\247E\311\232\270\277%\330r\364\205\346\274\277 \001\005~\236\303\250?\325\302$WE\330\223?+\370\323\375\311#\343\277\006B\305\326\204\200\323\277\313k\341\333\225s\303\277\272\342\'\336\'1\315\277o\322$\331 \n\302\277" + } + } + } +} +node { + name: "filter_type_0/matrix_3_1/read" + op: "Identity" + input: "filter_type_0/matrix_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_3_1" + } + } + } +} +node { + name: "filter_type_0/concat_4/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat_4/axis" + input: "gradients/filter_type_0/concat_4_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_10/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\370C\346\346\246\031\316?\364\345\202\'\273\"\326\277\240D\005G\'\013\353\277\025\240\346\030\254$\320\277" + } + } + } +} +node { + name: "filter_type_0/bias_2_1/read" + op: "Identity" + input: "filter_type_0/bias_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_2_1" + } + } + } +} +node { + name: "filter_type_0/matrix_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\362V\354\2341_\273?\035\020y\245\035a\303\277d\253\223%zM\325\277\235\nY\350==\267\2779\257{\374U3\351?\215\253\026U\0229\304\277\310\214\202\277\345\353\303?#d\376\000\241$\346\277" + } + } + } +} +node { + name: "filter_type_0/matrix_2_1/read" + op: "Identity" + input: "filter_type_0/matrix_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_2_1" + } + } + } +} +node { + name: "filter_type_0/concat_3/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat_3/axis" + input: "gradients/filter_type_0/concat_3_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_9/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\231\211\314L~\r\316?\311?\303\255\234\026\327\277" + } + } + } +} +node { + name: "filter_type_0/bias_1_1/read" + op: "Identity" + input: "filter_type_0/bias_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_1_1" + } + } + } +} +node { + name: "filter_type_0/matrix_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\353\244I\003\013\374\302?\372\274\3025\235\002\311\277" + } + } + } +} +node { + name: "filter_type_0/matrix_1_1/read" + op: "Identity" + input: "filter_type_0/matrix_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_1_1" + } + } + } +} +node { + name: "filter_type_0/Reshape_8/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_3/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_3/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/Reshape" + op: "Reshape" + input: "filter_type_0/Slice_3/begin" + input: "gradients/filter_type_0/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_7/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_2/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377p\001\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_2/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\270\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/Reshape" + op: "Reshape" + input: "filter_type_0/Slice_2/begin" + input: "gradients/filter_type_0/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_6/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat_2/axis" + input: "gradients/filter_type_0/concat_2_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_4/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\034e\254\325\271\026\316?\314\212\336\350\263\035\326\277\202\340\010\223Z\013\353\277>\027\323@N*\320\2779\315g\341\345n\376?\240\363=tf4\327\277y\364A\315Z\207\326?a\207\316{g\226\373\277" + } + } + } +} +node { + name: "filter_type_0/bias_3_0/read" + op: "Identity" + input: "filter_type_0/bias_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_3_0" + } + } + } +} +node { + name: "filter_type_0/matrix_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\266\303\000!\375\360\263?\235\320\211\242\305\034\274\277\244\306\334\340\205\313\315\277V\242kv\260g\257\277\331\005<\203\320\346\341?\267\243{\336j\373\274\277lq\374\274q\256\274?\220u\036\220\2670\337\277\020\311\224q\265/\311?\244:\211\034%\326\314\277VzRiC\302\254?\305\232K\200t\036\322\277\223\351j\276\340\334\236?\305\000\376\207\342\245\333?\222\3501\203\030\'\315?\\[\300XhS\276\277\352\245\312\336<\343\322\277\3054CW\001F\346?P\0009\345-.\267\277\341\326J\315\254\373\303?~\322\201W\022c\312?\211\n\roI9\305?ZJf?a\347\261?L\201Rs\233\232\270\277\035\017\000UL\367\274\277\022\226\330\244\014\366\250?\370\331\256\205\236\323\223?\334\342\375\234\356\"\343\277\252\363\306\026}\200\323\277\356\310\005+\260\301\303\277\312j\260\302\306*\315\277\014\237&\027\014\n\302\277" + } + } + } +} +node { + name: "filter_type_0/matrix_3_0/read" + op: "Identity" + input: "filter_type_0/matrix_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_3_0" + } + } + } +} +node { + name: "filter_type_0/concat_1/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat_1/axis" + input: "gradients/filter_type_0/concat_1_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\010\3519\237R\031\316?\373\275\001kt$\326\277m\262\242\327\025\013\353\277\035\343Q2\022%\320\277" + } + } + } +} +node { + name: "filter_type_0/bias_2_0/read" + op: "Identity" + input: "filter_type_0/bias_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_2_0" + } + } + } +} +node { + name: "filter_type_0/matrix_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\273\277\257\261\274\\\273?/P9\270\267d\303\277:\035\266\2160L\325\277\352\207u\006\325A\267\277 \260mR93\351?\253\177S\027B:\304\277\275\016\037\017\375\354\303?.N\207z\347$\346\277" + } + } + } +} +node { + name: "filter_type_0/matrix_2_0/read" + op: "Identity" + input: "filter_type_0/matrix_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_2_0" + } + } + } +} +node { + name: "filter_type_0/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat/axis" + input: "gradients/filter_type_0/concat_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_2/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: ";4\\\252j\r\316?\014_fH\356\030\327\277" + } + } + } +} +node { + name: "filter_type_0/bias_1_0/read" + op: "Identity" + input: "filter_type_0/bias_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_1_0" + } + } + } +} +node { + name: "filter_type_0/matrix_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\033R\363\253}\375\302?Ej\205\005\333\016\311\277" + } + } + } +} +node { + name: "filter_type_0/matrix_1_0/read" + op: "Identity" + input: "filter_type_0/matrix_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_1_0" + } + } + } +} +node { + name: "filter_type_0/Reshape_1/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_1/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_1/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Reshape" + op: "Reshape" + input: "filter_type_0/Slice_1/begin" + input: "gradients/filter_type_0/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\270\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Reshape" + op: "Reshape" + input: "filter_type_0/Slice/begin" + input: "gradients/filter_type_0/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_7/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377(\002\000\000" + } + } + } +} +node { + name: "Slice/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/Slice_grad/Reshape" + op: "Reshape" + input: "Slice/begin" + input: "gradients/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_3/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 552 + } + } + } +} +node { + name: "strided_slice_5/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_5/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_5/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "Reshape_6/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_2/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 552 + } + } + } +} +node { + name: "strided_slice_4/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_4/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_4/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377(\002\000\000" + } + } + } +} +node { + name: "Reshape_4/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "strided_slice_3/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_3/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_3/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\t\000\000\000" + } + } + } +} +node { + name: "Reshape_2/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_1/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_2/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_2/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_2/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "descrpt_attr/t_std" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 552 + } + } + tensor_content: "q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?" + } + } + } +} +node { + name: "descrpt_attr/t_std/read" + op: "Identity" + input: "descrpt_attr/t_std" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@descrpt_attr/t_std" + } + } + } +} +node { + name: "descrpt_attr/t_avg" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 552 + } + } + tensor_content: "\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "descrpt_attr/t_avg/read" + op: "Identity" + input: "descrpt_attr/t_avg" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@descrpt_attr/t_avg" + } + } + } +} +node { + name: "descrpt_attr/ntypes" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "descrpt_attr/rcut" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 6.0 + } + } + } +} +node { + name: "model_attr/model_type" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "ener" + } + } + } +} +node { + name: "model_attr/tmap" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "O H" + } + } + } +} +node { + name: "t_mesh" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "t_natoms" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: 4 + } + } + } + } +} +node { + name: "strided_slice_29" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_29/stack" + input: "strided_slice_29/stack_1" + input: "strided_slice_29/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_18" + op: "Mul" + input: "mul_18/x" + input: "strided_slice_29" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "o_atom_virial/shape" + op: "Pack" + input: "o_atom_virial/shape/0" + input: "mul_18" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_28" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_28/stack" + input: "strided_slice_28/stack_1" + input: "strided_slice_28/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_17" + op: "Mul" + input: "mul_17/x" + input: "strided_slice_28" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "o_force/shape" + op: "Pack" + input: "o_force/shape/0" + input: "mul_17" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_27" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_27/stack" + input: "strided_slice_27/stack_1" + input: "strided_slice_27/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_16" + op: "Mul" + input: "strided_slice_27" + input: "mul_16/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_19/shape" + op: "Pack" + input: "Reshape_19/shape/0" + input: "mul_16" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_26" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_26/stack" + input: "strided_slice_26/stack_1" + input: "strided_slice_26/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "o_atom_energy/shape" + op: "Pack" + input: "o_atom_energy/shape/0" + input: "strided_slice_26" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_25" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_25/stack" + input: "strided_slice_25/stack_1" + input: "strided_slice_25/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_22" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_22/stack" + input: "strided_slice_22/stack_1" + input: "strided_slice_22/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_15" + op: "Mul" + input: "strided_slice_22" + input: "mul_15/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_3/size" + op: "Pack" + input: "Slice_3/size/0" + input: "mul_15" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_21" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_21/stack" + input: "strided_slice_21/stack_1" + input: "strided_slice_21/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_19" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_19/stack" + input: "strided_slice_19/stack_1" + input: "strided_slice_19/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "add_2" + op: "Add" + input: "add_2/x" + input: "strided_slice_19" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_14" + op: "Mul" + input: "add_2" + input: "mul_14/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_3/begin" + op: "Pack" + input: "Slice_3/begin/0" + input: "mul_14" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/Slice_3_grad/Reshape" + op: "Reshape" + input: "Slice_3/begin" + input: "gradients/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_18" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_18/stack" + input: "strided_slice_18/stack_1" + input: "strided_slice_18/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_13" + op: "Mul" + input: "strided_slice_18" + input: "mul_13/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_2/size" + op: "Pack" + input: "Slice_2/size/0" + input: "mul_13" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_17" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_17/stack" + input: "strided_slice_17/stack_1" + input: "strided_slice_17/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_12" + op: "Mul" + input: "mul_12/x" + input: "strided_slice_17" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_13/shape" + op: "Pack" + input: "Reshape_13/shape/0" + input: "mul_12" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_13" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_13/stack" + input: "strided_slice_13/stack_1" + input: "strided_slice_13/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_9" + op: "Mul" + input: "strided_slice_13" + input: "mul_9/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_11" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_11/stack" + input: "strided_slice_11/stack_1" + input: "strided_slice_11/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_8" + op: "Mul" + input: "strided_slice_11" + input: "mul_8/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_1/size" + op: "Pack" + input: "Slice_1/size/0" + input: "mul_8" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_10" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_10/stack" + input: "strided_slice_10/stack_1" + input: "strided_slice_10/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "add" + op: "Add" + input: "add/x" + input: "strided_slice_10" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_7" + op: "Mul" + input: "add" + input: "mul_7/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_1/begin" + op: "Pack" + input: "Slice_1/begin/0" + input: "mul_7" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/Slice_1_grad/Reshape" + op: "Reshape" + input: "Slice_1/begin" + input: "gradients/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_7" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_7/stack" + input: "strided_slice_7/stack_1" + input: "strided_slice_7/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_4" + op: "Mul" + input: "strided_slice_7" + input: "mul_4/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_5" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_5/stack" + input: "strided_slice_5/stack_1" + input: "strided_slice_5/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_3" + op: "Mul" + input: "strided_slice_5" + input: "mul_3/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice/size" + op: "Pack" + input: "Slice/size/0" + input: "mul_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_4" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_4/stack" + input: "strided_slice_4/stack_1" + input: "strided_slice_4/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_2" + op: "Mul" + input: "mul_2/x" + input: "strided_slice_4" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_6/shape" + op: "Pack" + input: "Reshape_6/shape/0" + input: "mul_2" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_3" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_3/stack" + input: "strided_slice_3/stack_1" + input: "strided_slice_3/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_4/shape" + op: "Pack" + input: "Reshape_4/shape/0" + input: "strided_slice_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_2" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_2/stack" + input: "strided_slice_2/stack_1" + input: "strided_slice_2/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_1" + op: "Mul" + input: "strided_slice_2" + input: "mul_1/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_2/shape" + op: "Pack" + input: "Reshape_2/shape/0" + input: "mul_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "t_type" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_4" + op: "Reshape" + input: "t_type" + input: "Reshape_4/shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "t_coord" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_2" + op: "Reshape" + input: "t_coord" + input: "Reshape_2/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "t_box" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_3" + op: "Reshape" + input: "t_box" + input: "Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "DescrptSeA" + op: "DescrptSeA" + input: "Reshape_2" + input: "Reshape_4" + input: "t_natoms" + input: "Reshape_3" + input: "t_mesh" + input: "descrpt_attr/t_avg/read" + input: "descrpt_attr/t_std/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "rcut_a" + value { + f: -1.0 + } + } + attr { + key: "rcut_r" + value { + f: 6.0 + } + } + attr { + key: "rcut_r_smth" + value { + f: 0.5 + } + } + attr { + key: "sel_a" + value { + list { + i: 46 + i: 92 + } + } + } + attr { + key: "sel_r" + value { + list { + i: 0 + i: 0 + } + } + } +} +node { + name: "o_nlist" + op: "Identity" + input: "DescrptSeA:3" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "o_rij" + op: "Identity" + input: "DescrptSeA:2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "o_rmat_deriv" + op: "Identity" + input: "DescrptSeA:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_5" + op: "Reshape" + input: "DescrptSeA" + input: "Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_rmat" + op: "Identity" + input: "Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_6_grad/Shape" + op: "Shape" + input: "o_rmat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_6" + op: "Reshape" + input: "o_rmat" + input: "Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/Shape_1" + op: "Shape" + input: "Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/Shape_1" + op: "Shape" + input: "Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_2" + op: "Shape" + input: "Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_12" + op: "StridedSlice" + input: "Shape_2" + input: "strided_slice_12/stack" + input: "strided_slice_12/stack_1" + input: "strided_slice_12/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_11/shape" + op: "Pack" + input: "strided_slice_12" + input: "mul_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_1" + op: "Slice" + input: "Reshape_6" + input: "Slice_1/begin" + input: "Slice_1/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Slice_1_grad/Shape" + op: "Shape" + input: "Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/sub" + op: "Sub" + input: "gradients/Slice_1_grad/Shape_1" + input: "gradients/Slice_1_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/sub_1" + op: "Sub" + input: "gradients/Slice_1_grad/sub" + input: "Slice_1/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/Slice_1_grad/sub_1" + input: "gradients/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/concat" + op: "ConcatV2" + input: "gradients/Slice_1_grad/Reshape" + input: "gradients/Slice_1_grad/Reshape_1" + input: "gradients/Slice_1_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_10_grad/Shape" + op: "Shape" + input: "Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_10" + op: "Reshape" + input: "Slice_1" + input: "Reshape_10/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/Shape_1" + op: "Shape" + input: "Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Shape_1" + op: "Shape" + input: "Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Slice_2" + op: "Slice" + input: "Reshape_10" + input: "filter_type_1/Slice_2/begin" + input: "filter_type_1/Slice_2/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/sub" + op: "Sub" + input: "gradients/filter_type_1/Slice_2_grad/Shape_1" + input: "gradients/filter_type_1/Slice_2_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_1/Slice_2_grad/sub" + input: "filter_type_1/Slice_2/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/Slice_2_grad/sub_1" + input: "gradients/filter_type_1/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_1/Slice_2_grad/Reshape" + input: "gradients/filter_type_1/Slice_2_grad/Reshape_1" + input: "gradients/filter_type_1/Slice_2_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_7_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_13_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_13" + op: "Reshape" + input: "filter_type_1/Slice_2" + input: "filter_type_1/Reshape_13/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_7" + op: "Reshape" + input: "filter_type_1/Slice_2" + input: "filter_type_1/Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Slice_3" + op: "Slice" + input: "filter_type_1/Reshape_7" + input: "filter_type_1/Slice_3/begin" + input: "filter_type_1/Slice_3/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/sub" + op: "Sub" + input: "gradients/filter_type_1/Slice_3_grad/Shape_1" + input: "gradients/filter_type_1/Slice_3_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_1/Slice_3_grad/sub" + input: "filter_type_1/Slice_3/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/Slice_3_grad/sub_1" + input: "gradients/filter_type_1/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_1/Slice_3_grad/Reshape" + input: "gradients/filter_type_1/Slice_3_grad/Reshape_1" + input: "gradients/filter_type_1/Slice_3_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_8_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_8" + op: "Reshape" + input: "filter_type_1/Slice_3" + input: "filter_type_1/Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/Reshape_8" + input: "filter_type_1/Reshape_8" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_3_grad/mod" + input: "gradients/filter_type_1/concat_3_grad/ShapeN" + input: "gradients/filter_type_1/concat_3_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_3" + op: "ConcatV2" + input: "filter_type_1/Reshape_8" + input: "filter_type_1/Reshape_8" + input: "filter_type_1/concat_3/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_4" + op: "MatMul" + input: "filter_type_1/Reshape_8" + input: "filter_type_1/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_6_grad/Shape" + input: "gradients/filter_type_1/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_6" + op: "Add" + input: "filter_type_1/MatMul_4" + input: "filter_type_1/bias_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_3" + op: "Tanh" + input: "filter_type_1/add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_9_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_9" + op: "Reshape" + input: "filter_type_1/Tanh_3" + input: "filter_type_1/Reshape_9/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_7_grad/Shape" + input: "gradients/filter_type_1/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_7" + op: "Add" + input: "filter_type_1/concat_3" + input: "filter_type_1/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/add_7" + input: "filter_type_1/add_7" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_4_grad/mod" + input: "gradients/filter_type_1/concat_4_grad/ShapeN" + input: "gradients/filter_type_1/concat_4_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_4" + op: "ConcatV2" + input: "filter_type_1/add_7" + input: "filter_type_1/add_7" + input: "filter_type_1/concat_4/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_5" + op: "MatMul" + input: "filter_type_1/add_7" + input: "filter_type_1/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_8_grad/Shape" + input: "gradients/filter_type_1/add_8_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_8" + op: "Add" + input: "filter_type_1/MatMul_5" + input: "filter_type_1/bias_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_4" + op: "Tanh" + input: "filter_type_1/add_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_10_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_10" + op: "Reshape" + input: "filter_type_1/Tanh_4" + input: "filter_type_1/Reshape_10/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_9_grad/Shape" + input: "gradients/filter_type_1/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_9" + op: "Add" + input: "filter_type_1/concat_4" + input: "filter_type_1/Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/add_9" + input: "filter_type_1/add_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_5_grad/mod" + input: "gradients/filter_type_1/concat_5_grad/ShapeN" + input: "gradients/filter_type_1/concat_5_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_5" + op: "ConcatV2" + input: "filter_type_1/add_9" + input: "filter_type_1/add_9" + input: "filter_type_1/concat_5/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_6" + op: "MatMul" + input: "filter_type_1/add_9" + input: "filter_type_1/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_10_grad/Shape" + input: "gradients/filter_type_1/add_10_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_10" + op: "Add" + input: "filter_type_1/MatMul_6" + input: "filter_type_1/bias_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_5" + op: "Tanh" + input: "filter_type_1/add_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_11_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_11" + op: "Reshape" + input: "filter_type_1/Tanh_5" + input: "filter_type_1/Reshape_11/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_11_grad/Shape" + input: "gradients/filter_type_1/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_11" + op: "Add" + input: "filter_type_1/concat_5" + input: "filter_type_1/Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_12_grad/Shape" + op: "Shape" + input: "filter_type_1/add_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_12" + op: "Reshape" + input: "filter_type_1/add_11" + input: "filter_type_1/Reshape_12/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_7" + op: "BatchMatMul" + input: "filter_type_1/Reshape_13" + input: "filter_type_1/Reshape_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_12_grad/Shape_1" + op: "Shape" + input: "filter_type_1/MatMul_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Slice" + op: "Slice" + input: "Reshape_10" + input: "filter_type_1/Slice/begin" + input: "filter_type_1/Slice/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/sub" + op: "Sub" + input: "gradients/filter_type_1/Slice_grad/Shape_1" + input: "gradients/filter_type_1/Slice_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_1/Slice_grad/sub" + input: "filter_type_1/Slice/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/Slice_grad/sub_1" + input: "gradients/filter_type_1/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_1/Slice_grad/Reshape" + input: "gradients/filter_type_1/Slice_grad/Reshape_1" + input: "gradients/filter_type_1/Slice_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_6_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_6" + op: "Reshape" + input: "filter_type_1/Slice" + input: "filter_type_1/Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape" + op: "Reshape" + input: "filter_type_1/Slice" + input: "filter_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Slice_1" + op: "Slice" + input: "filter_type_1/Reshape" + input: "filter_type_1/Slice_1/begin" + input: "filter_type_1/Slice_1/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/sub" + op: "Sub" + input: "gradients/filter_type_1/Slice_1_grad/Shape_1" + input: "gradients/filter_type_1/Slice_1_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_1/Slice_1_grad/sub" + input: "filter_type_1/Slice_1/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/Slice_1_grad/sub_1" + input: "gradients/filter_type_1/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_1/Slice_1_grad/Reshape" + input: "gradients/filter_type_1/Slice_1_grad/Reshape_1" + input: "gradients/filter_type_1/Slice_1_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_1_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_1" + op: "Reshape" + input: "filter_type_1/Slice_1" + input: "filter_type_1/Reshape_1/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/Reshape_1" + input: "filter_type_1/Reshape_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_grad/mod" + input: "gradients/filter_type_1/concat_grad/ShapeN" + input: "gradients/filter_type_1/concat_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat" + op: "ConcatV2" + input: "filter_type_1/Reshape_1" + input: "filter_type_1/Reshape_1" + input: "filter_type_1/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Shape" + op: "Shape" + input: "filter_type_1/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul" + op: "MatMul" + input: "filter_type_1/Reshape_1" + input: "filter_type_1/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_grad/Shape" + input: "gradients/filter_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add" + op: "Add" + input: "filter_type_1/MatMul" + input: "filter_type_1/bias_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh" + op: "Tanh" + input: "filter_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_2_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_2" + op: "Reshape" + input: "filter_type_1/Tanh" + input: "filter_type_1/Reshape_2/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_1_grad/Shape" + input: "gradients/filter_type_1/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_1" + op: "Add" + input: "filter_type_1/concat" + input: "filter_type_1/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/add_1" + input: "filter_type_1/add_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_1_grad/mod" + input: "gradients/filter_type_1/concat_1_grad/ShapeN" + input: "gradients/filter_type_1/concat_1_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_1" + op: "ConcatV2" + input: "filter_type_1/add_1" + input: "filter_type_1/add_1" + input: "filter_type_1/concat_1/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_1" + op: "MatMul" + input: "filter_type_1/add_1" + input: "filter_type_1/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_2_grad/Shape" + input: "gradients/filter_type_1/add_2_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_2" + op: "Add" + input: "filter_type_1/MatMul_1" + input: "filter_type_1/bias_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_1" + op: "Tanh" + input: "filter_type_1/add_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_3_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_3" + op: "Reshape" + input: "filter_type_1/Tanh_1" + input: "filter_type_1/Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_3_grad/Shape" + input: "gradients/filter_type_1/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_3" + op: "Add" + input: "filter_type_1/concat_1" + input: "filter_type_1/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/add_3" + input: "filter_type_1/add_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_2_grad/mod" + input: "gradients/filter_type_1/concat_2_grad/ShapeN" + input: "gradients/filter_type_1/concat_2_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_2" + op: "ConcatV2" + input: "filter_type_1/add_3" + input: "filter_type_1/add_3" + input: "filter_type_1/concat_2/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_2" + op: "MatMul" + input: "filter_type_1/add_3" + input: "filter_type_1/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_4_grad/Shape" + input: "gradients/filter_type_1/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_4" + op: "Add" + input: "filter_type_1/MatMul_2" + input: "filter_type_1/bias_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_2" + op: "Tanh" + input: "filter_type_1/add_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_4_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_4" + op: "Reshape" + input: "filter_type_1/Tanh_2" + input: "filter_type_1/Reshape_4/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_5_grad/Shape" + input: "gradients/filter_type_1/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_5" + op: "Add" + input: "filter_type_1/concat_2" + input: "filter_type_1/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_5_grad/Shape" + op: "Shape" + input: "filter_type_1/add_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_5" + op: "Reshape" + input: "filter_type_1/add_5" + input: "filter_type_1/Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_3" + op: "BatchMatMul" + input: "filter_type_1/Reshape_6" + input: "filter_type_1/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_12_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_12_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_12_grad/Shape" + input: "gradients/filter_type_1/add_12_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_12" + op: "Add" + input: "filter_type_1/MatMul_3" + input: "filter_type_1/MatMul_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Shape" + op: "Shape" + input: "filter_type_1/add_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/mul_grad/Shape" + input: "gradients/filter_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/mul" + op: "Mul" + input: "filter_type_1/add_12" + input: "filter_type_1/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/Shape_1" + op: "Shape" + input: "filter_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Slice_4" + op: "Slice" + input: "filter_type_1/mul" + input: "filter_type_1/Slice_4/begin" + input: "filter_type_1/Slice_4/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/sub" + op: "Sub" + input: "gradients/filter_type_1/Slice_4_grad/Shape_1" + input: "gradients/filter_type_1/Slice_4_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_1/Slice_4_grad/sub" + input: "filter_type_1/Slice_4/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/Slice_4_grad/sub_1" + input: "gradients/filter_type_1/Slice_4_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_1/Slice_4_grad/Reshape" + input: "gradients/filter_type_1/Slice_4_grad/Reshape_1" + input: "gradients/filter_type_1/Slice_4_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_8" + op: "BatchMatMul" + input: "filter_type_1/mul" + input: "filter_type_1/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/Reshape_14_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_14" + op: "Reshape" + input: "filter_type_1/MatMul_8" + input: "filter_type_1/Reshape_14/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_11_grad/Shape" + op: "Shape" + input: "filter_type_1/Reshape_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_11" + op: "Reshape" + input: "filter_type_1/Reshape_14" + input: "Reshape_11/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape" + op: "Shape" + input: "Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_6" + op: "StridedSlice" + input: "Shape" + input: "strided_slice_6/stack" + input: "strided_slice_6/stack_1" + input: "strided_slice_6/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_8/shape" + op: "Pack" + input: "strided_slice_6" + input: "mul_4" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice" + op: "Slice" + input: "Reshape_6" + input: "Slice/begin" + input: "Slice/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Slice_grad/Shape" + op: "Shape" + input: "Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/sub" + op: "Sub" + input: "gradients/Slice_grad/Shape_1" + input: "gradients/Slice_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/sub_1" + op: "Sub" + input: "gradients/Slice_grad/sub" + input: "Slice/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/Reshape_1" + op: "Reshape" + input: "gradients/Slice_grad/sub_1" + input: "gradients/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/concat" + op: "ConcatV2" + input: "gradients/Slice_grad/Reshape" + input: "gradients/Slice_grad/Reshape_1" + input: "gradients/Slice_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_7_grad/Shape" + op: "Shape" + input: "Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_7" + op: "Reshape" + input: "Slice" + input: "Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/Shape_1" + op: "Shape" + input: "Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Shape_1" + op: "Shape" + input: "Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Slice_2" + op: "Slice" + input: "Reshape_7" + input: "filter_type_0/Slice_2/begin" + input: "filter_type_0/Slice_2/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/sub" + op: "Sub" + input: "gradients/filter_type_0/Slice_2_grad/Shape_1" + input: "gradients/filter_type_0/Slice_2_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_0/Slice_2_grad/sub" + input: "filter_type_0/Slice_2/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/Slice_2_grad/sub_1" + input: "gradients/filter_type_0/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_0/Slice_2_grad/Reshape" + input: "gradients/filter_type_0/Slice_2_grad/Reshape_1" + input: "gradients/filter_type_0/Slice_2_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_7_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_13_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_13" + op: "Reshape" + input: "filter_type_0/Slice_2" + input: "filter_type_0/Reshape_13/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_7" + op: "Reshape" + input: "filter_type_0/Slice_2" + input: "filter_type_0/Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Slice_3" + op: "Slice" + input: "filter_type_0/Reshape_7" + input: "filter_type_0/Slice_3/begin" + input: "filter_type_0/Slice_3/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/sub" + op: "Sub" + input: "gradients/filter_type_0/Slice_3_grad/Shape_1" + input: "gradients/filter_type_0/Slice_3_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_0/Slice_3_grad/sub" + input: "filter_type_0/Slice_3/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/Slice_3_grad/sub_1" + input: "gradients/filter_type_0/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_0/Slice_3_grad/Reshape" + input: "gradients/filter_type_0/Slice_3_grad/Reshape_1" + input: "gradients/filter_type_0/Slice_3_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_8_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_8" + op: "Reshape" + input: "filter_type_0/Slice_3" + input: "filter_type_0/Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/Reshape_8" + input: "filter_type_0/Reshape_8" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_3_grad/mod" + input: "gradients/filter_type_0/concat_3_grad/ShapeN" + input: "gradients/filter_type_0/concat_3_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_3" + op: "ConcatV2" + input: "filter_type_0/Reshape_8" + input: "filter_type_0/Reshape_8" + input: "filter_type_0/concat_3/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_4" + op: "MatMul" + input: "filter_type_0/Reshape_8" + input: "filter_type_0/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_6_grad/Shape" + input: "gradients/filter_type_0/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_6" + op: "Add" + input: "filter_type_0/MatMul_4" + input: "filter_type_0/bias_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_3" + op: "Tanh" + input: "filter_type_0/add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_9_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_9" + op: "Reshape" + input: "filter_type_0/Tanh_3" + input: "filter_type_0/Reshape_9/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_7_grad/Shape" + input: "gradients/filter_type_0/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_7" + op: "Add" + input: "filter_type_0/concat_3" + input: "filter_type_0/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/add_7" + input: "filter_type_0/add_7" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_4_grad/mod" + input: "gradients/filter_type_0/concat_4_grad/ShapeN" + input: "gradients/filter_type_0/concat_4_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_4" + op: "ConcatV2" + input: "filter_type_0/add_7" + input: "filter_type_0/add_7" + input: "filter_type_0/concat_4/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_5" + op: "MatMul" + input: "filter_type_0/add_7" + input: "filter_type_0/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_8_grad/Shape" + input: "gradients/filter_type_0/add_8_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_8" + op: "Add" + input: "filter_type_0/MatMul_5" + input: "filter_type_0/bias_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_4" + op: "Tanh" + input: "filter_type_0/add_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_10_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_10" + op: "Reshape" + input: "filter_type_0/Tanh_4" + input: "filter_type_0/Reshape_10/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_9_grad/Shape" + input: "gradients/filter_type_0/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_9" + op: "Add" + input: "filter_type_0/concat_4" + input: "filter_type_0/Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/add_9" + input: "filter_type_0/add_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_5_grad/mod" + input: "gradients/filter_type_0/concat_5_grad/ShapeN" + input: "gradients/filter_type_0/concat_5_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_5" + op: "ConcatV2" + input: "filter_type_0/add_9" + input: "filter_type_0/add_9" + input: "filter_type_0/concat_5/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_6" + op: "MatMul" + input: "filter_type_0/add_9" + input: "filter_type_0/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_10_grad/Shape" + input: "gradients/filter_type_0/add_10_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_10" + op: "Add" + input: "filter_type_0/MatMul_6" + input: "filter_type_0/bias_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_5" + op: "Tanh" + input: "filter_type_0/add_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_11_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_11" + op: "Reshape" + input: "filter_type_0/Tanh_5" + input: "filter_type_0/Reshape_11/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_11_grad/Shape" + input: "gradients/filter_type_0/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_11" + op: "Add" + input: "filter_type_0/concat_5" + input: "filter_type_0/Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_12_grad/Shape" + op: "Shape" + input: "filter_type_0/add_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_12" + op: "Reshape" + input: "filter_type_0/add_11" + input: "filter_type_0/Reshape_12/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_7" + op: "BatchMatMul" + input: "filter_type_0/Reshape_13" + input: "filter_type_0/Reshape_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_12_grad/Shape_1" + op: "Shape" + input: "filter_type_0/MatMul_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Slice" + op: "Slice" + input: "Reshape_7" + input: "filter_type_0/Slice/begin" + input: "filter_type_0/Slice/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/sub" + op: "Sub" + input: "gradients/filter_type_0/Slice_grad/Shape_1" + input: "gradients/filter_type_0/Slice_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_0/Slice_grad/sub" + input: "filter_type_0/Slice/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/Slice_grad/sub_1" + input: "gradients/filter_type_0/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_0/Slice_grad/Reshape" + input: "gradients/filter_type_0/Slice_grad/Reshape_1" + input: "gradients/filter_type_0/Slice_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_6_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_6" + op: "Reshape" + input: "filter_type_0/Slice" + input: "filter_type_0/Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape" + op: "Reshape" + input: "filter_type_0/Slice" + input: "filter_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Slice_1" + op: "Slice" + input: "filter_type_0/Reshape" + input: "filter_type_0/Slice_1/begin" + input: "filter_type_0/Slice_1/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/sub" + op: "Sub" + input: "gradients/filter_type_0/Slice_1_grad/Shape_1" + input: "gradients/filter_type_0/Slice_1_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_0/Slice_1_grad/sub" + input: "filter_type_0/Slice_1/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/Slice_1_grad/sub_1" + input: "gradients/filter_type_0/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_0/Slice_1_grad/Reshape" + input: "gradients/filter_type_0/Slice_1_grad/Reshape_1" + input: "gradients/filter_type_0/Slice_1_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_1_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_1" + op: "Reshape" + input: "filter_type_0/Slice_1" + input: "filter_type_0/Reshape_1/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/Reshape_1" + input: "filter_type_0/Reshape_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_grad/mod" + input: "gradients/filter_type_0/concat_grad/ShapeN" + input: "gradients/filter_type_0/concat_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat" + op: "ConcatV2" + input: "filter_type_0/Reshape_1" + input: "filter_type_0/Reshape_1" + input: "filter_type_0/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Shape" + op: "Shape" + input: "filter_type_0/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul" + op: "MatMul" + input: "filter_type_0/Reshape_1" + input: "filter_type_0/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_grad/Shape" + input: "gradients/filter_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add" + op: "Add" + input: "filter_type_0/MatMul" + input: "filter_type_0/bias_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh" + op: "Tanh" + input: "filter_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_2_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_2" + op: "Reshape" + input: "filter_type_0/Tanh" + input: "filter_type_0/Reshape_2/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_1_grad/Shape" + input: "gradients/filter_type_0/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_1" + op: "Add" + input: "filter_type_0/concat" + input: "filter_type_0/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/add_1" + input: "filter_type_0/add_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_1_grad/mod" + input: "gradients/filter_type_0/concat_1_grad/ShapeN" + input: "gradients/filter_type_0/concat_1_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_1" + op: "ConcatV2" + input: "filter_type_0/add_1" + input: "filter_type_0/add_1" + input: "filter_type_0/concat_1/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_1" + op: "MatMul" + input: "filter_type_0/add_1" + input: "filter_type_0/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_2_grad/Shape" + input: "gradients/filter_type_0/add_2_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_2" + op: "Add" + input: "filter_type_0/MatMul_1" + input: "filter_type_0/bias_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_1" + op: "Tanh" + input: "filter_type_0/add_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_3_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_3" + op: "Reshape" + input: "filter_type_0/Tanh_1" + input: "filter_type_0/Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_3_grad/Shape" + input: "gradients/filter_type_0/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_3" + op: "Add" + input: "filter_type_0/concat_1" + input: "filter_type_0/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/add_3" + input: "filter_type_0/add_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_2_grad/mod" + input: "gradients/filter_type_0/concat_2_grad/ShapeN" + input: "gradients/filter_type_0/concat_2_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_2" + op: "ConcatV2" + input: "filter_type_0/add_3" + input: "filter_type_0/add_3" + input: "filter_type_0/concat_2/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_2" + op: "MatMul" + input: "filter_type_0/add_3" + input: "filter_type_0/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_4_grad/Shape" + input: "gradients/filter_type_0/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_4" + op: "Add" + input: "filter_type_0/MatMul_2" + input: "filter_type_0/bias_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_2" + op: "Tanh" + input: "filter_type_0/add_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_4_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_4" + op: "Reshape" + input: "filter_type_0/Tanh_2" + input: "filter_type_0/Reshape_4/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_5_grad/Shape" + input: "gradients/filter_type_0/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_5" + op: "Add" + input: "filter_type_0/concat_2" + input: "filter_type_0/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_5_grad/Shape" + op: "Shape" + input: "filter_type_0/add_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_5" + op: "Reshape" + input: "filter_type_0/add_5" + input: "filter_type_0/Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_3" + op: "BatchMatMul" + input: "filter_type_0/Reshape_6" + input: "filter_type_0/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_12_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_12_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_12_grad/Shape" + input: "gradients/filter_type_0/add_12_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_12" + op: "Add" + input: "filter_type_0/MatMul_3" + input: "filter_type_0/MatMul_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Shape" + op: "Shape" + input: "filter_type_0/add_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/mul_grad/Shape" + input: "gradients/filter_type_0/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/mul" + op: "Mul" + input: "filter_type_0/add_12" + input: "filter_type_0/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/Shape_1" + op: "Shape" + input: "filter_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Slice_4" + op: "Slice" + input: "filter_type_0/mul" + input: "filter_type_0/Slice_4/begin" + input: "filter_type_0/Slice_4/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/sub" + op: "Sub" + input: "gradients/filter_type_0/Slice_4_grad/Shape_1" + input: "gradients/filter_type_0/Slice_4_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_0/Slice_4_grad/sub" + input: "filter_type_0/Slice_4/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/Slice_4_grad/sub_1" + input: "gradients/filter_type_0/Slice_4_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_0/Slice_4_grad/Reshape" + input: "gradients/filter_type_0/Slice_4_grad/Reshape_1" + input: "gradients/filter_type_0/Slice_4_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_8" + op: "BatchMatMul" + input: "filter_type_0/mul" + input: "filter_type_0/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/Reshape_14_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_14" + op: "Reshape" + input: "filter_type_0/MatMul_8" + input: "filter_type_0/Reshape_14/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_8_grad/Shape" + op: "Shape" + input: "filter_type_0/Reshape_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_8" + op: "Reshape" + input: "filter_type_0/Reshape_14" + input: "Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/ShapeN" + op: "ShapeN" + input: "Reshape_8" + input: "Reshape_11" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/concat_grad/mod" + input: "gradients/concat_grad/ShapeN" + input: "gradients/concat_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "concat" + op: "ConcatV2" + input: "Reshape_8" + input: "Reshape_11" + input: "concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "o_descriptor" + op: "Identity" + input: "concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_13_grad/Shape" + op: "Shape" + input: "o_descriptor" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_13" + op: "Reshape" + input: "o_descriptor" + input: "Reshape_13/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/Shape_1" + op: "Shape" + input: "Reshape_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/Shape_1" + op: "Shape" + input: "Reshape_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_5" + op: "Shape" + input: "Reshape_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_24" + op: "StridedSlice" + input: "Shape_5" + input: "strided_slice_24/stack" + input: "strided_slice_24/stack_1" + input: "strided_slice_24/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_17/shape" + op: "Pack" + input: "strided_slice_24" + input: "strided_slice_25" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_3" + op: "Slice" + input: "Reshape_13" + input: "Slice_3/begin" + input: "Slice_3/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Slice_3_grad/Shape" + op: "Shape" + input: "Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/sub" + op: "Sub" + input: "gradients/Slice_3_grad/Shape_1" + input: "gradients/Slice_3_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/sub_1" + op: "Sub" + input: "gradients/Slice_3_grad/sub" + input: "Slice_3/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/Slice_3_grad/sub_1" + input: "gradients/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/concat" + op: "ConcatV2" + input: "gradients/Slice_3_grad/Reshape" + input: "gradients/Slice_3_grad/Reshape_1" + input: "gradients/Slice_3_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_16_grad/Shape" + op: "Shape" + input: "Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_16" + op: "Reshape" + input: "Slice_3" + input: "Reshape_16/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_1/MatMul" + op: "MatMul" + input: "Reshape_16" + input: "layer_0_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/Shape" + op: "Shape" + input: "layer_0_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_0_type_1/add_grad/Shape" + input: "gradients/layer_0_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_1/add" + op: "Add" + input: "layer_0_type_1/MatMul" + input: "layer_0_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_0_type_1/Tanh" + op: "Tanh" + input: "layer_0_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_0_type_1/Reshape_grad/Shape" + op: "Shape" + input: "layer_0_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_1/Reshape" + op: "Reshape" + input: "layer_0_type_1/Tanh" + input: "layer_0_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_6_grad/Shape" + op: "Shape" + input: "layer_0_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/MatMul" + op: "MatMul" + input: "layer_0_type_1/Reshape" + input: "layer_1_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/Shape" + op: "Shape" + input: "layer_1_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_1_type_1/add_grad/Shape" + input: "gradients/layer_1_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/add" + op: "Add" + input: "layer_1_type_1/MatMul" + input: "layer_1_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_1_type_1/Tanh" + op: "Tanh" + input: "layer_1_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_1/Reshape_grad/Shape" + op: "Shape" + input: "layer_1_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/Reshape" + op: "Reshape" + input: "layer_1_type_1/Tanh" + input: "layer_1_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Shape" + op: "Shape" + input: "layer_1_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_1_type_1/mul_grad/Shape" + input: "gradients/layer_1_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/mul" + op: "Mul" + input: "layer_1_type_1/Reshape" + input: "layer_1_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_6_grad/Shape_1" + op: "Shape" + input: "layer_1_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_6_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/add_6_grad/Shape" + input: "gradients/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_6" + op: "Add" + input: "layer_0_type_1/Reshape" + input: "layer_1_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_7_grad/Shape" + op: "Shape" + input: "add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/MatMul" + op: "MatMul" + input: "add_6" + input: "layer_2_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/Shape" + op: "Shape" + input: "layer_2_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_2_type_1/add_grad/Shape" + input: "gradients/layer_2_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/add" + op: "Add" + input: "layer_2_type_1/MatMul" + input: "layer_2_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_1/Tanh" + op: "Tanh" + input: "layer_2_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_1/Reshape_grad/Shape" + op: "Shape" + input: "layer_2_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/Reshape" + op: "Reshape" + input: "layer_2_type_1/Tanh" + input: "layer_2_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Shape" + op: "Shape" + input: "layer_2_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_2_type_1/mul_grad/Shape" + input: "gradients/layer_2_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/mul" + op: "Mul" + input: "layer_2_type_1/Reshape" + input: "layer_2_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_7_grad/Shape_1" + op: "Shape" + input: "layer_2_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_7_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/add_7_grad/Shape" + input: "gradients/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_7" + op: "Add" + input: "add_6" + input: "layer_2_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "final_layer_type_1/MatMul" + op: "MatMul" + input: "add_7" + input: "final_layer_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/Shape" + op: "Shape" + input: "final_layer_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/final_layer_type_1/add_grad/Shape" + input: "gradients/final_layer_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "final_layer_type_1/add" + op: "Add" + input: "final_layer_type_1/MatMul" + input: "final_layer_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_17_grad/Shape" + op: "Shape" + input: "final_layer_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_17" + op: "Reshape" + input: "final_layer_type_1/add" + input: "Reshape_17/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_4" + op: "Shape" + input: "Reshape_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_20" + op: "StridedSlice" + input: "Shape_4" + input: "strided_slice_20/stack" + input: "strided_slice_20/stack_1" + input: "strided_slice_20/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_15/shape" + op: "Pack" + input: "strided_slice_20" + input: "strided_slice_21" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_2" + op: "Slice" + input: "Reshape_13" + input: "Slice_2/begin" + input: "Slice_2/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Slice_2_grad/Shape" + op: "Shape" + input: "Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/sub" + op: "Sub" + input: "gradients/Slice_2_grad/Shape_1" + input: "gradients/Slice_2_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/sub_1" + op: "Sub" + input: "gradients/Slice_2_grad/sub" + input: "Slice_2/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/Reshape_1" + op: "Reshape" + input: "gradients/Slice_2_grad/sub_1" + input: "gradients/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/concat" + op: "ConcatV2" + input: "gradients/Slice_2_grad/Reshape" + input: "gradients/Slice_2_grad/Reshape_1" + input: "gradients/Slice_2_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_14_grad/Shape" + op: "Shape" + input: "Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_14" + op: "Reshape" + input: "Slice_2" + input: "Reshape_14/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_0/MatMul" + op: "MatMul" + input: "Reshape_14" + input: "layer_0_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/Shape" + op: "Shape" + input: "layer_0_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_0_type_0/add_grad/Shape" + input: "gradients/layer_0_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_0/add" + op: "Add" + input: "layer_0_type_0/MatMul" + input: "layer_0_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_0_type_0/Tanh" + op: "Tanh" + input: "layer_0_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_0_type_0/Reshape_grad/Shape" + op: "Shape" + input: "layer_0_type_0/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_0/Reshape" + op: "Reshape" + input: "layer_0_type_0/Tanh" + input: "layer_0_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_3_grad/Shape" + op: "Shape" + input: "layer_0_type_0/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/MatMul" + op: "MatMul" + input: "layer_0_type_0/Reshape" + input: "layer_1_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/Shape" + op: "Shape" + input: "layer_1_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_1_type_0/add_grad/Shape" + input: "gradients/layer_1_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/add" + op: "Add" + input: "layer_1_type_0/MatMul" + input: "layer_1_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_1_type_0/Tanh" + op: "Tanh" + input: "layer_1_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_0/Reshape_grad/Shape" + op: "Shape" + input: "layer_1_type_0/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/Reshape" + op: "Reshape" + input: "layer_1_type_0/Tanh" + input: "layer_1_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Shape" + op: "Shape" + input: "layer_1_type_0/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_1_type_0/mul_grad/Shape" + input: "gradients/layer_1_type_0/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/mul" + op: "Mul" + input: "layer_1_type_0/Reshape" + input: "layer_1_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_3_grad/Shape_1" + op: "Shape" + input: "layer_1_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_3_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/add_3_grad/Shape" + input: "gradients/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_3" + op: "Add" + input: "layer_0_type_0/Reshape" + input: "layer_1_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_4_grad/Shape" + op: "Shape" + input: "add_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/MatMul" + op: "MatMul" + input: "add_3" + input: "layer_2_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/Shape" + op: "Shape" + input: "layer_2_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_2_type_0/add_grad/Shape" + input: "gradients/layer_2_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/add" + op: "Add" + input: "layer_2_type_0/MatMul" + input: "layer_2_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_0/Tanh" + op: "Tanh" + input: "layer_2_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_0/Reshape_grad/Shape" + op: "Shape" + input: "layer_2_type_0/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/Reshape" + op: "Reshape" + input: "layer_2_type_0/Tanh" + input: "layer_2_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Shape" + op: "Shape" + input: "layer_2_type_0/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_2_type_0/mul_grad/Shape" + input: "gradients/layer_2_type_0/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/mul" + op: "Mul" + input: "layer_2_type_0/Reshape" + input: "layer_2_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_4_grad/Shape_1" + op: "Shape" + input: "layer_2_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_4_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/add_4_grad/Shape" + input: "gradients/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_4" + op: "Add" + input: "add_3" + input: "layer_2_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "final_layer_type_0/MatMul" + op: "MatMul" + input: "add_4" + input: "final_layer_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/Shape" + op: "Shape" + input: "final_layer_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/final_layer_type_0/add_grad/Shape" + input: "gradients/final_layer_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "final_layer_type_0/add" + op: "Add" + input: "final_layer_type_0/MatMul" + input: "final_layer_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_15_grad/Shape" + op: "Shape" + input: "final_layer_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_15" + op: "Reshape" + input: "final_layer_type_0/add" + input: "Reshape_15/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_2_grad/ShapeN" + op: "ShapeN" + input: "Reshape_15" + input: "Reshape_17" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_2_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/concat_2_grad/mod" + input: "gradients/concat_2_grad/ShapeN" + input: "gradients/concat_2_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "concat_2" + op: "ConcatV2" + input: "Reshape_15" + input: "Reshape_17" + input: "concat_2/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_18_grad/Shape" + op: "Shape" + input: "concat_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_18" + op: "Reshape" + input: "concat_2" + input: "Reshape_18/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Shape" + op: "Shape" + input: "Reshape_18" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Fill" + op: "Fill" + input: "gradients/Shape" + input: "gradients/grad_ys_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "index_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_18_grad/Reshape" + op: "Reshape" + input: "gradients/Fill" + input: "gradients/Reshape_18_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_2_grad/Slice_1" + op: "Slice" + input: "gradients/Reshape_18_grad/Reshape" + input: "gradients/concat_2_grad/ConcatOffset:1" + input: "gradients/concat_2_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_17_grad/Reshape" + op: "Reshape" + input: "gradients/concat_2_grad/Slice_1" + input: "gradients/Reshape_17_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/Reshape_17_grad/Reshape" + input: "gradients/final_layer_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/final_layer_type_1/add_grad/Sum" + input: "gradients/final_layer_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/final_layer_type_1/add_grad/Reshape" + input: "final_layer_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_7_grad/Sum_1" + op: "Sum" + input: "gradients/final_layer_type_1/MatMul_grad/MatMul" + input: "gradients/add_7_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_7_grad/Reshape_1" + op: "Reshape" + input: "gradients/add_7_grad/Sum_1" + input: "gradients/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients/add_7_grad/Reshape_1" + input: "layer_2_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients/layer_2_type_1/mul_grad/Mul" + input: "gradients/layer_2_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_1/mul_grad/Sum" + input: "gradients/layer_2_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_1/mul_grad/Reshape" + input: "gradients/layer_2_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_2_type_1/Tanh" + input: "gradients/layer_2_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/layer_2_type_1/Tanh_grad/TanhGrad" + input: "gradients/layer_2_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_1/add_grad/Sum" + input: "gradients/layer_2_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_2_type_1/add_grad/Reshape" + input: "layer_2_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_7_grad/Sum" + op: "Sum" + input: "gradients/final_layer_type_1/MatMul_grad/MatMul" + input: "gradients/add_7_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_7_grad/Reshape" + op: "Reshape" + input: "gradients/add_7_grad/Sum" + input: "gradients/add_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_1" + op: "AddN" + input: "gradients/add_7_grad/Reshape" + input: "gradients/layer_2_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/add_7_grad/Reshape" + } + } + } +} +node { + name: "gradients/add_6_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_1" + input: "gradients/add_6_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_6_grad/Reshape_1" + op: "Reshape" + input: "gradients/add_6_grad/Sum_1" + input: "gradients/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients/add_6_grad/Reshape_1" + input: "layer_1_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients/layer_1_type_1/mul_grad/Mul" + input: "gradients/layer_1_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_1/mul_grad/Sum" + input: "gradients/layer_1_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_1/mul_grad/Reshape" + input: "gradients/layer_1_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_1_type_1/Tanh" + input: "gradients/layer_1_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/layer_1_type_1/Tanh_grad/TanhGrad" + input: "gradients/layer_1_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_1/add_grad/Sum" + input: "gradients/layer_1_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_1_type_1/add_grad/Reshape" + input: "layer_1_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_6_grad/Sum" + op: "Sum" + input: "gradients/AddN_1" + input: "gradients/add_6_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_6_grad/Reshape" + op: "Reshape" + input: "gradients/add_6_grad/Sum" + input: "gradients/add_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_3" + op: "AddN" + input: "gradients/add_6_grad/Reshape" + input: "gradients/layer_1_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/add_6_grad/Reshape" + } + } + } +} +node { + name: "gradients/layer_0_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_3" + input: "gradients/layer_0_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_0_type_1/Tanh" + input: "gradients/layer_0_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/layer_0_type_1/Tanh_grad/TanhGrad" + input: "gradients/layer_0_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_0_type_1/add_grad/Sum" + input: "gradients/layer_0_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_0_type_1/add_grad/Reshape" + input: "layer_0_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/Reshape_16_grad/Reshape" + op: "Reshape" + input: "gradients/layer_0_type_1/MatMul_grad/MatMul" + input: "gradients/Reshape_16_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/Pad" + op: "Pad" + input: "gradients/Reshape_16_grad/Reshape" + input: "gradients/Slice_3_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_2_grad/Slice" + op: "Slice" + input: "gradients/Reshape_18_grad/Reshape" + input: "gradients/concat_2_grad/ConcatOffset" + input: "gradients/concat_2_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_15_grad/Reshape" + op: "Reshape" + input: "gradients/concat_2_grad/Slice" + input: "gradients/Reshape_15_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/Reshape_15_grad/Reshape" + input: "gradients/final_layer_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/final_layer_type_0/add_grad/Sum" + input: "gradients/final_layer_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/final_layer_type_0/add_grad/Reshape" + input: "final_layer_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_4_grad/Sum_1" + op: "Sum" + input: "gradients/final_layer_type_0/MatMul_grad/MatMul" + input: "gradients/add_4_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_4_grad/Reshape_1" + op: "Reshape" + input: "gradients/add_4_grad/Sum_1" + input: "gradients/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Mul" + op: "Mul" + input: "gradients/add_4_grad/Reshape_1" + input: "layer_2_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Sum" + op: "Sum" + input: "gradients/layer_2_type_0/mul_grad/Mul" + input: "gradients/layer_2_type_0/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_0/mul_grad/Sum" + input: "gradients/layer_2_type_0/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_0/mul_grad/Reshape" + input: "gradients/layer_2_type_0/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_2_type_0/Tanh" + input: "gradients/layer_2_type_0/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/layer_2_type_0/Tanh_grad/TanhGrad" + input: "gradients/layer_2_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_0/add_grad/Sum" + input: "gradients/layer_2_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_2_type_0/add_grad/Reshape" + input: "layer_2_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_4_grad/Sum" + op: "Sum" + input: "gradients/final_layer_type_0/MatMul_grad/MatMul" + input: "gradients/add_4_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_4_grad/Reshape" + op: "Reshape" + input: "gradients/add_4_grad/Sum" + input: "gradients/add_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN" + op: "AddN" + input: "gradients/add_4_grad/Reshape" + input: "gradients/layer_2_type_0/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/add_4_grad/Reshape" + } + } + } +} +node { + name: "gradients/add_3_grad/Sum_1" + op: "Sum" + input: "gradients/AddN" + input: "gradients/add_3_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/add_3_grad/Sum_1" + input: "gradients/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Mul" + op: "Mul" + input: "gradients/add_3_grad/Reshape_1" + input: "layer_1_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Sum" + op: "Sum" + input: "gradients/layer_1_type_0/mul_grad/Mul" + input: "gradients/layer_1_type_0/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_0/mul_grad/Sum" + input: "gradients/layer_1_type_0/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_0/mul_grad/Reshape" + input: "gradients/layer_1_type_0/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_1_type_0/Tanh" + input: "gradients/layer_1_type_0/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/layer_1_type_0/Tanh_grad/TanhGrad" + input: "gradients/layer_1_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_0/add_grad/Sum" + input: "gradients/layer_1_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_1_type_0/add_grad/Reshape" + input: "layer_1_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_3_grad/Sum" + op: "Sum" + input: "gradients/AddN" + input: "gradients/add_3_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_3_grad/Reshape" + op: "Reshape" + input: "gradients/add_3_grad/Sum" + input: "gradients/add_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_2" + op: "AddN" + input: "gradients/add_3_grad/Reshape" + input: "gradients/layer_1_type_0/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/add_3_grad/Reshape" + } + } + } +} +node { + name: "gradients/layer_0_type_0/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_2" + input: "gradients/layer_0_type_0/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_0/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_0_type_0/Tanh" + input: "gradients/layer_0_type_0/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/layer_0_type_0/Tanh_grad/TanhGrad" + input: "gradients/layer_0_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_0_type_0/add_grad/Sum" + input: "gradients/layer_0_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_0_type_0/add_grad/Reshape" + input: "layer_0_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/Reshape_14_grad/Reshape" + op: "Reshape" + input: "gradients/layer_0_type_0/MatMul_grad/MatMul" + input: "gradients/Reshape_14_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/Pad" + op: "Pad" + input: "gradients/Reshape_14_grad/Reshape" + input: "gradients/Slice_2_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_4" + op: "AddN" + input: "gradients/Slice_2_grad/Pad" + input: "gradients/Slice_3_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/Slice_2_grad/Pad" + } + } + } +} +node { + name: "gradients/Reshape_13_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_4" + input: "gradients/Reshape_13_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/Slice_1" + op: "Slice" + input: "gradients/Reshape_13_grad/Reshape" + input: "gradients/concat_grad/ConcatOffset:1" + input: "gradients/concat_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_11_grad/Reshape" + op: "Reshape" + input: "gradients/concat_grad/Slice_1" + input: "gradients/Reshape_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_14_grad/Reshape" + op: "Reshape" + input: "gradients/Reshape_11_grad/Reshape" + input: "gradients/filter_type_1/Reshape_14_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_8_grad/MatMul_1" + op: "BatchMatMul" + input: "filter_type_1/mul" + input: "gradients/filter_type_1/Reshape_14_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/Pad" + op: "Pad" + input: "gradients/filter_type_1/MatMul_8_grad/MatMul_1" + input: "gradients/filter_type_1/Slice_4_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_8_grad/MatMul" + op: "BatchMatMul" + input: "filter_type_1/Slice_4" + input: "gradients/filter_type_1/Reshape_14_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/AddN_6" + op: "AddN" + input: "gradients/filter_type_1/MatMul_8_grad/MatMul" + input: "gradients/filter_type_1/Slice_4_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/MatMul_8_grad/MatMul" + } + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients/AddN_6" + input: "filter_type_1/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/mul_grad/Mul" + input: "gradients/filter_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/mul_grad/Sum" + input: "gradients/filter_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_12_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_1/mul_grad/Reshape" + input: "gradients/filter_type_1/add_12_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_12_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_12_grad/Sum_1" + input: "gradients/filter_type_1/add_12_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_7_grad/MatMul_1" + op: "BatchMatMul" + input: "filter_type_1/Reshape_13" + input: "gradients/filter_type_1/add_12_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/Reshape_12_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/MatMul_7_grad/MatMul_1" + input: "gradients/filter_type_1/Reshape_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_1/Reshape_12_grad/Reshape" + input: "gradients/filter_type_1/add_11_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_11_grad/Sum_1" + input: "gradients/filter_type_1/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_11_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_11_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_5_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_5" + input: "gradients/filter_type_1/Reshape_11_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_5_grad/TanhGrad" + input: "gradients/filter_type_1/add_10_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_10_grad/Sum" + input: "gradients/filter_type_1/add_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_6_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_10_grad/Reshape" + input: "filter_type_1/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Reshape_12_grad/Reshape" + input: "gradients/filter_type_1/add_11_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_11_grad/Sum" + input: "gradients/filter_type_1/add_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_11_grad/Reshape" + input: "gradients/filter_type_1/concat_5_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_5_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_11_grad/Reshape" + input: "gradients/filter_type_1/concat_5_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_5_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_10" + op: "AddN" + input: "gradients/filter_type_1/concat_5_grad/Slice" + input: "gradients/filter_type_1/concat_5_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_6_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_5_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_10" + input: "gradients/filter_type_1/add_9_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_9_grad/Sum_1" + input: "gradients/filter_type_1/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_10_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_9_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_4_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_4" + input: "gradients/filter_type_1/Reshape_10_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_4_grad/TanhGrad" + input: "gradients/filter_type_1/add_8_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_8_grad/Sum" + input: "gradients/filter_type_1/add_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_5_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_8_grad/Reshape" + input: "filter_type_1/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Sum" + op: "Sum" + input: "gradients/AddN_10" + input: "gradients/filter_type_1/add_9_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_9_grad/Sum" + input: "gradients/filter_type_1/add_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_9_grad/Reshape" + input: "gradients/filter_type_1/concat_4_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_4_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_9_grad/Reshape" + input: "gradients/filter_type_1/concat_4_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_4_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_14" + op: "AddN" + input: "gradients/filter_type_1/concat_4_grad/Slice" + input: "gradients/filter_type_1/concat_4_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_5_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_4_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_14" + input: "gradients/filter_type_1/add_7_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_7_grad/Sum_1" + input: "gradients/filter_type_1/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_9_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_7_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_3_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_3" + input: "gradients/filter_type_1/Reshape_9_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_3_grad/TanhGrad" + input: "gradients/filter_type_1/add_6_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_6_grad/Sum" + input: "gradients/filter_type_1/add_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_4_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_6_grad/Reshape" + input: "filter_type_1/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Sum" + op: "Sum" + input: "gradients/AddN_14" + input: "gradients/filter_type_1/add_7_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_7_grad/Sum" + input: "gradients/filter_type_1/add_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_7_grad/Reshape" + input: "gradients/filter_type_1/concat_3_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_3_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_7_grad/Reshape" + input: "gradients/filter_type_1/concat_3_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_3_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_18" + op: "AddN" + input: "gradients/filter_type_1/concat_3_grad/Slice" + input: "gradients/filter_type_1/concat_3_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_4_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_3_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/Reshape_8_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_18" + input: "gradients/filter_type_1/Reshape_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/Pad" + op: "Pad" + input: "gradients/filter_type_1/Reshape_8_grad/Reshape" + input: "gradients/filter_type_1/Slice_3_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_7_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/Slice_3_grad/Pad" + input: "gradients/filter_type_1/Reshape_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_7_grad/MatMul" + op: "BatchMatMul" + input: "filter_type_1/Reshape_12" + input: "gradients/filter_type_1/add_12_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/Reshape_13_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/MatMul_7_grad/MatMul" + input: "gradients/filter_type_1/Reshape_13_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_22" + op: "AddN" + input: "gradients/filter_type_1/Reshape_13_grad/Reshape" + input: "gradients/filter_type_1/Reshape_7_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Reshape_13_grad/Reshape" + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/Pad" + op: "Pad" + input: "gradients/AddN_22" + input: "gradients/filter_type_1/Slice_2_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_12_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/mul_grad/Reshape" + input: "gradients/filter_type_1/add_12_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_12_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_12_grad/Sum" + input: "gradients/filter_type_1/add_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_3_grad/MatMul_1" + op: "BatchMatMul" + input: "filter_type_1/Reshape_6" + input: "gradients/filter_type_1/add_12_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/Reshape_5_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/MatMul_3_grad/MatMul_1" + input: "gradients/filter_type_1/Reshape_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_1/Reshape_5_grad/Reshape" + input: "gradients/filter_type_1/add_5_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_5_grad/Sum_1" + input: "gradients/filter_type_1/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_4_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_5_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_2_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_2" + input: "gradients/filter_type_1/Reshape_4_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_2_grad/TanhGrad" + input: "gradients/filter_type_1/add_4_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_4_grad/Sum" + input: "gradients/filter_type_1/add_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_2_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_4_grad/Reshape" + input: "filter_type_1/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Reshape_5_grad/Reshape" + input: "gradients/filter_type_1/add_5_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_5_grad/Sum" + input: "gradients/filter_type_1/add_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_5_grad/Reshape" + input: "gradients/filter_type_1/concat_2_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_2_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_5_grad/Reshape" + input: "gradients/filter_type_1/concat_2_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_2_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_9" + op: "AddN" + input: "gradients/filter_type_1/concat_2_grad/Slice" + input: "gradients/filter_type_1/concat_2_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_2_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_2_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_9" + input: "gradients/filter_type_1/add_3_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_3_grad/Sum_1" + input: "gradients/filter_type_1/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_3_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_3_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_1_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_1" + input: "gradients/filter_type_1/Reshape_3_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_1_grad/TanhGrad" + input: "gradients/filter_type_1/add_2_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_2_grad/Sum" + input: "gradients/filter_type_1/add_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_1_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_2_grad/Reshape" + input: "filter_type_1/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Sum" + op: "Sum" + input: "gradients/AddN_9" + input: "gradients/filter_type_1/add_3_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_3_grad/Sum" + input: "gradients/filter_type_1/add_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_3_grad/Reshape" + input: "gradients/filter_type_1/concat_1_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_1_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_3_grad/Reshape" + input: "gradients/filter_type_1/concat_1_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_1_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_13" + op: "AddN" + input: "gradients/filter_type_1/concat_1_grad/Slice" + input: "gradients/filter_type_1/concat_1_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_1_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_1_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_13" + input: "gradients/filter_type_1/add_1_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_1_grad/Sum_1" + input: "gradients/filter_type_1/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_2_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_1_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh" + input: "gradients/filter_type_1/Reshape_2_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_grad/TanhGrad" + input: "gradients/filter_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_grad/Sum" + input: "gradients/filter_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_grad/Reshape" + input: "filter_type_1/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Sum" + op: "Sum" + input: "gradients/AddN_13" + input: "gradients/filter_type_1/add_1_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_1_grad/Sum" + input: "gradients/filter_type_1/add_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_1_grad/Reshape" + input: "gradients/filter_type_1/concat_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_1_grad/Reshape" + input: "gradients/filter_type_1/concat_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_17" + op: "AddN" + input: "gradients/filter_type_1/concat_grad/Slice" + input: "gradients/filter_type_1/concat_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/Reshape_1_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_17" + input: "gradients/filter_type_1/Reshape_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Pad" + op: "Pad" + input: "gradients/filter_type_1/Reshape_1_grad/Reshape" + input: "gradients/filter_type_1/Slice_1_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/Slice_1_grad/Pad" + input: "gradients/filter_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_3_grad/MatMul" + op: "BatchMatMul" + input: "filter_type_1/Reshape_5" + input: "gradients/filter_type_1/add_12_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/Reshape_6_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/MatMul_3_grad/MatMul" + input: "gradients/filter_type_1/Reshape_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_21" + op: "AddN" + input: "gradients/filter_type_1/Reshape_6_grad/Reshape" + input: "gradients/filter_type_1/Reshape_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Reshape_6_grad/Reshape" + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Pad" + op: "Pad" + input: "gradients/AddN_21" + input: "gradients/filter_type_1/Slice_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_24" + op: "AddN" + input: "gradients/filter_type_1/Slice_grad/Pad" + input: "gradients/filter_type_1/Slice_2_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Slice_grad/Pad" + } + } + } +} +node { + name: "gradients/Reshape_10_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_24" + input: "gradients/Reshape_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/Pad" + op: "Pad" + input: "gradients/Reshape_10_grad/Reshape" + input: "gradients/Slice_1_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/Slice" + op: "Slice" + input: "gradients/Reshape_13_grad/Reshape" + input: "gradients/concat_grad/ConcatOffset" + input: "gradients/concat_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_8_grad/Reshape" + op: "Reshape" + input: "gradients/concat_grad/Slice" + input: "gradients/Reshape_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_14_grad/Reshape" + op: "Reshape" + input: "gradients/Reshape_8_grad/Reshape" + input: "gradients/filter_type_0/Reshape_14_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_8_grad/MatMul_1" + op: "BatchMatMul" + input: "filter_type_0/mul" + input: "gradients/filter_type_0/Reshape_14_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/Pad" + op: "Pad" + input: "gradients/filter_type_0/MatMul_8_grad/MatMul_1" + input: "gradients/filter_type_0/Slice_4_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_8_grad/MatMul" + op: "BatchMatMul" + input: "filter_type_0/Slice_4" + input: "gradients/filter_type_0/Reshape_14_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/AddN_5" + op: "AddN" + input: "gradients/filter_type_0/MatMul_8_grad/MatMul" + input: "gradients/filter_type_0/Slice_4_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/MatMul_8_grad/MatMul" + } + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Mul" + op: "Mul" + input: "gradients/AddN_5" + input: "filter_type_0/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/mul_grad/Mul" + input: "gradients/filter_type_0/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/mul_grad/Sum" + input: "gradients/filter_type_0/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_12_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_0/mul_grad/Reshape" + input: "gradients/filter_type_0/add_12_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_12_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_12_grad/Sum_1" + input: "gradients/filter_type_0/add_12_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_7_grad/MatMul_1" + op: "BatchMatMul" + input: "filter_type_0/Reshape_13" + input: "gradients/filter_type_0/add_12_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/Reshape_12_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/MatMul_7_grad/MatMul_1" + input: "gradients/filter_type_0/Reshape_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_0/Reshape_12_grad/Reshape" + input: "gradients/filter_type_0/add_11_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_11_grad/Sum_1" + input: "gradients/filter_type_0/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_11_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_11_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_5_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_5" + input: "gradients/filter_type_0/Reshape_11_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_5_grad/TanhGrad" + input: "gradients/filter_type_0/add_10_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_10_grad/Sum" + input: "gradients/filter_type_0/add_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_6_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_10_grad/Reshape" + input: "filter_type_0/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Reshape_12_grad/Reshape" + input: "gradients/filter_type_0/add_11_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_11_grad/Sum" + input: "gradients/filter_type_0/add_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_11_grad/Reshape" + input: "gradients/filter_type_0/concat_5_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_5_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_11_grad/Reshape" + input: "gradients/filter_type_0/concat_5_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_5_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_8" + op: "AddN" + input: "gradients/filter_type_0/concat_5_grad/Slice" + input: "gradients/filter_type_0/concat_5_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_6_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_5_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_8" + input: "gradients/filter_type_0/add_9_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_9_grad/Sum_1" + input: "gradients/filter_type_0/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_10_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_9_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_4_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_4" + input: "gradients/filter_type_0/Reshape_10_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_4_grad/TanhGrad" + input: "gradients/filter_type_0/add_8_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_8_grad/Sum" + input: "gradients/filter_type_0/add_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_5_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_8_grad/Reshape" + input: "filter_type_0/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Sum" + op: "Sum" + input: "gradients/AddN_8" + input: "gradients/filter_type_0/add_9_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_9_grad/Sum" + input: "gradients/filter_type_0/add_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_9_grad/Reshape" + input: "gradients/filter_type_0/concat_4_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_4_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_9_grad/Reshape" + input: "gradients/filter_type_0/concat_4_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_4_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_12" + op: "AddN" + input: "gradients/filter_type_0/concat_4_grad/Slice" + input: "gradients/filter_type_0/concat_4_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_5_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_4_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_12" + input: "gradients/filter_type_0/add_7_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_7_grad/Sum_1" + input: "gradients/filter_type_0/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_9_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_7_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_3_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_3" + input: "gradients/filter_type_0/Reshape_9_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_3_grad/TanhGrad" + input: "gradients/filter_type_0/add_6_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_6_grad/Sum" + input: "gradients/filter_type_0/add_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_4_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_6_grad/Reshape" + input: "filter_type_0/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Sum" + op: "Sum" + input: "gradients/AddN_12" + input: "gradients/filter_type_0/add_7_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_7_grad/Sum" + input: "gradients/filter_type_0/add_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_7_grad/Reshape" + input: "gradients/filter_type_0/concat_3_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_3_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_7_grad/Reshape" + input: "gradients/filter_type_0/concat_3_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_3_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_16" + op: "AddN" + input: "gradients/filter_type_0/concat_3_grad/Slice" + input: "gradients/filter_type_0/concat_3_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_4_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_3_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/Reshape_8_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_16" + input: "gradients/filter_type_0/Reshape_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/Pad" + op: "Pad" + input: "gradients/filter_type_0/Reshape_8_grad/Reshape" + input: "gradients/filter_type_0/Slice_3_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_7_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/Slice_3_grad/Pad" + input: "gradients/filter_type_0/Reshape_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_7_grad/MatMul" + op: "BatchMatMul" + input: "filter_type_0/Reshape_12" + input: "gradients/filter_type_0/add_12_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/Reshape_13_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/MatMul_7_grad/MatMul" + input: "gradients/filter_type_0/Reshape_13_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_20" + op: "AddN" + input: "gradients/filter_type_0/Reshape_13_grad/Reshape" + input: "gradients/filter_type_0/Reshape_7_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Reshape_13_grad/Reshape" + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/Pad" + op: "Pad" + input: "gradients/AddN_20" + input: "gradients/filter_type_0/Slice_2_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_12_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/mul_grad/Reshape" + input: "gradients/filter_type_0/add_12_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_12_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_12_grad/Sum" + input: "gradients/filter_type_0/add_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_3_grad/MatMul_1" + op: "BatchMatMul" + input: "filter_type_0/Reshape_6" + input: "gradients/filter_type_0/add_12_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/Reshape_5_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/MatMul_3_grad/MatMul_1" + input: "gradients/filter_type_0/Reshape_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_0/Reshape_5_grad/Reshape" + input: "gradients/filter_type_0/add_5_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_5_grad/Sum_1" + input: "gradients/filter_type_0/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_4_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_5_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_2_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_2" + input: "gradients/filter_type_0/Reshape_4_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_2_grad/TanhGrad" + input: "gradients/filter_type_0/add_4_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_4_grad/Sum" + input: "gradients/filter_type_0/add_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_2_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_4_grad/Reshape" + input: "filter_type_0/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Reshape_5_grad/Reshape" + input: "gradients/filter_type_0/add_5_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_5_grad/Sum" + input: "gradients/filter_type_0/add_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_5_grad/Reshape" + input: "gradients/filter_type_0/concat_2_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_2_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_5_grad/Reshape" + input: "gradients/filter_type_0/concat_2_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_2_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_7" + op: "AddN" + input: "gradients/filter_type_0/concat_2_grad/Slice" + input: "gradients/filter_type_0/concat_2_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_2_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_2_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_7" + input: "gradients/filter_type_0/add_3_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_3_grad/Sum_1" + input: "gradients/filter_type_0/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_3_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_3_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_1_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_1" + input: "gradients/filter_type_0/Reshape_3_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_1_grad/TanhGrad" + input: "gradients/filter_type_0/add_2_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_2_grad/Sum" + input: "gradients/filter_type_0/add_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_1_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_2_grad/Reshape" + input: "filter_type_0/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Sum" + op: "Sum" + input: "gradients/AddN_7" + input: "gradients/filter_type_0/add_3_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_3_grad/Sum" + input: "gradients/filter_type_0/add_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_3_grad/Reshape" + input: "gradients/filter_type_0/concat_1_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_1_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_3_grad/Reshape" + input: "gradients/filter_type_0/concat_1_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_1_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_11" + op: "AddN" + input: "gradients/filter_type_0/concat_1_grad/Slice" + input: "gradients/filter_type_0/concat_1_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_1_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_1_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_11" + input: "gradients/filter_type_0/add_1_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_1_grad/Sum_1" + input: "gradients/filter_type_0/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_2_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_1_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh" + input: "gradients/filter_type_0/Reshape_2_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_grad/TanhGrad" + input: "gradients/filter_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_grad/Sum" + input: "gradients/filter_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_grad/Reshape" + input: "filter_type_0/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Sum" + op: "Sum" + input: "gradients/AddN_11" + input: "gradients/filter_type_0/add_1_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_1_grad/Sum" + input: "gradients/filter_type_0/add_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_1_grad/Reshape" + input: "gradients/filter_type_0/concat_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_1_grad/Reshape" + input: "gradients/filter_type_0/concat_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_15" + op: "AddN" + input: "gradients/filter_type_0/concat_grad/Slice" + input: "gradients/filter_type_0/concat_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/Reshape_1_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_15" + input: "gradients/filter_type_0/Reshape_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Pad" + op: "Pad" + input: "gradients/filter_type_0/Reshape_1_grad/Reshape" + input: "gradients/filter_type_0/Slice_1_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/Slice_1_grad/Pad" + input: "gradients/filter_type_0/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_3_grad/MatMul" + op: "BatchMatMul" + input: "filter_type_0/Reshape_5" + input: "gradients/filter_type_0/add_12_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/Reshape_6_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/MatMul_3_grad/MatMul" + input: "gradients/filter_type_0/Reshape_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_19" + op: "AddN" + input: "gradients/filter_type_0/Reshape_6_grad/Reshape" + input: "gradients/filter_type_0/Reshape_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Reshape_6_grad/Reshape" + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Pad" + op: "Pad" + input: "gradients/AddN_19" + input: "gradients/filter_type_0/Slice_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_23" + op: "AddN" + input: "gradients/filter_type_0/Slice_grad/Pad" + input: "gradients/filter_type_0/Slice_2_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Slice_grad/Pad" + } + } + } +} +node { + name: "gradients/Reshape_7_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_23" + input: "gradients/Reshape_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/Pad" + op: "Pad" + input: "gradients/Reshape_7_grad/Reshape" + input: "gradients/Slice_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_25" + op: "AddN" + input: "gradients/Slice_grad/Pad" + input: "gradients/Slice_1_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/Slice_grad/Pad" + } + } + } +} +node { + name: "gradients/Reshape_6_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_25" + input: "gradients/Reshape_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_19" + op: "Reshape" + input: "gradients/Reshape_6_grad/Reshape" + input: "Reshape_19/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "ProdVirialSeA" + op: "ProdVirialSeA" + input: "Reshape_19" + input: "o_rmat_deriv" + input: "o_rij" + input: "o_nlist" + input: "t_natoms" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "n_a_sel" + value { + i: 138 + } + } + attr { + key: "n_r_sel" + value { + i: 0 + } + } +} +node { + name: "o_atom_virial" + op: "Reshape" + input: "ProdVirialSeA:1" + input: "o_atom_virial/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_virial" + op: "Reshape" + input: "ProdVirialSeA" + input: "o_virial/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "ProdForceSeA" + op: "ProdForceSeA" + input: "Reshape_19" + input: "o_rmat_deriv" + input: "o_nlist" + input: "t_natoms" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "n_a_sel" + value { + i: 138 + } + } + attr { + key: "n_r_sel" + value { + i: 0 + } + } +} +node { + name: "o_force" + op: "Reshape" + input: "ProdForceSeA" + input: "o_force/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_atom_energy" + op: "Reshape" + input: "Reshape_18" + input: "o_atom_energy/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_energy" + op: "Sum" + input: "o_atom_energy" + input: "o_energy/reduction_indices" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +library { +} diff --git a/source/tests/test_deepdipole.py b/source/tests/test_deepdipole.py new file mode 100644 index 0000000000..2d7881e554 --- /dev/null +++ b/source/tests/test_deepdipole.py @@ -0,0 +1,63 @@ +import os,sys,platform,shutil,dpdata +import numpy as np +import unittest + +from infer.convert2pb import convert_pbtxt_to_pb +from deepmd import DeepDipole +from common import tests_path + +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +if GLOBAL_NP_FLOAT_PRECISION == np.float32 : + default_places = 4 +else : + default_places = 10 + +class TestDeepDipolePBC(unittest.TestCase) : + def setUp(self): + convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deepdipole.pbtxt")), "deepdipole.pb") + self.dp = DeepDipole("deepdipole.pb") + self.coords = np.array([12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56]) + self.atype = [0, 1, 1, 0, 1, 1] + self.box = np.array([13., 0., 0., 0., 13., 0., 0., 0., 13.]) + self.expected_d = np.array([-9.274180565967479195e-01,2.698028341272042496e+00,2.521268387140979117e-01,2.927260638453461628e+00,-8.571926301526779923e-01,1.667785136187720063e+00]) + + def tearDown(self): + os.remove("deepdipole.pb") + + def test_attrs(self): + self.assertEqual(self.dp.get_ntypes(), 2) + self.assertAlmostEqual(self.dp.get_rcut(), 4.0, places = default_places) + self.assertEqual(self.dp.get_type_map(), ['O', 'H']) + self.assertEqual(self.dp.get_sel_type(), [0]) + + def test_1frame_atm(self): + dd = self.dp.eval(self.coords, self.box, self.atype) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + nsel = 2 + self.assertEqual(dd.shape, (nframes,nsel,3)) + # check values + for ii in range(dd.size): + self.assertAlmostEqual(dd.reshape([-1])[ii], self.expected_d.reshape([-1])[ii], places = default_places) + + def test_2frame_atm(self): + coords2 = np.concatenate((self.coords, self.coords)) + box2 = np.concatenate((self.box, self.box)) + dd = self.dp.eval(coords2, box2, self.atype) + # check shape of the returns + nframes = 2 + natoms = len(self.atype) + nsel = 2 + self.assertEqual(dd.shape, (nframes,nsel,3)) + # check values + expected_d = np.concatenate((self.expected_d, self.expected_d)) + for ii in range(dd.size): + self.assertAlmostEqual(dd.reshape([-1])[ii], expected_d.reshape([-1])[ii], places = default_places) + + diff --git a/source/tests/test_deeppolar.py b/source/tests/test_deeppolar.py new file mode 100644 index 0000000000..434214ac6c --- /dev/null +++ b/source/tests/test_deeppolar.py @@ -0,0 +1,63 @@ +import os,sys,platform,shutil,dpdata +import numpy as np +import unittest + +from infer.convert2pb import convert_pbtxt_to_pb +from deepmd import DeepPolar +from common import tests_path + +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +if GLOBAL_NP_FLOAT_PRECISION == np.float32 : + default_places = 4 +else : + default_places = 10 + +class TestDeepPolarPBC(unittest.TestCase) : + def setUp(self): + convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppolar.pbtxt")), "deeppolar.pb") + self.dp = DeepPolar("deeppolar.pb") + self.coords = np.array([12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56]) + self.atype = [0, 1, 1, 0, 1, 1] + self.box = np.array([13., 0., 0., 0., 13., 0., 0., 0., 13.]) + self.expected_d = np.array([1.061407927405987051e-01,-3.569013342133873778e-01,-2.862108976089940138e-02,-3.569013342133875444e-01,1.304367268874677244e+00,1.037647501453442256e-01,-2.862108976089940138e-02,1.037647501453441284e-01,8.100521520762453409e-03,1.236797829492216616e+00,-3.717307430531632262e-01,7.371515676976750919e-01,-3.717307430531630041e-01,1.127222682121889058e-01,-2.239181552775717510e-01,7.371515676976746478e-01,-2.239181552775717787e-01,4.448255365635306879e-01]) + + def tearDown(self): + os.remove("deeppolar.pb") + + def test_attrs(self): + self.assertEqual(self.dp.get_ntypes(), 2) + self.assertAlmostEqual(self.dp.get_rcut(), 6.0, places = default_places) + self.assertEqual(self.dp.get_type_map(), ['O', 'H']) + self.assertEqual(self.dp.get_sel_type(), [0]) + + def test_1frame_atm(self): + dd = self.dp.eval(self.coords, self.box, self.atype) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + nsel = 2 + self.assertEqual(dd.shape, (nframes,nsel,9)) + # check values + for ii in range(dd.size): + self.assertAlmostEqual(dd.reshape([-1])[ii], self.expected_d.reshape([-1])[ii], places = default_places) + + def test_2frame_atm(self): + coords2 = np.concatenate((self.coords, self.coords)) + box2 = np.concatenate((self.box, self.box)) + dd = self.dp.eval(coords2, box2, self.atype) + # check shape of the returns + nframes = 2 + natoms = len(self.atype) + nsel = 2 + self.assertEqual(dd.shape, (nframes,nsel,9)) + # check values + expected_d = np.concatenate((self.expected_d, self.expected_d)) + for ii in range(dd.size): + self.assertAlmostEqual(dd.reshape([-1])[ii], expected_d.reshape([-1])[ii], places = default_places) + + diff --git a/source/tests/test_deeppot.py b/source/tests/test_deeppot.py new file mode 100644 index 0000000000..f758b609c0 --- /dev/null +++ b/source/tests/test_deeppot.py @@ -0,0 +1,266 @@ +import os,sys,platform,shutil,dpdata +import numpy as np +import unittest + +from infer.convert2pb import convert_pbtxt_to_pb +from deepmd import DeepPot +from common import tests_path + +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +if GLOBAL_NP_FLOAT_PRECISION == np.float32 : + default_places = 4 +else : + default_places = 10 + +class TestDeepPotPBC(unittest.TestCase) : + def setUp(self): + convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot.pbtxt")), "deeppot.pb") + self.dp = DeepPot("deeppot.pb") + self.coords = np.array([12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56]) + self.atype = [0, 1, 1, 0, 1, 1] + self.box = np.array([13., 0., 0., 0., 13., 0., 0., 0., 13.]) + self.expected_e = np.array([-9.275780747115504710e+01,-1.863501786584258468e+02,-1.863392472863538103e+02,-9.279281325486221021e+01,-1.863671545232153903e+02,-1.863619822847602165e+02]) + self.expected_f = np.array([-3.034045420701179663e-01,8.405844663871177014e-01,7.696947487118485642e-02,7.662001266663505117e-01,-1.880601391333554251e-01,-6.183333871091722944e-01,-5.036172391059643427e-01,-6.529525836149027151e-01,5.432962643022043459e-01,6.382357912332115024e-01,-1.748518296794561167e-01,3.457363524891907125e-01,1.286482986991941552e-03,3.757251165286925043e-01,-5.972588700887541124e-01,-5.987006197104716154e-01,-2.004450304880958100e-01,2.495901655353461868e-01]) + self.expected_v = np.array([-2.912234126853306959e-01,-3.800610846612756388e-02,2.776624987489437202e-01,-5.053761003913598976e-02,-3.152373041953385746e-01,1.060894290092162379e-01,2.826389131596073745e-01,1.039129970665329250e-01,-2.584378792325942586e-01,-3.121722367954994914e-01,8.483275876786681990e-02,2.524662342344257682e-01,4.142176771106586414e-02,-3.820285230785245428e-02,-2.727311173065460545e-02,2.668859789777112135e-01,-6.448243569420382404e-02,-2.121731470426218846e-01,-8.624335220278558922e-02,-1.809695356746038597e-01,1.529875294531883312e-01,-1.283658185172031341e-01,-1.992682279795223999e-01,1.409924999632362341e-01,1.398322735274434292e-01,1.804318474574856390e-01,-1.470309318999652726e-01,-2.593983661598450730e-01,-4.236536279233147489e-02,3.386387920184946720e-02,-4.174017537818433543e-02,-1.003500282164128260e-01,1.525690815194478966e-01,3.398976109910181037e-02,1.522253908435125536e-01,-2.349125581341701963e-01,9.515545977581392825e-04,-1.643218849228543846e-02,1.993234765412972564e-02,6.027265332209678569e-04,-9.563256398907417355e-02,1.510815124001868293e-01,-7.738094816888557714e-03,1.502832772532304295e-01,-2.380965783745832010e-01,-2.309456719810296654e-01,-6.666961081213038098e-02,7.955566551234216632e-02,-8.099093777937517447e-02,-3.386641099800401927e-02,4.447884755740908608e-02,1.008593228579038742e-01,4.556718179228393811e-02,-6.078081273849572641e-02]) + + def tearDown(self): + os.remove("deeppot.pb") + + def test_attrs(self): + self.assertEqual(self.dp.get_ntypes(), 2) + self.assertAlmostEqual(self.dp.get_rcut(), 6.0, places = default_places) + self.assertEqual(self.dp.get_type_map(), ['O', 'H']) + self.assertEqual(self.dp.get_dim_fparam(), 0) + self.assertEqual(self.dp.get_dim_aparam(), 0) + + def test_1frame(self): + ee, ff, vv = self.dp.eval(self.coords, self.box, self.atype, atomic = False) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + def test_1frame_atm(self): + ee, ff, vv, ae, av = self.dp.eval(self.coords, self.box, self.atype, atomic = True) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + self.assertEqual(ae.shape, (nframes,natoms,1)) + self.assertEqual(av.shape, (nframes,natoms,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + for ii in range(ae.size): + self.assertAlmostEqual(ae.reshape([-1])[ii], self.expected_e.reshape([-1])[ii], places = default_places) + for ii in range(av.size): + self.assertAlmostEqual(av.reshape([-1])[ii], self.expected_v.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + + def test_2frame_atm(self): + coords2 = np.concatenate((self.coords, self.coords)) + box2 = np.concatenate((self.box, self.box)) + ee, ff, vv, ae, av = self.dp.eval(coords2, box2, self.atype, atomic = True) + # check shape of the returns + nframes = 2 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + self.assertEqual(ae.shape, (nframes,natoms,1)) + self.assertEqual(av.shape, (nframes,natoms,9)) + # check values + expected_f = np.concatenate((self.expected_f, self.expected_f), axis = 0) + expected_e = np.concatenate((self.expected_e, self.expected_e), axis = 0) + expected_v = np.concatenate((self.expected_v, self.expected_v), axis = 0) + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], expected_f.reshape([-1])[ii], places = default_places) + for ii in range(ae.size): + self.assertAlmostEqual(ae.reshape([-1])[ii], expected_e.reshape([-1])[ii], places = default_places) + for ii in range(av.size): + self.assertAlmostEqual(av.reshape([-1])[ii], expected_v.reshape([-1])[ii], places = default_places) + expected_se = np.sum(expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + +class TestDeepPotNoPBC(unittest.TestCase) : + def setUp(self): + convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot.pbtxt")), "deeppot.pb") + self.dp = DeepPot("deeppot.pb") + self.coords = np.array([12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56]) + self.atype = [0, 1, 1, 0, 1, 1] + self.box = None + self.expected_e = np.array([-9.255934839310273787e+01,-1.863253376736990106e+02,-1.857237299341402945e+02,-9.279308539717486326e+01,-1.863708105823244239e+02,-1.863635196514972563e+02]) + self.expected_f = np.array([-2.161037360255332107e+00,9.052994347015581589e-01,1.635379623977007979e+00,2.161037360255332107e+00,-9.052994347015581589e-01,-1.635379623977007979e+00,-1.167128117249453811e-02,1.371975700096064992e-03,-1.575265180249604477e-03,6.226508593971802341e-01,-1.816734122009256991e-01,3.561766019664774907e-01,-1.406075393906316626e-02,3.789140061530929526e-01,-6.018777878642909140e-01,-5.969188242856223736e-01,-1.986125696522633155e-01,2.472764510780630642e-01]) + self.expected_v = np.array([-7.042445481792056761e-01,2.950213647777754078e-01,5.329418202437231633e-01,2.950213647777752968e-01,-1.235900311906896754e-01,-2.232594111831812944e-01,5.329418202437232743e-01,-2.232594111831813499e-01,-4.033073234276823849e-01,-8.949230984097404917e-01,3.749002169013777030e-01,6.772391014992630298e-01,3.749002169013777586e-01,-1.570527935667933583e-01,-2.837082722496912512e-01,6.772391014992631408e-01,-2.837082722496912512e-01,-5.125052659994422388e-01,4.858210330291591605e-02,-6.902596153269104431e-03,6.682612642430500391e-03,-5.612247004554610057e-03,9.767795567660207592e-04,-9.773758942738038254e-04,5.638322117219018645e-03,-9.483806049779926932e-04,8.493873281881353637e-04,-2.941738570564985666e-01,-4.482529909499673171e-02,4.091569840186781021e-02,-4.509020615859140463e-02,-1.013919988807244071e-01,1.551440772665269030e-01,4.181857726606644232e-02,1.547200233064863484e-01,-2.398213304685777592e-01,-3.218625798524068354e-02,-1.012438450438508421e-02,1.271639330380921855e-02,3.072814938490859779e-03,-9.556241797915024372e-02,1.512251983492413077e-01,-8.277872384009607454e-03,1.505412040827929787e-01,-2.386150620881526407e-01,-2.312295470054945568e-01,-6.631490213524345034e-02,7.932427266386249398e-02,-8.053754366323923053e-02,-3.294595881137418747e-02,4.342495071150231922e-02,1.004599500126941436e-01,4.450400364869536163e-02,-5.951077548033092968e-02]) + + def tearDown(self): + os.remove("deeppot.pb") + + def test_1frame(self): + ee, ff, vv = self.dp.eval(self.coords, self.box, self.atype, atomic = False) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + def test_1frame_atm(self): + ee, ff, vv, ae, av = self.dp.eval(self.coords, self.box, self.atype, atomic = True) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + self.assertEqual(ae.shape, (nframes,natoms,1)) + self.assertEqual(av.shape, (nframes,natoms,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + for ii in range(ae.size): + self.assertAlmostEqual(ae.reshape([-1])[ii], self.expected_e.reshape([-1])[ii], places = default_places) + for ii in range(av.size): + self.assertAlmostEqual(av.reshape([-1])[ii], self.expected_v.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + + def test_2frame_atm(self): + coords2 = np.concatenate((self.coords, self.coords)) + ee, ff, vv, ae, av = self.dp.eval(coords2, self.box, self.atype, atomic = True) + # check shape of the returns + nframes = 2 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + self.assertEqual(ae.shape, (nframes,natoms,1)) + self.assertEqual(av.shape, (nframes,natoms,9)) + # check values + expected_f = np.concatenate((self.expected_f, self.expected_f), axis = 0) + expected_e = np.concatenate((self.expected_e, self.expected_e), axis = 0) + expected_v = np.concatenate((self.expected_v, self.expected_v), axis = 0) + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], expected_f.reshape([-1])[ii], places = default_places) + for ii in range(ae.size): + self.assertAlmostEqual(ae.reshape([-1])[ii], expected_e.reshape([-1])[ii], places = default_places) + for ii in range(av.size): + self.assertAlmostEqual(av.reshape([-1])[ii], expected_v.reshape([-1])[ii], places = default_places) + expected_se = np.sum(expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + +class TestDeepPotLargeBoxNoPBC(unittest.TestCase) : + def setUp(self): + convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot.pbtxt")), "deeppot.pb") + self.dp = DeepPot("deeppot.pb") + self.coords = np.array([12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56]) + self.atype = [0, 1, 1, 0, 1, 1] + self.box = np.array([19., 0., 0., 0., 13., 0., 0., 0., 13.]) + self.expected_e = np.array([-9.255934839310273787e+01,-1.863253376736990106e+02,-1.857237299341402945e+02,-9.279308539717486326e+01,-1.863708105823244239e+02,-1.863635196514972563e+02]) + self.expected_f = np.array([-2.161037360255332107e+00,9.052994347015581589e-01,1.635379623977007979e+00,2.161037360255332107e+00,-9.052994347015581589e-01,-1.635379623977007979e+00,-1.167128117249453811e-02,1.371975700096064992e-03,-1.575265180249604477e-03,6.226508593971802341e-01,-1.816734122009256991e-01,3.561766019664774907e-01,-1.406075393906316626e-02,3.789140061530929526e-01,-6.018777878642909140e-01,-5.969188242856223736e-01,-1.986125696522633155e-01,2.472764510780630642e-01]) + self.expected_v = np.array([-7.042445481792056761e-01,2.950213647777754078e-01,5.329418202437231633e-01,2.950213647777752968e-01,-1.235900311906896754e-01,-2.232594111831812944e-01,5.329418202437232743e-01,-2.232594111831813499e-01,-4.033073234276823849e-01,-8.949230984097404917e-01,3.749002169013777030e-01,6.772391014992630298e-01,3.749002169013777586e-01,-1.570527935667933583e-01,-2.837082722496912512e-01,6.772391014992631408e-01,-2.837082722496912512e-01,-5.125052659994422388e-01,4.858210330291591605e-02,-6.902596153269104431e-03,6.682612642430500391e-03,-5.612247004554610057e-03,9.767795567660207592e-04,-9.773758942738038254e-04,5.638322117219018645e-03,-9.483806049779926932e-04,8.493873281881353637e-04,-2.941738570564985666e-01,-4.482529909499673171e-02,4.091569840186781021e-02,-4.509020615859140463e-02,-1.013919988807244071e-01,1.551440772665269030e-01,4.181857726606644232e-02,1.547200233064863484e-01,-2.398213304685777592e-01,-3.218625798524068354e-02,-1.012438450438508421e-02,1.271639330380921855e-02,3.072814938490859779e-03,-9.556241797915024372e-02,1.512251983492413077e-01,-8.277872384009607454e-03,1.505412040827929787e-01,-2.386150620881526407e-01,-2.312295470054945568e-01,-6.631490213524345034e-02,7.932427266386249398e-02,-8.053754366323923053e-02,-3.294595881137418747e-02,4.342495071150231922e-02,1.004599500126941436e-01,4.450400364869536163e-02,-5.951077548033092968e-02]) + + def tearDown(self): + os.remove("deeppot.pb") + + def test_1frame(self): + ee, ff, vv = self.dp.eval(self.coords, self.box, self.atype, atomic = False) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + def test_1frame_atm(self): + ee, ff, vv, ae, av = self.dp.eval(self.coords, self.box, self.atype, atomic = True) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + self.assertEqual(ae.shape, (nframes,natoms,1)) + self.assertEqual(av.shape, (nframes,natoms,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + for ii in range(ae.size): + self.assertAlmostEqual(ae.reshape([-1])[ii], self.expected_e.reshape([-1])[ii], places = default_places) + for ii in range(av.size): + self.assertAlmostEqual(av.reshape([-1])[ii], self.expected_v.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + From 0364fa5efcd64d219e9bd3d674e38a2a1beb89dc Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 21 Feb 2021 21:14:27 +0800 Subject: [PATCH 186/562] fix bug of wrong test data path --- source/tests/test_data_modifier_shuffle.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/tests/test_data_modifier_shuffle.py b/source/tests/test_data_modifier_shuffle.py index e2e875c544..738d379721 100644 --- a/source/tests/test_data_modifier_shuffle.py +++ b/source/tests/test_data_modifier_shuffle.py @@ -15,7 +15,7 @@ from deepmd.infer.data_modifier import DipoleChargeModifier from deepmd.infer.deep_dipole import DeepDipole -from common import Data, tests_path +from common import Data if GLOBAL_NP_FLOAT_PRECISION == np.float32 : global_default_fv_hh = 1e-2 @@ -63,7 +63,6 @@ def _setUp(self): # init data system systems = j_must_have(jdata['training'], 'systems') - systems = [tests_path / ii for ii in systems] set_pfx = j_must_have(jdata['training'], 'set_prefix') batch_size = j_must_have(jdata['training'], 'batch_size') test_size = j_must_have(jdata['training'], 'numb_test') From 7797058da1f231134562e412d88a09c32ec31536 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 22 Feb 2021 09:33:06 +0800 Subject: [PATCH 187/562] change prints in transform to log --- source/train/transform.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/source/train/transform.py b/source/train/transform.py index 19efd42976..1db29211d3 100644 --- a/source/train/transform.py +++ b/source/train/transform.py @@ -1,6 +1,8 @@ from deepmd.env import tf import re import numpy as np +import logging +log = logging.getLogger(__name__) def convertNumber(number): binary = bin(number).replace("0b", "").zfill(16) @@ -19,11 +21,11 @@ def convertMatrix(matrix, shape): def transform(args): raw_graph = load_graph(args.raw_model) old_graph = load_graph(args.old_model) - print("%d ops in the raw graph\n%d ops in the old graph" %(len(raw_graph.as_graph_def().node),len(old_graph.as_graph_def().node))) + log.debug("%d ops in the raw graph\n%d ops in the old graph" %(len(raw_graph.as_graph_def().node),len(old_graph.as_graph_def().node))) new_graph_def = transform_graph(raw_graph,old_graph) with tf.gfile.GFile(args.output, mode='wb') as f: f.write(new_graph_def.SerializeToString()) - print("the output model is saved in %s" % args.output) + log.debug("the output model is saved in %s" % args.output) def load_graph(graphName): graph_def = tf.GraphDef() @@ -54,7 +56,7 @@ def transform_graph(raw_graph,old_graph): tensor_shape = [dim.size for dim in raw_graph_node[node.name].tensor_shape.dim] old_graph_dtype = precision_dict[old_graph_node[node.name].dtype] raw_graph_dtype = precision_dict[raw_graph_node[node.name].dtype] - print("%s is passed from old graph(%s) to raw graph(%s)" % (node.name, old_graph_dtype[1],raw_graph_dtype[1])) + log.debug("%s is passed from old graph(%s) to raw graph(%s)" % (node.name, old_graph_dtype[1],raw_graph_dtype[1])) if raw_graph_dtype[1] == "float16": if old_graph_dtype[1] == "float64" or old_graph_dtype[1] == "float32": From c475178a98f1b38009577ad25c79f23f60fba389 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 22 Feb 2021 09:34:05 +0800 Subject: [PATCH 188/562] add unittest for transform --- source/tests/infer/deeppot-1.pbtxt | 24313 +++++++++++++++++++++++++++ source/tests/test_transform.py | 69 + 2 files changed, 24382 insertions(+) create mode 100644 source/tests/infer/deeppot-1.pbtxt create mode 100644 source/tests/test_transform.py diff --git a/source/tests/infer/deeppot-1.pbtxt b/source/tests/infer/deeppot-1.pbtxt new file mode 100644 index 0000000000..4ad2deb6ff --- /dev/null +++ b/source/tests/infer/deeppot-1.pbtxt @@ -0,0 +1,24313 @@ +node { + name: "o_atom_virial/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_18/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 9 + } + } + } +} +node { + name: "strided_slice_29/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_29/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_29/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "o_virial/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\t\000\000\000" + } + } + } +} +node { + name: "o_force/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_17/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_28/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_28/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_28/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "Reshape_19/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_16/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 552 + } + } + } +} +node { + name: "strided_slice_27/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_27/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_27/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "gradients/Slice_1_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_1_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_1_grad/stack" + op: "Pack" + input: "gradients/Slice_1_grad/Rank" + input: "gradients/Slice_1_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/Slice_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_grad/stack" + op: "Pack" + input: "gradients/Slice_grad/Rank" + input: "gradients/Slice_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/stack" + op: "Pack" + input: "gradients/filter_type_1/Slice_2_grad/Rank" + input: "gradients/filter_type_1/Slice_2_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/stack" + op: "Pack" + input: "gradients/filter_type_1/Slice_grad/Rank" + input: "gradients/filter_type_1/Slice_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/stack" + op: "Pack" + input: "gradients/filter_type_0/Slice_2_grad/Rank" + input: "gradients/filter_type_0/Slice_2_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/stack" + op: "Pack" + input: "gradients/filter_type_0/Slice_grad/Rank" + input: "gradients/filter_type_0/Slice_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/stack" + op: "Pack" + input: "gradients/filter_type_1/Slice_3_grad/Rank" + input: "gradients/filter_type_1/Slice_3_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/stack" + op: "Pack" + input: "gradients/filter_type_1/Slice_1_grad/Rank" + input: "gradients/filter_type_1/Slice_1_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/stack" + op: "Pack" + input: "gradients/filter_type_0/Slice_3_grad/Rank" + input: "gradients/filter_type_0/Slice_3_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/stack" + op: "Pack" + input: "gradients/filter_type_0/Slice_1_grad/Rank" + input: "gradients/filter_type_0/Slice_1_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + } + } + } + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + } + } + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/stack" + op: "Pack" + input: "gradients/filter_type_1/Slice_4_grad/Rank" + input: "gradients/filter_type_1/Slice_4_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/stack" + op: "Pack" + input: "gradients/filter_type_0/Slice_4_grad/Rank" + input: "gradients/filter_type_0/Slice_4_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/concat_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_3_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_3_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_3_grad/stack" + op: "Pack" + input: "gradients/Slice_3_grad/Rank" + input: "gradients/Slice_3_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/Slice_2_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_2_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_2_grad/stack" + op: "Pack" + input: "gradients/Slice_2_grad/Rank" + input: "gradients/Slice_2_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "gradients/concat_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/grad_ys_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 1.0 + } + } + } +} +node { + name: "o_energy/reduction_indices" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "o_atom_energy/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "strided_slice_26/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_26/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_26/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_18/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: -1 + } + } + } +} +node { + name: "concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/concat_2_grad/mod" + op: "FloorMod" + input: "concat_2/axis" + input: "gradients/concat_2_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_25/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_25/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_25/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_24/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_24/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_24/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "final_layer_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + } + double_val: -186.90367254590808 + } + } + } +} +node { + name: "final_layer_type_1/bias/read" + op: "Identity" + input: "final_layer_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_1/bias" + } + } + } +} +node { + name: "final_layer_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + dim { + size: 1 + } + } + tensor_content: "O\211\200\354\034=\267?\255h\234\256\013\363\300\277\200\207\366P\263+\324\277~\007V(\335\322\267\277\210\0231\326\340\021\347?\327\\\034\224\252\376\301\277" + } + } + } +} +node { + name: "final_layer_type_1/matrix/read" + op: "Identity" + input: "final_layer_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_1/matrix" + } + } + } +} +node { + name: "layer_2_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\006\000\000\000" + } + } + } +} +node { + name: "layer_2_type_1/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\007\232V\370/\353\271?:\243\30520\304\271?\244\240;\033\362 \271?\221\017\300\206\274G\271?\376u\026\231\341\324\271?\031\223~2\235?\271?" + } + } + } +} +node { + name: "layer_2_type_1/idt/read" + op: "Identity" + input: "layer_2_type_1/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_1/idt" + } + } + } +} +node { + name: "layer_2_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "c\021\220}\003\364\316?3\340-\026\013\207\326\277O\t&\330\343\314\352\277]F\034\354\013N\317\277o\202\357&\300\223\376??\257\263J\026\222\327\277" + } + } + } +} +node { + name: "layer_2_type_1/bias/read" + op: "Identity" + input: "layer_2_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_1/bias" + } + } + } +} +node { + name: "layer_2_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + dim { + size: 6 + } + } + tensor_content: "\222\030M\035+\260\261?\036\000Z\326q\324\271\277\2248\353#\343\307\316\277\357{\t\0212\276\261\277\225\317\205\232\301\234\341?/\0132\247\314\010\273\277\177\314\310\374\356\335\272?r\243@\322y\305\337\277\343\232\257\327\374\017\310?\035d\025\331\263\365\313\277F\020\224.S\332\250?\302\030\250\300\211\301\322\277\246\323\306e\016\266\227?\023E\247\224r\002\334?\333\230\210\336\031\376\313?\364\2314%.Q\300\277\004\322O\326\201R\323\277R\354^\242r~\346?\351\246\267v;\247\271\277]p\307N|\366\302?\010\234\2339\242}\311?\322Z\246Y\2773\306?`\330\201\336\010(\257?;\347Zc\263g\272\277\334\030\367\231\200:\277\277{\327\270:B\211\255?\224\277X\177\235\325\203?2\263\216K\027d\343\277\366\273\267\202\201\363\323\277\333\337\261:.\304\302\277\010R\321\312&U\316\277\323*An\017\361\302\277\371\317\206r\225\024\247\277L\356f\275X\213\323\277\374WG\022\377\354\315\277^\331l\010%\331\265\277" + } + } + } +} +node { + name: "layer_2_type_1/matrix/read" + op: "Identity" + input: "layer_2_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_1/matrix" + } + } + } +} +node { + name: "layer_1_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\006\000\000\000" + } + } + } +} +node { + name: "layer_1_type_1/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\177Yv\207;\353\271? \027\231\'5\304\271?D\325\350\237\362 \271?\345Z\260\017\277G\271?\177\325\0063\342\324\271?\232-\262c\237?\271?" + } + } + } +} +node { + name: "layer_1_type_1/idt/read" + op: "Identity" + input: "layer_1_type_1/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_1/idt" + } + } + } +} +node { + name: "layer_1_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "G\230\331\273\2315\317?\'\253\t\222\013\207\326\277\342\274w\316\343\314\352\277a-i\265\014N\317\277kF\337$\300\223\376?L\005(\006\030\222\327\277" + } + } + } +} +node { + name: "layer_1_type_1/bias/read" + op: "Identity" + input: "layer_1_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_1/bias" + } + } + } +} +node { + name: "layer_1_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + dim { + size: 6 + } + } + tensor_content: "(5YJ+\260\261?\240\210\353\024r\324\271\277\225\373{;\343\307\316\277,\2034I2\276\261\277P\252\013\237\301\234\341?\\Q\032\344\314\010\273\277Sn\304\313\357\335\272?\372\241\264\316y\305\337\277\352\346\247\342\374\017\310?h\244\223\317\263\365\313\277!}\345\rS\332\250?W\321\363\302\211\301\322\277R\255\021\353*\266\227?\247\007\223\304s\002\334?f\247\3078\032\376\313?\023\356\375\027-Q\300\277IA\265\350\201R\323\277\016^\036\010s~\346?\327\365\n\314\203\247\271\277\335\366\2160\202\366\302?\274\025\331B\242}\311?b\2211N\3003\306?\232\225\027\353\010(\257?\367\331\032_\243g\272\277\367\020\001\036\210:\277\277\357\226\276\252C\211\255?\t\271\000/\243\325\203?K\306 Q\027d\343\277\273\346\347\216\201\363\323\2770\302\310f-\304\302\277[\223\016\300)U\316\277\370l\323\371\016\361\302\277\023\020\303k\225\024\247\277\211\033\230\250X\213\323\277\220\375i\017\377\354\315\277\330\034\035\246#\331\265\277" + } + } + } +} +node { + name: "layer_1_type_1/matrix/read" + op: "Identity" + input: "layer_1_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_1/matrix" + } + } + } +} +node { + name: "layer_0_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\006\000\000\000" + } + } + } +} +node { + name: "layer_0_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\336\354\337\277\017\364\316?\256\273\3756\022\207\326\277\022BgSr\274\352\277b\335\345\261]\014\317\277\026\253@W\300\223\376?\027\034p\315\034\222\327\277" + } + } + } +} +node { + name: "layer_0_type_1/bias/read" + op: "Identity" + input: "layer_0_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_1/bias" + } + } + } +} +node { + name: "layer_0_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 32 + } + dim { + size: 6 + } + } + tensor_content: "\315\335\227\363\202\256\244?[\'\222\361\020\316\254\277=\026u\014\263=\301\277\273U\210YN\267\243\277~\246\224x\030\345\323?\346w\337\000\221(\256\277\223\371\tb\232k\256?\314\242\\\373\354\300\321\277*I\211?\377q\273?>q\337\222\311\005\277\277x2\254\374\354a\234?\0013\326b\017\341\304\277Uh\316\257\233\214\213?\273T\356\"A\256\317?\271\353%V\303\334\277?\304\t\272`\375\357\261\277(\n\267*\373\250\305\277\363\310\260,\241a\331?\210&\247\261\363\007\254\277\314\377\323\246\367l\265?n\227\\]\007\303\274?\"\253\2763\342\020\271?\313~\021$\250O\242?*\273\272B\251y\256\277l\"\207_\317%\261\277F\306\005\013\243\322\240?:bc\250n\266|?\371\373\375\010\367\303\325\277,\030\373\272\354]\306\277_\365\220\303\234\372\264\277\235\250\377]Q\330\300\277D\347\260\274\377,\265\277\265S\220\346N}\231\277!`h8\330\350\305\277z\235}\272\272\235\300\277\376J.\001UT\250\277N\3145q\315\024\306?\261\016E\236.\277\245?=\227|\206\244\206\214\277$\021\004\033&\217\300\277\360\236\252/\017\342\272\277\224\267X`\000\241\323?\224\014\312\035t\313\311\277\232v\344\266\227n\253\277\253k\311\270\206\232\275?\276\020\222#!\356\267\277\357\023W`e<\314\277\303W\252\206\246;\205\277%7\323S\r\226\236?H\316\014)\313\367\307?\227\013\255\352)\027\254\277\243c\204\211\210g\256\277p\020G\273~\230\322?\246\204\206\252\"\005\240\2776l\350\020\010\362\330\277\255Jv:\014:\266?<\254j\206j@\232?\006\332\337\264G\230\257\277b\032O\235.\307P?\260\316[\333\030\205v?hF\234\213mw\306?\243C\377\027\317\354\214?S\006\376\306\350\013\313\277\231q\327\227Q\265\247?`\346\361\004\\\215\270\277x&!\236\177g\177?g%\370+\376\215\266\277)\375\271\277*.\316?\316\253B\310\030d\241?\344|\232\233\241L\325?\'K\010\363z\362\221\277\272\341Z\350:\243\223?ds\364\232b\364\260\277\277\350\224\214\2227\270\277\261\324\231\252\236\353\304?^\326\'\211\347\351\231?\2317*\032\226\262\317\277\261\030\372\222\200g\313\277\245\201\232Z\031O\314?\307I\016\356\3011\303?l\356\213^Qs\303?\014!};l\377\206?\317(\256_\212I\266\277I\333r\014\340(\277\277}:\220V\r\377\303\277\261\2253\274(\021\330?\273\006g\355\256\253\271?\246\023\301\367\301\036\242?v\224\334\314\362\231\324?\321\223\302y`\037\317?\005|\310\210\023\302\301\277\021\255\016\324\r\006\302\277\031\005h\200\2760\253\277\331h{\244~\026\226?8\204\302G\013\223\241\277@\0346_\016U\304\277\310\316WU\247\272|\277\005\363;\200\220\256\304?\230E\354\332\330\211\312?\222\001\036?P\237\305\277\325\030\317d|%\266\277X\260\225\001(M\307\2775\305L\271\374\021\270?\350g\025\361m\320\244?#\005x:U\272/?*\264B\256\347\023\277\277\2120of\225\355\302?I\006\345\034\325\254\314\277\t/4\333\376\004\271\277ix\273\325b\244\320? {;pW.\306?\224\211\325\356w\223\220?V0\234\264h*\262?\243\036\234\211\220\220\300?G\232\336H\t\230\310\277h\242\277 \375\023\342.\\\300?\253\002\307\322X\353\247\277I\311\033\000\207\214\252\277x\2171C\022u\247\277\225\'\254R\001\t\254\277\2374\221?FL\265?0\275<\357\2238\253\277\031\024V\215sH\271\277\340m\346\n\007\364\250?\020\255\0143\307\357\322\277[\227\241FL\352\266\277\250(0AqL\315\277\307\023.\211\225.\242\277A\033P\336\036m\304?f\363\034A\330\224\311?\361\001\255\235\014\323\316\277K\370\206K\262\313\314?\2168PjOG\200?3\314;\340\363\271\231\277\235\375\312\367\361\227\300?\213v\005\300\312q\252\277\256(\362\374Q\336\206\277\365\253Ie\350s\273\277RI\345r\005t\211?\367\216\277\314l\317\241\277Mn\305\002D\007\314?\265\001\366\034k}\302?\272\002\036\032\326\244\316\277\352\\b\373\206\020\202\277\263*`a\364\246\231\277\277?H\000y\254\217\277jS\365:\034\035\322?\263\276lk\260\200\177?\357\033R[\236\201\320?v#\302<|\276\302?d\257i\376\345\256\254?\027u\330\2328\327\312\277\375\'|\177\3757\317?\032II\303\n\331\240?l\016\304\224R\010\322\277l\270\311\013\003!\272\277\t\356\033\274\216\225\301?*[\355N\216l\324?gy\017\331\364_\240?0\202\236\320\006^\256?U\276.\302\016;\322?L\004BP\366)\265?J\363r\036\221\020\261?&\013\210\237\317\003\324\277\325&\303O\213\263\211?\217e\001\372^E\252?c\357\314\034J?\232\277\326YT|\000\201\302\277\326\207\236h\214\226\277\277\221\276\250\307\344\032\303?\370o\347\240K\363\315?b\345-\026\366\224\257?wB<#r\354D?j\243\002\317#Lv?\023\"\224\215\207_\320\277\350\014\206i`\262\310?k\024\375\344\232\300\312\277\217\017#\013\313>\307?Z\267>\227\347\210\266\277\234\336\327\330O\n\273\277" + } + } + } +} +node { + name: "layer_0_type_1/matrix/read" + op: "Identity" + input: "layer_0_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_1/matrix" + } + } + } +} +node { + name: "Reshape_16/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "Slice_3/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_3/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_15/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_22/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_22/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_22/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "mul_14/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_21/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_21/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_21/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_20/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_20/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_20/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "final_layer_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + } + double_val: -93.33092474310311 + } + } + } +} +node { + name: "final_layer_type_0/bias/read" + op: "Identity" + input: "final_layer_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_0/bias" + } + } + } +} +node { + name: "final_layer_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + dim { + size: 1 + } + } + tensor_content: "\010NQ\276\034=\267?\347\245\005\345\n\363\300\277Yo8\025\261+\324\277\007\225\277E\356\322\267\277\260\223\205e\340\021\347?P\317f\312\251\376\301\277" + } + } + } +} +node { + name: "final_layer_type_0/matrix/read" + op: "Identity" + input: "final_layer_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_0/matrix" + } + } + } +} +node { + name: "layer_2_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\006\000\000\000" + } + } + } +} +node { + name: "layer_2_type_0/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\247\230\005\3306\353\271?\335+\023 \037\304\271?-&\031\254\361 \271?r9(\202\367\312\271?(\323\245M\340\324\271?\274\224\030\036\233?\271?" + } + } + } +} +node { + name: "layer_2_type_0/idt/read" + op: "Identity" + input: "layer_2_type_0/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_0/idt" + } + } + } +} +node { + name: "layer_2_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\233\212\036(\004\364\316?\317Z\300\024\r\207\326\277\314z-\n\344\314\352\277\254\343\037\252N\014\317\277@8i\'\300\223\376?]*\276\323\025\222\327\277" + } + } + } +} +node { + name: "layer_2_type_0/bias/read" + op: "Identity" + input: "layer_2_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_0/bias" + } + } + } +} +node { + name: "layer_2_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + dim { + size: 6 + } + } + tensor_content: "6\236x\364*\260\261?/[\325\255q\324\271\277\237i\321\026\343\307\316\277?\017\r\0072\276\261\277@L\330\230\301\234\341?\334\024\301\200\314\010\273\277\357E]\342\360\335\272?_z\306Ez\305\337\277k\207\330t\374\017\310?H\335\345\017\264\365\313\277\010\325\232\331S\332\250?,_\245+\212\301\322\277\265}b\337\\\266\227? y\204\360n\002\334?\352\017q\221\030\376\313?s\306\034?0Q\300\277\014=\242\233\201R\323\277D\010c\351p~\346?:n\344Dd\247\271\277\231\033\031~\214\366\302?\021<\255\027\243}\311?\266\351m\323\2623\306?t4dK\010(\257?\034h\224\272\235g\272\277\215\027\002\370\201:\277\277G\351\331\353\271?\277\226\264\302*\304\271?\2702\0361\362 \271?\2712a\225\002\313\271?\025q\334\346\340\324\271?Cm\026\024\234?\271?" + } + } + } +} +node { + name: "layer_1_type_0/idt/read" + op: "Identity" + input: "layer_1_type_0/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_0/idt" + } + } + } +} +node { + name: "layer_1_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "\000\345HX\t\364\316?{\323\241\327\016\207\326\277\236t\215\003\344\314\352\277\360\324\3453O\014\317\277\251o\366$\300\223\376?s\203\244\357\025\222\327\277" + } + } + } +} +node { + name: "layer_1_type_0/bias/read" + op: "Identity" + input: "layer_1_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_0/bias" + } + } + } +} +node { + name: "layer_1_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + dim { + size: 6 + } + } + tensor_content: "\276\214r/+\260\261?\215D\020\363q\324\271\277L\372p1\343\307\316\277x5\226M2\276\261\277\241\264:\236\301\234\341?\024\205O\310\314\010\273\277id\2418\361\335\272?\373\036\"@z\305\337\277\353\225\311\177\374\017\310?3\3223\010\264\365\313\277l7\220\264S\332\250?\027\342r#\212\301\322\277-\226:n_\266\227?\356\347\3018o\002\334?\344j\'\305\030\376\313?\326\230\327\253/Q\300\277\216C\351\252\201R\323\277\351f\310\027q~\346?Dr\353U\215\247\271\277*v\357\001\217\366\302?\257\262\303!\243}\311?\361\346\203Z\2703\306?\327:\026\\\010(\257?\221K\226\202\230g\272\277\331\177\252H\212:\277\277\231\256O\023P\211\255?\ti\354_p\325\203?*\335\363)\030d\343\2777\321\306k\201\363\323\277\244\007\243\332,\304\302\277\322\022\026\206)U\316\277^\031FL\016\361\302\277\244\216\365\330\224\024\247\277\347\324\023\356Y\213\323\277t\026U\377\376\354\315\277;n\215w$\331\265\277" + } + } + } +} +node { + name: "layer_1_type_0/matrix/read" + op: "Identity" + input: "layer_1_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_0/matrix" + } + } + } +} +node { + name: "layer_0_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\006\000\000\000" + } + } + } +} +node { + name: "layer_0_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 6 + } + } + tensor_content: "m\"\335\374\014\364\316?J8\030\374\021\207\326\277R\200~Qr\274\352\277\202\246\'d]\014\317\277\332p\\E\300\223\376?\2319\014\205\034\222\327\277" + } + } + } +} +node { + name: "layer_0_type_0/bias/read" + op: "Identity" + input: "layer_0_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_0/bias" + } + } + } +} +node { + name: "layer_0_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 32 + } + dim { + size: 6 + } + } + tensor_content: "\363\276\253\203\257\256\244?<\035\031\t\t\316\254\277\235\337\035\362\262=\301\277\334\320U\304I\267\243\277E\223HY\030\345\323?\211\356\207H\204(\256\277\311\272\337a\274k\256?)bj\356\353\300\321\277\372\302/v\377q\273?7:\316(\307\005\277\277\3622\352\020\353a\234?\342\037\212?\246\"\305\277\033\003O\310\004\215\213?\311\373lsC\256\317?\264\372\021\217\303\334\277?+~\376\303\372\357\261\277\261o\251f\373\250\305\277\322\304\214\347\312@\331?\024c\"^\356\007\254\277\273\3342\021\007m\265?\303\321G\257\007\303\274?\010\244\255\\\350\020\271?D\335lX\247O\242?\000\233\353\214fz\256\277\321A\234_\276%\261\277^\313\227r\253\322\240?5\377\312\022r\266|?7\256yn\366\303\325\277\035Xs\370\354]\306\277!\317\370|\312}\265\2770o\316tJ\330\300\277\202\t;P\373,\265\277fB\006\006N}\231\277\353#\276\365\326\350\305\277\322\372\376\366\272\235\300\277\004\261\333f\356Z\251\277\213\361\357\353\322\024\306?\023s~e8\277\245?x\327\030\263\242\206\214\277d\227:\275$\217\300\277\241D\253\245\017\342\272\277\266\26528%\200\323?h\270\377\346r\313\311\277J\025\205Ptn\253\2777c\360\014\207\232\275?*\227\220g\032\356\267\277\274\3213\222e<\314\277\276g]1\301=\205\277\210\204\023\340A\226\236?Vu\213y\315\367\307?\240\355\324x)\027\254\277pL\rP\203g\256\277\252\335M\235~\230\322?\256\245\246\323\324\013\241\277\230Y\213S\005\362\330\277\337\374\022\036\021:\266?\036\214\034pk@\232?\007\363\271=B\230\257\277\324\255%\035\021\307P?\325\255\266\243\235\234l?\260\353\376\000rw\306?R\334\372\220\372\354\214?\'\001\232\250\350\013\313\277\360XK\211W\265\247?P}\rx\\\215\270\277\377\220hv\216/w?\267\325\034\364\373\215\266\277\006jv\2015.\316?\323\216rv\031d\241?\243\333\206\205\243L\325?\023\203\231x|\362\221\277\373\317\325\311\205\242\223?\253\0212\361_\364\260\277\320\0136\"\2037\270\277\335q\217\323\236\353\304?\364\271\343,\000\352\231?\373_\023M\226\262\317\277\247P\206\345\257g\313\277\321\325d\221\032O\314?\032\"\246\307\3121\303?2j\237\210Qs\303?\257\355\210\033\242\377\206?j\244g\303\212I\266\277H=\311a#)\277\277\246\222\242:\014\377\303\277 \314\021\035.\021\330?>\370~D\257\253\271?\233\t$G\321\036\242?\370\200\203\264\362\231\324?\231\361\361\325I\037\317?\024\341.\367\022\302\301\277\313\231r5\321G\302\277\350sA\227\2750\253\277A-k\215\330\026\226?D\301\006\353\013\223\241\2771\004-\370\021U\304\277\323t?\255\\\271|\277;\263\344}\222\256\304?\024b-\365\330\211\312?\371\3715\031O\237\305\277|7\024\342|%\266\277#\214Q\354&M\307\277f4\352~\014\022\270?\354O(pv\320\244?\000\'7\177\302\272/?\017\227\305@\345\023\277\277X\036\374(\225\355\302?R\337O\331o\356\314\277x\301\213\216\362\004\271\277\210E`\001d\244\320?\307\264\260\214W.\306?\037\tlq\202\223\220?\326\203\275\242\277\206\007\254Z1\\\300?.Gk]X\353\247\277\n\350\376\201\201\214\252\277\224\366:0\023u\247\277i\371gR\343\017\255\277\370\365NxNL\265?\305[\021\361\2108\253\277y\204QPsH\271\277\335\377E\004\r\364\250?\327\034\363O\307\357\322\277\367\336\302\032\316m\267\277\373Bu/pL\315\277lm\025\364i.\242\277\210\031\320\t\037m\304?\264G\366\030\334\224\311?\r\210r\316\014\323\316\277\234\253Q\211\235\313\314?\t\014\336\343\327G\200?\330\260d\000\343\271\231\277\333@\355\022\362\227\300?\231[a\353\305q\252\277[D\261\325U\336\206\277\263\364\354\315\025\367\273\277\275h\3168rt\211?pF\216\330c\317\241\277\"O\320\036D\007\314?\244P\014bl}\302?92\231V\326\244\316\277b\177\373\350\003+\206\277-\230\t,\311\246\231\277 \203dhQ\254\217\277W\234\216I\034\035\322?v\207\023z\334\200\177?\2278\323=\236\201\320?\277\tM\037\305|\302?6r:\347\352\256\254?kE:\323/\327\312\277\230\276g\251\3757\317?\333\307?D\314\237\360\347\210\266\277\ng\3253^\n\273\277" + } + } + } +} +node { + name: "layer_0_type_0/matrix/read" + op: "Identity" + input: "layer_0_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_0/matrix" + } + } + } +} +node { + name: "add_2/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "strided_slice_19/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_19/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_19/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "Reshape_14/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "Slice_2/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_2/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/Slice_2_grad/Reshape" + op: "Reshape" + input: "Slice_2/begin" + input: "gradients/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_13/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_18/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_18/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_18/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "Reshape_13/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_12/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_17/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_17/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_17/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "fitting_attr/daparam" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "fitting_attr/dfparam" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/concat_grad/mod" + op: "FloorMod" + input: "concat/axis" + input: "gradients/concat_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_9/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_13/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_13/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_13/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_12/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_12/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_12/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "filter_type_1/Reshape_14/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_4/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_4/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\000\000\000\000\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/Reshape" + op: "Reshape" + input: "filter_type_1/Slice_4/begin" + input: "gradients/filter_type_1/Slice_4_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/mul/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.007246376811594203 + } + } + } +} +node { + name: "filter_type_1/Reshape_13/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\\\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Reshape_12/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\\\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/concat_5/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_5/axis" + input: "gradients/filter_type_1/concat_5_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_11/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\337\254\364\200\023\364\316?s{-\017\023\207\326\277\330}F\335\345\314\352\277\365\024fth\014\317\277]\327\331\366\206\213\376?\246\372\264}\003\263\327\277\226\361\223A\016\373\326?\245\214yD\253y\373\277" + } + } + } +} +node { + name: "filter_type_1/bias_3_1/read" + op: "Identity" + input: "filter_type_1/bias_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_3_1" + } + } + } +} +node { + name: "filter_type_1/matrix_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\246s\037\274\2773\262?@\0352\305\006X\272\277\206Y\256\'\341\307\316\277}\002\242\003DA\262\277\343\337#\2354\255\341?c\217EBb\214\273\277\241|\031_\370\335\272?k\365l\207\225\244\337\277\270o\302\360\305Q\310?\202d\024\250\265\365\313\277\352`I\177^\332\250?\241\300\220!~\301\322\277\027\037Y\245\215\266\227?Q5J\324l\002\334?\207\235\010\\\343?\314?\247\034\006\255i\017\300\277DI\244K\201R\323\277V`\225\334o~\346?\224&`A\023$\271\277\002\'\263\247\370\264\302?\021|\256\235\247}\311?4\220\374\212\001\362\305?\216\334P\326\231\027\260?\320\035}\271og\272\277\334\025lL\327\266\276\277\340\250\233\316\350\201\254?\335\231ZV\313\361\207?5\200\307v\200t\343\277j\355Ux\177\363\323\277\336\200#\014\005\006\303\277\305\276\216hc\023\316\277\237t\315A\007\361\302\277" + } + } + } +} +node { + name: "filter_type_1/matrix_3_1/read" + op: "Identity" + input: "filter_type_1/matrix_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_3_1" + } + } + } +} +node { + name: "filter_type_1/concat_4/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_4/axis" + input: "gradients/filter_type_1/concat_4_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_10/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "j\364\006h\024\364\316?\367\356\276\271\022\207\326\277\214\321Wy\346\314\352\277a\235\010\3170N\317\277" + } + } + } +} +node { + name: "filter_type_1/bias_2_1/read" + op: "Identity" + input: "filter_type_1/bias_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_2_1" + } + } + } +} +node { + name: "filter_type_1/matrix_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "d9\016,\241\242\271?N\200\005\333\037\223\302\2772\t\2325\272\312\325\277[<\331\267\3302\271\277q\265\267\3212\374\350?\334\334\346\035*m\303\277\236\t\217\353\326\361\302?)I\265*ac\346\277" + } + } + } +} +node { + name: "filter_type_1/matrix_2_1/read" + op: "Identity" + input: "filter_type_1/matrix_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_2_1" + } + } + } +} +node { + name: "filter_type_1/concat_3/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_3/axis" + input: "gradients/filter_type_1/concat_3_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_9/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: ",\346\220w\023\364\316?\245zf\203\367\247\326\277" + } + } + } +} +node { + name: "filter_type_1/bias_1_1/read" + op: "Identity" + input: "filter_type_1/bias_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_1_1" + } + } + } +} +node { + name: "filter_type_1/matrix_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "@\326\271o\334\022\302?\263\243\3771\0377\312\277" + } + } + } +} +node { + name: "filter_type_1/matrix_1_1/read" + op: "Identity" + input: "filter_type_1/matrix_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_1_1" + } + } + } +} +node { + name: "filter_type_1/Reshape_8/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_3/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_3/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/Reshape" + op: "Reshape" + input: "filter_type_1/Slice_3/begin" + input: "gradients/filter_type_1/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_7/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_2/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377p\001\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_2/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\270\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/Reshape" + op: "Reshape" + input: "filter_type_1/Slice_2/begin" + input: "gradients/filter_type_1/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_6/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_2/axis" + input: "gradients/filter_type_1/concat_2_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_4/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\226\321\237\340\r\364\316?\362N\211-\023\207\326\277\343\352\311\335\345\314\352\277\2612\205\022o\014\317\277f\200\320\366\206\213\376?1\004\0229\036\222\327\277\361\373\255:\016\373\326?\205\316wD\253y\373\277" + } + } + } +} +node { + name: "filter_type_1/bias_3_0/read" + op: "Identity" + input: "filter_type_1/bias_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_3_0" + } + } + } +} +node { + name: "filter_type_1/matrix_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "b\353k\207\2773\262?\255\326ky\006X\272\277\037Z\223%\341\307\316\277\246\232\265I\255A\262\277\324\026\355\2344\255\341?\222\034\'\303a\214\273\2777\266\330J\370\335\272?\244S\273\207\225\244\337\277\n\022\305\344\305Q\310?Fb\210x\265\365\313\277d~\324~^\332\250?\013\267\335V\202\301\322\277\203K7\246\215\266\227?\347\244r\017m\002\334?\007{8Y\343?\314?\245\366%\255i\017\300\277n\364eU\201R\323\277\251\n\357\347o~\346?\226\020,@\023$\271\277\035\336\223\036\344\264\302?\323\032\251\235\247}\311?\017C\364\353\001\362\305?\'\235\336\306\231\027\260?\310\274\336\271og\272\277\203\236N~\327\266\276\277Y\001;\323\353\201\254?4\250\331\022\313\361\207?\034\231\r\267\203t\343\277xrIx\177\363\323\277_\036\217b\004\006\303\277H\004azc\023\316\277\327u\340A\007\361\302\277" + } + } + } +} +node { + name: "filter_type_1/matrix_3_0/read" + op: "Identity" + input: "filter_type_1/matrix_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_3_0" + } + } + } +} +node { + name: "filter_type_1/concat_1/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_1/axis" + input: "gradients/filter_type_1/concat_1_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: ">\317@\033\257S\365\311\277" + } + } + } +} +node { + name: "filter_type_0/matrix_1_1/read" + op: "Identity" + input: "filter_type_0/matrix_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_1_1" + } + } + } +} +node { + name: "filter_type_0/Reshape_8/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_3/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_3/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/Reshape" + op: "Reshape" + input: "filter_type_0/Slice_3/begin" + input: "gradients/filter_type_0/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_7/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_2/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377p\001\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_2/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\270\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/Reshape" + op: "Reshape" + input: "filter_type_0/Slice_2/begin" + input: "gradients/filter_type_0/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_6/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat_2/axis" + input: "gradients/filter_type_0/concat_2_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_4/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "#@\032\327\023\364\316?\214\261\251\202\023\207\326\277\250\240\316\000\346\314\352\277\313\245\341$4N\317\277\036H2\360\206\213\376?\361\361+q\036\222\327\277\351\242`a\016\373\326?D\226MP\253y\373\277" + } + } + } +} +node { + name: "filter_type_0/bias_3_0/read" + op: "Identity" + input: "filter_type_0/bias_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_3_0" + } + } + } +} +node { + name: "filter_type_0/matrix_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\003`1\373\2773\262?~)\177\222\005X\272\277\375U\215\231\340\307\316\277\321\007\\\t\037\276\261\277\275\215\347\2514\255\341?K\024\231\312`\214\273\277@\303\213\275\367\335\272?\275\361\265X\225\244\337\277\375\204\245\010\306Q\310?\302$\205\002\265\365\313\277\"\373\262\270`\332\250?T\352F\351\240\240\322\277\016\304:L\217\266\227?_\332L-m\002\334?\001\t\025\003\343?\314?\337\201\310Ni\017\300\277G\354D=\201R\323\277\342G\251\004p~\346?`y,$\022$\271\277\301E\2629\250\366\302?B\316N\322\247}\311?\207\014\326@\002\362\305?\346/N\317\277" + } + } + } +} +node { + name: "filter_type_0/bias_2_0/read" + op: "Identity" + input: "filter_type_0/bias_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_2_0" + } + } + } +} +node { + name: "filter_type_0/matrix_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\342\005\207\031\242\242\271?\340Qpe \223\302\277\\|\033L\272\312\325\277\334\271+\245\3312\271\2772\0210\3612\374\350?\257\341\305\\*m\303\277\371\003\211Q\326\361\302?\031\227\331Qac\346\277" + } + } + } +} +node { + name: "filter_type_0/matrix_2_0/read" + op: "Identity" + input: "filter_type_0/matrix_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_2_0" + } + } + } +} +node { + name: "filter_type_0/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat/axis" + input: "gradients/filter_type_0/concat_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_2/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\267\263\241\301\022\364\316?\303\301\272\223\370\247\326\277" + } + } + } +} +node { + name: "filter_type_0/bias_1_0/read" + op: "Identity" + input: "filter_type_0/bias_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_1_0" + } + } + } +} +node { + name: "filter_type_0/matrix_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\216(\356\252\334\022\302?\340\341\366?V\365\311\277" + } + } + } +} +node { + name: "filter_type_0/matrix_1_0/read" + op: "Identity" + input: "filter_type_0/matrix_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_1_0" + } + } + } +} +node { + name: "filter_type_0/Reshape_1/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_1/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_1/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Reshape" + op: "Reshape" + input: "filter_type_0/Slice_1/begin" + input: "gradients/filter_type_0/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\270\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Reshape" + op: "Reshape" + input: "filter_type_0/Slice/begin" + input: "gradients/filter_type_0/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_7/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377(\002\000\000" + } + } + } +} +node { + name: "Slice/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/Slice_grad/Reshape" + op: "Reshape" + input: "Slice/begin" + input: "gradients/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_3/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 552 + } + } + } +} +node { + name: "strided_slice_5/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_5/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_5/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "Reshape_6/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_2/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 552 + } + } + } +} +node { + name: "strided_slice_4/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_4/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_4/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377(\002\000\000" + } + } + } +} +node { + name: "Reshape_4/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "strided_slice_3/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_3/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_3/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\t\000\000\000" + } + } + } +} +node { + name: "Reshape_2/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_1/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_2/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_2/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_2/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "descrpt_attr/t_std" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 552 + } + } + tensor_content: "q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?q\020!U\250\343\301?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\257\201<\276\276\363\265?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?\r\366\211\314\n\257\277?xP%\374D\237\263?xP%\374D\237\263?xP%\374D\237\263?" + } + } + } +} +node { + name: "descrpt_attr/t_std/read" + op: "Identity" + input: "descrpt_attr/t_std" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@descrpt_attr/t_std" + } + } + } +} +node { + name: "descrpt_attr/t_avg" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 552 + } + } + tensor_content: "\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\316ka/\275\251?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256\271\367\256y\230\250?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "descrpt_attr/t_avg/read" + op: "Identity" + input: "descrpt_attr/t_avg" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@descrpt_attr/t_avg" + } + } + } +} +node { + name: "descrpt_attr/ntypes" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "descrpt_attr/rcut" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 6.0 + } + } + } +} +node { + name: "model_attr/model_type" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "ener" + } + } + } +} +node { + name: "model_attr/tmap" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "O H" + } + } + } +} +node { + name: "t_mesh" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "t_natoms" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: 4 + } + } + } + } +} +node { + name: "strided_slice_29" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_29/stack" + input: "strided_slice_29/stack_1" + input: "strided_slice_29/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_18" + op: "Mul" + input: "mul_18/x" + input: "strided_slice_29" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "o_atom_virial/shape" + op: "Pack" + input: "o_atom_virial/shape/0" + input: "mul_18" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_28" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_28/stack" + input: "strided_slice_28/stack_1" + input: "strided_slice_28/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_17" + op: "Mul" + input: "mul_17/x" + input: "strided_slice_28" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "o_force/shape" + op: "Pack" + input: "o_force/shape/0" + input: "mul_17" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_27" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_27/stack" + input: "strided_slice_27/stack_1" + input: "strided_slice_27/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_16" + op: "Mul" + input: "strided_slice_27" + input: "mul_16/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_19/shape" + op: "Pack" + input: "Reshape_19/shape/0" + input: "mul_16" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_26" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_26/stack" + input: "strided_slice_26/stack_1" + input: "strided_slice_26/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "o_atom_energy/shape" + op: "Pack" + input: "o_atom_energy/shape/0" + input: "strided_slice_26" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_25" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_25/stack" + input: "strided_slice_25/stack_1" + input: "strided_slice_25/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_22" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_22/stack" + input: "strided_slice_22/stack_1" + input: "strided_slice_22/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_15" + op: "Mul" + input: "strided_slice_22" + input: "mul_15/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_3/size" + op: "Pack" + input: "Slice_3/size/0" + input: "mul_15" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_21" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_21/stack" + input: "strided_slice_21/stack_1" + input: "strided_slice_21/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_19" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_19/stack" + input: "strided_slice_19/stack_1" + input: "strided_slice_19/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "add_2" + op: "Add" + input: "add_2/x" + input: "strided_slice_19" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_14" + op: "Mul" + input: "add_2" + input: "mul_14/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_3/begin" + op: "Pack" + input: "Slice_3/begin/0" + input: "mul_14" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/Slice_3_grad/Reshape" + op: "Reshape" + input: "Slice_3/begin" + input: "gradients/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_18" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_18/stack" + input: "strided_slice_18/stack_1" + input: "strided_slice_18/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_13" + op: "Mul" + input: "strided_slice_18" + input: "mul_13/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_2/size" + op: "Pack" + input: "Slice_2/size/0" + input: "mul_13" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_17" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_17/stack" + input: "strided_slice_17/stack_1" + input: "strided_slice_17/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_12" + op: "Mul" + input: "mul_12/x" + input: "strided_slice_17" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_13/shape" + op: "Pack" + input: "Reshape_13/shape/0" + input: "mul_12" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_13" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_13/stack" + input: "strided_slice_13/stack_1" + input: "strided_slice_13/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_9" + op: "Mul" + input: "strided_slice_13" + input: "mul_9/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_11" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_11/stack" + input: "strided_slice_11/stack_1" + input: "strided_slice_11/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_8" + op: "Mul" + input: "strided_slice_11" + input: "mul_8/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_1/size" + op: "Pack" + input: "Slice_1/size/0" + input: "mul_8" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_10" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_10/stack" + input: "strided_slice_10/stack_1" + input: "strided_slice_10/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "add" + op: "Add" + input: "add/x" + input: "strided_slice_10" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_7" + op: "Mul" + input: "add" + input: "mul_7/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_1/begin" + op: "Pack" + input: "Slice_1/begin/0" + input: "mul_7" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/Slice_1_grad/Reshape" + op: "Reshape" + input: "Slice_1/begin" + input: "gradients/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_7" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_7/stack" + input: "strided_slice_7/stack_1" + input: "strided_slice_7/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_4" + op: "Mul" + input: "strided_slice_7" + input: "mul_4/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_5" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_5/stack" + input: "strided_slice_5/stack_1" + input: "strided_slice_5/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_3" + op: "Mul" + input: "strided_slice_5" + input: "mul_3/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice/size" + op: "Pack" + input: "Slice/size/0" + input: "mul_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_4" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_4/stack" + input: "strided_slice_4/stack_1" + input: "strided_slice_4/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_2" + op: "Mul" + input: "mul_2/x" + input: "strided_slice_4" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_6/shape" + op: "Pack" + input: "Reshape_6/shape/0" + input: "mul_2" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_3" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_3/stack" + input: "strided_slice_3/stack_1" + input: "strided_slice_3/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_4/shape" + op: "Pack" + input: "Reshape_4/shape/0" + input: "strided_slice_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_2" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_2/stack" + input: "strided_slice_2/stack_1" + input: "strided_slice_2/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_1" + op: "Mul" + input: "strided_slice_2" + input: "mul_1/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_2/shape" + op: "Pack" + input: "Reshape_2/shape/0" + input: "mul_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "t_type" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_4" + op: "Reshape" + input: "t_type" + input: "Reshape_4/shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "t_coord" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_2" + op: "Reshape" + input: "t_coord" + input: "Reshape_2/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "t_box" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_3" + op: "Reshape" + input: "t_box" + input: "Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "DescrptSeA" + op: "DescrptSeA" + input: "Reshape_2" + input: "Reshape_4" + input: "t_natoms" + input: "Reshape_3" + input: "t_mesh" + input: "descrpt_attr/t_avg/read" + input: "descrpt_attr/t_std/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "rcut_a" + value { + f: -1.0 + } + } + attr { + key: "rcut_r" + value { + f: 6.0 + } + } + attr { + key: "rcut_r_smth" + value { + f: 0.5 + } + } + attr { + key: "sel_a" + value { + list { + i: 46 + i: 92 + } + } + } + attr { + key: "sel_r" + value { + list { + i: 0 + i: 0 + } + } + } +} +node { + name: "o_nlist" + op: "Identity" + input: "DescrptSeA:3" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "o_rij" + op: "Identity" + input: "DescrptSeA:2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "o_rmat_deriv" + op: "Identity" + input: "DescrptSeA:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_5" + op: "Reshape" + input: "DescrptSeA" + input: "Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_rmat" + op: "Identity" + input: "Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_6_grad/Shape" + op: "Shape" + input: "o_rmat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_6" + op: "Reshape" + input: "o_rmat" + input: "Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/Shape_1" + op: "Shape" + input: "Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/Shape_1" + op: "Shape" + input: "Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_2" + op: "Shape" + input: "Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_12" + op: "StridedSlice" + input: "Shape_2" + input: "strided_slice_12/stack" + input: "strided_slice_12/stack_1" + input: "strided_slice_12/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_11/shape" + op: "Pack" + input: "strided_slice_12" + input: "mul_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_1" + op: "Slice" + input: "Reshape_6" + input: "Slice_1/begin" + input: "Slice_1/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Slice_1_grad/Shape" + op: "Shape" + input: "Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/sub" + op: "Sub" + input: "gradients/Slice_1_grad/Shape_1" + input: "gradients/Slice_1_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/sub_1" + op: "Sub" + input: "gradients/Slice_1_grad/sub" + input: "Slice_1/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/Slice_1_grad/sub_1" + input: "gradients/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/concat" + op: "ConcatV2" + input: "gradients/Slice_1_grad/Reshape" + input: "gradients/Slice_1_grad/Reshape_1" + input: "gradients/Slice_1_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_10_grad/Shape" + op: "Shape" + input: "Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_10" + op: "Reshape" + input: "Slice_1" + input: "Reshape_10/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/Shape_1" + op: "Shape" + input: "Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Shape_1" + op: "Shape" + input: "Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Slice_2" + op: "Slice" + input: "Reshape_10" + input: "filter_type_1/Slice_2/begin" + input: "filter_type_1/Slice_2/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/sub" + op: "Sub" + input: "gradients/filter_type_1/Slice_2_grad/Shape_1" + input: "gradients/filter_type_1/Slice_2_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_1/Slice_2_grad/sub" + input: "filter_type_1/Slice_2/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/Slice_2_grad/sub_1" + input: "gradients/filter_type_1/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_1/Slice_2_grad/Reshape" + input: "gradients/filter_type_1/Slice_2_grad/Reshape_1" + input: "gradients/filter_type_1/Slice_2_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_7_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_13_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_13" + op: "Reshape" + input: "filter_type_1/Slice_2" + input: "filter_type_1/Reshape_13/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_7" + op: "Reshape" + input: "filter_type_1/Slice_2" + input: "filter_type_1/Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Slice_3" + op: "Slice" + input: "filter_type_1/Reshape_7" + input: "filter_type_1/Slice_3/begin" + input: "filter_type_1/Slice_3/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/sub" + op: "Sub" + input: "gradients/filter_type_1/Slice_3_grad/Shape_1" + input: "gradients/filter_type_1/Slice_3_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_1/Slice_3_grad/sub" + input: "filter_type_1/Slice_3/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/Slice_3_grad/sub_1" + input: "gradients/filter_type_1/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_1/Slice_3_grad/Reshape" + input: "gradients/filter_type_1/Slice_3_grad/Reshape_1" + input: "gradients/filter_type_1/Slice_3_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_8_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_8" + op: "Reshape" + input: "filter_type_1/Slice_3" + input: "filter_type_1/Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/Reshape_8" + input: "filter_type_1/Reshape_8" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_3_grad/mod" + input: "gradients/filter_type_1/concat_3_grad/ShapeN" + input: "gradients/filter_type_1/concat_3_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_3" + op: "ConcatV2" + input: "filter_type_1/Reshape_8" + input: "filter_type_1/Reshape_8" + input: "filter_type_1/concat_3/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_4" + op: "MatMul" + input: "filter_type_1/Reshape_8" + input: "filter_type_1/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_6_grad/Shape" + input: "gradients/filter_type_1/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_6" + op: "Add" + input: "filter_type_1/MatMul_4" + input: "filter_type_1/bias_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_3" + op: "Tanh" + input: "filter_type_1/add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_9_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_9" + op: "Reshape" + input: "filter_type_1/Tanh_3" + input: "filter_type_1/Reshape_9/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_7_grad/Shape" + input: "gradients/filter_type_1/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_7" + op: "Add" + input: "filter_type_1/concat_3" + input: "filter_type_1/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/add_7" + input: "filter_type_1/add_7" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_4_grad/mod" + input: "gradients/filter_type_1/concat_4_grad/ShapeN" + input: "gradients/filter_type_1/concat_4_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_4" + op: "ConcatV2" + input: "filter_type_1/add_7" + input: "filter_type_1/add_7" + input: "filter_type_1/concat_4/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_5" + op: "MatMul" + input: "filter_type_1/add_7" + input: "filter_type_1/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_8_grad/Shape" + input: "gradients/filter_type_1/add_8_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_8" + op: "Add" + input: "filter_type_1/MatMul_5" + input: "filter_type_1/bias_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_4" + op: "Tanh" + input: "filter_type_1/add_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_10_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_10" + op: "Reshape" + input: "filter_type_1/Tanh_4" + input: "filter_type_1/Reshape_10/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_9_grad/Shape" + input: "gradients/filter_type_1/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_9" + op: "Add" + input: "filter_type_1/concat_4" + input: "filter_type_1/Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/add_9" + input: "filter_type_1/add_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_5_grad/mod" + input: "gradients/filter_type_1/concat_5_grad/ShapeN" + input: "gradients/filter_type_1/concat_5_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_5" + op: "ConcatV2" + input: "filter_type_1/add_9" + input: "filter_type_1/add_9" + input: "filter_type_1/concat_5/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_6" + op: "MatMul" + input: "filter_type_1/add_9" + input: "filter_type_1/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_10_grad/Shape" + input: "gradients/filter_type_1/add_10_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_10" + op: "Add" + input: "filter_type_1/MatMul_6" + input: "filter_type_1/bias_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_5" + op: "Tanh" + input: "filter_type_1/add_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_11_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_11" + op: "Reshape" + input: "filter_type_1/Tanh_5" + input: "filter_type_1/Reshape_11/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_11_grad/Shape" + input: "gradients/filter_type_1/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_11" + op: "Add" + input: "filter_type_1/concat_5" + input: "filter_type_1/Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_12_grad/Shape" + op: "Shape" + input: "filter_type_1/add_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_12" + op: "Reshape" + input: "filter_type_1/add_11" + input: "filter_type_1/Reshape_12/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_7" + op: "BatchMatMul" + input: "filter_type_1/Reshape_13" + input: "filter_type_1/Reshape_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_12_grad/Shape_1" + op: "Shape" + input: "filter_type_1/MatMul_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Slice" + op: "Slice" + input: "Reshape_10" + input: "filter_type_1/Slice/begin" + input: "filter_type_1/Slice/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/sub" + op: "Sub" + input: "gradients/filter_type_1/Slice_grad/Shape_1" + input: "gradients/filter_type_1/Slice_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_1/Slice_grad/sub" + input: "filter_type_1/Slice/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/Slice_grad/sub_1" + input: "gradients/filter_type_1/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_1/Slice_grad/Reshape" + input: "gradients/filter_type_1/Slice_grad/Reshape_1" + input: "gradients/filter_type_1/Slice_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_6_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_6" + op: "Reshape" + input: "filter_type_1/Slice" + input: "filter_type_1/Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape" + op: "Reshape" + input: "filter_type_1/Slice" + input: "filter_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Slice_1" + op: "Slice" + input: "filter_type_1/Reshape" + input: "filter_type_1/Slice_1/begin" + input: "filter_type_1/Slice_1/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/sub" + op: "Sub" + input: "gradients/filter_type_1/Slice_1_grad/Shape_1" + input: "gradients/filter_type_1/Slice_1_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_1/Slice_1_grad/sub" + input: "filter_type_1/Slice_1/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/Slice_1_grad/sub_1" + input: "gradients/filter_type_1/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_1/Slice_1_grad/Reshape" + input: "gradients/filter_type_1/Slice_1_grad/Reshape_1" + input: "gradients/filter_type_1/Slice_1_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_1_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_1" + op: "Reshape" + input: "filter_type_1/Slice_1" + input: "filter_type_1/Reshape_1/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/Reshape_1" + input: "filter_type_1/Reshape_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_grad/mod" + input: "gradients/filter_type_1/concat_grad/ShapeN" + input: "gradients/filter_type_1/concat_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat" + op: "ConcatV2" + input: "filter_type_1/Reshape_1" + input: "filter_type_1/Reshape_1" + input: "filter_type_1/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Shape" + op: "Shape" + input: "filter_type_1/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul" + op: "MatMul" + input: "filter_type_1/Reshape_1" + input: "filter_type_1/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_grad/Shape" + input: "gradients/filter_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add" + op: "Add" + input: "filter_type_1/MatMul" + input: "filter_type_1/bias_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh" + op: "Tanh" + input: "filter_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_2_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_2" + op: "Reshape" + input: "filter_type_1/Tanh" + input: "filter_type_1/Reshape_2/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_1_grad/Shape" + input: "gradients/filter_type_1/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_1" + op: "Add" + input: "filter_type_1/concat" + input: "filter_type_1/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/add_1" + input: "filter_type_1/add_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_1_grad/mod" + input: "gradients/filter_type_1/concat_1_grad/ShapeN" + input: "gradients/filter_type_1/concat_1_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_1" + op: "ConcatV2" + input: "filter_type_1/add_1" + input: "filter_type_1/add_1" + input: "filter_type_1/concat_1/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_1" + op: "MatMul" + input: "filter_type_1/add_1" + input: "filter_type_1/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_2_grad/Shape" + input: "gradients/filter_type_1/add_2_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_2" + op: "Add" + input: "filter_type_1/MatMul_1" + input: "filter_type_1/bias_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_1" + op: "Tanh" + input: "filter_type_1/add_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_3_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_3" + op: "Reshape" + input: "filter_type_1/Tanh_1" + input: "filter_type_1/Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_3_grad/Shape" + input: "gradients/filter_type_1/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_3" + op: "Add" + input: "filter_type_1/concat_1" + input: "filter_type_1/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/add_3" + input: "filter_type_1/add_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_2_grad/mod" + input: "gradients/filter_type_1/concat_2_grad/ShapeN" + input: "gradients/filter_type_1/concat_2_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_2" + op: "ConcatV2" + input: "filter_type_1/add_3" + input: "filter_type_1/add_3" + input: "filter_type_1/concat_2/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_2" + op: "MatMul" + input: "filter_type_1/add_3" + input: "filter_type_1/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_4_grad/Shape" + input: "gradients/filter_type_1/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_4" + op: "Add" + input: "filter_type_1/MatMul_2" + input: "filter_type_1/bias_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_2" + op: "Tanh" + input: "filter_type_1/add_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_4_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_4" + op: "Reshape" + input: "filter_type_1/Tanh_2" + input: "filter_type_1/Reshape_4/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_5_grad/Shape" + input: "gradients/filter_type_1/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_5" + op: "Add" + input: "filter_type_1/concat_2" + input: "filter_type_1/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_5_grad/Shape" + op: "Shape" + input: "filter_type_1/add_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_5" + op: "Reshape" + input: "filter_type_1/add_5" + input: "filter_type_1/Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_3" + op: "BatchMatMul" + input: "filter_type_1/Reshape_6" + input: "filter_type_1/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_12_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_12_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_12_grad/Shape" + input: "gradients/filter_type_1/add_12_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_12" + op: "Add" + input: "filter_type_1/MatMul_3" + input: "filter_type_1/MatMul_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Shape" + op: "Shape" + input: "filter_type_1/add_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/mul_grad/Shape" + input: "gradients/filter_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/mul" + op: "Mul" + input: "filter_type_1/add_12" + input: "filter_type_1/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/Shape_1" + op: "Shape" + input: "filter_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Slice_4" + op: "Slice" + input: "filter_type_1/mul" + input: "filter_type_1/Slice_4/begin" + input: "filter_type_1/Slice_4/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/sub" + op: "Sub" + input: "gradients/filter_type_1/Slice_4_grad/Shape_1" + input: "gradients/filter_type_1/Slice_4_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_1/Slice_4_grad/sub" + input: "filter_type_1/Slice_4/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/Slice_4_grad/sub_1" + input: "gradients/filter_type_1/Slice_4_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_1/Slice_4_grad/Reshape" + input: "gradients/filter_type_1/Slice_4_grad/Reshape_1" + input: "gradients/filter_type_1/Slice_4_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_8" + op: "BatchMatMul" + input: "filter_type_1/mul" + input: "filter_type_1/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/Reshape_14_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_14" + op: "Reshape" + input: "filter_type_1/MatMul_8" + input: "filter_type_1/Reshape_14/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_11_grad/Shape" + op: "Shape" + input: "filter_type_1/Reshape_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_11" + op: "Reshape" + input: "filter_type_1/Reshape_14" + input: "Reshape_11/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape" + op: "Shape" + input: "Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_6" + op: "StridedSlice" + input: "Shape" + input: "strided_slice_6/stack" + input: "strided_slice_6/stack_1" + input: "strided_slice_6/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_8/shape" + op: "Pack" + input: "strided_slice_6" + input: "mul_4" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice" + op: "Slice" + input: "Reshape_6" + input: "Slice/begin" + input: "Slice/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Slice_grad/Shape" + op: "Shape" + input: "Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/sub" + op: "Sub" + input: "gradients/Slice_grad/Shape_1" + input: "gradients/Slice_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/sub_1" + op: "Sub" + input: "gradients/Slice_grad/sub" + input: "Slice/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/Reshape_1" + op: "Reshape" + input: "gradients/Slice_grad/sub_1" + input: "gradients/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/concat" + op: "ConcatV2" + input: "gradients/Slice_grad/Reshape" + input: "gradients/Slice_grad/Reshape_1" + input: "gradients/Slice_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_7_grad/Shape" + op: "Shape" + input: "Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_7" + op: "Reshape" + input: "Slice" + input: "Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/Shape_1" + op: "Shape" + input: "Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Shape_1" + op: "Shape" + input: "Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Slice_2" + op: "Slice" + input: "Reshape_7" + input: "filter_type_0/Slice_2/begin" + input: "filter_type_0/Slice_2/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/sub" + op: "Sub" + input: "gradients/filter_type_0/Slice_2_grad/Shape_1" + input: "gradients/filter_type_0/Slice_2_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_0/Slice_2_grad/sub" + input: "filter_type_0/Slice_2/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/Slice_2_grad/sub_1" + input: "gradients/filter_type_0/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_0/Slice_2_grad/Reshape" + input: "gradients/filter_type_0/Slice_2_grad/Reshape_1" + input: "gradients/filter_type_0/Slice_2_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_7_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_13_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_13" + op: "Reshape" + input: "filter_type_0/Slice_2" + input: "filter_type_0/Reshape_13/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_7" + op: "Reshape" + input: "filter_type_0/Slice_2" + input: "filter_type_0/Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Slice_3" + op: "Slice" + input: "filter_type_0/Reshape_7" + input: "filter_type_0/Slice_3/begin" + input: "filter_type_0/Slice_3/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/sub" + op: "Sub" + input: "gradients/filter_type_0/Slice_3_grad/Shape_1" + input: "gradients/filter_type_0/Slice_3_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_0/Slice_3_grad/sub" + input: "filter_type_0/Slice_3/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/Slice_3_grad/sub_1" + input: "gradients/filter_type_0/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_0/Slice_3_grad/Reshape" + input: "gradients/filter_type_0/Slice_3_grad/Reshape_1" + input: "gradients/filter_type_0/Slice_3_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_8_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_8" + op: "Reshape" + input: "filter_type_0/Slice_3" + input: "filter_type_0/Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/Reshape_8" + input: "filter_type_0/Reshape_8" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_3_grad/mod" + input: "gradients/filter_type_0/concat_3_grad/ShapeN" + input: "gradients/filter_type_0/concat_3_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_3" + op: "ConcatV2" + input: "filter_type_0/Reshape_8" + input: "filter_type_0/Reshape_8" + input: "filter_type_0/concat_3/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_4" + op: "MatMul" + input: "filter_type_0/Reshape_8" + input: "filter_type_0/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_6_grad/Shape" + input: "gradients/filter_type_0/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_6" + op: "Add" + input: "filter_type_0/MatMul_4" + input: "filter_type_0/bias_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_3" + op: "Tanh" + input: "filter_type_0/add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_9_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_9" + op: "Reshape" + input: "filter_type_0/Tanh_3" + input: "filter_type_0/Reshape_9/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_7_grad/Shape" + input: "gradients/filter_type_0/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_7" + op: "Add" + input: "filter_type_0/concat_3" + input: "filter_type_0/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/add_7" + input: "filter_type_0/add_7" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_4_grad/mod" + input: "gradients/filter_type_0/concat_4_grad/ShapeN" + input: "gradients/filter_type_0/concat_4_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_4" + op: "ConcatV2" + input: "filter_type_0/add_7" + input: "filter_type_0/add_7" + input: "filter_type_0/concat_4/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_5" + op: "MatMul" + input: "filter_type_0/add_7" + input: "filter_type_0/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_8_grad/Shape" + input: "gradients/filter_type_0/add_8_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_8" + op: "Add" + input: "filter_type_0/MatMul_5" + input: "filter_type_0/bias_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_4" + op: "Tanh" + input: "filter_type_0/add_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_10_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_10" + op: "Reshape" + input: "filter_type_0/Tanh_4" + input: "filter_type_0/Reshape_10/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_9_grad/Shape" + input: "gradients/filter_type_0/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_9" + op: "Add" + input: "filter_type_0/concat_4" + input: "filter_type_0/Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/add_9" + input: "filter_type_0/add_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_5_grad/mod" + input: "gradients/filter_type_0/concat_5_grad/ShapeN" + input: "gradients/filter_type_0/concat_5_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_5" + op: "ConcatV2" + input: "filter_type_0/add_9" + input: "filter_type_0/add_9" + input: "filter_type_0/concat_5/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_6" + op: "MatMul" + input: "filter_type_0/add_9" + input: "filter_type_0/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_10_grad/Shape" + input: "gradients/filter_type_0/add_10_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_10" + op: "Add" + input: "filter_type_0/MatMul_6" + input: "filter_type_0/bias_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_5" + op: "Tanh" + input: "filter_type_0/add_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_11_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_11" + op: "Reshape" + input: "filter_type_0/Tanh_5" + input: "filter_type_0/Reshape_11/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_11_grad/Shape" + input: "gradients/filter_type_0/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_11" + op: "Add" + input: "filter_type_0/concat_5" + input: "filter_type_0/Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_12_grad/Shape" + op: "Shape" + input: "filter_type_0/add_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_12" + op: "Reshape" + input: "filter_type_0/add_11" + input: "filter_type_0/Reshape_12/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_7" + op: "BatchMatMul" + input: "filter_type_0/Reshape_13" + input: "filter_type_0/Reshape_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_12_grad/Shape_1" + op: "Shape" + input: "filter_type_0/MatMul_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Slice" + op: "Slice" + input: "Reshape_7" + input: "filter_type_0/Slice/begin" + input: "filter_type_0/Slice/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/sub" + op: "Sub" + input: "gradients/filter_type_0/Slice_grad/Shape_1" + input: "gradients/filter_type_0/Slice_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_0/Slice_grad/sub" + input: "filter_type_0/Slice/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/Slice_grad/sub_1" + input: "gradients/filter_type_0/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_0/Slice_grad/Reshape" + input: "gradients/filter_type_0/Slice_grad/Reshape_1" + input: "gradients/filter_type_0/Slice_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_6_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_6" + op: "Reshape" + input: "filter_type_0/Slice" + input: "filter_type_0/Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape" + op: "Reshape" + input: "filter_type_0/Slice" + input: "filter_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Slice_1" + op: "Slice" + input: "filter_type_0/Reshape" + input: "filter_type_0/Slice_1/begin" + input: "filter_type_0/Slice_1/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/sub" + op: "Sub" + input: "gradients/filter_type_0/Slice_1_grad/Shape_1" + input: "gradients/filter_type_0/Slice_1_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_0/Slice_1_grad/sub" + input: "filter_type_0/Slice_1/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/Slice_1_grad/sub_1" + input: "gradients/filter_type_0/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_0/Slice_1_grad/Reshape" + input: "gradients/filter_type_0/Slice_1_grad/Reshape_1" + input: "gradients/filter_type_0/Slice_1_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_1_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_1" + op: "Reshape" + input: "filter_type_0/Slice_1" + input: "filter_type_0/Reshape_1/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/Reshape_1" + input: "filter_type_0/Reshape_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_grad/mod" + input: "gradients/filter_type_0/concat_grad/ShapeN" + input: "gradients/filter_type_0/concat_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat" + op: "ConcatV2" + input: "filter_type_0/Reshape_1" + input: "filter_type_0/Reshape_1" + input: "filter_type_0/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Shape" + op: "Shape" + input: "filter_type_0/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul" + op: "MatMul" + input: "filter_type_0/Reshape_1" + input: "filter_type_0/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_grad/Shape" + input: "gradients/filter_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add" + op: "Add" + input: "filter_type_0/MatMul" + input: "filter_type_0/bias_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh" + op: "Tanh" + input: "filter_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_2_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_2" + op: "Reshape" + input: "filter_type_0/Tanh" + input: "filter_type_0/Reshape_2/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_1_grad/Shape" + input: "gradients/filter_type_0/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_1" + op: "Add" + input: "filter_type_0/concat" + input: "filter_type_0/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/add_1" + input: "filter_type_0/add_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_1_grad/mod" + input: "gradients/filter_type_0/concat_1_grad/ShapeN" + input: "gradients/filter_type_0/concat_1_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_1" + op: "ConcatV2" + input: "filter_type_0/add_1" + input: "filter_type_0/add_1" + input: "filter_type_0/concat_1/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_1" + op: "MatMul" + input: "filter_type_0/add_1" + input: "filter_type_0/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_2_grad/Shape" + input: "gradients/filter_type_0/add_2_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_2" + op: "Add" + input: "filter_type_0/MatMul_1" + input: "filter_type_0/bias_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_1" + op: "Tanh" + input: "filter_type_0/add_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_3_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_3" + op: "Reshape" + input: "filter_type_0/Tanh_1" + input: "filter_type_0/Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_3_grad/Shape" + input: "gradients/filter_type_0/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_3" + op: "Add" + input: "filter_type_0/concat_1" + input: "filter_type_0/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/add_3" + input: "filter_type_0/add_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_2_grad/mod" + input: "gradients/filter_type_0/concat_2_grad/ShapeN" + input: "gradients/filter_type_0/concat_2_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_2" + op: "ConcatV2" + input: "filter_type_0/add_3" + input: "filter_type_0/add_3" + input: "filter_type_0/concat_2/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_2" + op: "MatMul" + input: "filter_type_0/add_3" + input: "filter_type_0/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_4_grad/Shape" + input: "gradients/filter_type_0/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_4" + op: "Add" + input: "filter_type_0/MatMul_2" + input: "filter_type_0/bias_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_2" + op: "Tanh" + input: "filter_type_0/add_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_4_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_4" + op: "Reshape" + input: "filter_type_0/Tanh_2" + input: "filter_type_0/Reshape_4/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_5_grad/Shape" + input: "gradients/filter_type_0/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_5" + op: "Add" + input: "filter_type_0/concat_2" + input: "filter_type_0/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_5_grad/Shape" + op: "Shape" + input: "filter_type_0/add_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_5" + op: "Reshape" + input: "filter_type_0/add_5" + input: "filter_type_0/Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_3" + op: "BatchMatMul" + input: "filter_type_0/Reshape_6" + input: "filter_type_0/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_12_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_12_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_12_grad/Shape" + input: "gradients/filter_type_0/add_12_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_12" + op: "Add" + input: "filter_type_0/MatMul_3" + input: "filter_type_0/MatMul_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Shape" + op: "Shape" + input: "filter_type_0/add_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/mul_grad/Shape" + input: "gradients/filter_type_0/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/mul" + op: "Mul" + input: "filter_type_0/add_12" + input: "filter_type_0/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/Shape_1" + op: "Shape" + input: "filter_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Slice_4" + op: "Slice" + input: "filter_type_0/mul" + input: "filter_type_0/Slice_4/begin" + input: "filter_type_0/Slice_4/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/sub" + op: "Sub" + input: "gradients/filter_type_0/Slice_4_grad/Shape_1" + input: "gradients/filter_type_0/Slice_4_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_0/Slice_4_grad/sub" + input: "filter_type_0/Slice_4/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/Slice_4_grad/sub_1" + input: "gradients/filter_type_0/Slice_4_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_0/Slice_4_grad/Reshape" + input: "gradients/filter_type_0/Slice_4_grad/Reshape_1" + input: "gradients/filter_type_0/Slice_4_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_8" + op: "BatchMatMul" + input: "filter_type_0/mul" + input: "filter_type_0/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/Reshape_14_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_14" + op: "Reshape" + input: "filter_type_0/MatMul_8" + input: "filter_type_0/Reshape_14/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_8_grad/Shape" + op: "Shape" + input: "filter_type_0/Reshape_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_8" + op: "Reshape" + input: "filter_type_0/Reshape_14" + input: "Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/ShapeN" + op: "ShapeN" + input: "Reshape_8" + input: "Reshape_11" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/concat_grad/mod" + input: "gradients/concat_grad/ShapeN" + input: "gradients/concat_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "concat" + op: "ConcatV2" + input: "Reshape_8" + input: "Reshape_11" + input: "concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "o_descriptor" + op: "Identity" + input: "concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_13_grad/Shape" + op: "Shape" + input: "o_descriptor" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_13" + op: "Reshape" + input: "o_descriptor" + input: "Reshape_13/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/Shape_1" + op: "Shape" + input: "Reshape_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/Shape_1" + op: "Shape" + input: "Reshape_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_5" + op: "Shape" + input: "Reshape_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_24" + op: "StridedSlice" + input: "Shape_5" + input: "strided_slice_24/stack" + input: "strided_slice_24/stack_1" + input: "strided_slice_24/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_17/shape" + op: "Pack" + input: "strided_slice_24" + input: "strided_slice_25" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_3" + op: "Slice" + input: "Reshape_13" + input: "Slice_3/begin" + input: "Slice_3/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Slice_3_grad/Shape" + op: "Shape" + input: "Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/sub" + op: "Sub" + input: "gradients/Slice_3_grad/Shape_1" + input: "gradients/Slice_3_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/sub_1" + op: "Sub" + input: "gradients/Slice_3_grad/sub" + input: "Slice_3/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/Slice_3_grad/sub_1" + input: "gradients/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/concat" + op: "ConcatV2" + input: "gradients/Slice_3_grad/Reshape" + input: "gradients/Slice_3_grad/Reshape_1" + input: "gradients/Slice_3_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_16_grad/Shape" + op: "Shape" + input: "Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_16" + op: "Reshape" + input: "Slice_3" + input: "Reshape_16/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_1/MatMul" + op: "MatMul" + input: "Reshape_16" + input: "layer_0_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/Shape" + op: "Shape" + input: "layer_0_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_0_type_1/add_grad/Shape" + input: "gradients/layer_0_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_1/add" + op: "Add" + input: "layer_0_type_1/MatMul" + input: "layer_0_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_0_type_1/Tanh" + op: "Tanh" + input: "layer_0_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_0_type_1/Reshape_grad/Shape" + op: "Shape" + input: "layer_0_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_1/Reshape" + op: "Reshape" + input: "layer_0_type_1/Tanh" + input: "layer_0_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_6_grad/Shape" + op: "Shape" + input: "layer_0_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/MatMul" + op: "MatMul" + input: "layer_0_type_1/Reshape" + input: "layer_1_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/Shape" + op: "Shape" + input: "layer_1_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_1_type_1/add_grad/Shape" + input: "gradients/layer_1_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/add" + op: "Add" + input: "layer_1_type_1/MatMul" + input: "layer_1_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_1_type_1/Tanh" + op: "Tanh" + input: "layer_1_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_1/Reshape_grad/Shape" + op: "Shape" + input: "layer_1_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/Reshape" + op: "Reshape" + input: "layer_1_type_1/Tanh" + input: "layer_1_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Shape" + op: "Shape" + input: "layer_1_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_1_type_1/mul_grad/Shape" + input: "gradients/layer_1_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/mul" + op: "Mul" + input: "layer_1_type_1/Reshape" + input: "layer_1_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_6_grad/Shape_1" + op: "Shape" + input: "layer_1_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_6_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/add_6_grad/Shape" + input: "gradients/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_6" + op: "Add" + input: "layer_0_type_1/Reshape" + input: "layer_1_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_7_grad/Shape" + op: "Shape" + input: "add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/MatMul" + op: "MatMul" + input: "add_6" + input: "layer_2_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/Shape" + op: "Shape" + input: "layer_2_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_2_type_1/add_grad/Shape" + input: "gradients/layer_2_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/add" + op: "Add" + input: "layer_2_type_1/MatMul" + input: "layer_2_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_1/Tanh" + op: "Tanh" + input: "layer_2_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_1/Reshape_grad/Shape" + op: "Shape" + input: "layer_2_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/Reshape" + op: "Reshape" + input: "layer_2_type_1/Tanh" + input: "layer_2_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Shape" + op: "Shape" + input: "layer_2_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_2_type_1/mul_grad/Shape" + input: "gradients/layer_2_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/mul" + op: "Mul" + input: "layer_2_type_1/Reshape" + input: "layer_2_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_7_grad/Shape_1" + op: "Shape" + input: "layer_2_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_7_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/add_7_grad/Shape" + input: "gradients/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_7" + op: "Add" + input: "add_6" + input: "layer_2_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "final_layer_type_1/MatMul" + op: "MatMul" + input: "add_7" + input: "final_layer_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/Shape" + op: "Shape" + input: "final_layer_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/final_layer_type_1/add_grad/Shape" + input: "gradients/final_layer_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "final_layer_type_1/add" + op: "Add" + input: "final_layer_type_1/MatMul" + input: "final_layer_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_17_grad/Shape" + op: "Shape" + input: "final_layer_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_17" + op: "Reshape" + input: "final_layer_type_1/add" + input: "Reshape_17/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_4" + op: "Shape" + input: "Reshape_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_20" + op: "StridedSlice" + input: "Shape_4" + input: "strided_slice_20/stack" + input: "strided_slice_20/stack_1" + input: "strided_slice_20/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_15/shape" + op: "Pack" + input: "strided_slice_20" + input: "strided_slice_21" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_2" + op: "Slice" + input: "Reshape_13" + input: "Slice_2/begin" + input: "Slice_2/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Slice_2_grad/Shape" + op: "Shape" + input: "Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/sub" + op: "Sub" + input: "gradients/Slice_2_grad/Shape_1" + input: "gradients/Slice_2_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/sub_1" + op: "Sub" + input: "gradients/Slice_2_grad/sub" + input: "Slice_2/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/Reshape_1" + op: "Reshape" + input: "gradients/Slice_2_grad/sub_1" + input: "gradients/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/concat" + op: "ConcatV2" + input: "gradients/Slice_2_grad/Reshape" + input: "gradients/Slice_2_grad/Reshape_1" + input: "gradients/Slice_2_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_14_grad/Shape" + op: "Shape" + input: "Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_14" + op: "Reshape" + input: "Slice_2" + input: "Reshape_14/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_0/MatMul" + op: "MatMul" + input: "Reshape_14" + input: "layer_0_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/Shape" + op: "Shape" + input: "layer_0_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_0_type_0/add_grad/Shape" + input: "gradients/layer_0_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_0/add" + op: "Add" + input: "layer_0_type_0/MatMul" + input: "layer_0_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_0_type_0/Tanh" + op: "Tanh" + input: "layer_0_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_0_type_0/Reshape_grad/Shape" + op: "Shape" + input: "layer_0_type_0/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_0/Reshape" + op: "Reshape" + input: "layer_0_type_0/Tanh" + input: "layer_0_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_3_grad/Shape" + op: "Shape" + input: "layer_0_type_0/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/MatMul" + op: "MatMul" + input: "layer_0_type_0/Reshape" + input: "layer_1_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/Shape" + op: "Shape" + input: "layer_1_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_1_type_0/add_grad/Shape" + input: "gradients/layer_1_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/add" + op: "Add" + input: "layer_1_type_0/MatMul" + input: "layer_1_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_1_type_0/Tanh" + op: "Tanh" + input: "layer_1_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_0/Reshape_grad/Shape" + op: "Shape" + input: "layer_1_type_0/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/Reshape" + op: "Reshape" + input: "layer_1_type_0/Tanh" + input: "layer_1_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Shape" + op: "Shape" + input: "layer_1_type_0/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_1_type_0/mul_grad/Shape" + input: "gradients/layer_1_type_0/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/mul" + op: "Mul" + input: "layer_1_type_0/Reshape" + input: "layer_1_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_3_grad/Shape_1" + op: "Shape" + input: "layer_1_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_3_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/add_3_grad/Shape" + input: "gradients/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_3" + op: "Add" + input: "layer_0_type_0/Reshape" + input: "layer_1_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_4_grad/Shape" + op: "Shape" + input: "add_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/MatMul" + op: "MatMul" + input: "add_3" + input: "layer_2_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/Shape" + op: "Shape" + input: "layer_2_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_2_type_0/add_grad/Shape" + input: "gradients/layer_2_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/add" + op: "Add" + input: "layer_2_type_0/MatMul" + input: "layer_2_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_0/Tanh" + op: "Tanh" + input: "layer_2_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_0/Reshape_grad/Shape" + op: "Shape" + input: "layer_2_type_0/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/Reshape" + op: "Reshape" + input: "layer_2_type_0/Tanh" + input: "layer_2_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Shape" + op: "Shape" + input: "layer_2_type_0/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_2_type_0/mul_grad/Shape" + input: "gradients/layer_2_type_0/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/mul" + op: "Mul" + input: "layer_2_type_0/Reshape" + input: "layer_2_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_4_grad/Shape_1" + op: "Shape" + input: "layer_2_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_4_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/add_4_grad/Shape" + input: "gradients/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_4" + op: "Add" + input: "add_3" + input: "layer_2_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "final_layer_type_0/MatMul" + op: "MatMul" + input: "add_4" + input: "final_layer_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/Shape" + op: "Shape" + input: "final_layer_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/final_layer_type_0/add_grad/Shape" + input: "gradients/final_layer_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "final_layer_type_0/add" + op: "Add" + input: "final_layer_type_0/MatMul" + input: "final_layer_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_15_grad/Shape" + op: "Shape" + input: "final_layer_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_15" + op: "Reshape" + input: "final_layer_type_0/add" + input: "Reshape_15/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_2_grad/ShapeN" + op: "ShapeN" + input: "Reshape_15" + input: "Reshape_17" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_2_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/concat_2_grad/mod" + input: "gradients/concat_2_grad/ShapeN" + input: "gradients/concat_2_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "concat_2" + op: "ConcatV2" + input: "Reshape_15" + input: "Reshape_17" + input: "concat_2/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_18_grad/Shape" + op: "Shape" + input: "concat_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_18" + op: "Reshape" + input: "concat_2" + input: "Reshape_18/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Shape" + op: "Shape" + input: "Reshape_18" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Fill" + op: "Fill" + input: "gradients/Shape" + input: "gradients/grad_ys_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "index_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_18_grad/Reshape" + op: "Reshape" + input: "gradients/Fill" + input: "gradients/Reshape_18_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_2_grad/Slice_1" + op: "Slice" + input: "gradients/Reshape_18_grad/Reshape" + input: "gradients/concat_2_grad/ConcatOffset:1" + input: "gradients/concat_2_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_17_grad/Reshape" + op: "Reshape" + input: "gradients/concat_2_grad/Slice_1" + input: "gradients/Reshape_17_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/Reshape_17_grad/Reshape" + input: "gradients/final_layer_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/final_layer_type_1/add_grad/Sum" + input: "gradients/final_layer_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/final_layer_type_1/add_grad/Reshape" + input: "final_layer_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_7_grad/Sum_1" + op: "Sum" + input: "gradients/final_layer_type_1/MatMul_grad/MatMul" + input: "gradients/add_7_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_7_grad/Reshape_1" + op: "Reshape" + input: "gradients/add_7_grad/Sum_1" + input: "gradients/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients/add_7_grad/Reshape_1" + input: "layer_2_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients/layer_2_type_1/mul_grad/Mul" + input: "gradients/layer_2_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_1/mul_grad/Sum" + input: "gradients/layer_2_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_1/mul_grad/Reshape" + input: "gradients/layer_2_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_2_type_1/Tanh" + input: "gradients/layer_2_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/layer_2_type_1/Tanh_grad/TanhGrad" + input: "gradients/layer_2_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_1/add_grad/Sum" + input: "gradients/layer_2_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_2_type_1/add_grad/Reshape" + input: "layer_2_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_7_grad/Sum" + op: "Sum" + input: "gradients/final_layer_type_1/MatMul_grad/MatMul" + input: "gradients/add_7_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_7_grad/Reshape" + op: "Reshape" + input: "gradients/add_7_grad/Sum" + input: "gradients/add_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_1" + op: "AddN" + input: "gradients/add_7_grad/Reshape" + input: "gradients/layer_2_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/add_7_grad/Reshape" + } + } + } +} +node { + name: "gradients/add_6_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_1" + input: "gradients/add_6_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_6_grad/Reshape_1" + op: "Reshape" + input: "gradients/add_6_grad/Sum_1" + input: "gradients/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients/add_6_grad/Reshape_1" + input: "layer_1_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients/layer_1_type_1/mul_grad/Mul" + input: "gradients/layer_1_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_1/mul_grad/Sum" + input: "gradients/layer_1_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_1/mul_grad/Reshape" + input: "gradients/layer_1_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_1_type_1/Tanh" + input: "gradients/layer_1_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/layer_1_type_1/Tanh_grad/TanhGrad" + input: "gradients/layer_1_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_1/add_grad/Sum" + input: "gradients/layer_1_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_1_type_1/add_grad/Reshape" + input: "layer_1_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_6_grad/Sum" + op: "Sum" + input: "gradients/AddN_1" + input: "gradients/add_6_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_6_grad/Reshape" + op: "Reshape" + input: "gradients/add_6_grad/Sum" + input: "gradients/add_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_3" + op: "AddN" + input: "gradients/add_6_grad/Reshape" + input: "gradients/layer_1_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/add_6_grad/Reshape" + } + } + } +} +node { + name: "gradients/layer_0_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_3" + input: "gradients/layer_0_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_0_type_1/Tanh" + input: "gradients/layer_0_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/layer_0_type_1/Tanh_grad/TanhGrad" + input: "gradients/layer_0_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_0_type_1/add_grad/Sum" + input: "gradients/layer_0_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_0_type_1/add_grad/Reshape" + input: "layer_0_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/Reshape_16_grad/Reshape" + op: "Reshape" + input: "gradients/layer_0_type_1/MatMul_grad/MatMul" + input: "gradients/Reshape_16_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/Pad" + op: "Pad" + input: "gradients/Reshape_16_grad/Reshape" + input: "gradients/Slice_3_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_2_grad/Slice" + op: "Slice" + input: "gradients/Reshape_18_grad/Reshape" + input: "gradients/concat_2_grad/ConcatOffset" + input: "gradients/concat_2_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_15_grad/Reshape" + op: "Reshape" + input: "gradients/concat_2_grad/Slice" + input: "gradients/Reshape_15_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/Reshape_15_grad/Reshape" + input: "gradients/final_layer_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/final_layer_type_0/add_grad/Sum" + input: "gradients/final_layer_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/final_layer_type_0/add_grad/Reshape" + input: "final_layer_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_4_grad/Sum_1" + op: "Sum" + input: "gradients/final_layer_type_0/MatMul_grad/MatMul" + input: "gradients/add_4_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_4_grad/Reshape_1" + op: "Reshape" + input: "gradients/add_4_grad/Sum_1" + input: "gradients/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Mul" + op: "Mul" + input: "gradients/add_4_grad/Reshape_1" + input: "layer_2_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Sum" + op: "Sum" + input: "gradients/layer_2_type_0/mul_grad/Mul" + input: "gradients/layer_2_type_0/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_0/mul_grad/Sum" + input: "gradients/layer_2_type_0/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_0/mul_grad/Reshape" + input: "gradients/layer_2_type_0/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_2_type_0/Tanh" + input: "gradients/layer_2_type_0/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/layer_2_type_0/Tanh_grad/TanhGrad" + input: "gradients/layer_2_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_0/add_grad/Sum" + input: "gradients/layer_2_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_2_type_0/add_grad/Reshape" + input: "layer_2_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_4_grad/Sum" + op: "Sum" + input: "gradients/final_layer_type_0/MatMul_grad/MatMul" + input: "gradients/add_4_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_4_grad/Reshape" + op: "Reshape" + input: "gradients/add_4_grad/Sum" + input: "gradients/add_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN" + op: "AddN" + input: "gradients/add_4_grad/Reshape" + input: "gradients/layer_2_type_0/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/add_4_grad/Reshape" + } + } + } +} +node { + name: "gradients/add_3_grad/Sum_1" + op: "Sum" + input: "gradients/AddN" + input: "gradients/add_3_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/add_3_grad/Sum_1" + input: "gradients/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Mul" + op: "Mul" + input: "gradients/add_3_grad/Reshape_1" + input: "layer_1_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Sum" + op: "Sum" + input: "gradients/layer_1_type_0/mul_grad/Mul" + input: "gradients/layer_1_type_0/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_0/mul_grad/Sum" + input: "gradients/layer_1_type_0/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_0/mul_grad/Reshape" + input: "gradients/layer_1_type_0/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_1_type_0/Tanh" + input: "gradients/layer_1_type_0/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/layer_1_type_0/Tanh_grad/TanhGrad" + input: "gradients/layer_1_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_0/add_grad/Sum" + input: "gradients/layer_1_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_1_type_0/add_grad/Reshape" + input: "layer_1_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_3_grad/Sum" + op: "Sum" + input: "gradients/AddN" + input: "gradients/add_3_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_3_grad/Reshape" + op: "Reshape" + input: "gradients/add_3_grad/Sum" + input: "gradients/add_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_2" + op: "AddN" + input: "gradients/add_3_grad/Reshape" + input: "gradients/layer_1_type_0/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/add_3_grad/Reshape" + } + } + } +} +node { + name: "gradients/layer_0_type_0/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_2" + input: "gradients/layer_0_type_0/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_0/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_0_type_0/Tanh" + input: "gradients/layer_0_type_0/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/layer_0_type_0/Tanh_grad/TanhGrad" + input: "gradients/layer_0_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_0_type_0/add_grad/Sum" + input: "gradients/layer_0_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_0_type_0/add_grad/Reshape" + input: "layer_0_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/Reshape_14_grad/Reshape" + op: "Reshape" + input: "gradients/layer_0_type_0/MatMul_grad/MatMul" + input: "gradients/Reshape_14_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/Pad" + op: "Pad" + input: "gradients/Reshape_14_grad/Reshape" + input: "gradients/Slice_2_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_4" + op: "AddN" + input: "gradients/Slice_2_grad/Pad" + input: "gradients/Slice_3_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/Slice_2_grad/Pad" + } + } + } +} +node { + name: "gradients/Reshape_13_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_4" + input: "gradients/Reshape_13_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/Slice_1" + op: "Slice" + input: "gradients/Reshape_13_grad/Reshape" + input: "gradients/concat_grad/ConcatOffset:1" + input: "gradients/concat_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_11_grad/Reshape" + op: "Reshape" + input: "gradients/concat_grad/Slice_1" + input: "gradients/Reshape_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_14_grad/Reshape" + op: "Reshape" + input: "gradients/Reshape_11_grad/Reshape" + input: "gradients/filter_type_1/Reshape_14_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_8_grad/MatMul_1" + op: "BatchMatMul" + input: "filter_type_1/mul" + input: "gradients/filter_type_1/Reshape_14_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/Slice_4_grad/Pad" + op: "Pad" + input: "gradients/filter_type_1/MatMul_8_grad/MatMul_1" + input: "gradients/filter_type_1/Slice_4_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_8_grad/MatMul" + op: "BatchMatMul" + input: "filter_type_1/Slice_4" + input: "gradients/filter_type_1/Reshape_14_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/AddN_6" + op: "AddN" + input: "gradients/filter_type_1/MatMul_8_grad/MatMul" + input: "gradients/filter_type_1/Slice_4_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/MatMul_8_grad/MatMul" + } + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients/AddN_6" + input: "filter_type_1/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/mul_grad/Mul" + input: "gradients/filter_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/mul_grad/Sum" + input: "gradients/filter_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_12_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_1/mul_grad/Reshape" + input: "gradients/filter_type_1/add_12_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_12_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_12_grad/Sum_1" + input: "gradients/filter_type_1/add_12_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_7_grad/MatMul_1" + op: "BatchMatMul" + input: "filter_type_1/Reshape_13" + input: "gradients/filter_type_1/add_12_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/Reshape_12_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/MatMul_7_grad/MatMul_1" + input: "gradients/filter_type_1/Reshape_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_1/Reshape_12_grad/Reshape" + input: "gradients/filter_type_1/add_11_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_11_grad/Sum_1" + input: "gradients/filter_type_1/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_11_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_11_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_5_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_5" + input: "gradients/filter_type_1/Reshape_11_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_5_grad/TanhGrad" + input: "gradients/filter_type_1/add_10_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_10_grad/Sum" + input: "gradients/filter_type_1/add_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_6_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_10_grad/Reshape" + input: "filter_type_1/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Reshape_12_grad/Reshape" + input: "gradients/filter_type_1/add_11_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_11_grad/Sum" + input: "gradients/filter_type_1/add_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_11_grad/Reshape" + input: "gradients/filter_type_1/concat_5_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_5_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_11_grad/Reshape" + input: "gradients/filter_type_1/concat_5_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_5_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_10" + op: "AddN" + input: "gradients/filter_type_1/concat_5_grad/Slice" + input: "gradients/filter_type_1/concat_5_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_6_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_5_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_10" + input: "gradients/filter_type_1/add_9_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_9_grad/Sum_1" + input: "gradients/filter_type_1/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_10_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_9_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_4_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_4" + input: "gradients/filter_type_1/Reshape_10_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_4_grad/TanhGrad" + input: "gradients/filter_type_1/add_8_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_8_grad/Sum" + input: "gradients/filter_type_1/add_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_5_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_8_grad/Reshape" + input: "filter_type_1/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Sum" + op: "Sum" + input: "gradients/AddN_10" + input: "gradients/filter_type_1/add_9_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_9_grad/Sum" + input: "gradients/filter_type_1/add_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_9_grad/Reshape" + input: "gradients/filter_type_1/concat_4_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_4_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_9_grad/Reshape" + input: "gradients/filter_type_1/concat_4_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_4_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_14" + op: "AddN" + input: "gradients/filter_type_1/concat_4_grad/Slice" + input: "gradients/filter_type_1/concat_4_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_5_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_4_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_14" + input: "gradients/filter_type_1/add_7_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_7_grad/Sum_1" + input: "gradients/filter_type_1/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_9_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_7_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_3_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_3" + input: "gradients/filter_type_1/Reshape_9_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_3_grad/TanhGrad" + input: "gradients/filter_type_1/add_6_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_6_grad/Sum" + input: "gradients/filter_type_1/add_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_4_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_6_grad/Reshape" + input: "filter_type_1/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Sum" + op: "Sum" + input: "gradients/AddN_14" + input: "gradients/filter_type_1/add_7_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_7_grad/Sum" + input: "gradients/filter_type_1/add_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_7_grad/Reshape" + input: "gradients/filter_type_1/concat_3_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_3_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_7_grad/Reshape" + input: "gradients/filter_type_1/concat_3_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_3_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_18" + op: "AddN" + input: "gradients/filter_type_1/concat_3_grad/Slice" + input: "gradients/filter_type_1/concat_3_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_4_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_3_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/Reshape_8_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_18" + input: "gradients/filter_type_1/Reshape_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_3_grad/Pad" + op: "Pad" + input: "gradients/filter_type_1/Reshape_8_grad/Reshape" + input: "gradients/filter_type_1/Slice_3_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_7_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/Slice_3_grad/Pad" + input: "gradients/filter_type_1/Reshape_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_7_grad/MatMul" + op: "BatchMatMul" + input: "filter_type_1/Reshape_12" + input: "gradients/filter_type_1/add_12_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/Reshape_13_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/MatMul_7_grad/MatMul" + input: "gradients/filter_type_1/Reshape_13_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_22" + op: "AddN" + input: "gradients/filter_type_1/Reshape_13_grad/Reshape" + input: "gradients/filter_type_1/Reshape_7_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Reshape_13_grad/Reshape" + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_2_grad/Pad" + op: "Pad" + input: "gradients/AddN_22" + input: "gradients/filter_type_1/Slice_2_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_12_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/mul_grad/Reshape" + input: "gradients/filter_type_1/add_12_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_12_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_12_grad/Sum" + input: "gradients/filter_type_1/add_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_3_grad/MatMul_1" + op: "BatchMatMul" + input: "filter_type_1/Reshape_6" + input: "gradients/filter_type_1/add_12_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/Reshape_5_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/MatMul_3_grad/MatMul_1" + input: "gradients/filter_type_1/Reshape_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_1/Reshape_5_grad/Reshape" + input: "gradients/filter_type_1/add_5_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_5_grad/Sum_1" + input: "gradients/filter_type_1/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_4_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_5_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_2_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_2" + input: "gradients/filter_type_1/Reshape_4_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_2_grad/TanhGrad" + input: "gradients/filter_type_1/add_4_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_4_grad/Sum" + input: "gradients/filter_type_1/add_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_2_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_4_grad/Reshape" + input: "filter_type_1/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Reshape_5_grad/Reshape" + input: "gradients/filter_type_1/add_5_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_5_grad/Sum" + input: "gradients/filter_type_1/add_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_5_grad/Reshape" + input: "gradients/filter_type_1/concat_2_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_2_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_5_grad/Reshape" + input: "gradients/filter_type_1/concat_2_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_2_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_9" + op: "AddN" + input: "gradients/filter_type_1/concat_2_grad/Slice" + input: "gradients/filter_type_1/concat_2_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_2_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_2_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_9" + input: "gradients/filter_type_1/add_3_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_3_grad/Sum_1" + input: "gradients/filter_type_1/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_3_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_3_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_1_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_1" + input: "gradients/filter_type_1/Reshape_3_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_1_grad/TanhGrad" + input: "gradients/filter_type_1/add_2_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_2_grad/Sum" + input: "gradients/filter_type_1/add_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_1_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_2_grad/Reshape" + input: "filter_type_1/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Sum" + op: "Sum" + input: "gradients/AddN_9" + input: "gradients/filter_type_1/add_3_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_3_grad/Sum" + input: "gradients/filter_type_1/add_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_3_grad/Reshape" + input: "gradients/filter_type_1/concat_1_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_1_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_3_grad/Reshape" + input: "gradients/filter_type_1/concat_1_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_1_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_13" + op: "AddN" + input: "gradients/filter_type_1/concat_1_grad/Slice" + input: "gradients/filter_type_1/concat_1_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_1_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_1_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_13" + input: "gradients/filter_type_1/add_1_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_1_grad/Sum_1" + input: "gradients/filter_type_1/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_2_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_1_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh" + input: "gradients/filter_type_1/Reshape_2_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_grad/TanhGrad" + input: "gradients/filter_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_grad/Sum" + input: "gradients/filter_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_grad/Reshape" + input: "filter_type_1/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Sum" + op: "Sum" + input: "gradients/AddN_13" + input: "gradients/filter_type_1/add_1_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_1_grad/Sum" + input: "gradients/filter_type_1/add_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_1_grad/Reshape" + input: "gradients/filter_type_1/concat_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_1_grad/Reshape" + input: "gradients/filter_type_1/concat_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_17" + op: "AddN" + input: "gradients/filter_type_1/concat_grad/Slice" + input: "gradients/filter_type_1/concat_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/Reshape_1_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_17" + input: "gradients/filter_type_1/Reshape_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Pad" + op: "Pad" + input: "gradients/filter_type_1/Reshape_1_grad/Reshape" + input: "gradients/filter_type_1/Slice_1_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/Slice_1_grad/Pad" + input: "gradients/filter_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_3_grad/MatMul" + op: "BatchMatMul" + input: "filter_type_1/Reshape_5" + input: "gradients/filter_type_1/add_12_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/Reshape_6_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/MatMul_3_grad/MatMul" + input: "gradients/filter_type_1/Reshape_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_21" + op: "AddN" + input: "gradients/filter_type_1/Reshape_6_grad/Reshape" + input: "gradients/filter_type_1/Reshape_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Reshape_6_grad/Reshape" + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Pad" + op: "Pad" + input: "gradients/AddN_21" + input: "gradients/filter_type_1/Slice_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_24" + op: "AddN" + input: "gradients/filter_type_1/Slice_grad/Pad" + input: "gradients/filter_type_1/Slice_2_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Slice_grad/Pad" + } + } + } +} +node { + name: "gradients/Reshape_10_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_24" + input: "gradients/Reshape_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/Pad" + op: "Pad" + input: "gradients/Reshape_10_grad/Reshape" + input: "gradients/Slice_1_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/Slice" + op: "Slice" + input: "gradients/Reshape_13_grad/Reshape" + input: "gradients/concat_grad/ConcatOffset" + input: "gradients/concat_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_8_grad/Reshape" + op: "Reshape" + input: "gradients/concat_grad/Slice" + input: "gradients/Reshape_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_14_grad/Reshape" + op: "Reshape" + input: "gradients/Reshape_8_grad/Reshape" + input: "gradients/filter_type_0/Reshape_14_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_8_grad/MatMul_1" + op: "BatchMatMul" + input: "filter_type_0/mul" + input: "gradients/filter_type_0/Reshape_14_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/Slice_4_grad/Pad" + op: "Pad" + input: "gradients/filter_type_0/MatMul_8_grad/MatMul_1" + input: "gradients/filter_type_0/Slice_4_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_8_grad/MatMul" + op: "BatchMatMul" + input: "filter_type_0/Slice_4" + input: "gradients/filter_type_0/Reshape_14_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/AddN_5" + op: "AddN" + input: "gradients/filter_type_0/MatMul_8_grad/MatMul" + input: "gradients/filter_type_0/Slice_4_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/MatMul_8_grad/MatMul" + } + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Mul" + op: "Mul" + input: "gradients/AddN_5" + input: "filter_type_0/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/mul_grad/Mul" + input: "gradients/filter_type_0/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/mul_grad/Sum" + input: "gradients/filter_type_0/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_12_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_0/mul_grad/Reshape" + input: "gradients/filter_type_0/add_12_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_12_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_12_grad/Sum_1" + input: "gradients/filter_type_0/add_12_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_7_grad/MatMul_1" + op: "BatchMatMul" + input: "filter_type_0/Reshape_13" + input: "gradients/filter_type_0/add_12_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/Reshape_12_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/MatMul_7_grad/MatMul_1" + input: "gradients/filter_type_0/Reshape_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_0/Reshape_12_grad/Reshape" + input: "gradients/filter_type_0/add_11_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_11_grad/Sum_1" + input: "gradients/filter_type_0/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_11_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_11_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_5_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_5" + input: "gradients/filter_type_0/Reshape_11_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_5_grad/TanhGrad" + input: "gradients/filter_type_0/add_10_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_10_grad/Sum" + input: "gradients/filter_type_0/add_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_6_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_10_grad/Reshape" + input: "filter_type_0/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Reshape_12_grad/Reshape" + input: "gradients/filter_type_0/add_11_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_11_grad/Sum" + input: "gradients/filter_type_0/add_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_11_grad/Reshape" + input: "gradients/filter_type_0/concat_5_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_5_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_11_grad/Reshape" + input: "gradients/filter_type_0/concat_5_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_5_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_8" + op: "AddN" + input: "gradients/filter_type_0/concat_5_grad/Slice" + input: "gradients/filter_type_0/concat_5_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_6_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_5_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_8" + input: "gradients/filter_type_0/add_9_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_9_grad/Sum_1" + input: "gradients/filter_type_0/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_10_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_9_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_4_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_4" + input: "gradients/filter_type_0/Reshape_10_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_4_grad/TanhGrad" + input: "gradients/filter_type_0/add_8_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_8_grad/Sum" + input: "gradients/filter_type_0/add_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_5_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_8_grad/Reshape" + input: "filter_type_0/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Sum" + op: "Sum" + input: "gradients/AddN_8" + input: "gradients/filter_type_0/add_9_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_9_grad/Sum" + input: "gradients/filter_type_0/add_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_9_grad/Reshape" + input: "gradients/filter_type_0/concat_4_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_4_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_9_grad/Reshape" + input: "gradients/filter_type_0/concat_4_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_4_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_12" + op: "AddN" + input: "gradients/filter_type_0/concat_4_grad/Slice" + input: "gradients/filter_type_0/concat_4_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_5_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_4_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_12" + input: "gradients/filter_type_0/add_7_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_7_grad/Sum_1" + input: "gradients/filter_type_0/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_9_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_7_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_3_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_3" + input: "gradients/filter_type_0/Reshape_9_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_3_grad/TanhGrad" + input: "gradients/filter_type_0/add_6_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_6_grad/Sum" + input: "gradients/filter_type_0/add_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_4_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_6_grad/Reshape" + input: "filter_type_0/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Sum" + op: "Sum" + input: "gradients/AddN_12" + input: "gradients/filter_type_0/add_7_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_7_grad/Sum" + input: "gradients/filter_type_0/add_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_7_grad/Reshape" + input: "gradients/filter_type_0/concat_3_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_3_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_7_grad/Reshape" + input: "gradients/filter_type_0/concat_3_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_3_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_16" + op: "AddN" + input: "gradients/filter_type_0/concat_3_grad/Slice" + input: "gradients/filter_type_0/concat_3_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_4_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_3_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/Reshape_8_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_16" + input: "gradients/filter_type_0/Reshape_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_3_grad/Pad" + op: "Pad" + input: "gradients/filter_type_0/Reshape_8_grad/Reshape" + input: "gradients/filter_type_0/Slice_3_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_7_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/Slice_3_grad/Pad" + input: "gradients/filter_type_0/Reshape_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_7_grad/MatMul" + op: "BatchMatMul" + input: "filter_type_0/Reshape_12" + input: "gradients/filter_type_0/add_12_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/Reshape_13_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/MatMul_7_grad/MatMul" + input: "gradients/filter_type_0/Reshape_13_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_20" + op: "AddN" + input: "gradients/filter_type_0/Reshape_13_grad/Reshape" + input: "gradients/filter_type_0/Reshape_7_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Reshape_13_grad/Reshape" + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_2_grad/Pad" + op: "Pad" + input: "gradients/AddN_20" + input: "gradients/filter_type_0/Slice_2_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_12_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/mul_grad/Reshape" + input: "gradients/filter_type_0/add_12_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_12_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_12_grad/Sum" + input: "gradients/filter_type_0/add_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_3_grad/MatMul_1" + op: "BatchMatMul" + input: "filter_type_0/Reshape_6" + input: "gradients/filter_type_0/add_12_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/Reshape_5_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/MatMul_3_grad/MatMul_1" + input: "gradients/filter_type_0/Reshape_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_0/Reshape_5_grad/Reshape" + input: "gradients/filter_type_0/add_5_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_5_grad/Sum_1" + input: "gradients/filter_type_0/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_4_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_5_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_2_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_2" + input: "gradients/filter_type_0/Reshape_4_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_2_grad/TanhGrad" + input: "gradients/filter_type_0/add_4_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_4_grad/Sum" + input: "gradients/filter_type_0/add_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_2_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_4_grad/Reshape" + input: "filter_type_0/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Reshape_5_grad/Reshape" + input: "gradients/filter_type_0/add_5_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_5_grad/Sum" + input: "gradients/filter_type_0/add_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_5_grad/Reshape" + input: "gradients/filter_type_0/concat_2_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_2_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_5_grad/Reshape" + input: "gradients/filter_type_0/concat_2_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_2_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_7" + op: "AddN" + input: "gradients/filter_type_0/concat_2_grad/Slice" + input: "gradients/filter_type_0/concat_2_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_2_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_2_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_7" + input: "gradients/filter_type_0/add_3_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_3_grad/Sum_1" + input: "gradients/filter_type_0/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_3_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_3_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_1_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_1" + input: "gradients/filter_type_0/Reshape_3_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_1_grad/TanhGrad" + input: "gradients/filter_type_0/add_2_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_2_grad/Sum" + input: "gradients/filter_type_0/add_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_1_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_2_grad/Reshape" + input: "filter_type_0/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Sum" + op: "Sum" + input: "gradients/AddN_7" + input: "gradients/filter_type_0/add_3_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_3_grad/Sum" + input: "gradients/filter_type_0/add_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_3_grad/Reshape" + input: "gradients/filter_type_0/concat_1_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_1_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_3_grad/Reshape" + input: "gradients/filter_type_0/concat_1_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_1_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_11" + op: "AddN" + input: "gradients/filter_type_0/concat_1_grad/Slice" + input: "gradients/filter_type_0/concat_1_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_1_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_1_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_11" + input: "gradients/filter_type_0/add_1_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_1_grad/Sum_1" + input: "gradients/filter_type_0/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_2_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_1_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh" + input: "gradients/filter_type_0/Reshape_2_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_grad/TanhGrad" + input: "gradients/filter_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_grad/Sum" + input: "gradients/filter_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_grad/Reshape" + input: "filter_type_0/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Sum" + op: "Sum" + input: "gradients/AddN_11" + input: "gradients/filter_type_0/add_1_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_1_grad/Sum" + input: "gradients/filter_type_0/add_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_1_grad/Reshape" + input: "gradients/filter_type_0/concat_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_1_grad/Reshape" + input: "gradients/filter_type_0/concat_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_15" + op: "AddN" + input: "gradients/filter_type_0/concat_grad/Slice" + input: "gradients/filter_type_0/concat_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/Reshape_1_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_15" + input: "gradients/filter_type_0/Reshape_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Pad" + op: "Pad" + input: "gradients/filter_type_0/Reshape_1_grad/Reshape" + input: "gradients/filter_type_0/Slice_1_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/Slice_1_grad/Pad" + input: "gradients/filter_type_0/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_3_grad/MatMul" + op: "BatchMatMul" + input: "filter_type_0/Reshape_5" + input: "gradients/filter_type_0/add_12_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/Reshape_6_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/MatMul_3_grad/MatMul" + input: "gradients/filter_type_0/Reshape_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_19" + op: "AddN" + input: "gradients/filter_type_0/Reshape_6_grad/Reshape" + input: "gradients/filter_type_0/Reshape_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Reshape_6_grad/Reshape" + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Pad" + op: "Pad" + input: "gradients/AddN_19" + input: "gradients/filter_type_0/Slice_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_23" + op: "AddN" + input: "gradients/filter_type_0/Slice_grad/Pad" + input: "gradients/filter_type_0/Slice_2_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Slice_grad/Pad" + } + } + } +} +node { + name: "gradients/Reshape_7_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_23" + input: "gradients/Reshape_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/Pad" + op: "Pad" + input: "gradients/Reshape_7_grad/Reshape" + input: "gradients/Slice_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_25" + op: "AddN" + input: "gradients/Slice_grad/Pad" + input: "gradients/Slice_1_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/Slice_grad/Pad" + } + } + } +} +node { + name: "gradients/Reshape_6_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_25" + input: "gradients/Reshape_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_19" + op: "Reshape" + input: "gradients/Reshape_6_grad/Reshape" + input: "Reshape_19/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "ProdVirialSeA" + op: "ProdVirialSeA" + input: "Reshape_19" + input: "o_rmat_deriv" + input: "o_rij" + input: "o_nlist" + input: "t_natoms" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "n_a_sel" + value { + i: 138 + } + } + attr { + key: "n_r_sel" + value { + i: 0 + } + } +} +node { + name: "o_atom_virial" + op: "Reshape" + input: "ProdVirialSeA:1" + input: "o_atom_virial/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_virial" + op: "Reshape" + input: "ProdVirialSeA" + input: "o_virial/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "ProdForceSeA" + op: "ProdForceSeA" + input: "Reshape_19" + input: "o_rmat_deriv" + input: "o_nlist" + input: "t_natoms" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "n_a_sel" + value { + i: 138 + } + } + attr { + key: "n_r_sel" + value { + i: 0 + } + } +} +node { + name: "o_force" + op: "Reshape" + input: "ProdForceSeA" + input: "o_force/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_atom_energy" + op: "Reshape" + input: "Reshape_18" + input: "o_atom_energy/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_energy" + op: "Sum" + input: "o_atom_energy" + input: "o_energy/reduction_indices" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +library { +} diff --git a/source/tests/test_transform.py b/source/tests/test_transform.py new file mode 100644 index 0000000000..c019089629 --- /dev/null +++ b/source/tests/test_transform.py @@ -0,0 +1,69 @@ +import os,sys,platform,shutil,dpdata +import numpy as np +import unittest + +from deepmd.env import tf +from deepmd import DeepPot +from common import tests_path +from infer.convert2pb import convert_pbtxt_to_pb +from deepmd.transform import load_graph, transform_graph + +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +if GLOBAL_NP_FLOAT_PRECISION == np.float32 : + default_places = 4 +else : + default_places = 10 + +class TestTransform(unittest.TestCase) : + def setUp(self): + convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot.pbtxt")), "deeppot.pb") + convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot-1.pbtxt")), "deeppot-1.pb") + self.graph0 = load_graph("deeppot.pb") + self.graph1 = load_graph("deeppot-1.pb") + self.coords = np.array([12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56]) + self.atype = [0, 1, 1, 0, 1, 1] + self.box = np.array([13., 0., 0., 0., 13., 0., 0., 0., 13.]) + self.expected_e = np.array([-9.275780747115504710e+01,-1.863501786584258468e+02,-1.863392472863538103e+02,-9.279281325486221021e+01,-1.863671545232153903e+02,-1.863619822847602165e+02]) + self.expected_f = np.array([-3.034045420701179663e-01,8.405844663871177014e-01,7.696947487118485642e-02,7.662001266663505117e-01,-1.880601391333554251e-01,-6.183333871091722944e-01,-5.036172391059643427e-01,-6.529525836149027151e-01,5.432962643022043459e-01,6.382357912332115024e-01,-1.748518296794561167e-01,3.457363524891907125e-01,1.286482986991941552e-03,3.757251165286925043e-01,-5.972588700887541124e-01,-5.987006197104716154e-01,-2.004450304880958100e-01,2.495901655353461868e-01]) + self.expected_v = np.array([-2.912234126853306959e-01,-3.800610846612756388e-02,2.776624987489437202e-01,-5.053761003913598976e-02,-3.152373041953385746e-01,1.060894290092162379e-01,2.826389131596073745e-01,1.039129970665329250e-01,-2.584378792325942586e-01,-3.121722367954994914e-01,8.483275876786681990e-02,2.524662342344257682e-01,4.142176771106586414e-02,-3.820285230785245428e-02,-2.727311173065460545e-02,2.668859789777112135e-01,-6.448243569420382404e-02,-2.121731470426218846e-01,-8.624335220278558922e-02,-1.809695356746038597e-01,1.529875294531883312e-01,-1.283658185172031341e-01,-1.992682279795223999e-01,1.409924999632362341e-01,1.398322735274434292e-01,1.804318474574856390e-01,-1.470309318999652726e-01,-2.593983661598450730e-01,-4.236536279233147489e-02,3.386387920184946720e-02,-4.174017537818433543e-02,-1.003500282164128260e-01,1.525690815194478966e-01,3.398976109910181037e-02,1.522253908435125536e-01,-2.349125581341701963e-01,9.515545977581392825e-04,-1.643218849228543846e-02,1.993234765412972564e-02,6.027265332209678569e-04,-9.563256398907417355e-02,1.510815124001868293e-01,-7.738094816888557714e-03,1.502832772532304295e-01,-2.380965783745832010e-01,-2.309456719810296654e-01,-6.666961081213038098e-02,7.955566551234216632e-02,-8.099093777937517447e-02,-3.386641099800401927e-02,4.447884755740908608e-02,1.008593228579038742e-01,4.556718179228393811e-02,-6.078081273849572641e-02]) + + def tearDown(self): + os.remove("deeppot.pb") + os.remove("deeppot-1.pb") + + def test(self): + raw_graph = load_graph("deeppot-1.pb") + old_graph = load_graph("deeppot.pb") + new_graph_def = transform_graph(raw_graph,old_graph) + with tf.gfile.GFile("deeppot-2.pb", mode='wb') as f: + f.write(new_graph_def.SerializeToString()) + self.dp = DeepPot("deeppot-2.pb") + os.remove("deeppot-2.pb") + ee, ff, vv, ae, av = self.dp.eval(self.coords, self.box, self.atype, atomic = True) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + self.assertEqual(ae.shape, (nframes,natoms,1)) + self.assertEqual(av.shape, (nframes,natoms,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + for ii in range(ae.size): + self.assertAlmostEqual(ae.reshape([-1])[ii], self.expected_e.reshape([-1])[ii], places = default_places) + for ii in range(av.size): + self.assertAlmostEqual(av.reshape([-1])[ii], self.expected_v.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + From 2d9c7029289fbf1ff3d2cd95504b400e8bf19372 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 22 Feb 2021 09:44:01 +0800 Subject: [PATCH 189/562] remove duplicated code in test_transform --- source/tests/test_transform.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/source/tests/test_transform.py b/source/tests/test_transform.py index c019089629..ddb7b7653b 100644 --- a/source/tests/test_transform.py +++ b/source/tests/test_transform.py @@ -18,8 +18,6 @@ class TestTransform(unittest.TestCase) : def setUp(self): convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot.pbtxt")), "deeppot.pb") convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot-1.pbtxt")), "deeppot-1.pb") - self.graph0 = load_graph("deeppot.pb") - self.graph1 = load_graph("deeppot-1.pb") self.coords = np.array([12.83, 2.56, 2.18, 12.09, 2.87, 2.74, 00.25, 3.32, 1.68, @@ -37,9 +35,9 @@ def tearDown(self): os.remove("deeppot-1.pb") def test(self): - raw_graph = load_graph("deeppot-1.pb") - old_graph = load_graph("deeppot.pb") - new_graph_def = transform_graph(raw_graph,old_graph) + self.graph0 = load_graph("deeppot.pb") + self.graph1 = load_graph("deeppot-1.pb") + new_graph_def = transform_graph(self.graph1, self.graph0) with tf.gfile.GFile("deeppot-2.pb", mode='wb') as f: f.write(new_graph_def.SerializeToString()) self.dp = DeepPot("deeppot-2.pb") From ed3aa4b761d587e777e794366cff6a69b616a91a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Mon, 22 Feb 2021 11:54:47 +0100 Subject: [PATCH 190/562] fix op module not being found --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 390b18834e..ac8a6abb02 100644 --- a/setup.py +++ b/setup.py @@ -84,7 +84,8 @@ "deepmd/loss", "deepmd/utils", "deepmd/loggers", - "deepmd/cluster" + "deepmd/cluster", + "deepmd/op" ], python_requires=">=3.6", classifiers=[ From c024755369ac6984c6bff481df1ad36bca450e1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Mon, 22 Feb 2021 15:04:16 +0100 Subject: [PATCH 191/562] fix DeepPotential factory tests --- deepmd/infer/__init__.py | 20 ++++----- deepmd/infer/deep_dipole.py | 22 ++++++++-- deepmd/infer/deep_eval.py | 26 ++++++++--- deepmd/infer/deep_polar.py | 23 +++++++--- deepmd/infer/deep_pot.py | 68 ++++++++++++++++++----------- deepmd/infer/deep_wfc.py | 21 +++++++-- source/tests/test_deepdipole.py | 2 +- source/tests/test_deeppolar.py | 2 +- source/tests/test_deeppot.py | 2 +- source/tests/test_get_potential.py | 70 ++++++++++++++++++++++-------- source/tests/test_transform.py | 4 +- 11 files changed, 181 insertions(+), 79 deletions(-) diff --git a/deepmd/infer/__init__.py b/deepmd/infer/__init__.py index b76fbf1b7e..75ec05e097 100644 --- a/deepmd/infer/__init__.py +++ b/deepmd/infer/__init__.py @@ -50,26 +50,26 @@ def DeepPotential( RuntimeError if model file does not correspond to any implementd potential """ + mf = Path(model_file) + model_type = DeepEval( - str(model_file), load_prefix=load_prefix, default_tf_graph=default_tf_graph + mf, load_prefix=load_prefix, default_tf_graph=default_tf_graph ).model_type + print(mf, model_type) + if model_type == "ener": - dp = DeepPot(model_file, prefix=load_prefix, default_tf_graph=default_tf_graph) + dp = DeepPot(mf, load_prefix=load_prefix, default_tf_graph=default_tf_graph) elif model_type == "dipole": - dp = DeepDipole( - model_file, prefix=load_prefix, default_tf_graph=default_tf_graph - ) + dp = DeepDipole(mf, load_prefix=load_prefix, default_tf_graph=default_tf_graph) elif model_type == "polar": - dp = DeepPolar( - model_file, prefix=load_prefix, default_tf_graph=default_tf_graph - ) + dp = DeepPolar(mf, load_prefix=load_prefix, default_tf_graph=default_tf_graph) elif model_type == "global_polar": dp = DeepGlobalPolar( - model_file, prefix=load_prefix, default_tf_graph=default_tf_graph + mf, load_prefix=load_prefix, default_tf_graph=default_tf_graph ) elif model_type == "wfc": - dp = DeepWFC(model_file, prefix=load_prefix, default_tf_graph=default_tf_graph) + dp = DeepWFC(mf, load_prefix=load_prefix, default_tf_graph=default_tf_graph) else: raise RuntimeError(f"unknow model type {model_type}") diff --git a/deepmd/infer/deep_dipole.py b/deepmd/infer/deep_dipole.py index e3eb62a6b4..7ad3ee49a5 100644 --- a/deepmd/infer/deep_dipole.py +++ b/deepmd/infer/deep_dipole.py @@ -1,29 +1,43 @@ +from typing import TYPE_CHECKING + from deepmd.infer.deep_eval import DeepTensor +if TYPE_CHECKING: + from pathlib import Path + class DeepDipole(DeepTensor): """Constructor. Parameters ---------- - model_file : str + model_file : Path The name of the frozen model file. load_prefix: str The prefix in the load computational graph default_tf_graph : bool If uses the default tf graph, otherwise build a new tf graph for evaluation + + Warnings + -------- + For developers: `DeepTensor` initializer must be called at the end after + `self.tensors` are modified because it uses the data in `self.tensors` dict. + Do not chanage the order! """ def __init__( - self, model_file: str, load_prefix: str = "load", default_tf_graph: bool = False + self, model_file: "Path", load_prefix: str = "load", default_tf_graph: bool = False ) -> None: - self.tensors.update( + # use this in favor of dict update to move attribute from class to + # instance namespace + self.tensors = dict( { "t_sel_type": "model_attr/sel_type:0", # output tensor "t_tensor": "o_dipole:0", - } + }, + **self.tensors ) DeepTensor.__init__( diff --git a/deepmd/infer/deep_eval.py b/deepmd/infer/deep_eval.py index b51d9248ec..4add62c151 100644 --- a/deepmd/infer/deep_eval.py +++ b/deepmd/infer/deep_eval.py @@ -1,26 +1,37 @@ import os -from typing import List, Optional +from typing import List, Optional, TYPE_CHECKING import numpy as np from deepmd.common import make_default_mesh from deepmd.env import default_tf_session_config, tf +if TYPE_CHECKING: + from pathlib import Path + class DeepEval: """Common methods for DeepPot, DeepWFC, DeepPolar, ...""" - _model_type: Optional[str] + _model_type: Optional[str] = None + load_prefix: str # set by subclass def __init__( - self, model_file: str, load_prefix: str = "load", default_tf_graph: bool = False + self, + model_file: "Path", + load_prefix: str = "load", + default_tf_graph: bool = False ): self.graph = self._load_graph( model_file, prefix=load_prefix, default_tf_graph=default_tf_graph ) + self.load_prefix = load_prefix @property def model_type(self) -> str: + """Get type of model. + :type:str + """ if not self._model_type: t_mt = self._get_tensor("model_attr/model_type:0") sess = tf.Session(graph=self.graph, config=default_tf_session_config) @@ -57,11 +68,13 @@ def _get_tensor( @staticmethod def _load_graph( - frozen_graph_filename: str, prefix: str = "load", default_tf_graph: bool = False + frozen_graph_filename: "Path", prefix: str = "load", default_tf_graph: bool = False ): + + # We load the protobuf file from the disk and parse it to retrieve the # unserialized graph_def - with tf.gfile.GFile(frozen_graph_filename, "rb") as f: + with tf.gfile.GFile(str(frozen_graph_filename), "rb") as f: graph_def = tf.GraphDef() graph_def.ParseFromString(f.read()) @@ -119,7 +132,7 @@ class DeepTensor(DeepEval): def __init__( self, - model_file: str, + model_file: "Path", variable_dof: Optional[int], load_prefix: str = 'load', default_tf_graph: bool = False @@ -131,7 +144,6 @@ def __init__( default_tf_graph=default_tf_graph ) self.variable_dof = variable_dof - self.load_prefix = load_prefix # now load tensors to object attributes for attr_name, tensor_name in self.tensors.items(): diff --git a/deepmd/infer/deep_polar.py b/deepmd/infer/deep_polar.py index 8e7dcec017..48f565faa2 100644 --- a/deepmd/infer/deep_polar.py +++ b/deepmd/infer/deep_polar.py @@ -1,31 +1,44 @@ +from typing import TYPE_CHECKING, List, Optional + import numpy as np -from typing import Optional, List from deepmd.infer.deep_eval import DeepTensor +if TYPE_CHECKING: + from pathlib import Path + class DeepPolar(DeepTensor): """Constructor. Parameters ---------- - model_file : str + model_file : Path The name of the frozen model file. load_prefix: str The prefix in the load computational graph default_tf_graph : bool If uses the default tf graph, otherwise build a new tf graph for evaluation + + Warnings + -------- + For developers: `DeepTensor` initializer must be called at the end after + `self.tensors` are modified because it uses the data in `self.tensors` dict. + Do not chanage the order! """ def __init__( - self, model_file: str, load_prefix: str = "load", default_tf_graph: bool = False + self, model_file: "Path", load_prefix: str = "load", default_tf_graph: bool = False ) -> None: - self.tensors.update( + # use this in favor of dict update to move attribute from class to + # instance namespace + self.tensors = dict( { "t_sel_type": "model_attr/sel_type:0", # output tensor "t_tensor": "o_polar:0", - } + }, + **self.tensors ) DeepTensor.__init__( diff --git a/deepmd/infer/deep_pot.py b/deepmd/infer/deep_pot.py index 07b2116770..80157642ee 100644 --- a/deepmd/infer/deep_pot.py +++ b/deepmd/infer/deep_pot.py @@ -1,9 +1,13 @@ +import logging +from typing import TYPE_CHECKING, List, Optional, Tuple + import numpy as np -from typing import List, Optional, Tuple from deepmd.common import make_default_mesh from deepmd.infer.data_modifier import DipoleChargeModifier -from deepmd.infer.deep_eval import DeepTensor -import logging +from deepmd.infer.deep_eval import DeepEval, DeepTensor + +if TYPE_CHECKING: + from pathlib import Path log = logging.getLogger(__name__) @@ -13,48 +17,63 @@ class DeepPot(DeepTensor): Parameters ---------- - model_file : str + model_file : Path The name of the frozen model file. load_prefix: str The prefix in the load computational graph default_tf_graph : bool If uses the default tf graph, otherwise build a new tf graph for evaluation + + Warnings + -------- + For developers: `DeepTensor` initializer must be called at the end after + `self.tensors` are modified because it uses the data in `self.tensors` dict. + Do not chanage the order! """ def __init__( self, - model_file: str, + model_file: "Path", load_prefix: str = "load", default_tf_graph: bool = False ) -> None: - # this tensor does not apply here so delete it - self.tensors.pop("t_sel_type") - # add these tensors on top of what is defined by DeepTensor Class - self.tensors.update({ - # general - "t_dfparam": "fitting_attr/dfparam:0", - "t_daparam": "fitting_attr/daparam:0", - # add output tensors - "t_energy": "o_energy:0", - "t_force": "o_force:0", - "t_virial": "o_virial:0", - "t_ae": "o_atom_energy:0", - "t_av": "o_atom_virial:0" - }) + # use this in favor of dict update to move attribute from class to + # instance namespace + self.tensors = dict( + { + # general + "t_dfparam": "fitting_attr/dfparam:0", + "t_daparam": "fitting_attr/daparam:0", + # add output tensors + "t_energy": "o_energy:0", + "t_force": "o_force:0", + "t_virial": "o_virial:0", + "t_ae": "o_atom_energy:0", + "t_av": "o_atom_virial:0" + }, + **self.tensors + ) + DeepEval.__init__( + self, + model_file, + load_prefix=load_prefix, + default_tf_graph=default_tf_graph + ) - try: + # load optional tensors + operations = [op.name for op in self.graph.get_operations()] + # check if the graph has these operations: + # if yes add them + if 't_efield' in operations: self._get_tensor("t_efield:0", "t_efield") self.has_efield = True - except KeyError: + else: log.debug(f"Could not get tensor 't_efield:0'") self.t_efield = None self.has_efield = False - # load optional tensors - operations = [op.name for op in self.graph.get_operations()] - if 'load/t_fparam' in operations: self.tensors.update({"t_fparam": "t_fparam:0"}) self.has_fparam = True @@ -63,7 +82,6 @@ def __init__( self.t_fparam = None self.has_fparam = False - # check if the graph has aparam if 'load/t_aparam' in operations: self.tensors.update({"t_aparam": "t_aparam:0"}) self.has_aparam = True diff --git a/deepmd/infer/deep_wfc.py b/deepmd/infer/deep_wfc.py index bc097378fb..1f976af04a 100644 --- a/deepmd/infer/deep_wfc.py +++ b/deepmd/infer/deep_wfc.py @@ -1,4 +1,8 @@ from deepmd.infer.deep_eval import DeepTensor +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pathlib import Path class DeepWFC(DeepTensor): @@ -6,24 +10,33 @@ class DeepWFC(DeepTensor): Parameters ---------- - model_file : str + model_file : Path The name of the frozen model file. load_prefix: str The prefix in the load computational graph default_tf_graph : bool If uses the default tf graph, otherwise build a new tf graph for evaluation + + Warnings + -------- + For developers: `DeepTensor` initializer must be called at the end after + `self.tensors` are modified because it uses the data in `self.tensors` dict. + Do not chanage the order! """ def __init__( - self, model_file: str, load_prefix: str = "load", default_tf_graph: bool = False + self, model_file: "Path", load_prefix: str = "load", default_tf_graph: bool = False ) -> None: - self.tensors.update( + # use this in favor of dict update to move attribute from class to + # instance namespace + self.tensors = dict( { "t_sel_type": "model_attr/sel_type:0", # output tensor "t_tensor": "o_wfc:0", - } + }, + **self.tensors ) DeepTensor.__init__( self, diff --git a/source/tests/test_deepdipole.py b/source/tests/test_deepdipole.py index 2d7881e554..6d0e84aa14 100644 --- a/source/tests/test_deepdipole.py +++ b/source/tests/test_deepdipole.py @@ -3,7 +3,7 @@ import unittest from infer.convert2pb import convert_pbtxt_to_pb -from deepmd import DeepDipole +from deepmd.infer import DeepDipole from common import tests_path from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION diff --git a/source/tests/test_deeppolar.py b/source/tests/test_deeppolar.py index 434214ac6c..da0fd6b377 100644 --- a/source/tests/test_deeppolar.py +++ b/source/tests/test_deeppolar.py @@ -3,7 +3,7 @@ import unittest from infer.convert2pb import convert_pbtxt_to_pb -from deepmd import DeepPolar +from deepmd.infer import DeepPolar from common import tests_path from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION diff --git a/source/tests/test_deeppot.py b/source/tests/test_deeppot.py index f758b609c0..a513ad492d 100644 --- a/source/tests/test_deeppot.py +++ b/source/tests/test_deeppot.py @@ -3,7 +3,7 @@ import unittest from infer.convert2pb import convert_pbtxt_to_pb -from deepmd import DeepPot +from deepmd.infer import DeepPot from common import tests_path from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION diff --git a/source/tests/test_get_potential.py b/source/tests/test_get_potential.py index 2bb801968f..8637b7ff66 100644 --- a/source/tests/test_get_potential.py +++ b/source/tests/test_get_potential.py @@ -1,35 +1,67 @@ +"""Test if `DeepPotential` facto function returns the right type of potential.""" + import unittest from pathlib import Path -from shutil import rmtree -from deepmd.infer import DeepPotential, DeepDipole, DeepGlobalPolar, DeepPolar, DeepPot, DeepWFC -from deepmd.env import tf +from deepmd.infer import (DeepDipole, DeepGlobalPolar, DeepPolar, DeepPot, + DeepPotential, DeepWFC) + +from infer.convert2pb import convert_pbtxt_to_pb class TestGetPotential(unittest.TestCase): def setUp(self): - self.work_dir = Path(__file__).parent / "test_get_potential" - self.work_dir.mkdir(exist_ok=True) - # TODO create all types of graphs - ... + self.work_dir = Path(__file__).parent / "infer" + + convert_pbtxt_to_pb( + str(self.work_dir / "deeppot.pbtxt"), + str(self.work_dir / "deep_pot.pb") + ) + + convert_pbtxt_to_pb( + str(self.work_dir / "deepdipole.pbtxt"), + str(self.work_dir / "deep_dipole.pb") + ) + + convert_pbtxt_to_pb( + str(self.work_dir / "deeppolar.pbtxt"), + str(self.work_dir / "deep_polar.pb") + ) + + # TODO add model files for globalpolar and WFC + # convert_pbtxt_to_pb( + # str(self.work_dir / "deepglobalpolar.pbtxt"), + # str(self.work_dir / "deep_globalpolar.pb") + # ) + + # convert_pbtxt_to_pb( + # str(self.work_dir / "deepwfc.pbtxt"), + # str(self.work_dir / "deep_wfc.pb") + # ) def tearDown(self): - rmtree(self.work_dir) + for f in self.work_dir.glob("*.pb"): + f.unlink() + + def test_factory(self): - def test_merge_all_stat(self): + msg = "Returned wrong type of potential. Expected: {}, got: {}" - dp = DeepPotential(self.work_dir / "deep_pot_model.pb") - self.assertIsInstance(dp, DeepPot, "Returned wrong type of potential") + dp = DeepPotential(self.work_dir / "deep_dipole.pb") + self.assertIsInstance(dp, DeepDipole, msg.format(DeepDipole, type(dp))) - dp = DeepPotential(self.work_dir / "deep_polar_model.pb") - self.assertIsInstance(dp, DeepPolar, "Returned wrong type of potential") + dp = DeepPotential(self.work_dir / "deep_polar.pb") + self.assertIsInstance(dp, DeepPolar, msg.format(DeepPolar, type(dp))) - dp = DeepPotential(self.work_dir / "deep_global_polar_model.pb") - self.assertIsInstance(dp, DeepGlobalPolar, "Returned wrong type of potential") + dp = DeepPotential(self.work_dir / "deep_pot.pb") + self.assertIsInstance(dp, DeepPot, msg.format(DeepPot, type(dp))) - dp = DeepPotential(self.work_dir / "deep_wfc_model.pb") - self.assertIsInstance(dp, DeepWFC, "Returned wrong type of potential") + # TODO add model files for globalpolar and WFC + # dp = DeepPotential(self.work_dir / "deep_globalpolar.pb") + # self.assertIsInstance( + # dp, DeepGlobalPolar, msg.format(DeepGlobalPolar, type(dp)) + # ) - dp = DeepPotential(self.work_dir / "deep_dipole_model.pb") - self.assertIsInstance(dp, DeepDipole, "Returned wrong type of potential") + # dp = DeepPotential(self.work_dir / "deep_wfc.pb") + # self.assertIsInstance(dp, DeepWFC, msg.format(DeepWFC, type(dp))) diff --git a/source/tests/test_transform.py b/source/tests/test_transform.py index ddb7b7653b..bbc0719f0f 100644 --- a/source/tests/test_transform.py +++ b/source/tests/test_transform.py @@ -3,10 +3,10 @@ import unittest from deepmd.env import tf -from deepmd import DeepPot +from deepmd.infer import DeepPot from common import tests_path from infer.convert2pb import convert_pbtxt_to_pb -from deepmd.transform import load_graph, transform_graph +from deepmd.entrypoints.transfer import load_graph, transform_graph from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION if GLOBAL_NP_FLOAT_PRECISION == np.float32 : From 2f24b5d1bb33c8a04587dfb0c5fbb67af034671d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Mon, 22 Feb 2021 15:44:19 +0100 Subject: [PATCH 192/562] remove forgotten debug prints --- deepmd/entrypoints/transfer.py | 9 +++-- source/tests/test_transfer.py | 67 ++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 source/tests/test_transfer.py diff --git a/deepmd/entrypoints/transfer.py b/deepmd/entrypoints/transfer.py index d2d583fdb2..3e1aa1b5f2 100644 --- a/deepmd/entrypoints/transfer.py +++ b/deepmd/entrypoints/transfer.py @@ -121,15 +121,16 @@ def transform_graph(raw_graph: tf.Graph, old_graph: tf.Graph) -> tf.Graph: continue old_node = old_graph_node[node.name] + raw_node = raw_graph_node[node.name] cp_attr = CopyNodeAttr(node) check_dim(raw_graph_node, old_graph_node, node.name) - tensor_shape = [dim.size for dim in node.tensor_shape.dim] + tensor_shape = [dim.size for dim in raw_node.tensor_shape.dim] old_graph_dtype = PRECISION_MAPPING[old_node.dtype] - raw_graph_dtype = PRECISION_MAPPING[node.dtype] + raw_graph_dtype = PRECISION_MAPPING[raw_node.dtype] log.info( - f"{node.name:s} is passed from old graph({old_graph_dtype:s}) " - f"to raw graph({raw_graph_dtype:s})" + f"{node.name} is passed from old graph({old_graph_dtype}) " + f"to raw graph({raw_graph_dtype})" ) if raw_graph_dtype == np.float16: diff --git a/source/tests/test_transfer.py b/source/tests/test_transfer.py new file mode 100644 index 0000000000..bbc0719f0f --- /dev/null +++ b/source/tests/test_transfer.py @@ -0,0 +1,67 @@ +import os,sys,platform,shutil,dpdata +import numpy as np +import unittest + +from deepmd.env import tf +from deepmd.infer import DeepPot +from common import tests_path +from infer.convert2pb import convert_pbtxt_to_pb +from deepmd.entrypoints.transfer import load_graph, transform_graph + +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +if GLOBAL_NP_FLOAT_PRECISION == np.float32 : + default_places = 4 +else : + default_places = 10 + +class TestTransform(unittest.TestCase) : + def setUp(self): + convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot.pbtxt")), "deeppot.pb") + convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot-1.pbtxt")), "deeppot-1.pb") + self.coords = np.array([12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56]) + self.atype = [0, 1, 1, 0, 1, 1] + self.box = np.array([13., 0., 0., 0., 13., 0., 0., 0., 13.]) + self.expected_e = np.array([-9.275780747115504710e+01,-1.863501786584258468e+02,-1.863392472863538103e+02,-9.279281325486221021e+01,-1.863671545232153903e+02,-1.863619822847602165e+02]) + self.expected_f = np.array([-3.034045420701179663e-01,8.405844663871177014e-01,7.696947487118485642e-02,7.662001266663505117e-01,-1.880601391333554251e-01,-6.183333871091722944e-01,-5.036172391059643427e-01,-6.529525836149027151e-01,5.432962643022043459e-01,6.382357912332115024e-01,-1.748518296794561167e-01,3.457363524891907125e-01,1.286482986991941552e-03,3.757251165286925043e-01,-5.972588700887541124e-01,-5.987006197104716154e-01,-2.004450304880958100e-01,2.495901655353461868e-01]) + self.expected_v = np.array([-2.912234126853306959e-01,-3.800610846612756388e-02,2.776624987489437202e-01,-5.053761003913598976e-02,-3.152373041953385746e-01,1.060894290092162379e-01,2.826389131596073745e-01,1.039129970665329250e-01,-2.584378792325942586e-01,-3.121722367954994914e-01,8.483275876786681990e-02,2.524662342344257682e-01,4.142176771106586414e-02,-3.820285230785245428e-02,-2.727311173065460545e-02,2.668859789777112135e-01,-6.448243569420382404e-02,-2.121731470426218846e-01,-8.624335220278558922e-02,-1.809695356746038597e-01,1.529875294531883312e-01,-1.283658185172031341e-01,-1.992682279795223999e-01,1.409924999632362341e-01,1.398322735274434292e-01,1.804318474574856390e-01,-1.470309318999652726e-01,-2.593983661598450730e-01,-4.236536279233147489e-02,3.386387920184946720e-02,-4.174017537818433543e-02,-1.003500282164128260e-01,1.525690815194478966e-01,3.398976109910181037e-02,1.522253908435125536e-01,-2.349125581341701963e-01,9.515545977581392825e-04,-1.643218849228543846e-02,1.993234765412972564e-02,6.027265332209678569e-04,-9.563256398907417355e-02,1.510815124001868293e-01,-7.738094816888557714e-03,1.502832772532304295e-01,-2.380965783745832010e-01,-2.309456719810296654e-01,-6.666961081213038098e-02,7.955566551234216632e-02,-8.099093777937517447e-02,-3.386641099800401927e-02,4.447884755740908608e-02,1.008593228579038742e-01,4.556718179228393811e-02,-6.078081273849572641e-02]) + + def tearDown(self): + os.remove("deeppot.pb") + os.remove("deeppot-1.pb") + + def test(self): + self.graph0 = load_graph("deeppot.pb") + self.graph1 = load_graph("deeppot-1.pb") + new_graph_def = transform_graph(self.graph1, self.graph0) + with tf.gfile.GFile("deeppot-2.pb", mode='wb') as f: + f.write(new_graph_def.SerializeToString()) + self.dp = DeepPot("deeppot-2.pb") + os.remove("deeppot-2.pb") + ee, ff, vv, ae, av = self.dp.eval(self.coords, self.box, self.atype, atomic = True) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + self.assertEqual(ae.shape, (nframes,natoms,1)) + self.assertEqual(av.shape, (nframes,natoms,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + for ii in range(ae.size): + self.assertAlmostEqual(ae.reshape([-1])[ii], self.expected_e.reshape([-1])[ii], places = default_places) + for ii in range(av.size): + self.assertAlmostEqual(av.reshape([-1])[ii], self.expected_v.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + From ece66cf88e5969d01307d72d7d9dcb10e2b711a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Mon, 22 Feb 2021 17:11:27 +0100 Subject: [PATCH 193/562] added log level setting for tensorflow and OpenMP --- deepmd/loggers/loggers.py | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/deepmd/loggers/loggers.py b/deepmd/loggers/loggers.py index 8a27cf7797..063cce7ba3 100644 --- a/deepmd/loggers/loggers.py +++ b/deepmd/loggers/loggers.py @@ -1,6 +1,7 @@ """Logger initialization for package.""" import logging +import os from typing import TYPE_CHECKING, Optional if TYPE_CHECKING: @@ -165,10 +166,34 @@ def set_log_handles( References ---------- https://groups.google.com/g/mpi4py/c/SaNzc8bdj6U + https://stackoverflow.com/questions/35869137/avoid-tensorflow-print-on-standard-error + https://stackoverflow.com/questions/56085015/suppress-openmp-debug-messages-when-running-tensorflow-on-cpu + + Notes + ----- + Logging levels: + + +---------+--------------+----------------+----------------+----------------+ + | | our notation | python logging | tensorflow cpp | OpenMP | + +=========+==============+================+================+================+ + | debug | 3 | 10 | 0 | 1/on/true/yes | + +---------+--------------+----------------+----------------+----------------+ + | info | 2 | 20 | 1 | 0/off/false/no | + +---------+--------------+----------------+----------------+----------------+ + | warning | 1 | 30 | 2 | 0/off/false/no | + +---------+--------------+----------------+----------------+----------------+ + | error | 0 | 40 | 3 | 0/off/false/no | + +---------+--------------+----------------+----------------+----------------+ + """ - # convert 0 - 3 to python logging level - # we have debug=3 -> logging.DEBUG = 10 - # we have error=0 -> logging.ERROR = 40 + # silence logging for OpenMP when running on CPU if level is any other than debug + if level >= 3: + os.environ["KMP_WARNINGS"] = "FALSE" + + # set TF cpp internal logging level + os.environ['TF_CPP_MIN_LOG_LEVEL'] = str(3 - level) + + # set python logging level level = (4 - level) * 10 # get root logger From 64eb1844403a0c7519de8f7a5f9870dd259254f3 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Tue, 23 Feb 2021 02:56:14 +0800 Subject: [PATCH 194/562] add unittest for TestEnvMatA gpu implementation --- .gitmodules | 4 +- source/api_cc/include/common.h | 21 + source/api_cc/src/common.cc | 13 + source/lib/CMakeLists.txt | 5 +- source/lib/include/DeviceFunctor.h | 20 +- source/lib/include/device_common.h | 13 + source/lib/include/gpu_nv.h | 59 +++ source/lib/include/prod_env_mat.h | 20 +- source/{op => lib/src}/cuda/CMakeLists.txt | 2 + source/lib/src/cuda/cub | 1 + source/lib/src/cuda/descrpt_se_a.cu | 385 +++++++++++++++ source/{op => lib/src}/cuda/descrpt_se_r.cu | 1 + source/{op => lib/src}/cuda/gelu.cu | 1 + .../{op => lib/src}/cuda/prod_force_se_a.cu | 1 + .../{op => lib/src}/cuda/prod_force_se_r.cu | 1 + .../{op => lib/src}/cuda/prod_virial_se_a.cu | 1 + .../{op => lib/src}/cuda/prod_virial_se_r.cu | 1 + source/{op => lib/src}/cuda/tabulate.cu | 1 + source/lib/src/prod_env_mat.cc | 131 +++--- source/lib/tests/CMakeLists.txt | 31 +- source/lib/tests/test_env_mat_a.cc | 221 +++++++++ source/op/CMakeLists.txt | 9 +- source/op/cuda/cub | 1 - source/op/cuda/descrpt_se_a.cu | 438 ------------------ source/op/descrpt_se_a_multi_device.cc | 382 +++++++-------- source/op/descrpt_se_r_multi_device.cc | 15 +- 26 files changed, 995 insertions(+), 783 deletions(-) create mode 100644 source/lib/include/device_common.h create mode 100644 source/lib/include/gpu_nv.h rename source/{op => lib/src}/cuda/CMakeLists.txt (97%) create mode 160000 source/lib/src/cuda/cub create mode 100644 source/lib/src/cuda/descrpt_se_a.cu rename source/{op => lib/src}/cuda/descrpt_se_r.cu (99%) rename source/{op => lib/src}/cuda/gelu.cu (99%) rename source/{op => lib/src}/cuda/prod_force_se_a.cu (99%) rename source/{op => lib/src}/cuda/prod_force_se_r.cu (99%) rename source/{op => lib/src}/cuda/prod_virial_se_a.cu (99%) rename source/{op => lib/src}/cuda/prod_virial_se_r.cu (99%) rename source/{op => lib/src}/cuda/tabulate.cu (99%) delete mode 160000 source/op/cuda/cub delete mode 100644 source/op/cuda/descrpt_se_a.cu diff --git a/.gitmodules b/.gitmodules index c2225c5f76..c7710397a0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "source/op/cuda/cub"] - path = source/op/cuda/cub +[submodule "source/lib/src/cuda/cub"] + path = source/lib/src/cuda/cub url = git://github.com/NVlabs/cub.git diff --git a/source/api_cc/include/common.h b/source/api_cc/include/common.h index 644dc3593d..c3515b2597 100644 --- a/source/api_cc/include/common.h +++ b/source/api_cc/include/common.h @@ -243,3 +243,24 @@ select_map(std::vector & out, } } +// functions used in custom ops +struct DeviceFunctor { + void operator()( + std::string& device, + const CPUDevice& d) + { + device = "CPU"; + } +#if GOOGLE_CUDA + void operator()( + std::string& device, + const GPUDevice& d) + { + device = "GPU"; + } +#endif // GOOGLE_CUDA +}; + +void cum_sum( + std::vector & sec, + const std::vector & n_sel); \ No newline at end of file diff --git a/source/api_cc/src/common.cc b/source/api_cc/src/common.cc index 23fc998560..bbd587764a 100644 --- a/source/api_cc/src/common.cc +++ b/source/api_cc/src/common.cc @@ -1,6 +1,7 @@ #include "common.h" #include "NNPAtomMap.h" #include "SimulationRegion.h" +#include "device_common.h" void select_by_type(std::vector & fwd_map, @@ -724,3 +725,15 @@ session_input_tensors ( } return nloc; } + +// functions used in custom ops +void cum_sum( + std::vector & sec, + const std::vector & n_sel) +{ + sec.resize (n_sel.size() + 1); + sec[0] = 0; + for (int ii = 1; ii < sec.size(); ++ii) { + sec[ii] = sec[ii-1] + n_sel[ii-1]; + } +} \ No newline at end of file diff --git a/source/lib/CMakeLists.txt b/source/lib/CMakeLists.txt index bbc1237a6e..cfad48930c 100644 --- a/source/lib/CMakeLists.txt +++ b/source/lib/CMakeLists.txt @@ -12,7 +12,10 @@ file(GLOB INC_SRC include/*.h ${CMAKE_CURRENT_BINARY_DIR}/version.h) add_library(${libname} SHARED ${LIB_SRC}) if (USE_CUDA_TOOLKIT) - target_link_libraries (${libname} ${CUDA_LIBRARIES}) + add_definitions("-D GOOGLE_CUDA") + add_subdirectory(src/cuda) + set (EXTRA_LIBS ${EXTRA_LIBS} deepmd_op_cuda) + target_link_libraries (${libname} ${CUDA_LIBRARIES} ${EXTRA_LIBS}) endif() if(BUILD_PY_IF) diff --git a/source/lib/include/DeviceFunctor.h b/source/lib/include/DeviceFunctor.h index 82b6cf62fb..fa4a94b004 100644 --- a/source/lib/include/DeviceFunctor.h +++ b/source/lib/include/DeviceFunctor.h @@ -3,25 +3,7 @@ #include #include #include -#include - -typedef unsigned long long int_64; -#define SQRT_2_PI 0.7978845608028654 -#define TPB 256 -#define GPU_MAX_NBOR_SIZE 4096 - -#define cudaErrcheck(res) {cudaAssert((res), __FILE__, __LINE__);} -inline void cudaAssert(cudaError_t code, const char *file, int line, bool abort=true) { - if (code != cudaSuccess) { - fprintf(stderr,"cuda assert: %s %s %d\n", cudaGetErrorString(code), file, line); - if (abort) exit(code); - } -} - -template -struct DescrptSeAFunctor { - void operator()(FPTYPE * descript, FPTYPE * descript_deriv, FPTYPE * rij, int * nlist, const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec, const int max_nbor_size); -}; +#include "device_common.h" template struct DescrptSeRGPUExecuteFunctor { diff --git a/source/lib/include/device_common.h b/source/lib/include/device_common.h new file mode 100644 index 0000000000..7a885c9ad5 --- /dev/null +++ b/source/lib/include/device_common.h @@ -0,0 +1,13 @@ +#pragma once +#include +#include +#include +#include + +#define TPB 256 +#define SQRT_2_PI 0.7978845608028654 +typedef unsigned long long int_64; + +#if GOOGLE_CUDA +#include "gpu_nv.h" +#endif \ No newline at end of file diff --git a/source/lib/include/gpu_nv.h b/source/lib/include/gpu_nv.h new file mode 100644 index 0000000000..72565b886c --- /dev/null +++ b/source/lib/include/gpu_nv.h @@ -0,0 +1,59 @@ +#pragma once +#include + +#define GPU_MAX_NBOR_SIZE 4096 +#define cudaErrcheck(res) {cudaAssert((res), __FILE__, __LINE__);} +inline void cudaAssert(cudaError_t code, const char *file, int line, bool abort=true) { + if (code != cudaSuccess) { + fprintf(stderr,"cuda assert: %s %s %d\n", cudaGetErrorString(code), file, line); + if (abort) exit(code); + } +} + +template +void memcpy_host_to_device( + FPTYPE * device, + std::vector &host) +{ + cudaErrcheck(cudaMemcpy(device, &host[0], sizeof(FPTYPE) * host.size(), cudaMemcpyHostToDevice)); +} + +template +void memcpy_device_to_host( + FPTYPE * device, + std::vector &host) +{ + cudaErrcheck(cudaMemcpy(&host[0], device, sizeof(FPTYPE) * host.size(), cudaMemcpyDeviceToHost)); +} + +template +void malloc_device_memory( + FPTYPE * &device, + std::vector &host) +{ + cudaErrcheck(cudaMalloc((void **)&device, sizeof(FPTYPE) * host.size())); +} + +template +void malloc_device_memory( + FPTYPE * &device, + const int size) +{ + cudaErrcheck(cudaMalloc((void **)&device, sizeof(FPTYPE) * size)); +} + +template +void malloc_device_memory_sync( + FPTYPE * &device, + std::vector &host) +{ + cudaErrcheck(cudaMalloc((void **)&device, sizeof(FPTYPE) * host.size())); + memcpy_host_to_device(device, host); +} + +template +void delete_device_memory( + FPTYPE * device) +{ + cudaErrcheck(cudaFree(device)); +} \ No newline at end of file diff --git a/source/lib/include/prod_env_mat.h b/source/lib/include/prod_env_mat.h index 1348ee02cf..a010eb8181 100644 --- a/source/lib/include/prod_env_mat.h +++ b/source/lib/include/prod_env_mat.h @@ -1,8 +1,6 @@ #pragma once #include -#if GOOGLE_CUDA -#include "DeviceFunctor.h" -#endif +#include "device_common.h" template void prod_env_mat_a_cpu( @@ -15,6 +13,7 @@ void prod_env_mat_a_cpu( const int * ilist, const int * jrange, const int * jlist, + const int max_nbor_size, const FPTYPE * avg, const FPTYPE * std, const int nloc, @@ -47,4 +46,17 @@ void prod_env_mat_a_gpu_nv( const float rcut, const float rcut_smth, const std::vector sec); -#endif \ No newline at end of file + +void env_mat_nbor_update( + bool &init, + int * &ilist, + int * &jrange, + int * &jlist, + int &ilist_size, + int &jrange_size, + int &jlist_size, + int &max_nbor_size, + const int * mesh, + const int size); +#endif + diff --git a/source/op/cuda/CMakeLists.txt b/source/lib/src/cuda/CMakeLists.txt similarity index 97% rename from source/op/cuda/CMakeLists.txt rename to source/lib/src/cuda/CMakeLists.txt index 4f47aa1435..9aed3c1afb 100644 --- a/source/op/cuda/CMakeLists.txt +++ b/source/lib/src/cuda/CMakeLists.txt @@ -81,6 +81,8 @@ else () message(FATAL_ERROR "unsupported CUDA_VERSION " ${CUDA_VERSION} ", please use a newer version (>=7.0) of CUDA toolkit!") endif() +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -DCUB_IGNORE_DEPRECATED_CPP_DIALECT -DCUB_IGNORE_DEPRECATED_CPP_DIALECT") + set (SOURCE_FILES descrpt_se_a.cu descrpt_se_r.cu prod_force_se_a.cu prod_force_se_r.cu prod_virial_se_a.cu prod_virial_se_r.cu gelu.cu tabulate.cu ) diff --git a/source/lib/src/cuda/cub b/source/lib/src/cuda/cub new file mode 160000 index 0000000000..b229817e39 --- /dev/null +++ b/source/lib/src/cuda/cub @@ -0,0 +1 @@ +Subproject commit b229817e3963fc942c7cc2c61715a6b2b2c49bed diff --git a/source/lib/src/cuda/descrpt_se_a.cu b/source/lib/src/cuda/descrpt_se_a.cu new file mode 100644 index 0000000000..e9f2fb8b77 --- /dev/null +++ b/source/lib/src/cuda/descrpt_se_a.cu @@ -0,0 +1,385 @@ +#include +#include +#include +#include "prod_env_mat.h" +#include "gpu_nv.h" + +template < + typename Key, + int BLOCK_THREADS, + int ITEMS_PER_THREAD> +__launch_bounds__ (BLOCK_THREADS) +__global__ void BlockSortKernel( + Key * d_in, + Key * d_out) // Tile of output +{ + enum { TILE_SIZE = BLOCK_THREADS * ITEMS_PER_THREAD }; + // Specialize BlockLoad type for our thread block (uses warp-striped loads for coalescing, then transposes in shared memory to a blocked arrangement) + typedef cub::BlockLoad BlockLoadT; + // Specialize BlockRadixSort type for our thread block + typedef cub::BlockRadixSort BlockRadixSortT; + // Shared memory + __shared__ union TempStorage + { + typename BlockLoadT::TempStorage load; + typename BlockRadixSortT::TempStorage sort; + } temp_storage; + // Per-thread tile items + Key items[ITEMS_PER_THREAD]; + // Our current block's offset + int block_offset = blockIdx.x * TILE_SIZE; + // Load items into a blocked arrangement + BlockLoadT(temp_storage.load).Load(d_in + block_offset, items); + // Barrier for smem reuse + __syncthreads(); + // Sort keys + BlockRadixSortT(temp_storage.sort).SortBlockedToStriped(items); + // Store output in striped fashion + cub::StoreDirectStriped(threadIdx.x, d_out + block_offset, items); +} + +template +__device__ inline FPTYPE dev_dot( + FPTYPE * arr1, + FPTYPE * arr2) +{ + return arr1[0] * arr2[0] + arr1[1] * arr2[1] + arr1[2] * arr2[2]; +} + +template +__device__ inline void spline5_switch( + FPTYPE & vv, + FPTYPE & dd, + FPTYPE & xx, + const float & rmin, + const float & rmax) +{ + if (xx < rmin) { + dd = 0; + vv = 1; + } + else if (xx < rmax) { + FPTYPE uu = (xx - rmin) / (rmax - rmin) ; + FPTYPE du = 1. / (rmax - rmin) ; + vv = uu*uu*uu * (-6 * uu*uu + 15 * uu - 10) + 1; + dd = ( 3 * uu*uu * (-6 * uu*uu + 15 * uu - 10) + uu*uu*uu * (-12 * uu + 15) ) * du; + } + else { + dd = 0; + vv = 0; + } +} + +__global__ void get_i_idx_se_a( + int * i_idx, + const int nloc, + const int * ilist) +{ + const unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x; + if(idx >= nloc) { + return; + } + i_idx[ilist[idx]] = idx; +} + +template +__global__ void format_nlist_fill_a_se_a( + int_64 * key, + const FPTYPE * coord, + const int * type, + const int * jrange, + const int * jlist, + const float rcut, + int * i_idx, + const int MAX_NBOR_SIZE) +{ + // <<>> + const unsigned int idx = blockIdx.x; + const unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y; + + const int nsize = jrange[i_idx[idx] + 1] - jrange[i_idx[idx]]; + if (idy >= nsize) { + return; + } + const int * nei_idx = jlist + jrange[i_idx[idx]]; + // dev_copy(nei_idx, &jlist[jrange[i_idx]], nsize); + int_64 * key_in = key + idx * MAX_NBOR_SIZE; + FPTYPE diff[3]; + const int & j_idx = nei_idx[idy]; + for (int dd = 0; dd < 3; dd++) { + diff[dd] = coord[j_idx * 3 + dd] - coord[idx * 3 + dd]; + } + FPTYPE rr = sqrt(dev_dot(diff, diff)); + if (rr <= rcut) { + key_in[idy] = type[j_idx] * 1E15+ (int_64)(rr * 1.0E13) / 100000 * 100000 + j_idx; + } +} + +__global__ void format_nlist_fill_b_se_a( + int * nlist, + const int nlist_size, + const int nloc, + const int * jrange, + const int * jlist, + int_64 * key, + const int * sec, + const int sec_size, + int * nei_iter_dev, + const int MAX_NBOR_SIZE) +{ + const unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x; + if(idx >= nloc) { + return; + } + + int * row_nlist = nlist + idx * nlist_size; + int * nei_iter = nei_iter_dev + idx * sec_size; + int_64 * key_out = key + nloc * MAX_NBOR_SIZE + idx * MAX_NBOR_SIZE; + for (int ii = 0; ii < sec_size; ii++) { + nei_iter[ii] = sec[ii]; + } + + for (unsigned int kk = 0; key_out[kk] != key_out[MAX_NBOR_SIZE - 1]; kk++) { + const int & nei_type = key_out[kk] / 1E15; + if (nei_iter[nei_type] < sec[nei_type + 1]) { + row_nlist[nei_iter[nei_type]++] = key_out[kk] % 100000; + } + } +} + +template< + typename FPTYPE, + int THREADS_PER_BLOCK> +__global__ void compute_em_mat_a( + FPTYPE* em, + FPTYPE* em_deriv, + FPTYPE* rij, + const FPTYPE* coord, + const FPTYPE* avg, + const FPTYPE* std, + const int* type, + const int* nlist, + const int nnei, + const float rmin, + const float rmax) +{ + // <<>> + const unsigned int bid = blockIdx.x; + const unsigned int tid = threadIdx.x; + if (tid >= nnei) { + return; + } + const int ndescrpt = nnei * 4; + const int * row_nlist = nlist + bid * nnei; + FPTYPE * row_rij = rij + bid * nnei * 3; + FPTYPE * row_descript = em + bid * nnei * 4; + FPTYPE * row_descript_deriv = em_deriv + bid * nnei * 12; + for (int ii = tid; ii < nnei; ii += THREADS_PER_BLOCK) { + const int idx_value = ii * 4; // 4 components + const int idx_deriv = ii * 12; // 4 components time 3 directions + if (row_nlist[ii] >= 0) { + FPTYPE rr[3] = {0}; + FPTYPE dd[4] = {0}; + FPTYPE vv[12] = {0}; + const int j_idx = row_nlist[ii]; + for (int kk = 0; kk < 3; kk++) { + rr[kk] = coord[j_idx * 3 + kk] - coord[bid * 3 + kk]; + row_rij[ii * 3 + kk] = rr[kk]; + } + // const FPTYPE * rr = &row_rij[ii * 3]; + FPTYPE nr2 = dev_dot(rr, rr); + FPTYPE inr = 1./sqrt(nr2); + FPTYPE nr = nr2 * inr; + FPTYPE inr2 = inr * inr; + FPTYPE inr4 = inr2 * inr2; + FPTYPE inr3 = inr4 * nr; + FPTYPE sw, dsw; + spline5_switch(sw, dsw, nr, rmin, rmax); + dd[0] = (1./nr) ;//* sw; + dd[1] = (rr[0] / nr2) ;//* sw; + dd[2] = (rr[1] / nr2) ;//* sw; + dd[3] = (rr[2] / nr2) ;//* sw; + vv[0] = (rr[0] * inr3 * sw - dd[0] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 0) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 0) % (ndescrpt * 3)) / 3]; + vv[1] = (rr[1] * inr3 * sw - dd[0] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 1) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 1) % (ndescrpt * 3)) / 3]; + vv[2] = (rr[2] * inr3 * sw - dd[0] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 2) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 2) % (ndescrpt * 3)) / 3]; + // ****deriv of component x/r2 + vv[3] = ((2. * rr[0] * rr[0] * inr4 - inr2) * sw - dd[1] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 3) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 3) % (ndescrpt * 3)) / 3]; + vv[4] = ((2. * rr[0] * rr[1] * inr4 ) * sw - dd[1] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 4) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 4) % (ndescrpt * 3)) / 3]; + vv[5] = ((2. * rr[0] * rr[2] * inr4 ) * sw - dd[1] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 5) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 5) % (ndescrpt * 3)) / 3]; + // ***deriv of component y/r2 + vv[6] = ((2. * rr[1] * rr[0] * inr4 ) * sw - dd[2] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 6) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 6) % (ndescrpt * 3)) / 3]; + vv[7] = ((2. * rr[1] * rr[1] * inr4 - inr2) * sw - dd[2] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 7) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 7) % (ndescrpt * 3)) / 3]; + vv[8] = ((2. * rr[1] * rr[2] * inr4 ) * sw - dd[2] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 8) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 8) % (ndescrpt * 3)) / 3]; + // ***deriv of component z/r2 + vv[9] = ((2. * rr[2] * rr[0] * inr4 ) * sw - dd[3] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 9) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 9) % (ndescrpt * 3)) / 3]; + vv[10]= ((2. * rr[2] * rr[1] * inr4 ) * sw - dd[3] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 10) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 10) % (ndescrpt * 3)) / 3]; + vv[11]= ((2. * rr[2] * rr[2] * inr4 - inr2) * sw - dd[3] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 11) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 11) % (ndescrpt * 3)) / 3]; + // 4 value components + dd[0] *= sw; // * em[idx * ndescrpt + idx_value + 0]);// - avg[type[idx] * ndescrpt + idx_value + 0]) / std[type[idx] * ndescrpt + idx_value + 0]; + dd[1] *= sw; // * em[idx * ndescrpt + idx_value + 1]);// - avg[type[idx] * ndescrpt + idx_value + 1]) / std[type[idx] * ndescrpt + idx_value + 1]; + dd[2] *= sw; // * em[idx * ndescrpt + idx_value + 2]);// - avg[type[idx] * ndescrpt + idx_value + 2]) / std[type[idx] * ndescrpt + idx_value + 2]; + dd[3] *= sw; // * em[idx * ndescrpt + idx_value + 3]);// - avg[type[idx] * ndescrpt + idx_value + 3]) / std[type[idx] * ndescrpt + idx_value + 3]; + for (int ii = 0; ii < 12; ii++) { + row_descript_deriv[idx_deriv + ii] = vv[ii] / std[type[bid] * ndescrpt + idx_value + ii / 3]; + } + for (int ii = 0; ii < 4; ii++) { + row_descript[idx_value + ii] = (dd[ii] - avg[type[bid] * ndescrpt + idx_value + ii]) / std[type[bid] * ndescrpt + idx_value + ii]; + } + } + else { + // TODO: move it to the memset. + row_descript[idx_value] -= avg[type[bid] * ndescrpt + idx_value] / std[type[bid] * ndescrpt + idx_value]; + } + } +} + +template +void format_nbor_list_1024 ( + int_64 * key, + const FPTYPE* coord, + const int* type, + const int* jrange, + const int* jlist, + const int& nloc, + const float& rcut, + int * i_idx) +{ + const int LEN = 256; + const int MAX_NBOR_SIZE = 1024; + const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; + dim3 block_grid(nloc, nblock); + dim3 thread_grid(1, LEN); + format_nlist_fill_a_se_a<<>> ( + key, + coord, type, jrange, jlist, rcut, i_idx, MAX_NBOR_SIZE); + const int ITEMS_PER_THREAD = 8; + const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; + // BlockSortKernel<<>> ( + BlockSortKernel <<>> ( + key, + key + nloc * MAX_NBOR_SIZE); +} + +template +void format_nbor_list_2048 ( + int_64 * key, + const FPTYPE* coord, + const int* type, + const int* jrange, + const int* jlist, + const int& nloc, + const float& rcut, + int * i_idx) +{ + const int LEN = 256; + const int MAX_NBOR_SIZE = 2048; + const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; + dim3 block_grid(nloc, nblock); + dim3 thread_grid(1, LEN); + format_nlist_fill_a_se_a<<>> ( + key, + coord, type, jrange, jlist, rcut, i_idx, MAX_NBOR_SIZE); + const int ITEMS_PER_THREAD = 8; + const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; + // BlockSortKernel<<>> ( + BlockSortKernel <<>> ( + key, + key + nloc * MAX_NBOR_SIZE); +} + +template +void format_nbor_list_4096 ( + int_64 * key, + const FPTYPE* coord, + const int* type, + const int* jrange, + const int* jlist, + const int& nloc, + const float& rcut, + int * i_idx) +{ + const int LEN = 256; + const int MAX_NBOR_SIZE = 4096; + const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; + dim3 block_grid(nloc, nblock); + dim3 thread_grid(1, LEN); + format_nlist_fill_a_se_a<<>> ( + key, + coord, type, jrange, jlist, rcut, i_idx, MAX_NBOR_SIZE); + const int ITEMS_PER_THREAD = 16; + const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; + // BlockSortKernel<<>> ( + BlockSortKernel <<>> ( + key, + key + nloc * MAX_NBOR_SIZE); +} + +template +void prod_env_mat_a_gpu_nv( + FPTYPE * em, + FPTYPE * em_deriv, + FPTYPE * rij, + int * nlist, + const FPTYPE * coord, + const int * type, + const int * ilist, + const int * jrange, + const int * jlist, + int * array_int, + int_64 * array_longlong, + const int max_nbor_size, + const FPTYPE * avg, + const FPTYPE * std, + const int nloc, + const int nall, + const int ntypes, + const float rcut, + const float rcut_smth, + const std::vector sec) +{ + const int LEN = 256; + const int nnei = sec.back(); + const int ndescrpt = nnei * 4; + int nblock = (nloc + LEN -1) / LEN; + int * sec_dev = array_int; + int * nei_iter = array_int + sec.size(); // = new int[sec_size]; + int * i_idx = array_int + sec.size() + nloc * sec.size(); + int_64 * key = array_longlong; + + cudaErrcheck(cudaMemcpy(sec_dev, &sec[0], sizeof(int) * sec.size(), cudaMemcpyHostToDevice)); + cudaErrcheck(cudaMemset(key, 0xffffffff, sizeof(int_64) * nloc * GPU_MAX_NBOR_SIZE)); + cudaErrcheck(cudaMemset(nlist, -1, sizeof(int) * nloc * nnei)); + cudaErrcheck(cudaMemset(em, 0.0, sizeof(FPTYPE) * nloc * ndescrpt)); + cudaErrcheck(cudaMemset(em_deriv, 0.0, sizeof(FPTYPE) * nloc * ndescrpt * 3)); + + get_i_idx_se_a<<>>( + i_idx, + nloc, ilist); + + if (max_nbor_size <= 1024) { + format_nbor_list_1024 ( + key, + coord, type, jrange, jlist, nloc, rcut, i_idx); + } + else if (max_nbor_size <= 2048) { + format_nbor_list_2048 ( + key, + coord, type, jrange, jlist, nloc, rcut, i_idx); + } + else if (max_nbor_size <= 4096) { + format_nbor_list_4096 ( + key, + coord, type, jrange, jlist, nloc, rcut, i_idx); + } + + format_nlist_fill_b_se_a<<>> ( + nlist, + nnei, nloc, jrange, jlist, key, sec_dev, sec.size(), nei_iter, max_nbor_size); + + compute_em_mat_a <<>> ( + em, em_deriv, rij, + coord, avg, std, type, nlist, nnei, rcut_smth, rcut); +} + +template void prod_env_mat_a_gpu_nv(float * em, float * em_deriv, float * rij, int * nlist, const float * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const float * avg, const float * std, const int nloc, const int nall, const int ntypes, const float rcut, const float rcut_smth, const std::vector sec); +template void prod_env_mat_a_gpu_nv(double * em, double * em_deriv, double * rij, int * nlist, const double * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const double * avg, const double * std, const int nloc, const int nall, const int ntypes, const float rcut, const float rcut_smth, const std::vector sec); \ No newline at end of file diff --git a/source/op/cuda/descrpt_se_r.cu b/source/lib/src/cuda/descrpt_se_r.cu similarity index 99% rename from source/op/cuda/descrpt_se_r.cu rename to source/lib/src/cuda/descrpt_se_r.cu index 33932f4325..cb40ed1814 100644 --- a/source/op/cuda/descrpt_se_r.cu +++ b/source/lib/src/cuda/descrpt_se_r.cu @@ -2,6 +2,7 @@ #include #include #include "DeviceFunctor.h" +#include "gpu_nv.h" template < typename Key, diff --git a/source/op/cuda/gelu.cu b/source/lib/src/cuda/gelu.cu similarity index 99% rename from source/op/cuda/gelu.cu rename to source/lib/src/cuda/gelu.cu index 6329c8f085..1717e96704 100644 --- a/source/op/cuda/gelu.cu +++ b/source/lib/src/cuda/gelu.cu @@ -1,4 +1,5 @@ #include "DeviceFunctor.h" +#include "gpu_nv.h" template __global__ void gelu(const FPTYPE * in, FPTYPE * out, int const size) { diff --git a/source/op/cuda/prod_force_se_a.cu b/source/lib/src/cuda/prod_force_se_a.cu similarity index 99% rename from source/op/cuda/prod_force_se_a.cu rename to source/lib/src/cuda/prod_force_se_a.cu index 84615ff275..ede315e167 100644 --- a/source/op/cuda/prod_force_se_a.cu +++ b/source/lib/src/cuda/prod_force_se_a.cu @@ -1,4 +1,5 @@ #include "DeviceFunctor.h" +#include "gpu_nv.h" #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600 static __inline__ __device__ double atomicAdd(double* address, double val) { diff --git a/source/op/cuda/prod_force_se_r.cu b/source/lib/src/cuda/prod_force_se_r.cu similarity index 99% rename from source/op/cuda/prod_force_se_r.cu rename to source/lib/src/cuda/prod_force_se_r.cu index 88e2962536..7fcd0679f0 100644 --- a/source/op/cuda/prod_force_se_r.cu +++ b/source/lib/src/cuda/prod_force_se_r.cu @@ -1,4 +1,5 @@ #include "DeviceFunctor.h" +#include "gpu_nv.h" #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600 static __inline__ __device__ double atomicAdd(double* address, double val) { diff --git a/source/op/cuda/prod_virial_se_a.cu b/source/lib/src/cuda/prod_virial_se_a.cu similarity index 99% rename from source/op/cuda/prod_virial_se_a.cu rename to source/lib/src/cuda/prod_virial_se_a.cu index e084720c6d..ff61e3af36 100644 --- a/source/op/cuda/prod_virial_se_a.cu +++ b/source/lib/src/cuda/prod_virial_se_a.cu @@ -1,4 +1,5 @@ #include "DeviceFunctor.h" +#include "gpu_nv.h" #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600 static __inline__ __device__ double atomicAdd(double* address, double val) { diff --git a/source/op/cuda/prod_virial_se_r.cu b/source/lib/src/cuda/prod_virial_se_r.cu similarity index 99% rename from source/op/cuda/prod_virial_se_r.cu rename to source/lib/src/cuda/prod_virial_se_r.cu index 9b8f43543f..243c4ba94e 100644 --- a/source/op/cuda/prod_virial_se_r.cu +++ b/source/lib/src/cuda/prod_virial_se_r.cu @@ -1,4 +1,5 @@ #include "DeviceFunctor.h" +#include "gpu_nv.h" #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600 static __inline__ __device__ double atomicAdd(double* address, double val) { diff --git a/source/op/cuda/tabulate.cu b/source/lib/src/cuda/tabulate.cu similarity index 99% rename from source/op/cuda/tabulate.cu rename to source/lib/src/cuda/tabulate.cu index db1b917f02..a7bb696a76 100644 --- a/source/op/cuda/tabulate.cu +++ b/source/lib/src/cuda/tabulate.cu @@ -5,6 +5,7 @@ #include // or equivalently #include #include "DeviceFunctor.h" +#include "gpu_nv.h" #define MM 4 #define KK 4 diff --git a/source/lib/src/prod_env_mat.cc b/source/lib/src/prod_env_mat.cc index 3a8c49c1ff..13bb5f3eaf 100644 --- a/source/lib/src/prod_env_mat.cc +++ b/source/lib/src/prod_env_mat.cc @@ -1,5 +1,6 @@ #include #include +#include #include "prod_env_mat.h" #include "fmt_nlist.h" #include "env_mat.h" @@ -15,6 +16,7 @@ void prod_env_mat_a_cpu( const int * ilist, const int * jrange, const int * jlist, + const int max_nbor_size, const FPTYPE * avg, const FPTYPE * std, const int nloc, @@ -99,6 +101,7 @@ void prod_env_mat_a_cpu( const int * ilist, const int * jrange, const int * jlist, + const int max_nbor_size, const double * avg, const double * std, const int nloc, @@ -119,6 +122,7 @@ void prod_env_mat_a_cpu( const int * ilist, const int * jrange, const int * jlist, + const int max_nbor_size, const float * avg, const float * std, const int nloc, @@ -128,77 +132,60 @@ void prod_env_mat_a_cpu( const float rcut_smth, const std::vector sec); -#if GOOGLE_CUDA -template -void prod_env_mat_a_gpu_nv( - FPTYPE * em, - FPTYPE * em_deriv, - FPTYPE * rij, - int * nlist, - const FPTYPE * coord, - const int * type, - const int * ilist, - const int * jrange, - const int * jlist, - int * array_int, - unsigned long long * array_longlong, - const int max_nbor_size, - const FPTYPE * avg, - const FPTYPE * std, - const int nloc, - const int nall, - const int ntypes, - const float rcut, - const float rcut_smth, - const std::vector sec) { - DescrptSeAFunctor()( - em, em_deriv, rij, nlist, - coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, nloc, nall, rcut, rcut_smth, sec, max_nbor_size); -} -template -void prod_env_mat_a_gpu_nv( - double * em, - double * em_deriv, - double * rij, - int * nlist, - const double * coord, - const int * type, - const int * ilist, - const int * jrange, - const int * jlist, - int * array_int, - unsigned long long * array_longlong, - const int max_nbor_size, - const double * avg, - const double * std, - const int nloc, - const int nall, - const int ntypes, - const float rcut, - const float rcut_smth, - const std::vector sec); +#if GOOGLE_CUDA +void env_mat_nbor_update( + bool &init, + int * &ilist, + int * &jrange, + int * &jlist, + int &ilist_size, + int &jrange_size, + int &jlist_size, + int &max_nbor_size, + const int * mesh, + const int size) +{ + int *mesh_host = new int[size], *ilist_host = NULL, *jrange_host = NULL, *jlist_host = NULL; + cudaErrcheck(cudaMemcpy(mesh_host, mesh, sizeof(int) * size, cudaMemcpyDeviceToHost)); + memcpy (&ilist_host, 4 + mesh_host, sizeof(int *)); + memcpy (&jrange_host, 8 + mesh_host, sizeof(int *)); + memcpy (&jlist_host, 12 + mesh_host, sizeof(int *)); + int const ago = mesh_host[0]; + if (!init) { + ilist_size = (int)(mesh_host[1] * 1.2); + jrange_size = (int)(mesh_host[2] * 1.2); + jlist_size = (int)(mesh_host[3] * 1.2); + cudaErrcheck(cudaMalloc((void **)&ilist, sizeof(int) * ilist_size)); + cudaErrcheck(cudaMalloc((void **)&jrange, sizeof(int) * jrange_size)); + cudaErrcheck(cudaMalloc((void **)&jlist, sizeof(int) * jlist_size)); + init = true; + } + if (ago == 0) { + if (ilist_size < mesh_host[1]) { + ilist_size = (int)(mesh_host[1] * 1.2); + cudaErrcheck(cudaFree(ilist)); + cudaErrcheck(cudaMalloc((void **)&ilist, sizeof(int) * ilist_size)); + } + if (jrange_size < mesh_host[2]) { + jrange_size = (int)(mesh_host[2] * 1.2); + cudaErrcheck(cudaFree(jrange)); + cudaErrcheck(cudaMalloc((void **)&jrange,sizeof(int) * jrange_size)); + } + if (jlist_size < mesh_host[3]) { + jlist_size = (int)(mesh_host[3] * 1.2); + cudaErrcheck(cudaFree(jlist)); + cudaErrcheck(cudaMalloc((void **)&jlist, sizeof(int) * jlist_size)); + } + cudaErrcheck(cudaMemcpy(ilist, ilist_host, sizeof(int) * mesh_host[1], cudaMemcpyHostToDevice)); + cudaErrcheck(cudaMemcpy(jrange, jrange_host, sizeof(int) * mesh_host[2], cudaMemcpyHostToDevice)); + cudaErrcheck(cudaMemcpy(jlist, jlist_host, sizeof(int) * mesh_host[3], cudaMemcpyHostToDevice)); -template -void prod_env_mat_a_gpu_nv( - float * em, - float * em_deriv, - float * rij, - int * nlist, - const float * coord, - const int * type, - const int * ilist, - const int * jrange, - const int * jlist, - int * array_int, - unsigned long long * array_longlong, - const int max_nbor_size, - const float * avg, - const float * std, - const int nloc, - const int nall, - const int ntypes, - const float rcut, - const float rcut_smth, - const std::vector sec); -#endif + max_nbor_size = 1024; + for(int ii = 0; ii < mesh_host[2]; ii++) { + max_nbor_size = (jrange_host[ii + 1] - jrange_host[ii]) > max_nbor_size ? (jrange_host[ii + 1] - jrange_host[ii]) : max_nbor_size; + } + } + delete [] mesh_host; +} +#endif // GOOGLE_CUDA \ No newline at end of file diff --git a/source/lib/tests/CMakeLists.txt b/source/lib/tests/CMakeLists.txt index 12693830c7..6d7412cb3d 100644 --- a/source/lib/tests/CMakeLists.txt +++ b/source/lib/tests/CMakeLists.txt @@ -14,9 +14,38 @@ add_library(${libname} ${LIB_SRC}) message(status "${CMAKE_SOURCE_DIR}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + +# define USE_CUDA_TOOLKIT +if (DEFINED USE_CUDA_TOOLKIT) + if (USE_CUDA_TOOLKIT) + find_package(CUDA REQUIRED) + else() + message(STATUS "Will not build nv GPU support") + endif() +else() + find_package(CUDA QUIET) + if (CUDA_FOUND) + set(USE_CUDA_TOOLKIT TRUE) + message(STATUS "Found CUDA in ${CUDA_TOOLKIT_ROOT_DIR}, build nv GPU support") + else() + set(USE_CUDA_TOOLKIT FALSE) + message(STATUS "No cuda support found, will not build nv GPU support") + endif() +endif() +if (USE_CUDA_TOOLKIT) + add_definitions("-D GOOGLE_CUDA") +endif() + +if (USE_CUDA_TOOLKIT) + find_package(CUDA REQUIRED) + include_directories(${CUDA_INCLUDE_DIRS}) + add_subdirectory(${LIB_BASE_DIR}/src/cuda cuda_binary_dir) +endif() + file(GLOB TEST_SRC test_*.cc) add_executable( runUnitTests ${TEST_SRC} ) -target_link_libraries(runUnitTests gtest gtest_main ${libname}) +target_link_libraries(runUnitTests gtest gtest_main ${libname} pthread deepmd_op_cuda) add_test( runUnitTests runUnitTests ) # include(GoogleTest) diff --git a/source/lib/tests/test_env_mat_a.cc b/source/lib/tests/test_env_mat_a.cc index 56f13f83ac..beee75f07b 100644 --- a/source/lib/tests/test_env_mat_a.cc +++ b/source/lib/tests/test_env_mat_a.cc @@ -4,6 +4,7 @@ #include "env_mat.h" #include "prod_env_mat.h" #include "neighbor_list.h" +#include "device_common.h" class TestEnvMatA : public ::testing::Test { @@ -523,3 +524,223 @@ TEST_F(TestEnvMatA, prod_cpu_equal_cpu) // } // } } + + +#if GOOGLE_CUDA + +#include "device_common.h" + +TEST_F(TestEnvMatA, prod_gpu_nv) +{ + EXPECT_EQ(nlist_r_cpy.size(), nloc); + int tot_nnei = 0; + int max_nbor_size = 0; + for(int ii = 0; ii < nlist_a_cpy.size(); ++ii){ + tot_nnei += nlist_a_cpy[ii].size(); + if (nlist_a_cpy[ii].size() > max_nbor_size){ + max_nbor_size = nlist_a_cpy[ii].size(); + } + } + std::vector ilist(nloc), jlist(tot_nnei), jrange(nloc+1, 0); + for (int ii = 0; ii < nloc; ++ii){ + ilist[ii] = ii; + jrange[ii+1] = jrange[ii] + nlist_a_cpy[ii].size(); + int jj, cc; + for (jj = jrange[ii], cc = 0; jj < jrange[ii+1]; ++jj, ++cc){ + jlist[jj] = nlist_a_cpy[ii][cc]; + } + } + std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); + std::vector nlist(nloc * nnei); + std::vector avg(ntypes * ndescrpt, 0); + std::vector std(ntypes * ndescrpt, 1); + + double * em_dev = NULL, * em_deriv_dev = NULL, * rij_dev = NULL; + double * posi_cpy_dev = NULL, * avg_dev = NULL, * std_dev = NULL; + int * atype_cpy_dev = NULL, * nlist_dev = NULL, * ilist_dev = NULL, * jrange_dev = NULL, * jlist_dev = NULL, * array_int_dev = NULL; + int_64 * array_longlong_dev = NULL; + malloc_device_memory_sync(em_dev, em); + malloc_device_memory_sync(em_deriv_dev, em_deriv); + malloc_device_memory_sync(rij_dev, rij); + malloc_device_memory_sync(posi_cpy_dev, posi_cpy); + malloc_device_memory_sync(avg_dev, avg); + malloc_device_memory_sync(std_dev, std); + + malloc_device_memory_sync(atype_cpy_dev, atype_cpy); + malloc_device_memory_sync(nlist_dev, nlist); + malloc_device_memory_sync(ilist_dev, ilist); + malloc_device_memory_sync(jrange_dev, jrange); + malloc_device_memory_sync(jlist_dev, jlist); + + malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); + malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); + + prod_env_mat_a_gpu_nv( + em_dev, + em_deriv_dev, + rij_dev, + nlist_dev, + posi_cpy_dev, + atype_cpy_dev, + ilist_dev, + jrange_dev, + jlist_dev, + array_int_dev, + array_longlong_dev, + GPU_MAX_NBOR_SIZE, + avg_dev, + std_dev, + nloc, + nall, + ntypes, + rc, + rc_smth, + sec_a); + memcpy_device_to_host(em_dev, em); + delete_device_memory(em_dev); + delete_device_memory(em_deriv_dev); + delete_device_memory(nlist_dev); + delete_device_memory(posi_cpy_dev); + delete_device_memory(atype_cpy_dev); + delete_device_memory(ilist_dev); + delete_device_memory(jrange_dev); + delete_device_memory(jlist_dev); + delete_device_memory(array_int_dev); + delete_device_memory(array_longlong_dev); + delete_device_memory(avg_dev); + delete_device_memory(std_dev); + + for(int ii = 0; ii < nloc; ++ii){ + for (int jj = 0; jj < nnei; ++jj){ + for (int dd = 0; dd < 4; ++dd){ + EXPECT_LT(fabs(em[ii*nnei*4 + jj*4 + dd] - + expected_env[ii*nnei*4 + jj*4 + dd]) , + 1e-5); + } + } + } +} + + +TEST_F(TestEnvMatA, prod_gpu_equal_cpu) +{ + EXPECT_EQ(nlist_r_cpy.size(), nloc); + int tot_nnei = 0; + int max_nbor_size = 0; + for(int ii = 0; ii < nlist_a_cpy.size(); ++ii){ + tot_nnei += nlist_a_cpy[ii].size(); + if (nlist_a_cpy[ii].size() > max_nbor_size){ + max_nbor_size = nlist_a_cpy[ii].size(); + } + } + std::vector ilist(nloc), jlist(tot_nnei), jrange(nloc+1, 0); + for (int ii = 0; ii < nloc; ++ii){ + ilist[ii] = ii; + jrange[ii+1] = jrange[ii] + nlist_a_cpy[ii].size(); + int jj, cc; + for (jj = jrange[ii], cc = 0; jj < jrange[ii+1]; ++jj, ++cc){ + jlist[jj] = nlist_a_cpy[ii][cc]; + } + } + std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); + std::vector nlist(nloc * nnei); + std::vector avg(ntypes * ndescrpt, 0); + std::vector std(ntypes * ndescrpt, 1); + + double * em_dev = NULL, * em_deriv_dev = NULL, * rij_dev = NULL; + double * posi_cpy_dev = NULL, * avg_dev = NULL, * std_dev = NULL; + int * atype_cpy_dev = NULL, * nlist_dev = NULL, * ilist_dev = NULL, * jrange_dev = NULL, * jlist_dev = NULL, * array_int_dev = NULL; + int_64 * array_longlong_dev = NULL; + malloc_device_memory_sync(em_dev, em); + malloc_device_memory_sync(em_deriv_dev, em_deriv); + malloc_device_memory_sync(rij_dev, rij); + malloc_device_memory_sync(posi_cpy_dev, posi_cpy); + malloc_device_memory_sync(avg_dev, avg); + malloc_device_memory_sync(std_dev, std); + + malloc_device_memory_sync(atype_cpy_dev, atype_cpy); + malloc_device_memory_sync(nlist_dev, nlist); + malloc_device_memory_sync(ilist_dev, ilist); + malloc_device_memory_sync(jrange_dev, jrange); + malloc_device_memory_sync(jlist_dev, jlist); + + malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); + malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); + + prod_env_mat_a_gpu_nv( + em_dev, + em_deriv_dev, + rij_dev, + nlist_dev, + posi_cpy_dev, + atype_cpy_dev, + ilist_dev, + jrange_dev, + jlist_dev, + array_int_dev, + array_longlong_dev, + GPU_MAX_NBOR_SIZE, + avg_dev, + std_dev, + nloc, + nall, + ntypes, + rc, + rc_smth, + sec_a); + memcpy_device_to_host(em_dev, em); + memcpy_device_to_host(em_deriv_dev, em_deriv); + memcpy_device_to_host(rij_dev, rij); + memcpy_device_to_host(nlist_dev, nlist); + delete_device_memory(em_dev); + delete_device_memory(em_deriv_dev); + delete_device_memory(nlist_dev); + delete_device_memory(posi_cpy_dev); + delete_device_memory(atype_cpy_dev); + delete_device_memory(ilist_dev); + delete_device_memory(jrange_dev); + delete_device_memory(jlist_dev); + delete_device_memory(array_int_dev); + delete_device_memory(array_longlong_dev); + delete_device_memory(avg_dev); + delete_device_memory(std_dev); + + std::vector fmt_nlist_a_1, fmt_nlist_r_1; + std::vector env_1, env_deriv_1, rij_a_1; + for(int ii = 0; ii < nloc; ++ii){ + int ret_1 = format_nlist_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + EXPECT_EQ(ret_1, -1); + env_mat_a_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + EXPECT_EQ(env_1.size(), nnei * 4); + EXPECT_EQ(env_deriv_1.size(), nnei * 4 * 3); + EXPECT_EQ(rij_a_1.size(), nnei * 3); + EXPECT_EQ(fmt_nlist_a_1.size(), nnei); + EXPECT_EQ(env_1.size() * nloc, em.size()); + EXPECT_EQ(env_deriv_1.size() * nloc, em_deriv.size()); + EXPECT_EQ(rij_a_1.size() * nloc, rij.size()); + EXPECT_EQ(fmt_nlist_a_1.size() * nloc, nlist.size()); + for (unsigned jj = 0; jj < env_1.size(); ++jj){ + EXPECT_LT(fabs(em[ii*nnei*4+jj] - env_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < env_deriv_1.size(); ++jj){ + EXPECT_LT(fabs(em_deriv[ii*nnei*4*3+jj] - env_deriv_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < rij_a_1.size(); ++jj){ + EXPECT_LT(fabs(rij[ii*nnei*3+jj] - rij_a_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < fmt_nlist_a_1.size(); ++jj){ + EXPECT_EQ(nlist[ii*nnei+jj], fmt_nlist_a_1[jj]); + } + } + + // for(int ii = 0; ii < nloc; ++ii){ + // for (int jj = 0; jj < nnei; ++jj){ + // for (int dd = 0; dd < 4; ++dd){ + // EXPECT_LT(fabs(em[ii*nnei*4 + jj*4 + dd] - + // expected_env[ii*nnei*4 + jj*4 + dd]) , + // 1e-5); + // } + // } + // } +} +#endif //GOOGLE_CUDA \ No newline at end of file diff --git a/source/op/CMakeLists.txt b/source/op/CMakeLists.txt index ef2c57f8ea..b0a052ef17 100644 --- a/source/op/CMakeLists.txt +++ b/source/op/CMakeLists.txt @@ -11,11 +11,8 @@ file(GLOB OP_PY *.py) if (BUILD_CPP_IF) if (USE_CUDA_TOOLKIT) add_library(${LIB_DEEPMD_OP} SHARED ${OP_CUDA_SRC}) - add_subdirectory(cuda) find_package(CUDA REQUIRED) include_directories(${CUDA_INCLUDE_DIRS}) - set (EXTRA_LIBS ${EXTRA_LIBS} deepmd_op_cuda) - target_link_libraries (${LIB_DEEPMD_OP} ${EXTRA_LIBS}) target_link_libraries (${LIB_DEEPMD_OP} ${CUDA_LIBRARIES}) else (USE_CUDA_TOOLKIT) add_library(${LIB_DEEPMD_OP} SHARED ${OP_SRC}) @@ -28,12 +25,10 @@ if (BUILD_PY_IF) if (USE_CUDA_TOOLKIT) add_library(op_abi SHARED ${OP_SRC} ${OP_LIB}) add_library(op_grads SHARED ${OP_GRADS_SRC}) - add_subdirectory(cuda) find_package(CUDA REQUIRED) include_directories(${CUDA_INCLUDE_DIRS}) - set (EXTRA_LIBS ${EXTRA_LIBS} deepmd_op_cuda) - target_link_libraries (op_abi ${EXTRA_LIBS}) - target_link_libraries (op_grads ${EXTRA_LIBS}) + target_link_libraries (op_abi ${LIB_DEEPMD_OP_CUDA}) + target_link_libraries (op_grads ${LIB_DEEPMD_OP_CUDA}) else (USE_CUDA_TOOLKIT) add_library(op_abi SHARED ${OP_SRC} ${OP_LIB}) add_library(op_grads SHARED ${OP_GRADS_SRC}) diff --git a/source/op/cuda/cub b/source/op/cuda/cub deleted file mode 160000 index c3cceac115..0000000000 --- a/source/op/cuda/cub +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c3cceac115c072fb63df1836ff46d8c60d9eb304 diff --git a/source/op/cuda/descrpt_se_a.cu b/source/op/cuda/descrpt_se_a.cu deleted file mode 100644 index dc6d7aa2b8..0000000000 --- a/source/op/cuda/descrpt_se_a.cu +++ /dev/null @@ -1,438 +0,0 @@ -#include -#include -#include -#include "DeviceFunctor.h" - -template < - typename Key, - int BLOCK_THREADS, - int ITEMS_PER_THREAD> -__launch_bounds__ (BLOCK_THREADS) -__global__ void BlockSortKernel( - Key * d_in, - Key * d_out) // Tile of output -{ - enum { TILE_SIZE = BLOCK_THREADS * ITEMS_PER_THREAD }; - // Specialize BlockLoad type for our thread block (uses warp-striped loads for coalescing, then transposes in shared memory to a blocked arrangement) - typedef cub::BlockLoad BlockLoadT; - // Specialize BlockRadixSort type for our thread block - typedef cub::BlockRadixSort BlockRadixSortT; - // Shared memory - __shared__ union TempStorage - { - typename BlockLoadT::TempStorage load; - typename BlockRadixSortT::TempStorage sort; - } temp_storage; - // Per-thread tile items - Key items[ITEMS_PER_THREAD]; - // Our current block's offset - int block_offset = blockIdx.x * TILE_SIZE; - // Load items into a blocked arrangement - BlockLoadT(temp_storage.load).Load(d_in + block_offset, items); - // Barrier for smem reuse - __syncthreads(); - // Sort keys - BlockRadixSortT(temp_storage.sort).SortBlockedToStriped(items); - // Store output in striped fashion - cub::StoreDirectStriped(threadIdx.x, d_out + block_offset, items); -} - -template -__device__ inline FPTYPE dev_dot(FPTYPE * arr1, FPTYPE * arr2) { - return arr1[0] * arr2[0] + arr1[1] * arr2[1] + arr1[2] * arr2[2]; -} - -template -__device__ inline void spline5_switch(FPTYPE & vv, - FPTYPE & dd, - FPTYPE & xx, - const float & rmin, - const float & rmax) -{ - if (xx < rmin) { - dd = 0; - vv = 1; - } - else if (xx < rmax) { - FPTYPE uu = (xx - rmin) / (rmax - rmin) ; - FPTYPE du = 1. / (rmax - rmin) ; - vv = uu*uu*uu * (-6 * uu*uu + 15 * uu - 10) + 1; - dd = ( 3 * uu*uu * (-6 * uu*uu + 15 * uu - 10) + uu*uu*uu * (-12 * uu + 15) ) * du; - } - else { - dd = 0; - vv = 0; - } -} - -__global__ void get_i_idx_se_a(const int nloc, - const int * ilist, - int * i_idx) -{ - const unsigned int idy = blockIdx.x * blockDim.x + threadIdx.x; - if(idy >= nloc) { - return; - } - i_idx[ilist[idy]] = idy; -} - -template -__global__ void format_nlist_fill_a_se_a(const FPTYPE * coord, - const int * type, - const int * jrange, - const int * jlist, - const float rcut, - int_64 * key, - int * i_idx, - const int MAX_NBOR_SIZE) -{ - // <<>> - const unsigned int idx = blockIdx.x; - const unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y; - - const int nsize = jrange[i_idx[idx] + 1] - jrange[i_idx[idx]]; - if (idy >= nsize) { - return; - } - - const int * nei_idx = jlist + jrange[i_idx[idx]]; - // dev_copy(nei_idx, &jlist[jrange[i_idx]], nsize); - - int_64 * key_in = key + idx * MAX_NBOR_SIZE; - - FPTYPE diff[3]; - const int & j_idx = nei_idx[idy]; - for (int dd = 0; dd < 3; dd++) { - diff[dd] = coord[j_idx * 3 + dd] - coord[idx * 3 + dd]; - } - FPTYPE rr = sqrt(dev_dot(diff, diff)); - if (rr <= rcut) { - key_in[idy] = type[j_idx] * 1E15+ (int_64)(rr * 1.0E13) / 100000 * 100000 + j_idx; - } -} - - // bubble_sort(sel_nei, num_nei); -__global__ void format_nlist_fill_b_se_a(int * nlist, - const int nlist_size, - const int nloc, - const int * jrange, - const int * jlist, - int_64 * key, - const int * sec, - const int sec_a_size, - int * nei_iter_dev, - const int MAX_NBOR_SIZE) -{ - - const unsigned int idy = blockIdx.x * blockDim.x + threadIdx.x; - - if(idy >= nloc) { - return; - } - - int * row_nlist = nlist + idy * nlist_size; - int * nei_iter = nei_iter_dev + idy * sec_a_size; - int_64 * key_out = key + nloc * MAX_NBOR_SIZE + idy * MAX_NBOR_SIZE; - - for (int ii = 0; ii < sec_a_size; ii++) { - nei_iter[ii] = sec[ii]; - } - - for (unsigned int kk = 0; key_out[kk] != key_out[MAX_NBOR_SIZE - 1]; kk++) { - const int & nei_type = key_out[kk] / 1E15; - if (nei_iter[nei_type] < sec[nei_type + 1]) { - row_nlist[nei_iter[nei_type]++] = key_out[kk] % 100000; - } - } -} -//it's ok! - -template< - typename FPTYPE, - int THREADS_PER_BLOCK> -__global__ void compute_descriptor_se_a(FPTYPE* descript, - const int ndescrpt, - FPTYPE* descript_deriv, - const int descript_deriv_size, - FPTYPE* rij, - const int rij_size, - const int* type, - const FPTYPE* avg, - const FPTYPE* std, - int* nlist, - const int nlist_size, - const FPTYPE* coord, - const float rmin, - const float rmax, - const int sec_a_size) -{ - // <<>> - const unsigned int bid = blockIdx.x; - const unsigned int tid = threadIdx.x; - // usually false... - if (tid >= sec_a_size) { - return; - } - // const int idx_deriv = idy * 4 * 3; // 4 components time 3 directions - // const int idx_value = idy * 4; // 4 components - int * row_nlist = nlist + bid * nlist_size; - FPTYPE * row_rij = rij + bid * rij_size; - FPTYPE * row_descript = descript + bid * ndescrpt; - FPTYPE * row_descript_deriv = descript_deriv + bid * descript_deriv_size; - - for (int ii = tid; ii < sec_a_size; ii += THREADS_PER_BLOCK) { - const int idx_value = ii * 4; // 4 components - const int idx_deriv = ii * 12; // 4 components time 3 directions - if (row_nlist[ii] >= 0) { - FPTYPE rr[3] = {0}; - FPTYPE dd[4] = {0}; - FPTYPE vv[12] = {0}; - const int & j_idx = row_nlist[ii]; - for (int kk = 0; kk < 3; kk++) { - rr[kk] = coord[j_idx * 3 + kk] - coord[bid * 3 + kk]; - row_rij[ii * 3 + kk] = rr[kk]; - } - // const FPTYPE * rr = &row_rij[ii * 3]; - FPTYPE nr2 = dev_dot(rr, rr); - FPTYPE inr = 1./sqrt(nr2); - FPTYPE nr = nr2 * inr; - FPTYPE inr2 = inr * inr; - FPTYPE inr4 = inr2 * inr2; - FPTYPE inr3 = inr4 * nr; - FPTYPE sw, dsw; - spline5_switch(sw, dsw, nr, rmin, rmax); - dd[0] = (1./nr) ;//* sw; - dd[1] = (rr[0] / nr2) ;//* sw; - dd[2] = (rr[1] / nr2) ;//* sw; - dd[3] = (rr[2] / nr2) ;//* sw; - - vv[0] = (rr[0] * inr3 * sw - dd[0] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 0) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 0) % (ndescrpt * 3)) / 3]; - vv[1] = (rr[1] * inr3 * sw - dd[0] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 1) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 1) % (ndescrpt * 3)) / 3]; - vv[2] = (rr[2] * inr3 * sw - dd[0] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 2) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 2) % (ndescrpt * 3)) / 3]; - // ****deriv of component x/r2 - vv[3] = ((2. * rr[0] * rr[0] * inr4 - inr2) * sw - dd[1] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 3) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 3) % (ndescrpt * 3)) / 3]; - vv[4] = ((2. * rr[0] * rr[1] * inr4 ) * sw - dd[1] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 4) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 4) % (ndescrpt * 3)) / 3]; - vv[5] = ((2. * rr[0] * rr[2] * inr4 ) * sw - dd[1] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 5) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 5) % (ndescrpt * 3)) / 3]; - // ***deriv of component y/r2 - vv[6] = ((2. * rr[1] * rr[0] * inr4 ) * sw - dd[2] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 6) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 6) % (ndescrpt * 3)) / 3]; - vv[7] = ((2. * rr[1] * rr[1] * inr4 - inr2) * sw - dd[2] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 7) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 7) % (ndescrpt * 3)) / 3]; - vv[8] = ((2. * rr[1] * rr[2] * inr4 ) * sw - dd[2] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 8) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 8) % (ndescrpt * 3)) / 3]; - // ***deriv of component z/r2 - vv[9] = ((2. * rr[2] * rr[0] * inr4 ) * sw - dd[3] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 9) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 9) % (ndescrpt * 3)) / 3]; - vv[10]= ((2. * rr[2] * rr[1] * inr4 ) * sw - dd[3] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 10) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 10) % (ndescrpt * 3)) / 3]; - vv[11]= ((2. * rr[2] * rr[2] * inr4 - inr2) * sw - dd[3] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 11) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 11) % (ndescrpt * 3)) / 3]; - // 4 value components - dd[0] *= sw; // * descript[idx * ndescrpt + idx_value + 0]);// - avg[type[idx] * ndescrpt + idx_value + 0]) / std[type[idx] * ndescrpt + idx_value + 0]; - dd[1] *= sw; // * descript[idx * ndescrpt + idx_value + 1]);// - avg[type[idx] * ndescrpt + idx_value + 1]) / std[type[idx] * ndescrpt + idx_value + 1]; - dd[2] *= sw; // * descript[idx * ndescrpt + idx_value + 2]);// - avg[type[idx] * ndescrpt + idx_value + 2]) / std[type[idx] * ndescrpt + idx_value + 2]; - dd[3] *= sw; // * descript[idx * ndescrpt + idx_value + 3]);// - avg[type[idx] * ndescrpt + idx_value + 3]) / std[type[idx] * ndescrpt + idx_value + 3]; - for (int ii = 0; ii < 12; ii++) { - row_descript_deriv[idx_deriv + ii] = vv[ii] / std[type[bid] * ndescrpt + idx_value + ii / 3]; - } - for (int ii = 0; ii < 4; ii++) { - row_descript[idx_value + ii] = (dd[ii] - avg[type[bid] * ndescrpt + idx_value + ii]) / std[type[bid] * ndescrpt + idx_value + ii]; - } - } - else { - // TODO: move it to the memset. - row_descript[idx_value] -= avg[type[bid] * ndescrpt + idx_value] / std[type[bid] * ndescrpt + idx_value]; - } - } -} - - -template -void format_nbor_list_1024 ( - const FPTYPE* coord, - const int* type, - const int* jrange, - const int* jlist, - const int& nloc, - const float& rcut, - int * i_idx, - int_64 * key -) -{ - const int LEN = 256; - const int MAX_NBOR_SIZE = 1024; - const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; - dim3 block_grid(nloc, nblock); - dim3 thread_grid(1, LEN); - format_nlist_fill_a_se_a - <<>> ( - coord, - type, - jrange, - jlist, - rcut, - key, - i_idx, - MAX_NBOR_SIZE - ); - const int ITEMS_PER_THREAD = 8; - const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; - // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAX_NBOR_SIZE); -} - -template -void format_nbor_list_2048 ( - const FPTYPE* coord, - const int* type, - const int* jrange, - const int* jlist, - const int& nloc, - const float& rcut, - int * i_idx, - int_64 * key -) -{ - const int LEN = 256; - const int MAX_NBOR_SIZE = 2048; - const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; - dim3 block_grid(nloc, nblock); - dim3 thread_grid(1, LEN); - format_nlist_fill_a_se_a - <<>> ( - coord, - type, - jrange, - jlist, - rcut, - key, - i_idx, - MAX_NBOR_SIZE - ); - const int ITEMS_PER_THREAD = 8; - const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; - // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAX_NBOR_SIZE); -} - -template -void format_nbor_list_4096 ( - const FPTYPE* coord, - const int* type, - const int* jrange, - const int* jlist, - const int& nloc, - const float& rcut, - int * i_idx, - int_64 * key -) -{ - const int LEN = 256; - const int MAX_NBOR_SIZE = 4096; - const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; - dim3 block_grid(nloc, nblock); - dim3 thread_grid(1, LEN); - format_nlist_fill_a_se_a - <<>> ( - coord, - type, - jrange, - jlist, - rcut, - key, - i_idx, - MAX_NBOR_SIZE - ); - const int ITEMS_PER_THREAD = 16; - const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; - // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAX_NBOR_SIZE); -} - - -template -void DescrptSeAFunctor::operator()( - FPTYPE * descript, - FPTYPE * descript_deriv, - FPTYPE * rij, - int * nlist, - const FPTYPE * coord, - const int * type, - const int * ilist, - const int * jrange, - const int * jlist, - int * array_int, - unsigned long long * array_longlong, - const FPTYPE * avg, - const FPTYPE * std, - const int nloc, - const int nall, - const float rcut, - const float rcut_smth, - const std::vector sec, - const int max_nbor_size) -{ - const int LEN = 256; - const int nnei = sec.back(); - const int ndescrpt = nnei * 4; - int nblock = (nloc + LEN -1) / LEN; - int * sec_a_dev = array_int; - int * nei_iter = array_int + sec.size(); // = new int[sec_a_size]; - int * i_idx = array_int + sec.size() + nloc * sec.size(); - int_64 * key = array_longlong; - - cudaError_t res = cudaSuccess; - res = cudaMemcpy(sec_a_dev, &sec[0], sizeof(int) * sec.size(), cudaMemcpyHostToDevice); cudaErrcheck(res); - res = cudaMemset(key, 0xffffffff, sizeof(int_64) * nloc * max_nbor_size); cudaErrcheck(res); - res = cudaMemset(nlist, -1, sizeof(int) * nloc * nnei); cudaErrcheck(res); - res = cudaMemset(descript, 0.0, sizeof(FPTYPE) * nloc * ndescrpt); cudaErrcheck(res); - res = cudaMemset(descript_deriv, 0.0, sizeof(FPTYPE) * nloc * ndescrpt * 3); cudaErrcheck(res); - - get_i_idx_se_a<<>> (nloc, ilist, i_idx); - - if (max_nbor_size <= 1024) { - format_nbor_list_1024 ( - coord, - type, - jrange, - jlist, - nloc, - rcut, - i_idx, - key - ); - } else if (max_nbor_size <= 2048) { - format_nbor_list_2048 ( - coord, - type, - jrange, - jlist, - nloc, - rcut, - i_idx, - key - ); - } else if (max_nbor_size <= 4096) { - format_nbor_list_4096 ( - coord, - type, - jrange, - jlist, - nloc, - rcut, - i_idx, - key - ); - } - format_nlist_fill_b_se_a<<>> ( - nlist, - nnei, - nloc, - jrange, - jlist, - key, - sec_a_dev, - sec.size(), - nei_iter, - max_nbor_size - ); - - compute_descriptor_se_a <<>> (descript, ndescrpt, descript_deriv, ndescrpt * 3, rij, nnei * 3, type, avg, std, nlist, nnei, coord, rcut_smth, rcut, sec.back()); -} - -template struct DescrptSeAFunctor; -template struct DescrptSeAFunctor; \ No newline at end of file diff --git a/source/op/descrpt_se_a_multi_device.cc b/source/op/descrpt_se_a_multi_device.cc index 1daf11fd20..5dcb7a1682 100644 --- a/source/op/descrpt_se_a_multi_device.cc +++ b/source/op/descrpt_se_a_multi_device.cc @@ -21,239 +21,171 @@ REGISTER_OP("DescrptSeA") .Output("nlist: int32"); // only sel_a and rcut_r uesd. -struct DeviceFunctor { - void operator()(const CPUDevice& d, std::string& device) { - device = "CPU"; - } - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, std::string& device) { - device = "GPU"; - } - #endif // GOOGLE_CUDA -}; - - template class DescrptSeAOp : public OpKernel { public: - explicit DescrptSeAOp(OpKernelConstruction* context) : OpKernel(context) { - float nloc_f, nall_f; - OP_REQUIRES_OK(context, context->GetAttr("rcut_a", &rcut_a)); - OP_REQUIRES_OK(context, context->GetAttr("rcut_r", &rcut_r)); - OP_REQUIRES_OK(context, context->GetAttr("rcut_r_smth", &rcut_r_smth)); - OP_REQUIRES_OK(context, context->GetAttr("sel_a", &sel_a)); - OP_REQUIRES_OK(context, context->GetAttr("sel_r", &sel_r)); - // OP_REQUIRES_OK(context, context->GetAttr("nloc", &nloc_f)); - // OP_REQUIRES_OK(context, context->GetAttr("nall", &nall_f)); - cum_sum (sec_a, sel_a); - cum_sum (sec_r, sel_r); - ndescrpt_a = sec_a.back() * 4; - ndescrpt_r = sec_r.back() * 1; - ndescrpt = ndescrpt_a + ndescrpt_r; - nnei_a = sec_a.back(); - nnei_r = sec_r.back(); - nnei = nnei_a + nnei_r; - fill_nei_a = (rcut_a < 0); - max_nbor_size = 1024; + explicit DescrptSeAOp(OpKernelConstruction* context) : OpKernel(context) { + float nloc_f, nall_f; + OP_REQUIRES_OK(context, context->GetAttr("rcut_a", &rcut_a)); + OP_REQUIRES_OK(context, context->GetAttr("rcut_r", &rcut_r)); + OP_REQUIRES_OK(context, context->GetAttr("rcut_r_smth", &rcut_r_smth)); + OP_REQUIRES_OK(context, context->GetAttr("sel_a", &sel_a)); + OP_REQUIRES_OK(context, context->GetAttr("sel_r", &sel_r)); + // OP_REQUIRES_OK(context, context->GetAttr("nloc", &nloc_f)); + // OP_REQUIRES_OK(context, context->GetAttr("nall", &nall_f)); + cum_sum (sec_a, sel_a); + cum_sum (sec_r, sel_r); + ndescrpt_a = sec_a.back() * 4; + ndescrpt_r = sec_r.back() * 1; + ndescrpt = ndescrpt_a + ndescrpt_r; + nnei_a = sec_a.back(); + nnei_r = sec_r.back(); + nnei = nnei_a + nnei_r; + fill_nei_a = (rcut_a < 0); + max_nbor_size = 1024; + } + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& coord_tensor = context->input(context_input_index++); + const Tensor& type_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); + const Tensor& box_tensor = context->input(context_input_index++); + const Tensor& mesh_tensor = context->input(context_input_index++); + const Tensor& avg_tensor = context->input(context_input_index++); + const Tensor& std_tensor = context->input(context_input_index++); + // set size of the sample. assume 't' is [[[1, 1, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]]], then shape(t) ==> [2, 2, 3] + OP_REQUIRES (context, (coord_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of coord should be 2")); + OP_REQUIRES (context, (type_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of type should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + OP_REQUIRES (context, (box_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of box should be 2")); + OP_REQUIRES (context, (mesh_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of mesh should be 1")); + OP_REQUIRES (context, (avg_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of avg should be 2")); + OP_REQUIRES (context, (std_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of std should be 2")); + OP_REQUIRES (context, (fill_nei_a), errors::InvalidArgument ("Rotational free descriptor only support the case rcut_a < 0")); + OP_REQUIRES (context, (sec_r.back() == 0), errors::InvalidArgument ("Rotational free descriptor only support all-angular information: sel_r should be all zero.")); + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + DeviceFunctor() ( + device, + context->eigen_device() + ); + const int * natoms = natoms_tensor.flat().data(); + int nloc = natoms[0]; + int nall = natoms[1]; + int ntypes = natoms_tensor.shape().dim_size(0) - 2; //nloc and nall mean something. + int nsamples = coord_tensor.shape().dim_size(0); + //// check the sizes + OP_REQUIRES (context, (nsamples == type_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nsamples == box_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (ntypes == avg_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of avg should be ntype")); + OP_REQUIRES (context, (ntypes == std_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of std should be ntype")); + + OP_REQUIRES (context, (nall * 3 == coord_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); + OP_REQUIRES (context, (nall == type_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); + OP_REQUIRES (context, (9 == box_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of box should be 9")); + OP_REQUIRES (context, (ndescrpt == avg_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of avg should be ndescrpt")); + OP_REQUIRES (context, (ndescrpt == std_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of std should be ndescrpt")); + + OP_REQUIRES (context, (ntypes == int(sel_a.size())), errors::InvalidArgument ("number of types should match the length of sel array")); + OP_REQUIRES (context, (ntypes == int(sel_r.size())), errors::InvalidArgument ("number of types should match the length of sel array")); + // Create output tensors + TensorShape descrpt_shape ; + descrpt_shape.AddDim (nsamples); + descrpt_shape.AddDim (nloc * ndescrpt); + TensorShape descrpt_deriv_shape ; + descrpt_deriv_shape.AddDim (nsamples); + descrpt_deriv_shape.AddDim (nloc * ndescrpt * 3); + TensorShape rij_shape ; + rij_shape.AddDim (nsamples); + rij_shape.AddDim (nloc * nnei * 3); + TensorShape nlist_shape ; + nlist_shape.AddDim (nsamples); + nlist_shape.AddDim (nloc * nnei); + // define output tensor + int context_output_index = 0; + Tensor* descrpt_tensor = NULL; + Tensor* descrpt_deriv_tensor = NULL; + Tensor* rij_tensor = NULL; + Tensor* nlist_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + descrpt_shape, + &descrpt_tensor)); + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + descrpt_deriv_shape, + &descrpt_deriv_tensor)); + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + rij_shape, + &rij_tensor)); + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + nlist_shape, + &nlist_tensor)); + + FPTYPE * em = descrpt_tensor->flat().data(); + FPTYPE * em_deriv = descrpt_deriv_tensor->flat().data(); + FPTYPE * rij = rij_tensor->flat().data(); + int * nlist = nlist_tensor->flat().data(); + const FPTYPE * coord = coord_tensor.flat().data(); + const FPTYPE * avg = avg_tensor.flat().data(); + const FPTYPE * std = std_tensor.flat().data(); + const int * type = type_tensor.flat().data(); + + if(device == "GPU") { + // allocate temp memory, temp memory must not be used after this operation! + Tensor int_temp; + TensorShape int_shape; + int_shape.AddDim(sec_a.size() + nloc * sec_a.size() + nloc); + OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); + Tensor uint64_temp; + TensorShape uint64_shape; + uint64_shape.AddDim(nloc * GPU_MAX_NBOR_SIZE * 2); + OP_REQUIRES_OK(context, context->allocate_temp(DT_UINT64, uint64_shape, &uint64_temp)); + array_int = int_temp.flat().data(); + array_longlong = uint64_temp.flat().data(); + env_mat_nbor_update( + init, ilist, jrange, jlist, ilist_size, jrange_size, jlist_size, max_nbor_size, + mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); + OP_REQUIRES (context, (max_nbor_size <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than " + std::to_string(GPU_MAX_NBOR_SIZE) + ", which currently is not supported by deepmd-kit.")); + #if GOOGLE_CUDA + // launch the gpu(nv) compute function + prod_env_mat_a_gpu_nv( + em, em_deriv, rij, nlist, + coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, ntypes, rcut_r, rcut_r_smth, sec_a); + #endif //GOOGLE_CUDA } - - void Compute(OpKernelContext* context) override { - // Grab the input tensor - int context_input_index = 0; - const Tensor& coord_tensor = context->input(context_input_index++); - const Tensor& type_tensor = context->input(context_input_index++); - const Tensor& natoms_tensor = context->input(context_input_index++); - const Tensor& box_tensor = context->input(context_input_index++); - const Tensor& mesh_tensor = context->input(context_input_index++); - const Tensor& avg_tensor = context->input(context_input_index++); - const Tensor& std_tensor = context->input(context_input_index++); - // set size of the sample. assume 't' is [[[1, 1, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]]], then shape(t) ==> [2, 2, 3] - OP_REQUIRES (context, (coord_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of coord should be 2")); - OP_REQUIRES (context, (type_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of type should be 2")); - OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); - OP_REQUIRES (context, (box_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of box should be 2")); - OP_REQUIRES (context, (mesh_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of mesh should be 1")); - OP_REQUIRES (context, (avg_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of avg should be 2")); - OP_REQUIRES (context, (std_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of std should be 2")); - OP_REQUIRES (context, (fill_nei_a), errors::InvalidArgument ("Rotational free descriptor only support the case rcut_a < 0")); - OP_REQUIRES (context, (sec_r.back() == 0), errors::InvalidArgument ("Rotational free descriptor only support all-angular information: sel_r should be all zero.")); - - OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); - - DeviceFunctor() ( - context->eigen_device(), - device - ); - - const int * natoms = natoms_tensor.flat().data(); - int nloc = natoms[0]; - int nall = natoms[1]; - int ntypes = natoms_tensor.shape().dim_size(0) - 2; //nloc and nall mean something. - int nsamples = coord_tensor.shape().dim_size(0); - // - //// check the sizes - OP_REQUIRES (context, (nsamples == type_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (nsamples == box_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (ntypes == avg_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of avg should be ntype")); - OP_REQUIRES (context, (ntypes == std_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of std should be ntype")); - - OP_REQUIRES (context, (nall * 3 == coord_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); - OP_REQUIRES (context, (nall == type_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); - OP_REQUIRES (context, (9 == box_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of box should be 9")); - OP_REQUIRES (context, (ndescrpt == avg_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of avg should be ndescrpt")); - OP_REQUIRES (context, (ndescrpt == std_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of std should be ndescrpt")); - - OP_REQUIRES (context, (ntypes == int(sel_a.size())), errors::InvalidArgument ("number of types should match the length of sel array")); - OP_REQUIRES (context, (ntypes == int(sel_r.size())), errors::InvalidArgument ("number of types should match the length of sel array")); - - // Create output tensors - TensorShape descrpt_shape ; - descrpt_shape.AddDim (nsamples); - descrpt_shape.AddDim (nloc * ndescrpt); - TensorShape descrpt_deriv_shape ; - descrpt_deriv_shape.AddDim (nsamples); - descrpt_deriv_shape.AddDim (nloc * ndescrpt * 3); - TensorShape rij_shape ; - rij_shape.AddDim (nsamples); - rij_shape.AddDim (nloc * nnei * 3); - TensorShape nlist_shape ; - nlist_shape.AddDim (nsamples); - nlist_shape.AddDim (nloc * nnei); - - int context_output_index = 0; - Tensor* descrpt_tensor = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - descrpt_shape, - &descrpt_tensor)); - Tensor* descrpt_deriv_tensor = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - descrpt_deriv_shape, - &descrpt_deriv_tensor)); - Tensor* rij_tensor = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - rij_shape, - &rij_tensor)); - Tensor* nlist_tensor = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - nlist_shape, - &nlist_tensor)); - - FPTYPE * descrpt = descrpt_tensor->flat().data(); - FPTYPE * descrpt_deriv = descrpt_deriv_tensor->flat().data(); - FPTYPE * rij = rij_tensor->flat().data(); - int * nlist = nlist_tensor->flat().data(); - - const FPTYPE * coord = coord_tensor.flat().data(); - const FPTYPE * avg = avg_tensor.flat().data(); - const FPTYPE * std = std_tensor.flat().data(); - const int * type = type_tensor.flat().data(); - - if(device == "GPU") { - // allocate temp memory, temp memory must not be used after this operation! - Tensor int_temp; - TensorShape int_shape; - int_shape.AddDim(sec_a.size() + nloc * sec_a.size() + nloc); - OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); - Tensor uint64_temp; - TensorShape uint64_shape; - uint64_shape.AddDim(nloc * GPU_MAX_NBOR_SIZE * 2); - OP_REQUIRES_OK(context, context->allocate_temp(DT_UINT64, uint64_shape, &uint64_temp)); - - array_int = int_temp.flat().data(); - array_longlong = uint64_temp.flat().data(); - - nbor_update(mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); - OP_REQUIRES (context, (max_nbor_size <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than " + std::to_string(GPU_MAX_NBOR_SIZE) + ", which currently is not supported by deepmd-kit.")); - - // launch gpu compute function - prod_env_mat_a_gpu_nv( - descrpt, descrpt_deriv, rij, nlist, - coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, ntypes, rcut_r, rcut_r_smth, sec_a); - } - else if (device == "CPU") { - memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy (&jrange, 8 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy (&jlist, 12 + mesh_tensor.flat().data(), sizeof(int *)); - - // launch cpu compute function - prod_env_mat_a_cpu( - descrpt, descrpt_deriv, rij, nlist, - coord, type, ilist, jrange, jlist, avg, std, nloc, nall, ntypes, rcut_r, rcut_r_smth, sec_a); - } + else if (device == "CPU") { + memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); + memcpy (&jrange, 8 + mesh_tensor.flat().data(), sizeof(int *)); + memcpy (&jlist, 12 + mesh_tensor.flat().data(), sizeof(int *)); + // launch the cpu compute function + prod_env_mat_a_cpu( + em, em_deriv, rij, nlist, + coord, type, ilist, jrange, jlist, max_nbor_size, avg, std, nloc, nall, ntypes, rcut_r, rcut_r_smth, sec_a); } + } ///////////////////////////////////////////////////////////////////////////////////////////// private: - float rcut_a; - float rcut_r; - float rcut_r_smth; - std::vector sel_r; - std::vector sel_a; - std::vector sec_a; - std::vector sec_r; - int ndescrpt, ndescrpt_a, ndescrpt_r; - int nnei, nnei_a, nnei_r, nloc, nall, max_nbor_size; - bool fill_nei_a; - - //private func - void cum_sum (std::vector & sec, const std::vector & n_sel) const { - sec.resize (n_sel.size() + 1); - sec[0] = 0; - for (int ii = 1; ii < sec.size(); ++ii) { - sec[ii] = sec[ii-1] + n_sel[ii-1]; - } - } - - std::string device; - int *array_int; - unsigned long long*array_longlong; - int * ilist = NULL, * jrange = NULL, * jlist = NULL; - int ilist_size = 0, jrange_size = 0, jlist_size = 0; - bool init = false; - - void nbor_update(const int * mesh, const int size) { - int *mesh_host = new int[size], *ilist_host = NULL, *jrange_host = NULL, *jlist_host = NULL; - cudaErrcheck(cudaMemcpy(mesh_host, mesh, sizeof(int) * size, cudaMemcpyDeviceToHost)); - memcpy (&ilist_host, 4 + mesh_host, sizeof(int *)); - memcpy (&jrange_host, 8 + mesh_host, sizeof(int *)); - memcpy (&jlist_host, 12 + mesh_host, sizeof(int *)); - int const ago = mesh_host[0]; - if (!init) { - ilist_size = (int)(mesh_host[1] * 1.2); - jrange_size = (int)(mesh_host[2] * 1.2); - jlist_size = (int)(mesh_host[3] * 1.2); - cudaErrcheck(cudaMalloc((void **)&ilist, sizeof(int) * ilist_size)); - cudaErrcheck(cudaMalloc((void **)&jrange, sizeof(int) * jrange_size)); - cudaErrcheck(cudaMalloc((void **)&jlist, sizeof(int) * jlist_size)); - init = true; - } - if (ago == 0) { - if (ilist_size < mesh_host[1]) { - ilist_size = (int)(mesh_host[1] * 1.2); - cudaErrcheck(cudaFree(ilist)); - cudaErrcheck(cudaMalloc((void **)&ilist, sizeof(int) * ilist_size)); - } - if (jrange_size < mesh_host[2]) { - jrange_size = (int)(mesh_host[2] * 1.2); - cudaErrcheck(cudaFree(jrange)); - cudaErrcheck(cudaMalloc((void **)&jrange,sizeof(int) * jrange_size)); - } - if (jlist_size < mesh_host[3]) { - jlist_size = (int)(mesh_host[3] * 1.2); - cudaErrcheck(cudaFree(jlist)); - cudaErrcheck(cudaMalloc((void **)&jlist, sizeof(int) * jlist_size)); - } - cudaErrcheck(cudaMemcpy(ilist, ilist_host, sizeof(int) * mesh_host[1], cudaMemcpyHostToDevice)); - cudaErrcheck(cudaMemcpy(jrange, jrange_host, sizeof(int) * mesh_host[2], cudaMemcpyHostToDevice)); - cudaErrcheck(cudaMemcpy(jlist, jlist_host, sizeof(int) * mesh_host[3], cudaMemcpyHostToDevice)); - - max_nbor_size = 1024; - for(int ii = 0; ii < mesh_host[2]; ii++) { - max_nbor_size = (jrange_host[ii + 1] - jrange_host[ii]) > max_nbor_size ? (jrange_host[ii + 1] - jrange_host[ii]) : max_nbor_size; - } - } - delete [] mesh_host; - } + float rcut_a; + float rcut_r; + float rcut_r_smth; + std::vector sel_r; + std::vector sel_a; + std::vector sec_a; + std::vector sec_r; + int ndescrpt, ndescrpt_a, ndescrpt_r; + int nnei, nnei_a, nnei_r, nloc, nall, max_nbor_size; + bool fill_nei_a; + std::string device; + int * array_int = NULL; + unsigned long long * array_longlong = NULL; + bool init = false; + int * ilist = NULL, * jrange = NULL, * jlist = NULL; + int ilist_size = 0, jrange_size = 0, jlist_size = 0; }; // Register the CPU kernels. diff --git a/source/op/descrpt_se_r_multi_device.cc b/source/op/descrpt_se_r_multi_device.cc index fb04b50066..1d25414ea3 100644 --- a/source/op/descrpt_se_r_multi_device.cc +++ b/source/op/descrpt_se_r_multi_device.cc @@ -18,17 +18,6 @@ REGISTER_OP("DescrptSeR") .Output("rij: T") .Output("nlist: int32"); -struct DeviceFunctor { - void operator()(const CPUDevice& d, std::string& device) { - device = "CPU"; - } - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, std::string& device) { - device = "GPU"; - } - #endif // GOOGLE_CUDA -}; - template struct DescrptSeRFunctor { void operator()(const CPUDevice& d, const T * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const T * avg, const T * std, T * descrpt, T * descrpt_deriv, T * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { @@ -82,8 +71,8 @@ class DescrptSeROp : public OpKernel { OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); DeviceFunctor() ( - context->eigen_device(), - device + device, + context->eigen_device() ); const int * natoms = natoms_tensor.flat().data(); From 5be4b025c88f379799f97f296a19f7c670d2c49f Mon Sep 17 00:00:00 2001 From: denghuilu Date: Tue, 23 Feb 2021 03:18:06 +0800 Subject: [PATCH 195/562] adjust indent format of descrpt_se_a_multi --- source/op/descrpt_se_a_multi_device.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/op/descrpt_se_a_multi_device.cc b/source/op/descrpt_se_a_multi_device.cc index 5dcb7a1682..30fb531880 100644 --- a/source/op/descrpt_se_a_multi_device.cc +++ b/source/op/descrpt_se_a_multi_device.cc @@ -153,18 +153,18 @@ class DescrptSeAOp : public OpKernel { #if GOOGLE_CUDA // launch the gpu(nv) compute function prod_env_mat_a_gpu_nv( - em, em_deriv, rij, nlist, - coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, ntypes, rcut_r, rcut_r_smth, sec_a); + em, em_deriv, rij, nlist, + coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, ntypes, rcut_r, rcut_r_smth, sec_a); #endif //GOOGLE_CUDA } else if (device == "CPU") { memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy (&jrange, 8 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy (&jlist, 12 + mesh_tensor.flat().data(), sizeof(int *)); + memcpy (&jrange, 8 + mesh_tensor.flat().data(), sizeof(int *)); + memcpy (&jlist, 12 + mesh_tensor.flat().data(), sizeof(int *)); // launch the cpu compute function prod_env_mat_a_cpu( - em, em_deriv, rij, nlist, - coord, type, ilist, jrange, jlist, max_nbor_size, avg, std, nloc, nall, ntypes, rcut_r, rcut_r_smth, sec_a); + em, em_deriv, rij, nlist, + coord, type, ilist, jrange, jlist, max_nbor_size, avg, std, nloc, nall, ntypes, rcut_r, rcut_r_smth, sec_a); } } From 2ec1e707fd949860b12c271e828c0c789acf326f Mon Sep 17 00:00:00 2001 From: denghuilu Date: Tue, 23 Feb 2021 12:12:51 +0800 Subject: [PATCH 196/562] adjust code structure of custom op --- source/api_cc/include/common.h | 6 +- source/api_cc/src/common.cc | 12 - source/lib/include/lib_common.h | 9 + source/lib/include/prod_env_mat.h | 1 - source/lib/src/cuda/CMakeLists.txt | 2 +- source/lib/src/cuda/descrpt_se_r.cu | 322 +----------------- .../src/cuda/{descrpt_se_a.cu => gpu_nv.cuh} | 151 ++------ source/lib/src/cuda/prod_env_mat_a.cu | 122 +++++++ source/lib/src/lib_common.cc | 13 + source/lib/src/prod_env_mat.cc | 12 +- source/lib/tests/test_env_mat_a.cc | 29 +- source/op/descrpt_se_a_multi_device.cc | 19 +- source/op/descrpt_se_r_multi_device.cc | 1 + 13 files changed, 226 insertions(+), 473 deletions(-) create mode 100644 source/lib/include/lib_common.h rename source/lib/src/cuda/{descrpt_se_a.cu => gpu_nv.cuh} (52%) create mode 100644 source/lib/src/cuda/prod_env_mat_a.cu create mode 100644 source/lib/src/lib_common.cc diff --git a/source/api_cc/include/common.h b/source/api_cc/include/common.h index c3515b2597..209daf7f8d 100644 --- a/source/api_cc/include/common.h +++ b/source/api_cc/include/common.h @@ -259,8 +259,4 @@ struct DeviceFunctor { device = "GPU"; } #endif // GOOGLE_CUDA -}; - -void cum_sum( - std::vector & sec, - const std::vector & n_sel); \ No newline at end of file +}; \ No newline at end of file diff --git a/source/api_cc/src/common.cc b/source/api_cc/src/common.cc index bbd587764a..93ec4b14ca 100644 --- a/source/api_cc/src/common.cc +++ b/source/api_cc/src/common.cc @@ -724,16 +724,4 @@ session_input_tensors ( input_tensors.push_back({"t_aparam", aparam_tensor}); } return nloc; -} - -// functions used in custom ops -void cum_sum( - std::vector & sec, - const std::vector & n_sel) -{ - sec.resize (n_sel.size() + 1); - sec[0] = 0; - for (int ii = 1; ii < sec.size(); ++ii) { - sec[ii] = sec[ii-1] + n_sel[ii-1]; - } } \ No newline at end of file diff --git a/source/lib/include/lib_common.h b/source/lib/include/lib_common.h new file mode 100644 index 0000000000..8fb21c1a85 --- /dev/null +++ b/source/lib/include/lib_common.h @@ -0,0 +1,9 @@ +#pragma once + +#include +#include +#include + +void cum_sum( + std::vector & sec, + const std::vector & n_sel); \ No newline at end of file diff --git a/source/lib/include/prod_env_mat.h b/source/lib/include/prod_env_mat.h index a010eb8181..8f14f3abe8 100644 --- a/source/lib/include/prod_env_mat.h +++ b/source/lib/include/prod_env_mat.h @@ -42,7 +42,6 @@ void prod_env_mat_a_gpu_nv( const FPTYPE * std, const int nloc, const int nall, - const int ntypes, const float rcut, const float rcut_smth, const std::vector sec); diff --git a/source/lib/src/cuda/CMakeLists.txt b/source/lib/src/cuda/CMakeLists.txt index 9aed3c1afb..0c9e33bdc9 100644 --- a/source/lib/src/cuda/CMakeLists.txt +++ b/source/lib/src/cuda/CMakeLists.txt @@ -84,7 +84,7 @@ endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -DCUB_IGNORE_DEPRECATED_CPP_DIALECT -DCUB_IGNORE_DEPRECATED_CPP_DIALECT") set (SOURCE_FILES - descrpt_se_a.cu descrpt_se_r.cu prod_force_se_a.cu prod_force_se_r.cu prod_virial_se_a.cu prod_virial_se_r.cu gelu.cu tabulate.cu + prod_env_mat_a.cu descrpt_se_r.cu prod_force_se_a.cu prod_force_se_r.cu prod_virial_se_a.cu prod_virial_se_r.cu gelu.cu tabulate.cu ) cuda_add_library(deepmd_op_cuda SHARED ${SOURCE_FILES}) diff --git a/source/lib/src/cuda/descrpt_se_r.cu b/source/lib/src/cuda/descrpt_se_r.cu index cb40ed1814..38bc6db854 100644 --- a/source/lib/src/cuda/descrpt_se_r.cu +++ b/source/lib/src/cuda/descrpt_se_r.cu @@ -2,152 +2,9 @@ #include #include #include "DeviceFunctor.h" +#include "gpu_nv.cuh" #include "gpu_nv.h" -template < - typename Key, - int BLOCK_THREADS, - int ITEMS_PER_THREAD> -__launch_bounds__ (BLOCK_THREADS) -__global__ void BlockSortKernel( - Key * d_in, - Key * d_out) // Tile of output -{ - enum { TILE_SIZE = BLOCK_THREADS * ITEMS_PER_THREAD }; - // Specialize BlockLoad type for our thread block (uses warp-striped loads for coalescing, then transposes in shared memory to a blocked arrangement) - typedef cub::BlockLoad BlockLoadT; - // Specialize BlockRadixSort type for our thread block - typedef cub::BlockRadixSort BlockRadixSortT; - // Shared memory - __shared__ union TempStorage - { - typename BlockLoadT::TempStorage load; - typename BlockRadixSortT::TempStorage sort; - } temp_storage; - // Per-thread tile items - Key items[ITEMS_PER_THREAD]; - // Our current block's offset - int block_offset = blockIdx.x * TILE_SIZE; - // Load items into a blocked arrangement - BlockLoadT(temp_storage.load).Load(d_in + block_offset, items); - // Barrier for smem reuse - __syncthreads(); - // Sort keys - BlockRadixSortT(temp_storage.sort).SortBlockedToStriped(items); - // Store output in striped fashion - cub::StoreDirectStriped(threadIdx.x, d_out + block_offset, items); -} - -template -__device__ inline FPTYPE dev_dot(FPTYPE * arr1, FPTYPE * arr2) { - return arr1[0] * arr2[0] + arr1[1] * arr2[1] + arr1[2] * arr2[2]; -} - -template -__device__ inline void spline5_switch(FPTYPE & vv, - FPTYPE & dd, - FPTYPE & xx, - const float & rmin, - const float & rmax) -{ - if (xx < rmin) { - dd = 0; - vv = 1; - } - else if (xx < rmax) { - FPTYPE uu = (xx - rmin) / (rmax - rmin) ; - FPTYPE du = 1. / (rmax - rmin) ; - vv = uu*uu*uu * (-6 * uu*uu + 15 * uu - 10) + 1; - dd = ( 3 * uu*uu * (-6 * uu*uu + 15 * uu - 10) + uu*uu*uu * (-12 * uu + 15) ) * du; - } - else { - dd = 0; - vv = 0; - } -} - -__global__ void get_i_idx_se_r(const int nloc, - const int * ilist, - int * i_idx) -{ - const unsigned int idy = blockIdx.x * blockDim.x + threadIdx.x; - if(idy >= nloc) { - return; - } - i_idx[ilist[idy]] = idy; -} - -template -__global__ void format_nlist_fill_a_se_r(const FPTYPE * coord, - const int * type, - const int * jrange, - const int * jlist, - const float rcut, - int_64 * key, - int * i_idx, - const int MAX_NBOR_SIZE) -{ - // <<>> - const unsigned int idx = blockIdx.x; - const unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y; - - const int nsize = jrange[i_idx[idx] + 1] - jrange[i_idx[idx]]; - if (idy >= nsize) { - return; - } - - const int * nei_idx = jlist + jrange[i_idx[idx]]; - // dev_copy(nei_idx, &jlist[jrange[i_idx]], nsize); - - int_64 * key_in = key + idx * MAX_NBOR_SIZE; - - FPTYPE diff[3]; - const int & j_idx = nei_idx[idy]; - for (int dd = 0; dd < 3; dd++) { - diff[dd] = coord[j_idx * 3 + dd] - coord[idx * 3 + dd]; - } - FPTYPE rr = sqrt(dev_dot(diff, diff)); - if (rr <= rcut) { - key_in[idy] = type[j_idx] * 1E15+ (int_64)(rr * 1.0E13) / 100000 * 100000 + j_idx; - } -} - - // bubble_sort(sel_nei, num_nei); -__global__ void format_nlist_fill_b_se_r(int * nlist, - const int nlist_size, - const int nloc, - const int * jrange, - const int * jlist, - int_64 * key, - const int * sec_a, - const int sec_a_size, - int * nei_iter_dev, - const int MAX_NBOR_SIZE) -{ - - const unsigned int idy = blockIdx.x * blockDim.x + threadIdx.x; - - if(idy >= nloc) { - return; - } - - int * row_nlist = nlist + idy * nlist_size; - int * nei_iter = nei_iter_dev + idy * sec_a_size; - int_64 * key_out = key + nloc * MAX_NBOR_SIZE + idy * MAX_NBOR_SIZE; - - for (int ii = 0; ii < sec_a_size; ii++) { - nei_iter[ii] = sec_a[ii]; - } - - for (unsigned int kk = 0; key_out[kk] != key_out[MAX_NBOR_SIZE - 1]; kk++) { - const int & nei_type = key_out[kk] / 1E15; - if (nei_iter[nei_type] < sec_a[nei_type + 1]) { - row_nlist[nei_iter[nei_type]++] = key_out[kk] % 100000; - } - } -} -//it's ok! - template< typename FPTYPE, int THREADS_PER_BLOCK> @@ -222,180 +79,13 @@ __global__ void compute_descriptor_se_r(FPTYPE* descript, } } - -template -void format_nbor_list_1024 ( - const FPTYPE* coord, - const int* type, - const int* jrange, - const int* jlist, - const int& nloc, - const float& rcut_r, - int * i_idx, - int_64 * key -) -{ - const int LEN = 256; - const int MAX_NBOR_SIZE = 1024; - const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; - dim3 block_grid(nloc, nblock); - dim3 thread_grid(1, LEN); - format_nlist_fill_a_se_r - <<>> ( - coord, - type, - jrange, - jlist, - rcut_r, - key, - i_idx, - MAX_NBOR_SIZE - ); - const int ITEMS_PER_THREAD = 8; - const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; - // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAX_NBOR_SIZE); -} - -template -void format_nbor_list_2048 ( - const FPTYPE* coord, - const int* type, - const int* jrange, - const int* jlist, - const int& nloc, - const float& rcut_r, - int * i_idx, - int_64 * key -) -{ - const int LEN = 256; - const int MAX_NBOR_SIZE = 2048; - const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; - dim3 block_grid(nloc, nblock); - dim3 thread_grid(1, LEN); - format_nlist_fill_a_se_r - <<>> ( - coord, - type, - jrange, - jlist, - rcut_r, - key, - i_idx, - MAX_NBOR_SIZE - ); - const int ITEMS_PER_THREAD = 8; - const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; - // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAX_NBOR_SIZE); -} - -template -void format_nbor_list_4096 ( - const FPTYPE* coord, - const int* type, - const int* jrange, - const int* jlist, - const int& nloc, - const float& rcut_r, - int * i_idx, - int_64 * key -) -{ - const int LEN = 256; - const int MAX_NBOR_SIZE = 4096; - const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; - dim3 block_grid(nloc, nblock); - dim3 thread_grid(1, LEN); - format_nlist_fill_a_se_r - <<>> ( - coord, - type, - jrange, - jlist, - rcut_r, - key, - i_idx, - MAX_NBOR_SIZE - ); - const int ITEMS_PER_THREAD = 16; - const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; - // BlockSortKernel<<>> ( - BlockSortKernel <<>> (key, key + nloc * MAX_NBOR_SIZE); -} - template -void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descript, FPTYPE * descript_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { - const int LEN = 256; - int nblock = (nloc + LEN -1) / LEN; - int * sec_a_dev = array_int; - int * nei_iter = array_int + sec_a.size(); // = new int[sec_a_size]; - int * i_idx = array_int + sec_a.size() + nloc * sec_a.size(); - int_64 * key = array_longlong; - - cudaError_t res = cudaSuccess; - res = cudaMemcpy(sec_a_dev, &sec_a[0], sizeof(int) * sec_a.size(), cudaMemcpyHostToDevice); cudaErrcheck(res); - res = cudaMemset(key, 0xffffffff, sizeof(int_64) * nloc * max_nbor_size); cudaErrcheck(res); - res = cudaMemset(nlist, -1, sizeof(int) * nloc * nnei); cudaErrcheck(res); - res = cudaMemset(descript, 0.0, sizeof(FPTYPE) * nloc * ndescrpt); cudaErrcheck(res); - res = cudaMemset(descript_deriv, 0.0, sizeof(FPTYPE) * nloc * ndescrpt * 3); cudaErrcheck(res); - - if (fill_nei_a) { - // ~~~ - // cudaProfilerStart(); - get_i_idx_se_r<<>> (nloc, ilist, i_idx); - - if (max_nbor_size <= 1024) { - format_nbor_list_1024 ( - coord, - type, - jrange, - jlist, - nloc, - rcut_r, - i_idx, - key - ); - } else if (max_nbor_size <= 2048) { - format_nbor_list_2048 ( - coord, - type, - jrange, - jlist, - nloc, - rcut_r, - i_idx, - key - ); - } else if (max_nbor_size <= 4096) { - format_nbor_list_4096 ( - coord, - type, - jrange, - jlist, - nloc, - rcut_r, - i_idx, - key - ); - } - - format_nlist_fill_b_se_r<<>> ( - nlist, - nnei, - nloc, - jrange, - jlist, - key, - sec_a_dev, - sec_a.size(), - nei_iter, - max_nbor_size - ); - } +void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * em, FPTYPE * em_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { + prod_env_mat_common( + em, em_deriv, rij, nlist, + coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, rcut_r, rcut_r_smth, sec_a); - compute_descriptor_se_r <<>> (descript, ndescrpt, descript_deriv, ndescrpt * 3, rij, nnei * 3, type, avg, std, nlist, nnei, coord, rcut_r_smth, rcut_r, sec_a.back()); + compute_descriptor_se_r <<>> (em, ndescrpt, em_deriv, ndescrpt * 3, rij, nnei * 3, type, avg, std, nlist, nnei, coord, rcut_r_smth, rcut_r, sec_a.back()); } template struct DescrptSeRGPUExecuteFunctor; diff --git a/source/lib/src/cuda/descrpt_se_a.cu b/source/lib/src/cuda/gpu_nv.cuh similarity index 52% rename from source/lib/src/cuda/descrpt_se_a.cu rename to source/lib/src/cuda/gpu_nv.cuh index e9f2fb8b77..d2f681984e 100644 --- a/source/lib/src/cuda/descrpt_se_a.cu +++ b/source/lib/src/cuda/gpu_nv.cuh @@ -1,9 +1,10 @@ +#pragma once +#include "gpu_nv.h" #include #include #include -#include "prod_env_mat.h" -#include "gpu_nv.h" +// common part of prod_env_mat template < typename Key, int BLOCK_THREADS, @@ -51,8 +52,8 @@ __device__ inline void spline5_switch( FPTYPE & vv, FPTYPE & dd, FPTYPE & xx, - const float & rmin, - const float & rmax) + const float & rmin, + const float & rmax) { if (xx < rmin) { dd = 0; @@ -70,10 +71,11 @@ __device__ inline void spline5_switch( } } -__global__ void get_i_idx_se_a( - int * i_idx, +template +__global__ void get_i_idx( + FPTYPE * i_idx, const int nloc, - const int * ilist) + const FPTYPE * ilist) { const unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x; if(idx >= nloc) { @@ -83,7 +85,7 @@ __global__ void get_i_idx_se_a( } template -__global__ void format_nlist_fill_a_se_a( +__global__ void format_nlist_fill_a( int_64 * key, const FPTYPE * coord, const int * type, @@ -107,25 +109,26 @@ __global__ void format_nlist_fill_a_se_a( FPTYPE diff[3]; const int & j_idx = nei_idx[idy]; for (int dd = 0; dd < 3; dd++) { - diff[dd] = coord[j_idx * 3 + dd] - coord[idx * 3 + dd]; + diff[dd] = coord[j_idx * 3 + dd] - coord[idx * 3 + dd]; } FPTYPE rr = sqrt(dev_dot(diff, diff)); if (rr <= rcut) { - key_in[idy] = type[j_idx] * 1E15+ (int_64)(rr * 1.0E13) / 100000 * 100000 + j_idx; + key_in[idy] = type[j_idx] * 1E15+ (int_64)(rr * 1.0E13) / 100000 * 100000 + j_idx; } } -__global__ void format_nlist_fill_b_se_a( +template +__global__ void format_nlist_fill_b( int * nlist, const int nlist_size, const int nloc, const int * jrange, const int * jlist, - int_64 * key, + FPTYPE * key, const int * sec, const int sec_size, int * nei_iter_dev, - const int MAX_NBOR_SIZE) + const int max_nbor_size) { const unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x; if(idx >= nloc) { @@ -134,12 +137,12 @@ __global__ void format_nlist_fill_b_se_a( int * row_nlist = nlist + idx * nlist_size; int * nei_iter = nei_iter_dev + idx * sec_size; - int_64 * key_out = key + nloc * MAX_NBOR_SIZE + idx * MAX_NBOR_SIZE; + FPTYPE * key_out = key + nloc * max_nbor_size + idx * max_nbor_size; for (int ii = 0; ii < sec_size; ii++) { nei_iter[ii] = sec[ii]; } - for (unsigned int kk = 0; key_out[kk] != key_out[MAX_NBOR_SIZE - 1]; kk++) { + for (unsigned int kk = 0; key_out[kk] != key_out[max_nbor_size - 1]; kk++) { const int & nei_type = key_out[kk] / 1E15; if (nei_iter[nei_type] < sec[nei_type + 1]) { row_nlist[nei_iter[nei_type]++] = key_out[kk] % 100000; @@ -147,92 +150,6 @@ __global__ void format_nlist_fill_b_se_a( } } -template< - typename FPTYPE, - int THREADS_PER_BLOCK> -__global__ void compute_em_mat_a( - FPTYPE* em, - FPTYPE* em_deriv, - FPTYPE* rij, - const FPTYPE* coord, - const FPTYPE* avg, - const FPTYPE* std, - const int* type, - const int* nlist, - const int nnei, - const float rmin, - const float rmax) -{ - // <<>> - const unsigned int bid = blockIdx.x; - const unsigned int tid = threadIdx.x; - if (tid >= nnei) { - return; - } - const int ndescrpt = nnei * 4; - const int * row_nlist = nlist + bid * nnei; - FPTYPE * row_rij = rij + bid * nnei * 3; - FPTYPE * row_descript = em + bid * nnei * 4; - FPTYPE * row_descript_deriv = em_deriv + bid * nnei * 12; - for (int ii = tid; ii < nnei; ii += THREADS_PER_BLOCK) { - const int idx_value = ii * 4; // 4 components - const int idx_deriv = ii * 12; // 4 components time 3 directions - if (row_nlist[ii] >= 0) { - FPTYPE rr[3] = {0}; - FPTYPE dd[4] = {0}; - FPTYPE vv[12] = {0}; - const int j_idx = row_nlist[ii]; - for (int kk = 0; kk < 3; kk++) { - rr[kk] = coord[j_idx * 3 + kk] - coord[bid * 3 + kk]; - row_rij[ii * 3 + kk] = rr[kk]; - } - // const FPTYPE * rr = &row_rij[ii * 3]; - FPTYPE nr2 = dev_dot(rr, rr); - FPTYPE inr = 1./sqrt(nr2); - FPTYPE nr = nr2 * inr; - FPTYPE inr2 = inr * inr; - FPTYPE inr4 = inr2 * inr2; - FPTYPE inr3 = inr4 * nr; - FPTYPE sw, dsw; - spline5_switch(sw, dsw, nr, rmin, rmax); - dd[0] = (1./nr) ;//* sw; - dd[1] = (rr[0] / nr2) ;//* sw; - dd[2] = (rr[1] / nr2) ;//* sw; - dd[3] = (rr[2] / nr2) ;//* sw; - vv[0] = (rr[0] * inr3 * sw - dd[0] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 0) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 0) % (ndescrpt * 3)) / 3]; - vv[1] = (rr[1] * inr3 * sw - dd[0] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 1) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 1) % (ndescrpt * 3)) / 3]; - vv[2] = (rr[2] * inr3 * sw - dd[0] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 2) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 2) % (ndescrpt * 3)) / 3]; - // ****deriv of component x/r2 - vv[3] = ((2. * rr[0] * rr[0] * inr4 - inr2) * sw - dd[1] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 3) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 3) % (ndescrpt * 3)) / 3]; - vv[4] = ((2. * rr[0] * rr[1] * inr4 ) * sw - dd[1] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 4) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 4) % (ndescrpt * 3)) / 3]; - vv[5] = ((2. * rr[0] * rr[2] * inr4 ) * sw - dd[1] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 5) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 5) % (ndescrpt * 3)) / 3]; - // ***deriv of component y/r2 - vv[6] = ((2. * rr[1] * rr[0] * inr4 ) * sw - dd[2] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 6) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 6) % (ndescrpt * 3)) / 3]; - vv[7] = ((2. * rr[1] * rr[1] * inr4 - inr2) * sw - dd[2] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 7) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 7) % (ndescrpt * 3)) / 3]; - vv[8] = ((2. * rr[1] * rr[2] * inr4 ) * sw - dd[2] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 8) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 8) % (ndescrpt * 3)) / 3]; - // ***deriv of component z/r2 - vv[9] = ((2. * rr[2] * rr[0] * inr4 ) * sw - dd[3] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 9) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 9) % (ndescrpt * 3)) / 3]; - vv[10]= ((2. * rr[2] * rr[1] * inr4 ) * sw - dd[3] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 10) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 10) % (ndescrpt * 3)) / 3]; - vv[11]= ((2. * rr[2] * rr[2] * inr4 - inr2) * sw - dd[3] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 11) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 11) % (ndescrpt * 3)) / 3]; - // 4 value components - dd[0] *= sw; // * em[idx * ndescrpt + idx_value + 0]);// - avg[type[idx] * ndescrpt + idx_value + 0]) / std[type[idx] * ndescrpt + idx_value + 0]; - dd[1] *= sw; // * em[idx * ndescrpt + idx_value + 1]);// - avg[type[idx] * ndescrpt + idx_value + 1]) / std[type[idx] * ndescrpt + idx_value + 1]; - dd[2] *= sw; // * em[idx * ndescrpt + idx_value + 2]);// - avg[type[idx] * ndescrpt + idx_value + 2]) / std[type[idx] * ndescrpt + idx_value + 2]; - dd[3] *= sw; // * em[idx * ndescrpt + idx_value + 3]);// - avg[type[idx] * ndescrpt + idx_value + 3]) / std[type[idx] * ndescrpt + idx_value + 3]; - for (int ii = 0; ii < 12; ii++) { - row_descript_deriv[idx_deriv + ii] = vv[ii] / std[type[bid] * ndescrpt + idx_value + ii / 3]; - } - for (int ii = 0; ii < 4; ii++) { - row_descript[idx_value + ii] = (dd[ii] - avg[type[bid] * ndescrpt + idx_value + ii]) / std[type[bid] * ndescrpt + idx_value + ii]; - } - } - else { - // TODO: move it to the memset. - row_descript[idx_value] -= avg[type[bid] * ndescrpt + idx_value] / std[type[bid] * ndescrpt + idx_value]; - } - } -} - template void format_nbor_list_1024 ( int_64 * key, @@ -249,7 +166,7 @@ void format_nbor_list_1024 ( const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; dim3 block_grid(nloc, nblock); dim3 thread_grid(1, LEN); - format_nlist_fill_a_se_a<<>> ( + format_nlist_fill_a<<>> ( key, coord, type, jrange, jlist, rcut, i_idx, MAX_NBOR_SIZE); const int ITEMS_PER_THREAD = 8; @@ -276,7 +193,7 @@ void format_nbor_list_2048 ( const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; dim3 block_grid(nloc, nblock); dim3 thread_grid(1, LEN); - format_nlist_fill_a_se_a<<>> ( + format_nlist_fill_a<<>> ( key, coord, type, jrange, jlist, rcut, i_idx, MAX_NBOR_SIZE); const int ITEMS_PER_THREAD = 8; @@ -303,7 +220,7 @@ void format_nbor_list_4096 ( const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; dim3 block_grid(nloc, nblock); dim3 thread_grid(1, LEN); - format_nlist_fill_a_se_a<<>> ( + format_nlist_fill_a<<>> ( key, coord, type, jrange, jlist, rcut, i_idx, MAX_NBOR_SIZE); const int ITEMS_PER_THREAD = 16; @@ -315,7 +232,7 @@ void format_nbor_list_4096 ( } template -void prod_env_mat_a_gpu_nv( +void prod_env_mat_common( FPTYPE * em, FPTYPE * em_deriv, FPTYPE * rij, @@ -332,7 +249,6 @@ void prod_env_mat_a_gpu_nv( const FPTYPE * std, const int nloc, const int nall, - const int ntypes, const float rcut, const float rcut_smth, const std::vector sec) @@ -345,41 +261,34 @@ void prod_env_mat_a_gpu_nv( int * nei_iter = array_int + sec.size(); // = new int[sec_size]; int * i_idx = array_int + sec.size() + nloc * sec.size(); int_64 * key = array_longlong; - + assert(max_nbor_size == 1024 || max_nbor_size == 2048 || max_nbor_size == 4096); cudaErrcheck(cudaMemcpy(sec_dev, &sec[0], sizeof(int) * sec.size(), cudaMemcpyHostToDevice)); - cudaErrcheck(cudaMemset(key, 0xffffffff, sizeof(int_64) * nloc * GPU_MAX_NBOR_SIZE)); + cudaErrcheck(cudaMemset(key, 0xffffffff, sizeof(int_64) * nloc * max_nbor_size)); cudaErrcheck(cudaMemset(nlist, -1, sizeof(int) * nloc * nnei)); cudaErrcheck(cudaMemset(em, 0.0, sizeof(FPTYPE) * nloc * ndescrpt)); cudaErrcheck(cudaMemset(em_deriv, 0.0, sizeof(FPTYPE) * nloc * ndescrpt * 3)); - get_i_idx_se_a<<>>( + get_i_idx<<>>( i_idx, nloc, ilist); - if (max_nbor_size <= 1024) { + if (max_nbor_size == 1024) { format_nbor_list_1024 ( key, coord, type, jrange, jlist, nloc, rcut, i_idx); } - else if (max_nbor_size <= 2048) { + else if (max_nbor_size == 2048) { format_nbor_list_2048 ( key, coord, type, jrange, jlist, nloc, rcut, i_idx); } - else if (max_nbor_size <= 4096) { + else if (max_nbor_size == 4096) { format_nbor_list_4096 ( key, coord, type, jrange, jlist, nloc, rcut, i_idx); } - format_nlist_fill_b_se_a<<>> ( + format_nlist_fill_b<<>> ( nlist, nnei, nloc, jrange, jlist, key, sec_dev, sec.size(), nei_iter, max_nbor_size); - - compute_em_mat_a <<>> ( - em, em_deriv, rij, - coord, avg, std, type, nlist, nnei, rcut_smth, rcut); -} - -template void prod_env_mat_a_gpu_nv(float * em, float * em_deriv, float * rij, int * nlist, const float * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const float * avg, const float * std, const int nloc, const int nall, const int ntypes, const float rcut, const float rcut_smth, const std::vector sec); -template void prod_env_mat_a_gpu_nv(double * em, double * em_deriv, double * rij, int * nlist, const double * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const double * avg, const double * std, const int nloc, const int nall, const int ntypes, const float rcut, const float rcut_smth, const std::vector sec); \ No newline at end of file +} \ No newline at end of file diff --git a/source/lib/src/cuda/prod_env_mat_a.cu b/source/lib/src/cuda/prod_env_mat_a.cu new file mode 100644 index 0000000000..2702b30f9f --- /dev/null +++ b/source/lib/src/cuda/prod_env_mat_a.cu @@ -0,0 +1,122 @@ +#include "prod_env_mat.h" +#include "gpu_nv.cuh" + +template< + typename FPTYPE, + int THREADS_PER_BLOCK> +__global__ void compute_em_mat_a( + FPTYPE* em, + FPTYPE* em_deriv, + FPTYPE* rij, + const FPTYPE* coord, + const FPTYPE* avg, + const FPTYPE* std, + const int* type, + const int* nlist, + const int nnei, + const float rmin, + const float rmax) +{ + // <<>> + const unsigned int bid = blockIdx.x; + const unsigned int tid = threadIdx.x; + if (tid >= nnei) { + return; + } + const int ndescrpt = nnei * 4; + const int * row_nlist = nlist + bid * nnei; + FPTYPE * row_rij = rij + bid * nnei * 3; + FPTYPE * row_descript = em + bid * nnei * 4; + FPTYPE * row_descript_deriv = em_deriv + bid * nnei * 12; + for (int ii = tid; ii < nnei; ii += THREADS_PER_BLOCK) { + const int idx_value = ii * 4; // 4 components + const int idx_deriv = ii * 12; // 4 components time 3 directions + if (row_nlist[ii] >= 0) { + FPTYPE rr[3] = {0}; + FPTYPE dd[4] = {0}; + FPTYPE vv[12] = {0}; + const int j_idx = row_nlist[ii]; + for (int kk = 0; kk < 3; kk++) { + rr[kk] = coord[j_idx * 3 + kk] - coord[bid * 3 + kk]; + row_rij[ii * 3 + kk] = rr[kk]; + } + // const FPTYPE * rr = &row_rij[ii * 3]; + FPTYPE nr2 = dev_dot(rr, rr); + FPTYPE inr = 1./sqrt(nr2); + FPTYPE nr = nr2 * inr; + FPTYPE inr2 = inr * inr; + FPTYPE inr4 = inr2 * inr2; + FPTYPE inr3 = inr4 * nr; + FPTYPE sw, dsw; + spline5_switch(sw, dsw, nr, rmin, rmax); + dd[0] = (1./nr) ;//* sw; + dd[1] = (rr[0] / nr2) ;//* sw; + dd[2] = (rr[1] / nr2) ;//* sw; + dd[3] = (rr[2] / nr2) ;//* sw; + vv[0] = (rr[0] * inr3 * sw - dd[0] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 0) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 0) % (ndescrpt * 3)) / 3]; + vv[1] = (rr[1] * inr3 * sw - dd[0] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 1) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 1) % (ndescrpt * 3)) / 3]; + vv[2] = (rr[2] * inr3 * sw - dd[0] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 2) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 2) % (ndescrpt * 3)) / 3]; + // ****deriv of component x/r2 + vv[3] = ((2. * rr[0] * rr[0] * inr4 - inr2) * sw - dd[1] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 3) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 3) % (ndescrpt * 3)) / 3]; + vv[4] = ((2. * rr[0] * rr[1] * inr4 ) * sw - dd[1] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 4) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 4) % (ndescrpt * 3)) / 3]; + vv[5] = ((2. * rr[0] * rr[2] * inr4 ) * sw - dd[1] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 5) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 5) % (ndescrpt * 3)) / 3]; + // ***deriv of component y/r2 + vv[6] = ((2. * rr[1] * rr[0] * inr4 ) * sw - dd[2] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 6) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 6) % (ndescrpt * 3)) / 3]; + vv[7] = ((2. * rr[1] * rr[1] * inr4 - inr2) * sw - dd[2] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 7) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 7) % (ndescrpt * 3)) / 3]; + vv[8] = ((2. * rr[1] * rr[2] * inr4 ) * sw - dd[2] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 8) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 8) % (ndescrpt * 3)) / 3]; + // ***deriv of component z/r2 + vv[9] = ((2. * rr[2] * rr[0] * inr4 ) * sw - dd[3] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 9) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 9) % (ndescrpt * 3)) / 3]; + vv[10]= ((2. * rr[2] * rr[1] * inr4 ) * sw - dd[3] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 10) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 10) % (ndescrpt * 3)) / 3]; + vv[11]= ((2. * rr[2] * rr[2] * inr4 - inr2) * sw - dd[3] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 11) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 11) % (ndescrpt * 3)) / 3]; + // 4 value components + dd[0] *= sw; // * em[idx * ndescrpt + idx_value + 0]);// - avg[type[idx] * ndescrpt + idx_value + 0]) / std[type[idx] * ndescrpt + idx_value + 0]; + dd[1] *= sw; // * em[idx * ndescrpt + idx_value + 1]);// - avg[type[idx] * ndescrpt + idx_value + 1]) / std[type[idx] * ndescrpt + idx_value + 1]; + dd[2] *= sw; // * em[idx * ndescrpt + idx_value + 2]);// - avg[type[idx] * ndescrpt + idx_value + 2]) / std[type[idx] * ndescrpt + idx_value + 2]; + dd[3] *= sw; // * em[idx * ndescrpt + idx_value + 3]);// - avg[type[idx] * ndescrpt + idx_value + 3]) / std[type[idx] * ndescrpt + idx_value + 3]; + for (int ii = 0; ii < 12; ii++) { + row_descript_deriv[idx_deriv + ii] = vv[ii] / std[type[bid] * ndescrpt + idx_value + ii / 3]; + } + for (int ii = 0; ii < 4; ii++) { + row_descript[idx_value + ii] = (dd[ii] - avg[type[bid] * ndescrpt + idx_value + ii]) / std[type[bid] * ndescrpt + idx_value + ii]; + } + } + else { + // TODO: move it to the memset. + row_descript[idx_value] -= avg[type[bid] * ndescrpt + idx_value] / std[type[bid] * ndescrpt + idx_value]; + } + } +} + +template +void prod_env_mat_a_gpu_nv( + FPTYPE * em, + FPTYPE * em_deriv, + FPTYPE * rij, + int * nlist, + const FPTYPE * coord, + const int * type, + const int * ilist, + const int * jrange, + const int * jlist, + int * array_int, + int_64 * array_longlong, + const int max_nbor_size, + const FPTYPE * avg, + const FPTYPE * std, + const int nloc, + const int nall, + const float rcut, + const float rcut_smth, + const std::vector sec) +{ + prod_env_mat_common( + em, em_deriv, rij, nlist, + coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); + + compute_em_mat_a <<>> ( + em, em_deriv, rij, + coord, avg, std, type, nlist, sec.back(), rcut_smth, rcut); +} + +template void prod_env_mat_a_gpu_nv(float * em, float * em_deriv, float * rij, int * nlist, const float * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const float * avg, const float * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); +template void prod_env_mat_a_gpu_nv(double * em, double * em_deriv, double * rij, int * nlist, const double * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const double * avg, const double * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); \ No newline at end of file diff --git a/source/lib/src/lib_common.cc b/source/lib/src/lib_common.cc new file mode 100644 index 0000000000..c02f7f86c3 --- /dev/null +++ b/source/lib/src/lib_common.cc @@ -0,0 +1,13 @@ +#include "lib_common.h" + +// functions used in custom ops +void cum_sum( + std::vector & sec, + const std::vector & n_sel) +{ + sec.resize (n_sel.size() + 1); + sec[0] = 0; + for (int ii = 1; ii < sec.size(); ++ii) { + sec[ii] = sec[ii-1] + n_sel[ii-1]; + } +} \ No newline at end of file diff --git a/source/lib/src/prod_env_mat.cc b/source/lib/src/prod_env_mat.cc index 13bb5f3eaf..c0070bde72 100644 --- a/source/lib/src/prod_env_mat.cc +++ b/source/lib/src/prod_env_mat.cc @@ -181,10 +181,20 @@ void env_mat_nbor_update( cudaErrcheck(cudaMemcpy(jrange, jrange_host, sizeof(int) * mesh_host[2], cudaMemcpyHostToDevice)); cudaErrcheck(cudaMemcpy(jlist, jlist_host, sizeof(int) * mesh_host[3], cudaMemcpyHostToDevice)); - max_nbor_size = 1024; + max_nbor_size = 0; for(int ii = 0; ii < mesh_host[2]; ii++) { max_nbor_size = (jrange_host[ii + 1] - jrange_host[ii]) > max_nbor_size ? (jrange_host[ii + 1] - jrange_host[ii]) : max_nbor_size; } + assert(max_nbor_size <= GPU_MAX_NBOR_SIZE); + if (max_nbor_size <= 1024) { + max_nbor_size = 1024; + } + else if (max_nbor_size <= 2048) { + max_nbor_size = 2048; + } + else { + max_nbor_size = 4096; + } } delete [] mesh_host; } diff --git a/source/lib/tests/test_env_mat_a.cc b/source/lib/tests/test_env_mat_a.cc index beee75f07b..5282df47b2 100644 --- a/source/lib/tests/test_env_mat_a.cc +++ b/source/lib/tests/test_env_mat_a.cc @@ -527,9 +527,6 @@ TEST_F(TestEnvMatA, prod_cpu_equal_cpu) #if GOOGLE_CUDA - -#include "device_common.h" - TEST_F(TestEnvMatA, prod_gpu_nv) { EXPECT_EQ(nlist_r_cpy.size(), nloc); @@ -541,6 +538,16 @@ TEST_F(TestEnvMatA, prod_gpu_nv) max_nbor_size = nlist_a_cpy[ii].size(); } } + assert(max_nbor_size <= GPU_MAX_NBOR_SIZE); + if (max_nbor_size <= 1024) { + max_nbor_size = 1024; + } + else if (max_nbor_size <= 2048) { + max_nbor_size = 2048; + } + else { + max_nbor_size = 4096; + } std::vector ilist(nloc), jlist(tot_nnei), jrange(nloc+1, 0); for (int ii = 0; ii < nloc; ++ii){ ilist[ii] = ii; @@ -587,12 +594,11 @@ TEST_F(TestEnvMatA, prod_gpu_nv) jlist_dev, array_int_dev, array_longlong_dev, - GPU_MAX_NBOR_SIZE, + max_nbor_size, avg_dev, std_dev, nloc, nall, - ntypes, rc, rc_smth, sec_a); @@ -633,6 +639,16 @@ TEST_F(TestEnvMatA, prod_gpu_equal_cpu) max_nbor_size = nlist_a_cpy[ii].size(); } } + assert(max_nbor_size <= GPU_MAX_NBOR_SIZE); + if (max_nbor_size <= 1024) { + max_nbor_size = 1024; + } + else if (max_nbor_size <= 2048) { + max_nbor_size = 2048; + } + else { + max_nbor_size = 4096; + } std::vector ilist(nloc), jlist(tot_nnei), jrange(nloc+1, 0); for (int ii = 0; ii < nloc; ++ii){ ilist[ii] = ii; @@ -679,12 +695,11 @@ TEST_F(TestEnvMatA, prod_gpu_equal_cpu) jlist_dev, array_int_dev, array_longlong_dev, - GPU_MAX_NBOR_SIZE, + max_nbor_size, avg_dev, std_dev, nloc, nall, - ntypes, rc, rc_smth, sec_a); diff --git a/source/op/descrpt_se_a_multi_device.cc b/source/op/descrpt_se_a_multi_device.cc index 30fb531880..b66b139b2f 100644 --- a/source/op/descrpt_se_a_multi_device.cc +++ b/source/op/descrpt_se_a_multi_device.cc @@ -1,4 +1,5 @@ #include "common.h" +#include "lib_common.h" #include "prod_env_mat.h" REGISTER_OP("DescrptSeA") @@ -110,20 +111,20 @@ class DescrptSeAOp : public OpKernel { Tensor* nlist_tensor = NULL; OP_REQUIRES_OK(context, context->allocate_output( context_output_index++, - descrpt_shape, - &descrpt_tensor)); + descrpt_shape, + &descrpt_tensor)); OP_REQUIRES_OK(context, context->allocate_output( context_output_index++, - descrpt_deriv_shape, - &descrpt_deriv_tensor)); + descrpt_deriv_shape, + &descrpt_deriv_tensor)); OP_REQUIRES_OK(context, context->allocate_output( context_output_index++, - rij_shape, - &rij_tensor)); + rij_shape, + &rij_tensor)); OP_REQUIRES_OK(context, context->allocate_output( context_output_index++, - nlist_shape, - &nlist_tensor)); + nlist_shape, + &nlist_tensor)); FPTYPE * em = descrpt_tensor->flat().data(); FPTYPE * em_deriv = descrpt_deriv_tensor->flat().data(); @@ -154,7 +155,7 @@ class DescrptSeAOp : public OpKernel { // launch the gpu(nv) compute function prod_env_mat_a_gpu_nv( em, em_deriv, rij, nlist, - coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, ntypes, rcut_r, rcut_r_smth, sec_a); + coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, rcut_r, rcut_r_smth, sec_a); #endif //GOOGLE_CUDA } else if (device == "CPU") { diff --git a/source/op/descrpt_se_r_multi_device.cc b/source/op/descrpt_se_r_multi_device.cc index 1d25414ea3..5a830f0266 100644 --- a/source/op/descrpt_se_r_multi_device.cc +++ b/source/op/descrpt_se_r_multi_device.cc @@ -1,4 +1,5 @@ #include "common.h" +#include "lib_common.h" #include "CustomeOperation.h" REGISTER_OP("DescrptSeR") From bc6fa9b11670be79f94fec926c5694f3704eea53 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 24 Feb 2021 11:25:08 +0800 Subject: [PATCH 197/562] remove global path of polar examples. --- examples/water/train/polar.json | 2 +- examples/water/train/polar_se_a.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/water/train/polar.json b/examples/water/train/polar.json index 60e3fa3494..28e82d4587 100644 --- a/examples/water/train/polar.json +++ b/examples/water/train/polar.json @@ -39,7 +39,7 @@ "_comment": " traing controls", "training": { - "systems": ["/home/wanghan/study/deep.md/data/polar/bulk"], + "systems": ["/path/to/data/polar/bulk"], "set_prefix": "set", "stop_batch": 1000000, "batch_size": [4], diff --git a/examples/water/train/polar_se_a.json b/examples/water/train/polar_se_a.json index dc90e481ce..048c12f765 100644 --- a/examples/water/train/polar_se_a.json +++ b/examples/water/train/polar_se_a.json @@ -37,7 +37,7 @@ "_comment": " traing controls", "training": { - "systems": ["/home/wanghan/study/deep.md/data/polar/bulk"], + "systems": ["/path/to/data/polar/bulk"], "set_prefix": "set", "stop_batch": 1000000, "batch_size": [1], From 2265ad6b446bba500e1413de37b7c0731d5a7d53 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Wed, 24 Feb 2021 11:47:44 +0800 Subject: [PATCH 198/562] change the files name in 'lib/include' --- source/api_cc/src/common.cc | 2 +- source/lib/include/DeviceFunctor.h | 2 +- .../lib/include/{device_common.h => device.h} | 0 source/lib/include/gpu_nv.h | 3 ++ source/lib/include/prod_env_mat.h | 2 +- .../lib/include/{lib_common.h => utilities.h} | 0 source/lib/src/cuda/CMakeLists.txt | 2 +- source/lib/src/cuda/gpu_nv.cu | 44 +++++++++++++++++++ source/lib/src/cuda/gpu_nv.cuh | 30 +------------ .../lib/src/{lib_common.cc => utilities.cc} | 2 +- source/lib/tests/CMakeLists.txt | 11 ++--- source/lib/tests/test_env_mat_a.cc | 4 +- source/op/descrpt_se_a_multi_device.cc | 2 +- source/op/descrpt_se_r_multi_device.cc | 2 +- 14 files changed, 63 insertions(+), 43 deletions(-) rename source/lib/include/{device_common.h => device.h} (100%) rename source/lib/include/{lib_common.h => utilities.h} (100%) create mode 100644 source/lib/src/cuda/gpu_nv.cu rename source/lib/src/{lib_common.cc => utilities.cc} (91%) diff --git a/source/api_cc/src/common.cc b/source/api_cc/src/common.cc index 93ec4b14ca..31981658ee 100644 --- a/source/api_cc/src/common.cc +++ b/source/api_cc/src/common.cc @@ -1,7 +1,7 @@ #include "common.h" #include "NNPAtomMap.h" #include "SimulationRegion.h" -#include "device_common.h" +#include "device.h" void select_by_type(std::vector & fwd_map, diff --git a/source/lib/include/DeviceFunctor.h b/source/lib/include/DeviceFunctor.h index fa4a94b004..c422b013b0 100644 --- a/source/lib/include/DeviceFunctor.h +++ b/source/lib/include/DeviceFunctor.h @@ -3,7 +3,7 @@ #include #include #include -#include "device_common.h" +#include "device.h" template struct DescrptSeRGPUExecuteFunctor { diff --git a/source/lib/include/device_common.h b/source/lib/include/device.h similarity index 100% rename from source/lib/include/device_common.h rename to source/lib/include/device.h diff --git a/source/lib/include/gpu_nv.h b/source/lib/include/gpu_nv.h index 72565b886c..2f5c3c5957 100644 --- a/source/lib/include/gpu_nv.h +++ b/source/lib/include/gpu_nv.h @@ -1,4 +1,7 @@ #pragma once +#include +#include +#include #include #define GPU_MAX_NBOR_SIZE 4096 diff --git a/source/lib/include/prod_env_mat.h b/source/lib/include/prod_env_mat.h index 8f14f3abe8..795c3eaeda 100644 --- a/source/lib/include/prod_env_mat.h +++ b/source/lib/include/prod_env_mat.h @@ -1,6 +1,6 @@ #pragma once #include -#include "device_common.h" +#include "device.h" template void prod_env_mat_a_cpu( diff --git a/source/lib/include/lib_common.h b/source/lib/include/utilities.h similarity index 100% rename from source/lib/include/lib_common.h rename to source/lib/include/utilities.h diff --git a/source/lib/src/cuda/CMakeLists.txt b/source/lib/src/cuda/CMakeLists.txt index 0c9e33bdc9..3c09a814dd 100644 --- a/source/lib/src/cuda/CMakeLists.txt +++ b/source/lib/src/cuda/CMakeLists.txt @@ -84,7 +84,7 @@ endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -DCUB_IGNORE_DEPRECATED_CPP_DIALECT -DCUB_IGNORE_DEPRECATED_CPP_DIALECT") set (SOURCE_FILES - prod_env_mat_a.cu descrpt_se_r.cu prod_force_se_a.cu prod_force_se_r.cu prod_virial_se_a.cu prod_virial_se_r.cu gelu.cu tabulate.cu + prod_env_mat_a.cu descrpt_se_r.cu prod_force_se_a.cu prod_force_se_r.cu prod_virial_se_a.cu prod_virial_se_r.cu gelu.cu tabulate.cu gpu_nv.cu ) cuda_add_library(deepmd_op_cuda SHARED ${SOURCE_FILES}) diff --git a/source/lib/src/cuda/gpu_nv.cu b/source/lib/src/cuda/gpu_nv.cu new file mode 100644 index 0000000000..11bb1a5357 --- /dev/null +++ b/source/lib/src/cuda/gpu_nv.cu @@ -0,0 +1,44 @@ +#include "gpu_nv.h" +#include "device.h" +#include +#include +#include + +// common part of prod_env_mat +template < + typename Key, + int BLOCK_THREADS, + int ITEMS_PER_THREAD> +__launch_bounds__ (BLOCK_THREADS) +__global__ void BlockSortKernel( + Key * d_in, + Key * d_out) // Tile of output +{ + enum { TILE_SIZE = BLOCK_THREADS * ITEMS_PER_THREAD }; + // Specialize BlockLoad type for our thread block (uses warp-striped loads for coalescing, then transposes in shared memory to a blocked arrangement) + typedef cub::BlockLoad BlockLoadT; + // Specialize BlockRadixSort type for our thread block + typedef cub::BlockRadixSort BlockRadixSortT; + // Shared memory + __shared__ union TempStorage + { + typename BlockLoadT::TempStorage load; + typename BlockRadixSortT::TempStorage sort; + } temp_storage; + // Per-thread tile items + Key items[ITEMS_PER_THREAD]; + // Our current block's offset + int block_offset = blockIdx.x * TILE_SIZE; + // Load items into a blocked arrangement + BlockLoadT(temp_storage.load).Load(d_in + block_offset, items); + // Barrier for smem reuse + __syncthreads(); + // Sort keys + BlockRadixSortT(temp_storage.sort).SortBlockedToStriped(items); + // Store output in striped fashion + cub::StoreDirectStriped(threadIdx.x, d_out + block_offset, items); +} + +template __global__ void BlockSortKernel(int_64 * d_in, int_64 * d_out); +template __global__ void BlockSortKernel(int_64 * d_in, int_64 * d_out); +template __global__ void BlockSortKernel(int_64 * d_in, int_64 * d_out); diff --git a/source/lib/src/cuda/gpu_nv.cuh b/source/lib/src/cuda/gpu_nv.cuh index d2f681984e..f0d19b86a4 100644 --- a/source/lib/src/cuda/gpu_nv.cuh +++ b/source/lib/src/cuda/gpu_nv.cuh @@ -1,8 +1,5 @@ #pragma once #include "gpu_nv.h" -#include -#include -#include // common part of prod_env_mat template < @@ -12,32 +9,7 @@ template < __launch_bounds__ (BLOCK_THREADS) __global__ void BlockSortKernel( Key * d_in, - Key * d_out) // Tile of output -{ - enum { TILE_SIZE = BLOCK_THREADS * ITEMS_PER_THREAD }; - // Specialize BlockLoad type for our thread block (uses warp-striped loads for coalescing, then transposes in shared memory to a blocked arrangement) - typedef cub::BlockLoad BlockLoadT; - // Specialize BlockRadixSort type for our thread block - typedef cub::BlockRadixSort BlockRadixSortT; - // Shared memory - __shared__ union TempStorage - { - typename BlockLoadT::TempStorage load; - typename BlockRadixSortT::TempStorage sort; - } temp_storage; - // Per-thread tile items - Key items[ITEMS_PER_THREAD]; - // Our current block's offset - int block_offset = blockIdx.x * TILE_SIZE; - // Load items into a blocked arrangement - BlockLoadT(temp_storage.load).Load(d_in + block_offset, items); - // Barrier for smem reuse - __syncthreads(); - // Sort keys - BlockRadixSortT(temp_storage.sort).SortBlockedToStriped(items); - // Store output in striped fashion - cub::StoreDirectStriped(threadIdx.x, d_out + block_offset, items); -} + Key * d_out); template __device__ inline FPTYPE dev_dot( diff --git a/source/lib/src/lib_common.cc b/source/lib/src/utilities.cc similarity index 91% rename from source/lib/src/lib_common.cc rename to source/lib/src/utilities.cc index c02f7f86c3..2176715938 100644 --- a/source/lib/src/lib_common.cc +++ b/source/lib/src/utilities.cc @@ -1,4 +1,4 @@ -#include "lib_common.h" +#include "utilities.h" // functions used in custom ops void cum_sum( diff --git a/source/lib/tests/CMakeLists.txt b/source/lib/tests/CMakeLists.txt index 6d7412cb3d..c2a36156f6 100644 --- a/source/lib/tests/CMakeLists.txt +++ b/source/lib/tests/CMakeLists.txt @@ -33,19 +33,20 @@ else() message(STATUS "No cuda support found, will not build nv GPU support") endif() endif() -if (USE_CUDA_TOOLKIT) - add_definitions("-D GOOGLE_CUDA") -endif() if (USE_CUDA_TOOLKIT) - find_package(CUDA REQUIRED) + add_definitions("-D GOOGLE_CUDA") include_directories(${CUDA_INCLUDE_DIRS}) add_subdirectory(${LIB_BASE_DIR}/src/cuda cuda_binary_dir) endif() file(GLOB TEST_SRC test_*.cc) add_executable( runUnitTests ${TEST_SRC} ) -target_link_libraries(runUnitTests gtest gtest_main ${libname} pthread deepmd_op_cuda) +if (USE_CUDA_TOOLKIT) + target_link_libraries(runUnitTests gtest gtest_main ${libname} pthread deepmd_op_cuda) +else() + target_link_libraries(runUnitTests gtest gtest_main ${libname} pthread) +endif() add_test( runUnitTests runUnitTests ) # include(GoogleTest) diff --git a/source/lib/tests/test_env_mat_a.cc b/source/lib/tests/test_env_mat_a.cc index 5282df47b2..572c363ee8 100644 --- a/source/lib/tests/test_env_mat_a.cc +++ b/source/lib/tests/test_env_mat_a.cc @@ -4,7 +4,7 @@ #include "env_mat.h" #include "prod_env_mat.h" #include "neighbor_list.h" -#include "device_common.h" +#include "device.h" class TestEnvMatA : public ::testing::Test { @@ -628,7 +628,7 @@ TEST_F(TestEnvMatA, prod_gpu_nv) } -TEST_F(TestEnvMatA, prod_gpu_equal_cpu) +TEST_F(TestEnvMatA, prod_gpu_nv_equal_cpu) { EXPECT_EQ(nlist_r_cpy.size(), nloc); int tot_nnei = 0; diff --git a/source/op/descrpt_se_a_multi_device.cc b/source/op/descrpt_se_a_multi_device.cc index b66b139b2f..213918da23 100644 --- a/source/op/descrpt_se_a_multi_device.cc +++ b/source/op/descrpt_se_a_multi_device.cc @@ -1,5 +1,5 @@ #include "common.h" -#include "lib_common.h" +#include "utilities.h" #include "prod_env_mat.h" REGISTER_OP("DescrptSeA") diff --git a/source/op/descrpt_se_r_multi_device.cc b/source/op/descrpt_se_r_multi_device.cc index 5a830f0266..ca4262fbd3 100644 --- a/source/op/descrpt_se_r_multi_device.cc +++ b/source/op/descrpt_se_r_multi_device.cc @@ -1,5 +1,5 @@ #include "common.h" -#include "lib_common.h" +#include "utilities.h" #include "CustomeOperation.h" REGISTER_OP("DescrptSeR") From 7400855c862163e2cb4d52c2c79456413b6b9536 Mon Sep 17 00:00:00 2001 From: Denghui Lu Date: Wed, 24 Feb 2021 12:16:47 +0800 Subject: [PATCH 199/562] Add introduction about the acceptable original model version in model compression part --- doc/use-deepmd-kit.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/use-deepmd-kit.md b/doc/use-deepmd-kit.md index e4cfff5aa6..773912f62b 100644 --- a/doc/use-deepmd-kit.md +++ b/doc/use-deepmd-kit.md @@ -324,6 +324,10 @@ Finally, we added a check frequency parameter. It indicates how often the progra Model compression, with little loss of accuracy, can greatly speed up MD inference time. According to different simulation systems and training parameters, the speedup can reach more than 10 times at both CPU and GPU devices. At the same time, model compression can greatly change the memory usage, reducing as much as 20 times under the same hardware conditions. +**Acceptable original model version** + +The model compression method requires that the version of DeePMD-kit used in original model generation should be 1.3 or above. If one has a frozen 1.2 model, one can first use the convenient conversion interface(eg: ```dp convert-to-1.3 -i frozen_1.2.pb -o frozen_1.3.pb```) of r1.2 branch(python interface of r1.2 branch is needed) to get a 1.3 executable model. + ## Model inference One may use the python interface of DeePMD-kit for model inference, an example is given as follows ```python From 430871e9cabb15151794a3d5e4701958369ec1de Mon Sep 17 00:00:00 2001 From: Denghui Lu Date: Wed, 24 Feb 2021 14:13:14 +0800 Subject: [PATCH 200/562] update model compression document --- doc/use-deepmd-kit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/use-deepmd-kit.md b/doc/use-deepmd-kit.md index 773912f62b..d182c61b50 100644 --- a/doc/use-deepmd-kit.md +++ b/doc/use-deepmd-kit.md @@ -326,7 +326,7 @@ Model compression, with little loss of accuracy, can greatly speed up MD inferen **Acceptable original model version** -The model compression method requires that the version of DeePMD-kit used in original model generation should be 1.3 or above. If one has a frozen 1.2 model, one can first use the convenient conversion interface(eg: ```dp convert-to-1.3 -i frozen_1.2.pb -o frozen_1.3.pb```) of r1.2 branch(python interface of r1.2 branch is needed) to get a 1.3 executable model. +The model compression method requires that the version of DeePMD-kit used in original model generation should be 1.3 or above. If one has a frozen 1.2 model, one can first use the convenient conversion interface of DeePMD-kit-v1.2.4 to get a 1.3 executable model.(eg: ```dp convert-to-1.3 -i frozen_1.2.pb -o frozen_1.3.pb```) ## Model inference One may use the python interface of DeePMD-kit for model inference, an example is given as follows From 822d301292adaef0b464cfe5efca887381353f02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Wed, 24 Feb 2021 20:13:56 +0100 Subject: [PATCH 201/562] fix known bugs --- deepmd/__init__.py | 1 - deepmd/infer/__init__.py | 2 -- deepmd/utils/data_system.py | 28 +++++++++++++--------------- setup.py | 1 + source/train/main.py | 36 +++++++++++++++++++++++++++--------- source/train/run_options.py | 22 +++++++++++----------- 6 files changed, 52 insertions(+), 38 deletions(-) diff --git a/deepmd/__init__.py b/deepmd/__init__.py index c9a24bb04a..64386b754c 100644 --- a/deepmd/__init__.py +++ b/deepmd/__init__.py @@ -6,7 +6,6 @@ from .env import set_mkl from .infer import DeepPotential from .infer.data_modifier import DipoleChargeModifier -from .infer.deep_eval import DeepEval set_mkl() diff --git a/deepmd/infer/__init__.py b/deepmd/infer/__init__.py index 75ec05e097..c0c7c73182 100644 --- a/deepmd/infer/__init__.py +++ b/deepmd/infer/__init__.py @@ -56,8 +56,6 @@ def DeepPotential( mf, load_prefix=load_prefix, default_tf_graph=default_tf_graph ).model_type - print(mf, model_type) - if model_type == "ener": dp = DeepPot(mf, load_prefix=load_prefix, default_tf_graph=default_tf_graph) elif model_type == "dipole": diff --git a/deepmd/utils/data_system.py b/deepmd/utils/data_system.py index 31f63692a5..e9d07a51ad 100644 --- a/deepmd/utils/data_system.py +++ b/deepmd/utils/data_system.py @@ -402,24 +402,22 @@ def print_summary(self, sys_probs = None, auto_prob_style = "prob_sys_size") : prob = self._get_sys_probs(sys_probs, auto_prob_style) - tmp_msg = "" # width 65 sys_width = 42 - tmp_msg += "---Summary of DataSystem------------------------------------------------\n" - tmp_msg += "found %d system(s):\n" % self.nsystems - tmp_msg += "%s " % self._format_name_length('system', sys_width) - tmp_msg += "%s %s %s %s %5s\n" % ('natoms', 'bch_sz', 'n_bch', "n_test", 'prob') + log.info("---Summary of DataSystem------------------------------------------------") + log.info("found %d system(s):" % self.nsystems) + log.info("%s " % self._format_name_length('system', sys_width)) + log.info("%s %s %s %s %5s" % ('natoms', 'bch_sz', 'n_bch', "n_test", 'prob')) for ii in range(self.nsystems) : - tmp_msg += ("%s %6d %6d %6d %6d %5.3f\n" % - (self._format_name_length(self.system_dirs[ii], sys_width), - self.natoms[ii], - # TODO batch size * nbatches = number of structures - self.batch_size[ii], - self.nbatches[ii], - self.test_size[ii], - prob[ii]) ) - tmp_msg += "------------------------------------------------------------------------\n" - log.info(tmp_msg) + log.info("%s %6d %6d %6d %6d %5.3f" % + (self._format_name_length(self.system_dirs[ii], sys_width), + self.natoms[ii], + # TODO batch size * nbatches = number of structures + self.batch_size[ii], + self.nbatches[ii], + self.test_size[ii], + prob[ii]) ) + log.info("------------------------------------------------------------------------\n") def _make_auto_bs(self, rule) : bs = [] diff --git a/setup.py b/setup.py index ac8a6abb02..cf83e4955f 100644 --- a/setup.py +++ b/setup.py @@ -85,6 +85,7 @@ "deepmd/utils", "deepmd/loggers", "deepmd/cluster", + "deepmd/entrypoints", "deepmd/op" ], python_requires=">=3.6", diff --git a/source/train/main.py b/source/train/main.py index 4bfffe6881..d4c63ac921 100644 --- a/source/train/main.py +++ b/source/train/main.py @@ -10,7 +10,7 @@ freeze, test, train, - transfer + transfer, ) from deepmd.loggers import set_log_handles @@ -34,7 +34,9 @@ def main(): # * logging options parser ********************************************************* # with use of the parent argument this options will be added to every parser - parser_log = argparse.ArgumentParser(add_help=False) + parser_log = argparse.ArgumentParser( + add_help=False, formatter_class=argparse.ArgumentDefaultsHelpFormatter + ) parser_log.add_argument( "-v", "--verbose", @@ -52,7 +54,9 @@ def main(): "only be output to console", ) # * mpi logging parser ************************************************************* - parser_mpi_log = argparse.ArgumentParser(add_help=False) + parser_mpi_log = argparse.ArgumentParser( + add_help=False, formatter_class=argparse.ArgumentDefaultsHelpFormatter + ) parser_mpi_log.add_argument( "-m", "--mpi-log", @@ -69,6 +73,7 @@ def main(): "config", parents=[parser_log], help="fast configuration of parameter file for smooth model", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) parser_cfig.add_argument( "-o", "--output", type=str, default="input.json", help="the output json file" @@ -102,7 +107,10 @@ def main(): # * config parser ****************************************************************** parser_train = subparsers.add_parser( - "train", parents=[parser_log, parser_mpi_log], help="train a model" + "train", + parents=[parser_log, parser_mpi_log], + help="train a model", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) parser_train.add_argument( "INPUT", help="the input parameter file in json or yaml format" @@ -111,14 +119,14 @@ def main(): "-i", "--init-model", type=str, - default=False, + default=None, help="Initialize the model by the provided checkpoint.", ) parser_train.add_argument( "-r", "--restart", type=str, - default=False, + default=None, help="Restart the training from the provided checkpoint.", ) parser_train.add_argument( @@ -131,7 +139,10 @@ def main(): # * freeze script ****************************************************************** parser_frz = subparsers.add_parser( - "freeze", parents=[parser_log], help="freeze the model" + "freeze", + parents=[parser_log], + help="freeze the model", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) parser_frz.add_argument( "-c", @@ -157,7 +168,10 @@ def main(): # * test script ******************************************************************** parser_tst = subparsers.add_parser( - "test", parents=[parser_log], help="test the model" + "test", + parents=[parser_log], + help="test the model", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) parser_tst.add_argument( "-m", @@ -207,7 +221,10 @@ def main(): # second table ranges from the first table's upper boundary(upper) to the # extrapolate(parameter) * upper. parser_compress = subparsers.add_parser( - "compress", parents=[parser_log, parser_mpi_log], help="compress a model" + "compress", + parents=[parser_log, parser_mpi_log], + help="compress a model", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) parser_compress.add_argument( "INPUT", @@ -265,6 +282,7 @@ def main(): "doc-train-input", parents=[parser_log], help="print the documentation (in rst format) of input training parameters.", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) args = parser.parse_args() diff --git a/source/train/run_options.py b/source/train/run_options.py index 94edf15d9b..632c18af63 100644 --- a/source/train/run_options.py +++ b/source/train/run_options.py @@ -304,22 +304,22 @@ def __init__( def print_resource_summary(self): """Print build and current running cluster configuration summary.""" - log.info("---Summary of the training---------------------------------------\n") + log.info("---Summary of the training---------------------------------------") if self.is_distrib: - log.info("distributed\n") - log.info(f"ps list: {self.cluster['ps']}\n") - log.info(f"worker list: {self.cluster['worker']}\n") - log.info(f"chief on: {self.nodename}\n") + log.info("distributed") + log.info(f"ps list: {self.cluster['ps']}") + log.info(f"worker list: {self.cluster['worker']}") + log.info(f"chief on: {self.nodename}") else: - log.info(f"running on: {self.nodename}\n") + log.info(f"running on: {self.nodename}") if self.gpus is None: - log.info(f"CUDA_VISIBLE_DEVICES: unset\n") + log.info(f"CUDA_VISIBLE_DEVICES: unset") else: - log.info(f"CUDA_VISIBLE_DEVICES: {self.gpus}\n") + log.info(f"CUDA_VISIBLE_DEVICES: {self.gpus}") intra, inter = get_tf_default_nthreads() - log.info(f"num_intra_threads: {intra:d}\n") - log.info(f"num_inter_threads: {inter:d}\n") - log.info("-----------------------------------------------------------------\n") + log.info(f"num_intra_threads: {intra:d}") + log.info(f"num_inter_threads: {inter:d}") + log.info("-----------------------------------------------------------------") def _setup_logger( self, From 8b89c0698ad6c7e221d2a9551b144e468a7b6c35 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 24 Feb 2021 17:45:55 -0500 Subject: [PATCH 202/562] install tensorflow_cc automatically with cmake and conda (1) install tensorflow_cc automatically with cmake and conda (2) add a script to compile the deepmd-kit (3) use github actions to test this script and compiling process TODO: (1) consider integrating LAMMPS with the above process (2) consider build tensorflow with cmake --- .github/workflows/test_cc.yml | 11 ++++++++ source/CMakeLists.txt | 42 +++++++++++++++---------------- source/cmake/Findtensorflow.cmake | 19 ++++++++++++++ source/install/build_cc.sh | 27 ++++++++++++++++++++ 4 files changed, 78 insertions(+), 21 deletions(-) create mode 100644 .github/workflows/test_cc.yml create mode 100755 source/install/build_cc.sh diff --git a/.github/workflows/test_cc.yml b/.github/workflows/test_cc.yml new file mode 100644 index 0000000000..5fff8c946e --- /dev/null +++ b/.github/workflows/test_cc.yml @@ -0,0 +1,11 @@ +on: + push: + pull_request: +name: Test C++ +jobs: + testpython: + name: Test C++ + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - run: source/install/build_cc.sh diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index d8e5addb31..6b7bd3f10f 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -46,6 +46,27 @@ endif(GIT_FOUND) list (APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-ignored-attributes") +# define USE_CUDA_TOOLKIT +if (DEFINED USE_CUDA_TOOLKIT) + if (USE_CUDA_TOOLKIT) + find_package(CUDA REQUIRED) + else() + message(STATUS "Will not build nv GPU support") + endif() +else() + find_package(CUDA QUIET) + if (CUDA_FOUND) + set(USE_CUDA_TOOLKIT TRUE) + message(STATUS "Found CUDA in ${CUDA_TOOLKIT_ROOT_DIR}, build nv GPU support") + else() + set(USE_CUDA_TOOLKIT FALSE) + message(STATUS "No cuda support found, will not build nv GPU support") + endif() +endif() +if (USE_CUDA_TOOLKIT) + add_definitions("-D GOOGLE_CUDA") +endif() + # find tensorflow, I need tf abi info find_package(tensorflow REQUIRED) @@ -107,27 +128,6 @@ else () message (STATUS "Set GLIBCXX_USE_CXX_ABI=1 when compiling ops") endif () -# define USE_CUDA_TOOLKIT -if (DEFINED USE_CUDA_TOOLKIT) - if (USE_CUDA_TOOLKIT) - find_package(CUDA REQUIRED) - else() - message(STATUS "Will not build nv GPU support") - endif() -else() - find_package(CUDA QUIET) - if (CUDA_FOUND) - set(USE_CUDA_TOOLKIT TRUE) - message(STATUS "Found CUDA in ${CUDA_TOOLKIT_ROOT_DIR}, build nv GPU support") - else() - set(USE_CUDA_TOOLKIT FALSE) - message(STATUS "No cuda support found, will not build nv GPU support") - endif() -endif() -if (USE_CUDA_TOOLKIT) - add_definitions("-D GOOGLE_CUDA") -endif() - # define USE_TTM if (NOT DEFINED USE_TTM) set(USE_TTM FALSE) diff --git a/source/cmake/Findtensorflow.cmake b/source/cmake/Findtensorflow.cmake index 708b8e86d5..9281b67ac8 100644 --- a/source/cmake/Findtensorflow.cmake +++ b/source/cmake/Findtensorflow.cmake @@ -10,6 +10,25 @@ # TensorFlowFramework_LIBRARY # TensorFlowFramework_LIBRARY_PATH + +if (BUILD_CPP_IF AND INSTALL_TENSORFLOW) + # Here we try to install libtensorflow_cc using conda install. + + if (USE_CUDA_TOOLKIT) + set (VARIANT gpu) + else () + set (VARIANT cpu) + endif () + + if (NOT DEFINED TENSORFLOW_ROOT) + set (TENSORFLOW_ROOT ${CMAKE_INSTALL_PREFIX}) + endif () + # execute conda install + execute_process( + COMMAND conda install libtensorflow_cc=*=${VARIANT}* -c deepmodeling -y -p ${TENSORFLOW_ROOT} + ) +endif () + string(REPLACE "lib64" "lib" TENSORFLOW_ROOT_NO64 ${TENSORFLOW_ROOT}) # define the search path diff --git a/source/install/build_cc.sh b/source/install/build_cc.sh new file mode 100755 index 0000000000..4f89c7bfe0 --- /dev/null +++ b/source/install/build_cc.sh @@ -0,0 +1,27 @@ +set -e + +if [ -z "$FLOAT_PREC" ] then + FLOAT_PREC=high +fi +#------------------ + +SCRIPT_PATH=$(dirname $(realpath -s $0)) +if [ -z "$INSTALL_PREFIX" ] then + INSTALL_PREFIX=$(realpath -s ${SCRIPT_PATH}/../../dp) +fi +mkdir -p ${INSTALL_PREFIX} +echo "Installing DeePMD-kit to ${INSTALL_PREFIX}" +NPROC=$(nproc --all) + +#------------------ + +BUILD_TMP_DIR=${SCRIPT_PATH}/../build +mkdir -p ${BUILD_TMP_DIR} +cd ${BUILD_TMP_DIR} +cmake -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} -DFLOAT_PREC=${FLOAT_PREC} -DINSTALL_TENSORFLOW=TRUE .. +make -j${NPROC} +make install + +#------------------ +echo "Congratulations! DeePMD-kit has been installed at ${INSTALL_PREFIX}" + From b9743ed00f41989756ffdfe52f8f8e6005bf9925 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 24 Feb 2021 17:51:13 -0500 Subject: [PATCH 203/562] fix syntax error --- source/install/build_cc.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/install/build_cc.sh b/source/install/build_cc.sh index 4f89c7bfe0..6e27a1e60f 100755 --- a/source/install/build_cc.sh +++ b/source/install/build_cc.sh @@ -1,12 +1,14 @@ set -e -if [ -z "$FLOAT_PREC" ] then +if [ -z "$FLOAT_PREC" ] +then FLOAT_PREC=high fi #------------------ SCRIPT_PATH=$(dirname $(realpath -s $0)) -if [ -z "$INSTALL_PREFIX" ] then +if [ -z "$INSTALL_PREFIX" ] +then INSTALL_PREFIX=$(realpath -s ${SCRIPT_PATH}/../../dp) fi mkdir -p ${INSTALL_PREFIX} From a9c21cf3b62eb55a416f731df23ead2bc09025fa Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 24 Feb 2021 18:04:53 -0500 Subject: [PATCH 204/562] test both two FLOAT_PRECs --- .github/workflows/test_cc.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/test_cc.yml b/.github/workflows/test_cc.yml index 5fff8c946e..af246082b2 100644 --- a/.github/workflows/test_cc.yml +++ b/.github/workflows/test_cc.yml @@ -6,6 +6,13 @@ jobs: testpython: name: Test C++ runs-on: ubuntu-latest + strategy: + matrix: + include: + - float_prec: high + - float_prec: low steps: - uses: actions/checkout@master - run: source/install/build_cc.sh + env: + FLOAT_PREC: ${{ matrix.float_prec }} From eb4e4f371ece4650baff87b3c8b6414911865813 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 24 Feb 2021 20:34:31 -0500 Subject: [PATCH 205/562] add C++ unittest to CI --- .github/workflows/build_cc.yml | 18 ++++++++++++++++++ .github/workflows/test_cc.yml | 9 +-------- source/install/test_cc.sh | 18 ++++++++++++++++++ source/lib/tests/CMakeLists.txt | 21 +++++++++++++++++++++ source/lib/tests/CMakeLists.txt.in | 15 +++++++++++++++ 5 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/build_cc.yml create mode 100755 source/install/test_cc.sh create mode 100644 source/lib/tests/CMakeLists.txt.in diff --git a/.github/workflows/build_cc.yml b/.github/workflows/build_cc.yml new file mode 100644 index 0000000000..b50989650e --- /dev/null +++ b/.github/workflows/build_cc.yml @@ -0,0 +1,18 @@ +on: + push: + pull_request: +name: Build C++ +jobs: + testpython: + name: Build C++ + runs-on: ubuntu-latest + strategy: + matrix: + include: + - float_prec: high + - float_prec: low + steps: + - uses: actions/checkout@master + - run: source/install/build_cc.sh + env: + FLOAT_PREC: ${{ matrix.float_prec }} diff --git a/.github/workflows/test_cc.yml b/.github/workflows/test_cc.yml index af246082b2..5192eda6e9 100644 --- a/.github/workflows/test_cc.yml +++ b/.github/workflows/test_cc.yml @@ -6,13 +6,6 @@ jobs: testpython: name: Test C++ runs-on: ubuntu-latest - strategy: - matrix: - include: - - float_prec: high - - float_prec: low steps: - uses: actions/checkout@master - - run: source/install/build_cc.sh - env: - FLOAT_PREC: ${{ matrix.float_prec }} + - run: source/install/test_cc.sh diff --git a/source/install/test_cc.sh b/source/install/test_cc.sh new file mode 100755 index 0000000000..e5cc88319c --- /dev/null +++ b/source/install/test_cc.sh @@ -0,0 +1,18 @@ +set -e + +#------------------ + +SCRIPT_PATH=$(dirname $(realpath -s $0)) +NPROC=$(nproc --all) + +#------------------ + +BUILD_TMP_DIR=${SCRIPT_PATH}/../build_tests +mkdir -p ${BUILD_TMP_DIR} +cd ${BUILD_TMP_DIR} +cmake ../lib/tests +make -j${NPROC} + +#------------------ +../lib/tests/runUnitTests + diff --git a/source/lib/tests/CMakeLists.txt b/source/lib/tests/CMakeLists.txt index c2a36156f6..c3b54f2a09 100644 --- a/source/lib/tests/CMakeLists.txt +++ b/source/lib/tests/CMakeLists.txt @@ -42,6 +42,7 @@ endif() file(GLOB TEST_SRC test_*.cc) add_executable( runUnitTests ${TEST_SRC} ) + if (USE_CUDA_TOOLKIT) target_link_libraries(runUnitTests gtest gtest_main ${libname} pthread deepmd_op_cuda) else() @@ -56,3 +57,23 @@ add_test( runUnitTests runUnitTests ) # TEST_LIST noArgsTests # ) +find_package(GTest) +if(NOT GTEST_LIBRARY) + configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt) + execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) + if(result) + message(FATAL_ERROR "CMake step for googletest failed: ${result}") + endif() + execute_process(COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) + if(result) + message(FATAL_ERROR "Build step for googletest failed: ${result}") + endif() + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src ${CMAKE_CURRENT_BINARY_DIR}/googletest-build EXCLUDE_FROM_ALL) +else () + include_directories(${GTEST_INCLUDE_DIRS}) +endif () diff --git a/source/lib/tests/CMakeLists.txt.in b/source/lib/tests/CMakeLists.txt.in new file mode 100644 index 0000000000..c6247af53c --- /dev/null +++ b/source/lib/tests/CMakeLists.txt.in @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 2.8.2) + +project(googletest-download NONE) + +include(ExternalProject) +ExternalProject_Add(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG master + SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" + BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" +) From efa089d975baba1e085131b6ee6be49b6a10ac28 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 24 Feb 2021 20:39:44 -0500 Subject: [PATCH 206/562] fix the script --- source/install/test_cc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/install/test_cc.sh b/source/install/test_cc.sh index e5cc88319c..6464a9a904 100755 --- a/source/install/test_cc.sh +++ b/source/install/test_cc.sh @@ -14,5 +14,5 @@ cmake ../lib/tests make -j${NPROC} #------------------ -../lib/tests/runUnitTests +${BUILD_TMP_DIR}/runUnitTests From 4e9beca229f4dc811e7ef9a3938416c540e0cbc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 25 Feb 2021 20:36:02 +0100 Subject: [PATCH 207/562] added tests for argument parser --- source/tests/test_argument_parser.py | 282 +++++++++++++++++++++++++++ source/tests/test_transform.py | 67 ------- source/train/main.py | 40 ++-- 3 files changed, 310 insertions(+), 79 deletions(-) create mode 100644 source/tests/test_argument_parser.py delete mode 100644 source/tests/test_transform.py diff --git a/source/tests/test_argument_parser.py b/source/tests/test_argument_parser.py new file mode 100644 index 0000000000..749cce58ab --- /dev/null +++ b/source/tests/test_argument_parser.py @@ -0,0 +1,282 @@ +"""Unittests for argument parser.""" + +import unittest +from argparse import Namespace +from typing import Any, Dict, List, Tuple, Union, TYPE_CHECKING +import re +from io import StringIO +from contextlib import redirect_stderr + +from deepmd.main import parse_args + +if TYPE_CHECKING: + try: + from typing import TypedDict # python==3.8 + except ImportError: + from typing_extensions import TypedDict # python<=3.7 + + DATA = TypedDict("DATA", {"type": Union[type, Tuple[type]], "value": Any}) + TEST_DICT = Dict[str, DATA] + + +def build_args(args: "TEST_DICT", command: str) -> List[str]: + """Build list of arguments similar to one generated by `sys.argv` used by argparse. + + Parameters + ---------- + args : TEST_DICT + from dictionary with specifications how to build each argument + command : str + first argument that chooses subparser + + Returns + ------- + List[str] + arguments with options as list of strings, goal is to emulate `sys.argv` + """ + args_list = [command] + + for argument, test_data in args.items(): + # arguments without dash are positional, their name should not appear in + # arguments list + if argument.startswith("-"): + args_list.append(argument) + # arguments without value are passed as such, typically these are where action + # is 'count' or 'store_true' + if "value" in test_data: + args_list.append(str(test_data["value"])) + + return args_list + + +class TestParserOutput(unittest.TestCase): + """Test if parser correctly parses supplied arguments.""" + + def attr_and_type_check( + self, namespace: Namespace, mapping: "TEST_DICT", command: str, test_value: bool + ): + """Check attributes of `argparse.Manespace` types and values are as expected. + + First check for attribute existence, if it exists check its type and if type is + as expected check value + + Parameters + ---------- + namespace : Namespace + `argparse.Manespace` object aoutput from parser + mapping : TEST_DICT + mapping of argument names and their types and values + command : str + first argument that sets subparser + test_value : bool + whether to test for value match + """ + mapping = {**{"command": dict(type=str, value=command)}, **mapping} + + for argument, test_data in mapping.items(): + + # get expected type + expected_type = test_data["type"] + + # if data has different destination attribute, use it + if "dest" in test_data: + argument = test_data["dest"] + + # remove first one/two hyphens from argument name + argument = re.sub(r"^-{1,2}", "", argument) + + # remove any hyphens from string as these are replaced to + # underscores by argparse + attribute = re.sub("-", "_", argument) + + # first check if namespace object hat the expected attribute + self.assertTrue( + hasattr(namespace, attribute), + msg=f"Namespace object does not have expected attribute: {attribute}" + ) + # than check if the attribute is of expected type + self.assertIsInstance( + getattr(namespace, attribute), + expected_type, + msg=f"Namespace attribute '{attribute}' is of wrong type, expected: " + f"{expected_type}, got: {type(getattr(namespace, attribute))}" + ) + # if argument has associated value check if it is same as expected + if "value" in test_data and test_value: + self.assertEqual( + test_data["value"], + getattr(namespace, attribute), + msg=f"Got wrong parsed value, expected: {test_data['value']}, got " + f"{getattr(namespace, attribute)}" + ) + + def run_test(self, *, command: str, mapping: "TEST_DICT"): + """Run test first for specified arguments and then for default. + + Parameters + ---------- + command : str + first argument that sets subparser + mapping : TEST_DICT + mapping of argument names and their types and values + + Raises + ------ + SystemExit + If parser for some reason fails + NotImplementedError + [description] + """ + # test passed in arguments + cmd_args = build_args(mapping, command) + buffer = StringIO() + try: + with redirect_stderr(buffer): + namespace = parse_args(cmd_args) + except SystemExit: + raise SystemExit( + f"Encountered expection when parsing arguments ->\n\n" + f"{buffer.getvalue()}\n" + f"passed in arguments were: {cmd_args}\n" + f"built from dict {mapping}" + ) + self.attr_and_type_check(namespace, mapping, command, test_value=True) + + # check for required arguments + required = [] + for argument, data in mapping.items(): + if not argument.startswith("-"): + if isinstance(data["type"], tuple): + t = data["type"][0] + else: + t = data["type"] + if t == str: + required.append("STRING") + elif t in (int, float): + required.append("11111") + else: + raise NotImplementedError( + f"Option for type: {t} not implemented, please do so!" + ) + + # test default values + cmd_args = [command] + required + buffer = StringIO() + try: + with redirect_stderr(buffer): + namespace = parse_args(cmd_args) + except SystemExit: + raise SystemExit( + f"Encountered expection when parsing DEFAULT arguments ->\n\n" + f"{buffer.getvalue()}\n" + f"passed in arguments were: {cmd_args}\n" + f"built from dict {mapping}" + ) + self.attr_and_type_check(namespace, mapping, command, test_value=False) + + def test_no_command(self): + """Test that parser outputs nothing when no command is input and does not fail.""" + self.assertIsNone(parse_args([]).command) + + def test_wrong_command(self): + """Test that parser fails if no command is passed in.""" + with self.assertRaises(SystemExit): + parse_args(["RANDOM_WRONG_COMMAND"]) + + def test_parser_log(self): + """Check if logging associated attributes are present in specified parsers.""" + ARGS = { + "--verbose": dict(type=int, dest="log_level"), + "--log-path": dict(type=(str, type(None)), value="LOGFILE") + } + + for parser in ("config", "transfer", "train", "freeze", "test", "compress"): + if parser in ("compress", "train"): + args = {**{"INPUT": dict(type=str, value="INFILE")}, **ARGS} + else: + args = ARGS + + self.run_test(command=parser, mapping=args) + + def test_parser_mpi(self): + """Check if mpi-log attribute is present in specified parsers.""" + ARGS = {"--mpi-log": dict(type=str, value="master")} + + for parser in ("train", "compress"): + if parser in ("train", "compress"): + args = {**{"INPUT": dict(type=str, value="INFILE")}, **ARGS} + else: + args = ARGS + self.run_test(command=parser, mapping=args) + + def test_parser_config(self): + """Test config subparser.""" + ARGS = { + "--output": dict(type=str, value="OUTPUT"), + } + + self.run_test(command="config", mapping=ARGS) + + def test_parser_transfer(self): + """Test transfer subparser.""" + ARGS = { + "--raw-model": dict(type=str, value="INFILE.PB"), + "--old-model": dict(type=str, value="OUTFILE.PB"), + "--output": dict(type=str, value="OUTPUT"), + } + + self.run_test(command="transfer", mapping=ARGS) + + def test_parser_train(self): + """Test train subparser.""" + ARGS = { + "INPUT": dict(type=str, value="INFILE"), + "--init-model": dict(type=(str, type(None)), value="SYSTEM_DIR"), + "--restart": dict(type=(str, type(None)), value="RESTART"), + "--output": dict(type=str, value="OUTPUT"), + } + + self.run_test(command="train", mapping=ARGS) + + def test_parser_freeze(self): + """Test freeze subparser.""" + ARGS = { + "--checkpoint-folder": dict(type=str, value="FOLDER"), + "--output": dict(type=str, value="FROZEN.PB"), + "--node-names": dict(type=(str, type(None)), value="NODES"), + } + + self.run_test(command="freeze", mapping=ARGS) + + def test_parser_test(self): + """Test test subparser.""" + ARGS = { + "--model": dict(type=str, value="MODEL.PB"), + "--system": dict(type=str, value="SYSTEM_DIR"), + "--set-prefix": dict(type=str, value="SET_PREFIX"), + "--numb-test": dict(type=int, value=1), + "--rand-seed": dict(type=(int, type(None)), value=12321), + "--detail-file": dict(type=(str, type(None)), value="TARGET.FILE"), + "--atomic-energy": dict(type=bool), + } + + self.run_test(command="test", mapping=ARGS) + + def test_parser_compress(self): + """Test compress subparser.""" + ARGS = { + "INPUT": dict(type=str, value="INFILE"), + "--output": dict(type=str, value="OUTFILE"), + "--extrapolate": dict(type=int, value=10), + "--stride": dict(type=float, value=0.1), + "--frequency": dict(type=int, value=1), + "--checkpoint-folder": dict(type=str, value="FOLDER"), + } + + self.run_test(command="compress", mapping=ARGS) + + def test_parser_doc(self): + """Test doc subparser.""" + ARGS = {} + + self.run_test(command="doc-train-input", mapping=ARGS) diff --git a/source/tests/test_transform.py b/source/tests/test_transform.py deleted file mode 100644 index bbc0719f0f..0000000000 --- a/source/tests/test_transform.py +++ /dev/null @@ -1,67 +0,0 @@ -import os,sys,platform,shutil,dpdata -import numpy as np -import unittest - -from deepmd.env import tf -from deepmd.infer import DeepPot -from common import tests_path -from infer.convert2pb import convert_pbtxt_to_pb -from deepmd.entrypoints.transfer import load_graph, transform_graph - -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -if GLOBAL_NP_FLOAT_PRECISION == np.float32 : - default_places = 4 -else : - default_places = 10 - -class TestTransform(unittest.TestCase) : - def setUp(self): - convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot.pbtxt")), "deeppot.pb") - convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot-1.pbtxt")), "deeppot-1.pb") - self.coords = np.array([12.83, 2.56, 2.18, - 12.09, 2.87, 2.74, - 00.25, 3.32, 1.68, - 3.36, 3.00, 1.81, - 3.51, 2.51, 2.60, - 4.27, 3.22, 1.56]) - self.atype = [0, 1, 1, 0, 1, 1] - self.box = np.array([13., 0., 0., 0., 13., 0., 0., 0., 13.]) - self.expected_e = np.array([-9.275780747115504710e+01,-1.863501786584258468e+02,-1.863392472863538103e+02,-9.279281325486221021e+01,-1.863671545232153903e+02,-1.863619822847602165e+02]) - self.expected_f = np.array([-3.034045420701179663e-01,8.405844663871177014e-01,7.696947487118485642e-02,7.662001266663505117e-01,-1.880601391333554251e-01,-6.183333871091722944e-01,-5.036172391059643427e-01,-6.529525836149027151e-01,5.432962643022043459e-01,6.382357912332115024e-01,-1.748518296794561167e-01,3.457363524891907125e-01,1.286482986991941552e-03,3.757251165286925043e-01,-5.972588700887541124e-01,-5.987006197104716154e-01,-2.004450304880958100e-01,2.495901655353461868e-01]) - self.expected_v = np.array([-2.912234126853306959e-01,-3.800610846612756388e-02,2.776624987489437202e-01,-5.053761003913598976e-02,-3.152373041953385746e-01,1.060894290092162379e-01,2.826389131596073745e-01,1.039129970665329250e-01,-2.584378792325942586e-01,-3.121722367954994914e-01,8.483275876786681990e-02,2.524662342344257682e-01,4.142176771106586414e-02,-3.820285230785245428e-02,-2.727311173065460545e-02,2.668859789777112135e-01,-6.448243569420382404e-02,-2.121731470426218846e-01,-8.624335220278558922e-02,-1.809695356746038597e-01,1.529875294531883312e-01,-1.283658185172031341e-01,-1.992682279795223999e-01,1.409924999632362341e-01,1.398322735274434292e-01,1.804318474574856390e-01,-1.470309318999652726e-01,-2.593983661598450730e-01,-4.236536279233147489e-02,3.386387920184946720e-02,-4.174017537818433543e-02,-1.003500282164128260e-01,1.525690815194478966e-01,3.398976109910181037e-02,1.522253908435125536e-01,-2.349125581341701963e-01,9.515545977581392825e-04,-1.643218849228543846e-02,1.993234765412972564e-02,6.027265332209678569e-04,-9.563256398907417355e-02,1.510815124001868293e-01,-7.738094816888557714e-03,1.502832772532304295e-01,-2.380965783745832010e-01,-2.309456719810296654e-01,-6.666961081213038098e-02,7.955566551234216632e-02,-8.099093777937517447e-02,-3.386641099800401927e-02,4.447884755740908608e-02,1.008593228579038742e-01,4.556718179228393811e-02,-6.078081273849572641e-02]) - - def tearDown(self): - os.remove("deeppot.pb") - os.remove("deeppot-1.pb") - - def test(self): - self.graph0 = load_graph("deeppot.pb") - self.graph1 = load_graph("deeppot-1.pb") - new_graph_def = transform_graph(self.graph1, self.graph0) - with tf.gfile.GFile("deeppot-2.pb", mode='wb') as f: - f.write(new_graph_def.SerializeToString()) - self.dp = DeepPot("deeppot-2.pb") - os.remove("deeppot-2.pb") - ee, ff, vv, ae, av = self.dp.eval(self.coords, self.box, self.atype, atomic = True) - # check shape of the returns - nframes = 1 - natoms = len(self.atype) - self.assertEqual(ee.shape, (nframes,1)) - self.assertEqual(ff.shape, (nframes,natoms,3)) - self.assertEqual(vv.shape, (nframes,9)) - self.assertEqual(ae.shape, (nframes,natoms,1)) - self.assertEqual(av.shape, (nframes,natoms,9)) - # check values - for ii in range(ff.size): - self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) - for ii in range(ae.size): - self.assertAlmostEqual(ae.reshape([-1])[ii], self.expected_e.reshape([-1])[ii], places = default_places) - for ii in range(av.size): - self.assertAlmostEqual(av.reshape([-1])[ii], self.expected_v.reshape([-1])[ii], places = default_places) - expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) - for ii in range(nframes): - self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) - expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) - for ii in range(nframes, 9): - self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) - diff --git a/source/train/main.py b/source/train/main.py index d4c63ac921..a7b5574cdd 100644 --- a/source/train/main.py +++ b/source/train/main.py @@ -2,6 +2,7 @@ import argparse from pathlib import Path +from typing import List, Optional from deepmd.entrypoints import ( compress, @@ -14,16 +15,17 @@ ) from deepmd.loggers import set_log_handles -__all__ = ["main"] +__all__ = ["main", "parse_args"] -def main(): - """DeePMD-Kit entry point. +def parse_args(args: Optional[List[str]] = None): + """DeePMD-Kit commandline options argument parser. - Raises - ------ - RuntimeError - if no command was input + Parameters + ---------- + args: List[str] + list of command line arguments, main purpose is testing default option None + takes arguments from sys.argv """ parser = argparse.ArgumentParser( description="DeePMD-kit: A deep learning package for many-body potential energy" @@ -49,6 +51,7 @@ def main(): parser_log.add_argument( "-l", "--log-path", + type=str, default=None, help="set log file to log messages to disk, if not specified, the logs will " "only be output to console", @@ -285,9 +288,24 @@ def main(): formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) - args = parser.parse_args() + parsed_args = parser.parse_args(args=args) + if parsed_args.command is None: + parser.print_help() + + return parsed_args + - # do not set log handles for None it is useless +def main(): + """DeePMD-Kit entry point. + + Raises + ------ + RuntimeError + if no command was input + """ + args = parse_args() + + # do not set log handles for None, it is useless # log handles for train will be set separatelly # when the use of MPI will be determined in `RunOptions` if args.command not in (None, "train"): @@ -295,9 +313,7 @@ def main(): dict_args = vars(args) - if args.command is None: - parser.print_help() - elif args.command == "train": + if args.command == "train": train(**dict_args) elif args.command == "freeze": freeze(**dict_args) From 76a1a2a1d126c79f4a684e5588f780940144bc57 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Fri, 26 Feb 2021 20:56:00 +0800 Subject: [PATCH 208/562] optimize interface of custom ops --- source/api_cc/include/common.h | 50 +- source/api_cc/include/custom_op.h | 45 ++ source/lib/include/CustomeOperation.h | 491 ------------- source/lib/include/device.h | 2 +- source/lib/include/gelu.h | 45 ++ source/lib/include/{gpu_nv.h => gpu_cuda.h} | 0 source/lib/include/prod_env_mat.h | 47 +- source/lib/include/prod_force.h | 21 + source/lib/include/prod_virial.h | 25 + source/lib/include/tabulate.h | 51 ++ source/lib/src/cuda/CMakeLists.txt | 2 +- source/lib/src/cuda/descrpt_se_r.cu | 92 --- source/lib/src/cuda/gelu.cu | 167 +++-- source/lib/src/cuda/prod_env_mat.cu | 514 ++++++++++++++ source/lib/src/cuda/prod_env_mat_a.cu | 122 ---- source/lib/src/cuda/prod_force.cu | 171 +++++ source/lib/src/cuda/prod_force_se_a.cu | 106 --- source/lib/src/cuda/prod_force_se_r.cu | 101 --- source/lib/src/cuda/prod_virial.cu | 151 ++++ source/lib/src/cuda/prod_virial_se_a.cu | 90 --- source/lib/src/cuda/prod_virial_se_r.cu | 83 --- source/lib/src/cuda/tabulate.cu | 643 ++++++------------ source/lib/src/gelu.cc | 49 ++ source/lib/src/prod_env_mat.cc | 125 ++++ source/lib/src/prod_virial.cc | 4 +- source/lib/src/tabulate.cc | 192 ++++++ source/lib/tests/test_env_mat_a.cc | 4 +- source/op/CMakeLists.txt | 7 +- source/op/descrpt.cc | 14 +- source/op/descrpt_se_a.cc | 15 +- source/op/descrpt_se_a_ef.cc | 14 +- source/op/descrpt_se_a_ef_para.cc | 14 +- source/op/descrpt_se_a_ef_vert.cc | 15 +- source/op/descrpt_se_r.cc | 14 +- source/op/descrpt_se_r_multi_device.cc | 272 -------- source/op/ewald_recp.cc | 13 +- source/op/gelu.cc | 206 ------ source/op/gelu_multi_device.cc | 200 +++--- source/op/map_aparam.cc | 12 +- source/op/neighbor_stat.cc | 15 +- source/op/pair_tab.cc | 10 +- ...device.cc => prod_env_mat_multi_device.cc} | 187 ++++- source/op/prod_force.cc | 8 +- source/op/prod_force_grad.cc | 8 +- source/op/prod_force_multi_device.cc | 190 ++++++ source/op/prod_force_se_a.cc | 9 +- source/op/prod_force_se_a_grad.cc | 9 +- source/op/prod_force_se_a_multi_device.cc | 123 ---- source/op/prod_force_se_r.cc | 9 +- source/op/prod_force_se_r_grad.cc | 9 +- source/op/prod_force_se_r_multi_device.cc | 111 --- source/op/prod_virial.cc | 8 +- source/op/prod_virial_grad.cc | 8 +- source/op/prod_virial_multi_device.cc | 203 ++++++ source/op/prod_virial_se_a.cc | 9 +- source/op/prod_virial_se_a_grad.cc | 9 +- source/op/prod_virial_se_a_multi_device.cc | 125 ---- source/op/prod_virial_se_r.cc | 10 +- source/op/prod_virial_se_r_grad.cc | 9 +- source/op/prod_virial_se_r_multi_device.cc | 2 +- source/op/soft_min.cc | 10 +- source/op/soft_min_force.cc | 9 +- source/op/soft_min_force_grad.cc | 9 +- source/op/soft_min_virial.cc | 9 +- source/op/soft_min_virial_grad.cc | 9 +- source/op/tabulate.cc | 385 ----------- source/op/tabulate_multi_device.cc | 259 ++++--- source/op/unaggregated_grad.cc | 12 +- 68 files changed, 2549 insertions(+), 3413 deletions(-) create mode 100644 source/api_cc/include/custom_op.h delete mode 100644 source/lib/include/CustomeOperation.h create mode 100644 source/lib/include/gelu.h rename source/lib/include/{gpu_nv.h => gpu_cuda.h} (100%) create mode 100644 source/lib/include/tabulate.h delete mode 100644 source/lib/src/cuda/descrpt_se_r.cu create mode 100644 source/lib/src/cuda/prod_env_mat.cu delete mode 100644 source/lib/src/cuda/prod_env_mat_a.cu create mode 100644 source/lib/src/cuda/prod_force.cu delete mode 100644 source/lib/src/cuda/prod_force_se_a.cu delete mode 100644 source/lib/src/cuda/prod_force_se_r.cu create mode 100644 source/lib/src/cuda/prod_virial.cu delete mode 100644 source/lib/src/cuda/prod_virial_se_a.cu delete mode 100644 source/lib/src/cuda/prod_virial_se_r.cu create mode 100644 source/lib/src/gelu.cc create mode 100644 source/lib/src/tabulate.cc delete mode 100644 source/op/descrpt_se_r_multi_device.cc delete mode 100644 source/op/gelu.cc rename source/op/{descrpt_se_a_multi_device.cc => prod_env_mat_multi_device.cc} (53%) create mode 100644 source/op/prod_force_multi_device.cc delete mode 100644 source/op/prod_force_se_a_multi_device.cc delete mode 100644 source/op/prod_force_se_r_multi_device.cc create mode 100644 source/op/prod_virial_multi_device.cc delete mode 100644 source/op/prod_virial_se_a_multi_device.cc delete mode 100644 source/op/tabulate.cc diff --git a/source/api_cc/include/common.h b/source/api_cc/include/common.h index 209daf7f8d..13a03b873c 100644 --- a/source/api_cc/include/common.h +++ b/source/api_cc/include/common.h @@ -1,17 +1,7 @@ #pragma once - -#include "tensorflow/core/public/session.h" -#include "tensorflow/core/public/version.h" -#include "tensorflow/core/platform/env.h" -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - -using namespace tensorflow; -// using namespace std; -#include -#include +#include "custom_op.h" +#include "NNPAtomMap.h" +#include "version.h" #if TF_MAJOR_VERSION >= 2 && TF_MINOR_VERSION >= 2 typedef tensorflow::tstring STRINGTYPE; @@ -19,20 +9,6 @@ typedef tensorflow::tstring STRINGTYPE; typedef std::string STRINGTYPE; #endif -#include "NNPAtomMap.h" -#include -#include -#include "version.h" - -using CPUDevice = Eigen::ThreadPoolDevice; -using GPUDevice = Eigen::GpuDevice; -#ifdef HIGH_PREC -typedef double VALUETYPE; -typedef double ENERGYTYPE; -#else -typedef float VALUETYPE; -typedef double ENERGYTYPE; -#endif struct LammpsNeighborList { @@ -241,22 +217,4 @@ select_map(std::vector & out, } } } -} - -// functions used in custom ops -struct DeviceFunctor { - void operator()( - std::string& device, - const CPUDevice& d) - { - device = "CPU"; - } -#if GOOGLE_CUDA - void operator()( - std::string& device, - const GPUDevice& d) - { - device = "GPU"; - } -#endif // GOOGLE_CUDA -}; \ No newline at end of file +} \ No newline at end of file diff --git a/source/api_cc/include/custom_op.h b/source/api_cc/include/custom_op.h new file mode 100644 index 0000000000..714e9f3d33 --- /dev/null +++ b/source/api_cc/include/custom_op.h @@ -0,0 +1,45 @@ +#include +#include +#include + +#include "tensorflow/core/platform/env.h" +#include "tensorflow/core/framework/op.h" +#include "tensorflow/core/public/session.h" +#include "tensorflow/core/public/version.h" +#include "tensorflow/core/framework/op_kernel.h" +#include "tensorflow/core/framework/shape_inference.h" +#include +#include + +using namespace tensorflow; +using CPUDevice = Eigen::ThreadPoolDevice; +using GPUDevice = Eigen::GpuDevice; + +#ifdef HIGH_PREC +typedef double VALUETYPE; +typedef double ENERGYTYPE; +#else +typedef float VALUETYPE; +typedef double ENERGYTYPE; +#endif + +typedef double boxtensor_t ; +typedef double compute_t; + +// functions used in custom ops +struct DeviceFunctor { + void operator()( + std::string& device, + const CPUDevice& d) + { + device = "CPU"; + } +#if GOOGLE_CUDA + void operator()( + std::string& device, + const GPUDevice& d) + { + device = "GPU"; + } +#endif // GOOGLE_CUDA +}; \ No newline at end of file diff --git a/source/lib/include/CustomeOperation.h b/source/lib/include/CustomeOperation.h deleted file mode 100644 index f7cd8e1b01..0000000000 --- a/source/lib/include/CustomeOperation.h +++ /dev/null @@ -1,491 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include "MathUtilities.h" -#include "fmt_nlist.h" -#include "env_mat.h" -#if GOOGLE_CUDA -#include "DeviceFunctor.h" -#endif // GOOGLE_CUDA - -using CPUDevice = Eigen::ThreadPoolDevice; -using GPUDevice = Eigen::GpuDevice; - - -inline void make_descript_range (int & idx_start, int & idx_end, const int & nei_idx, const int& n_a_sel, const int n_a_shift) { - if (nei_idx < n_a_sel) { - idx_start = nei_idx * 4; - idx_end = nei_idx * 4 + 4; - } - else { - idx_start = n_a_shift + (nei_idx - n_a_sel); - idx_end = n_a_shift + (nei_idx - n_a_sel) + 1; - } -} - -template -void ProdForceSeACPULauncher(FPTYPE * force, const FPTYPE * net_deriv, const FPTYPE * in_deriv, const int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const int n_a_sel, const int n_a_shift) { - memset(force, 0.0, sizeof(FPTYPE) * nall * 3); - // compute force of a frame - for (int i_idx = 0; i_idx < nloc; ++i_idx) { - // deriv wrt center atom - for (int aa = 0; aa < ndescrpt; ++aa) { - force[i_idx * 3 + 0] -= net_deriv[i_idx * ndescrpt + aa] * in_deriv[i_idx * ndescrpt * 3 + aa * 3 + 0]; - force[i_idx * 3 + 1] -= net_deriv[i_idx * ndescrpt + aa] * in_deriv[i_idx * ndescrpt * 3 + aa * 3 + 1]; - force[i_idx * 3 + 2] -= net_deriv[i_idx * ndescrpt + aa] * in_deriv[i_idx * ndescrpt * 3 + aa * 3 + 2]; - } - // deriv wrt neighbors - for (int jj = 0; jj < nnei; ++jj) { - int j_idx = nlist[i_idx * nnei + jj]; - if (j_idx < 0) continue; - int aa_start, aa_end; - make_descript_range (aa_start, aa_end, jj, n_a_sel, n_a_shift); - for (int aa = aa_start; aa < aa_end; ++aa) { - force[j_idx * 3 + 0] += net_deriv[i_idx * ndescrpt + aa] * in_deriv[i_idx * ndescrpt * 3 + aa * 3 + 0]; - force[j_idx * 3 + 1] += net_deriv[i_idx * ndescrpt + aa] * in_deriv[i_idx * ndescrpt * 3 + aa * 3 + 1]; - force[j_idx * 3 + 2] += net_deriv[i_idx * ndescrpt + aa] * in_deriv[i_idx * ndescrpt * 3 + aa * 3 + 2]; - } - } - } -} - -#if GOOGLE_CUDA -template -void ProdForceSeAGPULauncher(FPTYPE * force, const FPTYPE * net_deriv, const FPTYPE * in_deriv, const int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const int n_a_sel, const int n_a_shift) { - ProdForceSeAGPUExecuteFunctor()(force, net_deriv, in_deriv, nlist, nloc, nall, nnei, ndescrpt, n_a_sel, n_a_shift); -} -#endif // GOOGLE_CUDA - -// ****************************************************************************** -// end of custome op ProdForceSeA -// ****************************************************************************** - -template -void ProdVirialSeACPULauncher(FPTYPE * virial, FPTYPE * atom_virial, const FPTYPE * net_deriv, const FPTYPE * in_deriv, const FPTYPE * rij, const int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const int n_a_sel, const int n_a_shift) { - memset(virial, 0.0, sizeof(FPTYPE) * 9); - memset(atom_virial, 0.0, sizeof(FPTYPE) * nall * 9); - - // compute virial of a frame - for (int i_idx = 0; i_idx < nloc; ++i_idx) { - // deriv wrt neighbors - for (int jj = 0; jj < nnei; ++jj) { - int j_idx = nlist[i_idx * nnei + jj]; - if (j_idx < 0) continue; - int aa_start, aa_end; - make_descript_range (aa_start, aa_end, jj, n_a_sel, n_a_shift); - for (int aa = aa_start; aa < aa_end; ++aa) { - FPTYPE pref = -1.0 * net_deriv[i_idx * ndescrpt + aa]; - for (int dd0 = 0; dd0 < 3; ++dd0) - for (int dd1 = 0; dd1 < 3; ++dd1) { - FPTYPE tmp_v = pref * rij[i_idx * nnei * 3 + jj * 3 + dd1] * in_deriv[i_idx * ndescrpt * 3 + aa * 3 + dd0]; - virial[dd0 * 3 + dd1] -= tmp_v; - atom_virial[j_idx * 9 + dd0 * 3 + dd1] -= tmp_v; - } - } - } - } -} - -#if GOOGLE_CUDA -template -void ProdVirialSeAGPULauncher(FPTYPE * virial, FPTYPE * atom_virial, const FPTYPE * net_deriv, const FPTYPE * in_deriv, const FPTYPE * rij, const int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const int n_a_sel, const int n_a_shift) { - ProdVirialSeAGPUExecuteFunctor()(virial, atom_virial, net_deriv, in_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, n_a_sel, n_a_shift); -} -#endif // GOOGLE_CUDA -// ****************************************************************************** -// end of custome op ProdVirialSeA -// ****************************************************************************** - -template -void GeluCPULauncher(const FPTYPE * in, FPTYPE * out, int const size) { - for (int ii = 0; ii < size; ii++) { - out[ii] = in[ii] * 0.5 * (1.0 + tanh(SQRT_2_PI * (in[ii] + 0.044715 * in[ii] * in[ii] *in[ii]))); - } -} - -template -void GeluGradCPULauncher(const FPTYPE * dy, const FPTYPE * in, FPTYPE * out, int const size) { - for (int ii = 0; ii < size; ii++) { - FPTYPE const var1 = tanh(SQRT_2_PI * (in[ii] + 0.044715 * in[ii] * in[ii] *in[ii])); - out[ii] = dy[ii] * (0.5 * SQRT_2_PI * in[ii] * (1 - var1 * var1) * (0.134145 * in[ii] * in[ii] + 1) + 0.5 * var1 + 0.5); - } -} - -template -void GeluGradGradCPULauncher(const FPTYPE * dy, const FPTYPE * dy_, const FPTYPE * in, FPTYPE * out, int const size) { - for (int ii = 0; ii < size; ii++) { - FPTYPE const var1 = tanh(SQRT_2_PI * (in[ii] + 0.044715 * in[ii] * in[ii] *in[ii])); - FPTYPE const var2 = SQRT_2_PI * (1 - var1 * var1) * (0.134145 * in[ii] * in[ii] + 1); - out[ii] = dy[ii] * dy_[ii] * (0.134145 * SQRT_2_PI * in[ii] * in[ii] * (1 - var1 * var1) - SQRT_2_PI * in[ii] * var2 * (0.134145 * in[ii] * in[ii] + 1) * var1 + var2); - } -} - -#if GOOGLE_CUDA -template -void GeluGPULauncher(const FPTYPE * in, FPTYPE * out, int const size) { - GeluGPUExecuteFunctor()(in, out, size); -} - -template -void GeluGradGPULauncher(const FPTYPE * dy, const FPTYPE * in, FPTYPE * out, int const size) { - GeluGradGPUExecuteFunctor()(dy, in, out, size); -} - -template -void GeluGradGradGPULauncher(const FPTYPE * dy, const FPTYPE * dy_, const FPTYPE * in, FPTYPE * out, int const size) { - GeluGradGradGPUExecuteFunctor()(dy, dy_, in, out, size); -} -#endif // GOOGLE_CUDA -// ****************************************************************************** -// end of custome op Gelu -// ****************************************************************************** - - -template -void DescrptSeRCPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { - // set & normalize coord - std::vector d_coord3(nall * 3); - for (int ii = 0; ii < nall; ++ii) { - for (int dd = 0; dd < 3; ++dd) { - d_coord3[ii * 3 + dd] = coord[ii * 3 + dd]; - } - } - - // set type - std::vector d_type (nall); - for (int ii = 0; ii < nall; ++ii) { - d_type[ii] = type[ii]; - } - - // build nlist - std::vector > d_nlist_a(nloc); - - for (unsigned ii = 0; ii < nloc; ++ii) { - d_nlist_a.reserve (jrange[nloc] / nloc + 10); - } - for (unsigned ii = 0; ii < nloc; ++ii) { - int i_idx = ilist[ii]; - for (unsigned jj = jrange[ii]; jj < jrange[ii+1]; ++jj) { - int j_idx = jlist[jj]; - d_nlist_a[i_idx].push_back (j_idx); - } - } - - #pragma omp parallel for - for (int ii = 0; ii < nloc; ++ii) { - std::vector fmt_nlist_a; - int ret = -1; - if (fill_nei_a) { - format_nlist_cpu(fmt_nlist_a, d_coord3, ntypes, d_type, ii, d_nlist_a[ii], rcut_r, sec_a); - } - std::vector d_descrpt_a; - std::vector d_descrpt_a_deriv; - std::vector d_descrpt_r; - std::vector d_descrpt_r_deriv; - std::vector d_rij_a; - env_mat_r_cpu (d_descrpt_a, d_descrpt_a_deriv, d_rij_a, d_coord3, ntypes, d_type, ii, fmt_nlist_a, sec_a, rcut_r_smth, rcut_r); - - // check sizes - assert (d_descrpt_a.size() == ndescrpt); - assert (d_descrpt_a_deriv.size() == ndescrpt * 3); - assert (d_rij_a.size() == nnei * 3); - assert (fmt_nlist_a.size() == nnei); - // record outputs - for (int jj = 0; jj < ndescrpt; ++jj) { - descrpt[ii * ndescrpt + jj] = (d_descrpt_a[jj] - avg[d_type[ii] * ndescrpt + jj]) / std[d_type[ii] * ndescrpt + jj]; - } - for (int jj = 0; jj < ndescrpt * 3; ++jj) { - descrpt_deriv[ii * ndescrpt * 3 + jj] = d_descrpt_a_deriv[jj] / std[d_type[ii] * ndescrpt + jj / 3]; - } - for (int jj = 0; jj < nnei * 3; ++jj) { - rij[ii * nnei * 3 + jj] = d_rij_a[jj]; - } - for (int jj = 0; jj < nnei; ++jj) { - nlist[ii * nnei + jj] = fmt_nlist_a[jj]; - } - } -} - -#if GOOGLE_CUDA -template -void DescrptSeRGPULauncher(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * descrpt, FPTYPE * descrpt_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { - DescrptSeRGPUExecuteFunctor()(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); -} -#endif // GOOGLE_CUDA -// ****************************************************************************** -// end of custome op DescrptSeR -// ****************************************************************************** - -template -void ProdForceSeRCPULauncher(FPTYPE * force, const FPTYPE * net_deriv, const FPTYPE * in_deriv, const int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt) { - memset(force, 0.0, sizeof(FPTYPE) * nall * 3); - // compute force of a frame - for (int i_idx = 0; i_idx < nloc; ++i_idx) { - // deriv wrt center atom - for (int aa = 0; aa < ndescrpt; ++aa) { - force[i_idx * 3 + 0] -= net_deriv[i_idx * ndescrpt + aa] * in_deriv[i_idx * ndescrpt * 3 + aa * 3 + 0]; - force[i_idx * 3 + 1] -= net_deriv[i_idx * ndescrpt + aa] * in_deriv[i_idx * ndescrpt * 3 + aa * 3 + 1]; - force[i_idx * 3 + 2] -= net_deriv[i_idx * ndescrpt + aa] * in_deriv[i_idx * ndescrpt * 3 + aa * 3 + 2]; - } - // deriv wrt neighbors - for (int jj = 0; jj < nnei; ++jj) { - int j_idx = nlist[i_idx * nnei + jj]; - if (j_idx < 0) continue; - force[j_idx * 3 + 0] += net_deriv[i_idx * ndescrpt + jj] * in_deriv[i_idx * ndescrpt * 3 + jj * 3 + 0]; - force[j_idx * 3 + 1] += net_deriv[i_idx * ndescrpt + jj] * in_deriv[i_idx * ndescrpt * 3 + jj * 3 + 1]; - force[j_idx * 3 + 2] += net_deriv[i_idx * ndescrpt + jj] * in_deriv[i_idx * ndescrpt * 3 + jj * 3 + 2]; - } - } -} - -#if GOOGLE_CUDA -template -void ProdForceSeRGPULauncher(FPTYPE * force, const FPTYPE * net_deriv, const FPTYPE * in_deriv, const int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt) { - ProdForceSeRGPUExecuteFunctor()(force, net_deriv, in_deriv, nlist, nloc, nall, nnei, ndescrpt); -} -#endif // GOOGLE_CUDA - -// ****************************************************************************** -// end of custome op ProdForceSeR -// ****************************************************************************** - -template -void ProdVirialSeRCPULauncher(FPTYPE * virial, FPTYPE * atom_virial, const FPTYPE * net_deriv, const FPTYPE * in_deriv, const FPTYPE * rij, const int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt) { - memset(virial, 0.0, sizeof(FPTYPE) * 9); - memset(atom_virial, 0.0, sizeof(FPTYPE) * nall * 9); - - // compute virial of a frame - for (int i_idx = 0; i_idx < nloc; ++i_idx) { - // deriv wrt neighbors - for (int jj = 0; jj < nnei; ++jj) { - int j_idx = nlist[i_idx * nnei + jj]; - if (j_idx < 0) continue; - FPTYPE pref = -1.0 * net_deriv[i_idx * ndescrpt + jj]; - for (int dd0 = 0; dd0 < 3; ++dd0) - for (int dd1 = 0; dd1 < 3; ++dd1) { - FPTYPE tmp_v = pref * rij[i_idx * nnei * 3 + jj * 3 + dd1] * in_deriv[i_idx * ndescrpt * 3 + jj * 3 + dd0]; - virial[dd0 * 3 + dd1] -= tmp_v; - atom_virial[j_idx * 9 + dd0 * 3 + dd1] -= tmp_v; - } - } - } -} - -#if GOOGLE_CUDA -template -void ProdVirialSeRGPULauncher(FPTYPE * virial, FPTYPE * atom_virial, const FPTYPE * net_deriv, const FPTYPE * in_deriv, const FPTYPE * rij, const int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt) { - ProdVirialSeRGPUExecuteFunctor()(virial, atom_virial, net_deriv, in_deriv, rij, nlist, nloc, nall, nnei, ndescrpt); -} -#endif // GOOGLE_CUDA -// ****************************************************************************** -// end of custome op ProdVirialSeR -// ****************************************************************************** - -template -inline FPTYPE dot(FPTYPE a[4], FPTYPE b[4]) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; -} - -/* - This inline function was designed to get the table info and bias value for current input xx! - lower: indicate the lower boundary of the first table; - upper: indicate the upper boundary of the first table as well as the lower boundary of the second table; - max: indicate the upper boundary of the second table; - stride0: indicate the stride of the first table; - stride1: indicate the stride of the second table; - xx: indicate the inputs value; - table_idx: indicate the location of table info of input value xx; -*/ -template -inline void locate_xx(const FPTYPE& lower, const FPTYPE& upper, const FPTYPE& max, const FPTYPE& stride0, const FPTYPE& stride1, FPTYPE& xx, int& table_idx) { - if (xx < lower) { - table_idx = 0; - xx = 0; - } - else if (xx < upper) { - table_idx = (int)((xx - lower) / stride0); - xx -= (table_idx * stride0 + lower); - } - else if (xx < max) { - int first_stride = int((upper - lower) / stride0); - table_idx = first_stride + (int)((xx - upper) / stride1); - xx -= ((table_idx - first_stride) * stride1 + upper); - } - else { - table_idx = int((upper - lower) / stride0) + (int)((max - upper) / stride1) - 1; - xx = 0; - } -} - -template -void TabulateFusionCPULauncher(const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const int nloc, const int nnei, const int last_layer_size, FPTYPE * out) { - //Currently, Do nothing at all! - // std::cout << "I'm in tabulate @CPU!" << std::endl; - memset(out, 0.0, sizeof(FPTYPE) * nloc * 4 * last_layer_size); - FPTYPE const lower = table_info[0]; - FPTYPE const upper = table_info[1]; - FPTYPE const _max = table_info[2]; - FPTYPE const stride0 = table_info[3]; - FPTYPE const stride1 = table_info[4]; - // for every atom, execute a small gemm~ - // FPTYPE * res = new FPTYPE[4 * last_layer_size]; - #pragma omp parallel for - for (int ii = 0; ii < nloc; ii++) { - FPTYPE ll[4] = {0}; - FPTYPE ago = in[ii * nnei + nnei - 1]; - bool unloop = false; - for (int jj = 0; jj < nnei; jj++) { - ll[0] = ff[ii * nnei * 4 + jj * 4 + 0]; - ll[1] = ff[ii * nnei * 4 + jj * 4 + 1]; - ll[2] = ff[ii * nnei * 4 + jj * 4 + 2]; - ll[3] = ff[ii * nnei * 4 + jj * 4 + 3]; - FPTYPE xx = in[ii * nnei + jj]; - if (ago == xx) { - unloop = true; - } - int table_idx = 0; - locate_xx(lower, upper, _max, stride0, stride1, xx, table_idx); - for (int kk = 0; kk < last_layer_size; kk++) { - // 1.094 timesteps/s - FPTYPE a0 = table[table_idx * last_layer_size * 6 + 6 * kk + 0]; - FPTYPE a1 = table[table_idx * last_layer_size * 6 + 6 * kk + 1]; - FPTYPE a2 = table[table_idx * last_layer_size * 6 + 6 * kk + 2]; - FPTYPE a3 = table[table_idx * last_layer_size * 6 + 6 * kk + 3]; - FPTYPE a4 = table[table_idx * last_layer_size * 6 + 6 * kk + 4]; - FPTYPE a5 = table[table_idx * last_layer_size * 6 + 6 * kk + 5]; - FPTYPE var = a0 + (a1 + (a2 + (a3 + (a4 + a5 * xx) * xx) * xx) * xx) * xx; - if (unloop) { - out[ii * last_layer_size * 4 + 0 * last_layer_size + kk] += (nnei - jj) * var * ll[0]; - out[ii * last_layer_size * 4 + 1 * last_layer_size + kk] += (nnei - jj) * var * ll[1]; - out[ii * last_layer_size * 4 + 2 * last_layer_size + kk] += (nnei - jj) * var * ll[2]; - out[ii * last_layer_size * 4 + 3 * last_layer_size + kk] += (nnei - jj) * var * ll[3]; - } - else { - out[ii * last_layer_size * 4 + 0 * last_layer_size + kk] += var * ll[0]; - out[ii * last_layer_size * 4 + 1 * last_layer_size + kk] += var * ll[1]; - out[ii * last_layer_size * 4 + 2 * last_layer_size + kk] += var * ll[2]; - out[ii * last_layer_size * 4 + 3 * last_layer_size + kk] += var * ll[3]; - } - } - if (unloop) break; - } - } -} - -template -void TabulateFusionGradCPULauncher(const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const FPTYPE * dy, const int nloc, const int nnei, const int last_layer_size, FPTYPE * dy_dx, FPTYPE * dy_df) { - // std::cout << "I'm in tabulate gradient @CPU!" << std::endl; - memset(dy_dx, 0.0, sizeof(FPTYPE) * nloc * nnei); - memset(dy_df, 0.0, sizeof(FPTYPE) * nloc * nnei * 4); - FPTYPE const lower = table_info[0]; - FPTYPE const upper = table_info[1]; - FPTYPE const _max = table_info[2]; - FPTYPE const stride0 = table_info[3]; - FPTYPE const stride1 = table_info[4]; - // for every atom, execute a small gemm~ - // FPTYPE * res = new FPTYPE[4 * last_layer_size]; - #pragma omp parallel for - for (int ii = 0; ii < nloc; ii++) { - FPTYPE ll[4]; - FPTYPE rr[4]; - FPTYPE ago = in[ii * nnei + nnei - 1]; - bool unloop = false; - for (int jj = 0; jj < nnei; jj++) { - // construct the dy/dx - ll[0] = ff[ii * nnei * 4 + jj * 4 + 0]; - ll[1] = ff[ii * nnei * 4 + jj * 4 + 1]; - ll[2] = ff[ii * nnei * 4 + jj * 4 + 2]; - ll[3] = ff[ii * nnei * 4 + jj * 4 + 3]; - FPTYPE xx = in[ii * nnei + jj]; - if (ago == xx) { - unloop = true; - } - int table_idx = 0; - locate_xx(lower, upper, _max, stride0, stride1, xx, table_idx); - FPTYPE grad = 0.0; - for (int kk = 0; kk < last_layer_size; kk++) { - rr[0] = dy[ii * last_layer_size * 4 + 0 * last_layer_size + kk]; - rr[1] = dy[ii * last_layer_size * 4 + 1 * last_layer_size + kk]; - rr[2] = dy[ii * last_layer_size * 4 + 2 * last_layer_size + kk]; - rr[3] = dy[ii * last_layer_size * 4 + 3 * last_layer_size + kk]; - // 1.094 timesteps/s - FPTYPE a0 = table[table_idx * last_layer_size * 6 + 6 * kk + 0]; - FPTYPE a1 = table[table_idx * last_layer_size * 6 + 6 * kk + 1]; - FPTYPE a2 = table[table_idx * last_layer_size * 6 + 6 * kk + 2]; - FPTYPE a3 = table[table_idx * last_layer_size * 6 + 6 * kk + 3]; - FPTYPE a4 = table[table_idx * last_layer_size * 6 + 6 * kk + 4]; - FPTYPE a5 = table[table_idx * last_layer_size * 6 + 6 * kk + 5]; - FPTYPE res = a0 + (a1 + (a2 + (a3 + (a4 + a5 * xx) * xx) * xx) * xx) * xx; - - if (unloop) { - grad += (a1 + (2 * a2 + (3 * a3 + (4 * a4 + 5 * a5 * xx) * xx) * xx) * xx) * dot(ll, rr) * (nnei - jj); - dy_df[ii * nnei * 4 + jj * 4 + 0] += res * rr[0] * (nnei - jj); - dy_df[ii * nnei * 4 + jj * 4 + 1] += res * rr[1] * (nnei - jj); - dy_df[ii * nnei * 4 + jj * 4 + 2] += res * rr[2] * (nnei - jj); - dy_df[ii * nnei * 4 + jj * 4 + 3] += res * rr[3] * (nnei - jj); - } - else { - grad += (a1 + (2 * a2 + (3 * a3 + (4 * a4 + 5 * a5 * xx) * xx) * xx) * xx) * dot(ll, rr); - dy_df[ii * nnei * 4 + jj * 4 + 0] += res * rr[0]; - dy_df[ii * nnei * 4 + jj * 4 + 1] += res * rr[1]; - dy_df[ii * nnei * 4 + jj * 4 + 2] += res * rr[2]; - dy_df[ii * nnei * 4 + jj * 4 + 3] += res * rr[3]; - } - } - dy_dx[ii * nnei + jj] = grad; - if (unloop) break; - } - } -} - -template -void TabulateCheckerCPULauncher(const FPTYPE * table_info, const FPTYPE * in, int * out, const int nloc, const int nnei) { - FPTYPE const lower = table_info[0]; - FPTYPE const upper = table_info[1]; - FPTYPE const _max = table_info[2]; - FPTYPE const stride0 = table_info[3]; - FPTYPE const stride1 = table_info[4]; - // for every atom, execute a small gemm~ - // FPTYPE * res = new FPTYPE[4 * last_layer_size]; - int Csub = 0; // summation of second table approximate; - int Dsub = 0; // summation of the endpoint approximate; - for (int ii = 0; ii < nloc; ii++) { - for (int jj = 0; jj < nnei; jj++) { - FPTYPE xx = in[ii * nnei + jj]; - if (xx < lower || xx > _max) { - Csub += 1; - } - else if (xx >= upper && xx <= _max) { - Dsub += 1; - } - } - } - if(Csub > 0) { - std::cout << "# DEEPMD: warning! some values [" << Csub << "/" << nloc * nnei << "] overflow the range of the table, using the endpoint approximate processing.." << std::endl; - } - if(Dsub > 0) { - std::cout << "# DEEPMD: warning! some values [" << Dsub << "/" << nloc * nnei << "] overflow the range of the table, using second table approximate processing.." << std::endl; - } -} - -#if GOOGLE_CUDA -template -void TabulateFusionGPULauncher(const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const int nloc, const int nnei, const int last_layer_size, FPTYPE * out) { - TabulateFusionGPUExecuteFunctor()(table, table_info, in, ff, nloc, nnei, last_layer_size, out); -} - -template -void TabulateFusionGradGPULauncher(const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const FPTYPE * dy, const int nloc, const int nnei, const int last_layer_size, FPTYPE * dy_dx, FPTYPE * dy_df) { - TabulateFusionGradGPUExecuteFunctor()(table, table_info, in, ff, dy, nloc, nnei, last_layer_size, dy_dx, dy_df); -} - -template -void TabulateCheckerGPULauncher(const FPTYPE * table_info, const FPTYPE * in, int * out, const int nloc, const int nnei) { - TabulateCheckerGPUExecuteFunctor()(table_info, in, out, nloc, nnei); -} -#endif // GOOGLE_CUDA -// ****************************************************************************** -// end of custome op Tabulate -// ****************************************************************************** diff --git a/source/lib/include/device.h b/source/lib/include/device.h index 7a885c9ad5..dfd12a4f27 100644 --- a/source/lib/include/device.h +++ b/source/lib/include/device.h @@ -9,5 +9,5 @@ typedef unsigned long long int_64; #if GOOGLE_CUDA -#include "gpu_nv.h" +#include "gpu_cuda.h" #endif \ No newline at end of file diff --git a/source/lib/include/gelu.h b/source/lib/include/gelu.h new file mode 100644 index 0000000000..5e5baffb5c --- /dev/null +++ b/source/lib/include/gelu.h @@ -0,0 +1,45 @@ +#pragma once + +template +void gelu_cpu( + FPTYPE * out, + const FPTYPE * x, + const int size); + +template +void gelu_grad_cpu( + FPTYPE * out, + const FPTYPE * x, + const FPTYPE * dy, + const int size); + +template +void gelu_grad_grad_cpu( + FPTYPE * out, + const FPTYPE * x, + const FPTYPE * dy, + const FPTYPE * dy_2, + const int size); + +#if GOOGLE_CUDA +template +void gelu_gpu_cuda( + FPTYPE * out, + const FPTYPE * x, + const int size); + +template +void gelu_grad_gpu_cuda( + FPTYPE * out, + const FPTYPE * x, + const FPTYPE * dy, + const int size); + +template +void gelu_grad_grad_gpu_cuda( + FPTYPE * out, + const FPTYPE * x, + const FPTYPE * dy, + const FPTYPE * dy_2, + const int size); +#endif // GOOGLE_CUDA diff --git a/source/lib/include/gpu_nv.h b/source/lib/include/gpu_cuda.h similarity index 100% rename from source/lib/include/gpu_nv.h rename to source/lib/include/gpu_cuda.h diff --git a/source/lib/include/prod_env_mat.h b/source/lib/include/prod_env_mat.h index 795c3eaeda..f49078260e 100644 --- a/source/lib/include/prod_env_mat.h +++ b/source/lib/include/prod_env_mat.h @@ -23,9 +23,52 @@ void prod_env_mat_a_cpu( const float rcut_smth, const std::vector sec); +template +void prod_env_mat_r_cpu( + FPTYPE * em, + FPTYPE * em_deriv, + FPTYPE * rij, + int * nlist, + const FPTYPE * coord, + const int * type, + const int * ilist, + const int * jrange, + const int * jlist, + const int max_nbor_size, + const FPTYPE * avg, + const FPTYPE * std, + const int nloc, + const int nall, + const int ntypes, + const float rcut, + const float rcut_smth, + const std::vector sec); + #if GOOGLE_CUDA template -void prod_env_mat_a_gpu_nv( +void prod_env_mat_a_gpu_cuda( + FPTYPE * em, + FPTYPE * em_deriv, + FPTYPE * rij, + int * nlist, + const FPTYPE * coord, + const int * type, + const int * ilist, + const int * jrange, + const int * jlist, + int * array_int, + unsigned long long * array_longlong, + const int max_nbor_size, + const FPTYPE * avg, + const FPTYPE * std, + const int nloc, + const int nall, + const float rcut, + const float rcut_smth, + const std::vector sec); + +template +void prod_env_mat_r_gpu_cuda( FPTYPE * em, FPTYPE * em_deriv, FPTYPE * rij, @@ -57,5 +100,5 @@ void env_mat_nbor_update( int &max_nbor_size, const int * mesh, const int size); -#endif +#endif // GOOGLE_CUDA diff --git a/source/lib/include/prod_force.h b/source/lib/include/prod_force.h index 89d9cc4117..9236f7802f 100644 --- a/source/lib/include/prod_force.h +++ b/source/lib/include/prod_force.h @@ -20,3 +20,24 @@ void prod_force_r_cpu( const int nall, const int nnei); +#if GOOGLE_CUDA +template +void prod_force_a_gpu_cuda( + FPTYPE * force, + const FPTYPE * net_deriv, + const FPTYPE * in_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei); + +template +void prod_force_r_gpu_cuda( + FPTYPE * force, + const FPTYPE * net_deriv, + const FPTYPE * in_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei); +#endif // GOOGLE_CUDA \ No newline at end of file diff --git a/source/lib/include/prod_virial.h b/source/lib/include/prod_virial.h index aeb061eca1..c86d47f79b 100644 --- a/source/lib/include/prod_virial.h +++ b/source/lib/include/prod_virial.h @@ -24,3 +24,28 @@ void prod_virial_r_cpu( const int nall, const int nnei); +#if GOOGLE_CUDA +template +void prod_virial_a_gpu_cuda( + FPTYPE * virial, + FPTYPE * atom_virial, + const FPTYPE * net_deriv, + const FPTYPE * env_deriv, + const FPTYPE * rij_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei); + +template +void prod_virial_r_gpu_cuda( + FPTYPE * virial, + FPTYPE * atom_virial, + const FPTYPE * net_deriv, + const FPTYPE * env_deriv, + const FPTYPE * rij_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei); +#endif // GOOGLE_CUDA diff --git a/source/lib/include/tabulate.h b/source/lib/include/tabulate.h new file mode 100644 index 0000000000..77507ec8eb --- /dev/null +++ b/source/lib/include/tabulate.h @@ -0,0 +1,51 @@ +#pragma once + +template +void tabulate_fusion_cpu( + FPTYPE * out, + const FPTYPE * table, + const FPTYPE * table_info, + const FPTYPE * em_x, + const FPTYPE * em, + const int nloc, + const int nnei, + const int last_layer_size); + +template +void tabulate_fusion_grad_cpu( + FPTYPE * dy_dem_x, + FPTYPE * dy_dem, + const FPTYPE * table, + const FPTYPE * table_info, + const FPTYPE * em_x, + const FPTYPE * em, + const FPTYPE * dy, + const int nloc, + const int nnei, + const int last_layer_size); + +#if GOOGLE_CUDA +template +void tabulate_fusion_gpu_cuda( + FPTYPE * out, + const FPTYPE * table, + const FPTYPE * table_info, + const FPTYPE * em_x, + const FPTYPE * em, + const int nloc, + const int nnei, + const int last_layer_size); + +template +void tabulate_fusion_grad_gpu_cuda( + FPTYPE * dy_dem_x, + FPTYPE * dy_dem, + const FPTYPE * table, + const FPTYPE * table_info, + const FPTYPE * em_x, + const FPTYPE * em, + const FPTYPE * dy, + const int nloc, + const int nnei, + const int last_layer_size); +#endif // GOOGLE_CUDA diff --git a/source/lib/src/cuda/CMakeLists.txt b/source/lib/src/cuda/CMakeLists.txt index 3c09a814dd..92ffe8e78a 100644 --- a/source/lib/src/cuda/CMakeLists.txt +++ b/source/lib/src/cuda/CMakeLists.txt @@ -84,7 +84,7 @@ endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -DCUB_IGNORE_DEPRECATED_CPP_DIALECT -DCUB_IGNORE_DEPRECATED_CPP_DIALECT") set (SOURCE_FILES - prod_env_mat_a.cu descrpt_se_r.cu prod_force_se_a.cu prod_force_se_r.cu prod_virial_se_a.cu prod_virial_se_r.cu gelu.cu tabulate.cu gpu_nv.cu + prod_env_mat.cu prod_force.cu prod_virial.cu gelu.cu tabulate.cu ) cuda_add_library(deepmd_op_cuda SHARED ${SOURCE_FILES}) diff --git a/source/lib/src/cuda/descrpt_se_r.cu b/source/lib/src/cuda/descrpt_se_r.cu deleted file mode 100644 index 38bc6db854..0000000000 --- a/source/lib/src/cuda/descrpt_se_r.cu +++ /dev/null @@ -1,92 +0,0 @@ -#include -#include -#include -#include "DeviceFunctor.h" -#include "gpu_nv.cuh" -#include "gpu_nv.h" - -template< - typename FPTYPE, - int THREADS_PER_BLOCK> -__global__ void compute_descriptor_se_r(FPTYPE* descript, - const int ndescrpt, - FPTYPE* descript_deriv, - const int descript_deriv_size, - FPTYPE* rij, - const int rij_size, - const int* type, - const FPTYPE* avg, - const FPTYPE* std, - int* nlist, - const int nlist_size, - const FPTYPE* coord, - const float rmin, - const float rmax, - const int sec_a_size) -{ - // <<>> - const unsigned int bid = blockIdx.x; - const unsigned int tid = threadIdx.x; - // usually false... - if (tid >= sec_a_size) { - return; - } - // const int idx_deriv = idy * 4 * 3; // 4 components time 3 directions - // const int idx_value = idy * 4; // 4 components - int * row_nlist = nlist + bid * nlist_size; - FPTYPE * row_rij = rij + bid * rij_size; - FPTYPE * row_descript = descript + bid * ndescrpt; - FPTYPE * row_descript_deriv = descript_deriv + bid * descript_deriv_size; - - for (int ii = tid; ii < sec_a_size; ii += THREADS_PER_BLOCK) { - const int idx_value = ii; // 4 components - const int idx_deriv = ii * 3; // 4 components time 3 directions - if (row_nlist[ii] >= 0) { - FPTYPE rr[3] = {0}; - FPTYPE vv[3] = {0}; - FPTYPE dd = 0; - const int & j_idx = row_nlist[ii]; - for (int kk = 0; kk < 3; kk++) { - rr[kk] = coord[j_idx * 3 + kk] - coord[bid * 3 + kk]; - row_rij[ii * 3 + kk] = rr[kk]; - } - // const FPTYPE * rr = &row_rij[ii * 3]; - FPTYPE nr2 = dev_dot(rr, rr); - FPTYPE inr = 1./sqrt(nr2); - FPTYPE nr = nr2 * inr; - FPTYPE inr2 = inr * inr; - FPTYPE inr4 = inr2 * inr2; - FPTYPE inr3 = inr4 * nr; - FPTYPE sw, dsw; - spline5_switch(sw, dsw, nr, rmin, rmax); - dd = (1./nr) ;//* sw; - - vv[0] = (rr[0] * inr3 * sw - dd * dsw * rr[0] * inr); // avg[type[(idx_deriv + 0) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 0) % (ndescrpt * 3)) / 3]; - vv[1] = (rr[1] * inr3 * sw - dd * dsw * rr[1] * inr); // avg[type[(idx_deriv + 1) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 1) % (ndescrpt * 3)) / 3]; - vv[2] = (rr[2] * inr3 * sw - dd * dsw * rr[2] * inr); // avg[type[(idx_deriv + 2) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 2) % (ndescrpt * 3)) / 3]; - - // 4 value components - dd *= sw; // * descript[idx * ndescrpt + idx_value + 0]);// - avg[type[idx] * ndescrpt + idx_value + 0]) / std[type[idx] * ndescrpt + idx_value + 0]; - for (int ii = 0; ii < 3; ii++) { - row_descript_deriv[idx_deriv + ii] = vv[ii] / std[type[bid] * ndescrpt + idx_value + ii / 3]; - } - row_descript[idx_value] = (dd - avg[type[bid] * ndescrpt + idx_value]) / std[type[bid] * ndescrpt + idx_value]; - } - else { - // TODO: move it to the memset. - row_descript[idx_value] -= avg[type[bid] * ndescrpt + idx_value] / std[type[bid] * ndescrpt + idx_value]; - } - } -} - -template -void DescrptSeRGPUExecuteFunctor::operator()(const FPTYPE * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const FPTYPE * avg, const FPTYPE * std, FPTYPE * em, FPTYPE * em_deriv, FPTYPE * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { - prod_env_mat_common( - em, em_deriv, rij, nlist, - coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, rcut_r, rcut_r_smth, sec_a); - - compute_descriptor_se_r <<>> (em, ndescrpt, em_deriv, ndescrpt * 3, rij, nnei * 3, type, avg, std, nlist, nnei, coord, rcut_r_smth, rcut_r, sec_a.back()); -} - -template struct DescrptSeRGPUExecuteFunctor; -template struct DescrptSeRGPUExecuteFunctor; \ No newline at end of file diff --git a/source/lib/src/cuda/gelu.cu b/source/lib/src/cuda/gelu.cu index 1717e96704..37e44329cd 100644 --- a/source/lib/src/cuda/gelu.cu +++ b/source/lib/src/cuda/gelu.cu @@ -1,105 +1,96 @@ -#include "DeviceFunctor.h" -#include "gpu_nv.h" +#include "gelu.h" +#include "device.h" +#include "gpu_cuda.h" template -__global__ void gelu(const FPTYPE * in, FPTYPE * out, int const size) { - int const idx = blockIdx.x * blockDim.x + threadIdx.x; - if (idx >= size) {return;} - - out[idx] = in[idx] * 0.5 * (1.0 + tanh(SQRT_2_PI * (in[idx] + 0.044715 * in[idx] * in[idx] *in[idx]))); +__global__ void gelu( + FPTYPE * out, + const FPTYPE * xx, + int const size) +{ + int const idx = blockIdx.x * blockDim.x + threadIdx.x; + if (idx >= size) { + return; + } + out[idx] = xx[idx] * 0.5 * (1.0 + tanh(SQRT_2_PI * (xx[idx] + 0.044715 * xx[idx] * xx[idx] *xx[idx]))); } template -__global__ void gelu_grad(const FPTYPE * dy, const FPTYPE * in, FPTYPE * out, int const size) { - int const idx = blockIdx.x * blockDim.x + threadIdx.x; - if (idx >= size) {return;} - - // out[idx] = in[idx] * 0.5 * (1.0 + tanh(SQRT_2_PI * (in[idx] + 0.044715 * in[idx] * in[idx] *in[idx]))); - FPTYPE const var1 = tanh(SQRT_2_PI * (in[idx] + 0.044715 * in[idx] * in[idx] *in[idx])); - out[idx] = dy[idx] * (0.5 * SQRT_2_PI * in[idx] * (1 - var1 * var1) * (0.134145 * in[idx] * in[idx] + 1) + 0.5 * var1 + 0.5); +__global__ void gelu_grad( + FPTYPE * out, + const FPTYPE * xx, + const FPTYPE * dy, + int const size) +{ + const int idx = blockIdx.x * blockDim.x + threadIdx.x; + if (idx >= size) { + return; + } + // out[idx] = xx[idx] * 0.5 * (1.0 + tanh(SQRT_2_PI * (xx[idx] + 0.044715 * xx[idx] * xx[idx] *xx[idx]))); + const FPTYPE var = tanh(SQRT_2_PI * (xx[idx] + 0.044715 * xx[idx] * xx[idx] *xx[idx])); + out[idx] = dy[idx] * (0.5 * SQRT_2_PI * xx[idx] * (1 - var * var) * (0.134145 * xx[idx] * xx[idx] + 1) + 0.5 * var + 0.5); } template -__global__ void gelu_grad_grad(const FPTYPE * dy, const FPTYPE * dy_, const FPTYPE * in, FPTYPE * out, int const size) { - int const idx = blockIdx.x * blockDim.x + threadIdx.x; - if (idx >= size) {return;} - - // out[idx] = in[idx] * 0.5 * (1.0 + tanh(SQRT_2_PI * (in[idx] + 0.044715 * in[idx] * in[idx] *in[idx]))); - FPTYPE const var1 = tanh(SQRT_2_PI * (in[idx] + 0.044715 * in[idx] * in[idx] *in[idx])); - FPTYPE const var2 = SQRT_2_PI * (1 - var1 * var1) * (0.134145 * in[idx] * in[idx] + 1); - - out[idx] = dy[idx] * dy_[idx] * (0.134145 * SQRT_2_PI * in[idx] * in[idx] * (1 - var1 * var1) - SQRT_2_PI * in[idx] * var2 * (0.134145 * in[idx] * in[idx] + 1) * var1 + var2); +__global__ void gelu_grad_grad( + FPTYPE * out, + const FPTYPE * xx, + const FPTYPE * dy, + const FPTYPE * dy_2, + int const size) +{ + const int idx = blockIdx.x * blockDim.x + threadIdx.x; + if (idx >= size) { + return; + } + // out[idx] = xx[idx] * 0.5 * (1.0 + tanh(SQRT_2_PI * (xx[idx] + 0.044715 * xx[idx] * xx[idx] *xx[idx]))); + const FPTYPE var1 = tanh(SQRT_2_PI * (xx[idx] + 0.044715 * xx[idx] * xx[idx] *xx[idx])); + const FPTYPE var2 = SQRT_2_PI * (1 - var1 * var1) * (0.134145 * xx[idx] * xx[idx] + 1); + out[idx] = dy[idx] * dy_2[idx] * (0.134145 * SQRT_2_PI * xx[idx] * xx[idx] * (1 - var1 * var1) - SQRT_2_PI * xx[idx] * var2 * (0.134145 * xx[idx] * xx[idx] + 1) * var1 + var2); } -void GeluLauncher(const float * in, float * out, int const size) { - int const THREAD_ITEMS = 1024; - int const BLOCK_NUMS = (size + THREAD_ITEMS - 1) / THREAD_ITEMS; +template +void gelu_gpu_cuda( + FPTYPE * out, + const FPTYPE * xx, + const int size) +{ + const int THREAD_ITEMS = 1024; + const int BLOCK_NUMS = (size + THREAD_ITEMS - 1) / THREAD_ITEMS; - gelu<<>>(in, out, size); + gelu<<>>(out, xx, size); } -void GeluLauncher(const double * in, double * out, int const size) { - int const THREAD_ITEMS = 1024; - int const BLOCK_NUMS = (size + THREAD_ITEMS - 1) / THREAD_ITEMS; - - gelu<<>>(in, out, size); -} - -void GeluGradLauncher(const float * dy, const float * in, float * out, int const size) { - int const THREAD_ITEMS = 1024; - int const BLOCK_NUMS = (size + THREAD_ITEMS - 1) / THREAD_ITEMS; - - gelu_grad<<>>(dy, in, out, size); -} - -void GeluGradLauncher(const double * dy, const double * in, double * out, int const size) { - int const THREAD_ITEMS = 1024; - int const BLOCK_NUMS = (size + THREAD_ITEMS - 1) / THREAD_ITEMS; - - gelu_grad<<>>(dy, in, out, size); -} - -void GeluGradGradLauncher(const float * dy, const float * dy_, const float * in, float * out, int const size) { - int const THREAD_ITEMS = 1024; - int const BLOCK_NUMS = (size + THREAD_ITEMS - 1) / THREAD_ITEMS; - - gelu_grad_grad<<>>(dy, dy_, in, out, size); +template +void gelu_grad_gpu_cuda( + FPTYPE * out, + const FPTYPE * xx, + const FPTYPE * dy, + const int size) +{ + const int THREAD_ITEMS = 1024; + const int BLOCK_NUMS = (size + THREAD_ITEMS - 1) / THREAD_ITEMS; + + gelu_grad<<>>(out, xx, dy, size); } -void GeluGradGradLauncher(const double * dy, const double * dy_, const double * in, double * out, int const size) { - int const THREAD_ITEMS = 1024; - int const BLOCK_NUMS = (size + THREAD_ITEMS - 1) / THREAD_ITEMS; - - gelu_grad_grad<<>>(dy, dy_, in, out, size); -} - -template -void GeluGPUExecuteFunctor::operator()(const FPTYPE * in, FPTYPE * out, int const size) { - int const THREAD_ITEMS = 1024; - int const BLOCK_NUMS = (size + THREAD_ITEMS - 1) / THREAD_ITEMS; - - gelu<<>>(in, out, size); -} - -template -void GeluGradGPUExecuteFunctor::operator()(const FPTYPE * dy, const FPTYPE * in, FPTYPE * out, int const size) { - int const THREAD_ITEMS = 1024; - int const BLOCK_NUMS = (size + THREAD_ITEMS - 1) / THREAD_ITEMS; - - gelu_grad<<>>(dy, in, out, size); -} - -template -void GeluGradGradGPUExecuteFunctor::operator()(const FPTYPE * dy, const FPTYPE * dy_, const FPTYPE * in, FPTYPE * out, int const size) { - int const THREAD_ITEMS = 1024; - int const BLOCK_NUMS = (size + THREAD_ITEMS - 1) / THREAD_ITEMS; - - gelu_grad_grad<<>>(dy, dy_, in, out, size); +template +void gelu_grad_grad_gpu_cuda( + FPTYPE * out, + const FPTYPE * xx, + const FPTYPE * dy, + const FPTYPE * dy_2, + const int size) +{ + const int THREAD_ITEMS = 1024; + const int BLOCK_NUMS = (size + THREAD_ITEMS - 1) / THREAD_ITEMS; + + gelu_grad_grad<<>>(out, xx, dy, dy_2, size); } -template struct GeluGPUExecuteFunctor; -template struct GeluGPUExecuteFunctor; -template struct GeluGradGPUExecuteFunctor; -template struct GeluGradGPUExecuteFunctor; -template struct GeluGradGradGPUExecuteFunctor; -template struct GeluGradGradGPUExecuteFunctor; \ No newline at end of file +template void gelu_gpu_cuda(float * out, const float * x, const int size); +template void gelu_gpu_cuda(double * out, const double * x, const int size); +template void gelu_grad_gpu_cuda(float * out, const float * x, const float * dy, const int size); +template void gelu_grad_gpu_cuda(double * out, const double * x, const double * dy, const int size); +template void gelu_grad_grad_gpu_cuda(float * out, const float * x, const float * dy, const float * dy_2, const int size); +template void gelu_grad_grad_gpu_cuda(double * out, const double * x, const double * dy, const double * dy_2, const int size); diff --git a/source/lib/src/cuda/prod_env_mat.cu b/source/lib/src/cuda/prod_env_mat.cu new file mode 100644 index 0000000000..4925e12ff3 --- /dev/null +++ b/source/lib/src/cuda/prod_env_mat.cu @@ -0,0 +1,514 @@ +#include "gpu_cuda.h" +#include "prod_env_mat.h" +#include +#include +#include + +// common part of prod_env_mat +template < + typename Key, + int BLOCK_THREADS, + int ITEMS_PER_THREAD> +__launch_bounds__ (BLOCK_THREADS) +__global__ void BlockSortKernel( + Key * d_in, + Key * d_out) // Tile of output +{ + enum { TILE_SIZE = BLOCK_THREADS * ITEMS_PER_THREAD }; + // Specialize BlockLoad type for our thread block (uses warp-striped loads for coalescing, then transposes in shared memory to a blocked arrangement) + typedef cub::BlockLoad BlockLoadT; + // Specialize BlockRadixSort type for our thread block + typedef cub::BlockRadixSort BlockRadixSortT; + // Shared memory + __shared__ union TempStorage + { + typename BlockLoadT::TempStorage load; + typename BlockRadixSortT::TempStorage sort; + } temp_storage; + // Per-thread tile items + Key items[ITEMS_PER_THREAD]; + // Our current block's offset + int block_offset = blockIdx.x * TILE_SIZE; + // Load items into a blocked arrangement + BlockLoadT(temp_storage.load).Load(d_in + block_offset, items); + // Barrier for smem reuse + __syncthreads(); + // Sort keys + BlockRadixSortT(temp_storage.sort).SortBlockedToStriped(items); + // Store output in striped fashion + cub::StoreDirectStriped(threadIdx.x, d_out + block_offset, items); +} + +template +__device__ inline FPTYPE dev_dot( + FPTYPE * arr1, + FPTYPE * arr2) +{ + return arr1[0] * arr2[0] + arr1[1] * arr2[1] + arr1[2] * arr2[2]; +} + +template +__device__ inline void spline5_switch( + FPTYPE & vv, + FPTYPE & dd, + FPTYPE & xx, + const float & rmin, + const float & rmax) +{ + if (xx < rmin) { + dd = 0; + vv = 1; + } + else if (xx < rmax) { + FPTYPE uu = (xx - rmin) / (rmax - rmin) ; + FPTYPE du = 1. / (rmax - rmin) ; + vv = uu*uu*uu * (-6 * uu*uu + 15 * uu - 10) + 1; + dd = ( 3 * uu*uu * (-6 * uu*uu + 15 * uu - 10) + uu*uu*uu * (-12 * uu + 15) ) * du; + } + else { + dd = 0; + vv = 0; + } +} + +template +__global__ void get_i_idx( + FPTYPE * i_idx, + const int nloc, + const FPTYPE * ilist) +{ + const unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x; + if(idx >= nloc) { + return; + } + i_idx[ilist[idx]] = idx; +} + +template +__global__ void format_nlist_fill_a( + int_64 * key, + const FPTYPE * coord, + const int * type, + const int * jrange, + const int * jlist, + const float rcut, + int * i_idx, + const int MAX_NBOR_SIZE) +{ + // <<>> + const unsigned int idx = blockIdx.x; + const unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y; + + const int nsize = jrange[i_idx[idx] + 1] - jrange[i_idx[idx]]; + if (idy >= nsize) { + return; + } + const int * nei_idx = jlist + jrange[i_idx[idx]]; + // dev_copy(nei_idx, &jlist[jrange[i_idx]], nsize); + int_64 * key_in = key + idx * MAX_NBOR_SIZE; + FPTYPE diff[3]; + const int & j_idx = nei_idx[idy]; + for (int dd = 0; dd < 3; dd++) { + diff[dd] = coord[j_idx * 3 + dd] - coord[idx * 3 + dd]; + } + FPTYPE rr = sqrt(dev_dot(diff, diff)); + if (rr <= rcut) { + key_in[idy] = type[j_idx] * 1E15+ (int_64)(rr * 1.0E13) / 100000 * 100000 + j_idx; + } +} + +template +__global__ void format_nlist_fill_b( + int * nlist, + const int nlist_size, + const int nloc, + const int * jrange, + const int * jlist, + FPTYPE * key, + const int * sec, + const int sec_size, + int * nei_iter_dev, + const int max_nbor_size) +{ + const unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x; + if(idx >= nloc) { + return; + } + + int * row_nlist = nlist + idx * nlist_size; + int * nei_iter = nei_iter_dev + idx * sec_size; + FPTYPE * key_out = key + nloc * max_nbor_size + idx * max_nbor_size; + for (int ii = 0; ii < sec_size; ii++) { + nei_iter[ii] = sec[ii]; + } + + for (unsigned int kk = 0; key_out[kk] != key_out[max_nbor_size - 1]; kk++) { + const int & nei_type = key_out[kk] / 1E15; + if (nei_iter[nei_type] < sec[nei_type + 1]) { + row_nlist[nei_iter[nei_type]++] = key_out[kk] % 100000; + } + } +} + +template +void format_nbor_list_1024 ( + int_64 * key, + const FPTYPE* coord, + const int* type, + const int* jrange, + const int* jlist, + const int& nloc, + const float& rcut, + int * i_idx) +{ + const int LEN = 256; + const int MAX_NBOR_SIZE = 1024; + const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; + dim3 block_grid(nloc, nblock); + dim3 thread_grid(1, LEN); + format_nlist_fill_a<<>> ( + key, + coord, type, jrange, jlist, rcut, i_idx, MAX_NBOR_SIZE); + const int ITEMS_PER_THREAD = 8; + const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; + // BlockSortKernel<<>> ( + BlockSortKernel <<>> ( + key, + key + nloc * MAX_NBOR_SIZE); +} + +template +void format_nbor_list_2048 ( + int_64 * key, + const FPTYPE* coord, + const int* type, + const int* jrange, + const int* jlist, + const int& nloc, + const float& rcut, + int * i_idx) +{ + const int LEN = 256; + const int MAX_NBOR_SIZE = 2048; + const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; + dim3 block_grid(nloc, nblock); + dim3 thread_grid(1, LEN); + format_nlist_fill_a<<>> ( + key, + coord, type, jrange, jlist, rcut, i_idx, MAX_NBOR_SIZE); + const int ITEMS_PER_THREAD = 8; + const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; + // BlockSortKernel<<>> ( + BlockSortKernel <<>> ( + key, + key + nloc * MAX_NBOR_SIZE); +} + +template +void format_nbor_list_4096 ( + int_64 * key, + const FPTYPE* coord, + const int* type, + const int* jrange, + const int* jlist, + const int& nloc, + const float& rcut, + int * i_idx) +{ + const int LEN = 256; + const int MAX_NBOR_SIZE = 4096; + const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; + dim3 block_grid(nloc, nblock); + dim3 thread_grid(1, LEN); + format_nlist_fill_a<<>> ( + key, + coord, type, jrange, jlist, rcut, i_idx, MAX_NBOR_SIZE); + const int ITEMS_PER_THREAD = 16; + const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; + // BlockSortKernel<<>> ( + BlockSortKernel <<>> ( + key, + key + nloc * MAX_NBOR_SIZE); +} + +template +void format_nbor_list( + FPTYPE * em, + FPTYPE * em_deriv, + FPTYPE * rij, + int * nlist, + const FPTYPE * coord, + const int * type, + const int * ilist, + const int * jrange, + const int * jlist, + int * array_int, + int_64 * array_longlong, + const int max_nbor_size, + const FPTYPE * avg, + const FPTYPE * std, + const int nloc, + const int nall, + const float rcut, + const float rcut_smth, + const std::vector sec) +{ + const int LEN = 256; + const int nnei = sec.back(); + const int ndescrpt = nnei * 4; + int nblock = (nloc + LEN -1) / LEN; + int * sec_dev = array_int; + int * nei_iter = array_int + sec.size(); // = new int[sec_size]; + int * i_idx = array_int + sec.size() + nloc * sec.size(); + int_64 * key = array_longlong; + assert(max_nbor_size == 1024 || max_nbor_size == 2048 || max_nbor_size == 4096); + cudaErrcheck(cudaMemcpy(sec_dev, &sec[0], sizeof(int) * sec.size(), cudaMemcpyHostToDevice)); + cudaErrcheck(cudaMemset(key, 0xffffffff, sizeof(int_64) * nloc * max_nbor_size)); + cudaErrcheck(cudaMemset(nlist, -1, sizeof(int) * nloc * nnei)); + cudaErrcheck(cudaMemset(em, 0.0, sizeof(FPTYPE) * nloc * ndescrpt)); + cudaErrcheck(cudaMemset(em_deriv, 0.0, sizeof(FPTYPE) * nloc * ndescrpt * 3)); + + get_i_idx<<>>( + i_idx, + nloc, ilist); + + if (max_nbor_size == 1024) { + format_nbor_list_1024 ( + key, + coord, type, jrange, jlist, nloc, rcut, i_idx); + } + else if (max_nbor_size == 2048) { + format_nbor_list_2048 ( + key, + coord, type, jrange, jlist, nloc, rcut, i_idx); + } + else if (max_nbor_size == 4096) { + format_nbor_list_4096 ( + key, + coord, type, jrange, jlist, nloc, rcut, i_idx); + } + + format_nlist_fill_b<<>> ( + nlist, + nnei, nloc, jrange, jlist, key, sec_dev, sec.size(), nei_iter, max_nbor_size); +} + +template< + typename FPTYPE, + int THREADS_PER_BLOCK> +__global__ void compute_env_mat_a( + FPTYPE* em, + FPTYPE* em_deriv, + FPTYPE* rij, + const FPTYPE* coord, + const FPTYPE* avg, + const FPTYPE* std, + const int* type, + const int* nlist, + const int nnei, + const float rmin, + const float rmax) +{ + // <<>> + const unsigned int bid = blockIdx.x; + const unsigned int tid = threadIdx.x; + if (tid >= nnei) { + return; + } + const int ndescrpt = nnei * 4; + const int * row_nlist = nlist + bid * nnei; + FPTYPE * row_rij = rij + bid * nnei * 3; + FPTYPE * row_descript = em + bid * nnei * 4; + FPTYPE * row_descript_deriv = em_deriv + bid * nnei * 12; + for (int ii = tid; ii < nnei; ii += THREADS_PER_BLOCK) { + const int idx_value = ii * 4; // 4 components + const int idx_deriv = ii * 12; // 4 components time 3 directions + if (row_nlist[ii] >= 0) { + FPTYPE rr[3] = {0}; + FPTYPE dd[4] = {0}; + FPTYPE vv[12] = {0}; + const int j_idx = row_nlist[ii]; + for (int kk = 0; kk < 3; kk++) { + rr[kk] = coord[j_idx * 3 + kk] - coord[bid * 3 + kk]; + row_rij[ii * 3 + kk] = rr[kk]; + } + // const FPTYPE * rr = &row_rij[ii * 3]; + FPTYPE nr2 = dev_dot(rr, rr); + FPTYPE inr = 1./sqrt(nr2); + FPTYPE nr = nr2 * inr; + FPTYPE inr2 = inr * inr; + FPTYPE inr4 = inr2 * inr2; + FPTYPE inr3 = inr4 * nr; + FPTYPE sw, dsw; + spline5_switch(sw, dsw, nr, rmin, rmax); + dd[0] = (1./nr) ;//* sw; + dd[1] = (rr[0] / nr2) ;//* sw; + dd[2] = (rr[1] / nr2) ;//* sw; + dd[3] = (rr[2] / nr2) ;//* sw; + vv[0] = (rr[0] * inr3 * sw - dd[0] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 0) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 0) % (ndescrpt * 3)) / 3]; + vv[1] = (rr[1] * inr3 * sw - dd[0] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 1) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 1) % (ndescrpt * 3)) / 3]; + vv[2] = (rr[2] * inr3 * sw - dd[0] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 2) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 2) % (ndescrpt * 3)) / 3]; + // ****deriv of component x/r2 + vv[3] = ((2. * rr[0] * rr[0] * inr4 - inr2) * sw - dd[1] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 3) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 3) % (ndescrpt * 3)) / 3]; + vv[4] = ((2. * rr[0] * rr[1] * inr4 ) * sw - dd[1] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 4) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 4) % (ndescrpt * 3)) / 3]; + vv[5] = ((2. * rr[0] * rr[2] * inr4 ) * sw - dd[1] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 5) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 5) % (ndescrpt * 3)) / 3]; + // ***deriv of component y/r2 + vv[6] = ((2. * rr[1] * rr[0] * inr4 ) * sw - dd[2] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 6) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 6) % (ndescrpt * 3)) / 3]; + vv[7] = ((2. * rr[1] * rr[1] * inr4 - inr2) * sw - dd[2] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 7) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 7) % (ndescrpt * 3)) / 3]; + vv[8] = ((2. * rr[1] * rr[2] * inr4 ) * sw - dd[2] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 8) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 8) % (ndescrpt * 3)) / 3]; + // ***deriv of component z/r2 + vv[9] = ((2. * rr[2] * rr[0] * inr4 ) * sw - dd[3] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 9) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 9) % (ndescrpt * 3)) / 3]; + vv[10]= ((2. * rr[2] * rr[1] * inr4 ) * sw - dd[3] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 10) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 10) % (ndescrpt * 3)) / 3]; + vv[11]= ((2. * rr[2] * rr[2] * inr4 - inr2) * sw - dd[3] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 11) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 11) % (ndescrpt * 3)) / 3]; + // 4 value components + dd[0] *= sw; // * em[idx * ndescrpt + idx_value + 0]);// - avg[type[idx] * ndescrpt + idx_value + 0]) / std[type[idx] * ndescrpt + idx_value + 0]; + dd[1] *= sw; // * em[idx * ndescrpt + idx_value + 1]);// - avg[type[idx] * ndescrpt + idx_value + 1]) / std[type[idx] * ndescrpt + idx_value + 1]; + dd[2] *= sw; // * em[idx * ndescrpt + idx_value + 2]);// - avg[type[idx] * ndescrpt + idx_value + 2]) / std[type[idx] * ndescrpt + idx_value + 2]; + dd[3] *= sw; // * em[idx * ndescrpt + idx_value + 3]);// - avg[type[idx] * ndescrpt + idx_value + 3]) / std[type[idx] * ndescrpt + idx_value + 3]; + for (int ii = 0; ii < 12; ii++) { + row_descript_deriv[idx_deriv + ii] = vv[ii] / std[type[bid] * ndescrpt + idx_value + ii / 3]; + } + for (int ii = 0; ii < 4; ii++) { + row_descript[idx_value + ii] = (dd[ii] - avg[type[bid] * ndescrpt + idx_value + ii]) / std[type[bid] * ndescrpt + idx_value + ii]; + } + } + else { + // TODO: move it to the memset. + row_descript[idx_value] -= avg[type[bid] * ndescrpt + idx_value] / std[type[bid] * ndescrpt + idx_value]; + } + } +} + +template< + typename FPTYPE, + int THREADS_PER_BLOCK> +__global__ void compute_env_mat_r( + FPTYPE* em, + FPTYPE* em_deriv, + FPTYPE* rij, + const FPTYPE* coord, + const FPTYPE* avg, + const FPTYPE* std, + const int* type, + const int* nlist, + const int nnei, + const float rmin, + const float rmax) +{ + // <<>> + const unsigned int bid = blockIdx.x; + const unsigned int tid = threadIdx.x; + if (tid >= nnei) { + return; + } + const int ndescrpt = nnei; + const int * row_nlist = nlist + bid * nnei; + FPTYPE * row_rij = rij + bid * nnei * 3; + FPTYPE * row_em = em + bid * nnei; + FPTYPE * row_em_deriv = em_deriv + bid * nnei * 3; + for (int ii = tid; ii < nnei; ii += THREADS_PER_BLOCK) { + const int idx_value = ii; // 4 components + const int idx_deriv = ii * 3; // 4 components time 3 directions + if (row_nlist[ii] >= 0) { + FPTYPE rr[3] = {0}; + FPTYPE vv[3] = {0}; + FPTYPE dd = 0; + const int & j_idx = row_nlist[ii]; + for (int kk = 0; kk < 3; kk++) { + rr[kk] = coord[j_idx * 3 + kk] - coord[bid * 3 + kk]; + row_rij[ii * 3 + kk] = rr[kk]; + } + // const FPTYPE * rr = &row_rij[ii * 3]; + FPTYPE nr2 = dev_dot(rr, rr); + FPTYPE inr = 1./sqrt(nr2); + FPTYPE nr = nr2 * inr; + FPTYPE inr2 = inr * inr; + FPTYPE inr4 = inr2 * inr2; + FPTYPE inr3 = inr4 * nr; + FPTYPE sw, dsw; + spline5_switch(sw, dsw, nr, rmin, rmax); + dd = (1./nr) ;//* sw; + vv[0] = (rr[0] * inr3 * sw - dd * dsw * rr[0] * inr); // avg[type[(idx_deriv + 0) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 0) % (ndescrpt * 3)) / 3]; + vv[1] = (rr[1] * inr3 * sw - dd * dsw * rr[1] * inr); // avg[type[(idx_deriv + 1) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 1) % (ndescrpt * 3)) / 3]; + vv[2] = (rr[2] * inr3 * sw - dd * dsw * rr[2] * inr); // avg[type[(idx_deriv + 2) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 2) % (ndescrpt * 3)) / 3]; + + // 4 value components + dd *= sw; // * em[idx * ndescrpt + idx_value + 0]);// - avg[type[idx] * ndescrpt + idx_value + 0]) / std[type[idx] * ndescrpt + idx_value + 0]; + for (int ii = 0; ii < 3; ii++) { + row_em_deriv[idx_deriv + ii] = vv[ii] / std[type[bid] * ndescrpt + idx_value + ii / 3]; + } + row_em[idx_value] = (dd - avg[type[bid] * ndescrpt + idx_value]) / std[type[bid] * ndescrpt + idx_value]; + } + else { + // TODO: move it to the memset. + row_em[idx_value] -= avg[type[bid] * ndescrpt + idx_value] / std[type[bid] * ndescrpt + idx_value]; + } + } +} + +template +void prod_env_mat_a_gpu_cuda( + FPTYPE * em, + FPTYPE * em_deriv, + FPTYPE * rij, + int * nlist, + const FPTYPE * coord, + const int * type, + const int * ilist, + const int * jrange, + const int * jlist, + int * array_int, + int_64 * array_longlong, + const int max_nbor_size, + const FPTYPE * avg, + const FPTYPE * std, + const int nloc, + const int nall, + const float rcut, + const float rcut_smth, + const std::vector sec) +{ + format_nbor_list( + em, em_deriv, rij, nlist, + coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); + + compute_env_mat_a <<>> ( + em, em_deriv, rij, + coord, avg, std, type, nlist, sec.back(), rcut_smth, rcut); +} + +template +void prod_env_mat_r_gpu_cuda( + FPTYPE * em, + FPTYPE * em_deriv, + FPTYPE * rij, + int * nlist, + const FPTYPE * coord, + const int * type, + const int * ilist, + const int * jrange, + const int * jlist, + int * array_int, + int_64 * array_longlong, + const int max_nbor_size, + const FPTYPE * avg, + const FPTYPE * std, + const int nloc, + const int nall, + const float rcut, + const float rcut_smth, + const std::vector sec) +{ + format_nbor_list( + em, em_deriv, rij, nlist, + coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); + + compute_env_mat_r <<>> ( + em, em_deriv, rij, + coord, avg, std, type, nlist, sec.back(), rcut_smth, rcut); +} + +template void prod_env_mat_a_gpu_cuda(float * em, float * em_deriv, float * rij, int * nlist, const float * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const float * avg, const float * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); +template void prod_env_mat_a_gpu_cuda(double * em, double * em_deriv, double * rij, int * nlist, const double * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const double * avg, const double * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); +template void prod_env_mat_r_gpu_cuda(float * em, float * em_deriv, float * rij, int * nlist, const float * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const float * avg, const float * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); +template void prod_env_mat_r_gpu_cuda(double * em, double * em_deriv, double * rij, int * nlist, const double * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const double * avg, const double * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); diff --git a/source/lib/src/cuda/prod_env_mat_a.cu b/source/lib/src/cuda/prod_env_mat_a.cu deleted file mode 100644 index 2702b30f9f..0000000000 --- a/source/lib/src/cuda/prod_env_mat_a.cu +++ /dev/null @@ -1,122 +0,0 @@ -#include "prod_env_mat.h" -#include "gpu_nv.cuh" - -template< - typename FPTYPE, - int THREADS_PER_BLOCK> -__global__ void compute_em_mat_a( - FPTYPE* em, - FPTYPE* em_deriv, - FPTYPE* rij, - const FPTYPE* coord, - const FPTYPE* avg, - const FPTYPE* std, - const int* type, - const int* nlist, - const int nnei, - const float rmin, - const float rmax) -{ - // <<>> - const unsigned int bid = blockIdx.x; - const unsigned int tid = threadIdx.x; - if (tid >= nnei) { - return; - } - const int ndescrpt = nnei * 4; - const int * row_nlist = nlist + bid * nnei; - FPTYPE * row_rij = rij + bid * nnei * 3; - FPTYPE * row_descript = em + bid * nnei * 4; - FPTYPE * row_descript_deriv = em_deriv + bid * nnei * 12; - for (int ii = tid; ii < nnei; ii += THREADS_PER_BLOCK) { - const int idx_value = ii * 4; // 4 components - const int idx_deriv = ii * 12; // 4 components time 3 directions - if (row_nlist[ii] >= 0) { - FPTYPE rr[3] = {0}; - FPTYPE dd[4] = {0}; - FPTYPE vv[12] = {0}; - const int j_idx = row_nlist[ii]; - for (int kk = 0; kk < 3; kk++) { - rr[kk] = coord[j_idx * 3 + kk] - coord[bid * 3 + kk]; - row_rij[ii * 3 + kk] = rr[kk]; - } - // const FPTYPE * rr = &row_rij[ii * 3]; - FPTYPE nr2 = dev_dot(rr, rr); - FPTYPE inr = 1./sqrt(nr2); - FPTYPE nr = nr2 * inr; - FPTYPE inr2 = inr * inr; - FPTYPE inr4 = inr2 * inr2; - FPTYPE inr3 = inr4 * nr; - FPTYPE sw, dsw; - spline5_switch(sw, dsw, nr, rmin, rmax); - dd[0] = (1./nr) ;//* sw; - dd[1] = (rr[0] / nr2) ;//* sw; - dd[2] = (rr[1] / nr2) ;//* sw; - dd[3] = (rr[2] / nr2) ;//* sw; - vv[0] = (rr[0] * inr3 * sw - dd[0] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 0) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 0) % (ndescrpt * 3)) / 3]; - vv[1] = (rr[1] * inr3 * sw - dd[0] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 1) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 1) % (ndescrpt * 3)) / 3]; - vv[2] = (rr[2] * inr3 * sw - dd[0] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 2) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 2) % (ndescrpt * 3)) / 3]; - // ****deriv of component x/r2 - vv[3] = ((2. * rr[0] * rr[0] * inr4 - inr2) * sw - dd[1] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 3) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 3) % (ndescrpt * 3)) / 3]; - vv[4] = ((2. * rr[0] * rr[1] * inr4 ) * sw - dd[1] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 4) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 4) % (ndescrpt * 3)) / 3]; - vv[5] = ((2. * rr[0] * rr[2] * inr4 ) * sw - dd[1] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 5) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 5) % (ndescrpt * 3)) / 3]; - // ***deriv of component y/r2 - vv[6] = ((2. * rr[1] * rr[0] * inr4 ) * sw - dd[2] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 6) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 6) % (ndescrpt * 3)) / 3]; - vv[7] = ((2. * rr[1] * rr[1] * inr4 - inr2) * sw - dd[2] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 7) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 7) % (ndescrpt * 3)) / 3]; - vv[8] = ((2. * rr[1] * rr[2] * inr4 ) * sw - dd[2] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 8) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 8) % (ndescrpt * 3)) / 3]; - // ***deriv of component z/r2 - vv[9] = ((2. * rr[2] * rr[0] * inr4 ) * sw - dd[3] * dsw * rr[0] * inr); // avg[type[(idx_deriv + 9) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 9) % (ndescrpt * 3)) / 3]; - vv[10]= ((2. * rr[2] * rr[1] * inr4 ) * sw - dd[3] * dsw * rr[1] * inr); // avg[type[(idx_deriv + 10) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 10) % (ndescrpt * 3)) / 3]; - vv[11]= ((2. * rr[2] * rr[2] * inr4 - inr2) * sw - dd[3] * dsw * rr[2] * inr); // avg[type[(idx_deriv + 11) / (ndescrpt * 3)] * ndescrpt + ((idx_deriv + 11) % (ndescrpt * 3)) / 3]; - // 4 value components - dd[0] *= sw; // * em[idx * ndescrpt + idx_value + 0]);// - avg[type[idx] * ndescrpt + idx_value + 0]) / std[type[idx] * ndescrpt + idx_value + 0]; - dd[1] *= sw; // * em[idx * ndescrpt + idx_value + 1]);// - avg[type[idx] * ndescrpt + idx_value + 1]) / std[type[idx] * ndescrpt + idx_value + 1]; - dd[2] *= sw; // * em[idx * ndescrpt + idx_value + 2]);// - avg[type[idx] * ndescrpt + idx_value + 2]) / std[type[idx] * ndescrpt + idx_value + 2]; - dd[3] *= sw; // * em[idx * ndescrpt + idx_value + 3]);// - avg[type[idx] * ndescrpt + idx_value + 3]) / std[type[idx] * ndescrpt + idx_value + 3]; - for (int ii = 0; ii < 12; ii++) { - row_descript_deriv[idx_deriv + ii] = vv[ii] / std[type[bid] * ndescrpt + idx_value + ii / 3]; - } - for (int ii = 0; ii < 4; ii++) { - row_descript[idx_value + ii] = (dd[ii] - avg[type[bid] * ndescrpt + idx_value + ii]) / std[type[bid] * ndescrpt + idx_value + ii]; - } - } - else { - // TODO: move it to the memset. - row_descript[idx_value] -= avg[type[bid] * ndescrpt + idx_value] / std[type[bid] * ndescrpt + idx_value]; - } - } -} - -template -void prod_env_mat_a_gpu_nv( - FPTYPE * em, - FPTYPE * em_deriv, - FPTYPE * rij, - int * nlist, - const FPTYPE * coord, - const int * type, - const int * ilist, - const int * jrange, - const int * jlist, - int * array_int, - int_64 * array_longlong, - const int max_nbor_size, - const FPTYPE * avg, - const FPTYPE * std, - const int nloc, - const int nall, - const float rcut, - const float rcut_smth, - const std::vector sec) -{ - prod_env_mat_common( - em, em_deriv, rij, nlist, - coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); - - compute_em_mat_a <<>> ( - em, em_deriv, rij, - coord, avg, std, type, nlist, sec.back(), rcut_smth, rcut); -} - -template void prod_env_mat_a_gpu_nv(float * em, float * em_deriv, float * rij, int * nlist, const float * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const float * avg, const float * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); -template void prod_env_mat_a_gpu_nv(double * em, double * em_deriv, double * rij, int * nlist, const double * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const double * avg, const double * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); \ No newline at end of file diff --git a/source/lib/src/cuda/prod_force.cu b/source/lib/src/cuda/prod_force.cu new file mode 100644 index 0000000000..c5fe49b99b --- /dev/null +++ b/source/lib/src/cuda/prod_force.cu @@ -0,0 +1,171 @@ +#include "device.h" +#include "gpu_cuda.h" +#include "prod_force.h" + +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600 +static __inline__ __device__ double atomicAdd(double* address, double val) { + unsigned long long int* address_as_ull = (unsigned long long int*)address; + unsigned long long int old = *address_as_ull, assumed; + do { + assumed = old; + old = atomicCAS(address_as_ull, assumed, + __double_as_longlong(val + __longlong_as_double(assumed))); + // Note: uses integer comparison to avoid hang in case of NaN (since NaN != NaN) } while (assumed != old); + } while (assumed != old); + return __longlong_as_double(old); +} +#endif + +template < + typename FPTYPE, + int THREADS_PER_BLOCK> +__global__ void force_deriv_wrt_center_atom( + FPTYPE * force, + const FPTYPE * net_deriv, + const FPTYPE * in_deriv, + const int ndescrpt) +{ + __shared__ FPTYPE data[THREADS_PER_BLOCK * 3]; + unsigned int bid = blockIdx.x; + unsigned int tid = threadIdx.x; + for (int ii = tid; ii < THREADS_PER_BLOCK * 3; ii += THREADS_PER_BLOCK) { + data[ii] = 0.f; + } + for (int ii = tid; ii < ndescrpt; ii += THREADS_PER_BLOCK) { + for (int jj = 0; jj < 3; jj++) { + data[jj * THREADS_PER_BLOCK + tid] += net_deriv[bid * ndescrpt + ii] * in_deriv[bid * ndescrpt * 3 + ii * 3 + jj]; + } + } + __syncthreads(); + // do reduction in shared memory + for (int ii = THREADS_PER_BLOCK >> 1; ii > 0; ii >>= 1) { + if (tid < ii) { + for (int jj = 0; jj < 3; jj++) { + data[jj * THREADS_PER_BLOCK + tid] += data[jj * THREADS_PER_BLOCK + tid + ii]; + } + } + __syncthreads(); + } + // write result for this block to global memory + if (tid == 0) { + force[bid * 3 + 0] -= data[THREADS_PER_BLOCK * 0]; + force[bid * 3 + 1] -= data[THREADS_PER_BLOCK * 1]; + force[bid * 3 + 2] -= data[THREADS_PER_BLOCK * 2]; + } +} + +template +__global__ void force_deriv_wrt_neighbors_a( + FPTYPE * force, + const FPTYPE * net_deriv, + const FPTYPE * in_deriv, + const int * nlist, + const int nloc, + const int nnei) +{ + // idy -> nnei + const unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x; + const unsigned int idy = blockIdx.y; + const unsigned int idz = threadIdx.y; + const unsigned int idw = threadIdx.z; + const int ndescrpt = nnei * 4; + if (idx >= nloc) { + return; + } + // deriv wrt neighbors + int j_idx = nlist[idx * nnei + idy]; + if (j_idx < 0) { + return; + } + atomicAdd( + force + j_idx * 3 + idz, + net_deriv[idx * ndescrpt + idy * 4 + idw] * in_deriv[idx * ndescrpt * 3 + (idy * 4 + idw) * 3 + idz]); +} + +template +__global__ void force_deriv_wrt_neighbors_r( + FPTYPE * force, + const FPTYPE * net_deriv, + const FPTYPE * in_deriv, + const int * nlist, + const int nloc, + const int nnei) +{ + // idy -> nnei + const unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x; + const unsigned int idy = blockIdx.y; + const unsigned int idz = threadIdx.y; + const int ndescrpt = nnei * 1; + if (idx >= nloc) { + return; + } + // deriv wrt neighbors + int j_idx = nlist[idx * nnei + idy]; + if (j_idx < 0) { + return; + } + atomicAdd( + force + j_idx * 3 + idz, + net_deriv[idx * ndescrpt + idy] * in_deriv[idx * ndescrpt * 3 + idy * 3 + idz]); +} + +template +void prod_force_a_gpu_cuda( + FPTYPE * force, + const FPTYPE * net_deriv, + const FPTYPE * in_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei) +{ + const int ndescrpt = nnei * 4; + cudaErrcheck(cudaMemset( + force, + 0.0, sizeof(FPTYPE) * nall * 3)); + + force_deriv_wrt_center_atom <<>>( + force, + net_deriv, in_deriv, ndescrpt); + + const int LEN = 64; + const int nblock = (nloc + LEN -1) / LEN; + dim3 block_grid(nblock, nnei); + dim3 thread_grid(LEN, 3, 4); + force_deriv_wrt_neighbors_a<<>>( + force, + net_deriv, in_deriv, nlist, nloc, nnei); +} + +template +void prod_force_r_gpu_cuda( + FPTYPE * force, + const FPTYPE * net_deriv, + const FPTYPE * in_deriv, + const int * nlist, + const int nloc, + const int nall, + const int nnei) +{ + const int ndescrpt = nnei * 1; + cudaErrcheck(cudaMemset( + force, + 0.0, sizeof(FPTYPE) * nall * 3)); + + force_deriv_wrt_center_atom <<>>( + force, + net_deriv, in_deriv, ndescrpt); + + const int LEN = 64; + const int nblock = (nloc + LEN -1) / LEN; + dim3 block_grid(nblock, nnei); + dim3 thread_grid(LEN, 3, 4); + force_deriv_wrt_neighbors_r<<>>( + force, + net_deriv, in_deriv, nlist, nloc, nnei); +} + +template void prod_force_a_gpu_cuda(float * force, const float * net_deriv, const float * in_deriv, const int * nlist, const int nloc, const int nall, const int nnei); +template void prod_force_a_gpu_cuda(double * force, const double * net_deriv, const double * in_deriv, const int * nlist, const int nloc, const int nall, const int nnei); +template void prod_force_r_gpu_cuda(float * force, const float * net_deriv, const float * in_deriv, const int * nlist, const int nloc, const int nall, const int nnei); +template void prod_force_r_gpu_cuda(double * force, const double * net_deriv, const double * in_deriv, const int * nlist, const int nloc, const int nall, const int nnei); diff --git a/source/lib/src/cuda/prod_force_se_a.cu b/source/lib/src/cuda/prod_force_se_a.cu deleted file mode 100644 index ede315e167..0000000000 --- a/source/lib/src/cuda/prod_force_se_a.cu +++ /dev/null @@ -1,106 +0,0 @@ -#include "DeviceFunctor.h" -#include "gpu_nv.h" - -#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600 -static __inline__ __device__ double atomicAdd(double* address, double val) { - unsigned long long int* address_as_ull = (unsigned long long int*)address; - unsigned long long int old = *address_as_ull, assumed; - do { - assumed = old; - old = atomicCAS(address_as_ull, assumed, - __double_as_longlong(val + __longlong_as_double(assumed))); - // Note: uses integer comparison to avoid hang in case of NaN (since NaN != NaN) } while (assumed != old); - } while (assumed != old); - return __longlong_as_double(old); -} -#endif - -template < - typename FPTYPE, - int THREADS_PER_BLOCK> -__global__ void force_deriv_wrt_center_atom_se_a(FPTYPE * force, const FPTYPE * net_deriv, const FPTYPE * in_deriv, const int ndescrpt) -{ - __shared__ FPTYPE data[THREADS_PER_BLOCK * 3]; - unsigned int bid = blockIdx.x; - unsigned int tid = threadIdx.x; - for (int ii = tid; ii < THREADS_PER_BLOCK * 3; ii += THREADS_PER_BLOCK) { - data[ii] = 0.f; - } - - for (int ii = tid; ii < ndescrpt; ii += THREADS_PER_BLOCK) { - for (int jj = 0; jj < 3; jj++) { - data[jj * THREADS_PER_BLOCK + tid] += net_deriv[bid * ndescrpt + ii] * in_deriv[bid * ndescrpt * 3 + ii * 3 + jj]; - } - } - __syncthreads(); - - // do reduction in shared memory - for (int ii = THREADS_PER_BLOCK >> 1; ii > 0; ii >>= 1) { - if (tid < ii) { - for (int jj = 0; jj < 3; jj++) { - data[jj * THREADS_PER_BLOCK + tid] += data[jj * THREADS_PER_BLOCK + tid + ii]; - } - } - __syncthreads(); - } - // write result for this block to global memory - if (tid == 0) { - force[bid * 3 + 0] -= data[THREADS_PER_BLOCK * 0]; - force[bid * 3 + 1] -= data[THREADS_PER_BLOCK * 1]; - force[bid * 3 + 2] -= data[THREADS_PER_BLOCK * 2]; - } -} - -template -__global__ void force_deriv_wrt_neighbors_se_a(FPTYPE * force, - const FPTYPE * net_deriv, - const FPTYPE * in_deriv, - const int * nlist, - const int nloc, - const int nnei, - const int ndescrpt, - const int n_a_sel, - const int n_a_shift) -{ - // idy -> nnei - const unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x; - const unsigned int idy = blockIdx.y; - const unsigned int idz = threadIdx.y; - const unsigned int idw = threadIdx.z; - - if (idx >= nloc) { - return; - } - // deriv wrt neighbors - int j_idx = nlist[idx * nnei + idy]; - if (j_idx < 0) { - return; - } - atomicAdd(force + j_idx * 3 + idz, net_deriv[idx * ndescrpt + idy * 4 + idw] * in_deriv[idx * ndescrpt * 3 + (idy * 4 + idw) * 3 + idz]); -} - -template -void ProdForceSeAGPUExecuteFunctor::operator()(FPTYPE * force, - const FPTYPE * net_deriv, - const FPTYPE * in_deriv, - const int * nlist, - const int nloc, - const int nall, - const int nnei, - const int ndescrpt, - const int n_a_sel, - const int n_a_shift) -{ - // std::cout << "I'm here!" << std::endl; - cudaErrcheck(cudaMemset(force, 0.0, sizeof(FPTYPE) * nall * 3)); - force_deriv_wrt_center_atom_se_a <<>>(force, net_deriv, in_deriv, ndescrpt); - - const int LEN = 64; - int nblock = (nloc + LEN -1) / LEN; - dim3 block_grid(nblock, nnei); - dim3 thread_grid(LEN, 3, 4); - force_deriv_wrt_neighbors_se_a<<>>(force, net_deriv, in_deriv, nlist, nloc, nnei, ndescrpt, n_a_sel, n_a_shift); -} - -template struct ProdForceSeAGPUExecuteFunctor; -template struct ProdForceSeAGPUExecuteFunctor; \ No newline at end of file diff --git a/source/lib/src/cuda/prod_force_se_r.cu b/source/lib/src/cuda/prod_force_se_r.cu deleted file mode 100644 index 7fcd0679f0..0000000000 --- a/source/lib/src/cuda/prod_force_se_r.cu +++ /dev/null @@ -1,101 +0,0 @@ -#include "DeviceFunctor.h" -#include "gpu_nv.h" - -#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600 -static __inline__ __device__ double atomicAdd(double* address, double val) { - unsigned long long int* address_as_ull = (unsigned long long int*)address; - unsigned long long int old = *address_as_ull, assumed; - do { - assumed = old; - old = atomicCAS(address_as_ull, assumed, - __double_as_longlong(val + __longlong_as_double(assumed))); - // Note: uses integer comparison to avoid hang in case of NaN (since NaN != NaN) } while (assumed != old); - } while (assumed != old); - return __longlong_as_double(old); -} -#endif - -template < - typename FPTYPE, - int THREADS_PER_BLOCK> -__global__ void force_deriv_wrt_center_atom_se_r(FPTYPE * force, const FPTYPE * net_deriv, const FPTYPE * in_deriv, const int ndescrpt) -{ - __shared__ FPTYPE data[THREADS_PER_BLOCK * 3]; - unsigned int bid = blockIdx.x; - unsigned int tid = threadIdx.x; - for (int ii = tid; ii < THREADS_PER_BLOCK * 3; ii += THREADS_PER_BLOCK) { - data[ii] = 0.f; - } - - for (int ii = tid; ii < ndescrpt; ii += THREADS_PER_BLOCK) { - for (int jj = 0; jj < 3; jj++) { - data[jj * THREADS_PER_BLOCK + tid] += net_deriv[bid * ndescrpt + ii] * in_deriv[bid * ndescrpt * 3 + ii * 3 + jj]; - } - } - __syncthreads(); - - // do reduction in shared memory - for (int ii = THREADS_PER_BLOCK >> 1; ii > 0; ii >>= 1) { - if (tid < ii) { - for (int jj = 0; jj < 3; jj++) { - data[jj * THREADS_PER_BLOCK + tid] += data[jj * THREADS_PER_BLOCK + tid + ii]; - } - } - __syncthreads(); - } - // write result for this block to global memory - if (tid == 0) { - force[bid * 3 + 0] -= data[THREADS_PER_BLOCK * 0]; - force[bid * 3 + 1] -= data[THREADS_PER_BLOCK * 1]; - force[bid * 3 + 2] -= data[THREADS_PER_BLOCK * 2]; - } -} - -template -__global__ void force_deriv_wrt_neighbors_se_r(FPTYPE * force, - const FPTYPE * net_deriv, - const FPTYPE * in_deriv, - const int * nlist, - const int nloc, - const int nnei, - const int ndescrpt) -{ - // idy -> nnei - const unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x; - const unsigned int idy = blockIdx.y; - const unsigned int idz = threadIdx.y; - - if (idx >= nloc) { - return; - } - // deriv wrt neighbors - int j_idx = nlist[idx * nnei + idy]; - if (j_idx < 0) { - return; - } - atomicAdd(force + j_idx * 3 + idz, net_deriv[idx * ndescrpt + idy] * in_deriv[idx * ndescrpt * 3 + idy * 3 + idz]); -} - -template -void ProdForceSeRGPUExecuteFunctor::operator()(FPTYPE * force, - const FPTYPE * net_deriv, - const FPTYPE * in_deriv, - const int * nlist, - const int nloc, - const int nall, - const int nnei, - const int ndescrpt) -{ - // std::cout << "I'm here!" << std::endl; - cudaErrcheck(cudaMemset(force, 0.0, sizeof(FPTYPE) * nall * 3)); - force_deriv_wrt_center_atom_se_r <<>>(force, net_deriv, in_deriv, ndescrpt); - - const int LEN = 64; - int nblock = (nloc + LEN -1) / LEN; - dim3 block_grid(nblock, nnei); - dim3 thread_grid(LEN, 3); - force_deriv_wrt_neighbors_se_r<<>>(force, net_deriv, in_deriv, nlist, nloc, nnei, ndescrpt); -} - -template struct ProdForceSeRGPUExecuteFunctor; -template struct ProdForceSeRGPUExecuteFunctor; \ No newline at end of file diff --git a/source/lib/src/cuda/prod_virial.cu b/source/lib/src/cuda/prod_virial.cu new file mode 100644 index 0000000000..cdecad83c9 --- /dev/null +++ b/source/lib/src/cuda/prod_virial.cu @@ -0,0 +1,151 @@ +#include "gpu_cuda.h" +#include "prod_virial.h" + +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600 +static __inline__ __device__ double atomicAdd(double* address, double val) { + unsigned long long int* address_as_ull = (unsigned long long int*)address; + unsigned long long int old = *address_as_ull, assumed; + do { + assumed = old; + old = atomicCAS(address_as_ull, assumed, + __double_as_longlong(val + __longlong_as_double(assumed))); + // Note: uses integer comparison to avoid hang in case of NaN (since NaN != NaN) } while (assumed != old); + } while (assumed != old); + return __longlong_as_double(old); +} +#endif + +template +__global__ void virial_deriv_wrt_neighbors_a( + FPTYPE * virial, + FPTYPE * atom_virial, + const FPTYPE * net_deriv, + const FPTYPE * in_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nnei) +{ + // idx -> nloc + // idy -> nnei + // idz = dd0 * 3 + dd1 + // dd0 = idz / 3 + // dd1 = idz % 3 + const unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x; + const unsigned int idy = blockIdx.y; + const unsigned int idz = threadIdx.y; + const unsigned int idw = threadIdx.z; + const int ndescrpt = nnei * 4; + if (idx >= nloc) { + return; + } + int j_idx = nlist[idx * nnei + idy]; + if (j_idx < 0) { + return; + } + // atomicAdd( + // virial + idz, + // net_deriv[idx * ndescrpt + idy * 4 + idw] * rij[idx * nnei * 3 + idy * 3 + idz / 3] * in_deriv[idx * ndescrpt * 3 + (idy * 4 + idw) * 3 + idz % 3]); + atomicAdd( + atom_virial + j_idx * 9 + idz, + net_deriv[idx * ndescrpt + idy * 4 + idw] * rij[idx * nnei * 3 + idy * 3 + idz % 3] * in_deriv[idx * ndescrpt * 3 + (idy * 4 + idw) * 3 + idz / 3]); +} + +template +__global__ void virial_deriv_wrt_neighbors_r( + FPTYPE * virial, + FPTYPE * atom_virial, + const FPTYPE * net_deriv, + const FPTYPE * in_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nnei) +{ + // idx -> nloc + // idy -> nnei + // idz = dd0 * 3 + dd1 + // dd0 = idz / 3 + // dd1 = idz % 3 + const unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x; + const unsigned int idy = blockIdx.y; + const unsigned int idz = threadIdx.y; + const int ndescrpt = nnei * 1; + + if (idx >= nloc) { + return; + } + int j_idx = nlist[idx * nnei + idy]; + if (j_idx < 0) { + return; + } + // atomicAdd( + // virial + idz, + // net_deriv[idx * ndescrpt + idy * 4 + idw] * rij[idx * nnei * 3 + idy * 3 + idz / 3] * in_deriv[idx * ndescrpt * 3 + (idy * 4 + idw) * 3 + idz % 3]); + atomicAdd( + atom_virial + j_idx * 9 + idz, + net_deriv[idx * ndescrpt + idy] * rij[idx * nnei * 3 + idy * 3 + idz % 3] * in_deriv[idx * ndescrpt * 3 + idy * 3 + idz / 3]); +} + +template +void prod_virial_a_gpu_cuda( + FPTYPE * virial, + FPTYPE * atom_virial, + const FPTYPE * net_deriv, + const FPTYPE * in_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nall, + const int nnei) +{ + cudaErrcheck(cudaMemset( + virial, + 0.0, sizeof(FPTYPE) * 9)); + cudaErrcheck(cudaMemset( + atom_virial, + 0.0, sizeof(FPTYPE) * 9 * nall)); + + const int LEN = 16; + int nblock = (nloc + LEN -1) / LEN; + dim3 block_grid(nblock, nnei); + dim3 thread_grid(LEN, 9, 4); + // compute virial of a frame + virial_deriv_wrt_neighbors_a<<>>( + virial, atom_virial, + net_deriv, in_deriv, rij, nlist, nloc, nnei); +} + +template +void prod_virial_r_gpu_cuda( + FPTYPE * virial, + FPTYPE * atom_virial, + const FPTYPE * net_deriv, + const FPTYPE * in_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nall, + const int nnei) +{ + cudaErrcheck(cudaMemset( + virial, + 0.0, sizeof(FPTYPE) * 9)); + cudaErrcheck(cudaMemset( + atom_virial, + 0.0, sizeof(FPTYPE) * 9 * nall)); + + const int LEN = 16; + int nblock = (nloc + LEN -1) / LEN; + dim3 block_grid(nblock, nnei); + dim3 thread_grid(LEN, 9, 4); + // compute virial of a frame + virial_deriv_wrt_neighbors_r<<>>( + virial, atom_virial, + net_deriv, in_deriv, rij, nlist, nloc, nnei); +} + +template void prod_virial_a_gpu_cuda(float * virial, float * atom_virial, const float * net_deriv, const float * in_deriv, const float * rij, const int * nlist, const int nloc, const int nall, const int nnei); +template void prod_virial_a_gpu_cuda(double * virial, double * atom_virial, const double * net_deriv, const double * in_deriv, const double * rij, const int * nlist, const int nloc, const int nall, const int nnei); +template void prod_virial_r_gpu_cuda(float * virial, float * atom_virial, const float * net_deriv, const float * in_deriv, const float * rij, const int * nlist, const int nloc, const int nall, const int nnei); +template void prod_virial_r_gpu_cuda(double * virial, double * atom_virial, const double * net_deriv, const double * in_deriv, const double * rij, const int * nlist, const int nloc, const int nall, const int nnei); diff --git a/source/lib/src/cuda/prod_virial_se_a.cu b/source/lib/src/cuda/prod_virial_se_a.cu deleted file mode 100644 index ff61e3af36..0000000000 --- a/source/lib/src/cuda/prod_virial_se_a.cu +++ /dev/null @@ -1,90 +0,0 @@ -#include "DeviceFunctor.h" -#include "gpu_nv.h" - -#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600 -static __inline__ __device__ double atomicAdd(double* address, double val) { - unsigned long long int* address_as_ull = (unsigned long long int*)address; - unsigned long long int old = *address_as_ull, assumed; - do { - assumed = old; - old = atomicCAS(address_as_ull, assumed, - __double_as_longlong(val + __longlong_as_double(assumed))); - // Note: uses integer comparison to avoid hang in case of NaN (since NaN != NaN) } while (assumed != old); - } while (assumed != old); - return __longlong_as_double(old); -} -#endif - -template -__global__ void deriv_wrt_neighbors_se_a(FPTYPE * virial, - FPTYPE * atom_virial, - const FPTYPE * net_deriv, - const FPTYPE * in_deriv, - const FPTYPE * rij, - const int * nlist, - const int nloc, - const int nnei, - const int ndescrpt, - const int n_a_sel, - const int n_a_shift) -{ - // idx -> nloc - // idy -> nnei - // idz = dd0 * 3 + dd1 - // dd0 = idz / 3 - // dd1 = idz % 3 - const unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x; - const unsigned int idy = blockIdx.y; - const unsigned int idz = threadIdx.y; - const unsigned int idw = threadIdx.z; - - if (idx >= nloc) { - return; - } - int j_idx = nlist[idx * nnei + idy]; - if (j_idx < 0) { - return; - } - // atomicAdd(virial + idz, net_deriv[idx * ndescrpt + idy * 4 + idw] * rij[idx * nnei * 3 + idy * 3 + idz / 3] * in_deriv[idx * ndescrpt * 3 + (idy * 4 + idw) * 3 + idz % 3]); - atomicAdd(atom_virial + j_idx * 9 + idz, net_deriv[idx * ndescrpt + idy * 4 + idw] * rij[idx * nnei * 3 + idy * 3 + idz % 3] * in_deriv[idx * ndescrpt * 3 + (idy * 4 + idw) * 3 + idz / 3]); -} - -template -void ProdVirialSeAGPUExecuteFunctor::operator()(FPTYPE * virial, - FPTYPE * atom_virial, - const FPTYPE * net_deriv, - const FPTYPE * in_deriv, - const FPTYPE * rij, - const int * nlist, - const int nloc, - const int nall, - const int nnei, - const int ndescrpt, - const int n_a_sel, - const int n_a_shift) -{ - cudaErrcheck(cudaMemset(virial, 0.0, sizeof(FPTYPE) * 9)); - cudaErrcheck(cudaMemset(atom_virial, 0.0, sizeof(FPTYPE) * 9 * nall)); - - const int LEN = 16; - int nblock = (nloc + LEN -1) / LEN; - dim3 block_grid(nblock, nnei); - dim3 thread_grid(LEN, 9, 4); - // compute virial of a frame - deriv_wrt_neighbors_se_a<<>>( - virial, - atom_virial, - net_deriv, - in_deriv, - rij, - nlist, - nloc, - nnei, - ndescrpt, - n_a_sel, - n_a_shift - ); -} - -template struct ProdVirialSeAGPUExecuteFunctor; -template struct ProdVirialSeAGPUExecuteFunctor; \ No newline at end of file diff --git a/source/lib/src/cuda/prod_virial_se_r.cu b/source/lib/src/cuda/prod_virial_se_r.cu deleted file mode 100644 index 243c4ba94e..0000000000 --- a/source/lib/src/cuda/prod_virial_se_r.cu +++ /dev/null @@ -1,83 +0,0 @@ -#include "DeviceFunctor.h" -#include "gpu_nv.h" - -#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600 -static __inline__ __device__ double atomicAdd(double* address, double val) { - unsigned long long int* address_as_ull = (unsigned long long int*)address; - unsigned long long int old = *address_as_ull, assumed; - do { - assumed = old; - old = atomicCAS(address_as_ull, assumed, - __double_as_longlong(val + __longlong_as_double(assumed))); - // Note: uses integer comparison to avoid hang in case of NaN (since NaN != NaN) } while (assumed != old); - } while (assumed != old); - return __longlong_as_double(old); -} -#endif - -template -__global__ void deriv_wrt_neighbors_se_r(FPTYPE * virial, - FPTYPE * atom_virial, - const FPTYPE * net_deriv, - const FPTYPE * in_deriv, - const FPTYPE * rij, - const int * nlist, - const int nloc, - const int nnei, - const int ndescrpt) -{ - // idx -> nloc - // idy -> nnei - // idz = dd0 * 3 + dd1 - // dd0 = idz / 3 - // dd1 = idz % 3 - const unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x; - const unsigned int idy = blockIdx.y; - const unsigned int idz = threadIdx.y; - - if (idx >= nloc) { - return; - } - int j_idx = nlist[idx * nnei + idy]; - if (j_idx < 0) { - return; - } - // atomicAdd(virial + idz, net_deriv[idx * ndescrpt + idy * 4 + idw] * rij[idx * nnei * 3 + idy * 3 + idz / 3] * in_deriv[idx * ndescrpt * 3 + (idy * 4 + idw) * 3 + idz % 3]); - atomicAdd(atom_virial + j_idx * 9 + idz, net_deriv[idx * ndescrpt + idy] * rij[idx * nnei * 3 + idy * 3 + idz % 3] * in_deriv[idx * ndescrpt * 3 + idy * 3 + idz / 3]); -} - -template -void ProdVirialSeRGPUExecuteFunctor::operator()(FPTYPE * virial, - FPTYPE * atom_virial, - const FPTYPE * net_deriv, - const FPTYPE * in_deriv, - const FPTYPE * rij, - const int * nlist, - const int nloc, - const int nall, - const int nnei, - const int ndescrpt) -{ - cudaErrcheck(cudaMemset(virial, 0.0, sizeof(FPTYPE) * 9)); - cudaErrcheck(cudaMemset(atom_virial, 0.0, sizeof(FPTYPE) * 9 * nall)); - - const int LEN = 64; - int nblock = (nloc + LEN -1) / LEN; - dim3 block_grid(nblock, nnei); - dim3 thread_grid(LEN, 9); - // compute virial of a frame - deriv_wrt_neighbors_se_r<<>>( - virial, - atom_virial, - net_deriv, - in_deriv, - rij, - nlist, - nloc, - nnei, - ndescrpt - ); -} - -template struct ProdVirialSeRGPUExecuteFunctor; -template struct ProdVirialSeRGPUExecuteFunctor; \ No newline at end of file diff --git a/source/lib/src/cuda/tabulate.cu b/source/lib/src/cuda/tabulate.cu index a7bb696a76..f8bdbd45ac 100644 --- a/source/lib/src/cuda/tabulate.cu +++ b/source/lib/src/cuda/tabulate.cu @@ -1,11 +1,7 @@ -#include -#include -#include -#include -#include // or equivalently +#include #include -#include "DeviceFunctor.h" -#include "gpu_nv.h" +#include "tabulate.h" +#include "gpu_cuda.h" #define MM 4 #define KK 4 @@ -14,466 +10,231 @@ #define FULL_MASK 0xffffffff template -__forceinline__ -__device__ -void locate_xx(const FPTYPE& lower, const FPTYPE& upper, const FPTYPE& max, const FPTYPE& stride0, const FPTYPE& stride1, FPTYPE& xx, int& table_idx) { - if (xx < lower) { - table_idx = 0; - xx = 0; - } - else if (xx < upper) { - table_idx = (int)((xx - lower) / stride0); - xx -= (table_idx * stride0 + lower); - } - else if (xx < max) { - int first_stride = int((upper - lower) / stride0); - table_idx = first_stride + (int)((xx - upper) / stride1); - xx -= ((table_idx - first_stride) * stride1 + upper); - } - else { - table_idx = int((upper - lower) / stride0) + (int)((max - upper) / stride1) - 1; - xx = 0; - } +__forceinline__ __device__ +void locate_xx( + FPTYPE& xx, + int& table_idx, + const FPTYPE& lower, + const FPTYPE& upper, + const FPTYPE& max, + const FPTYPE& stride0, + const FPTYPE& stride1) +{ + if (xx < lower) { + table_idx = 0; + xx = 0; + } + else if (xx < upper) { + table_idx = (int)((xx - lower) / stride0); + xx -= (table_idx * stride0 + lower); + } + else if (xx < max) { + int first_stride = int((upper - lower) / stride0); + table_idx = first_stride + (int)((xx - upper) / stride1); + xx -= ((table_idx - first_stride) * stride1 + upper); + } + else { + table_idx = int((upper - lower) / stride0) + (int)((max - upper) / stride1) - 1; + xx = 0; + } } template -__forceinline__ -__device__ -FPTYPE dot(FPTYPE ll[4], FPTYPE rr[4]) { - return ll[0] * rr[0] + ll[1] * rr[1] + ll[2] * rr[2] + ll[3] * rr[3]; +__forceinline__ __device__ +FPTYPE dot( + FPTYPE ll[4], + FPTYPE rr[4]) +{ + return ll[0] * rr[0] + ll[1] * rr[1] + ll[2] * rr[2] + ll[3] * rr[3]; } template __forceinline__ __device__ -void warp_reduce(FPTYPE & val) { - for (int offset = 16; offset > 0; offset >>= 1) - val += __shfl_down_sync(FULL_MASK, val, offset); -} - -// last_layer_size must larger than MTILE * KTILE! -// TODO: A more flexible implementation of sparse -template < - typename FPTYPE, - int MTILE, - int KTILE> -__global__ void tabulate_fusion(const FPTYPE * table, const FPTYPE * in, const FPTYPE * ff, FPTYPE * out, const FPTYPE lower, const FPTYPE upper, const FPTYPE max, const FPTYPE stride0, const FPTYPE stride1, const int nnei, const int last_layer_size) { - extern __shared__ int _data[]; - int const block_idx = blockIdx.x; // nloc - int const thread_idx = threadIdx.x; // last_layer_size - FPTYPE ago = __shfl_sync(0xffffffff, in[block_idx * nnei + nnei - 1], 0); - bool unloop = false; - int breakpoint = nnei - 1; - // int const warp_idx = __shfl_sync(0xffffffff, threadIdx.x / 32, 0); - // int const lane_idx = threadIdx.x % 32; - // iteratorC for data reuse... - FPTYPE * iteratorC = (FPTYPE*) &_data[0]; - for (int kk = 0; kk < MTILE; kk++) - iteratorC[kk * last_layer_size + thread_idx] = 0.f; - __syncthreads(); - - for (int ii = 0; ii < nnei; ii++) { - FPTYPE var[4]; - FPTYPE xx = in[block_idx * nnei + ii]; - - if (ago == xx) { - unloop = true; - breakpoint = ii; - } - int table_idx = 0; - locate_xx(lower, upper, max, stride0, stride1, xx, table_idx); - var[0] = table[table_idx * last_layer_size * 4 + thread_idx * 4 + 0]; - var[1] = table[table_idx * last_layer_size * 4 + thread_idx * 4 + 1]; - var[2] = table[table_idx * last_layer_size * 4 + thread_idx * 4 + 2]; - var[3] = table[table_idx * last_layer_size * 4 + thread_idx * 4 + 3]; - FPTYPE res = ((var[0] * xx + var[1]) * xx + var[2]) * xx + var[3]; - for (int kk = 0; kk < MTILE; kk++) { - iteratorC[kk * last_layer_size + thread_idx] += (nnei - breakpoint) * ff[block_idx * nnei * MTILE + ii * MTILE + kk] * res; - } - if (unloop) break; - } - for (int ii = 0; ii < MTILE; ii++) { - out[block_idx * MTILE * last_layer_size + ii * last_layer_size + thread_idx] = iteratorC[ii * last_layer_size + thread_idx]; - } -} - -// last_layer_size must larger than MTILE * KTILE! -// TODO: A more flexible implementation of sparse - - -template < - typename FPTYPE, - int MTILE, - int KTILE> -__global__ void tabulate_fusion_grad_warp_reduce(const FPTYPE * table, const FPTYPE * in, const FPTYPE * ff, const FPTYPE * dy, FPTYPE * dy_dx, FPTYPE * dy_df, const FPTYPE lower, const FPTYPE upper, const FPTYPE max, const FPTYPE stride0, const FPTYPE stride1, const int nnei, const int last_layer_size) { - extern __shared__ int _data[]; - int const block_idx = blockIdx.x; // nloc - int const thread_idx = threadIdx.x; // KTILE * WARP_SIZE, usally 128 here~ - int warp_idx = __shfl_sync(0xffffffff, threadIdx.x / 32, 0); - int lane_idx = threadIdx.x % 32; - int breakpoint = nnei - 1; - bool unloop = false; - - FPTYPE * iteratorA = (FPTYPE *)&_data[0]; // dy - for (int ii = 0; ii < MTILE; ii++) { - if (thread_idx < last_layer_size) { - iteratorA[ii * last_layer_size + thread_idx] = dy[block_idx * MTILE * last_layer_size + ii * last_layer_size + thread_idx]; - } - } - __syncthreads(); - FPTYPE ago = __shfl_sync(0xffffffff, in[block_idx * nnei + nnei - 1], 0); - for (int ii = 0; ii < nnei; ii += KTILE) { - FPTYPE xx = in[block_idx * nnei + ii + warp_idx]; - // if (ago == xx) { - // unloop = true; - // breakpoint = ii; - // } - - int table_idx = 0; - locate_xx(lower, upper, max, stride0, stride1, xx, table_idx); - FPTYPE sum[KTILE] = {0.f}; - FPTYPE Csub = 0.f; - for (int jj = lane_idx; jj < last_layer_size; jj += WARP_SIZE) { - // load iteratorB through table - FPTYPE var[KTILE]; - var[0] = table[table_idx * last_layer_size * 4 + jj * 4 + 0]; - var[1] = table[table_idx * last_layer_size * 4 + jj * 4 + 1]; - var[2] = table[table_idx * last_layer_size * 4 + jj * 4 + 2]; - var[3] = table[table_idx * last_layer_size * 4 + jj * 4 + 3]; - FPTYPE tmp = (var[0] * xx + var[1]) * xx + var[2]; - for (int kk = 0; kk < KTILE; kk++) { - sum[kk] += (nnei - breakpoint) * iteratorA[kk * last_layer_size + jj] * (tmp * xx + var[3]); - } - var[2] = ff[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 0] * iteratorA[0 * last_layer_size + jj]; - var[2] += ff[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 1] * iteratorA[1 * last_layer_size + jj]; - var[2] += ff[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 2] * iteratorA[2 * last_layer_size + jj]; - var[2] += ff[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 3] * iteratorA[3 * last_layer_size + jj]; - Csub += (nnei - breakpoint) * ((2.0 * var[0] * xx + var[1]) * xx + tmp) * var[2]; - } - __syncwarp(); - for (int kk = 0; kk < KTILE; kk++) { - warp_reduce(sum[kk]); - } - warp_reduce(Csub); - if (lane_idx == 0) { - for (int kk = 0; kk < KTILE; kk++) { - dy_df[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + kk] = sum[kk]; - } - dy_dx[block_idx * nnei + ii + warp_idx] = Csub; - } - if (unloop) break; - } +void warp_reduce( + FPTYPE & val) +{ + for (int offset = 16; offset > 0; offset >>= 1) + val += __shfl_down_sync(FULL_MASK, val, offset); } template < typename FPTYPE, int MTILE, int KTILE> -__global__ void tabulate_fusion_special(const FPTYPE * table, const FPTYPE * in, const FPTYPE * ff, FPTYPE * out, const FPTYPE lower, const FPTYPE upper, const FPTYPE max, const FPTYPE stride0, const FPTYPE stride1, const int nnei, const int last_layer_size) { - extern __shared__ int _data[]; - int const block_idx = blockIdx.x; // nloc - int const thread_idx = threadIdx.x; // last_layer_size - FPTYPE ago = __shfl_sync(0xffffffff, in[block_idx * nnei + nnei - 1], 0); - bool unloop = false; - int breakpoint = nnei - 1; - - FPTYPE * iteratorC = (FPTYPE*) &_data[0]; - for (int kk = 0; kk < MTILE; kk++) - iteratorC[kk * last_layer_size + thread_idx] = 0.f; - __syncthreads(); - - for (int ii = 0; ii < nnei; ii++) { - FPTYPE var[6]; - FPTYPE xx = in[block_idx * nnei + ii]; - if (xx == ago) { - unloop = true; - breakpoint = ii; - } - int table_idx = 0; - locate_xx(lower, upper, max, stride0, stride1, xx, table_idx); - var[0] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 0]; - var[1] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 1]; - var[2] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 2]; - var[3] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 3]; - var[4] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 4]; - var[5] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 5]; - FPTYPE res = var[0] + (var[1] + (var[2] + (var[3] + (var[4] + var[5] * xx) * xx) * xx) * xx) * xx; - - for (int kk = 0; kk < MTILE; kk++) { - iteratorC[kk * last_layer_size + thread_idx] += (nnei - breakpoint) * ff[block_idx * nnei * MTILE + ii * MTILE + kk] * res; - } - if (unloop) break; - } - for (int ii = 0; ii < MTILE; ii++) { - out[block_idx * MTILE * last_layer_size + ii * last_layer_size + thread_idx] = iteratorC[ii * last_layer_size + thread_idx]; +__global__ void tabulate_fusion_fifth_order_polynomial( + FPTYPE * out, + const FPTYPE * table, + const FPTYPE * em_x, + const FPTYPE * em, + const FPTYPE lower, + const FPTYPE upper, + const FPTYPE max, + const FPTYPE stride0, + const FPTYPE stride1, + const int nnei, + const int last_layer_size) +{ + extern __shared__ int _data[]; + const int block_idx = blockIdx.x; // nloc + const int thread_idx = threadIdx.x; // last_layer_size + FPTYPE ago = __shfl_sync(0xffffffff, em_x[block_idx * nnei + nnei - 1], 0); + bool unloop = false; + int breakpoint = nnei - 1; + FPTYPE * iteratorC = (FPTYPE*) &_data[0]; + for (int kk = 0; kk < MTILE; kk++) + iteratorC[kk * last_layer_size + thread_idx] = 0.f; + __syncthreads(); + + for (int ii = 0; ii < nnei; ii++) { + FPTYPE var[6]; + FPTYPE xx = em_x[block_idx * nnei + ii]; + if (xx == ago) { + unloop = true; + breakpoint = ii; + } + int table_idx = 0; + locate_xx(xx, table_idx, lower, upper, max, stride0, stride1); + var[0] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 0]; + var[1] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 1]; + var[2] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 2]; + var[3] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 3]; + var[4] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 4]; + var[5] = table[table_idx * last_layer_size * 6 + thread_idx * 6 + 5]; + FPTYPE res = var[0] + (var[1] + (var[2] + (var[3] + (var[4] + var[5] * xx) * xx) * xx) * xx) * xx; + + for (int kk = 0; kk < MTILE; kk++) { + iteratorC[kk * last_layer_size + thread_idx] += (nnei - breakpoint) * em[block_idx * nnei * MTILE + ii * MTILE + kk] * res; } + if (unloop) break; + } + for (int ii = 0; ii < MTILE; ii++) { + out[block_idx * MTILE * last_layer_size + ii * last_layer_size + thread_idx] = iteratorC[ii * last_layer_size + thread_idx]; + } } template < typename FPTYPE, int MTILE, int KTILE> -__global__ void tabulate_fusion_grad_warp_reduce_special(const FPTYPE * table, const FPTYPE * in, const FPTYPE * ff, const FPTYPE * dy, FPTYPE * dy_dx, FPTYPE * dy_df, const FPTYPE lower, const FPTYPE upper, const FPTYPE max, const FPTYPE stride0, const FPTYPE stride1, const int nnei, const int last_layer_size) { - extern __shared__ int _data[]; - int const block_idx = blockIdx.x; // nloc - int const thread_idx = threadIdx.x; // KTILE * WARP_SIZE, usally 128 here~ - int warp_idx = __shfl_sync(0xffffffff, threadIdx.x / 32, 0); - int lane_idx = threadIdx.x % 32; - int breakpoint = nnei - 1; - bool unloop = false; - - FPTYPE * iteratorA = (FPTYPE *)&_data[0]; // dy - for (int ii = 0; ii < MTILE; ii++) { - if (thread_idx < last_layer_size) { - iteratorA[ii * last_layer_size + thread_idx] = dy[block_idx * MTILE * last_layer_size + ii * last_layer_size + thread_idx]; - } - } - __syncthreads(); - FPTYPE ago = __shfl_sync(0xffffffff, in[block_idx * nnei + nnei - 1], 0); - for (int ii = 0; ii < nnei; ii += KTILE) { - FPTYPE xx = in[block_idx * nnei + ii + warp_idx]; - if (ago == xx) { - unloop = true; - breakpoint = ii; - } - - int table_idx = 0; - locate_xx(lower, upper, max, stride0, stride1, xx, table_idx); - FPTYPE sum[KTILE] = {0.f}; - FPTYPE Csub = 0.f; - for (int jj = lane_idx; jj < last_layer_size; jj += WARP_SIZE) { - FPTYPE var[6]; - // load iteratorB through table - var[0] = table[table_idx * last_layer_size * 6 + 6 * jj + 0]; - var[1] = table[table_idx * last_layer_size * 6 + 6 * jj + 1]; - var[2] = table[table_idx * last_layer_size * 6 + 6 * jj + 2]; - var[3] = table[table_idx * last_layer_size * 6 + 6 * jj + 3]; - var[4] = table[table_idx * last_layer_size * 6 + 6 * jj + 4]; - var[5] = table[table_idx * last_layer_size * 6 + 6 * jj + 5]; - FPTYPE res = var[0] + (var[1] + (var[2] + (var[3] + (var[4] + var[5] * xx) * xx) * xx) * xx) * xx; - - for (int kk = 0; kk < KTILE; kk++) { - sum[kk] += (nnei - breakpoint) * iteratorA[kk * last_layer_size + jj] * res; - } - res = ff[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 0] * iteratorA[0 * last_layer_size + jj]; - res += ff[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 1] * iteratorA[1 * last_layer_size + jj]; - res += ff[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 2] * iteratorA[2 * last_layer_size + jj]; - res += ff[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 3] * iteratorA[3 * last_layer_size + jj]; - Csub += (nnei - breakpoint) * (var[1] + (2 * var[2] + (3 * var[3] + (4 * var[4] + 5 * var[5] * xx) * xx) * xx) * xx) * res; - } - __syncwarp(); - for (int kk = 0; kk < KTILE; kk++) { - warp_reduce(sum[kk]); - } - warp_reduce(Csub); - if (lane_idx == 0) { - for (int kk = 0; kk < KTILE; kk++) { - dy_df[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + kk] = sum[kk]; - } - dy_dx[block_idx * nnei + ii + warp_idx] = Csub; - } - if (unloop) break; +__global__ void tabulate_fusion__grad_fifth_order_polynomial( + FPTYPE * dy_dem_x, + FPTYPE * dy_dem, + const FPTYPE * table, + const FPTYPE * em_x, + const FPTYPE * em, + const FPTYPE * dy, + const FPTYPE lower, + const FPTYPE upper, + const FPTYPE max, + const FPTYPE stride0, + const FPTYPE stride1, + const int nnei, + const int last_layer_size) +{ + extern __shared__ int _data[]; + const int block_idx = blockIdx.x; // nloc + const int thread_idx = threadIdx.x; // KTILE * WARP_SIZE, usally 128 here~ + int warp_idx = __shfl_sync(0xffffffff, threadIdx.x / 32, 0); + int lane_idx = threadIdx.x % 32; + int breakpoint = nnei - 1; + bool unloop = false; + FPTYPE * iteratorA = (FPTYPE *)&_data[0]; // dy + for (int ii = 0; ii < MTILE; ii++) { + if (thread_idx < last_layer_size) { + iteratorA[ii * last_layer_size + thread_idx] = dy[block_idx * MTILE * last_layer_size + ii * last_layer_size + thread_idx]; + } + } + __syncthreads(); + FPTYPE ago = __shfl_sync(0xffffffff, em_x[block_idx * nnei + nnei - 1], 0); + for (int ii = 0; ii < nnei; ii += KTILE) { + FPTYPE xx = em_x[block_idx * nnei + ii + warp_idx]; + if (ago == xx) { + unloop = true; + breakpoint = ii; } -} - -template -__global__ void tabulate_checker(const FPTYPE * in, int * out, const FPTYPE lower, const FPTYPE upper, const FPTYPE max, const int nloc, const int nnei) { - __shared__ int Csub[THREADS_PER_BLOCK]; - __shared__ int Dsub[THREADS_PER_BLOCK]; - int const bid = blockIdx.x; - int const tid = threadIdx.x; - Csub[tid] = 0; - Dsub[tid] = 0; - __syncthreads(); - - for (int ii = tid; ii < nnei; ii += THREADS_PER_BLOCK) { - FPTYPE xx = in[bid * nnei + ii]; - if (xx < lower || xx > max) { - Csub[tid] += 1; - // printf("# DEEPMD: level 2 overflow, xx:\t%f\n", xx); - } - else if (xx >= upper && xx <= max) { - Dsub[tid] += 1; - // printf("# DEEPMD: level 1 overflow, xx:\t%f\n", xx); - } - } - __syncthreads(); - // do reduction in shared memory - for (int ii = THREADS_PER_BLOCK >> 1; ii > 0; ii >>= 1) { - if (tid < ii) { - Csub[tid] += Csub[tid + ii]; - Dsub[tid] += Dsub[tid + ii]; - } - __syncthreads(); - } - if (tid == 0) { - out[bid] = Csub[0]; - out[nloc + bid] = Dsub[0]; - } -} - -void TabulateFusionLauncher(const double * table, const double * table_info, const double * in, const double * ff, const int nloc, const int nnei, const int last_layer_size, double * out) { - // std::cout << "I'm in tabulate GPU!" << std::endl; - tabulate_fusion_special <<>>(table, in, ff, out, table_info[0], table_info[1], table_info[2], table_info[3], table_info[4], nnei, last_layer_size); -} -void TabulateFusionLauncher(const float * table, const float * table_info, const float * in, const float * ff, const int nloc, const int nnei, const int last_layer_size, float * out) { - tabulate_fusion_special <<>>(table, in, ff, out, table_info[0], table_info[1], table_info[2], table_info[3], table_info[4], nnei, last_layer_size); -} - -void TabulateFusionGradLauncher(const double * table, const double * table_info, const double * in, const double * ff, const double * dy, const int nloc, const int nnei, const int last_layer_size, double * dy_dx, double * dy_df) { - // cudaMemset(dy_df, 0.0, sizeof(double) * nloc * nnei * 4); - cudaMemset(dy_dx, 0.0, sizeof(double) * nloc * nnei); - cudaMemset(dy_df, 0.0, sizeof(double) * nloc * nnei * 4); - tabulate_fusion_grad_warp_reduce_special <<>>(table, in, ff, dy, dy_dx, dy_df, table_info[0], table_info[1], table_info[2], table_info[3], table_info[4], nnei, last_layer_size); -} -void TabulateFusionGradLauncher(const float * table, const float * table_info, const float * in, const float * ff, const float * dy, const int nloc, const int nnei, const int last_layer_size, float * dy_dx, float * dy_df) { - // cudaMemset(dy_df, 0.0, sizeof(float) * nloc * nnei * 4); - cudaMemset(dy_dx, 0.0, sizeof(float) * nloc * nnei); - cudaMemset(dy_df, 0.0, sizeof(float) * nloc * nnei * 4); - tabulate_fusion_grad_warp_reduce_special <<>>(table, in, ff, dy, dy_dx, dy_df, table_info[0], table_info[1], table_info[2], table_info[3], table_info[4], nnei, last_layer_size); -} - -void TabulateCheckerLauncher(const double * table_info, const double * in, int * out, const int nloc, const int nnei) { - tabulate_checker <<>>(in, out, table_info[0], table_info[1], table_info[2], nloc, nnei); - // Declare, allocate, and initialize device-accessible pointers for input and output - int * d_out = NULL; - int * h_out = NULL; - cudaMalloc((void **)&d_out, sizeof(int)); - h_out = (int*)malloc(sizeof(int)); - // Determine temporary device storage requirements - void *d_temp_storage = NULL; - size_t temp_storage_bytes = 0; - cub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, out, d_out, nloc); - - // Allocate temporary storage - cudaMalloc(&d_temp_storage, temp_storage_bytes); - - // Run sum-reduction - cub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, out, d_out, nloc); - - // d_out <-- [38] - cudaMemcpy(h_out, d_out, sizeof(int), cudaMemcpyDeviceToHost); - - if(h_out[0] > 0) { - std::cout << "# DEEPMD: warning! some values [" << h_out[0] << "/" << nloc * nnei << "] overflow the range of the table, using the endpoint approximate processing.." << std::endl; - } - - // Run sum-reduction - cub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, out + nloc, d_out, nloc); - - // d_out <-- [38] - cudaMemcpy(h_out, d_out, sizeof(int), cudaMemcpyDeviceToHost); - - if(h_out[0] > 0) { - std::cout << "# DEEPMD: warning! some values [" << h_out[0] << "/" << nloc * nnei << "] overflow the range of the table, using second table approximate processing.." << std::endl; - } - - // free the temperary storage - cudaFree(d_out); - cudaFree(d_temp_storage); - free(h_out); -} - -void TabulateCheckerLauncher(const float * table_info, const float * in, int * out, const int nloc, const int nnei) { - tabulate_checker <<>>(in, out, table_info[0], table_info[1], table_info[2], nloc, nnei); - // Declare, allocate, and initialize device-accessible pointers for input and output - int * d_out = NULL; - int * h_out = NULL; - cudaMalloc((void **)&d_out, sizeof(int)); - h_out = (int*)malloc(sizeof(int)); - // Determine temporary device storage requirements - void *d_temp_storage = NULL; - size_t temp_storage_bytes = 0; - cub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, out, d_out, nloc); - - // Allocate temporary storage - cudaMalloc(&d_temp_storage, temp_storage_bytes); - - // Run sum-reduction - cub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, out, d_out, nloc); - - // d_out <-- [38] - cudaMemcpy(h_out, d_out, sizeof(int), cudaMemcpyDeviceToHost); - - if(h_out[0] > 0) { - std::cout << "# DEEPMD: warning! some values [" << h_out[0] << "/" << nloc * nnei << "] overflow the range of the table, using the endpoint approximate processing.." << std::endl; - } - - // Run sum-reduction - cub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, out + nloc, d_out, nloc); - - // d_out <-- [38] - cudaMemcpy(h_out, d_out, sizeof(int), cudaMemcpyDeviceToHost); - - if(h_out[0] > 0) { - std::cout << "# DEEPMD: warning! some values [" << h_out[0] << "/" << nloc * nnei << "] overflow the range of the table, using second table approximate processing.." << std::endl; - } - - // free the temperary storage - cudaFree(d_out); - cudaFree(d_temp_storage); - free(h_out); + int table_idx = 0; + locate_xx(xx, table_idx, lower, upper, max, stride0, stride1); + FPTYPE sum[KTILE] = {0.f}; + FPTYPE Csub = 0.f; + for (int jj = lane_idx; jj < last_layer_size; jj += WARP_SIZE) { + FPTYPE var[6]; + // load iteratorB through table + var[0] = table[table_idx * last_layer_size * 6 + 6 * jj + 0]; + var[1] = table[table_idx * last_layer_size * 6 + 6 * jj + 1]; + var[2] = table[table_idx * last_layer_size * 6 + 6 * jj + 2]; + var[3] = table[table_idx * last_layer_size * 6 + 6 * jj + 3]; + var[4] = table[table_idx * last_layer_size * 6 + 6 * jj + 4]; + var[5] = table[table_idx * last_layer_size * 6 + 6 * jj + 5]; + FPTYPE res = var[0] + (var[1] + (var[2] + (var[3] + (var[4] + var[5] * xx) * xx) * xx) * xx) * xx; + + for (int kk = 0; kk < KTILE; kk++) { + sum[kk] += (nnei - breakpoint) * iteratorA[kk * last_layer_size + jj] * res; + } + res = em[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 0] * iteratorA[0 * last_layer_size + jj]; + res += em[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 1] * iteratorA[1 * last_layer_size + jj]; + res += em[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 2] * iteratorA[2 * last_layer_size + jj]; + res += em[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + 3] * iteratorA[3 * last_layer_size + jj]; + Csub += (nnei - breakpoint) * (var[1] + (2 * var[2] + (3 * var[3] + (4 * var[4] + 5 * var[5] * xx) * xx) * xx) * xx) * res; + } + __syncwarp(); + for (int kk = 0; kk < KTILE; kk++) { + warp_reduce(sum[kk]); + } + warp_reduce(Csub); + if (lane_idx == 0) { + for (int kk = 0; kk < KTILE; kk++) { + dy_dem[block_idx * nnei * MTILE + (ii + warp_idx) * 4 + kk] = sum[kk]; + } + dy_dem_x[block_idx * nnei + ii + warp_idx] = Csub; + } + if (unloop) break; + } } template -void TabulateFusionGPUExecuteFunctor::operator()(const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const int nloc, const int nnei, const int last_layer_size, FPTYPE * out) { - tabulate_fusion_special <<>>(table, in, ff, out, table_info[0], table_info[1], table_info[2], table_info[3], table_info[4], nnei, last_layer_size); +void tabulate_fusion_gpu_cuda( + FPTYPE * out, + const FPTYPE * table, + const FPTYPE * table_info, + const FPTYPE * em_x, + const FPTYPE * em, + const int nloc, + const int nnei, + const int last_layer_size) +{ + tabulate_fusion_fifth_order_polynomial <<>>( + out, + table, em_x, em, table_info[0], table_info[1], table_info[2], table_info[3], table_info[4], nnei, last_layer_size); } template -void TabulateFusionGradGPUExecuteFunctor::operator()(const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const FPTYPE * dy, const int nloc, const int nnei, const int last_layer_size, FPTYPE * dy_dx, FPTYPE * dy_df) { - cudaErrcheck(cudaMemset(dy_dx, 0.0, sizeof(FPTYPE) * nloc * nnei)); - cudaErrcheck(cudaMemset(dy_df, 0.0, sizeof(FPTYPE) * nloc * nnei * 4)); - tabulate_fusion_grad_warp_reduce_special <<>>(table, in, ff, dy, dy_dx, dy_df, table_info[0], table_info[1], table_info[2], table_info[3], table_info[4], nnei, last_layer_size); -} - -template -void TabulateCheckerGPUExecuteFunctor::operator()(const FPTYPE * table_info, const FPTYPE * in, int * out, const int nloc, const int nnei) { - tabulate_checker <<>>(in, out, table_info[0], table_info[1], table_info[2], nloc, nnei); - // Declare, allocate, and initialize device-accessible pointers for input and output - int * d_out = NULL; - int * h_out = NULL; - cudaMalloc((void **)&d_out, sizeof(int)); - h_out = (int*)malloc(sizeof(int)); - // Determine temporary device storage requirements - void *d_temp_storage = NULL; - size_t temp_storage_bytes = 0; - cub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, out, d_out, nloc); - - // Allocate temporary storage - cudaMalloc(&d_temp_storage, temp_storage_bytes); - - // Run sum-reduction - cub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, out, d_out, nloc); - - // d_out <-- [38] - cudaMemcpy(h_out, d_out, sizeof(int), cudaMemcpyDeviceToHost); - - if(h_out[0] > 0) { - std::cout << "# DEEPMD: warning! some values [" << h_out[0] << "/" << nloc * nnei << "] overflow the range of the table, using the endpoint approximate processing.." << std::endl; - } - - // Run sum-reduction - cub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, out + nloc, d_out, nloc); - - // d_out <-- [38] - cudaMemcpy(h_out, d_out, sizeof(int), cudaMemcpyDeviceToHost); - - if(h_out[0] > 0) { - std::cout << "# DEEPMD: warning! some values [" << h_out[0] << "/" << nloc * nnei << "] overflow the range of the table, using second table approximate processing.." << std::endl; - } - - // free the temperary storage - cudaFree(d_out); - cudaFree(d_temp_storage); - free(h_out); -} - -template struct TabulateFusionGPUExecuteFunctor; -template struct TabulateFusionGPUExecuteFunctor; -template struct TabulateFusionGradGPUExecuteFunctor; -template struct TabulateFusionGradGPUExecuteFunctor; -template struct TabulateCheckerGPUExecuteFunctor; -template struct TabulateCheckerGPUExecuteFunctor; \ No newline at end of file +void tabulate_fusion_grad_gpu_cuda( + FPTYPE * dy_dem_x, + FPTYPE * dy_dem, + const FPTYPE * table, + const FPTYPE * table_info, + const FPTYPE * em_x, + const FPTYPE * em, + const FPTYPE * dy, + const int nloc, + const int nnei, + const int last_layer_size) +{ + cudaErrcheck(cudaMemset( + dy_dem_x, + 0.0, sizeof(FPTYPE) * nloc * nnei)); + cudaErrcheck(cudaMemset( + dy_dem, + 0.0, sizeof(FPTYPE) * nloc * nnei * 4)); + + tabulate_fusion__grad_fifth_order_polynomial <<>>( + dy_dem_x, dy_dem, + table, em_x, em, dy, table_info[0], table_info[1], table_info[2], table_info[3], table_info[4], nnei, last_layer_size); +} + +template void tabulate_fusion_gpu_cuda(float * out, const float * table, const float * table_info, const float * em_x, const float * em, const int nloc, const int nnei, const int last_layer_size); +template void tabulate_fusion_gpu_cuda(double * out, const double * table, const double * table_info, const double * em_x, const double * em, const int nloc, const int nnei, const int last_layer_size); +template void tabulate_fusion_grad_gpu_cuda (float * dy_dem_x, float * dy_dem, const float * table, const float * table_info, const float * em_x, const float * em, const float * dy, const int nloc, const int nnei, const int last_layer_size); +template void tabulate_fusion_grad_gpu_cuda (double * dy_dem_x, double * dy_dem, const double * table, const double * table_info, const double * em_x, const double * em, const double * dy, const int nloc, const int nnei, const int last_layer_size); diff --git a/source/lib/src/gelu.cc b/source/lib/src/gelu.cc new file mode 100644 index 0000000000..7f0cde9a65 --- /dev/null +++ b/source/lib/src/gelu.cc @@ -0,0 +1,49 @@ +#include "gelu.h" +#include "math.h" +#include "device.h" + +template +void gelu_cpu( + FPTYPE * out, + const FPTYPE * xx, + const int size) +{ + for (int ii = 0; ii < size; ii++) { + out[ii] = xx[ii] * 0.5 * (1.0 + tanh(SQRT_2_PI * (xx[ii] + 0.044715 * xx[ii] * xx[ii] *xx[ii]))); + } +} + +template +void gelu_grad_cpu( + FPTYPE * out, + const FPTYPE * xx, + const FPTYPE * dy, + const int size) +{ + for (int ii = 0; ii < size; ii++) { + const FPTYPE var = tanh(SQRT_2_PI * (xx[ii] + 0.044715 * xx[ii] * xx[ii] * xx[ii])); + out[ii] = dy[ii] * (0.5 * SQRT_2_PI * xx[ii] * (1 - var * var) * (0.134145 * xx[ii] * xx[ii] + 1) + 0.5 * var + 0.5); + } +} + +template +void gelu_grad_grad_cpu( + FPTYPE * out, + const FPTYPE * xx, + const FPTYPE * dy, + const FPTYPE * dy_2, + const int size) +{ + for (int ii = 0; ii < size; ii++) { + const FPTYPE var1 = tanh(SQRT_2_PI * (xx[ii] + 0.044715 * xx[ii] * xx[ii] *xx[ii])); + const FPTYPE var2 = SQRT_2_PI * (1 - var1 * var1) * (0.134145 * xx[ii] * xx[ii] + 1); + out[ii] = dy[ii] * dy_2[ii] * (0.134145 * SQRT_2_PI * xx[ii] * xx[ii] * (1 - var1 * var1) - SQRT_2_PI * xx[ii] * var2 * (0.134145 * xx[ii] * xx[ii] + 1) * var1 + var2); + } +} + +template void gelu_cpu(float * out, const float * x, const int size); +template void gelu_cpu(double * out, const double * x, const int size); +template void gelu_grad_cpu(float * out, const float * x, const float * dy, const int size); +template void gelu_grad_cpu(double * out, const double * x, const double * dy, const int size); +template void gelu_grad_grad_cpu(float * out, const float * x, const float * dy, const float * dy_2, const int size); +template void gelu_grad_grad_cpu(double * out, const double * x, const double * dy, const double * dy_2, const int size); diff --git a/source/lib/src/prod_env_mat.cc b/source/lib/src/prod_env_mat.cc index c0070bde72..ac0d35be5b 100644 --- a/source/lib/src/prod_env_mat.cc +++ b/source/lib/src/prod_env_mat.cc @@ -89,6 +89,90 @@ void prod_env_mat_a_cpu( } } +template +void prod_env_mat_r_cpu( + FPTYPE * em, + FPTYPE * em_deriv, + FPTYPE * rij, + int * nlist, + const FPTYPE * coord, + const int * type, + const int * ilist, + const int * jrange, + const int * jlist, + const int max_nbor_size, + const FPTYPE * avg, + const FPTYPE * std, + const int nloc, + const int nall, + const int ntypes, + const float rcut, + const float rcut_smth, + const std::vector sec) +{ + const int nnei = sec.back(); + const int nem = nnei * 1; + + // set & normalize coord + std::vector d_coord3(nall * 3); + for (int ii = 0; ii < nall; ++ii) { + for (int dd = 0; dd < 3; ++dd) { + d_coord3[ii * 3 + dd] = coord[ii * 3 + dd]; + } + } + + // set type + std::vector d_type (nall); + for (int ii = 0; ii < nall; ++ii) { + d_type[ii] = type[ii]; + } + + // build nlist + std::vector > d_nlist_a(nloc); + + for (unsigned ii = 0; ii < nloc; ++ii) { + d_nlist_a.reserve (jrange[nloc] / nloc + 10); + } + for (unsigned ii = 0; ii < nloc; ++ii) { + int i_idx = ilist[ii]; + for (unsigned jj = jrange[ii]; jj < jrange[ii+1]; ++jj) { + int j_idx = jlist[jj]; + d_nlist_a[i_idx].push_back (j_idx); + } + } + +#pragma omp parallel for + for (int ii = 0; ii < nloc; ++ii) { + std::vector fmt_nlist_a; + int ret = format_nlist_cpu(fmt_nlist_a, d_coord3, ntypes, d_type, ii, d_nlist_a[ii], rcut, sec); + std::vector d_em_a; + std::vector d_em_a_deriv; + std::vector d_em_r; + std::vector d_em_r_deriv; + std::vector d_rij_a; + env_mat_r_cpu (d_em_a, d_em_a_deriv, d_rij_a, d_coord3, ntypes, d_type, ii, fmt_nlist_a, sec, rcut_smth, rcut); + + // check sizes + assert (d_em_a.size() == nem); + assert (d_em_a_deriv.size() == nem * 3); + assert (d_rij_a.size() == nnei * 3); + assert (fmt_nlist_a.size() == nnei); + // record outputs + for (int jj = 0; jj < nem; ++jj) { + em[ii * nem + jj] = (d_em_a[jj] - avg[d_type[ii] * nem + jj]) / std[d_type[ii] * nem + jj]; + } + for (int jj = 0; jj < nem * 3; ++jj) { + em_deriv[ii * nem * 3 + jj] = d_em_a_deriv[jj] / std[d_type[ii] * nem + jj / 3]; + } + for (int jj = 0; jj < nnei * 3; ++jj) { + rij[ii * nnei * 3 + jj] = d_rij_a[jj]; + } + for (int jj = 0; jj < nnei; ++jj) { + nlist[ii * nnei + jj] = fmt_nlist_a[jj]; + } + } +} + template void prod_env_mat_a_cpu( @@ -132,6 +216,47 @@ void prod_env_mat_a_cpu( const float rcut_smth, const std::vector sec); +template +void prod_env_mat_r_cpu( + double * em, + double * em_deriv, + double * rij, + int * nlist, + const double * coord, + const int * type, + const int * ilist, + const int * jrange, + const int * jlist, + const int max_nbor_size, + const double * avg, + const double * std, + const int nloc, + const int nall, + const int ntypes, + const float rcut, + const float rcut_smth, + const std::vector sec); + +template +void prod_env_mat_r_cpu( + float * em, + float * em_deriv, + float * rij, + int * nlist, + const float * coord, + const int * type, + const int * ilist, + const int * jrange, + const int * jlist, + const int max_nbor_size, + const float * avg, + const float * std, + const int nloc, + const int nall, + const int ntypes, + const float rcut, + const float rcut_smth, + const std::vector sec); #if GOOGLE_CUDA void env_mat_nbor_update( diff --git a/source/lib/src/prod_virial.cc b/source/lib/src/prod_virial.cc index feaf39e357..89c8f46185 100644 --- a/source/lib/src/prod_virial.cc +++ b/source/lib/src/prod_virial.cc @@ -140,7 +140,7 @@ void prod_virial_r_cpu( const int * nlist, const int nloc, const int nall, - const int nnei) ; + const int nnei); template void prod_virial_r_cpu( @@ -152,4 +152,4 @@ void prod_virial_r_cpu( const int * nlist, const int nloc, const int nall, - const int nnei) ; + const int nnei); diff --git a/source/lib/src/tabulate.cc b/source/lib/src/tabulate.cc new file mode 100644 index 0000000000..98b561a348 --- /dev/null +++ b/source/lib/src/tabulate.cc @@ -0,0 +1,192 @@ +#include +#include +#include +#include +#include "tabulate.h" +/* + This inline function was designed to get the table info and bias value for current input xx! + lower: indicate the lower boundary of the first table; + upper: indicate the upper boundary of the first table as well as the lower boundary of the second table; + max: indicate the upper boundary of the second table; + stride0: indicate the stride of the first table; + stride1: indicate the stride of the second table; + xx: indicate the inputs value; + table_idx: indicate the location of table info of input value xx; +*/ +template +inline void locate_xx( + const FPTYPE& lower, + const FPTYPE& upper, + const FPTYPE& max, + const FPTYPE& stride0, + const FPTYPE& stride1, + FPTYPE& xx, + int& table_idx) +{ + if (xx < lower) { + table_idx = 0; + xx = 0; + } + else if (xx < upper) { + table_idx = (int)((xx - lower) / stride0); + xx -= (table_idx * stride0 + lower); + } + else if (xx < max) { + int first_stride = int((upper - lower) / stride0); + table_idx = first_stride + (int)((xx - upper) / stride1); + xx -= ((table_idx - first_stride) * stride1 + upper); + } + else { + table_idx = int((upper - lower) / stride0) + (int)((max - upper) / stride1) - 1; + xx = 0; + } +} + +template +inline FPTYPE dot( + FPTYPE a[4], + FPTYPE b[4]) +{ + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; +} + +template +void tabulate_fusion_cpu( + FPTYPE * out, + const FPTYPE * table, + const FPTYPE * table_info, + const FPTYPE * em_x, + const FPTYPE * em, + const int nloc, + const int nnei, + const int last_layer_size) +{ + memset(out, 0.0, sizeof(FPTYPE) * nloc * 4 * last_layer_size); + const FPTYPE lower = table_info[0]; + const FPTYPE upper = table_info[1]; + const FPTYPE _max = table_info[2]; + const FPTYPE stride0 = table_info[3]; + const FPTYPE stride1 = table_info[4]; + // for every atom, execute a small manual gemm ~ + // FPTYPE * res = new FPTYPE[4 * last_layer_size]; + #pragma omp parallel for + for (int ii = 0; ii < nloc; ii++) { + FPTYPE ll[4] = {0}; + FPTYPE ago = em_x[ii * nnei + nnei - 1]; + bool unloop = false; + for (int jj = 0; jj < nnei; jj++) { + ll[0] = em[ii * nnei * 4 + jj * 4 + 0]; + ll[1] = em[ii * nnei * 4 + jj * 4 + 1]; + ll[2] = em[ii * nnei * 4 + jj * 4 + 2]; + ll[3] = em[ii * nnei * 4 + jj * 4 + 3]; + FPTYPE xx = em_x[ii * nnei + jj]; + if (ago == xx) { + unloop = true; + } + int table_idx = 0; + locate_xx(lower, upper, _max, stride0, stride1, xx, table_idx); + for (int kk = 0; kk < last_layer_size; kk++) { + FPTYPE a0 = table[table_idx * last_layer_size * 6 + 6 * kk + 0]; + FPTYPE a1 = table[table_idx * last_layer_size * 6 + 6 * kk + 1]; + FPTYPE a2 = table[table_idx * last_layer_size * 6 + 6 * kk + 2]; + FPTYPE a3 = table[table_idx * last_layer_size * 6 + 6 * kk + 3]; + FPTYPE a4 = table[table_idx * last_layer_size * 6 + 6 * kk + 4]; + FPTYPE a5 = table[table_idx * last_layer_size * 6 + 6 * kk + 5]; + FPTYPE var = a0 + (a1 + (a2 + (a3 + (a4 + a5 * xx) * xx) * xx) * xx) * xx; + if (unloop) { + out[ii * last_layer_size * 4 + 0 * last_layer_size + kk] += (nnei - jj) * var * ll[0]; + out[ii * last_layer_size * 4 + 1 * last_layer_size + kk] += (nnei - jj) * var * ll[1]; + out[ii * last_layer_size * 4 + 2 * last_layer_size + kk] += (nnei - jj) * var * ll[2]; + out[ii * last_layer_size * 4 + 3 * last_layer_size + kk] += (nnei - jj) * var * ll[3]; + } + else { + out[ii * last_layer_size * 4 + 0 * last_layer_size + kk] += var * ll[0]; + out[ii * last_layer_size * 4 + 1 * last_layer_size + kk] += var * ll[1]; + out[ii * last_layer_size * 4 + 2 * last_layer_size + kk] += var * ll[2]; + out[ii * last_layer_size * 4 + 3 * last_layer_size + kk] += var * ll[3]; + } + } + if (unloop) break; + } + } +} + +template +void tabulate_fusion_grad_cpu( + FPTYPE * dy_dem_x, + FPTYPE * dy_dem, + const FPTYPE * table, + const FPTYPE * table_info, + const FPTYPE * em_x, + const FPTYPE * em, + const FPTYPE * dy, + const int nloc, + const int nnei, + const int last_layer_size) +{ + memset(dy_dem_x, 0.0, sizeof(FPTYPE) * nloc * nnei); + memset(dy_dem, 0.0, sizeof(FPTYPE) * nloc * nnei * 4); + FPTYPE const lower = table_info[0]; + FPTYPE const upper = table_info[1]; + FPTYPE const _max = table_info[2]; + FPTYPE const stride0 = table_info[3]; + FPTYPE const stride1 = table_info[4]; + // for every atom, execute a small gemm~ + // FPTYPE * res = new FPTYPE[4 * last_layer_size]; + #pragma omp parallel for + for (int ii = 0; ii < nloc; ii++) { + FPTYPE ll[4]; + FPTYPE rr[4]; + FPTYPE ago = em_x[ii * nnei + nnei - 1]; + bool unloop = false; + for (int jj = 0; jj < nnei; jj++) { + // construct the dy/dx + ll[0] = em[ii * nnei * 4 + jj * 4 + 0]; + ll[1] = em[ii * nnei * 4 + jj * 4 + 1]; + ll[2] = em[ii * nnei * 4 + jj * 4 + 2]; + ll[3] = em[ii * nnei * 4 + jj * 4 + 3]; + FPTYPE xx = em_x[ii * nnei + jj]; + if (ago == xx) { + unloop = true; + } + int table_idx = 0; + locate_xx(lower, upper, _max, stride0, stride1, xx, table_idx); + FPTYPE grad = 0.0; + for (int kk = 0; kk < last_layer_size; kk++) { + rr[0] = dy[ii * last_layer_size * 4 + 0 * last_layer_size + kk]; + rr[1] = dy[ii * last_layer_size * 4 + 1 * last_layer_size + kk]; + rr[2] = dy[ii * last_layer_size * 4 + 2 * last_layer_size + kk]; + rr[3] = dy[ii * last_layer_size * 4 + 3 * last_layer_size + kk]; + FPTYPE a0 = table[table_idx * last_layer_size * 6 + 6 * kk + 0]; + FPTYPE a1 = table[table_idx * last_layer_size * 6 + 6 * kk + 1]; + FPTYPE a2 = table[table_idx * last_layer_size * 6 + 6 * kk + 2]; + FPTYPE a3 = table[table_idx * last_layer_size * 6 + 6 * kk + 3]; + FPTYPE a4 = table[table_idx * last_layer_size * 6 + 6 * kk + 4]; + FPTYPE a5 = table[table_idx * last_layer_size * 6 + 6 * kk + 5]; + FPTYPE res = a0 + (a1 + (a2 + (a3 + (a4 + a5 * xx) * xx) * xx) * xx) * xx; + + if (unloop) { + grad += (a1 + (2 * a2 + (3 * a3 + (4 * a4 + 5 * a5 * xx) * xx) * xx) * xx) * dot(ll, rr) * (nnei - jj); + dy_dem[ii * nnei * 4 + jj * 4 + 0] += res * rr[0] * (nnei - jj); + dy_dem[ii * nnei * 4 + jj * 4 + 1] += res * rr[1] * (nnei - jj); + dy_dem[ii * nnei * 4 + jj * 4 + 2] += res * rr[2] * (nnei - jj); + dy_dem[ii * nnei * 4 + jj * 4 + 3] += res * rr[3] * (nnei - jj); + } + else { + grad += (a1 + (2 * a2 + (3 * a3 + (4 * a4 + 5 * a5 * xx) * xx) * xx) * xx) * dot(ll, rr); + dy_dem[ii * nnei * 4 + jj * 4 + 0] += res * rr[0]; + dy_dem[ii * nnei * 4 + jj * 4 + 1] += res * rr[1]; + dy_dem[ii * nnei * 4 + jj * 4 + 2] += res * rr[2]; + dy_dem[ii * nnei * 4 + jj * 4 + 3] += res * rr[3]; + } + } + dy_dem_x[ii * nnei + jj] = grad; + if (unloop) break; + } + } +} + +template void tabulate_fusion_cpu(float * out, const float * table, const float * table_info, const float * em_x, const float * em, const int nloc, const int nnei, const int last_layer_size); +template void tabulate_fusion_cpu(double * out, const double * table, const double * table_info, const double * em_x, const double * em, const int nloc, const int nnei, const int last_layer_size); +template void tabulate_fusion_grad_cpu (float * dy_dem_x, float * dy_dem, const float * table, const float * table_info, const float * em_x, const float * em, const float * dy, const int nloc, const int nnei, const int last_layer_size); +template void tabulate_fusion_grad_cpu (double * dy_dem_x, double * dy_dem, const double * table, const double * table_info, const double * em_x, const double * em, const double * dy, const int nloc, const int nnei, const int last_layer_size); diff --git a/source/lib/tests/test_env_mat_a.cc b/source/lib/tests/test_env_mat_a.cc index 572c363ee8..ffdfb73eba 100644 --- a/source/lib/tests/test_env_mat_a.cc +++ b/source/lib/tests/test_env_mat_a.cc @@ -582,7 +582,7 @@ TEST_F(TestEnvMatA, prod_gpu_nv) malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); - prod_env_mat_a_gpu_nv( + prod_env_mat_a_gpu_cuda( em_dev, em_deriv_dev, rij_dev, @@ -683,7 +683,7 @@ TEST_F(TestEnvMatA, prod_gpu_nv_equal_cpu) malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); - prod_env_mat_a_gpu_nv( + prod_env_mat_a_gpu_cuda( em_dev, em_deriv_dev, rij_dev, diff --git a/source/op/CMakeLists.txt b/source/op/CMakeLists.txt index b0a052ef17..b959bde9b4 100644 --- a/source/op/CMakeLists.txt +++ b/source/op/CMakeLists.txt @@ -3,8 +3,8 @@ set(OP_LIB ${PROJECT_SOURCE_DIR}/lib/src/SimulationRegion.cpp ${PROJECT_SOURCE_DIR}/lib/src/neighbor_list.cc) set (OP_CXX_FLAG -D_GLIBCXX_USE_CXX11_ABI=${OP_CXX_ABI} ) -file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc descrpt_se_r.cc pair_tab.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc gelu.cc map_aparam.cc neighbor_stat.cc unaggregated_grad.cc tabulate.cc) -file(GLOB OP_CUDA_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a_multi_device.cc descrpt_se_r_multi_device.cc pair_tab.cc prod_force_se_a_multi_device.cc prod_virial_se_a_multi_device.cc prod_force_se_r_multi_device.cc prod_virial_se_r_multi_device.cc soft_min.cc soft_min_force.cc soft_min_virial.cc gelu_multi_device.cc tabulate_multi_device.cc) +file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc descrpt_se_r.cc pair_tab.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc gelu_multi_device.cc map_aparam.cc neighbor_stat.cc unaggregated_grad.cc tabulate_multi_device.cc) +file(GLOB OP_CUDA_SRC prod_force.cc prod_virial.cc descrpt.cc prod_env_mat_multi_device.cc pair_tab.cc prod_force_multi_device.cc prod_virial_multi_device.cc soft_min.cc soft_min_force.cc soft_min_virial.cc gelu_multi_device.cc tabulate_multi_device.cc) file(GLOB OP_GRADS_SRC prod_force_grad.cc prod_force_se_a_grad.cc prod_force_se_r_grad.cc prod_virial_grad.cc prod_virial_se_a_grad.cc prod_virial_se_r_grad.cc soft_min_force_grad.cc soft_min_virial_grad.cc ) file(GLOB OP_PY *.py) @@ -22,6 +22,9 @@ endif (BUILD_CPP_IF) if (BUILD_PY_IF) set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) set(CMAKE_INSTALL_RPATH $ORIGIN) + set(LIB_BASE_DIR ${CMAKE_SOURCE_DIR}) + include_directories(${LIB_BASE_DIR}/api_cc/include) + MESSAGE( STATUS ${LIB_BASE_DIR}) if (USE_CUDA_TOOLKIT) add_library(op_abi SHARED ${OP_SRC} ${OP_LIB}) add_library(op_grads SHARED ${OP_GRADS_SRC}) diff --git a/source/op/descrpt.cc b/source/op/descrpt.cc index a9e08e5d6d..bd6693d520 100644 --- a/source/op/descrpt.cc +++ b/source/op/descrpt.cc @@ -1,20 +1,8 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "ComputeDescriptor.h" #include "neighbor_list.h" #include "fmt_nlist.h" -typedef double boxtensor_t ; -typedef double compute_t; - -using namespace tensorflow; -// using namespace std; - -using CPUDevice = Eigen::ThreadPoolDevice; - REGISTER_OP("Descrpt") .Attr("T: {float, double}") .Input("coord: T") diff --git a/source/op/descrpt_se_a.cc b/source/op/descrpt_se_a.cc index 306724851b..99b9f0f5ca 100644 --- a/source/op/descrpt_se_a.cc +++ b/source/op/descrpt_se_a.cc @@ -1,22 +1,9 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "ComputeDescriptor.h" #include "neighbor_list.h" #include "fmt_nlist.h" #include "env_mat.h" -typedef double boxtensor_t ; -typedef double compute_t; - -using namespace tensorflow; -// using namespace std; - -using CPUDevice = Eigen::ThreadPoolDevice; -using GPUDevice = Eigen::GpuDevice; - REGISTER_OP("DescrptSeA") .Attr("T: {float, double}") .Input("coord: T") //atomic coordinates diff --git a/source/op/descrpt_se_a_ef.cc b/source/op/descrpt_se_a_ef.cc index fa554c5d0f..5c30ed19dd 100644 --- a/source/op/descrpt_se_a_ef.cc +++ b/source/op/descrpt_se_a_ef.cc @@ -1,21 +1,9 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include +#include "custom_op.h" #include "ComputeDescriptor.h" #include "neighbor_list.h" #include "fmt_nlist.h" -typedef double boxtensor_t ; -typedef double compute_t; - -using namespace tensorflow; -// using namespace std; - -using CPUDevice = Eigen::ThreadPoolDevice; -using GPUDevice = Eigen::GpuDevice; - REGISTER_OP("DescrptSeAEf") .Attr("T: {float, double}") .Input("coord: T") diff --git a/source/op/descrpt_se_a_ef_para.cc b/source/op/descrpt_se_a_ef_para.cc index 54fe809d63..1f7819601e 100644 --- a/source/op/descrpt_se_a_ef_para.cc +++ b/source/op/descrpt_se_a_ef_para.cc @@ -1,20 +1,8 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "ComputeDescriptor.h" #include "neighbor_list.h" #include "fmt_nlist.h" -typedef double boxtensor_t ; -typedef double compute_t; - -using namespace tensorflow; -// using namespace std; -using CPUDevice = Eigen::ThreadPoolDevice; -using GPUDevice = Eigen::GpuDevice; - REGISTER_OP("DescrptSeAEfPara") .Attr("T: {float, double}") .Input("coord: T") diff --git a/source/op/descrpt_se_a_ef_vert.cc b/source/op/descrpt_se_a_ef_vert.cc index ee73db7d70..fca75a0ce6 100644 --- a/source/op/descrpt_se_a_ef_vert.cc +++ b/source/op/descrpt_se_a_ef_vert.cc @@ -1,21 +1,8 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "ComputeDescriptor.h" #include "neighbor_list.h" #include "fmt_nlist.h" -typedef double boxtensor_t ; -typedef double compute_t; - -using namespace tensorflow; -// using namespace std; - -using CPUDevice = Eigen::ThreadPoolDevice; -using GPUDevice = Eigen::GpuDevice; - REGISTER_OP("DescrptSeAEfVert") .Attr("T: {float, double}") .Input("coord: T") diff --git a/source/op/descrpt_se_r.cc b/source/op/descrpt_se_r.cc index 37b22df698..0da2d8ef6b 100644 --- a/source/op/descrpt_se_r.cc +++ b/source/op/descrpt_se_r.cc @@ -1,21 +1,9 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "ComputeDescriptor.h" #include "neighbor_list.h" #include "fmt_nlist.h" #include "env_mat.h" -typedef double boxtensor_t ; -typedef double compute_t; - -using namespace tensorflow; -// using namespace std; - -using CPUDevice = Eigen::ThreadPoolDevice; - REGISTER_OP("DescrptSeR") .Attr("T: {float, double}") .Input("coord: T") diff --git a/source/op/descrpt_se_r_multi_device.cc b/source/op/descrpt_se_r_multi_device.cc deleted file mode 100644 index ca4262fbd3..0000000000 --- a/source/op/descrpt_se_r_multi_device.cc +++ /dev/null @@ -1,272 +0,0 @@ -#include "common.h" -#include "utilities.h" -#include "CustomeOperation.h" - -REGISTER_OP("DescrptSeR") - .Attr("T: {float, double}") - .Input("coord: T") - .Input("type: int32") - .Input("natoms: int32") - .Input("box: T") - .Input("mesh: int32") - .Input("davg: T") - .Input("dstd: T") - .Attr("rcut: float") - .Attr("rcut_smth: float") - .Attr("sel: list(int)") - .Output("descrpt: T") - .Output("descrpt_deriv: T") - .Output("rij: T") - .Output("nlist: int32"); - -template -struct DescrptSeRFunctor { - void operator()(const CPUDevice& d, const T * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const T * avg, const T * std, T * descrpt, T * descrpt_deriv, T * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { - DescrptSeRCPULauncher(coord, type, ilist, jrange, jlist, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ntypes, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); - } - - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const T * coord, const int * type, const int * mesh, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const T * avg, const T * std, T * descrpt, T * descrpt_deriv, T * rij, int * nlist, const int nloc, const int nall, const int nnei, const int ntypes, const int ndescrpt, const float rcut_r, const float rcut_r_smth, const std::vector sec_a, const bool fill_nei_a, const int max_nbor_size) { - DescrptSeRGPULauncher(coord, type, ilist, jrange, jlist, array_int, array_longlong, avg, std, descrpt, descrpt_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, rcut_r, rcut_r_smth, sec_a, fill_nei_a, max_nbor_size); - } - #endif // GOOGLE_CUDA -}; - -template -class DescrptSeROp : public OpKernel { -public: - explicit DescrptSeROp(OpKernelConstruction* context) : OpKernel(context) { - OP_REQUIRES_OK(context, context->GetAttr("rcut", &rcut)); - OP_REQUIRES_OK(context, context->GetAttr("rcut_smth", &rcut_smth)); - OP_REQUIRES_OK(context, context->GetAttr("sel", &sel)); - cum_sum (sec, sel); - sel_null.resize(3, 0); - cum_sum (sec_null, sel_null); - ndescrpt = sec.back() * 1; - nnei = sec.back(); - fill_nei_a = true; - max_nbor_size = 1024; - } - - void Compute(OpKernelContext* context) override { - // Grab the input tensor - int context_input_index = 0; - const Tensor& coord_tensor = context->input(context_input_index++); - const Tensor& type_tensor = context->input(context_input_index++); - const Tensor& natoms_tensor = context->input(context_input_index++); - const Tensor& box_tensor = context->input(context_input_index++); - const Tensor& mesh_tensor = context->input(context_input_index++); - const Tensor& avg_tensor = context->input(context_input_index++); - const Tensor& std_tensor = context->input(context_input_index++); - - // set size of the sample - OP_REQUIRES (context, (coord_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of coord should be 2")); - OP_REQUIRES (context, (type_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of type should be 2")); - OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); - OP_REQUIRES (context, (box_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of box should be 2")); - OP_REQUIRES (context, (mesh_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of mesh should be 1")); - OP_REQUIRES (context, (avg_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of avg should be 2")); - OP_REQUIRES (context, (std_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of std should be 2")); - OP_REQUIRES (context, (fill_nei_a), errors::InvalidArgument ("Rotational free descriptor only support the case rcut_a < 0")); - - OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); - - DeviceFunctor() ( - device, - context->eigen_device() - ); - - const int * natoms = natoms_tensor.flat().data(); - int nloc = natoms[0]; - int nall = natoms[1]; - int ntypes = natoms_tensor.shape().dim_size(0) - 2; //nloc and nall mean something. - int nsamples = coord_tensor.shape().dim_size(0); - // - //// check the sizes - // check the sizes - OP_REQUIRES (context, (nsamples == type_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (nsamples == box_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (ntypes == avg_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of avg should be ntype")); - OP_REQUIRES (context, (ntypes == std_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of std should be ntype")); - - OP_REQUIRES (context, (nall * 3 == coord_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); - OP_REQUIRES (context, (nall == type_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); - OP_REQUIRES (context, (9 == box_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of box should be 9")); - OP_REQUIRES (context, (ndescrpt == avg_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of avg should be ndescrpt")); - OP_REQUIRES (context, (ndescrpt == std_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of std should be ndescrpt")); - - // Create an output tensor - TensorShape descrpt_shape ; - descrpt_shape.AddDim (nsamples); - descrpt_shape.AddDim (nloc * ndescrpt); - TensorShape descrpt_deriv_shape ; - descrpt_deriv_shape.AddDim (nsamples); - descrpt_deriv_shape.AddDim (nloc * ndescrpt * 3); - TensorShape rij_shape ; - rij_shape.AddDim (nsamples); - rij_shape.AddDim (nloc * nnei * 3); - TensorShape nlist_shape ; - nlist_shape.AddDim (nsamples); - nlist_shape.AddDim (nloc * nnei); - - int context_output_index = 0; - Tensor* descrpt_tensor = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - descrpt_shape, - &descrpt_tensor)); - Tensor* descrpt_deriv_tensor = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - descrpt_deriv_shape, - &descrpt_deriv_tensor)); - Tensor* rij_tensor = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - rij_shape, - &rij_tensor)); - Tensor* nlist_tensor = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - nlist_shape, - &nlist_tensor)); - - if(device == "GPU") { - // allocate temp memory, temp memory must not be used after this operation! - Tensor int_temp; - TensorShape int_shape; - int_shape.AddDim(sec.size() + nloc * sec.size() + nloc); - OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); - Tensor uint64_temp; - TensorShape uint64_shape; - uint64_shape.AddDim(nloc * GPU_MAX_NBOR_SIZE * 2); - OP_REQUIRES_OK(context, context->allocate_temp(DT_UINT64, uint64_shape, &uint64_temp)); - - array_int = int_temp.flat().data(); - array_longlong = uint64_temp.flat().data(); - - nbor_update(mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); - OP_REQUIRES (context, (max_nbor_size <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than " + std::to_string(GPU_MAX_NBOR_SIZE) + ", which currently is not supported by deepmd-kit.")); - } - else if (device == "CPU") { - memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy (&jrange, 8 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy (&jlist, 12 + mesh_tensor.flat().data(), sizeof(int *)); - } - - DescrptSeRFunctor()( - context->eigen_device(), // define actually graph execution device - coord_tensor.matrix().data(), // related to the kk argument - type_tensor.matrix().data(), // also related to the kk argument - mesh_tensor.flat().data(), - ilist, - jrange, - jlist, - array_int, - array_longlong, - avg_tensor.matrix().data(), - std_tensor.matrix().data(), - descrpt_tensor->matrix().data(), - descrpt_deriv_tensor->matrix().data(), - rij_tensor->matrix().data(), - nlist_tensor->matrix().data(), - nloc, - nall, - nnei, - ntypes, - ndescrpt, - rcut, - rcut_smth, - sec, - fill_nei_a, - max_nbor_size - ); - } - -///////////////////////////////////////////////////////////////////////////////////////////// - -private: - float rcut; - float rcut_smth; - std::vector sel; - std::vector sel_null; - std::vector sec; - std::vector sec_null; - int nnei, ndescrpt, nloc, nall; - bool fill_nei_a; - - //private func - void cum_sum (std::vector & sec, const std::vector & n_sel) const { - sec.resize (n_sel.size() + 1); - sec[0] = 0; - for (int ii = 1; ii < sec.size(); ++ii) { - sec[ii] = sec[ii-1] + n_sel[ii-1]; - } - } - - int max_nbor_size; - std::string device; - int *array_int; - unsigned long long*array_longlong; - int * ilist = NULL, * jrange = NULL, * jlist = NULL; - int ilist_size = 0, jrange_size = 0, jlist_size = 0; - bool init = false; - - void nbor_update(const int * mesh, const int size) { - int *mesh_host = new int[size], *ilist_host = NULL, *jrange_host = NULL, *jlist_host = NULL; - cudaErrcheck(cudaMemcpy(mesh_host, mesh, sizeof(int) * size, cudaMemcpyDeviceToHost)); - memcpy (&ilist_host, 4 + mesh_host, sizeof(int *)); - memcpy (&jrange_host, 8 + mesh_host, sizeof(int *)); - memcpy (&jlist_host, 12 + mesh_host, sizeof(int *)); - int const ago = mesh_host[0]; - if (!init) { - ilist_size = (int)(mesh_host[1] * 1.2); - jrange_size = (int)(mesh_host[2] * 1.2); - jlist_size = (int)(mesh_host[3] * 1.2); - cudaErrcheck(cudaMalloc((void **)&ilist, sizeof(int) * ilist_size)); - cudaErrcheck(cudaMalloc((void **)&jrange, sizeof(int) * jrange_size)); - cudaErrcheck(cudaMalloc((void **)&jlist, sizeof(int) * jlist_size)); - init = true; - } - if (ago == 0) { - if (ilist_size < mesh_host[1]) { - ilist_size = (int)(mesh_host[1] * 1.2); - cudaErrcheck(cudaFree(ilist)); - cudaErrcheck(cudaMalloc((void **)&ilist, sizeof(int) * ilist_size)); - } - if (jrange_size < mesh_host[2]) { - jrange_size = (int)(mesh_host[2] * 1.2); - cudaErrcheck(cudaFree(jrange)); - cudaErrcheck(cudaMalloc((void **)&jrange,sizeof(int) * jrange_size)); - } - if (jlist_size < mesh_host[3]) { - jlist_size = (int)(mesh_host[3] * 1.2); - cudaErrcheck(cudaFree(jlist)); - cudaErrcheck(cudaMalloc((void **)&jlist, sizeof(int) * jlist_size)); - } - cudaErrcheck(cudaMemcpy(ilist, ilist_host, sizeof(int) * mesh_host[1], cudaMemcpyHostToDevice)); - cudaErrcheck(cudaMemcpy(jrange, jrange_host, sizeof(int) * mesh_host[2], cudaMemcpyHostToDevice)); - cudaErrcheck(cudaMemcpy(jlist, jlist_host, sizeof(int) * mesh_host[3], cudaMemcpyHostToDevice)); - - max_nbor_size = 1024; - for(int ii = 0; ii < mesh_host[2]; ii++) { - max_nbor_size = (jrange_host[ii + 1] - jrange_host[ii]) > max_nbor_size ? (jrange_host[ii + 1] - jrange_host[ii]) : max_nbor_size; - } - } - delete [] mesh_host; - } - -}; - -// Register the CPU kernels. -#define REGISTER_CPU(T) \ -REGISTER_KERNEL_BUILDER( \ - Name("DescrptSeR").Device(DEVICE_CPU).TypeConstraint("T"), \ - DescrptSeROp); -REGISTER_CPU(float); -REGISTER_CPU(double); -// Register the GPU kernels. -#if GOOGLE_CUDA -#define REGISTER_GPU(T) \ -REGISTER_KERNEL_BUILDER( \ - Name("DescrptSeR").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ - DescrptSeROp); -REGISTER_GPU(float); -REGISTER_GPU(double); -#endif // GOOGLE_CUDA diff --git a/source/op/ewald_recp.cc b/source/op/ewald_recp.cc index b2b1356330..739cb5faca 100644 --- a/source/op/ewald_recp.cc +++ b/source/op/ewald_recp.cc @@ -1,17 +1,6 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "Ewald.h" -typedef double boxtensor_t ; - -using namespace tensorflow; -// using namespace std; - -using CPUDevice = Eigen::ThreadPoolDevice; - REGISTER_OP("EwaldRecp") .Attr("T: {float, double}") .Input("coord: T") diff --git a/source/op/gelu.cc b/source/op/gelu.cc deleted file mode 100644 index 7012438db9..0000000000 --- a/source/op/gelu.cc +++ /dev/null @@ -1,206 +0,0 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/register_types.h" -#include "tensorflow/core/framework/shape_inference.h" - -using namespace tensorflow; -using CPUDevice = Eigen::ThreadPoolDevice; -using GPUDevice = Eigen::GpuDevice; -#define SQRT_2_PI 0.7978845608028654 - -REGISTER_OP("Gelu") - .Attr("T: {float, double}") - .Input("x: T") - .Output("output: T"); - -REGISTER_OP("GeluGrad") - .Attr("T: {float, double}") - .Input("dy: T") - .Input("x: T") - .Output("output: T"); - -REGISTER_OP("GeluGradGrad") - .Attr("T: {float, double}") - .Input("dy: T") - .Input("dy_: T") - .Input("x: T") - .Output("output: T"); - -#if GOOGLE_CUDA -// maybe instead use cudnn activation forward -void GeluLauncher(const float * in, float * out, int const size); -void GeluLauncher(const double * in, double * out, int const size); -void GeluGradLauncher(const float * dy, const float * in, float * out, int const size); -void GeluGradLauncher(const double * dy, const double * in, double * out, int const size); -void GeluGradGradLauncher(const float * dy, const float * dy_, const float * in, float * out, int const size); -void GeluGradGradLauncher(const double * dy, const double * dy_, const double * in, double * out, int const size); -#endif // GOOGLE_CUDa - -template -struct GeluFunctor { - void operator()(const CPUDevice& d, const FPTYPE * in, FPTYPE * out, int const size) { - #pragma omp parallel for - for (int ii = 0; ii < size; ii++) { - out[ii] = in[ii] * 0.5 * (1.0 + tanh(SQRT_2_PI * (in[ii] + 0.044715 * in[ii] * in[ii] * in[ii]))); - } - } - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const FPTYPE * in, FPTYPE * out, int const size) { - GeluLauncher(in, out, size); - } - #endif -}; - -template -struct GeluGradFunctor { - void operator()(const CPUDevice& d, const FPTYPE * dy, const FPTYPE * in, FPTYPE * out, int const size) { - #pragma omp parallel for - for (int ii = 0; ii < size; ii++) { - FPTYPE const var1 = tanh(SQRT_2_PI * (in[ii] + 0.044715 * in[ii] * in[ii] *in[ii])); - out[ii] = dy[ii] * (0.5 * SQRT_2_PI * in[ii] * (1 - var1 * var1) * (0.134145 * in[ii] * in[ii] + 1) + 0.5 * var1 + 0.5); - } - } - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const FPTYPE * dy, const FPTYPE * in, FPTYPE * out, int const size) { - GeluGradLauncher(dy, in, out, size); - } - #endif -}; - -template -struct GeluGradGradFunctor { - void operator()(const CPUDevice& d, const FPTYPE * dy, const FPTYPE * dy_, const FPTYPE * in, FPTYPE * out, int const size) { - #pragma omp parallel for - for (int ii = 0; ii < size; ii++) { - FPTYPE const var1 = tanh(SQRT_2_PI * (in[ii] + 0.044715 * in[ii] * in[ii] *in[ii])); - FPTYPE const var2 = SQRT_2_PI * (1 - var1 * var1) * (0.134145 * in[ii] * in[ii] + 1); - - out[ii] = dy[ii] * dy_[ii] * (0.134145 * SQRT_2_PI * in[ii] * in[ii] * (1 - var1 * var1) - SQRT_2_PI * in[ii] * var2 * (0.134145 * in[ii] * in[ii] + 1) * var1 + var2); - } - } - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const FPTYPE * dy, const FPTYPE * dy_, const FPTYPE * in, FPTYPE * out, int const size) { - GeluGradGradLauncher(dy, dy_, in, out, size); - } - #endif -}; - -// OpKernel definition. -// template parameter is the datatype of the tensors. -template -class GeluOp : public OpKernel { - public : - explicit GeluOp(OpKernelConstruction* context) : OpKernel(context) {} - - void Compute(OpKernelContext* context) override { - // Grab the input tensor - const Tensor& x = context->input(0); - Tensor * output = NULL; - int context_output_index = 0; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - x.shape(), - &output)); - - GeluFunctor()( - context->eigen_device(), - x.flat().data(), - output->flat().data(), - static_cast(output->NumElements()) - ); - // GeluLauncher(x.flat().data(), output->flat().data(), static_cast(output->NumElements())); - } -}; - -// OpKernel definition. -// template parameter is the datatype of the tensors. -template -class GeluGradOp : public OpKernel { - public : - explicit GeluGradOp(OpKernelConstruction* context) : OpKernel(context) {} - - void Compute(OpKernelContext* context) override { - // Grab the input tensor - const Tensor& dy = context->input(0); - const Tensor& x = context->input(1); - - Tensor * output = NULL; - int context_output_index = 0; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - x.shape(), - &output)); - - GeluGradFunctor()( - context->eigen_device(), - dy.flat().data(), - x.flat().data(), - output->flat().data(), - static_cast(output->NumElements()) - ); - // GeluGradLauncher(dy.flat().data(), x.flat().data(), output->flat().data(), static_cast(output->NumElements())); - } -}; - -// OpKernel definition. -// template parameter is the datatype of the tensors. -template -class GeluGradGradOp : public OpKernel { - public : - explicit GeluGradGradOp(OpKernelConstruction* context) : OpKernel(context) {} - - void Compute(OpKernelContext* context) override { - // Grab the input tensor - const Tensor& dy = context->input(0); - const Tensor& dy_ = context->input(1); - const Tensor& x = context->input(2); - - Tensor * output = NULL; - int context_output_index = 0; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - x.shape(), - &output)); - - GeluGradGradFunctor()( - context->eigen_device(), - dy.flat().data(), - dy_.flat().data(), - x.flat().data(), - output->flat().data(), - static_cast(output->NumElements()) - ); - // GeluGradGradLauncher(dy.flat().data(), x.flat().data(), output->flat().data(), static_cast(output->NumElements())); - } -}; - -#define REGISTER_CPU(T) \ -/* Declare explicit instantiations in kernel_example.cu.cc. */ \ -REGISTER_KERNEL_BUILDER( \ - Name("Gelu").Device(DEVICE_CPU).TypeConstraint("T"), \ - GeluOp); \ -/* Declare explicit instantiations in kernel_example.cu.cc. */ \ -REGISTER_KERNEL_BUILDER( \ - Name("GeluGrad").Device(DEVICE_CPU).TypeConstraint("T"), \ - GeluGradOp); \ -/* Declare explicit instantiations in kernel_example.cu.cc. */ \ -REGISTER_KERNEL_BUILDER( \ - Name("GeluGradGrad").Device(DEVICE_CPU).TypeConstraint("T"), \ - GeluGradGradOp); -REGISTER_CPU(float); -REGISTER_CPU(double); - -#if GOOGLE_CUDA -#define REGISTER_GPU(T) \ -/* Declare explicit instantiations in kernel_example.cu.cc. */ \ -REGISTER_KERNEL_BUILDER( \ - Name("Gelu").Device(DEVICE_GPU).TypeConstraint("T"), \ - GeluOp); \ -/* Declare explicit instantiations in kernel_example.cu.cc. */ \ -REGISTER_KERNEL_BUILDER( \ - Name("GeluGrad").Device(DEVICE_GPU).TypeConstraint("T"), \ - GeluGradOp); \ -/* Declare explicit instantiations in kernel_example.cu.cc. */ \ -REGISTER_KERNEL_BUILDER( \ - Name("GeluGradGrad").Device(DEVICE_GPU).TypeConstraint("T"), \ - GeluGradGradOp); -REGISTER_GPU(float); -REGISTER_GPU(double); -#endif // GOOGLE_CUDA diff --git a/source/op/gelu_multi_device.cc b/source/op/gelu_multi_device.cc index f84c9c0f9f..4ea7afad17 100644 --- a/source/op/gelu_multi_device.cc +++ b/source/op/gelu_multi_device.cc @@ -1,5 +1,5 @@ -#include "common.h" -#include "CustomeOperation.h" +#include "custom_op.h" +#include "gelu.h" REGISTER_OP("Gelu") .Attr("T: {float, double}") @@ -19,123 +19,129 @@ REGISTER_OP("GeluGradGrad") .Input("x: T") .Output("output: T"); -template -struct GeluFunctor { - void operator()(const CPUDevice& d, const FPTYPE * in, FPTYPE * out, int const size) { - GeluCPULauncher(in, out, size); - } - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const FPTYPE * in, FPTYPE * out, int const size) { - GeluGPULauncher(in, out, size); - } - #endif -}; - -template -struct GeluGradFunctor { - void operator()(const CPUDevice& d, const FPTYPE * dy, const FPTYPE * in, FPTYPE * out, int const size) { - GeluGradCPULauncher(dy, in, out, size); - } - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const FPTYPE * dy, const FPTYPE * in, FPTYPE * out, int const size) { - GeluGradGPULauncher(dy, in, out, size); - } - #endif -}; - -template -struct GeluGradGradFunctor { - void operator()(const CPUDevice& d, const FPTYPE * dy, const FPTYPE * dy_, const FPTYPE * in, FPTYPE * out, int const size) { - GeluGradGradCPULauncher(dy, dy_, in, out, size); - } - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const FPTYPE * dy, const FPTYPE * dy_, const FPTYPE * in, FPTYPE * out, int const size) { - GeluGradGradGPULauncher(dy, dy_, in, out, size); - } - #endif -}; - // OpKernel definition. // template parameter is the datatype of the tensors. template class GeluOp : public OpKernel { - public : - explicit GeluOp(OpKernelConstruction* context) : OpKernel(context) {} + public : + explicit GeluOp(OpKernelConstruction* context) : OpKernel(context) {} + void Compute(OpKernelContext* context) override { + // Grab the input tensor + const Tensor& x_tensor = context->input(0); + Tensor * output_tensor = NULL; + int context_output_index = 0; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + x_tensor.shape(), + &output_tensor)); + DeviceFunctor() ( + device, + context->eigen_device() + ); + // flat the tensors + FPTYPE * out = output_tensor->flat().data(); + const FPTYPE * x = x_tensor.flat().data(); + const int size = static_cast(output_tensor->NumElements()); - void Compute(OpKernelContext* context) override { - // Grab the input tensor - const Tensor& x = context->input(0); - Tensor * output = NULL; - int context_output_index = 0; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - x.shape(), - &output)); - - GeluFunctor()( - context->eigen_device(), - x.flat().data(), - output->flat().data(), - static_cast(output->NumElements()) - ); + if (device == "GPU") { + #if GOOGLE_CUDA + gelu_gpu_cuda( + out, + x, size); + #endif // GOOGLE_CUDA + } + else if (device == "CPU") { + gelu_cpu( + out, + x, size); } + } + private : + std::string device; }; // OpKernel definition. // template parameter is the datatype of the tensors. template class GeluGradOp : public OpKernel { - public : - explicit GeluGradOp(OpKernelConstruction* context) : OpKernel(context) {} + public : + explicit GeluGradOp(OpKernelConstruction* context) : OpKernel(context) {} + void Compute(OpKernelContext* context) override { + // Grab the input tensor + const Tensor& dy_tensor = context->input(0); + const Tensor& x_tensor = context->input(1); + Tensor * output_tensor = NULL; + int context_output_index = 0; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + x_tensor.shape(), + &output_tensor)); + DeviceFunctor() ( + device, + context->eigen_device() + ); + // flat the tensors + FPTYPE * out = output_tensor->flat().data(); + const FPTYPE * x = x_tensor.flat().data(); + const FPTYPE * dy = dy_tensor.flat().data(); + const int size = static_cast(output_tensor->NumElements()); - void Compute(OpKernelContext* context) override { - // Grab the input tensor - const Tensor& dy = context->input(0); - const Tensor& x = context->input(1); - - Tensor * output = NULL; - int context_output_index = 0; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - x.shape(), - &output)); - - GeluGradFunctor()( - context->eigen_device(), - dy.flat().data(), - x.flat().data(), - output->flat().data(), - static_cast(output->NumElements()) - ); + if (device == "GPU") { + #if GOOGLE_CUDA + gelu_grad_gpu_cuda( + out, + x, dy, size); + #endif // GOOGLE_CUDA } + else if (device == "CPU") { + gelu_grad_cpu( + out, + x, dy, size); + } + } + private : + std::string device; }; // OpKernel definition. // template parameter is the datatype of the tensors. template class GeluGradGradOp : public OpKernel { - public : - explicit GeluGradGradOp(OpKernelConstruction* context) : OpKernel(context) {} - - void Compute(OpKernelContext* context) override { - // Grab the input tensor - const Tensor& dy = context->input(0); - const Tensor& dy_ = context->input(1); - const Tensor& x = context->input(2); - - Tensor * output = NULL; + public : + explicit GeluGradGradOp(OpKernelConstruction* context) : OpKernel(context) {} + void Compute(OpKernelContext* context) override { + // Grab the input tensor + const Tensor& dy_tensor = context->input(0); + const Tensor& dy_2_tensor = context->input(1); + const Tensor& x_tensor = context->input(2); + Tensor * output_tensor = NULL; int context_output_index = 0; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - x.shape(), - &output)); - - GeluGradGradFunctor()( - context->eigen_device(), - dy.flat().data(), - dy_.flat().data(), - x.flat().data(), - output->flat().data(), - static_cast(output->NumElements()) - ); + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + x_tensor.shape(), + &output_tensor)); + // flat the tensors + FPTYPE * out = output_tensor->flat().data(); + const FPTYPE * x = x_tensor.flat().data(); + const FPTYPE * dy = dy_tensor.flat().data(); + const FPTYPE * dy_2 = dy_2_tensor.flat().data(); + const int size = static_cast(output_tensor->NumElements()); + + if (device == "GPU") { + #if GOOGLE_CUDA + gelu_grad_grad_gpu_cuda( + out, + x, dy, dy_2, size); + #endif // GOOGLE_CUDA + } + else if (device == "CPU") { + gelu_grad_grad_cpu( + out, + x, dy, dy_2, size); } + } + private : + std::string device; }; #define REGISTER_CPU(T) \ diff --git a/source/op/map_aparam.cc b/source/op/map_aparam.cc index cd6543c401..1a08b678c3 100644 --- a/source/op/map_aparam.cc +++ b/source/op/map_aparam.cc @@ -1,16 +1,6 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "map_aparam.h" -using namespace tensorflow; -// using namespace std; - -using CPUDevice = Eigen::ThreadPoolDevice; -using GPUDevice = Eigen::GpuDevice; - REGISTER_OP("MapAparam") .Attr("T: {float, double}") .Input("aparam: T") diff --git a/source/op/neighbor_stat.cc b/source/op/neighbor_stat.cc index bbc82e9d98..13f3160089 100644 --- a/source/op/neighbor_stat.cc +++ b/source/op/neighbor_stat.cc @@ -1,19 +1,6 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "neighbor_list.h" -typedef double boxtensor_t ; -typedef double compute_t; - -using namespace tensorflow; -// using namespace std; - -using CPUDevice = Eigen::ThreadPoolDevice; -using GPUDevice = Eigen::GpuDevice; - REGISTER_OP("NeighborStat") .Attr("T: {float, double}") .Input("coord: T") diff --git a/source/op/pair_tab.cc b/source/op/pair_tab.cc index 0bfac34de1..31c2083cf7 100644 --- a/source/op/pair_tab.cc +++ b/source/op/pair_tab.cc @@ -1,14 +1,6 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "pair_tab.h" -using namespace tensorflow; -//using namespace std; - - REGISTER_OP("PairTab") .Attr("T: {float, double}") .Input("table_info: double") diff --git a/source/op/descrpt_se_a_multi_device.cc b/source/op/prod_env_mat_multi_device.cc similarity index 53% rename from source/op/descrpt_se_a_multi_device.cc rename to source/op/prod_env_mat_multi_device.cc index 213918da23..32d4f96cfe 100644 --- a/source/op/descrpt_se_a_multi_device.cc +++ b/source/op/prod_env_mat_multi_device.cc @@ -1,4 +1,4 @@ -#include "common.h" +#include "custom_op.h" #include "utilities.h" #include "prod_env_mat.h" @@ -22,6 +22,23 @@ REGISTER_OP("DescrptSeA") .Output("nlist: int32"); // only sel_a and rcut_r uesd. +REGISTER_OP("DescrptSeR") + .Attr("T: {float, double}") + .Input("coord: T") + .Input("type: int32") + .Input("natoms: int32") + .Input("box: T") + .Input("mesh: int32") + .Input("davg: T") + .Input("dstd: T") + .Attr("rcut: float") + .Attr("rcut_smth: float") + .Attr("sel: list(int)") + .Output("descrpt: T") + .Output("descrpt_deriv: T") + .Output("rij: T") + .Output("nlist: int32"); + template class DescrptSeAOp : public OpKernel { public: @@ -42,7 +59,6 @@ class DescrptSeAOp : public OpKernel { nnei_a = sec_a.back(); nnei_r = sec_r.back(); nnei = nnei_a + nnei_r; - fill_nei_a = (rcut_a < 0); max_nbor_size = 1024; } @@ -64,7 +80,6 @@ class DescrptSeAOp : public OpKernel { OP_REQUIRES (context, (mesh_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of mesh should be 1")); OP_REQUIRES (context, (avg_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of avg should be 2")); OP_REQUIRES (context, (std_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of std should be 2")); - OP_REQUIRES (context, (fill_nei_a), errors::InvalidArgument ("Rotational free descriptor only support the case rcut_a < 0")); OP_REQUIRES (context, (sec_r.back() == 0), errors::InvalidArgument ("Rotational free descriptor only support all-angular information: sel_r should be all zero.")); OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); DeviceFunctor() ( @@ -153,7 +168,7 @@ class DescrptSeAOp : public OpKernel { OP_REQUIRES (context, (max_nbor_size <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than " + std::to_string(GPU_MAX_NBOR_SIZE) + ", which currently is not supported by deepmd-kit.")); #if GOOGLE_CUDA // launch the gpu(nv) compute function - prod_env_mat_a_gpu_nv( + prod_env_mat_a_gpu_cuda( em, em_deriv, rij, nlist, coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, rcut_r, rcut_r_smth, sec_a); #endif //GOOGLE_CUDA @@ -180,7 +195,158 @@ class DescrptSeAOp : public OpKernel { std::vector sec_r; int ndescrpt, ndescrpt_a, ndescrpt_r; int nnei, nnei_a, nnei_r, nloc, nall, max_nbor_size; - bool fill_nei_a; + std::string device; + int * array_int = NULL; + unsigned long long * array_longlong = NULL; + bool init = false; + int * ilist = NULL, * jrange = NULL, * jlist = NULL; + int ilist_size = 0, jrange_size = 0, jlist_size = 0; +}; + +template +class DescrptSeROp : public OpKernel { +public: + explicit DescrptSeROp(OpKernelConstruction* context) : OpKernel(context) { + OP_REQUIRES_OK(context, context->GetAttr("rcut", &rcut)); + OP_REQUIRES_OK(context, context->GetAttr("rcut_smth", &rcut_smth)); + OP_REQUIRES_OK(context, context->GetAttr("sel", &sel)); + cum_sum (sec, sel); + sel_null.resize(3, 0); + cum_sum (sec_null, sel_null); + ndescrpt = sec.back() * 1; + nnei = sec.back(); + max_nbor_size = 1024; + } + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& coord_tensor = context->input(context_input_index++); + const Tensor& type_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); + const Tensor& box_tensor = context->input(context_input_index++); + const Tensor& mesh_tensor = context->input(context_input_index++); + const Tensor& avg_tensor = context->input(context_input_index++); + const Tensor& std_tensor = context->input(context_input_index++); + // set size of the sample + OP_REQUIRES (context, (coord_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of coord should be 2")); + OP_REQUIRES (context, (type_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of type should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + OP_REQUIRES (context, (box_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of box should be 2")); + OP_REQUIRES (context, (mesh_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of mesh should be 1")); + OP_REQUIRES (context, (avg_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of avg should be 2")); + OP_REQUIRES (context, (std_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of std should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + DeviceFunctor() ( + device, + context->eigen_device() + ); + const int * natoms = natoms_tensor.flat().data(); + int nloc = natoms[0]; + int nall = natoms[1]; + int ntypes = natoms_tensor.shape().dim_size(0) - 2; //nloc and nall mean something. + int nsamples = coord_tensor.shape().dim_size(0); + // + //// check the sizes + // check the sizes + OP_REQUIRES (context, (nsamples == type_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nsamples == box_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (ntypes == avg_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of avg should be ntype")); + OP_REQUIRES (context, (ntypes == std_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of std should be ntype")); + OP_REQUIRES (context, (nall * 3 == coord_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); + OP_REQUIRES (context, (nall == type_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); + OP_REQUIRES (context, (9 == box_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of box should be 9")); + OP_REQUIRES (context, (ndescrpt == avg_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of avg should be ndescrpt")); + OP_REQUIRES (context, (ndescrpt == std_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of std should be ndescrpt")); + // Create an output tensor + TensorShape descrpt_shape ; + descrpt_shape.AddDim (nsamples); + descrpt_shape.AddDim (nloc * ndescrpt); + TensorShape descrpt_deriv_shape ; + descrpt_deriv_shape.AddDim (nsamples); + descrpt_deriv_shape.AddDim (nloc * ndescrpt * 3); + TensorShape rij_shape ; + rij_shape.AddDim (nsamples); + rij_shape.AddDim (nloc * nnei * 3); + TensorShape nlist_shape ; + nlist_shape.AddDim (nsamples); + nlist_shape.AddDim (nloc * nnei); + + int context_output_index = 0; + Tensor* descrpt_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + descrpt_shape, + &descrpt_tensor)); + Tensor* descrpt_deriv_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + descrpt_deriv_shape, + &descrpt_deriv_tensor)); + Tensor* rij_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + rij_shape, + &rij_tensor)); + Tensor* nlist_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + nlist_shape, + &nlist_tensor)); + + FPTYPE * em = descrpt_tensor->flat().data(); + FPTYPE * em_deriv = descrpt_deriv_tensor->flat().data(); + FPTYPE * rij = rij_tensor->flat().data(); + int * nlist = nlist_tensor->flat().data(); + const FPTYPE * coord = coord_tensor.flat().data(); + const FPTYPE * avg = avg_tensor.flat().data(); + const FPTYPE * std = std_tensor.flat().data(); + const int * type = type_tensor.flat().data(); + + if(device == "GPU") { + // allocate temp memory, temp memory must not be used after this operation! + Tensor int_temp; + TensorShape int_shape; + int_shape.AddDim(sec.size() + nloc * sec.size() + nloc); + OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); + Tensor uint64_temp; + TensorShape uint64_shape; + uint64_shape.AddDim(nloc * GPU_MAX_NBOR_SIZE * 2); + OP_REQUIRES_OK(context, context->allocate_temp(DT_UINT64, uint64_shape, &uint64_temp)); + array_int = int_temp.flat().data(); + array_longlong = uint64_temp.flat().data(); + env_mat_nbor_update( + init, ilist, jrange, jlist, ilist_size, jrange_size, jlist_size, max_nbor_size, + mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); + OP_REQUIRES (context, (max_nbor_size <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than " + std::to_string(GPU_MAX_NBOR_SIZE) + ", which currently is not supported by deepmd-kit.")); + #if GOOGLE_CUDA + // launch the gpu(nv) compute function + prod_env_mat_r_gpu_cuda( + em, em_deriv, rij, nlist, + coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); + #endif //GOOGLE_CUDA + } + else if (device == "CPU") { + memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); + memcpy (&jrange, 8 + mesh_tensor.flat().data(), sizeof(int *)); + memcpy (&jlist, 12 + mesh_tensor.flat().data(), sizeof(int *)); + // launch the cpu compute function + prod_env_mat_r_cpu( + em, em_deriv, rij, nlist, + coord, type, ilist, jrange, jlist, max_nbor_size, avg, std, nloc, nall, ntypes, rcut, rcut_smth, sec); + } + } + +///////////////////////////////////////////////////////////////////////////////////////////// + +private: + float rcut; + float rcut_smth; + std::vector sel; + std::vector sel_null; + std::vector sec; + std::vector sec_null; + int nnei, ndescrpt, nloc, nall, max_nbor_size; std::string device; int * array_int = NULL; unsigned long long * array_longlong = NULL; @@ -193,15 +359,22 @@ class DescrptSeAOp : public OpKernel { #define REGISTER_CPU(T) \ REGISTER_KERNEL_BUILDER( \ Name("DescrptSeA").Device(DEVICE_CPU).TypeConstraint("T"), \ - DescrptSeAOp); + DescrptSeAOp); \ +REGISTER_KERNEL_BUILDER( \ + Name("DescrptSeR").Device(DEVICE_CPU).TypeConstraint("T"), \ + DescrptSeROp); REGISTER_CPU(float); REGISTER_CPU(double); + // Register the GPU kernels. #if GOOGLE_CUDA #define REGISTER_GPU(T) \ REGISTER_KERNEL_BUILDER( \ Name("DescrptSeA").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ - DescrptSeAOp); + DescrptSeAOp); \ +REGISTER_KERNEL_BUILDER( \ + Name("DescrptSeR").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ + DescrptSeROp); REGISTER_GPU(float); REGISTER_GPU(double); #endif // GOOGLE_CUDA diff --git a/source/op/prod_force.cc b/source/op/prod_force.cc index 382f807e53..e2c01cc211 100644 --- a/source/op/prod_force.cc +++ b/source/op/prod_force.cc @@ -1,10 +1,4 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - -using namespace tensorflow; -// using namespace std; +#include "custom_op.h" REGISTER_OP("ProdForce") .Attr("T: {float, double}") diff --git a/source/op/prod_force_grad.cc b/source/op/prod_force_grad.cc index 71992a110e..fff7afd25b 100644 --- a/source/op/prod_force_grad.cc +++ b/source/op/prod_force_grad.cc @@ -1,10 +1,4 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - -using namespace tensorflow; -// using namespace std; +#include "custom_op.h" REGISTER_OP("ProdForceGrad") .Attr("T: {float, double}") diff --git a/source/op/prod_force_multi_device.cc b/source/op/prod_force_multi_device.cc new file mode 100644 index 0000000000..f86d349149 --- /dev/null +++ b/source/op/prod_force_multi_device.cc @@ -0,0 +1,190 @@ +#include "custom_op.h" +#include "prod_force.h" + +REGISTER_OP("ProdForceSeA") + .Attr("T: {float, double}") + .Input("net_deriv: T") + .Input("in_deriv: T") + .Input("nlist: int32") + .Input("natoms: int32") + .Attr("n_a_sel: int") + .Attr("n_r_sel: int") + .Output("force: T"); + +REGISTER_OP("ProdForceSeR") + .Attr("T: {float, double}") + .Input("net_deriv: T") + .Input("in_deriv: T") + .Input("nlist: int32") + .Input("natoms: int32") + .Output("force: T"); + +template +class ProdForceSeAOp : public OpKernel { +public: + explicit ProdForceSeAOp(OpKernelConstruction* context) : OpKernel(context) {} + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& net_deriv_tensor = context->input(context_input_index++); + const Tensor& in_deriv_tensor = context->input(context_input_index++); + const Tensor& nlist_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); + // set size of the sample + OP_REQUIRES (context, (net_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of net deriv should be 2")); + OP_REQUIRES (context, (in_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); + OP_REQUIRES (context, (nlist_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + const int * natoms = natoms_tensor.flat().data(); + int nloc = natoms[0]; + int nall = natoms[1]; + int nframes = net_deriv_tensor.shape().dim_size(0); + int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; + int nnei = nlist_tensor.shape().dim_size(1) / nloc; + // check the sizes + OP_REQUIRES (context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nframes == nlist_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of descriptors should match")); + // Create an output tensor + TensorShape force_shape ; + force_shape.AddDim (nframes); + force_shape.AddDim (3 * nall); + Tensor* force_tensor = NULL; + int context_output_index = 0; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + force_shape, + &force_tensor)); + DeviceFunctor() ( + device, + context->eigen_device() + ); + assert (nframes == force_shape.dim_size(0)); + assert (nframes == net_deriv_tensor.shape().dim_size(0)); + assert (nframes == in_deriv_tensor.shape().dim_size(0)); + assert (nframes == nlist_tensor.shape().dim_size(0)); + assert (nall * 3 == force_shape.dim_size(1)); + assert (nloc * ndescrpt == net_deriv_tensor.shape().dim_size(1)); + assert (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)); + assert (nloc * nnei == nlist_tensor.shape().dim_size(1)); + assert (nnei * 4 == ndescrpt); + // flat the tensors + FPTYPE * force = force_tensor->flat().data(); + const FPTYPE * net_deriv = net_deriv_tensor.flat().data(); + const FPTYPE * in_deriv = in_deriv_tensor.flat().data(); + const int * nlist = nlist_tensor.flat().data(); + + if (device == "GPU") { + #if GOOGLE_CUDA + prod_force_a_gpu_cuda( + force, + net_deriv, in_deriv, nlist, nloc, nall, nnei); + #endif // GOOGLE_CUDA + } + else if (device == "CPU") { + prod_force_a_cpu( + force, + net_deriv, in_deriv, nlist, nloc, nall, nnei); + } + } + private: + std::string device; +}; + +template +class ProdForceSeROp : public OpKernel { +public: + explicit ProdForceSeROp(OpKernelConstruction* context) : OpKernel(context) {} + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& net_deriv_tensor = context->input(context_input_index++); + const Tensor& in_deriv_tensor = context->input(context_input_index++); + const Tensor& nlist_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); + // set size of the sample + OP_REQUIRES (context, (net_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of net deriv should be 2")); + OP_REQUIRES (context, (in_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); + OP_REQUIRES (context, (nlist_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + const int * natoms = natoms_tensor.flat().data(); + int nloc = natoms[0]; + int nall = natoms[1]; + int nframes = net_deriv_tensor.shape().dim_size(0); + int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; + int nnei = nlist_tensor.shape().dim_size(1) / nloc; + // check the sizes + OP_REQUIRES (context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nframes == nlist_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of descriptors should match")); + // Create an output tensor + TensorShape force_shape ; + force_shape.AddDim (nframes); + force_shape.AddDim (3 * nall); + Tensor* force_tensor = NULL; + int context_output_index = 0; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + force_shape, + &force_tensor)); + DeviceFunctor() ( + device, + context->eigen_device() + ); + assert (nframes == force_shape.dim_size(0)); + assert (nframes == net_deriv_tensor.shape().dim_size(0)); + assert (nframes == in_deriv_tensor.shape().dim_size(0)); + assert (nframes == nlist_tensor.shape().dim_size(0)); + assert (nall * 3 == force_shape.dim_size(1)); + assert (nloc * ndescrpt == net_deriv_tensor.shape().dim_size(1)); + assert (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)); + assert (nloc * nnei == nlist_tensor.shape().dim_size(1)); + assert (nnei * 4 == ndescrpt); + // flat the tensors + FPTYPE * force = force_tensor->flat().data(); + const FPTYPE * net_deriv = net_deriv_tensor.flat().data(); + const FPTYPE * in_deriv = in_deriv_tensor.flat().data(); + const int * nlist = nlist_tensor.flat().data(); + + if (device == "GPU") { + #if GOOGLE_CUDA + prod_force_r_gpu_cuda( + force, + net_deriv, in_deriv, nlist, nloc, nall, nnei); + #endif // GOOGLE_CUDA + } + else if (device == "CPU") { + prod_force_r_cpu( + force, + net_deriv, in_deriv, nlist, nloc, nall, nnei); + } + } + private: + std::string device; +}; + +// Register the CPU kernels. +#define REGISTER_CPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdForceSeA").Device(DEVICE_CPU).TypeConstraint("T"), \ + ProdForceSeAOp); \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdForceSeR").Device(DEVICE_CPU).TypeConstraint("T"), \ + ProdForceSeROp); +REGISTER_CPU(float); +REGISTER_CPU(double); +// Register the GPU kernels. +#if GOOGLE_CUDA +#define REGISTER_GPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdForceSeA").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ + ProdForceSeAOp); \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdForceSeR").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ + ProdForceSeROp); +REGISTER_GPU(float); +REGISTER_GPU(double); +#endif // GOOGLE_CUDA diff --git a/source/op/prod_force_se_a.cc b/source/op/prod_force_se_a.cc index 209253e98c..d286326c76 100644 --- a/source/op/prod_force_se_a.cc +++ b/source/op/prod_force_se_a.cc @@ -1,13 +1,6 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "prod_force.h" -using namespace tensorflow; -// using namespace std; - REGISTER_OP("ProdForceSeA") .Attr("T: {float, double}") .Input("net_deriv: T") diff --git a/source/op/prod_force_se_a_grad.cc b/source/op/prod_force_se_a_grad.cc index 15b3bbbbfd..aa8dd4e62b 100644 --- a/source/op/prod_force_se_a_grad.cc +++ b/source/op/prod_force_se_a_grad.cc @@ -1,13 +1,6 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "prod_force_grad.h" -using namespace tensorflow; -// using namespace std; - REGISTER_OP("ProdForceSeAGrad") .Attr("T: {float, double}") .Input("grad: T") diff --git a/source/op/prod_force_se_a_multi_device.cc b/source/op/prod_force_se_a_multi_device.cc deleted file mode 100644 index 87a3ae3ecc..0000000000 --- a/source/op/prod_force_se_a_multi_device.cc +++ /dev/null @@ -1,123 +0,0 @@ -#include "common.h" -#include "CustomeOperation.h" - -REGISTER_OP("ProdForceSeA") - .Attr("T: {float, double}") - .Input("net_deriv: T") - .Input("in_deriv: T") - .Input("nlist: int32") - .Input("natoms: int32") - .Attr("n_a_sel: int") - .Attr("n_r_sel: int") - .Output("force: T"); - -template -struct ProdForceSeAFunctor { - void operator()(const CPUDevice& d, FPTYPE * force, const FPTYPE * net_deriv, const FPTYPE * in_deriv, const int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const int n_a_sel, const int n_a_shift) { - ProdForceSeACPULauncher(force, net_deriv, in_deriv, nlist, nloc, nall, nnei, ndescrpt, n_a_sel, n_a_shift); - } - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, FPTYPE * force, const FPTYPE * net_deriv, const FPTYPE * in_deriv, const int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const int n_a_sel, const int n_a_shift) { - ProdForceSeAGPULauncher(force, net_deriv, in_deriv, nlist, nloc, nall, nnei, ndescrpt, n_a_sel, n_a_shift); - } - #endif // GOOGLE_CUDA -}; - -template -class ProdForceSeAOp : public OpKernel { -public: - explicit ProdForceSeAOp(OpKernelConstruction* context) : OpKernel(context) { - OP_REQUIRES_OK(context, context->GetAttr("n_a_sel", &n_a_sel)); - OP_REQUIRES_OK(context, context->GetAttr("n_r_sel", &n_r_sel)); - n_a_shift = n_a_sel * 4; - } - - void Compute(OpKernelContext* context) override { - // Grab the input tensor - int context_input_index = 0; - const Tensor& net_deriv_tensor = context->input(context_input_index++); - const Tensor& in_deriv_tensor = context->input(context_input_index++); - const Tensor& nlist_tensor = context->input(context_input_index++); - const Tensor& natoms_tensor = context->input(context_input_index++); - - // set size of the sample - OP_REQUIRES (context, (net_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of net deriv should be 2")); - OP_REQUIRES (context, (in_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); - OP_REQUIRES (context, (nlist_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); - OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); - - OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); - const int * natoms = natoms_tensor.flat().data(); - int nloc = natoms[0]; - int nall = natoms[1]; - int nframes = net_deriv_tensor.shape().dim_size(0); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; - - // check the sizes - OP_REQUIRES (context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (nframes == nlist_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - - OP_REQUIRES (context, (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of descriptors should match")); - OP_REQUIRES (context, (nnei == n_a_sel + n_r_sel), errors::InvalidArgument ("number of neighbors should match")); - OP_REQUIRES (context, (0 == n_r_sel), errors::InvalidArgument ("Rotational free only support all-angular information")); - - // Create an output tensor - TensorShape force_shape ; - force_shape.AddDim (nframes); - force_shape.AddDim (3 * nall); - Tensor* force_tensor = NULL; - int context_output_index = 0; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - force_shape, &force_tensor)); - - // flat the tensors - auto net_deriv = net_deriv_tensor.flat(); - auto in_deriv = in_deriv_tensor.flat(); - auto nlist = nlist_tensor.flat(); - auto force = force_tensor->flat(); - - assert (nframes == force_shape.dim_size(0)); - assert (nframes == net_deriv_tensor.shape().dim_size(0)); - assert (nframes == in_deriv_tensor.shape().dim_size(0)); - assert (nframes == nlist_tensor.shape().dim_size(0)); - assert (nall * 3 == force_shape.dim_size(1)); - assert (nloc * ndescrpt == net_deriv_tensor.shape().dim_size(1)); - assert (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)); - assert (nloc * nnei == nlist_tensor.shape().dim_size(1)); - assert (nnei * 4 == ndescrpt); - - ProdForceSeAFunctor()( - context->eigen_device(), - force_tensor->flat().data(), - net_deriv_tensor.flat().data(), - in_deriv_tensor.flat().data(), - nlist_tensor.flat().data(), - nloc, - nall, - nnei, - ndescrpt, - n_a_sel, - n_a_shift - ); - } -private: - int n_r_sel, n_a_sel, n_a_shift; -}; - -// Register the CPU kernels. -#define REGISTER_CPU(T) \ -REGISTER_KERNEL_BUILDER( \ - Name("ProdForceSeA").Device(DEVICE_CPU).TypeConstraint("T"), \ - ProdForceSeAOp); -REGISTER_CPU(float); -REGISTER_CPU(double); -// Register the GPU kernels. -#if GOOGLE_CUDA -#define REGISTER_GPU(T) \ -REGISTER_KERNEL_BUILDER( \ - Name("ProdForceSeA").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ - ProdForceSeAOp); -REGISTER_GPU(float); -REGISTER_GPU(double); -#endif // GOOGLE_CUDA \ No newline at end of file diff --git a/source/op/prod_force_se_r.cc b/source/op/prod_force_se_r.cc index 7620bff7e0..8ce34a1489 100644 --- a/source/op/prod_force_se_r.cc +++ b/source/op/prod_force_se_r.cc @@ -1,13 +1,6 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "prod_force.h" -using namespace tensorflow; -// using namespace std; - REGISTER_OP("ProdForceSeR") .Attr("T: {float, double}") .Input("net_deriv: T") diff --git a/source/op/prod_force_se_r_grad.cc b/source/op/prod_force_se_r_grad.cc index c2417b1804..039a452e94 100644 --- a/source/op/prod_force_se_r_grad.cc +++ b/source/op/prod_force_se_r_grad.cc @@ -1,13 +1,6 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "prod_force_grad.h" -using namespace tensorflow; -// using namespace std; - REGISTER_OP("ProdForceSeRGrad") .Attr("T: {float, double}") .Input("grad: T") diff --git a/source/op/prod_force_se_r_multi_device.cc b/source/op/prod_force_se_r_multi_device.cc deleted file mode 100644 index 0a97d17742..0000000000 --- a/source/op/prod_force_se_r_multi_device.cc +++ /dev/null @@ -1,111 +0,0 @@ -#include "common.h" -#include "CustomeOperation.h" - -REGISTER_OP("ProdForceSeR") -.Attr("T: {float, double}") -.Input("net_deriv: T") -.Input("in_deriv: T") -.Input("nlist: int32") -.Input("natoms: int32") -.Output("force: T"); - -template -struct ProdForceSeRFunctor { - void operator()(const CPUDevice& d, T * force, const T * net_deriv, const T * in_deriv, const int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt) { - ProdForceSeRCPULauncher(force, net_deriv, in_deriv, nlist, nloc, nall, nnei, ndescrpt); - } - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, T * force, const T * net_deriv, const T * in_deriv, const int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt) { - ProdForceSeRGPULauncher(force, net_deriv, in_deriv, nlist, nloc, nall, nnei, ndescrpt); - } - #endif // GOOGLE_CUDA -}; - -template -class ProdForceSeROp : public OpKernel { -public: - explicit ProdForceSeROp(OpKernelConstruction* context) : OpKernel(context) {} - - void Compute(OpKernelContext* context) override { - // Grab the input tensor - int context_input_index = 0; - const Tensor& net_deriv_tensor = context->input(context_input_index++); - const Tensor& in_deriv_tensor = context->input(context_input_index++); - const Tensor& nlist_tensor = context->input(context_input_index++); - const Tensor& natoms_tensor = context->input(context_input_index++); - - // set size of the sample - OP_REQUIRES (context, (net_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of net deriv should be 2")); - OP_REQUIRES (context, (in_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); - OP_REQUIRES (context, (nlist_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); - OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); - - OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); - const int * natoms = natoms_tensor.flat().data(); - int nloc = natoms[0]; - int nall = natoms[1]; - int nframes = net_deriv_tensor.shape().dim_size(0); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; - - // check the sizes - OP_REQUIRES (context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (nframes == nlist_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - - OP_REQUIRES (context, (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of descriptors should match")); - - // Create an output tensor - TensorShape force_shape ; - force_shape.AddDim (nframes); - force_shape.AddDim (3 * nall); - Tensor* force_tensor = NULL; - int context_output_index = 0; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - force_shape, &force_tensor)); - - // flat the tensors - auto net_deriv = net_deriv_tensor.flat(); - auto in_deriv = in_deriv_tensor.flat(); - auto nlist = nlist_tensor.flat(); - auto force = force_tensor->flat(); - - assert (nframes == force_shape.dim_size(0)); - assert (nframes == net_deriv_tensor.shape().dim_size(0)); - assert (nframes == in_deriv_tensor.shape().dim_size(0)); - assert (nframes == nlist_tensor.shape().dim_size(0)); - assert (nall * 3 == force_shape.dim_size(1)); - assert (nloc * ndescrpt == net_deriv_tensor.shape().dim_size(1)); - assert (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)); - assert (nloc * nnei == nlist_tensor.shape().dim_size(1)); - assert (nnei * 4 == ndescrpt); - - ProdForceSeRFunctor()( - context->eigen_device(), - force_tensor->flat().data(), - net_deriv_tensor.flat().data(), - in_deriv_tensor.flat().data(), - nlist_tensor.flat().data(), - nloc, - nall, - nnei, - ndescrpt - ); - } -}; - -// Register the CPU kernels. -#define REGISTER_CPU(T) \ -REGISTER_KERNEL_BUILDER( \ - Name("ProdForceSeR").Device(DEVICE_CPU).TypeConstraint("T"), \ - ProdForceSeROp); -REGISTER_CPU(float); -REGISTER_CPU(double); -// Register the GPU kernels. -#if GOOGLE_CUDA -#define REGISTER_GPU(T) \ -REGISTER_KERNEL_BUILDER( \ - Name("ProdForceSeR").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ - ProdForceSeROp); -REGISTER_GPU(float); -REGISTER_GPU(double); -#endif // GOOGLE_CUDA \ No newline at end of file diff --git a/source/op/prod_virial.cc b/source/op/prod_virial.cc index b39567ae82..65dc329b4c 100644 --- a/source/op/prod_virial.cc +++ b/source/op/prod_virial.cc @@ -1,10 +1,4 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - -using namespace tensorflow; -// using namespace std; +#include "custom_op.h" REGISTER_OP("ProdVirial") .Attr("T: {float, double}") diff --git a/source/op/prod_virial_grad.cc b/source/op/prod_virial_grad.cc index 5cce265935..afe9a15382 100644 --- a/source/op/prod_virial_grad.cc +++ b/source/op/prod_virial_grad.cc @@ -1,10 +1,4 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - -using namespace tensorflow; -// using namespace std; +#include "custom_op.h" REGISTER_OP("ProdVirialGrad") .Attr("T: {float, double}") diff --git a/source/op/prod_virial_multi_device.cc b/source/op/prod_virial_multi_device.cc new file mode 100644 index 0000000000..d4f4c0675a --- /dev/null +++ b/source/op/prod_virial_multi_device.cc @@ -0,0 +1,203 @@ +#include "custom_op.h" +#include "prod_virial.h" + +REGISTER_OP("ProdVirialSeA") + .Attr("T: {float, double}") + .Input("net_deriv: T") + .Input("in_deriv: T") + .Input("rij: T") + .Input("nlist: int32") + .Input("natoms: int32") + .Attr("n_a_sel: int") + .Attr("n_r_sel: int") + .Output("virial: T") + .Output("atom_virial: T"); + +REGISTER_OP("ProdVirialSeR") + .Attr("T: {float, double}") + .Input("net_deriv: T") + .Input("in_deriv: T") + .Input("rij: T") + .Input("nlist: int32") + .Input("natoms: int32") + .Output("virial: T") + .Output("atom_virial: T"); + +template +class ProdVirialSeAOp : public OpKernel { + public: + explicit ProdVirialSeAOp(OpKernelConstruction* context) : OpKernel(context) {} + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& net_deriv_tensor = context->input(context_input_index++); + const Tensor& in_deriv_tensor = context->input(context_input_index++); + const Tensor& rij_tensor = context->input(context_input_index++); + const Tensor& nlist_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); + // set size of the sample + OP_REQUIRES (context, (net_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of net deriv should be 2")); + OP_REQUIRES (context, (in_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); + OP_REQUIRES (context, (rij_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of rij should be 2")); + OP_REQUIRES (context, (nlist_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + const int * natoms = natoms_tensor.flat().data(); + int nloc = natoms[0]; + int nall = natoms[1]; + int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int nframes = net_deriv_tensor.shape().dim_size(0); + int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; + // check the sizes + OP_REQUIRES (context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nframes == rij_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nframes == nlist_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of descriptors should match")); + OP_REQUIRES (context, (nloc * nnei * 3 == rij_tensor.shape().dim_size(1)), errors::InvalidArgument ("dim of rij should be nnei * 3")); + // Create an output tensor + TensorShape virial_shape ; + virial_shape.AddDim (nframes); + virial_shape.AddDim (9); + TensorShape atom_virial_shape; + atom_virial_shape.AddDim (nframes); + atom_virial_shape.AddDim (9 * nall); + int context_output_index = 0; + Tensor* virial_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + virial_shape, + &virial_tensor)); + Tensor* atom_virial_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + atom_virial_shape, + &atom_virial_tensor)); + DeviceFunctor() ( + device, + context->eigen_device() + ); + // flat the tensors + FPTYPE * virial = virial_tensor->flat().data(); + FPTYPE * atom_virial = atom_virial_tensor->flat().data(); + const FPTYPE * net_deriv = net_deriv_tensor.flat().data(); + const FPTYPE * in_deriv = in_deriv_tensor.flat().data(); + const FPTYPE * rij = rij_tensor.flat().data(); + const int * nlist = nlist_tensor.flat().data(); + + if (device == "GPU") { + #if GOOGLE_CUDA + prod_virial_a_gpu_cuda( + virial, atom_virial, + net_deriv, in_deriv, rij, nlist, nloc, nall, nnei); + #endif // GOOGLE_CUDA + } + else if (device == "CPU") { + prod_virial_a_cpu( + virial, atom_virial, + net_deriv, in_deriv, rij, nlist, nloc, nall, nnei); + } + } + private: + std::string device; +}; + +template +class ProdVirialSeROp : public OpKernel { + public: + explicit ProdVirialSeROp(OpKernelConstruction* context) : OpKernel(context) {} + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& net_deriv_tensor = context->input(context_input_index++); + const Tensor& in_deriv_tensor = context->input(context_input_index++); + const Tensor& rij_tensor = context->input(context_input_index++); + const Tensor& nlist_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); + // set size of the sample + OP_REQUIRES (context, (net_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of net deriv should be 2")); + OP_REQUIRES (context, (in_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); + OP_REQUIRES (context, (rij_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of rij should be 2")); + OP_REQUIRES (context, (nlist_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + const int * natoms = natoms_tensor.flat().data(); + int nloc = natoms[0]; + int nall = natoms[1]; + int nnei = nlist_tensor.shape().dim_size(1) / nloc; + int nframes = net_deriv_tensor.shape().dim_size(0); + int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; + // check the sizes + OP_REQUIRES (context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nframes == rij_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nframes == nlist_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of descriptors should match")); + OP_REQUIRES (context, (nloc * nnei * 3 == rij_tensor.shape().dim_size(1)), errors::InvalidArgument ("dim of rij should be nnei * 3")); + // Create an output tensor + TensorShape virial_shape ; + virial_shape.AddDim (nframes); + virial_shape.AddDim (9); + TensorShape atom_virial_shape; + atom_virial_shape.AddDim (nframes); + atom_virial_shape.AddDim (9 * nall); + int context_output_index = 0; + Tensor* virial_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + virial_shape, + &virial_tensor)); + Tensor* atom_virial_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + atom_virial_shape, + &atom_virial_tensor)); + DeviceFunctor() ( + device, + context->eigen_device() + ); + // flat the tensors + FPTYPE * virial = virial_tensor->flat().data(); + FPTYPE * atom_virial = atom_virial_tensor->flat().data(); + const FPTYPE * net_deriv = net_deriv_tensor.flat().data(); + const FPTYPE * in_deriv = in_deriv_tensor.flat().data(); + const FPTYPE * rij = rij_tensor.flat().data(); + const int * nlist = nlist_tensor.flat().data(); + + if (device == "GPU") { + #if GOOGLE_CUDA + prod_virial_r_gpu_cuda( + virial, atom_virial, + net_deriv, in_deriv, rij, nlist, nloc, nall, nnei); + #endif // GOOGLE_CUDA + } + else if (device == "CPU") { + prod_virial_r_cpu( + virial, atom_virial, + net_deriv, in_deriv, rij, nlist, nloc, nall, nnei); + } + } + private: + std::string device; +}; + +// Register the CPU kernels. +#define REGISTER_CPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdVirialSeA").Device(DEVICE_CPU).TypeConstraint("T"), \ + ProdVirialSeAOp); \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdVirialSeR").Device(DEVICE_CPU).TypeConstraint("T"), \ + ProdVirialSeROp); +REGISTER_CPU(float); +REGISTER_CPU(double); +// Register the GPU kernels. +#if GOOGLE_CUDA +#define REGISTER_GPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdVirialSeA").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ + ProdVirialSeAOp); \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdVirialSeR").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ + ProdVirialSeROp); +REGISTER_GPU(float); +REGISTER_GPU(double); +#endif // GOOGLE_CUDA \ No newline at end of file diff --git a/source/op/prod_virial_se_a.cc b/source/op/prod_virial_se_a.cc index f55ba49510..454edb2fbd 100644 --- a/source/op/prod_virial_se_a.cc +++ b/source/op/prod_virial_se_a.cc @@ -1,13 +1,6 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include +#include "custom_op.h" #include "prod_virial.h" -using namespace tensorflow; -// using namespace std; - - REGISTER_OP("ProdVirialSeA") .Attr("T: {float, double}") .Input("net_deriv: T") diff --git a/source/op/prod_virial_se_a_grad.cc b/source/op/prod_virial_se_a_grad.cc index 0285a2f65a..d1366baf6f 100644 --- a/source/op/prod_virial_se_a_grad.cc +++ b/source/op/prod_virial_se_a_grad.cc @@ -1,13 +1,6 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "prod_virial_grad.h" -using namespace tensorflow; -// using namespace std; - REGISTER_OP("ProdVirialSeAGrad") .Attr("T: {float, double}") .Input("grad: T") diff --git a/source/op/prod_virial_se_a_multi_device.cc b/source/op/prod_virial_se_a_multi_device.cc deleted file mode 100644 index 7929fbd588..0000000000 --- a/source/op/prod_virial_se_a_multi_device.cc +++ /dev/null @@ -1,125 +0,0 @@ -#include "common.h" -#include "CustomeOperation.h" - -REGISTER_OP("ProdVirialSeA") - .Attr("T: {float, double}") - .Input("net_deriv: T") - .Input("in_deriv: T") - .Input("rij: T") - .Input("nlist: int32") - .Input("natoms: int32") - .Attr("n_a_sel: int") - .Attr("n_r_sel: int") - .Output("virial: T") - .Output("atom_virial: T"); - -template -struct ProdVirialSeAFunctor { - void operator()(const CPUDevice& d, FPTYPE * virial, FPTYPE * atom_virial, const FPTYPE * net_deriv, const FPTYPE * in_deriv, const FPTYPE * rij, const int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const int n_a_sel, const int n_a_shift) { - ProdVirialSeACPULauncher(virial, atom_virial, net_deriv, in_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, n_a_sel, n_a_shift); - } - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, FPTYPE * virial, FPTYPE * atom_virial, const FPTYPE * net_deriv, const FPTYPE * in_deriv, const FPTYPE * rij, const int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt, const int n_a_sel, const int n_a_shift) { - ProdVirialSeAGPULauncher(virial, atom_virial, net_deriv, in_deriv, rij, nlist, nloc, nall, nnei, ndescrpt, n_a_sel, n_a_shift); - } - #endif // GOOGLE_CUDA -}; - -template -class ProdVirialSeAOp : public OpKernel { - public: - explicit ProdVirialSeAOp(OpKernelConstruction* context) : OpKernel(context) { - OP_REQUIRES_OK(context, context->GetAttr("n_a_sel", &n_a_sel)); - OP_REQUIRES_OK(context, context->GetAttr("n_r_sel", &n_r_sel)); - n_a_shift = n_a_sel * 4; - } - - void Compute(OpKernelContext* context) override { - // Grab the input tensor - int context_input_index = 0; - const Tensor& net_deriv_tensor = context->input(context_input_index++); - const Tensor& in_deriv_tensor = context->input(context_input_index++); - const Tensor& rij_tensor = context->input(context_input_index++); - const Tensor& nlist_tensor = context->input(context_input_index++); - const Tensor& natoms_tensor = context->input(context_input_index++); - - // set size of the sample - OP_REQUIRES (context, (net_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of net deriv should be 2")); - OP_REQUIRES (context, (in_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); - OP_REQUIRES (context, (rij_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of rij should be 2")); - OP_REQUIRES (context, (nlist_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); - OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); - - OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); - const int * natoms = natoms_tensor.flat().data(); - int nloc = natoms[0]; - int nall = natoms[1]; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; - int nframes = net_deriv_tensor.shape().dim_size(0); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; - - // check the sizes - OP_REQUIRES (context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (nframes == rij_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (nframes == nlist_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - - OP_REQUIRES (context, (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of descriptors should match")); - OP_REQUIRES (context, (nloc * nnei * 3 == rij_tensor.shape().dim_size(1)), errors::InvalidArgument ("dim of rij should be nnei * 3")); - OP_REQUIRES (context, (nnei == n_a_sel + n_r_sel), errors::InvalidArgument ("number of neighbors should match")); - - // Create an output tensor - TensorShape virial_shape ; - virial_shape.AddDim (nframes); - virial_shape.AddDim (9); - Tensor* virial_tensor = NULL; - OP_REQUIRES_OK(context, context->allocate_output(0, virial_shape, &virial_tensor)); - TensorShape atom_virial_shape; - atom_virial_shape.AddDim (nframes); - atom_virial_shape.AddDim (9 * nall); - Tensor* atom_virial_tensor = NULL; - OP_REQUIRES_OK(context, context->allocate_output(1, atom_virial_shape, &atom_virial_tensor)); - - // flat the tensors - auto net_deriv = net_deriv_tensor.flat(); - auto in_deriv = in_deriv_tensor.flat(); - auto rij = rij_tensor.flat(); - auto nlist = nlist_tensor.flat(); - auto virial = virial_tensor->flat(); - auto atom_virial = atom_virial_tensor->flat(); - - ProdVirialSeAFunctor()( - context->eigen_device(), - virial_tensor->flat().data(), - atom_virial_tensor->flat().data(), - net_deriv_tensor.flat().data(), - in_deriv_tensor.flat().data(), - rij_tensor.flat().data(), - nlist_tensor.flat().data(), - nloc, - nall, - nnei, - ndescrpt, - n_a_sel, - n_a_shift - ); - } -private: - int n_r_sel, n_a_sel, n_a_shift; -}; - -// Register the CPU kernels. -#define REGISTER_CPU(T) \ -REGISTER_KERNEL_BUILDER( \ - Name("ProdVirialSeA").Device(DEVICE_CPU).TypeConstraint("T"), \ - ProdVirialSeAOp); -REGISTER_CPU(float); -REGISTER_CPU(double); -// Register the GPU kernels. -#if GOOGLE_CUDA -#define REGISTER_GPU(T) \ -REGISTER_KERNEL_BUILDER( \ - Name("ProdVirialSeA").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ - ProdVirialSeAOp); -REGISTER_GPU(float); -REGISTER_GPU(double); -#endif // GOOGLE_CUDA \ No newline at end of file diff --git a/source/op/prod_virial_se_r.cc b/source/op/prod_virial_se_r.cc index d41fddd4c8..4b6285ff48 100644 --- a/source/op/prod_virial_se_r.cc +++ b/source/op/prod_virial_se_r.cc @@ -1,14 +1,6 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "prod_virial.h" -using namespace tensorflow; -// using namespace std; - - REGISTER_OP("ProdVirialSeR") .Attr("T: {float, double}") .Input("net_deriv: T") diff --git a/source/op/prod_virial_se_r_grad.cc b/source/op/prod_virial_se_r_grad.cc index 94847b9880..d900781709 100644 --- a/source/op/prod_virial_se_r_grad.cc +++ b/source/op/prod_virial_se_r_grad.cc @@ -1,13 +1,6 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "prod_virial_grad.h" -using namespace tensorflow; -//using namespace std; - REGISTER_OP("ProdVirialSeRGrad") .Attr("T: {float, double}") .Input("grad: T") diff --git a/source/op/prod_virial_se_r_multi_device.cc b/source/op/prod_virial_se_r_multi_device.cc index 61e37eb215..bb74cc0500 100644 --- a/source/op/prod_virial_se_r_multi_device.cc +++ b/source/op/prod_virial_se_r_multi_device.cc @@ -1,4 +1,4 @@ -#include "common.h" +#include "custom_op.h" #include "CustomeOperation.h" REGISTER_OP("ProdVirialSeR") diff --git a/source/op/soft_min.cc b/source/op/soft_min.cc index cbcc6868fe..4dcedbaea1 100644 --- a/source/op/soft_min.cc +++ b/source/op/soft_min.cc @@ -1,15 +1,7 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "ComputeDescriptor.h" #include "soft_min_switch.h" -using namespace tensorflow; -// using namespace std; - - REGISTER_OP("SoftMinSwitch") .Attr("T: {float, double}") .Input("type: int32") diff --git a/source/op/soft_min_force.cc b/source/op/soft_min_force.cc index 84c0b910fb..143d70d5ae 100644 --- a/source/op/soft_min_force.cc +++ b/source/op/soft_min_force.cc @@ -1,13 +1,6 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "soft_min_switch_force.h" -using namespace tensorflow; -// using namespace std; - REGISTER_OP("SoftMinForce") .Attr("T: {float, double}") .Input("du: T") diff --git a/source/op/soft_min_force_grad.cc b/source/op/soft_min_force_grad.cc index 82d7817738..59ccb32351 100644 --- a/source/op/soft_min_force_grad.cc +++ b/source/op/soft_min_force_grad.cc @@ -1,13 +1,6 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "soft_min_switch_force_grad.h" -using namespace tensorflow; -// using namespace std; - REGISTER_OP("SoftMinForceGrad") .Attr("T: {float, double}") .Input("grad: T") diff --git a/source/op/soft_min_virial.cc b/source/op/soft_min_virial.cc index b083427912..05e76d2741 100644 --- a/source/op/soft_min_virial.cc +++ b/source/op/soft_min_virial.cc @@ -1,13 +1,6 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "soft_min_switch_virial.h" -using namespace tensorflow; -// using namespace std; - REGISTER_OP("SoftMinVirial") .Attr("T: {float, double}") .Input("du: T") diff --git a/source/op/soft_min_virial_grad.cc b/source/op/soft_min_virial_grad.cc index 8294b74144..a115c461e3 100644 --- a/source/op/soft_min_virial_grad.cc +++ b/source/op/soft_min_virial_grad.cc @@ -1,11 +1,4 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - -using namespace tensorflow; -// using namespace std; - +#include "custom_op.h" #include "soft_min_switch_virial_grad.h" REGISTER_OP("SoftMinVirialGrad") diff --git a/source/op/tabulate.cc b/source/op/tabulate.cc deleted file mode 100644 index 1ca5b774ea..0000000000 --- a/source/op/tabulate.cc +++ /dev/null @@ -1,385 +0,0 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/register_types.h" -#include "tensorflow/core/framework/shape_inference.h" - -using namespace tensorflow; -using CPUDevice = Eigen::ThreadPoolDevice; -using GPUDevice = Eigen::GpuDevice; - -REGISTER_OP("TabulateFusion") - .Attr("T: {float, double}") - .Input("table: T") - .Input("table_info: T") - .Input("input: T") - .Input("ff: T") - .Attr("last_layer_size: int") - .Output("output: T"); - -REGISTER_OP("TabulateFusionGrad") - .Attr("T: {float, double}") - .Input("table: T") - .Input("table_info: T") - .Input("input: T") - .Input("ff: T") - .Input("dy: T") - .Input("output: T") - .Output("dy_dx: T") - .Output("dy_df: T"); - -#if GOOGLE_CUDA -void TabulateFusionLauncher(const float * table, const float * table_info, const float * in, const float * ff, const int nloc, const int nnei, const int last_layer_size, float * out); -void TabulateFusionLauncher(const double * table, const double * table_info, const double * in, const double * ff, const int nloc, const int nnei, const int last_layer_size, double * out); -void TabulateFusionGradLauncher(const float * table, const float * table_info, const float * in, const float * ff, const float * dy, const int nloc, const int nnei, const int last_layer_size, float * dy_dx, float * dy_df); -void TabulateFusionGradLauncher(const double * table, const double * table_info, const double * in, const double * ff, const double * dy, const int nloc, const int nnei, const int last_layer_size, double * dy_dx, double * dy_df); -void TabulateCheckerLauncher(const float * table_info, const float * in, int * out, const int nloc, const int nnei); -void TabulateCheckerLauncher(const double * table_info, const double * in, int * out, const int nloc, const int nnei); -#endif - -template -inline FPTYPE dot(FPTYPE a[4], FPTYPE b[4]) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; -} - -/* - This inline function was designed to get the table info and bias value for current input xx! - lower: indicate the lower boundary of the first table; - upper: indicate the upper boundary of the first table as well as the lower boundary of the second table; - max: indicate the upper boundary of the second table; - stride0: indicate the stride of the first table; - stride1: indicate the stride of the second table; - xx: indicate the inputs value; - table_idx: indicate the location of table info of input value xx; -*/ -template -inline void locate_xx(const FPTYPE& lower, const FPTYPE& upper, const FPTYPE& max, const FPTYPE& stride0, const FPTYPE& stride1, FPTYPE& xx, int& table_idx) { - if (xx < lower) { - table_idx = 0; - xx = 0; - } - else if (xx < upper) { - table_idx = (int)((xx - lower) / stride0); - xx -= (table_idx * stride0 + lower); - } - else if (xx < max) { - int first_stride = int((upper - lower) / stride0); - table_idx = first_stride + (int)((xx - upper) / stride1); - xx -= ((table_idx - first_stride) * stride1 + upper); - } - else { - table_idx = int((upper - lower) / stride0) + (int)((max - upper) / stride1) - 1; - xx = 0; - } -} - -template -struct TabulateFusionFunctor { - void operator()(const CPUDevice& d, const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const int nloc, const int nnei, const int last_layer_size, FPTYPE * out) { - //Currently, Do nothing at all! - // std::cout << "I'm in tabulate @CPU!" << std::endl; - memset(out, 0.0, sizeof(FPTYPE) * nloc * 4 * last_layer_size); - FPTYPE const lower = table_info[0]; - FPTYPE const upper = table_info[1]; - FPTYPE const _max = table_info[2]; - FPTYPE const stride0 = table_info[3]; - FPTYPE const stride1 = table_info[4]; - // for every atom, execute a small gemm~ - // FPTYPE * res = new FPTYPE[4 * last_layer_size]; - #pragma omp parallel for - for (int ii = 0; ii < nloc; ii++) { - FPTYPE ll[4] = {0}; - FPTYPE ago = in[ii * nnei + nnei - 1]; - bool unloop = false; - for (int jj = 0; jj < nnei; jj++) { - ll[0] = ff[ii * nnei * 4 + jj * 4 + 0]; - ll[1] = ff[ii * nnei * 4 + jj * 4 + 1]; - ll[2] = ff[ii * nnei * 4 + jj * 4 + 2]; - ll[3] = ff[ii * nnei * 4 + jj * 4 + 3]; - FPTYPE xx = in[ii * nnei + jj]; - if (ago == xx) { - unloop = true; - } - int table_idx = 0; - locate_xx(lower, upper, _max, stride0, stride1, xx, table_idx); - for (int kk = 0; kk < last_layer_size; kk++) { - // 1.094 timesteps/s - FPTYPE a0 = table[table_idx * last_layer_size * 6 + 6 * kk + 0]; - FPTYPE a1 = table[table_idx * last_layer_size * 6 + 6 * kk + 1]; - FPTYPE a2 = table[table_idx * last_layer_size * 6 + 6 * kk + 2]; - FPTYPE a3 = table[table_idx * last_layer_size * 6 + 6 * kk + 3]; - FPTYPE a4 = table[table_idx * last_layer_size * 6 + 6 * kk + 4]; - FPTYPE a5 = table[table_idx * last_layer_size * 6 + 6 * kk + 5]; - // FPTYPE var = a0 + a1 * xx + a2 * xx * xx + a3 * xx * xx * xx + a4 * xx * xx * xx * xx + a5 * xx * xx * xx * xx * xx; - FPTYPE var = a0 + (a1 + (a2 + (a3 + (a4 + a5 * xx) * xx) * xx) * xx) * xx; - if (unloop) { - out[ii * last_layer_size * 4 + 0 * last_layer_size + kk] += (nnei - jj) * var * ll[0]; - out[ii * last_layer_size * 4 + 1 * last_layer_size + kk] += (nnei - jj) * var * ll[1]; - out[ii * last_layer_size * 4 + 2 * last_layer_size + kk] += (nnei - jj) * var * ll[2]; - out[ii * last_layer_size * 4 + 3 * last_layer_size + kk] += (nnei - jj) * var * ll[3]; - } - else { - out[ii * last_layer_size * 4 + 0 * last_layer_size + kk] += var * ll[0]; - out[ii * last_layer_size * 4 + 1 * last_layer_size + kk] += var * ll[1]; - out[ii * last_layer_size * 4 + 2 * last_layer_size + kk] += var * ll[2]; - out[ii * last_layer_size * 4 + 3 * last_layer_size + kk] += var * ll[3]; - } - } - if (unloop) break; - } - } - } - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const int nloc, const int nnei, const int last_layer_size, FPTYPE * out) { - //Currently, Do nothing at all! - TabulateFusionLauncher(table, table_info, in, ff, nloc, nnei, last_layer_size, out); - } - #endif // GOOGLE_CUDA -}; - -template -struct TabulateFusionGradFunctor { - void operator()(const CPUDevice& d, const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const FPTYPE * dy, const int nloc, const int nnei, const int last_layer_size, FPTYPE * dy_dx, FPTYPE * dy_df) { - // std::cout << "I'm in tabulate gradient @CPU!" << std::endl; - memset(dy_dx, 0.0, sizeof(FPTYPE) * nloc * nnei); - memset(dy_df, 0.0, sizeof(FPTYPE) * nloc * nnei * 4); - FPTYPE const lower = table_info[0]; - FPTYPE const upper = table_info[1]; - FPTYPE const _max = table_info[2]; - FPTYPE const stride0 = table_info[3]; - FPTYPE const stride1 = table_info[4]; - // for every atom, execute a small gemm~ - // FPTYPE * res = new FPTYPE[4 * last_layer_size]; - #pragma omp parallel for - for (int ii = 0; ii < nloc; ii++) { - FPTYPE ll[4]; - FPTYPE rr[4]; - FPTYPE ago = in[ii * nnei + nnei - 1]; - bool unloop = false; - for (int jj = 0; jj < nnei; jj++) { - // construct the dy/dx - ll[0] = ff[ii * nnei * 4 + jj * 4 + 0]; - ll[1] = ff[ii * nnei * 4 + jj * 4 + 1]; - ll[2] = ff[ii * nnei * 4 + jj * 4 + 2]; - ll[3] = ff[ii * nnei * 4 + jj * 4 + 3]; - FPTYPE xx = in[ii * nnei + jj]; - if (ago == xx) { - unloop = true; - } - int table_idx = 0; - locate_xx(lower, upper, _max, stride0, stride1, xx, table_idx); - FPTYPE grad = 0.0; - for (int kk = 0; kk < last_layer_size; kk++) { - rr[0] = dy[ii * last_layer_size * 4 + 0 * last_layer_size + kk]; - rr[1] = dy[ii * last_layer_size * 4 + 1 * last_layer_size + kk]; - rr[2] = dy[ii * last_layer_size * 4 + 2 * last_layer_size + kk]; - rr[3] = dy[ii * last_layer_size * 4 + 3 * last_layer_size + kk]; - // 1.094 timesteps/s - FPTYPE a0 = table[table_idx * last_layer_size * 6 + 6 * kk + 0]; - FPTYPE a1 = table[table_idx * last_layer_size * 6 + 6 * kk + 1]; - FPTYPE a2 = table[table_idx * last_layer_size * 6 + 6 * kk + 2]; - FPTYPE a3 = table[table_idx * last_layer_size * 6 + 6 * kk + 3]; - FPTYPE a4 = table[table_idx * last_layer_size * 6 + 6 * kk + 4]; - FPTYPE a5 = table[table_idx * last_layer_size * 6 + 6 * kk + 5]; - // FPTYPE res = a0 + a1 * xx + a2 * xx * xx + a3 * xx * xx * xx + a4 * xx * xx * xx * xx + a5 * xx * xx * xx * xx * xx; - FPTYPE res = a0 + (a1 + (a2 + (a3 + (a4 + a5 * xx) * xx) * xx) * xx) * xx; - - if (unloop) { - // grad += (a1 + 2 * a2 * xx + 3 * a3 * xx * xx + 4 * a4 * xx * xx * xx + 5 * a5 * xx * xx * xx * xx) * dot(ll, rr) * (nnei - jj); - grad += (a1 + (2 * a2 + (3 * a3 + (4 * a4 + 5 * a5 * xx) * xx) * xx) * xx) * dot(ll, rr) * (nnei - jj); - dy_df[ii * nnei * 4 + jj * 4 + 0] += res * rr[0] * (nnei - jj); - dy_df[ii * nnei * 4 + jj * 4 + 1] += res * rr[1] * (nnei - jj); - dy_df[ii * nnei * 4 + jj * 4 + 2] += res * rr[2] * (nnei - jj); - dy_df[ii * nnei * 4 + jj * 4 + 3] += res * rr[3] * (nnei - jj); - } - else { - // grad += (a1 + 2 * a2 * xx + 3 * a3 * xx * xx + 4 * a4 * xx * xx * xx + 5 * a5 * xx * xx * xx * xx) * dot(ll, rr); - grad += (a1 + (2 * a2 + (3 * a3 + (4 * a4 + 5 * a5 * xx) * xx) * xx) * xx) * dot(ll, rr); - dy_df[ii * nnei * 4 + jj * 4 + 0] += res * rr[0]; - dy_df[ii * nnei * 4 + jj * 4 + 1] += res * rr[1]; - dy_df[ii * nnei * 4 + jj * 4 + 2] += res * rr[2]; - dy_df[ii * nnei * 4 + jj * 4 + 3] += res * rr[3]; - } - } - dy_dx[ii * nnei + jj] = grad; - if (unloop) break; - } - } - } - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const FPTYPE * dy, const int nloc, const int nnei, const int last_layer_size, FPTYPE * dy_dx, FPTYPE * dy_df) { - //Currently, Do nothing at all! - TabulateFusionGradLauncher(table, table_info, in, ff, dy, nloc, nnei, last_layer_size, dy_dx, dy_df); - } - #endif // GOOGLE_CUDA -}; - -template -struct TabulateCheckerFunctor { - void operator()(const CPUDevice& d, const FPTYPE * table_info, const FPTYPE * in, int * out, const int nloc, const int nnei) { - FPTYPE const lower = table_info[0]; - FPTYPE const upper = table_info[1]; - FPTYPE const _max = table_info[2]; - FPTYPE const stride0 = table_info[3]; - FPTYPE const stride1 = table_info[4]; - // for every atom, execute a small gemm~ - // FPTYPE * res = new FPTYPE[4 * last_layer_size]; - int Csub = 0; // summation of second table approximate; - int Dsub = 0; // summation of the endpoint approximate; - for (int ii = 0; ii < nloc; ii++) { - for (int jj = 0; jj < nnei; jj++) { - FPTYPE xx = in[ii * nnei + jj]; - if (xx < lower || xx > _max) { - Csub += 1; - } - else if (xx >= upper && xx <= _max) { - Dsub += 1; - } - } - } - if(Csub > 0) { - std::cout << "# DEEPMD: warning! some values [" << Csub << "/" << nloc * nnei << "] overflow the range of the table, using the endpoint approximate processing.." << std::endl; - } - if(Dsub > 0) { - std::cout << "# DEEPMD: warning! some values [" << Dsub << "/" << nloc * nnei << "] overflow the range of the table, using second table approximate processing.." << std::endl; - } - } - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const FPTYPE * table_info, const FPTYPE * in, int * out, const int nloc, const int nnei) { - //Currently, Do nothing at all! - TabulateCheckerLauncher(table_info, in, out, nloc, nnei); - } - #endif // GOOGLE_CUDA -}; - -template -class TabulateFusionOp : public OpKernel { - public: - explicit TabulateFusionOp(OpKernelConstruction* context) : OpKernel(context) { - OP_REQUIRES_OK(context, context->GetAttr("last_layer_size", &last_layer_size)); - counter = -1; - } - - void Compute(OpKernelContext* context) override { - // Grab the input tensor - int context_input_index = 0; - const Tensor& table = context->input(context_input_index++); - const Tensor& table_info = context->input(context_input_index++); - const Tensor& input = context->input(context_input_index++); - const Tensor& ff = context->input(context_input_index++); - - // set size of the sample - OP_REQUIRES (context, (table.shape().dims() == 2), errors::InvalidArgument ("Dim of table should be 2")); - OP_REQUIRES (context, (input.shape().dims() == 2), errors::InvalidArgument ("Dim of input should be 2")); - OP_REQUIRES (context, (ff.shape().dims() == 3), errors::InvalidArgument ("Dim of input should be 3")); - - TensorShape output_shape; - output_shape.AddDim (ff.shape().dim_size(0)); - output_shape.AddDim (4); - output_shape.AddDim (last_layer_size); - - int context_output_index = 0; - Tensor* output = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - output_shape, - &output)); - - // counter++; - // if ((int)table_info.flat().data()[5] != -1 && counter % (int)table_info.flat().data()[5] == 0) { - // Tensor int_temp; - // TensorShape int_shape; - // int_shape.AddDim(2 * ff.shape().dim_size(0)); - // OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); - // TabulateCheckerFunctor()( - // context->eigen_device(), - // table_info.flat().data(), - // input.flat().data(), - // int_temp.flat().data(), - // ff.shape().dim_size(0), - // ff.shape().dim_size(1) - // ); - // } - - TabulateFusionFunctor()( - context->eigen_device(), // define actually graph execution device - table.flat().data(), - table_info.flat().data(), - input.flat().data(), - ff.flat().data(), - ff.shape().dim_size(0), - ff.shape().dim_size(1), - last_layer_size, - output->flat().data() - ); - } -private: - int counter; - int last_layer_size; -}; - -template -class TabulateFusionGradOp : public OpKernel { - public: - explicit TabulateFusionGradOp(OpKernelConstruction* context) : OpKernel(context) {} - - void Compute(OpKernelContext* context) override { - // std::cout << "I'm here" << std::endl; - // Grab the input tensor - int context_input_index = 0; - const Tensor& table = context->input(context_input_index++); - const Tensor& table_info = context->input(context_input_index++); - const Tensor& input = context->input(context_input_index++); - const Tensor& ff = context->input(context_input_index++); - const Tensor& dy = context->input(context_input_index++); - const Tensor& output = context->input(context_input_index++); - - // set size of the sample - OP_REQUIRES (context, (dy.shape().dims() == 3), errors::InvalidArgument ("Dim of table should be 1")); - - int context_output_index = 0; - Tensor* dy_dx = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - input.shape(), - &dy_dx)); - Tensor* dy_df = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - ff.shape(), - &dy_df)); - - TabulateFusionGradFunctor()( - context->eigen_device(), // define actually graph execution device - table.flat().data(), - table_info.flat().data(), - input.flat().data(), - ff.flat().data(), - dy.flat().data(), - ff.shape().dim_size(0), - ff.shape().dim_size(1), - output.shape().dim_size(2), - dy_dx->flat().data(), - dy_df->flat().data() - ); - } -private: -}; - -#define REGISTER_CPU(T) \ -REGISTER_KERNEL_BUILDER( \ - Name("TabulateFusion").Device(DEVICE_CPU).TypeConstraint("T").HostMemory("table_info"), \ - TabulateFusionOp); \ -REGISTER_KERNEL_BUILDER( \ - Name("TabulateFusionGrad").Device(DEVICE_CPU).TypeConstraint("T").HostMemory("table_info"), \ - TabulateFusionGradOp); -REGISTER_CPU(float); -REGISTER_CPU(double); - -#if GOOGLE_CUDA -#define REGISTER_GPU(T) \ -REGISTER_KERNEL_BUILDER( \ - Name("TabulateFusion").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("table_info"), \ - TabulateFusionOp); \ -REGISTER_KERNEL_BUILDER( \ - Name("TabulateFusionGrad").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("table_info"), \ - TabulateFusionGradOp); -REGISTER_GPU(float); -REGISTER_GPU(double); -#endif // GOOGLE_CUDA diff --git a/source/op/tabulate_multi_device.cc b/source/op/tabulate_multi_device.cc index 4cce523def..b4e891518d 100644 --- a/source/op/tabulate_multi_device.cc +++ b/source/op/tabulate_multi_device.cc @@ -1,174 +1,143 @@ -#include "common.h" -#include "CustomeOperation.h" +#include "custom_op.h" +#include "tabulate.h" REGISTER_OP("TabulateFusion") .Attr("T: {float, double}") .Input("table: T") .Input("table_info: T") - .Input("input: T") - .Input("ff: T") + .Input("em_x: T") + .Input("em: T") .Attr("last_layer_size: int") - .Output("output: T"); + .Output("descriptor: T"); REGISTER_OP("TabulateFusionGrad") .Attr("T: {float, double}") .Input("table: T") .Input("table_info: T") - .Input("input: T") - .Input("ff: T") + .Input("em_x: T") + .Input("em: T") .Input("dy: T") - .Input("output: T") - .Output("dy_dx: T") - .Output("dy_df: T"); - -template -struct TabulateFusionFunctor { - void operator()(const CPUDevice& d, const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const int nloc, const int nnei, const int last_layer_size, FPTYPE * out) { - TabulateFusionCPULauncher(table, table_info, in, ff, nloc, nnei, last_layer_size, out); - } - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const int nloc, const int nnei, const int last_layer_size, FPTYPE * out) { - //Currently, Do nothing at all! - TabulateFusionGPULauncher(table, table_info, in, ff, nloc, nnei, last_layer_size, out); - } - #endif // GOOGLE_CUDA -}; - -template -struct TabulateFusionGradFunctor { - void operator()(const CPUDevice& d, const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const FPTYPE * dy, const int nloc, const int nnei, const int last_layer_size, FPTYPE * dy_dx, FPTYPE * dy_df) { - TabulateFusionGradCPULauncher(table, table_info, in, ff, dy, nloc, nnei, last_layer_size, dy_dx, dy_df); - } - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const FPTYPE * table, const FPTYPE * table_info, const FPTYPE * in, const FPTYPE * ff, const FPTYPE * dy, const int nloc, const int nnei, const int last_layer_size, FPTYPE * dy_dx, FPTYPE * dy_df) { - //Currently, Do nothing at all! - TabulateFusionGradGPULauncher(table, table_info, in, ff, dy, nloc, nnei, last_layer_size, dy_dx, dy_df); - } - #endif // GOOGLE_CUDA -}; - -template -struct TabulateCheckerFunctor { - void operator()(const CPUDevice& d, const FPTYPE * table_info, const FPTYPE * in, int * out, const int nloc, const int nnei) { - TabulateCheckerCPULauncher(table_info, in, out, nloc, nnei); - } - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, const FPTYPE * table_info, const FPTYPE * in, int * out, const int nloc, const int nnei) { - //Currently, Do nothing at all! - TabulateCheckerGPULauncher(table_info, in, out, nloc, nnei); - } - #endif // GOOGLE_CUDA -}; + .Input("descriptor: T") + .Output("dy_dem_x: T") + .Output("dy_dem: T"); template class TabulateFusionOp : public OpKernel { - public: - explicit TabulateFusionOp(OpKernelConstruction* context) : OpKernel(context) { - OP_REQUIRES_OK(context, context->GetAttr("last_layer_size", &last_layer_size)); - counter = -1; + public: + explicit TabulateFusionOp(OpKernelConstruction* context) : OpKernel(context) { + OP_REQUIRES_OK(context, context->GetAttr("last_layer_size", &last_layer_size)); + } + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& table_tensor = context->input(context_input_index++); + const Tensor& table_info_tensor = context->input(context_input_index++); + const Tensor& em_x_tensor = context->input(context_input_index++); + const Tensor& em_tensor = context->input(context_input_index++); + // set size of the sample + OP_REQUIRES (context, (table_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of table should be 2")); + OP_REQUIRES (context, (em_x_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of input should be 2")); + OP_REQUIRES (context, (em_tensor.shape().dims() == 3), errors::InvalidArgument ("Dim of input should be 3")); + TensorShape descriptor_shape; + descriptor_shape.AddDim (em_tensor.shape().dim_size(0)); + descriptor_shape.AddDim (4); // TODO: be careful here; + descriptor_shape.AddDim (last_layer_size); + int context_output_index = 0; + Tensor* descriptor_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + descriptor_shape, + &descriptor_tensor)); + DeviceFunctor() ( + device, + context->eigen_device() + ); + // flat the tensors + FPTYPE * descriptor = descriptor_tensor->flat().data(); + const FPTYPE * table = table_tensor.flat().data(); + const FPTYPE * table_info = table_info_tensor.flat().data(); + const FPTYPE * em_x = em_x_tensor.flat().data(); + const FPTYPE * em = em_tensor.flat().data(); + const int nloc = em_tensor.shape().dim_size(0); + const int nnei = em_tensor.shape().dim_size(1); + + if (device == "GPU") { + #if GOOGLE_CUDA + tabulate_fusion_gpu_cuda( + descriptor, + table, table_info, em_x, em, nloc, nnei, last_layer_size); + #endif // GOOGLE_CUDA } - - void Compute(OpKernelContext* context) override { - // Grab the input tensor - int context_input_index = 0; - const Tensor& table = context->input(context_input_index++); - const Tensor& table_info = context->input(context_input_index++); - const Tensor& input = context->input(context_input_index++); - const Tensor& ff = context->input(context_input_index++); - - // set size of the sample - OP_REQUIRES (context, (table.shape().dims() == 2), errors::InvalidArgument ("Dim of table should be 2")); - OP_REQUIRES (context, (input.shape().dims() == 2), errors::InvalidArgument ("Dim of input should be 2")); - OP_REQUIRES (context, (ff.shape().dims() == 3), errors::InvalidArgument ("Dim of input should be 3")); - - TensorShape output_shape; - output_shape.AddDim (ff.shape().dim_size(0)); - output_shape.AddDim (4); - output_shape.AddDim (last_layer_size); - - int context_output_index = 0; - Tensor* output = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - output_shape, - &output)); - - // counter++; - // if ((int)table_info.flat().data()[5] != -1 && counter % (int)table_info.flat().data()[5] == 0) { - // Tensor int_temp; - // TensorShape int_shape; - // int_shape.AddDim(2 * ff.shape().dim_size(0)); - // OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); - // TabulateCheckerFunctor()( - // context->eigen_device(), - // table_info.flat().data(), - // input.flat().data(), - // int_temp.flat().data(), - // ff.shape().dim_size(0), - // ff.shape().dim_size(1) - // ); - // } - - TabulateFusionFunctor()( - context->eigen_device(), // define actually graph execution device - table.flat().data(), - table_info.flat().data(), - input.flat().data(), - ff.flat().data(), - ff.shape().dim_size(0), - ff.shape().dim_size(1), - last_layer_size, - output->flat().data() - ); + else if (device == "CPU") { + tabulate_fusion_cpu( + descriptor, + table, table_info, em_x, em, nloc, nnei, last_layer_size); } + } private: - int counter; int last_layer_size; + std::string device; }; template class TabulateFusionGradOp : public OpKernel { public: - explicit TabulateFusionGradOp(OpKernelConstruction* context) : OpKernel(context) {} - - void Compute(OpKernelContext* context) override { - // std::cout << "I'm here" << std::endl; - // Grab the input tensor - int context_input_index = 0; - const Tensor& table = context->input(context_input_index++); - const Tensor& table_info = context->input(context_input_index++); - const Tensor& input = context->input(context_input_index++); - const Tensor& ff = context->input(context_input_index++); - const Tensor& dy = context->input(context_input_index++); - const Tensor& output = context->input(context_input_index++); - - // set size of the sample - OP_REQUIRES (context, (dy.shape().dims() == 3), errors::InvalidArgument ("Dim of table should be 1")); - - int context_output_index = 0; - Tensor* dy_dx = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - input.shape(), - &dy_dx)); - Tensor* dy_df = NULL; - OP_REQUIRES_OK(context, context->allocate_output(context_output_index++, - ff.shape(), - &dy_df)); - - TabulateFusionGradFunctor()( - context->eigen_device(), // define actually graph execution device - table.flat().data(), - table_info.flat().data(), - input.flat().data(), - ff.flat().data(), - dy.flat().data(), - ff.shape().dim_size(0), - ff.shape().dim_size(1), - output.shape().dim_size(2), - dy_dx->flat().data(), - dy_df->flat().data() - ); + explicit TabulateFusionGradOp(OpKernelConstruction* context) : OpKernel(context) {} + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& table_tensor = context->input(context_input_index++); + const Tensor& table_info_tensor = context->input(context_input_index++); + const Tensor& em_x_tensor = context->input(context_input_index++); + const Tensor& em_tensor = context->input(context_input_index++); + const Tensor& dy_tensor = context->input(context_input_index++); + const Tensor& descriptor_tensor = context->input(context_input_index++); + // set size of the sample + OP_REQUIRES (context, (dy_tensor.shape().dims() == 3), errors::InvalidArgument ("Dim of table should be 3")); + int context_output_index = 0; + Tensor* dy_dem_x_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + em_x_tensor.shape(), + &dy_dem_x_tensor)); + Tensor* dy_dem_tensor = NULL; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + em_tensor.shape(), + &dy_dem_tensor)); + DeviceFunctor() ( + device, + context->eigen_device() + ); + + // flat the tensors + FPTYPE * dy_dem_x = dy_dem_x_tensor->flat().data(); + FPTYPE * dy_dem = dy_dem_tensor->flat().data(); + const FPTYPE * descriptor = descriptor_tensor.flat().data(); + const FPTYPE * table = table_tensor.flat().data(); + const FPTYPE * table_info = table_info_tensor.flat().data(); + const FPTYPE * em_x = em_x_tensor.flat().data(); + const FPTYPE * em = em_tensor.flat().data(); + const FPTYPE * dy = dy_tensor.flat().data(); + const int nloc = em_tensor.shape().dim_size(0); + const int nnei = em_tensor.shape().dim_size(1); + const int last_layer_size = descriptor_tensor.shape().dim_size(2); + + if (device == "GPU") { + #if GOOGLE_CUDA + tabulate_fusion_grad_gpu_cuda( + dy_dem_x, dy_dem, + table, table_info, em_x, em, dy, nloc, nnei, last_layer_size); + #endif // GOOGLE_CUDA + } + else if (device == "CPU") { + tabulate_fusion_grad_cpu( + dy_dem_x, dy_dem, + table, table_info, em_x, em, dy, nloc, nnei, last_layer_size); } + } private: + std::string device; }; #define REGISTER_CPU(T) \ diff --git a/source/op/unaggregated_grad.cc b/source/op/unaggregated_grad.cc index 39b70ceee0..9cc2b5ef2a 100644 --- a/source/op/unaggregated_grad.cc +++ b/source/op/unaggregated_grad.cc @@ -1,17 +1,7 @@ -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_kernel.h" -#include "tensorflow/core/framework/shape_inference.h" -#include - +#include "custom_op.h" #include "ComputeDescriptor.h" #include "neighbor_list.h" -using namespace tensorflow; -// using namespace std; - -using CPUDevice = Eigen::ThreadPoolDevice; -using GPUDevice = Eigen::GpuDevice; - REGISTER_OP("UnaggregatedDyDxS") .Attr("T: {float, double}") .Input("y: T") From d60af8096c02e21c2585b59d6f3caff7dd12ca38 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 26 Feb 2021 21:12:05 +0800 Subject: [PATCH 209/562] fix bug in expand_sys_dir, add unittest for it --- deepmd/common.py | 6 +++-- source/tests/test_common.py | 48 +++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 source/tests/test_common.py diff --git a/deepmd/common.py b/deepmd/common.py index 04cf73e28f..1486260408 100644 --- a/deepmd/common.py +++ b/deepmd/common.py @@ -427,8 +427,10 @@ def expand_sys_str(root_dir: Union[str, Path]) -> List[str]: List[str] list of string pointing to system directories """ - matches = [d for d in Path(root_dir).rglob("*") if (d / "type.raw").is_file()] - return [str(m.relative_to(root_dir)) for m in matches] + matches = [str(d) for d in Path(root_dir).rglob("*") if (d / "type.raw").is_file()] + if (Path(root_dir) / "type.raw").is_file(): + matches += [root_dir] + return matches def docstring_parameter(*sub: Tuple[str, ...]): diff --git a/source/tests/test_common.py b/source/tests/test_common.py new file mode 100644 index 0000000000..0f052663b2 --- /dev/null +++ b/source/tests/test_common.py @@ -0,0 +1,48 @@ +import os,sys,shutil,fnmatch +import numpy as np +import unittest +from pathlib import Path + +from deepmd.common import expand_sys_str + +# compute relative path +# https://stackoverflow.com/questions/38083555/using-pathlibs-relative-to-for-directories-on-the-same-level +def relpath(path_to, path_from): + path_to = Path(path_to).resolve() + path_from = Path(path_from).resolve() + try: + for p in (*reversed(path_from.parents), path_from): + head, tail = p, path_to.relative_to(p) + except ValueError: # Stop when the paths diverge. + pass + return Path('../' * (len(path_from.parents) - len(head.parents))).joinpath(tail) + +class TestCommonExpandSysDir(unittest.TestCase) : + def setUp(self): + self.match_file = Path('type.raw') + Path('test_sys').mkdir() + self.dir = Path('test_sys') + self.dira = Path('test_sys/a') + self.dirb = Path('test_sys/a/b') + self.dirc = Path('test_sys/c') + self.dird = Path('test_sys/c/d') + self.dire = Path('test_sys/c/type.raw') + self.dira.mkdir() + self.dirb.mkdir() + self.dirc.mkdir() + for ii in [self.dir, self.dira, self.dirb]: + (ii/self.match_file).touch() + relb = relpath(self.dirb, self.dirc) + absb = self.dirb.resolve() + self.dird.symlink_to(relb) + self.dire.symlink_to(absb) + self.expected_out = ['test_sys', 'test_sys/a', 'test_sys/a/b', 'test_sys/c/d', 'test_sys/c/type.raw'] + self.expected_out.sort() + + def tearDown(self): + shutil.rmtree('test_sys') + + def test_expand(self): + ret = expand_sys_str('test_sys') + ret.sort() + self.assertEqual(ret, self.expected_out) From f3806b22beefd50177aa4264e496c2c74cd519b5 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Fri, 26 Feb 2021 21:40:55 +0800 Subject: [PATCH 210/562] adjust code spaces --- source/api_cc/include/custom_op.h | 4 +- source/lib/src/cuda/gelu.cu | 4 +- source/lib/src/cuda/prod_force.cu | 27 +++++---- source/lib/src/cuda/prod_virial.cu | 23 ++++---- source/lib/src/gelu.cc | 2 +- source/op/prod_env_mat_multi_device.cc | 82 +++++++++++++------------- source/op/prod_force_multi_device.cc | 44 +++++++------- source/op/prod_virial_multi_device.cc | 60 +++++++++---------- 8 files changed, 126 insertions(+), 120 deletions(-) diff --git a/source/api_cc/include/custom_op.h b/source/api_cc/include/custom_op.h index 714e9f3d33..9cb386dd23 100644 --- a/source/api_cc/include/custom_op.h +++ b/source/api_cc/include/custom_op.h @@ -34,12 +34,12 @@ struct DeviceFunctor { { device = "CPU"; } -#if GOOGLE_CUDA + #if GOOGLE_CUDA void operator()( std::string& device, const GPUDevice& d) { device = "GPU"; } -#endif // GOOGLE_CUDA + #endif // GOOGLE_CUDA }; \ No newline at end of file diff --git a/source/lib/src/cuda/gelu.cu b/source/lib/src/cuda/gelu.cu index 37e44329cd..cd4cfa0541 100644 --- a/source/lib/src/cuda/gelu.cu +++ b/source/lib/src/cuda/gelu.cu @@ -33,8 +33,8 @@ __global__ void gelu_grad( template __global__ void gelu_grad_grad( - FPTYPE * out, - const FPTYPE * xx, + FPTYPE * out, + const FPTYPE * xx, const FPTYPE * dy, const FPTYPE * dy_2, int const size) diff --git a/source/lib/src/cuda/prod_force.cu b/source/lib/src/cuda/prod_force.cu index c5fe49b99b..2f6e5f8479 100644 --- a/source/lib/src/cuda/prod_force.cu +++ b/source/lib/src/cuda/prod_force.cu @@ -3,16 +3,19 @@ #include "prod_force.h" #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600 -static __inline__ __device__ double atomicAdd(double* address, double val) { - unsigned long long int* address_as_ull = (unsigned long long int*)address; - unsigned long long int old = *address_as_ull, assumed; - do { - assumed = old; - old = atomicCAS(address_as_ull, assumed, - __double_as_longlong(val + __longlong_as_double(assumed))); - // Note: uses integer comparison to avoid hang in case of NaN (since NaN != NaN) } while (assumed != old); - } while (assumed != old); - return __longlong_as_double(old); +static __inline__ __device__ double atomicAdd( + double* address, + double val) +{ + unsigned long long int* address_as_ull = (unsigned long long int*)address; + unsigned long long int old = *address_as_ull, assumed; + do { + assumed = old; + old = atomicCAS(address_as_ull, assumed, + __double_as_longlong(val + __longlong_as_double(assumed))); + // Note: uses integer comparison to avoid hang in case of NaN (since NaN != NaN) } while (assumed != old); + } while (assumed != old); + return __longlong_as_double(old); } #endif @@ -105,8 +108,8 @@ __global__ void force_deriv_wrt_neighbors_r( return; } atomicAdd( - force + j_idx * 3 + idz, - net_deriv[idx * ndescrpt + idy] * in_deriv[idx * ndescrpt * 3 + idy * 3 + idz]); + force + j_idx * 3 + idz, + net_deriv[idx * ndescrpt + idy] * in_deriv[idx * ndescrpt * 3 + idy * 3 + idz]); } template diff --git a/source/lib/src/cuda/prod_virial.cu b/source/lib/src/cuda/prod_virial.cu index cdecad83c9..95d912e737 100644 --- a/source/lib/src/cuda/prod_virial.cu +++ b/source/lib/src/cuda/prod_virial.cu @@ -2,16 +2,19 @@ #include "prod_virial.h" #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600 -static __inline__ __device__ double atomicAdd(double* address, double val) { - unsigned long long int* address_as_ull = (unsigned long long int*)address; - unsigned long long int old = *address_as_ull, assumed; - do { - assumed = old; - old = atomicCAS(address_as_ull, assumed, - __double_as_longlong(val + __longlong_as_double(assumed))); - // Note: uses integer comparison to avoid hang in case of NaN (since NaN != NaN) } while (assumed != old); - } while (assumed != old); - return __longlong_as_double(old); +static __inline__ __device__ double atomicAdd( + double* address, + double val) +{ + unsigned long long int* address_as_ull = (unsigned long long int*)address; + unsigned long long int old = *address_as_ull, assumed; + do { + assumed = old; + old = atomicCAS(address_as_ull, assumed, + __double_as_longlong(val + __longlong_as_double(assumed))); + // Note: uses integer comparison to avoid hang in case of NaN (since NaN != NaN) } while (assumed != old); + } while (assumed != old); + return __longlong_as_double(old); } #endif diff --git a/source/lib/src/gelu.cc b/source/lib/src/gelu.cc index 7f0cde9a65..b887df89de 100644 --- a/source/lib/src/gelu.cc +++ b/source/lib/src/gelu.cc @@ -37,7 +37,7 @@ void gelu_grad_grad_cpu( for (int ii = 0; ii < size; ii++) { const FPTYPE var1 = tanh(SQRT_2_PI * (xx[ii] + 0.044715 * xx[ii] * xx[ii] *xx[ii])); const FPTYPE var2 = SQRT_2_PI * (1 - var1 * var1) * (0.134145 * xx[ii] * xx[ii] + 1); - out[ii] = dy[ii] * dy_2[ii] * (0.134145 * SQRT_2_PI * xx[ii] * xx[ii] * (1 - var1 * var1) - SQRT_2_PI * xx[ii] * var2 * (0.134145 * xx[ii] * xx[ii] + 1) * var1 + var2); + out[ii] = dy[ii] * dy_2[ii] * (0.134145 * SQRT_2_PI * xx[ii] * xx[ii] * (1 - var1 * var1) - SQRT_2_PI * xx[ii] * var2 * (0.134145 * xx[ii] * xx[ii] + 1) * var1 + var2); } } diff --git a/source/op/prod_env_mat_multi_device.cc b/source/op/prod_env_mat_multi_device.cc index 32d4f96cfe..54ce6bde1f 100644 --- a/source/op/prod_env_mat_multi_device.cc +++ b/source/op/prod_env_mat_multi_device.cc @@ -73,14 +73,14 @@ class DescrptSeAOp : public OpKernel { const Tensor& avg_tensor = context->input(context_input_index++); const Tensor& std_tensor = context->input(context_input_index++); // set size of the sample. assume 't' is [[[1, 1, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]]], then shape(t) ==> [2, 2, 3] - OP_REQUIRES (context, (coord_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of coord should be 2")); - OP_REQUIRES (context, (type_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of type should be 2")); - OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); - OP_REQUIRES (context, (box_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of box should be 2")); - OP_REQUIRES (context, (mesh_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of mesh should be 1")); - OP_REQUIRES (context, (avg_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of avg should be 2")); - OP_REQUIRES (context, (std_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of std should be 2")); - OP_REQUIRES (context, (sec_r.back() == 0), errors::InvalidArgument ("Rotational free descriptor only support all-angular information: sel_r should be all zero.")); + OP_REQUIRES (context, (coord_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of coord should be 2")); + OP_REQUIRES (context, (type_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of type should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + OP_REQUIRES (context, (box_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of box should be 2")); + OP_REQUIRES (context, (mesh_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of mesh should be 1")); + OP_REQUIRES (context, (avg_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of avg should be 2")); + OP_REQUIRES (context, (std_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of std should be 2")); + OP_REQUIRES (context, (sec_r.back() == 0), errors::InvalidArgument ("Rotational free descriptor only support all-angular information: sel_r should be all zero.")); OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); DeviceFunctor() ( device, @@ -92,19 +92,19 @@ class DescrptSeAOp : public OpKernel { int ntypes = natoms_tensor.shape().dim_size(0) - 2; //nloc and nall mean something. int nsamples = coord_tensor.shape().dim_size(0); //// check the sizes - OP_REQUIRES (context, (nsamples == type_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (nsamples == box_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (ntypes == avg_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of avg should be ntype")); - OP_REQUIRES (context, (ntypes == std_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of std should be ntype")); + OP_REQUIRES (context, (nsamples == type_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nsamples == box_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (ntypes == avg_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of avg should be ntype")); + OP_REQUIRES (context, (ntypes == std_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of std should be ntype")); - OP_REQUIRES (context, (nall * 3 == coord_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); - OP_REQUIRES (context, (nall == type_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); - OP_REQUIRES (context, (9 == box_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of box should be 9")); - OP_REQUIRES (context, (ndescrpt == avg_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of avg should be ndescrpt")); - OP_REQUIRES (context, (ndescrpt == std_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of std should be ndescrpt")); + OP_REQUIRES (context, (nall * 3 == coord_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); + OP_REQUIRES (context, (nall == type_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); + OP_REQUIRES (context, (9 == box_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of box should be 9")); + OP_REQUIRES (context, (ndescrpt == avg_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of avg should be ndescrpt")); + OP_REQUIRES (context, (ndescrpt == std_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of std should be ndescrpt")); - OP_REQUIRES (context, (ntypes == int(sel_a.size())), errors::InvalidArgument ("number of types should match the length of sel array")); - OP_REQUIRES (context, (ntypes == int(sel_r.size())), errors::InvalidArgument ("number of types should match the length of sel array")); + OP_REQUIRES (context, (ntypes == int(sel_a.size())), errors::InvalidArgument ("number of types should match the length of sel array")); + OP_REQUIRES (context, (ntypes == int(sel_r.size())), errors::InvalidArgument ("number of types should match the length of sel array")); // Create output tensors TensorShape descrpt_shape ; descrpt_shape.AddDim (nsamples); @@ -221,22 +221,22 @@ class DescrptSeROp : public OpKernel { void Compute(OpKernelContext* context) override { // Grab the input tensor int context_input_index = 0; - const Tensor& coord_tensor = context->input(context_input_index++); - const Tensor& type_tensor = context->input(context_input_index++); - const Tensor& natoms_tensor = context->input(context_input_index++); - const Tensor& box_tensor = context->input(context_input_index++); - const Tensor& mesh_tensor = context->input(context_input_index++); - const Tensor& avg_tensor = context->input(context_input_index++); - const Tensor& std_tensor = context->input(context_input_index++); + const Tensor& coord_tensor = context->input(context_input_index++); + const Tensor& type_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); + const Tensor& box_tensor = context->input(context_input_index++); + const Tensor& mesh_tensor = context->input(context_input_index++); + const Tensor& avg_tensor = context->input(context_input_index++); + const Tensor& std_tensor = context->input(context_input_index++); // set size of the sample OP_REQUIRES (context, (coord_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of coord should be 2")); OP_REQUIRES (context, (type_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of type should be 2")); - OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); - OP_REQUIRES (context, (box_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of box should be 2")); - OP_REQUIRES (context, (mesh_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of mesh should be 1")); - OP_REQUIRES (context, (avg_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of avg should be 2")); - OP_REQUIRES (context, (std_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of std should be 2")); - OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + OP_REQUIRES (context, (box_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of box should be 2")); + OP_REQUIRES (context, (mesh_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of mesh should be 1")); + OP_REQUIRES (context, (avg_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of avg should be 2")); + OP_REQUIRES (context, (std_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of std should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); DeviceFunctor() ( device, context->eigen_device() @@ -249,15 +249,15 @@ class DescrptSeROp : public OpKernel { // //// check the sizes // check the sizes - OP_REQUIRES (context, (nsamples == type_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (nsamples == box_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (ntypes == avg_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of avg should be ntype")); - OP_REQUIRES (context, (ntypes == std_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of std should be ntype")); - OP_REQUIRES (context, (nall * 3 == coord_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); - OP_REQUIRES (context, (nall == type_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); - OP_REQUIRES (context, (9 == box_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of box should be 9")); - OP_REQUIRES (context, (ndescrpt == avg_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of avg should be ndescrpt")); - OP_REQUIRES (context, (ndescrpt == std_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of std should be ndescrpt")); + OP_REQUIRES (context, (nsamples == type_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nsamples == box_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (ntypes == avg_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of avg should be ntype")); + OP_REQUIRES (context, (ntypes == std_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of std should be ntype")); + OP_REQUIRES (context, (nall * 3 == coord_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); + OP_REQUIRES (context, (nall == type_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of atoms should match")); + OP_REQUIRES (context, (9 == box_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of box should be 9")); + OP_REQUIRES (context, (ndescrpt == avg_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of avg should be ndescrpt")); + OP_REQUIRES (context, (ndescrpt == std_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of std should be ndescrpt")); // Create an output tensor TensorShape descrpt_shape ; descrpt_shape.AddDim (nsamples); diff --git a/source/op/prod_force_multi_device.cc b/source/op/prod_force_multi_device.cc index f86d349149..372c9e2169 100644 --- a/source/op/prod_force_multi_device.cc +++ b/source/op/prod_force_multi_device.cc @@ -27,16 +27,16 @@ class ProdForceSeAOp : public OpKernel { void Compute(OpKernelContext* context) override { // Grab the input tensor int context_input_index = 0; - const Tensor& net_deriv_tensor = context->input(context_input_index++); - const Tensor& in_deriv_tensor = context->input(context_input_index++); - const Tensor& nlist_tensor = context->input(context_input_index++); - const Tensor& natoms_tensor = context->input(context_input_index++); + const Tensor& net_deriv_tensor = context->input(context_input_index++); + const Tensor& in_deriv_tensor = context->input(context_input_index++); + const Tensor& nlist_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); // set size of the sample - OP_REQUIRES (context, (net_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of net deriv should be 2")); - OP_REQUIRES (context, (in_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); - OP_REQUIRES (context, (nlist_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); - OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); - OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + OP_REQUIRES (context, (net_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of net deriv should be 2")); + OP_REQUIRES (context, (in_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); + OP_REQUIRES (context, (nlist_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); const int * natoms = natoms_tensor.flat().data(); int nloc = natoms[0]; int nall = natoms[1]; @@ -44,8 +44,8 @@ class ProdForceSeAOp : public OpKernel { int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; int nnei = nlist_tensor.shape().dim_size(1) / nloc; // check the sizes - OP_REQUIRES (context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (nframes == nlist_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nframes == nlist_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); OP_REQUIRES (context, (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of descriptors should match")); // Create an output tensor TensorShape force_shape ; @@ -100,16 +100,16 @@ class ProdForceSeROp : public OpKernel { void Compute(OpKernelContext* context) override { // Grab the input tensor int context_input_index = 0; - const Tensor& net_deriv_tensor = context->input(context_input_index++); - const Tensor& in_deriv_tensor = context->input(context_input_index++); - const Tensor& nlist_tensor = context->input(context_input_index++); - const Tensor& natoms_tensor = context->input(context_input_index++); + const Tensor& net_deriv_tensor = context->input(context_input_index++); + const Tensor& in_deriv_tensor = context->input(context_input_index++); + const Tensor& nlist_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); // set size of the sample - OP_REQUIRES (context, (net_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of net deriv should be 2")); - OP_REQUIRES (context, (in_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); - OP_REQUIRES (context, (nlist_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); - OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); - OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + OP_REQUIRES (context, (net_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of net deriv should be 2")); + OP_REQUIRES (context, (in_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); + OP_REQUIRES (context, (nlist_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); const int * natoms = natoms_tensor.flat().data(); int nloc = natoms[0]; int nall = natoms[1]; @@ -117,8 +117,8 @@ class ProdForceSeROp : public OpKernel { int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; int nnei = nlist_tensor.shape().dim_size(1) / nloc; // check the sizes - OP_REQUIRES (context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (nframes == nlist_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nframes == nlist_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); OP_REQUIRES (context, (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of descriptors should match")); // Create an output tensor TensorShape force_shape ; diff --git a/source/op/prod_virial_multi_device.cc b/source/op/prod_virial_multi_device.cc index d4f4c0675a..9aab65443c 100644 --- a/source/op/prod_virial_multi_device.cc +++ b/source/op/prod_virial_multi_device.cc @@ -30,18 +30,18 @@ class ProdVirialSeAOp : public OpKernel { void Compute(OpKernelContext* context) override { // Grab the input tensor int context_input_index = 0; - const Tensor& net_deriv_tensor = context->input(context_input_index++); - const Tensor& in_deriv_tensor = context->input(context_input_index++); - const Tensor& rij_tensor = context->input(context_input_index++); - const Tensor& nlist_tensor = context->input(context_input_index++); - const Tensor& natoms_tensor = context->input(context_input_index++); + const Tensor& net_deriv_tensor = context->input(context_input_index++); + const Tensor& in_deriv_tensor = context->input(context_input_index++); + const Tensor& rij_tensor = context->input(context_input_index++); + const Tensor& nlist_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); // set size of the sample - OP_REQUIRES (context, (net_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of net deriv should be 2")); - OP_REQUIRES (context, (in_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); - OP_REQUIRES (context, (rij_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of rij should be 2")); - OP_REQUIRES (context, (nlist_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); - OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); - OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + OP_REQUIRES (context, (net_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of net deriv should be 2")); + OP_REQUIRES (context, (in_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); + OP_REQUIRES (context, (rij_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of rij should be 2")); + OP_REQUIRES (context, (nlist_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); const int * natoms = natoms_tensor.flat().data(); int nloc = natoms[0]; int nall = natoms[1]; @@ -49,11 +49,11 @@ class ProdVirialSeAOp : public OpKernel { int nframes = net_deriv_tensor.shape().dim_size(0); int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; // check the sizes - OP_REQUIRES (context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (nframes == rij_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (nframes == nlist_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nframes == rij_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nframes == nlist_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); OP_REQUIRES (context, (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of descriptors should match")); - OP_REQUIRES (context, (nloc * nnei * 3 == rij_tensor.shape().dim_size(1)), errors::InvalidArgument ("dim of rij should be nnei * 3")); + OP_REQUIRES (context, (nloc * nnei * 3 == rij_tensor.shape().dim_size(1)), errors::InvalidArgument ("dim of rij should be nnei * 3")); // Create an output tensor TensorShape virial_shape ; virial_shape.AddDim (nframes); @@ -108,18 +108,18 @@ class ProdVirialSeROp : public OpKernel { void Compute(OpKernelContext* context) override { // Grab the input tensor int context_input_index = 0; - const Tensor& net_deriv_tensor = context->input(context_input_index++); - const Tensor& in_deriv_tensor = context->input(context_input_index++); - const Tensor& rij_tensor = context->input(context_input_index++); - const Tensor& nlist_tensor = context->input(context_input_index++); - const Tensor& natoms_tensor = context->input(context_input_index++); + const Tensor& net_deriv_tensor = context->input(context_input_index++); + const Tensor& in_deriv_tensor = context->input(context_input_index++); + const Tensor& rij_tensor = context->input(context_input_index++); + const Tensor& nlist_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); // set size of the sample - OP_REQUIRES (context, (net_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of net deriv should be 2")); - OP_REQUIRES (context, (in_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); - OP_REQUIRES (context, (rij_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of rij should be 2")); - OP_REQUIRES (context, (nlist_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); - OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); - OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + OP_REQUIRES (context, (net_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of net deriv should be 2")); + OP_REQUIRES (context, (in_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); + OP_REQUIRES (context, (rij_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of rij should be 2")); + OP_REQUIRES (context, (nlist_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); const int * natoms = natoms_tensor.flat().data(); int nloc = natoms[0]; int nall = natoms[1]; @@ -127,11 +127,11 @@ class ProdVirialSeROp : public OpKernel { int nframes = net_deriv_tensor.shape().dim_size(0); int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; // check the sizes - OP_REQUIRES (context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (nframes == rij_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (nframes == nlist_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nframes == rij_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); + OP_REQUIRES (context, (nframes == nlist_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); OP_REQUIRES (context, (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of descriptors should match")); - OP_REQUIRES (context, (nloc * nnei * 3 == rij_tensor.shape().dim_size(1)), errors::InvalidArgument ("dim of rij should be nnei * 3")); + OP_REQUIRES (context, (nloc * nnei * 3 == rij_tensor.shape().dim_size(1)), errors::InvalidArgument ("dim of rij should be nnei * 3")); // Create an output tensor TensorShape virial_shape ; virial_shape.AddDim (nframes); From 31721c6e609740a4182473ba17dc8bbe0bb51a13 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 26 Feb 2021 23:04:17 +0800 Subject: [PATCH 211/562] fix bug in main (no command) and config (systems type and rcut default type) --- deepmd/entrypoints/config.py | 4 ++-- source/train/main.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/deepmd/entrypoints/config.py b/deepmd/entrypoints/config.py index d5b2044d25..0c98bb5f82 100644 --- a/deepmd/entrypoints/config.py +++ b/deepmd/entrypoints/config.py @@ -125,7 +125,7 @@ def get_rcut() -> float: ValueError if rcut is smaller than 0.0 """ - dv = 6 + dv = 6.0 rcut_input = input(f"Enter rcut (default {dv:.1f} A): \n") try: rcut = float(rcut_input) @@ -336,7 +336,7 @@ def config(*, output: str, **kwargs): decay_steps, decay_rate = suggest_decay(stop_batch) jdata = DEFAULT_DATA.copy() - jdata["systems"] = all_sys + jdata["systems"] = [str(ii) for ii in all_sys] jdata["sel_a"] = sel jdata["rcut"] = rcut jdata["rcut_smth"] = rcut - 0.2 diff --git a/source/train/main.py b/source/train/main.py index a7b5574cdd..366b6a1a94 100644 --- a/source/train/main.py +++ b/source/train/main.py @@ -327,5 +327,7 @@ def main(): compress(**dict_args) elif args.command == "doc-train-input": doc_train_input() + elif args.command is None: + pass else: raise RuntimeError(f"unknown command {args.command}") From ba6c98fd1f4f22bdd41eec979172351c35ffd0c7 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 27 Feb 2021 10:44:27 +0800 Subject: [PATCH 212/562] fix bug in neighbor stat --- deepmd/utils/neighbor_stat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deepmd/utils/neighbor_stat.py b/deepmd/utils/neighbor_stat.py index ed9467a731..c48ed641d2 100644 --- a/deepmd/utils/neighbor_stat.py +++ b/deepmd/utils/neighbor_stat.py @@ -32,7 +32,7 @@ def __init__(self, sub_graph = tf.Graph() with sub_graph.as_default(): for ii in ['coord', 'box']: - self.place_holders[ii] = tf.placeholder(global_np_float_precision, [None, None], name='t_'+ii) + self.place_holders[ii] = tf.placeholder(GLOBAL_NP_FLOAT_PRECISION, [None, None], name='t_'+ii) self.place_holders['type'] = tf.placeholder(tf.int32, [None, None], name='t_type') self.place_holders['natoms_vec'] = tf.placeholder(tf.int32, [self.ntypes+2], name='t_natoms') self.place_holders['default_mesh'] = tf.placeholder(tf.int32, [None], name='t_mesh') From 992e96d6334cbc761272b5db8c86fcb9c37d90ba Mon Sep 17 00:00:00 2001 From: denghuilu Date: Sun, 28 Feb 2021 18:07:21 +0800 Subject: [PATCH 213/562] rm custom_op.h from api_cc to op --- .gitmodules | 2 +- deepmd/utils/neighbor_stat.py | 10 +++++++--- deepmd/utils/tabulate.py | 10 +++++++--- source/api_cc/include/common.h | 24 ++++++++++++++++++++--- source/lib/include/prod_virial.h | 8 ++++---- source/lib/src/cuda/CMakeLists.txt | 2 +- source/op/custom_op.h | 29 ++++++++++++++++++++++++++++ source/op/descrpt.cc | 3 +++ source/op/descrpt_se_a.cc | 3 +++ source/op/descrpt_se_a_ef.cc | 3 +++ source/op/descrpt_se_a_ef_para.cc | 3 +++ source/op/descrpt_se_a_ef_vert.cc | 3 +++ source/op/descrpt_se_r.cc | 3 +++ source/op/ewald_recp.cc | 3 +++ source/op/neighbor_stat.cc | 3 +++ source/op/prod_force_multi_device.cc | 2 +- 16 files changed, 95 insertions(+), 16 deletions(-) create mode 100644 source/op/custom_op.h diff --git a/.gitmodules b/.gitmodules index c7710397a0..5373ec05b3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "source/lib/src/cuda/cub"] path = source/lib/src/cuda/cub - url = git://github.com/NVlabs/cub.git + url = git://github.com/NVIDIA/cub.git diff --git a/deepmd/utils/neighbor_stat.py b/deepmd/utils/neighbor_stat.py index c48ed641d2..255a81b453 100644 --- a/deepmd/utils/neighbor_stat.py +++ b/deepmd/utils/neighbor_stat.py @@ -1,4 +1,5 @@ import math +import logging import numpy as np from tqdm import tqdm from deepmd.env import tf @@ -8,6 +9,8 @@ from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION from deepmd.utils.data_system import DeepmdDataSystem +log = logging.getLogger(__name__) + class NeighborStat(): """ Class for getting training data information. @@ -65,7 +68,8 @@ def get_stat(self, self.min_nbor_dist = 100.0 self.max_nbor_size = [0] * self.ntypes - for ii in tqdm(range(len(data.system_dirs)), desc = '# DEEPMD: getting data info'): + # for ii in tqdm(range(len(data.system_dirs)), desc = 'DEEPMD INFO |-> deepmd.utils.neighbor_stat\t\t\tgetting neighbor status'): + for ii in range(len(data.system_dirs)): for jj in data.data_systems[ii].dirs: data_set = data.data_systems[ii]._load_set(jj) for kk in range(np.array(data_set['type']).shape[0]): @@ -86,6 +90,6 @@ def get_stat(self, if var > self.max_nbor_size[ww]: self.max_nbor_size[ww] = var - print('# DEEPMD: training data with min nbor dist: ' + str(self.min_nbor_dist)) - print('# DEEPMD: training data with max nbor size: ' + str(self.max_nbor_size)) + log.info('training data with min nbor dist: ' + str(self.min_nbor_dist)) + log.info('training data with max nbor size: ' + str(self.max_nbor_size)) return self.min_nbor_dist, self.max_nbor_size diff --git a/deepmd/utils/tabulate.py b/deepmd/utils/tabulate.py index 4291a8127b..ad13365f55 100644 --- a/deepmd/utils/tabulate.py +++ b/deepmd/utils/tabulate.py @@ -1,5 +1,6 @@ import re import math +import logging import numpy as np from tqdm import tqdm from typing import Tuple, List @@ -8,6 +9,8 @@ from tensorflow.python.platform import gfile from tensorflow.python.framework import tensor_util +log = logging.getLogger(__name__) + class DeepTabulate(): """ Class for tabulation. @@ -106,7 +109,8 @@ def build(self, else: net = "filter_" + str(int(ii / self.ntypes)) + "_net_" + str(int(ii % self.ntypes)) self.data[net] = np.zeros([self.nspline, 6 * self.last_layer_size], dtype = self.data_type) - for jj in tqdm(range(self.nspline), desc = '# DEEPMD: ' + net + ', tabulating'): + # for jj in tqdm(range(self.nspline), desc = 'DEEPMD INFO |-> deepmd.utils.tabulate\t\t\t' + net + ', tabulating'): + for jj in range(self.nspline): for kk in range(self.last_layer_size): if jj < int((upper - lower) / stride0): tt = stride0 @@ -227,8 +231,8 @@ def _get_env_mat_range(self, lower = -self.davg[ii][0] / self.dstd[ii][0] if upper < ((1 / min_nbor_dist) * sw - self.davg[ii][0]) / self.dstd[ii][0]: upper = ((1 / min_nbor_dist) * sw - self.davg[ii][0]) / self.dstd[ii][0] - print('# DEEPMD: training data with lower boundary: ' + str(lower)) - print('# DEEPMD: training data with upper boundary: ' + str(upper)) + log.info('training data with lower boundary: ' + str(lower)) + log.info('training data with upper boundary: ' + str(upper)) return math.floor(lower), math.ceil(upper) def _spline5_switch(self, diff --git a/source/api_cc/include/common.h b/source/api_cc/include/common.h index 13a03b873c..4014b643b8 100644 --- a/source/api_cc/include/common.h +++ b/source/api_cc/include/common.h @@ -1,14 +1,31 @@ #pragma once -#include "custom_op.h" -#include "NNPAtomMap.h" + +#include +#include +#include #include "version.h" +#include "NNPAtomMap.h" + +#include "tensorflow/core/platform/env.h" +#include "tensorflow/core/public/session.h" +#include "tensorflow/core/public/version.h" +#include +#include +using namespace tensorflow; #if TF_MAJOR_VERSION >= 2 && TF_MINOR_VERSION >= 2 typedef tensorflow::tstring STRINGTYPE; #else typedef std::string STRINGTYPE; #endif +#ifdef HIGH_PREC +typedef double VALUETYPE; +typedef double ENERGYTYPE; +#else +typedef float VALUETYPE; +typedef double ENERGYTYPE; +#endif struct LammpsNeighborList { @@ -217,4 +234,5 @@ select_map(std::vector & out, } } } -} \ No newline at end of file +} + diff --git a/source/lib/include/prod_virial.h b/source/lib/include/prod_virial.h index c86d47f79b..5a5c9ad996 100644 --- a/source/lib/include/prod_virial.h +++ b/source/lib/include/prod_virial.h @@ -6,7 +6,7 @@ void prod_virial_a_cpu( FPTYPE * atom_virial, const FPTYPE * net_deriv, const FPTYPE * env_deriv, - const FPTYPE * rij_deriv, + const FPTYPE * rij, const int * nlist, const int nloc, const int nall, @@ -18,7 +18,7 @@ void prod_virial_r_cpu( FPTYPE * atom_virial, const FPTYPE * net_deriv, const FPTYPE * env_deriv, - const FPTYPE * rij_deriv, + const FPTYPE * rij, const int * nlist, const int nloc, const int nall, @@ -31,7 +31,7 @@ void prod_virial_a_gpu_cuda( FPTYPE * atom_virial, const FPTYPE * net_deriv, const FPTYPE * env_deriv, - const FPTYPE * rij_deriv, + const FPTYPE * rij, const int * nlist, const int nloc, const int nall, @@ -43,7 +43,7 @@ void prod_virial_r_gpu_cuda( FPTYPE * atom_virial, const FPTYPE * net_deriv, const FPTYPE * env_deriv, - const FPTYPE * rij_deriv, + const FPTYPE * rij, const int * nlist, const int nloc, const int nall, diff --git a/source/lib/src/cuda/CMakeLists.txt b/source/lib/src/cuda/CMakeLists.txt index 92ffe8e78a..953e8d9ea3 100644 --- a/source/lib/src/cuda/CMakeLists.txt +++ b/source/lib/src/cuda/CMakeLists.txt @@ -93,5 +93,5 @@ if (BUILD_CPP_IF) install(TARGETS deepmd_op_cuda DESTINATION lib/) endif (BUILD_CPP_IF) if (BUILD_PY_IF) - install(TARGETS deepmd_op_cuda DESTINATION deepmd/) + install(TARGETS deepmd_op_cuda DESTINATION deepmd/op/) endif (BUILD_PY_IF) diff --git a/source/op/custom_op.h b/source/op/custom_op.h new file mode 100644 index 0000000000..6a8533f66f --- /dev/null +++ b/source/op/custom_op.h @@ -0,0 +1,29 @@ +#include +#include +#include + +#include "tensorflow/core/framework/op.h" +#include "tensorflow/core/framework/op_kernel.h" +#include "tensorflow/core/framework/shape_inference.h" + +using namespace tensorflow; +using CPUDevice = Eigen::ThreadPoolDevice; +using GPUDevice = Eigen::GpuDevice; + +// functions used in custom ops +struct DeviceFunctor { + void operator()( + std::string& device, + const CPUDevice& d) + { + device = "CPU"; + } + #if GOOGLE_CUDA + void operator()( + std::string& device, + const GPUDevice& d) + { + device = "GPU"; + } + #endif // GOOGLE_CUDA +}; \ No newline at end of file diff --git a/source/op/descrpt.cc b/source/op/descrpt.cc index bd6693d520..c96f3a3a44 100644 --- a/source/op/descrpt.cc +++ b/source/op/descrpt.cc @@ -3,6 +3,9 @@ #include "neighbor_list.h" #include "fmt_nlist.h" +typedef double boxtensor_t ; +typedef double compute_t; + REGISTER_OP("Descrpt") .Attr("T: {float, double}") .Input("coord: T") diff --git a/source/op/descrpt_se_a.cc b/source/op/descrpt_se_a.cc index 99b9f0f5ca..4444ac0218 100644 --- a/source/op/descrpt_se_a.cc +++ b/source/op/descrpt_se_a.cc @@ -4,6 +4,9 @@ #include "fmt_nlist.h" #include "env_mat.h" +typedef double boxtensor_t ; +typedef double compute_t; + REGISTER_OP("DescrptSeA") .Attr("T: {float, double}") .Input("coord: T") //atomic coordinates diff --git a/source/op/descrpt_se_a_ef.cc b/source/op/descrpt_se_a_ef.cc index 5c30ed19dd..607c9bf1c5 100644 --- a/source/op/descrpt_se_a_ef.cc +++ b/source/op/descrpt_se_a_ef.cc @@ -4,6 +4,9 @@ #include "neighbor_list.h" #include "fmt_nlist.h" +typedef double boxtensor_t ; +typedef double compute_t; + REGISTER_OP("DescrptSeAEf") .Attr("T: {float, double}") .Input("coord: T") diff --git a/source/op/descrpt_se_a_ef_para.cc b/source/op/descrpt_se_a_ef_para.cc index 1f7819601e..2a83026874 100644 --- a/source/op/descrpt_se_a_ef_para.cc +++ b/source/op/descrpt_se_a_ef_para.cc @@ -3,6 +3,9 @@ #include "neighbor_list.h" #include "fmt_nlist.h" +typedef double boxtensor_t ; +typedef double compute_t; + REGISTER_OP("DescrptSeAEfPara") .Attr("T: {float, double}") .Input("coord: T") diff --git a/source/op/descrpt_se_a_ef_vert.cc b/source/op/descrpt_se_a_ef_vert.cc index fca75a0ce6..c98f2fc615 100644 --- a/source/op/descrpt_se_a_ef_vert.cc +++ b/source/op/descrpt_se_a_ef_vert.cc @@ -3,6 +3,9 @@ #include "neighbor_list.h" #include "fmt_nlist.h" +typedef double boxtensor_t ; +typedef double compute_t; + REGISTER_OP("DescrptSeAEfVert") .Attr("T: {float, double}") .Input("coord: T") diff --git a/source/op/descrpt_se_r.cc b/source/op/descrpt_se_r.cc index 0da2d8ef6b..c76f247a51 100644 --- a/source/op/descrpt_se_r.cc +++ b/source/op/descrpt_se_r.cc @@ -4,6 +4,9 @@ #include "fmt_nlist.h" #include "env_mat.h" +typedef double boxtensor_t ; +typedef double compute_t; + REGISTER_OP("DescrptSeR") .Attr("T: {float, double}") .Input("coord: T") diff --git a/source/op/ewald_recp.cc b/source/op/ewald_recp.cc index 739cb5faca..956582c8c2 100644 --- a/source/op/ewald_recp.cc +++ b/source/op/ewald_recp.cc @@ -1,6 +1,9 @@ #include "custom_op.h" #include "Ewald.h" +typedef double boxtensor_t ; +typedef double compute_t; + REGISTER_OP("EwaldRecp") .Attr("T: {float, double}") .Input("coord: T") diff --git a/source/op/neighbor_stat.cc b/source/op/neighbor_stat.cc index 13f3160089..fd9ae776e7 100644 --- a/source/op/neighbor_stat.cc +++ b/source/op/neighbor_stat.cc @@ -1,6 +1,9 @@ #include "custom_op.h" #include "neighbor_list.h" +typedef double boxtensor_t ; +typedef double compute_t; + REGISTER_OP("NeighborStat") .Attr("T: {float, double}") .Input("coord: T") diff --git a/source/op/prod_force_multi_device.cc b/source/op/prod_force_multi_device.cc index 372c9e2169..209a12639f 100644 --- a/source/op/prod_force_multi_device.cc +++ b/source/op/prod_force_multi_device.cc @@ -142,7 +142,7 @@ class ProdForceSeROp : public OpKernel { assert (nloc * ndescrpt == net_deriv_tensor.shape().dim_size(1)); assert (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)); assert (nloc * nnei == nlist_tensor.shape().dim_size(1)); - assert (nnei * 4 == ndescrpt); + assert (nnei * 1 == ndescrpt); // flat the tensors FPTYPE * force = force_tensor->flat().data(); const FPTYPE * net_deriv = net_deriv_tensor.flat().data(); From 62b10c5af65893693185c5dfed29b9ade82ace99 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Sun, 28 Feb 2021 18:17:05 +0800 Subject: [PATCH 214/562] rm compute_t as well as HIPH_PREC from custom_op.h --- source/api_cc/include/custom_op.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/source/api_cc/include/custom_op.h b/source/api_cc/include/custom_op.h index 9cb386dd23..60e15234aa 100644 --- a/source/api_cc/include/custom_op.h +++ b/source/api_cc/include/custom_op.h @@ -15,17 +15,6 @@ using namespace tensorflow; using CPUDevice = Eigen::ThreadPoolDevice; using GPUDevice = Eigen::GpuDevice; -#ifdef HIGH_PREC -typedef double VALUETYPE; -typedef double ENERGYTYPE; -#else -typedef float VALUETYPE; -typedef double ENERGYTYPE; -#endif - -typedef double boxtensor_t ; -typedef double compute_t; - // functions used in custom ops struct DeviceFunctor { void operator()( From 13933cd02bb5c8efa95dd54acb0bbc9a4a7b394f Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 28 Feb 2021 20:47:50 +0800 Subject: [PATCH 215/562] rm MathUtilities.h and mv all necessary functions to utilities.h --- source/lib/include/ComputeDescriptor.h | 94 +++--- source/lib/include/CustomeOperation.h | 2 +- source/lib/include/Ewald.h | 3 +- source/lib/include/MathUtilities.h | 93 ------ source/lib/include/MathUtilities_Impl.h | 353 --------------------- source/lib/include/SimulationRegion.h | 2 +- source/lib/include/SimulationRegion_Impl.h | 12 +- source/lib/include/neighbor_list.h | 2 +- source/lib/include/utilities.h | 60 +++- source/lib/src/env_mat.cc | 8 +- source/lib/src/fmt_nlist.cc | 4 +- source/lib/src/neighbor_list.cc | 6 +- 12 files changed, 126 insertions(+), 513 deletions(-) delete mode 100644 source/lib/include/MathUtilities.h delete mode 100644 source/lib/include/MathUtilities_Impl.h diff --git a/source/lib/include/ComputeDescriptor.h b/source/lib/include/ComputeDescriptor.h index 61fc1d0099..63713d42d8 100644 --- a/source/lib/include/ComputeDescriptor.h +++ b/source/lib/include/ComputeDescriptor.h @@ -5,7 +5,7 @@ #include #include "SimulationRegion.h" -#include "MathUtilities.h" +#include "utilities.h" #include "switcher.h" @@ -110,11 +110,11 @@ compute_dRdT (double (* dRdT)[9], const double *xx = rot; const double *yy = rot+3; - double nr1 = sqrt(MathUtilities::dot (r1, r1)); + double nr1 = sqrt(dot3(r1, r1)); double nr12 = nr1 * nr1; double nr13 = nr1 * nr12; double nr14 = nr12 * nr12; - double r1dr2 = MathUtilities::dot (r1, r2); + double r1dr2 = dot3(r1, r2); // dRdT0 for (int ii = 0; ii < 3; ++ii){ @@ -137,7 +137,7 @@ compute_dRdT (double (* dRdT)[9], } double tmpy[3]; for (int dd = 0; dd < 3; ++dd) tmpy[dd] = r2[dd] - r1dr2 / nr12 * r1[dd]; - double ntmpy = sqrt(MathUtilities::dot(tmpy, tmpy)); + double ntmpy = sqrt(dot3(tmpy, tmpy)); double ydRdy [3] = {0}; for (int ii = 0; ii < 3; ++ii){ for (int jj = 0; jj < 3; ++jj){ @@ -153,8 +153,8 @@ compute_dRdT (double (* dRdT)[9], // dRdT2 for (int ii = 0; ii < 3; ++ii){ double res[3]; - MathUtilities::cprod (dRdT0 + ii*3, yy, dRdT2 + ii*3); - MathUtilities::cprod (xx, dRdT1 + ii*3, res); + cprod(dRdT0 + ii*3, yy, dRdT2 + ii*3); + cprod(xx, dRdT1 + ii*3, res); for (int dd = 0; dd < 3; ++dd) dRdT2[ii*3+dd] += res[dd]; } } @@ -171,11 +171,11 @@ compute_dRdT_1 (double (* dRdT)[9], const double *xx = rot; const double *yy = rot+3; - double nr1 = sqrt(MathUtilities::dot (r1, r1)); + double nr1 = sqrt(dot3(r1, r1)); double nr12 = nr1 * nr1; double nr13 = nr1 * nr12; double nr14 = nr12 * nr12; - double r1dr2 = MathUtilities::dot (r1, r2); + double r1dr2 = dot3(r1, r2); // dRdT0 for (int ii = 0; ii < 3; ++ii){ @@ -198,7 +198,7 @@ compute_dRdT_1 (double (* dRdT)[9], } double tmpy[3]; for (int dd = 0; dd < 3; ++dd) tmpy[dd] = r2[dd] - r1dr2 / nr12 * r1[dd]; - double ntmpy = sqrt(MathUtilities::dot(tmpy, tmpy)); + double ntmpy = sqrt(dot3(tmpy, tmpy)); double ydRdy [3] = {0}; for (int ii = 0; ii < 3; ++ii){ for (int jj = 0; jj < 3; ++jj){ @@ -214,8 +214,8 @@ compute_dRdT_1 (double (* dRdT)[9], // dRdT2 for (int ii = 0; ii < 3; ++ii){ double res[3]; - MathUtilities::cprod (dRdT0 + ii*3, yy, dRdT2 + ii*3); - MathUtilities::cprod (xx, dRdT1 + ii*3, res); + cprod(dRdT0 + ii*3, yy, dRdT2 + ii*3); + cprod(xx, dRdT1 + ii*3, res); for (int dd = 0; dd < 3; ++dd) dRdT2[ii*3+dd] += res[dd]; } } @@ -233,9 +233,9 @@ compute_dRdT_2 (double (* dRdT)[9], const double *xx = rot; const double *yy = rot+3; - double nr1 = sqrt(MathUtilities::dot (r1, r1)); + double nr1 = sqrt(dot3(r1, r1)); double nr12 = nr1 * nr1; - double r1dr2 = MathUtilities::dot (r1, r2); + double r1dr2 = dot3(r1, r2); // dRdT0 for (int ii = 0; ii < 3; ++ii){ @@ -256,7 +256,7 @@ compute_dRdT_2 (double (* dRdT)[9], } double tmpy[3]; for (int dd = 0; dd < 3; ++dd) tmpy[dd] = r2[dd] - r1dr2 / nr12 * r1[dd]; - double ntmpy = sqrt(MathUtilities::dot(tmpy, tmpy)); + double ntmpy = sqrt(dot3(tmpy, tmpy)); double ydRdy [3] = {0}; for (int ii = 0; ii < 3; ++ii){ for (int jj = 0; jj < 3; ++jj){ @@ -272,8 +272,8 @@ compute_dRdT_2 (double (* dRdT)[9], // dRdT2 for (int ii = 0; ii < 3; ++ii){ double res[3]; - MathUtilities::cprod (dRdT0 + ii*3, yy, dRdT2 + ii*3); - MathUtilities::cprod (xx, dRdT1 + ii*3, res); + cprod(dRdT0 + ii*3, yy, dRdT2 + ii*3); + cprod(xx, dRdT1 + ii*3, res); for (int dd = 0; dd < 3; ++dd) dRdT2[ii*3+dd] += res[dd]; } } @@ -353,7 +353,7 @@ void compute_descriptor (std::vector & descrpt_a, // cout << jj << "\t jidx " << j_idx; // if (j_idx >= 0){ // cout << "\t type " << type[j_idx]; - // cout << "\t " << sqrt(MathUtilities::dot (&sel_a_diff[jj][0], &sel_a_diff[jj][0])); + // cout << "\t " << sqrt(dot3(&sel_a_diff[jj][0], &sel_a_diff[jj][0])); // } // cout << endl; // } @@ -365,7 +365,7 @@ void compute_descriptor (std::vector & descrpt_a, // cout << jj << "\t jidx " << j_idx; // if (j_idx >= 0){ // cout << "\t type " << type[j_idx]; - // cout << "\t " << sqrt(MathUtilities::dot (&sel_r_diff[jj][0], &sel_r_diff[jj][0])); + // cout << "\t " << sqrt(dot3(&sel_r_diff[jj][0], &sel_r_diff[jj][0])); // } // cout << endl; // } @@ -402,13 +402,13 @@ void compute_descriptor (std::vector & descrpt_a, xx[dd] = r1[dd]; yy[dd] = r2[dd]; } - double norm_xx = sqrt(MathUtilities::dot (xx, xx)); + double norm_xx = sqrt(dot3(xx, xx)); for (unsigned dd = 0; dd < 3; ++dd) xx[dd] /= norm_xx; - double dxy = MathUtilities::dot (xx, yy); + double dxy = dot3(xx, yy); for (unsigned dd = 0; dd < 3; ++dd) yy[dd] -= dxy * xx[dd]; - double norm_yy = sqrt(MathUtilities::dot (yy, yy)); + double norm_yy = sqrt(dot3(yy, yy)); for (unsigned dd = 0; dd < 3; ++dd) yy[dd] /= norm_yy; - MathUtilities::cprod (xx, yy, zz); + cprod(xx, yy, zz); rot_mat.resize (9); for (int dd = 0; dd < 9; ++dd) rot_mat[dd] = rot[dd]; @@ -419,8 +419,8 @@ void compute_descriptor (std::vector & descrpt_a, for (int jj = sec_a[ii]; jj < sec_a[ii+1]; ++jj){ if (fmt_nlist_a[jj] < 0) break; double rdiff[3] ; - MathUtilities::dot (rdiff, rot, &sel_a_diff[jj][0]); - double rr2 = MathUtilities::dot(rdiff, rdiff); + dot3(rdiff, rot, &sel_a_diff[jj][0]); + double rr2 = dot3(rdiff, rdiff); double rr = sqrt(rr2); #ifdef DESCRPT_THETAPHI double cos_theta = rdiff[2] / rr; @@ -445,7 +445,7 @@ void compute_descriptor (std::vector & descrpt_a, for (int jj = sec_r[ii]; jj < sec_r[ii+1]; ++jj){ if (fmt_nlist_r[jj] < 0) break; const double *rdiff = &sel_r_diff[jj][0]; - double rr = sqrt (MathUtilities::dot(rdiff, rdiff)); + double rr = sqrt (dot3(rdiff, rdiff)); descrpt_r[jj] = 1./rr; } } @@ -474,8 +474,8 @@ void compute_descriptor (std::vector & descrpt_a, double dtrdST[4][3]; double * rr = &sel_a_diff[nei_iter][0]; double tr[3] ; - MathUtilities::dot (tr, rot, rr); - double nr2 = MathUtilities::dot(tr, tr); + dot3(tr, rot, rr); + double nr2 = dot3(tr, tr); double nr = sqrt(nr2); double nr3 = nr * nr2; for (int dd = 0; dd < 3; ++dd){ @@ -601,7 +601,7 @@ void compute_descriptor (std::vector & descrpt_a, if (fmt_nlist_r[nei_iter] < 0) break; const double * rr = &sel_r_diff[nei_iter][0]; - double nr = sqrt(MathUtilities::dot(rr, rr)); + double nr = sqrt(dot3(rr, rr)); double nr3 = nr * nr * nr; int idx = nei_iter * 12; @@ -699,13 +699,13 @@ void compute_descriptor (std::vector & descrpt_a, xx[dd] = r1[dd]; yy[dd] = r2[dd]; } - double norm_xx = sqrt(MathUtilities::dot (xx, xx)); + double norm_xx = sqrt(dot3(xx, xx)); for (unsigned dd = 0; dd < 3; ++dd) xx[dd] /= norm_xx; - double dxy = MathUtilities::dot (xx, yy); + double dxy = dot3(xx, yy); for (unsigned dd = 0; dd < 3; ++dd) yy[dd] -= dxy * xx[dd]; - double norm_yy = sqrt(MathUtilities::dot (yy, yy)); + double norm_yy = sqrt(dot3(yy, yy)); for (unsigned dd = 0; dd < 3; ++dd) yy[dd] /= norm_yy; - MathUtilities::cprod (xx, yy, zz); + cprod(xx, yy, zz); rot_mat.resize (9); for (int dd = 0; dd < 9; ++dd) rot_mat[dd] = rot[dd]; @@ -716,8 +716,8 @@ void compute_descriptor (std::vector & descrpt_a, for (int jj = sec_a[ii]; jj < sec_a[ii+1]; ++jj){ if (fmt_nlist_a[jj] < 0) break; double rdiff[3] ; - MathUtilities::dot (rdiff, rot, &sel_a_diff[jj][0]); - double rr2 = MathUtilities::dot(rdiff, rdiff); + dot3(rdiff, rot, &sel_a_diff[jj][0]); + double rr2 = dot3(rdiff, rdiff); double rr = sqrt(rr2); #ifdef DESCRPT_THETAPHI double cos_theta = rdiff[2] / rr; @@ -742,8 +742,8 @@ void compute_descriptor (std::vector & descrpt_a, for (int jj = sec_r[ii]; jj < sec_r[ii+1]; ++jj){ if (fmt_nlist_r[jj] < 0) break; double rdiff[3] ; - MathUtilities::dot (rdiff, rot, &sel_r_diff[jj][0]); - double rr = sqrt (MathUtilities::dot(rdiff, rdiff)); + dot3(rdiff, rot, &sel_r_diff[jj][0]); + double rr = sqrt (dot3(rdiff, rdiff)); descrpt_r[jj] = 1./rr; } } @@ -784,7 +784,7 @@ void compute_descriptor_se_a_extf (std::vector & descrpt_a, ef[ii] = ef_[ii]; } } - assert( fabs(MathUtilities::dot(ef, ef) - 1.0) < 1e-12 ), "ef should be a normalized std::vector"; + assert( fabs(dot3(ef, ef) - 1.0) < 1e-12 ), "ef should be a normalized std::vector"; // compute the diff of the neighbors std::vector > sel_a_diff (sec_a.back()); @@ -819,7 +819,7 @@ void compute_descriptor_se_a_extf (std::vector & descrpt_a, if (fmt_nlist_a[nei_iter] < 0) break; const double * rr = &sel_a_diff[nei_iter][0]; // check validity of ef - double nr2 = MathUtilities::dot(rr, rr); + double nr2 = dot3(rr, rr); double inr = 1./sqrt(nr2); double nr = nr2 * inr; double inr2 = inr * inr; @@ -830,7 +830,7 @@ void compute_descriptor_se_a_extf (std::vector & descrpt_a, int idx_deriv = nei_iter * 4 * 3; // 4 components time 3 directions int idx_value = nei_iter * 4; // 4 components // projections - double rp = MathUtilities::dot(rr, ef); + double rp = dot3(rr, ef); double rv[3]; rv[0] = rr[0] - rp * ef[0]; rv[1] = rr[1] - rp * ef[1]; @@ -893,7 +893,7 @@ void compute_descriptor_se_a_ef_para (std::vector & descrpt_a, ef[ii] = ef_[ii]; } } - assert( fabs(MathUtilities::dot(ef, ef) - 1.0) < 1e-12 ), "ef should be a normalized vector"; + assert( fabs(dot3(ef, ef) - 1.0) < 1e-12 ), "ef should be a normalized vector"; // compute the diff of the neighbors std::vector > sel_a_diff (sec_a.back()); @@ -928,7 +928,7 @@ void compute_descriptor_se_a_ef_para (std::vector & descrpt_a, if (fmt_nlist_a[nei_iter] < 0) break; const double * rr = &sel_a_diff[nei_iter][0]; // check validity of ef - double nr2 = MathUtilities::dot(rr, rr); + double nr2 = dot3(rr, rr); double inr = 1./sqrt(nr2); double nr = nr2 * inr; double inr2 = inr * inr; @@ -940,9 +940,9 @@ void compute_descriptor_se_a_ef_para (std::vector & descrpt_a, int idx_value = nei_iter * 4; // 4 components // projections double rp[3]; - rp[0] = MathUtilities::dot(rr, ef) * ef[0]; - rp[1] = MathUtilities::dot(rr, ef) * ef[1]; - rp[2] = MathUtilities::dot(rr, ef) * ef[2]; + rp[0] = dot3(rr, ef) * ef[0]; + rp[1] = dot3(rr, ef) * ef[1]; + rp[2] = dot3(rr, ef) * ef[2]; // 4 value components descrpt_a[idx_value + 0] = 1 / nr; descrpt_a[idx_value + 1] = rp[0] / nr2; @@ -1001,7 +1001,7 @@ void compute_descriptor_se_a_ef_vert (std::vector & descrpt_a, ef[ii] = ef_[ii]; } } - assert( fabs(MathUtilities::dot(ef, ef) - 1.0) < 1e-12 ), "ef should be a normalized vector"; + assert( fabs(dot3(ef, ef) - 1.0) < 1e-12 ), "ef should be a normalized vector"; // compute the diff of the neighbors std::vector > sel_a_diff (sec_a.back()); @@ -1036,7 +1036,7 @@ void compute_descriptor_se_a_ef_vert (std::vector & descrpt_a, if (fmt_nlist_a[nei_iter] < 0) break; const double * rr = &sel_a_diff[nei_iter][0]; // check validity of ef - double nr2 = MathUtilities::dot(rr, rr); + double nr2 = dot3(rr, rr); double inr = 1./sqrt(nr2); double nr = nr2 * inr; double inr2 = inr * inr; @@ -1047,7 +1047,7 @@ void compute_descriptor_se_a_ef_vert (std::vector & descrpt_a, int idx_deriv = nei_iter * 4 * 3; // 4 components time 3 directions int idx_value = nei_iter * 4; // 4 components // projections - double rp = MathUtilities::dot(rr, ef); + double rp = dot3(rr, ef); double rv[3]; rv[0] = rr[0] - rp * ef[0]; rv[1] = rr[1] - rp * ef[1]; diff --git a/source/lib/include/CustomeOperation.h b/source/lib/include/CustomeOperation.h index f7cd8e1b01..e0edef36bd 100644 --- a/source/lib/include/CustomeOperation.h +++ b/source/lib/include/CustomeOperation.h @@ -3,7 +3,7 @@ #include #include #include -#include "MathUtilities.h" +#include "utilities.h" #include "fmt_nlist.h" #include "env_mat.h" #if GOOGLE_CUDA diff --git a/source/lib/include/Ewald.h b/source/lib/include/Ewald.h index 8dec44e332..8bd5ce9dfa 100644 --- a/source/lib/include/Ewald.h +++ b/source/lib/include/Ewald.h @@ -4,6 +4,7 @@ #include #include +#include "utilities.h" #include "SimulationRegion.h" // 8.988e9 / pc.electron_volt / pc.angstrom * (1.602e-19)**2 @@ -91,7 +92,7 @@ cmpt_k(std::vector & KK, } KK.resize(3); for (int dd = 0; dd < 3; ++dd){ - VALUETYPE ll = sqrt(MathUtilities::dot(boxt+dd*3, boxt+dd*3)); + VALUETYPE ll = sqrt(dot3(boxt+dd*3, boxt+dd*3)); KK[dd] = ll / param.spacing; // KK[dd] should be large enough if (KK[dd] * param.spacing < ll) KK[dd] += 1; diff --git a/source/lib/include/MathUtilities.h b/source/lib/include/MathUtilities.h deleted file mode 100644 index 36b2435bdf..0000000000 --- a/source/lib/include/MathUtilities.h +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef __MathUtilities_h_wanghan__ -#define __MathUtilities_h_wanghan__ - -#include -#include - -// using namespace std; - - namespace MathUtilities - { - - template - TYPE det1d (const TYPE * tensor); - - template - TYPE det2d (const TYPE * tensor); - - template - TYPE det3d (const TYPE * tensor); - - template - TYPE det4d (const TYPE * tensor); - - template - struct det - { - inline TYPE operator () (const TYPE * tensor) const; - }; - - template - TYPE max (const TYPE & v0, const TYPE & v1); - - template - TYPE min (const TYPE & v0, const TYPE & v1); - - template - void dot (TYPE * vec_o, const TYPE * tensor, const TYPE * vec_i); - - template - TYPE dot (const TYPE& x0, const TYPE& y0, const TYPE& z0, - const TYPE& x1, const TYPE& y1, const TYPE& z1); - - template - TYPE dot (const TYPE* r0, const TYPE* r1); - - template - void cprod (const TYPE& x0, const TYPE& y0, const TYPE& z0, - const TYPE& x1, const TYPE& y1, const TYPE& z1, - TYPE& x2, TYPE& y2, TYPE& z2); - - template - void cprod (const TYPE * r0, const TYPE * r1, TYPE* r2); - - template - TYPE cos (const TYPE& x0, const TYPE& y0, const TYPE& z0, - const TYPE& x1, const TYPE& y1, const TYPE& z1); - - template - TYPE angle (const TYPE& x0, const TYPE& y0, const TYPE& z0, - const TYPE& x1, const TYPE& y1, const TYPE& z1); - - template - inline TYPE invsqrt (const TYPE x); - - template - inline TYPE msp_sqrt (const TYPE x); - - template - inline int searchVec (const std::vector & vec, - const int sta_, - const int end_, - const VALUETYPE & val); - template - inline int lowerBound (const std::vector & vec, - const int sta_, - const int end_, - const VALUETYPE & val); - template - inline int upperBound (const std::vector & vec, - const int sta_, - const int end_, - const VALUETYPE & val); - template - inline int upperBound (const std::vector & vec, - const int sta_, - const int end_, - const VALUETYPE & val, - const COMPARE & less); - }; - -#include "MathUtilities_Impl.h" - -#endif diff --git a/source/lib/include/MathUtilities_Impl.h b/source/lib/include/MathUtilities_Impl.h deleted file mode 100644 index 378498c625..0000000000 --- a/source/lib/include/MathUtilities_Impl.h +++ /dev/null @@ -1,353 +0,0 @@ -#pragma once - -#include -#include - -#include - -template -inline TYPE -MathUtilities:: -max (const TYPE & v0, const TYPE & v1) -{ - return (v0 > v1) ? v0 : v1; -} - -template -inline TYPE -MathUtilities:: -min (const TYPE & v0, const TYPE & v1) -{ - return (v0 < v1) ? v0 : v1; -} - -template -inline -void -MathUtilities:: -dot (TYPE * vec_o, const TYPE * tensor, const TYPE * vec_i) -{ - vec_o[0] = dot(tensor+0, vec_i); - vec_o[1] = dot(tensor+3, vec_i); - vec_o[2] = dot(tensor+6, vec_i); -} - -template -inline TYPE -MathUtilities:: -dot (const TYPE& x0, const TYPE& y0, const TYPE& z0, - const TYPE& x1, const TYPE& y1, const TYPE& z1) -{ - return x0 * x1 + y0 * y1 + z0 * z1; -} - -template -inline TYPE -MathUtilities:: -dot (const TYPE* r0, const TYPE* r1) -{ - return r0[0] * r1[0] + r0[1] * r1[1] + r0[2] * r1[2]; -} - -template -inline void -MathUtilities:: -cprod (const TYPE& x0, const TYPE& y0, const TYPE& z0, - const TYPE& x1, const TYPE& y1, const TYPE& z1, - TYPE& x2, TYPE& y2, TYPE& z2) -{ - x2 = y0 * z1 - z0 * y1; - y2 = z0 * x1 - x0 * z1; - z2 = x0 * y1 - y0 * x1; -} - -template -inline void -MathUtilities:: -cprod (const TYPE * r0, - const TYPE * r1, - TYPE* r2) -{ - r2[0] = r0[1] * r1[2] - r0[2] * r1[1]; - r2[1] = r0[2] * r1[0] - r0[0] * r1[2]; - r2[2] = r0[0] * r1[1] - r0[1] * r1[0]; -} - - -template -inline TYPE -MathUtilities:: -cos (const TYPE& x0, const TYPE& y0, const TYPE& z0, - const TYPE& x1, const TYPE& y1, const TYPE& z1) -{ - double dblx0 = (double) (x0); - double dblx1 = (double) (x1); - double dbly0 = (double) (y0); - double dbly1 = (double) (y1); - double dblz0 = (double) (z0); - double dblz1 = (double) (z1); - - double ip = dot (dblx0, dbly0, dblz0, dblx1, dbly1, dblz1); - double ip0 = dot (dblx0, dbly0, dblz0, dblx0, dbly0, dblz0); - double ip1 = dot (dblx1, dbly1, dblz1, dblx1, dbly1, dblz1); - double ip01 = ip0 * ip1; - - double cosval; - if (ip01 > 0) { - cosval = ip * invsqrt(ip01); - } - else { - cosval = 1.0; - } - if (cosval > 1.0) { - return 1.0; - } - if (cosval < -1.0) { - return -1.0; - } - return cosval; -} - -template -inline TYPE -MathUtilities:: -angle (const TYPE& x0_, const TYPE& y0_, const TYPE& z0_, - const TYPE& x1_, const TYPE& y1_, const TYPE& z1_) -{ - double x0 = (double) (x0_); - double x1 = (double) (x1_); - double y0 = (double) (y0_); - double y1 = (double) (y1_); - double z0 = (double) (z0_); - double z1 = (double) (z1_); - - double x2, y2, z2; - cprod (x0, y0, z0, x1, y1, z1, x2, y2, z2); - - double length = sqrt (dot(x2, y2, z2, x2, y2, z2)); - - double s = dot (x0, y0, z0, x1, y1, z1); - - return atan2 (length, s); -} - - - -template -inline TYPE -MathUtilities:: -det1d (const TYPE * tensor) -{ - return (tensor[0]); -} - -template -inline TYPE -MathUtilities:: -det2d (const TYPE * tensor) -{ - return ((tensor[0*2+0]*tensor[1*2+1] - tensor[1*2+0]*tensor[0*2+1])); -} - -template -inline TYPE -MathUtilities:: -det3d (const TYPE * tensor) -{ - return (tensor[0*3+0] * (tensor[1*3+1]*tensor[2*3+2] - tensor[2*3+1]*tensor[1*3+2]) - - tensor[0*3+1] * (tensor[1*3+0]*tensor[2*3+2] - tensor[2*3+0]*tensor[1*3+2]) + - tensor[0*3+2] * (tensor[1*3+0]*tensor[2*3+1] - tensor[2*3+0]*tensor[1*3+1]) ); -} - -template -inline TYPE -MathUtilities:: -det4d (const TYPE * mat) -{ - return - ( + mat[0*4+0] * - ( mat[1*4+1] * (mat[2*4+2]*mat[3*4+3]-mat[3*4+2]*mat[2*4+3] ) - - mat[1*4+2] * (mat[2*4+1]*mat[3*4+3]-mat[3*4+1]*mat[2*4+3] ) + - mat[1*4+3] * (mat[2*4+1]*mat[3*4+2]-mat[3*4+1]*mat[2*4+2] ) ) - - mat[0*4+1] * - ( mat[1*4+0] * (mat[2*4+2]*mat[3*4+3]-mat[3*4+2]*mat[2*4+3] ) - - mat[1*4+2] * (mat[2*4+0]*mat[3*4+3]-mat[3*4+0]*mat[2*4+3] ) + - mat[1*4+3] * (mat[2*4+0]*mat[3*4+2]-mat[3*4+0]*mat[2*4+2] ) ) - + mat[0*4+2] * - ( mat[1*4+0] * (mat[2*4+1]*mat[3*4+3]-mat[3*4+1]*mat[2*4+3] ) - - mat[1*4+1] * (mat[2*4+0]*mat[3*4+3]-mat[3*4+0]*mat[2*4+3] ) + - mat[1*4+3] * (mat[2*4+0]*mat[3*4+1]-mat[3*4+0]*mat[2*4+1] ) ) - - mat[0*4+3] * - ( mat[1*4+0] * (mat[2*4+1]*mat[3*4+2]-mat[3*4+1]*mat[2*4+2] ) - - mat[1*4+1] * (mat[2*4+0]*mat[3*4+2]-mat[3*4+0]*mat[2*4+2] ) + - mat[1*4+2] * (mat[2*4+0]*mat[3*4+1]-mat[3*4+0]*mat[2*4+1] ) ) - ); -} - - namespace MathUtilities{ - template - struct det - { - inline TYPE operator () (const TYPE * tensor) const {return det1d (tensor);} - }; - - template - struct det - { - inline TYPE operator () (const TYPE * tensor) const {return det2d (tensor);} - }; - - template - struct det - { - inline TYPE operator () (const TYPE * tensor) const {return det3d (tensor);} - }; - - template - struct det - { - inline TYPE operator () (const TYPE * tensor) const {return det4d (tensor);} - }; - } - -template -inline int -MathUtilities:: -searchVec (const std::vector & vec, - const int sta_, - const int end_, - const VALUETYPE & val) -{ - int sta (sta_); - int end (end_); - if (sta == end) return -1; - while (end - sta > 1){ - int mid = (sta + end) >> 1; - if ((vec[mid] < val)) sta = mid; - else end = mid; - } - return sta; -} - -template -inline int -MathUtilities:: -lowerBound (const std::vector & vec, - const int sta_, - const int end_, - const VALUETYPE & val) -{ - int sta (sta_); - int iter, step; - int count = end_ - sta; - while (count > 0){ - iter = sta; - step = count >> 1; - iter += step; - if (vec[iter] < val){ - sta = ++iter; - count -= step + 1; - } - else count = step; - } - return sta; -} - -template -inline int -MathUtilities:: -upperBound (const std::vector & vec, - const int sta_, - const int end_, - const VALUETYPE & val) -{ - int sta (sta_); - int iter, step; - int count = end_ - sta; - while (count > 0){ - iter = sta; - step = count >> 1; - iter += step; - if ( ! (val < vec[iter]) ){ - sta = ++iter; - count -= step + 1; - } - else count = step; - } - return sta; -} - -template -inline int -MathUtilities:: -upperBound (const std::vector & vec, - const int sta_, - const int end_, - const VALUETYPE & val, - const COMPARE & less) -{ - int sta (sta_); - int iter, step; - int count = end_ - sta; - while (count > 0){ - iter = sta; - step = count >> 1; - iter += step; - if ( ! less (val , vec[iter]) ){ - sta = ++iter; - count -= step + 1; - } - else count = step; - } - return sta; -} - - namespace MathUtilities{ - template <> - inline double - msp_sqrt (const double x) - { - return ::sqrt (x); - } - - template <> - inline float - msp_sqrt (const float x) - { - return ::sqrtf (x); - } - - template <> - inline double - invsqrt (const double x) - { - return 1./sqrt (x); - } - - template <> - inline float - invsqrt (const float x) - { - return 1./sqrtf (x); - } - } - -// template -// int -// searchVec (const std::vector & vec, -// const int sta_, -// const int end_, -// const VALUETYPE & val, -// const COMPARE & lessOrEq) -// { -// int sta (sta_); -// int end (end_); -// if (sta == end) return -1; -// while (end - sta > 1){ -// int mid = (sta + end) >> 1; -// if (lessOrEq (vec[mid], val)) sta = mid; -// else end = mid; -// } -// return sta; -// } - diff --git a/source/lib/include/SimulationRegion.h b/source/lib/include/SimulationRegion.h index eb625b64e1..d9de1bff18 100644 --- a/source/lib/include/SimulationRegion.h +++ b/source/lib/include/SimulationRegion.h @@ -2,7 +2,7 @@ #define __SimulationRegion_h_wanghan__ #define MOASPNDIM 3 -#include "MathUtilities.h" +#include "utilities.h" #include template diff --git a/source/lib/include/SimulationRegion_Impl.h b/source/lib/include/SimulationRegion_Impl.h index 9f3ecdd241..d19f1a5650 100644 --- a/source/lib/include/SimulationRegion_Impl.h +++ b/source/lib/include/SimulationRegion_Impl.h @@ -417,12 +417,12 @@ SimulationRegion:: toFaceDistance (double * dd) const { double tmp[3]; - MathUtilities::cprod (boxt+3, boxt+6, tmp); - dd[0] = volume * MathUtilities::invsqrt (MathUtilities::dot(tmp,tmp)); - MathUtilities::cprod (boxt+6, boxt+0, tmp); - dd[1] = volume * MathUtilities::invsqrt (MathUtilities::dot(tmp,tmp)); - MathUtilities::cprod (boxt+0, boxt+3, tmp); - dd[2] = volume * MathUtilities::invsqrt (MathUtilities::dot(tmp,tmp)); + cprod(boxt+3, boxt+6, tmp); + dd[0] = volume * invsqrt(dot3(tmp,tmp)); + cprod(boxt+6, boxt+0, tmp); + dd[1] = volume * invsqrt(dot3(tmp,tmp)); + cprod(boxt+0, boxt+3, tmp); + dd[2] = volume * invsqrt(dot3(tmp,tmp)); } // static int tmp_count = 0; diff --git a/source/lib/include/neighbor_list.h b/source/lib/include/neighbor_list.h index c97fcc3099..b47249c81a 100644 --- a/source/lib/include/neighbor_list.h +++ b/source/lib/include/neighbor_list.h @@ -4,7 +4,7 @@ #include #include -#include "MathUtilities.h" +#include "utilities.h" #include "SimulationRegion.h" // build nlist by an extended grid diff --git a/source/lib/include/utilities.h b/source/lib/include/utilities.h index 8fb21c1a85..d82a6b5f34 100644 --- a/source/lib/include/utilities.h +++ b/source/lib/include/utilities.h @@ -3,7 +3,65 @@ #include #include #include +#include void cum_sum( std::vector & sec, - const std::vector & n_sel); \ No newline at end of file + const std::vector & n_sel); + +template +inline TYPE +dot1 (const TYPE* r0, const TYPE* r1) +{ + return r0[0] * r1[0]; +} + +template +inline TYPE +dot2 (const TYPE* r0, const TYPE* r1) +{ + return r0[0] * r1[0] + r0[1] * r1[1]; +} + +template +inline TYPE +dot3 (const TYPE* r0, const TYPE* r1) +{ + return r0[0] * r1[0] + r0[1] * r1[1] + r0[2] * r1[2]; +} + +template +inline TYPE +dot4 (const TYPE* r0, const TYPE* r1) +{ + return r0[0] * r1[0] + r0[1] * r1[1] + r0[2] * r1[2] + r0[3] * r1[3]; +} + +template +inline void +cprod (const TYPE * r0, + const TYPE * r1, + TYPE* r2) +{ + r2[0] = r0[1] * r1[2] - r0[2] * r1[1]; + r2[1] = r0[2] * r1[0] - r0[0] * r1[2]; + r2[2] = r0[0] * r1[1] - r0[1] * r1[0]; +} + +template +inline TYPE invsqrt (const TYPE x); + +template <> +inline double +invsqrt (const double x) +{ + return 1./sqrt (x); +} + +template <> +inline float +invsqrt (const float x) +{ + return 1./sqrtf (x); +} + diff --git a/source/lib/src/env_mat.cc b/source/lib/src/env_mat.cc index aa5417b3ca..7aec89feaa 100644 --- a/source/lib/src/env_mat.cc +++ b/source/lib/src/env_mat.cc @@ -50,7 +50,7 @@ void env_mat_a ( for (int nei_iter = sec_a[sec_iter]; nei_iter < sec_a[sec_iter+1]; ++nei_iter) { if (fmt_nlist_a[nei_iter] < 0) break; const double * rr = &sel_a_diff[nei_iter][0]; - double nr2 = MathUtilities::dot(rr, rr); + double nr2 = dot3(rr, rr); double inr = 1./sqrt(nr2); double nr = nr2 * inr; double inr2 = inr * inr; @@ -128,7 +128,7 @@ void env_mat_a_cpu ( for (int nei_iter = sec_a[sec_iter]; nei_iter < sec_a[sec_iter+1]; ++nei_iter) { if (fmt_nlist_a[nei_iter] < 0) break; const FPTYPE * rr = &rij_a[nei_iter * 3]; - FPTYPE nr2 = MathUtilities::dot(rr, rr); + FPTYPE nr2 = dot3(rr, rr); FPTYPE inr = 1./sqrt(nr2); FPTYPE nr = nr2 * inr; FPTYPE inr2 = inr * inr; @@ -216,7 +216,7 @@ void env_mat_r ( for (int nei_iter = sec[sec_iter]; nei_iter < sec[sec_iter+1]; ++nei_iter) { if (fmt_nlist[nei_iter] < 0) break; const double * rr = &sel_diff[nei_iter][0]; - double nr2 = MathUtilities::dot(rr, rr); + double nr2 = dot3(rr, rr); double inr = 1./sqrt(nr2); double nr = nr2 * inr; double inr2 = inr * inr; @@ -276,7 +276,7 @@ void env_mat_r_cpu ( for (int nei_iter = sec[sec_iter]; nei_iter < sec[sec_iter+1]; ++nei_iter) { if (fmt_nlist[nei_iter] < 0) break; const FPTYPE * rr = &rij_a[nei_iter * 3]; - FPTYPE nr2 = MathUtilities::dot(rr, rr); + FPTYPE nr2 = dot3(rr, rr); FPTYPE inr = 1./sqrt(nr2); FPTYPE nr = nr2 * inr; FPTYPE inr2 = inr * inr; diff --git a/source/lib/src/fmt_nlist.cc b/source/lib/src/fmt_nlist.cc index 1def0a8fb5..740860e540 100644 --- a/source/lib/src/fmt_nlist.cc +++ b/source/lib/src/fmt_nlist.cc @@ -48,7 +48,7 @@ int format_nlist_fill_a ( else { for (int dd = 0; dd < 3; ++dd) diff[dd] = posi[j_idx*3+dd] - posi[i_idx*3+dd]; } - double rr = sqrt(MathUtilities::dot (diff, diff)); + double rr = sqrt(dot3(diff, diff)); if (rr <= rcut) { sel_nei.push_back(NeighborInfo (type[j_idx], rr, j_idx)); } @@ -102,7 +102,7 @@ int format_nlist_cpu ( for (int dd = 0; dd < 3; ++dd) { diff[dd] = posi[j_idx * 3 + dd] - posi[i_idx * 3 + dd]; } - FPTYPE rr = sqrt(MathUtilities::dot (diff, diff)); + FPTYPE rr = sqrt(dot3(diff, diff)); if (rr <= rcut) { sel_nei.push_back(NeighborInfo(type[j_idx], rr, j_idx)); } diff --git a/source/lib/src/neighbor_list.cc b/source/lib/src/neighbor_list.cc index 11a5dcccdb..01ba7a2a26 100644 --- a/source/lib/src/neighbor_list.cc +++ b/source/lib/src/neighbor_list.cc @@ -212,7 +212,7 @@ build_nlist_cell (std::vector > & nlist0, diff[dd0] += shift[dd1] * boxt[3*dd1+dd0]; } } - double r2 = MathUtilities::dot (diff, diff); + double r2 = dot3(diff, diff); if (r2 < rc02) { if (i_idx < nloc) nlist0[i_idx].push_back (j_idx); if (j_idx < nloc) nlist0[j_idx].push_back (i_idx); @@ -253,7 +253,7 @@ build_nlist_cell (std::vector > & nlist0, diff[dd0] += shift[dd1] * boxt[3*dd1+dd0]; } } - double r2 = MathUtilities::dot (diff, diff); + double r2 = dot3(diff, diff); if (r2 < rc02) { nlist0[i_idx].push_back (j_idx); } @@ -611,7 +611,7 @@ build_nlist (std::vector > & nlist0, diff[1] = posi3[jj*3+1] - posi3[ii*3+1]; diff[2] = posi3[jj*3+2] - posi3[ii*3+2]; } - double r2 = MathUtilities::dot (diff, diff); + double r2 = dot3(diff, diff); if (r2 < rc02) { nlist0[ii].push_back (jj); nlist0[jj].push_back (ii); From c9114b95e33785ce6c2c11de1d4e1f0543759a12 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Sun, 28 Feb 2021 21:52:06 +0800 Subject: [PATCH 216/562] rm api_cc/include directory from op/CMakeLists.txt --- source/op/CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/source/op/CMakeLists.txt b/source/op/CMakeLists.txt index 3a8e723396..67ffc7f844 100644 --- a/source/op/CMakeLists.txt +++ b/source/op/CMakeLists.txt @@ -22,9 +22,6 @@ endif (BUILD_CPP_IF) if (BUILD_PY_IF) set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) set(CMAKE_INSTALL_RPATH $ORIGIN) - set(LIB_BASE_DIR ${CMAKE_SOURCE_DIR}) - include_directories(${LIB_BASE_DIR}/api_cc/include) - MESSAGE( STATUS ${LIB_BASE_DIR}) if (USE_CUDA_TOOLKIT) add_library(op_abi SHARED ${OP_SRC} ${OP_LIB}) add_library(op_grads SHARED ${OP_GRADS_SRC}) From f0b3748440699e36b9cd211a8931827b3f267657 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 28 Feb 2021 22:28:50 +0800 Subject: [PATCH 217/562] fix bugs --- source/lib/include/ComputeDescriptor.h | 8 ++++---- source/lib/include/utilities.h | 9 +++++++++ source/op/descrpt.cc | 10 +++++----- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/source/lib/include/ComputeDescriptor.h b/source/lib/include/ComputeDescriptor.h index 63713d42d8..aaac53b657 100644 --- a/source/lib/include/ComputeDescriptor.h +++ b/source/lib/include/ComputeDescriptor.h @@ -419,7 +419,7 @@ void compute_descriptor (std::vector & descrpt_a, for (int jj = sec_a[ii]; jj < sec_a[ii+1]; ++jj){ if (fmt_nlist_a[jj] < 0) break; double rdiff[3] ; - dot3(rdiff, rot, &sel_a_diff[jj][0]); + dotmv3(rdiff, rot, &sel_a_diff[jj][0]); double rr2 = dot3(rdiff, rdiff); double rr = sqrt(rr2); #ifdef DESCRPT_THETAPHI @@ -474,7 +474,7 @@ void compute_descriptor (std::vector & descrpt_a, double dtrdST[4][3]; double * rr = &sel_a_diff[nei_iter][0]; double tr[3] ; - dot3(tr, rot, rr); + dotmv3(tr, rot, rr); double nr2 = dot3(tr, tr); double nr = sqrt(nr2); double nr3 = nr * nr2; @@ -716,7 +716,7 @@ void compute_descriptor (std::vector & descrpt_a, for (int jj = sec_a[ii]; jj < sec_a[ii+1]; ++jj){ if (fmt_nlist_a[jj] < 0) break; double rdiff[3] ; - dot3(rdiff, rot, &sel_a_diff[jj][0]); + dotmv3(rdiff, rot, &sel_a_diff[jj][0]); double rr2 = dot3(rdiff, rdiff); double rr = sqrt(rr2); #ifdef DESCRPT_THETAPHI @@ -742,7 +742,7 @@ void compute_descriptor (std::vector & descrpt_a, for (int jj = sec_r[ii]; jj < sec_r[ii+1]; ++jj){ if (fmt_nlist_r[jj] < 0) break; double rdiff[3] ; - dot3(rdiff, rot, &sel_r_diff[jj][0]); + dotmv3(rdiff, rot, &sel_r_diff[jj][0]); double rr = sqrt (dot3(rdiff, rdiff)); descrpt_r[jj] = 1./rr; } diff --git a/source/lib/include/utilities.h b/source/lib/include/utilities.h index d82a6b5f34..08a808ac11 100644 --- a/source/lib/include/utilities.h +++ b/source/lib/include/utilities.h @@ -37,6 +37,15 @@ dot4 (const TYPE* r0, const TYPE* r1) return r0[0] * r1[0] + r0[1] * r1[1] + r0[2] * r1[2] + r0[3] * r1[3]; } +template +inline void +dotmv3 (TYPE * vec_o, const TYPE * tensor, const TYPE * vec_i) +{ + vec_o[0] = dot3(tensor+0, vec_i); + vec_o[1] = dot3(tensor+3, vec_i); + vec_o[2] = dot3(tensor+6, vec_i); +} + template inline void cprod (const TYPE * r0, diff --git a/source/op/descrpt.cc b/source/op/descrpt.cc index a9e08e5d6d..a6b0a3f57f 100644 --- a/source/op/descrpt.cc +++ b/source/op/descrpt.cc @@ -504,7 +504,7 @@ class DescrptOp : public OpKernel { } } sort_info.push_back (std::pair - (MathUtilities::dot (diff, diff), list_idx) ); + (dot3(diff, diff), list_idx) ); } } sort (sort_info.begin(), sort_info.end()); @@ -536,7 +536,7 @@ class DescrptOp : public OpKernel { } } sort_info.push_back (std::pair - (MathUtilities::dot (diff, diff), list_idx) ); + (dot3(diff, diff), list_idx) ); } } sort (sort_info.begin(), sort_info.end()); @@ -589,9 +589,9 @@ class DescrptOp : public OpKernel { } } } - compute_t rij = MathUtilities::dot (diff[0], diff[1]); - compute_t rii = MathUtilities::dot (diff[0], diff[0]); - compute_t rjj = MathUtilities::dot (diff[1], diff[1]); + compute_t rij = dot3(diff[0], diff[1]); + compute_t rii = dot3(diff[0], diff[0]); + compute_t rjj = dot3(diff[1], diff[1]); if ( fabs (rij / sqrt(rii * rjj) + 1) < 1e-4 ) { return false; } From e94234420934b17cfa3428ca3978258b4000f21c Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sun, 28 Feb 2021 21:50:06 -0500 Subject: [PATCH 218/562] test building gpu version C++ API --- .github/workflows/build_cc.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/build_cc.yml b/.github/workflows/build_cc.yml index b50989650e..6b56712e6d 100644 --- a/.github/workflows/build_cc.yml +++ b/.github/workflows/build_cc.yml @@ -10,9 +10,17 @@ jobs: matrix: include: - float_prec: high + cudatoolkit: false - float_prec: low + cudatoolkit: false + - float_prec: high + cudatoolkit: true + - float_prec: low + cudatoolkit: true steps: - uses: actions/checkout@master + - run: sudo apt update && sudo apt install nvidia-cuda-toolkit + if: ${{ matrix.cudatoolkit }} != 'false' - run: source/install/build_cc.sh env: FLOAT_PREC: ${{ matrix.float_prec }} From 0677bdd1a46263cba8d362e4fe4e0f92d323c557 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sun, 28 Feb 2021 22:22:36 -0500 Subject: [PATCH 219/562] fix action bugs --- .github/workflows/build_cc.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build_cc.yml b/.github/workflows/build_cc.yml index 6b56712e6d..bd54819c36 100644 --- a/.github/workflows/build_cc.yml +++ b/.github/workflows/build_cc.yml @@ -5,22 +5,24 @@ name: Build C++ jobs: testpython: name: Build C++ - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 strategy: matrix: include: - float_prec: high - cudatoolkit: false + variant: cpu - float_prec: low - cudatoolkit: false + variant: cpu - float_prec: high - cudatoolkit: true + variant: gpu - float_prec: low - cudatoolkit: true + variant: gpu steps: - uses: actions/checkout@master - run: sudo apt update && sudo apt install nvidia-cuda-toolkit - if: ${{ matrix.cudatoolkit }} != 'false' + if: matrix.variant == 'gpu' - run: source/install/build_cc.sh env: FLOAT_PREC: ${{ matrix.float_prec }} + CC: gcc-7 + CXX: g++-7 From 5f11626f5beeb1a83029677de56f963d9fa8fb7b Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 1 Mar 2021 17:16:19 +0800 Subject: [PATCH 220/562] fix bugs of using dot3 --- source/api_cc/src/NNPInter.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/api_cc/src/NNPInter.cc b/source/api_cc/src/NNPInter.cc index f4f3ff0a33..56f38d9900 100644 --- a/source/api_cc/src/NNPInter.cc +++ b/source/api_cc/src/NNPInter.cc @@ -888,7 +888,7 @@ compute_std_f (std::vector & std, vdiff[0] = tmp_f[0] - tmp_avg[0]; vdiff[1] = tmp_f[1] - tmp_avg[1]; vdiff[2] = tmp_f[2] - tmp_avg[2]; - std[jj] += MathUtilities::dot(vdiff, vdiff); + std[jj] += dot3(vdiff, vdiff); } } @@ -911,7 +911,7 @@ compute_relative_std_f (std::vector &std, vdiff[0] = tmp_avg[0]; vdiff[1] = tmp_avg[1]; vdiff[2] = tmp_avg[2]; - VALUETYPE f_norm = sqrt(MathUtilities::dot(vdiff, vdiff)); + VALUETYPE f_norm = sqrt(dot3(vdiff, vdiff)); // relative std = std/(abs(f)+eps) std[ii] /= f_norm + eps; } From 0c8edaf69c47e9ae63eaf91900013c2f7d12a766 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Mon, 1 Mar 2021 16:27:51 -0500 Subject: [PATCH 221/562] clone submodules --- .github/workflows/build_cc.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build_cc.yml b/.github/workflows/build_cc.yml index bd54819c36..6f7d9f047b 100644 --- a/.github/workflows/build_cc.yml +++ b/.github/workflows/build_cc.yml @@ -19,6 +19,8 @@ jobs: variant: gpu steps: - uses: actions/checkout@master + with: + submodules: true - run: sudo apt update && sudo apt install nvidia-cuda-toolkit if: matrix.variant == 'gpu' - run: source/install/build_cc.sh From 03a040b900d3f2aa081ad1a7ba22e92362a77640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Tue, 2 Mar 2021 12:49:00 +0100 Subject: [PATCH 222/562] fix bug in log levels parser --- deepmd/loggers/loggers.py | 15 +++++------ source/tests/test_argument_parser.py | 39 +++++++++++++++++++++++----- source/train/main.py | 39 ++++++++++++++++++++++------ 3 files changed, 69 insertions(+), 24 deletions(-) diff --git a/deepmd/loggers/loggers.py b/deepmd/loggers/loggers.py index 063cce7ba3..6400cb0a15 100644 --- a/deepmd/loggers/loggers.py +++ b/deepmd/loggers/loggers.py @@ -176,25 +176,22 @@ def set_log_handles( +---------+--------------+----------------+----------------+----------------+ | | our notation | python logging | tensorflow cpp | OpenMP | +=========+==============+================+================+================+ - | debug | 3 | 10 | 0 | 1/on/true/yes | + | debug | 10 | 10 | 0 | 1/on/true/yes | +---------+--------------+----------------+----------------+----------------+ - | info | 2 | 20 | 1 | 0/off/false/no | + | info | 20 | 20 | 1 | 0/off/false/no | +---------+--------------+----------------+----------------+----------------+ - | warning | 1 | 30 | 2 | 0/off/false/no | + | warning | 30 | 30 | 2 | 0/off/false/no | +---------+--------------+----------------+----------------+----------------+ - | error | 0 | 40 | 3 | 0/off/false/no | + | error | 40 | 40 | 3 | 0/off/false/no | +---------+--------------+----------------+----------------+----------------+ """ # silence logging for OpenMP when running on CPU if level is any other than debug - if level >= 3: + if level <= 10: os.environ["KMP_WARNINGS"] = "FALSE" # set TF cpp internal logging level - os.environ['TF_CPP_MIN_LOG_LEVEL'] = str(3 - level) - - # set python logging level - level = (4 - level) * 10 + os.environ['TF_CPP_MIN_LOG_LEVEL'] = str(int((level / 10) - 1)) # get root logger root_log = logging.getLogger() diff --git a/source/tests/test_argument_parser.py b/source/tests/test_argument_parser.py index 749cce58ab..ac5ea959a2 100644 --- a/source/tests/test_argument_parser.py +++ b/source/tests/test_argument_parser.py @@ -7,7 +7,7 @@ from io import StringIO from contextlib import redirect_stderr -from deepmd.main import parse_args +from deepmd.main import parse_args, get_ll if TYPE_CHECKING: try: @@ -92,22 +92,27 @@ def attr_and_type_check( # first check if namespace object hat the expected attribute self.assertTrue( hasattr(namespace, attribute), - msg=f"Namespace object does not have expected attribute: {attribute}" + msg=f"Namespace object does not have expected attribute: {attribute}", ) # than check if the attribute is of expected type self.assertIsInstance( getattr(namespace, attribute), expected_type, msg=f"Namespace attribute '{attribute}' is of wrong type, expected: " - f"{expected_type}, got: {type(getattr(namespace, attribute))}" + f"{expected_type}, got: {type(getattr(namespace, attribute))}", ) # if argument has associated value check if it is same as expected if "value" in test_data and test_value: + # use expected value if supplied + if "expected" in test_data: + expected = test_data["expected"] + else: + expected = test_data["value"] self.assertEqual( - test_data["value"], + expected, getattr(namespace, attribute), msg=f"Got wrong parsed value, expected: {test_data['value']}, got " - f"{getattr(namespace, attribute)}" + f"{getattr(namespace, attribute)}", ) def run_test(self, *, command: str, mapping: "TEST_DICT"): @@ -186,8 +191,8 @@ def test_wrong_command(self): def test_parser_log(self): """Check if logging associated attributes are present in specified parsers.""" ARGS = { - "--verbose": dict(type=int, dest="log_level"), - "--log-path": dict(type=(str, type(None)), value="LOGFILE") + "--log-level": dict(type=int, value="INFO", expected=20), + "--log-path": dict(type=(str, type(None)), value="LOGFILE"), } for parser in ("config", "transfer", "train", "freeze", "test", "compress"): @@ -280,3 +285,23 @@ def test_parser_doc(self): ARGS = {} self.run_test(command="doc-train-input", mapping=ARGS) + + def test_get_log_level(self): + MAPPING = { + "DEBUG": 10, + "INFO": 20, + "WARNING": 30, + "ERROR": 40, + "3": 10, + "2": 20, + "1": 30, + "0": 40, + } + + for input_val, expected_result in MAPPING.items(): + self.assertEqual( + get_ll(input_val), + expected_result, + msg=f"Expected: {expected_result} result for input value: {input_val} " + f"but got {get_ll(input_val)}" + ) diff --git a/source/train/main.py b/source/train/main.py index 366b6a1a94..ab936dd867 100644 --- a/source/train/main.py +++ b/source/train/main.py @@ -1,6 +1,7 @@ """DeePMD-Kit entry point module.""" import argparse +import logging from pathlib import Path from typing import List, Optional @@ -15,7 +16,28 @@ ) from deepmd.loggers import set_log_handles -__all__ = ["main", "parse_args"] +__all__ = ["main", "parse_args", "get_ll"] + + +def get_ll(log_level: str) -> int: + """Convert string to python logging level. + + Parameters + ---------- + log_level : str + allowed input values are: DEBUG, INFO, WARNING, ERROR, 3, 2, 1, 0 + + Returns + ------- + int + one of python logging module log levels - 10, 20, 30 or 40 + """ + if log_level.isdigit(): + int_level = (4 - int(log_level)) * 10 + else: + int_level = getattr(logging, log_level) + + return int_level def parse_args(args: Optional[List[str]] = None): @@ -40,13 +62,12 @@ def parse_args(args: Optional[List[str]] = None): add_help=False, formatter_class=argparse.ArgumentDefaultsHelpFormatter ) parser_log.add_argument( - "-v", - "--verbose", - default=2, - action="count", - dest="log_level", - help="set verbosity level 0 - 3, 0=ERROR, 1(-v)=WARNING, 2(-vv)=INFO " - "and 3(-vvv)=DEBUG", + #"-l", + "--log-level", + choices=["DEBUG", 3, "INFO", 2, "WARNING", 1, "ERROR", 0], + default="INFO", + help="set verbosity level by string or number, 0=ERROR, 1=WARNING, 2=INFO " + "and 3=DEBUG", ) parser_log.add_argument( "-l", @@ -291,6 +312,8 @@ def parse_args(args: Optional[List[str]] = None): parsed_args = parser.parse_args(args=args) if parsed_args.command is None: parser.print_help() + else: + parsed_args.log_level = get_ll(parsed_args.log_level) return parsed_args From 319f6854f86f32364f270514289812224d12f2b6 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 2 Mar 2021 21:06:54 +0800 Subject: [PATCH 223/562] print message to std:cerr and return rather than assertion. The assertions will be bypassed in release building mode --- source/api_cc/src/NNPInter.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/source/api_cc/src/NNPInter.cc b/source/api_cc/src/NNPInter.cc index 56f38d9900..4ac454a324 100644 --- a/source/api_cc/src/NNPInter.cc +++ b/source/api_cc/src/NNPInter.cc @@ -190,7 +190,10 @@ void NNPInter:: init (const std::string & model, const int & gpu_rank, const std::string & file_content) { - assert (!inited); + if (inited){ + std::cerr << "WARNING: deepmd-kit should not be initialized twice, do nothing at the second call of initializer" << std::endl; + return ; + } SessionOptions options; options.config.set_inter_op_parallelism_threads(num_inter_nthreads); options.config.set_intra_op_parallelism_threads(num_intra_nthreads); @@ -500,7 +503,10 @@ void NNPInterModelDevi:: init (const std::vector & models, const int & gpu_rank, const std::vector & file_contents) { - assert (!inited); + if (inited){ + std::cerr << "WARNING: deepmd-kit should not be initialized twice, do nothing at the second call of initializer" << std::endl; + return ; + } numb_models = models.size(); sessions.resize(numb_models); graph_defs.resize(numb_models); From 05c7272f4efcde83296cd1e6fa2f4d5d77b0170f Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 3 Mar 2021 08:18:54 +0800 Subject: [PATCH 224/562] change name of format_nlist to format_nlist_i, because the function only deals with one of the atoms --- source/lib/include/fmt_nlist.h | 4 +-- source/lib/src/fmt_nlist.cc | 8 +++--- source/lib/src/prod_env_mat.cc | 4 +-- source/lib/tests/test_env_mat_a.cc | 28 +++++++++---------- source/lib/tests/test_env_mat_r.cc | 18 ++++++------ source/lib/tests/test_fmt_nlist.cc | 16 +++++------ source/lib/tests/test_map_aparam.cc | 2 +- source/lib/tests/test_pair_tab.cc | 2 +- source/lib/tests/test_prod_force_a.cc | 2 +- source/lib/tests/test_prod_force_grad_a.cc | 2 +- source/lib/tests/test_prod_force_grad_r.cc | 2 +- source/lib/tests/test_prod_force_r.cc | 2 +- source/lib/tests/test_prod_virial_a.cc | 2 +- source/lib/tests/test_prod_virial_grad_a.cc | 2 +- source/lib/tests/test_prod_virial_grad_r.cc | 2 +- source/lib/tests/test_prod_virial_r.cc | 2 +- source/lib/tests/test_soft_min_switch.cc | 4 +-- .../lib/tests/test_soft_min_switch_force.cc | 2 +- .../tests/test_soft_min_switch_force_grad.cc | 2 +- .../lib/tests/test_soft_min_switch_virial.cc | 2 +- .../tests/test_soft_min_switch_virial_grad.cc | 2 +- source/op/descrpt.cc | 2 +- source/op/descrpt_se_a.cc | 2 +- source/op/descrpt_se_a_ef.cc | 2 +- source/op/descrpt_se_a_ef_para.cc | 2 +- source/op/descrpt_se_a_ef_vert.cc | 2 +- source/op/descrpt_se_r.cc | 2 +- 27 files changed, 61 insertions(+), 61 deletions(-) diff --git a/source/lib/include/fmt_nlist.h b/source/lib/include/fmt_nlist.h index f60f9de0d8..759d887b66 100644 --- a/source/lib/include/fmt_nlist.h +++ b/source/lib/include/fmt_nlist.h @@ -5,7 +5,7 @@ // return: -1 OK // > 0 the type of unsuccessful neighbor list -int format_nlist_fill_a ( +int format_nlist_i_fill_a ( std::vector & fmt_nei_idx_a, std::vector & fmt_nei_idx_r, const std::vector & posi, @@ -22,7 +22,7 @@ int format_nlist_fill_a ( template -int format_nlist_cpu ( +int format_nlist_i_cpu ( std::vector & fmt_nei_idx_a, const std::vector & posi, const int & ntypes, diff --git a/source/lib/src/fmt_nlist.cc b/source/lib/src/fmt_nlist.cc index 740860e540..cfdf845a17 100644 --- a/source/lib/src/fmt_nlist.cc +++ b/source/lib/src/fmt_nlist.cc @@ -5,7 +5,7 @@ #include "SimulationRegion.h" #include -int format_nlist_fill_a ( +int format_nlist_i_fill_a ( std::vector & fmt_nei_idx_a, std::vector & fmt_nei_idx_r, const std::vector & posi, @@ -78,7 +78,7 @@ int format_nlist_fill_a ( template -int format_nlist_cpu ( +int format_nlist_i_cpu ( std::vector & fmt_nei_idx_a, const std::vector &posi, const int & ntypes, @@ -124,7 +124,7 @@ int format_nlist_cpu ( } template -int format_nlist_cpu ( +int format_nlist_i_cpu ( std::vector & fmt_nei_idx_a, const std::vector &posi, const int & ntypes, @@ -136,7 +136,7 @@ int format_nlist_cpu ( template -int format_nlist_cpu ( +int format_nlist_i_cpu ( std::vector & fmt_nei_idx_a, const std::vector & posi, const int & ntypes, diff --git a/source/lib/src/prod_env_mat.cc b/source/lib/src/prod_env_mat.cc index ac0d35be5b..d5b2338415 100644 --- a/source/lib/src/prod_env_mat.cc +++ b/source/lib/src/prod_env_mat.cc @@ -60,7 +60,7 @@ void prod_env_mat_a_cpu( #pragma omp parallel for for (int ii = 0; ii < nloc; ++ii) { std::vector fmt_nlist_a; - int ret = format_nlist_cpu(fmt_nlist_a, d_coord3, ntypes, d_type, ii, d_nlist_a[ii], rcut, sec); + int ret = format_nlist_i_cpu(fmt_nlist_a, d_coord3, ntypes, d_type, ii, d_nlist_a[ii], rcut, sec); std::vector d_em_a; std::vector d_em_a_deriv; std::vector d_em_r; @@ -144,7 +144,7 @@ void prod_env_mat_r_cpu( #pragma omp parallel for for (int ii = 0; ii < nloc; ++ii) { std::vector fmt_nlist_a; - int ret = format_nlist_cpu(fmt_nlist_a, d_coord3, ntypes, d_type, ii, d_nlist_a[ii], rcut, sec); + int ret = format_nlist_i_cpu(fmt_nlist_a, d_coord3, ntypes, d_type, ii, d_nlist_a[ii], rcut, sec); std::vector d_em_a; std::vector d_em_a_deriv; std::vector d_em_r; diff --git a/source/lib/tests/test_env_mat_a.cc b/source/lib/tests/test_env_mat_a.cc index ffdfb73eba..f616fe6e0b 100644 --- a/source/lib/tests/test_env_mat_a.cc +++ b/source/lib/tests/test_env_mat_a.cc @@ -124,7 +124,7 @@ TEST_F(TestEnvMatA, orig_cpy) std::vector env, env_deriv, rij_a; bool pbc = false; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); env_mat_a(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]*4); @@ -148,7 +148,7 @@ TEST_F(TestEnvMatA, orig_pbc) std::vector env, env_deriv, rij_a; bool pbc = true; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi, ntypes, atype, region, pbc, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); + int ret = format_nlist_i_fill_a(fmt_nlist_a, fmt_nlist_r, posi, ntypes, atype, region, pbc, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); EXPECT_EQ(ret, -1); env_mat_a(env, env_deriv, rij_a, posi, ntypes, atype, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]*4); @@ -170,10 +170,10 @@ TEST_F(TestEnvMatA, orig_cpy_equal_pbc) std::vector env_0, env_deriv_0, rij_a_0; std::vector env_1, env_deriv_1, rij_a_1; for(int ii = 0; ii < nloc; ++ii){ - int ret_0 = format_nlist_cpu(fmt_nlist_a_0, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret_0 = format_nlist_i_cpu(fmt_nlist_a_0, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_0, -1); env_mat_a(env_0, env_deriv_0, rij_a_0, posi_cpy, ntypes, atype_cpy, region, false, ii, fmt_nlist_a_0, sec_a, rc_smth, rc); - int ret_1 = format_nlist_fill_a(fmt_nlist_a_1, fmt_nlist_r_1, posi, ntypes, atype, region, true, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); + int ret_1 = format_nlist_i_fill_a(fmt_nlist_a_1, fmt_nlist_r_1, posi, ntypes, atype, region, true, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); EXPECT_EQ(ret_1, -1); env_mat_a(env_1, env_deriv_1, rij_a_1, posi, ntypes, atype, region, true, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); EXPECT_EQ(env_0.size(), env_1.size()); @@ -199,7 +199,7 @@ TEST_F(TestEnvMatA, orig_cpy_num_deriv) bool pbc = false; double hh = 1e-5; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); env_mat_a(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]*4); @@ -237,7 +237,7 @@ TEST_F(TestEnvMatA, cpu) std::vector env, env_deriv, rij_a; bool pbc = false; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]*4); @@ -258,11 +258,11 @@ TEST_F(TestEnvMatA, cpu_equal_orig_cpy) std::vector env_0, env_deriv_0, rij_a_0; std::vector env_1, env_deriv_1, rij_a_1; for(int ii = 0; ii < nloc; ++ii){ - int ret_0 = format_nlist_cpu(fmt_nlist_a_0, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret_0 = format_nlist_i_cpu(fmt_nlist_a_0, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_0, -1); env_mat_a(env_0, env_deriv_0, rij_a_0, posi_cpy, ntypes, atype_cpy, region, false, ii, fmt_nlist_a_0, sec_a, rc_smth, rc); - int ret_1 = format_nlist_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_1, -1); env_mat_a_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); @@ -289,7 +289,7 @@ TEST_F(TestEnvMatA, cpu_num_deriv) bool pbc = false; double hh = 1e-5; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]*4); @@ -327,7 +327,7 @@ TEST_F(TestEnvMatAShortSel, orig_cpy) std::vector env, env_deriv, rij_a; bool pbc = false; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, 1); env_mat_a(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]*4); @@ -351,7 +351,7 @@ TEST_F(TestEnvMatAShortSel, orig_pbc) std::vector env, env_deriv, rij_a; bool pbc = true; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi, ntypes, atype, region, pbc, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); + int ret = format_nlist_i_fill_a(fmt_nlist_a, fmt_nlist_r, posi, ntypes, atype, region, pbc, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); EXPECT_EQ(ret, 1); env_mat_a(env, env_deriv, rij_a, posi, ntypes, atype, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]*4); @@ -371,7 +371,7 @@ TEST_F(TestEnvMatAShortSel, cpu) std::vector env, env_deriv, rij_a; bool pbc = false; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, 1); env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]*4); @@ -489,7 +489,7 @@ TEST_F(TestEnvMatA, prod_cpu_equal_cpu) std::vector fmt_nlist_a_1, fmt_nlist_r_1; std::vector env_1, env_deriv_1, rij_a_1; for(int ii = 0; ii < nloc; ++ii){ - int ret_1 = format_nlist_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_1, -1); env_mat_a_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); EXPECT_EQ(env_1.size(), nnei * 4); @@ -723,7 +723,7 @@ TEST_F(TestEnvMatA, prod_gpu_nv_equal_cpu) std::vector fmt_nlist_a_1, fmt_nlist_r_1; std::vector env_1, env_deriv_1, rij_a_1; for(int ii = 0; ii < nloc; ++ii){ - int ret_1 = format_nlist_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_1, -1); env_mat_a_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); EXPECT_EQ(env_1.size(), nnei * 4); diff --git a/source/lib/tests/test_env_mat_r.cc b/source/lib/tests/test_env_mat_r.cc index 9f8e5c62bc..cbc2e38a1e 100644 --- a/source/lib/tests/test_env_mat_r.cc +++ b/source/lib/tests/test_env_mat_r.cc @@ -63,7 +63,7 @@ TEST_F(TestEnvMatR, orig_cpy) std::vector env, env_deriv, rij_a; bool pbc = false; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); env_mat_r(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]); @@ -84,7 +84,7 @@ TEST_F(TestEnvMatR, orig_pbc) std::vector env, env_deriv, rij_a; bool pbc = true; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi, ntypes, atype, region, pbc, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); + int ret = format_nlist_i_fill_a(fmt_nlist_a, fmt_nlist_r, posi, ntypes, atype, region, pbc, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); EXPECT_EQ(ret, -1); env_mat_r(env, env_deriv, rij_a, posi, ntypes, atype, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < sec_a[2]; ++jj){ @@ -101,10 +101,10 @@ TEST_F(TestEnvMatR, orig_cpy_equal_pbc) std::vector env_0, env_deriv_0, rij_a_0; std::vector env_1, env_deriv_1, rij_a_1; for(int ii = 0; ii < nloc; ++ii){ - int ret_0 = format_nlist_cpu(fmt_nlist_a_0, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret_0 = format_nlist_i_cpu(fmt_nlist_a_0, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_0, -1); env_mat_r(env_0, env_deriv_0, rij_a_0, posi_cpy, ntypes, atype_cpy, region, false, ii, fmt_nlist_a_0, sec_a, rc_smth, rc); - int ret_1 = format_nlist_fill_a(fmt_nlist_a_1, fmt_nlist_r_1, posi, ntypes, atype, region, true, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); + int ret_1 = format_nlist_i_fill_a(fmt_nlist_a_1, fmt_nlist_r_1, posi, ntypes, atype, region, true, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); EXPECT_EQ(ret_1, -1); env_mat_r(env_1, env_deriv_1, rij_a_1, posi, ntypes, atype, region, true, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); EXPECT_EQ(env_0.size(), env_1.size()); @@ -130,7 +130,7 @@ TEST_F(TestEnvMatR, orig_cpy_num_deriv) bool pbc = false; double hh = 1e-5; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); env_mat_r(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); @@ -163,7 +163,7 @@ TEST_F(TestEnvMatR, cpu) std::vector env, env_deriv, rij_a; bool pbc = false; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); env_mat_r_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < sec_a[2]; ++jj){ @@ -179,11 +179,11 @@ TEST_F(TestEnvMatR, cpu_equal_orig_cpy) std::vector env_0, env_deriv_0, rij_a_0; std::vector env_1, env_deriv_1, rij_a_1; for(int ii = 0; ii < nloc; ++ii){ - int ret_0 = format_nlist_cpu(fmt_nlist_a_0, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret_0 = format_nlist_i_cpu(fmt_nlist_a_0, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_0, -1); env_mat_r(env_0, env_deriv_0, rij_a_0, posi_cpy, ntypes, atype_cpy, region, false, ii, fmt_nlist_a_0, sec_a, rc_smth, rc); - int ret_1 = format_nlist_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_1, -1); env_mat_r_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); @@ -209,7 +209,7 @@ TEST_F(TestEnvMatR, cpu_num_deriv) bool pbc = false; double hh = 1e-5; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); env_mat_r_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); diff --git a/source/lib/tests/test_fmt_nlist.cc b/source/lib/tests/test_fmt_nlist.cc index 87588b635d..019abb55f6 100644 --- a/source/lib/tests/test_fmt_nlist.cc +++ b/source/lib/tests/test_fmt_nlist.cc @@ -128,7 +128,7 @@ TEST_F(TestFormatNlist, orig_cpy) bool pbc = false; int ii = 0; for (ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi_cpy, ntypes, atype_cpy, region, pbc, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); + int ret = format_nlist_i_fill_a(fmt_nlist_a, fmt_nlist_r, posi_cpy, ntypes, atype_cpy, region, pbc, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); EXPECT_EQ(ret, -1); for (int jj = 0; jj < sec_a[2]; ++jj){ @@ -146,7 +146,7 @@ TEST_F(TestFormatNlist, orig_pbc) std::vector fmt_nlist_a_1, fmt_nlist_r_1; for (int ii = 0; ii < nloc; ++ii){ - int ret_1 = format_nlist_fill_a(fmt_nlist_a_1, fmt_nlist_r_1, posi, ntypes, atype, region, true, ii, nlist_a_1[ii], nlist_r_1[ii], rc, sec_a, sec_r); + int ret_1 = format_nlist_i_fill_a(fmt_nlist_a_1, fmt_nlist_r_1, posi, ntypes, atype, region, true, ii, nlist_a_1[ii], nlist_r_1[ii], rc, sec_a, sec_r); EXPECT_EQ(ret_1, -1); for (int jj = 0; jj < sec_a[2]; ++jj){ @@ -167,8 +167,8 @@ TEST_F(TestFormatNlist, orig_cpy_equal_pbc) std::vector fmt_nlist_a_1, fmt_nlist_r_1; for (int ii = 0; ii < nloc; ++ii){ - int ret_0 = format_nlist_fill_a(fmt_nlist_a_0, fmt_nlist_r_0, posi_cpy, ntypes, atype_cpy, region, false, ii, nlist_a_0[ii], nlist_r_0[ii], rc, sec_a, sec_r); - int ret_1 = format_nlist_fill_a(fmt_nlist_a_1, fmt_nlist_r_1, posi, ntypes, atype, region, true, ii, nlist_a_1[ii], nlist_r_1[ii], rc, sec_a, sec_r); + int ret_0 = format_nlist_i_fill_a(fmt_nlist_a_0, fmt_nlist_r_0, posi_cpy, ntypes, atype_cpy, region, false, ii, nlist_a_0[ii], nlist_r_0[ii], rc, sec_a, sec_r); + int ret_1 = format_nlist_i_fill_a(fmt_nlist_a_1, fmt_nlist_r_1, posi, ntypes, atype, region, true, ii, nlist_a_1[ii], nlist_r_1[ii], rc, sec_a, sec_r); EXPECT_EQ(ret_0, -1); EXPECT_EQ(ret_1, -1); @@ -193,8 +193,8 @@ TEST_F(TestFormatNlist, cpu_equal_orig) std::vector fmt_nlist_a_1; for (int ii = 0; ii < nloc; ++ii){ - int ret_0 = format_nlist_fill_a(fmt_nlist_a_0, fmt_nlist_r_0, posi_cpy, ntypes, atype_cpy, region, false, ii, nlist_a_0[ii], nlist_r_0[ii], rc, sec_a, sec_r); - int ret_1 = format_nlist_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_0[ii], rc, sec_a); + int ret_0 = format_nlist_i_fill_a(fmt_nlist_a_0, fmt_nlist_r_0, posi_cpy, ntypes, atype_cpy, region, false, ii, nlist_a_0[ii], nlist_r_0[ii], rc, sec_a, sec_r); + int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_0[ii], rc, sec_a); EXPECT_EQ(ret_0, -1); EXPECT_EQ(ret_1, -1); for (int jj = 0; jj < sec_a[2]; ++jj){ @@ -214,7 +214,7 @@ TEST_F(TestFormatNlistShortSel, orig_cpy) bool pbc = false; int ii = 0; for (ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_fill_a(fmt_nlist_a, fmt_nlist_r, posi_cpy, ntypes, atype_cpy, region, pbc, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); + int ret = format_nlist_i_fill_a(fmt_nlist_a, fmt_nlist_r, posi_cpy, ntypes, atype_cpy, region, pbc, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); EXPECT_EQ(ret, 1); for (int jj = 0; jj < sec_a[2]; ++jj){ EXPECT_EQ(fmt_nlist_a[jj], expect_nlist_cpy[ii*sec_a[2]+jj]); @@ -233,7 +233,7 @@ TEST_F(TestFormatNlistShortSel, cpu_equal_orig) std::vector fmt_nlist_a_1; for (int ii = 0; ii < nloc; ++ii){ - int ret_1 = format_nlist_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_0[ii], rc, sec_a); + int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_0[ii], rc, sec_a); EXPECT_EQ(ret_1, 1); for (int jj = 0; jj < sec_a[2]; ++jj){ EXPECT_EQ(fmt_nlist_a_1[jj], expect_nlist_cpy[ii*sec_a[2]+jj]); diff --git a/source/lib/tests/test_map_aparam.cc b/source/lib/tests/test_map_aparam.cc index 3bee6d4f63..43d11d676f 100644 --- a/source/lib/tests/test_map_aparam.cc +++ b/source/lib/tests/test_map_aparam.cc @@ -54,7 +54,7 @@ class TestMapAparam : public ::testing::Test nlist.resize(nloc * nnei); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } diff --git a/source/lib/tests/test_pair_tab.cc b/source/lib/tests/test_pair_tab.cc index 97a87120e3..0f8e5dea38 100644 --- a/source/lib/tests/test_pair_tab.cc +++ b/source/lib/tests/test_pair_tab.cc @@ -92,7 +92,7 @@ class TestPairTab : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } diff --git a/source/lib/tests/test_prod_force_a.cc b/source/lib/tests/test_prod_force_a.cc index 93766e1b78..964181da6f 100644 --- a/source/lib/tests/test_prod_force_a.cc +++ b/source/lib/tests/test_prod_force_a.cc @@ -58,7 +58,7 @@ class TestProdForceA : public ::testing::Test rij_a.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } diff --git a/source/lib/tests/test_prod_force_grad_a.cc b/source/lib/tests/test_prod_force_grad_a.cc index ec7afc5d86..496c0ae98f 100644 --- a/source/lib/tests/test_prod_force_grad_a.cc +++ b/source/lib/tests/test_prod_force_grad_a.cc @@ -58,7 +58,7 @@ class TestProdForceGradA : public ::testing::Test rij_a.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } diff --git a/source/lib/tests/test_prod_force_grad_r.cc b/source/lib/tests/test_prod_force_grad_r.cc index 80a5978c0c..843ac2717e 100644 --- a/source/lib/tests/test_prod_force_grad_r.cc +++ b/source/lib/tests/test_prod_force_grad_r.cc @@ -58,7 +58,7 @@ class TestProdForceGradR : public ::testing::Test rij_a.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } diff --git a/source/lib/tests/test_prod_force_r.cc b/source/lib/tests/test_prod_force_r.cc index 93247b2d86..228a7d9d11 100644 --- a/source/lib/tests/test_prod_force_r.cc +++ b/source/lib/tests/test_prod_force_r.cc @@ -58,7 +58,7 @@ class TestProdForceR : public ::testing::Test rij_a.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } diff --git a/source/lib/tests/test_prod_virial_a.cc b/source/lib/tests/test_prod_virial_a.cc index a8fb5fb914..563063f5a4 100644 --- a/source/lib/tests/test_prod_virial_a.cc +++ b/source/lib/tests/test_prod_virial_a.cc @@ -61,7 +61,7 @@ class TestProdVirialA : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } diff --git a/source/lib/tests/test_prod_virial_grad_a.cc b/source/lib/tests/test_prod_virial_grad_a.cc index 75475fc2a6..fb75886e34 100644 --- a/source/lib/tests/test_prod_virial_grad_a.cc +++ b/source/lib/tests/test_prod_virial_grad_a.cc @@ -58,7 +58,7 @@ class TestProdVirialGradA : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } diff --git a/source/lib/tests/test_prod_virial_grad_r.cc b/source/lib/tests/test_prod_virial_grad_r.cc index 5951b634d8..67d5562712 100644 --- a/source/lib/tests/test_prod_virial_grad_r.cc +++ b/source/lib/tests/test_prod_virial_grad_r.cc @@ -58,7 +58,7 @@ class TestProdVirialGradR : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } diff --git a/source/lib/tests/test_prod_virial_r.cc b/source/lib/tests/test_prod_virial_r.cc index 359eda8345..a25771c397 100644 --- a/source/lib/tests/test_prod_virial_r.cc +++ b/source/lib/tests/test_prod_virial_r.cc @@ -61,7 +61,7 @@ class TestProdVirialR : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } diff --git a/source/lib/tests/test_soft_min_switch.cc b/source/lib/tests/test_soft_min_switch.cc index f8aacccf34..98ef5c05a2 100644 --- a/source/lib/tests/test_soft_min_switch.cc +++ b/source/lib/tests/test_soft_min_switch.cc @@ -59,7 +59,7 @@ class TestSoftMinSwitch : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } @@ -111,7 +111,7 @@ TEST_F(TestSoftMinSwitch, cpu_num_deriv) EXPECT_EQ(sw_deriv.size(), nloc * nnei * 3); for (int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); int i_idx = ii; diff --git a/source/lib/tests/test_soft_min_switch_force.cc b/source/lib/tests/test_soft_min_switch_force.cc index 202e633402..b2d103c715 100644 --- a/source/lib/tests/test_soft_min_switch_force.cc +++ b/source/lib/tests/test_soft_min_switch_force.cc @@ -60,7 +60,7 @@ class TestSoftMinSwitchForce : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } diff --git a/source/lib/tests/test_soft_min_switch_force_grad.cc b/source/lib/tests/test_soft_min_switch_force_grad.cc index 216767d267..7885f6e33f 100644 --- a/source/lib/tests/test_soft_min_switch_force_grad.cc +++ b/source/lib/tests/test_soft_min_switch_force_grad.cc @@ -60,7 +60,7 @@ class TestSoftMinSwitchForceGrad : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } diff --git a/source/lib/tests/test_soft_min_switch_virial.cc b/source/lib/tests/test_soft_min_switch_virial.cc index 7ef06c739b..6c50b6c743 100644 --- a/source/lib/tests/test_soft_min_switch_virial.cc +++ b/source/lib/tests/test_soft_min_switch_virial.cc @@ -63,7 +63,7 @@ class TestSoftMinSwitchVirial : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } diff --git a/source/lib/tests/test_soft_min_switch_virial_grad.cc b/source/lib/tests/test_soft_min_switch_virial_grad.cc index 15545ccde5..3c4a73fcca 100644 --- a/source/lib/tests/test_soft_min_switch_virial_grad.cc +++ b/source/lib/tests/test_soft_min_switch_virial_grad.cc @@ -60,7 +60,7 @@ class TestSoftMinSwitchVirialGrad : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } diff --git a/source/op/descrpt.cc b/source/op/descrpt.cc index a6d007e674..1cbfb96574 100644 --- a/source/op/descrpt.cc +++ b/source/op/descrpt.cc @@ -264,7 +264,7 @@ class DescrptOp : public OpKernel { std::vector fmt_nlist_r; int ret = -1; if (fill_nei_a){ - if ((ret = format_nlist_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ + if ((ret = format_nlist_i_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ if (count_nei_idx_overflow == 0) { std::cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << std::endl; flush(std::cout); diff --git a/source/op/descrpt_se_a.cc b/source/op/descrpt_se_a.cc index 4444ac0218..51b8e26e0f 100644 --- a/source/op/descrpt_se_a.cc +++ b/source/op/descrpt_se_a.cc @@ -263,7 +263,7 @@ class DescrptSeAOp : public OpKernel { std::vector fmt_nlist_r; int ret = -1; if (fill_nei_a){ - if ((ret = format_nlist_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ + if ((ret = format_nlist_i_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ if (count_nei_idx_overflow == 0) { std::cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << std::endl; flush(std::cout); diff --git a/source/op/descrpt_se_a_ef.cc b/source/op/descrpt_se_a_ef.cc index 607c9bf1c5..7f07cc84b9 100644 --- a/source/op/descrpt_se_a_ef.cc +++ b/source/op/descrpt_se_a_ef.cc @@ -277,7 +277,7 @@ class DescrptSeAEfOp : public OpKernel { std::vector fmt_nlist_r; int ret = -1; if (fill_nei_a){ - if ((ret = format_nlist_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ + if ((ret = format_nlist_i_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ if (count_nei_idx_overflow == 0) { std::cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << std::endl; flush(std::cout); diff --git a/source/op/descrpt_se_a_ef_para.cc b/source/op/descrpt_se_a_ef_para.cc index 2a83026874..6e38e24a86 100644 --- a/source/op/descrpt_se_a_ef_para.cc +++ b/source/op/descrpt_se_a_ef_para.cc @@ -276,7 +276,7 @@ class DescrptSeAEfParaOp : public OpKernel { std::vector fmt_nlist_r; int ret = -1; if (fill_nei_a){ - if ((ret = format_nlist_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ + if ((ret = format_nlist_i_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ if (count_nei_idx_overflow == 0) { std::cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << std::endl; flush(std::cout); diff --git a/source/op/descrpt_se_a_ef_vert.cc b/source/op/descrpt_se_a_ef_vert.cc index c98f2fc615..9b08f87ce6 100644 --- a/source/op/descrpt_se_a_ef_vert.cc +++ b/source/op/descrpt_se_a_ef_vert.cc @@ -276,7 +276,7 @@ class DescrptSeAEfVertOp : public OpKernel { std::vector fmt_nlist_r; int ret = -1; if (fill_nei_a){ - if ((ret = format_nlist_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ + if ((ret = format_nlist_i_fill_a (fmt_nlist_a, fmt_nlist_r, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_a[ii], d_nlist_r[ii], rcut_r, sec_a, sec_r)) != -1){ if (count_nei_idx_overflow == 0) { std::cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << std::endl; flush(std::cout); diff --git a/source/op/descrpt_se_r.cc b/source/op/descrpt_se_r.cc index c76f247a51..7031ed20e8 100644 --- a/source/op/descrpt_se_r.cc +++ b/source/op/descrpt_se_r.cc @@ -248,7 +248,7 @@ class DescrptSeROp : public OpKernel { std::vector fmt_nlist; int ret = -1; if (fill_nei_a){ - if ((ret = format_nlist_fill_a (fmt_nlist, fmt_nlist_null, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_null[ii], d_nlist[ii], rcut, sec, sec_null)) != -1){ + if ((ret = format_nlist_i_fill_a (fmt_nlist, fmt_nlist_null, d_coord3, ntypes, d_type, region, b_pbc, ii, d_nlist_null[ii], d_nlist[ii], rcut, sec, sec_null)) != -1){ if (count_nei_idx_overflow == 0) { std::cout << "WARNING: Radial neighbor list length of type " << ret << " is not enough" << std::endl; flush(std::cout); From 8ad6192a252fc1316924f0a748b8805369ba767b Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 3 Mar 2021 09:10:36 +0800 Subject: [PATCH 225/562] clean up the cpu interface of env_mat and fmt_nlist. --- source/lib/include/env_mat.h | 2 - source/lib/include/fmt_nlist.h | 13 ++++++- source/lib/include/neighbor_list.h | 23 +++++++++++ source/lib/include/prod_env_mat.h | 2 - source/lib/src/env_mat.cc | 6 --- source/lib/src/fmt_nlist.cc | 15 ++++++-- source/lib/src/neighbor_list.cc | 16 ++++++++ source/lib/src/prod_env_mat.cc | 16 +++----- source/lib/tests/test_env_mat_a.cc | 38 +++++++++---------- source/lib/tests/test_env_mat_r.cc | 20 +++++----- source/lib/tests/test_fmt_nlist.cc | 4 +- source/lib/tests/test_map_aparam.cc | 2 +- source/lib/tests/test_pair_tab.cc | 24 ++++++------ source/lib/tests/test_prod_force_a.cc | 4 +- source/lib/tests/test_prod_force_grad_a.cc | 4 +- source/lib/tests/test_prod_force_grad_r.cc | 4 +- source/lib/tests/test_prod_force_r.cc | 4 +- source/lib/tests/test_prod_virial_a.cc | 4 +- source/lib/tests/test_prod_virial_grad_a.cc | 4 +- source/lib/tests/test_prod_virial_grad_r.cc | 4 +- source/lib/tests/test_prod_virial_r.cc | 4 +- source/lib/tests/test_soft_min_switch.cc | 10 ++--- .../lib/tests/test_soft_min_switch_force.cc | 4 +- .../tests/test_soft_min_switch_force_grad.cc | 4 +- .../lib/tests/test_soft_min_switch_virial.cc | 4 +- .../tests/test_soft_min_switch_virial_grad.cc | 4 +- source/op/prod_env_mat_multi_device.cc | 4 +- 27 files changed, 142 insertions(+), 101 deletions(-) diff --git a/source/lib/include/env_mat.h b/source/lib/include/env_mat.h index 067c6949d6..1217051f70 100644 --- a/source/lib/include/env_mat.h +++ b/source/lib/include/env_mat.h @@ -24,7 +24,6 @@ void env_mat_a_cpu ( std::vector & descrpt_a_deriv, std::vector & rij_a, const std::vector & posi, - const int & ntypes, const std::vector & type, const int & i_idx, const std::vector & fmt_nlist, @@ -53,7 +52,6 @@ void env_mat_r_cpu ( std::vector & descrpt_a_deriv, std::vector & rij_a, const std::vector & posi, - const int & ntypes, const std::vector & type, const int & i_idx, const std::vector & fmt_nlist_a, diff --git a/source/lib/include/fmt_nlist.h b/source/lib/include/fmt_nlist.h index 759d887b66..3b8a30eefe 100644 --- a/source/lib/include/fmt_nlist.h +++ b/source/lib/include/fmt_nlist.h @@ -1,8 +1,20 @@ #pragma once #include +#include "neighbor_list.h" #include "SimulationRegion.h" +template +void format_nlist_cpu( + int * nlist, + const InputNlist & in_nlist, + const FPTYPE * coord, + const int * type, + const int nloc, + const int nall, + const float rcut, + const std::vector sec); + // return: -1 OK // > 0 the type of unsuccessful neighbor list int format_nlist_i_fill_a ( @@ -25,7 +37,6 @@ template int format_nlist_i_cpu ( std::vector & fmt_nei_idx_a, const std::vector & posi, - const int & ntypes, const std::vector & type, const int & i_idx, const std::vector & nei_idx_a, diff --git a/source/lib/include/neighbor_list.h b/source/lib/include/neighbor_list.h index b47249c81a..17d7f8d6db 100644 --- a/source/lib/include/neighbor_list.h +++ b/source/lib/include/neighbor_list.h @@ -3,10 +3,33 @@ #include #include #include +#include #include "utilities.h" #include "SimulationRegion.h" +// format of the input neighbor list +struct InputNlist +{ + int inum; + int * ilist; + int * numneigh; + int ** firstneigh; + InputNlist ( + int inum_, + int * ilist_, + int * numneigh_, + int ** firstneigh_ + ) + : inum(inum_), ilist(ilist_), numneigh(numneigh_), firstneigh(firstneigh_) + {} +}; + +void convert_from( + InputNlist & to_nlist, + std::vector > & from_nlist + ); + // build nlist by an extended grid void build_nlist (std::vector > & nlist0, diff --git a/source/lib/include/prod_env_mat.h b/source/lib/include/prod_env_mat.h index f49078260e..2b09d07d22 100644 --- a/source/lib/include/prod_env_mat.h +++ b/source/lib/include/prod_env_mat.h @@ -18,7 +18,6 @@ void prod_env_mat_a_cpu( const FPTYPE * std, const int nloc, const int nall, - const int ntypes, const float rcut, const float rcut_smth, const std::vector sec); @@ -39,7 +38,6 @@ void prod_env_mat_r_cpu( const FPTYPE * std, const int nloc, const int nall, - const int ntypes, const float rcut, const float rcut_smth, const std::vector sec); diff --git a/source/lib/src/env_mat.cc b/source/lib/src/env_mat.cc index 7aec89feaa..c9cadb4b0d 100644 --- a/source/lib/src/env_mat.cc +++ b/source/lib/src/env_mat.cc @@ -97,7 +97,6 @@ void env_mat_a_cpu ( std::vector & descrpt_a_deriv, std::vector & rij_a, const std::vector & posi, - const int & ntypes, const std::vector & type, const int & i_idx, const std::vector & fmt_nlist_a, @@ -244,7 +243,6 @@ void env_mat_r_cpu ( std::vector & descrpt_a_deriv, std::vector & rij_a, const std::vector & posi, - const int & ntypes, const std::vector & type, const int & i_idx, const std::vector & fmt_nlist, @@ -305,7 +303,6 @@ void env_mat_a_cpu ( std::vector & descrpt_a_deriv, std::vector & rij_a, const std::vector & posi, - const int & ntypes, const std::vector & type, const int & i_idx, const std::vector & fmt_nlist, @@ -320,7 +317,6 @@ void env_mat_a_cpu ( std::vector & descrpt_a_deriv, std::vector & rij_a, const std::vector & posi, - const int & ntypes, const std::vector & type, const int & i_idx, const std::vector & fmt_nlist, @@ -335,7 +331,6 @@ void env_mat_r_cpu ( std::vector & descrpt_r_deriv, std::vector & rij_r, const std::vector & posi, - const int & ntypes, const std::vector & type, const int & i_idx, const std::vector & fmt_nlist, @@ -350,7 +345,6 @@ void env_mat_r_cpu ( std::vector & descrpt_r_deriv, std::vector & rij_r, const std::vector & posi, - const int & ntypes, const std::vector & type, const int & i_idx, const std::vector & fmt_nlist, diff --git a/source/lib/src/fmt_nlist.cc b/source/lib/src/fmt_nlist.cc index cfdf845a17..72e9620c65 100644 --- a/source/lib/src/fmt_nlist.cc +++ b/source/lib/src/fmt_nlist.cc @@ -81,7 +81,6 @@ template int format_nlist_i_cpu ( std::vector & fmt_nei_idx_a, const std::vector &posi, - const int & ntypes, const std::vector & type, const int & i_idx, const std::vector & nei_idx_a, @@ -123,11 +122,22 @@ int format_nlist_i_cpu ( return overflowed; } +template +void format_nlist_cpu ( + int * nlist, + const InputNlist & in_nlist, + const FPTYPE * coord, + const int * type, + const float rcut, + const std::vector sec) +{ + +} + template int format_nlist_i_cpu ( std::vector & fmt_nei_idx_a, const std::vector &posi, - const int & ntypes, const std::vector & type, const int & i_idx, const std::vector & nei_idx_a, @@ -139,7 +149,6 @@ template int format_nlist_i_cpu ( std::vector & fmt_nei_idx_a, const std::vector & posi, - const int & ntypes, const std::vector & type, const int & i_idx, const std::vector & nei_idx_a, diff --git a/source/lib/src/neighbor_list.cc b/source/lib/src/neighbor_list.cc index 01ba7a2a26..060a92d995 100644 --- a/source/lib/src/neighbor_list.cc +++ b/source/lib/src/neighbor_list.cc @@ -742,3 +742,19 @@ copy_coord (std::vector & out_c, } } + +void +convert_from( + InputNlist & to_nlist, + std::vector > & from_nlist + ) +{ + to_nlist.inum = from_nlist.size(); + for(int ii = 0; ii < to_nlist.inum; ++ii){ + to_nlist.ilist[ii] = ii; + to_nlist.numneigh[ii] = from_nlist[ii].size(); + to_nlist.firstneigh[ii] = &from_nlist[ii][0]; + } +} + + diff --git a/source/lib/src/prod_env_mat.cc b/source/lib/src/prod_env_mat.cc index d5b2338415..ce052b3df0 100644 --- a/source/lib/src/prod_env_mat.cc +++ b/source/lib/src/prod_env_mat.cc @@ -21,7 +21,6 @@ void prod_env_mat_a_cpu( const FPTYPE * std, const int nloc, const int nall, - const int ntypes, const float rcut, const float rcut_smth, const std::vector sec) @@ -60,13 +59,13 @@ void prod_env_mat_a_cpu( #pragma omp parallel for for (int ii = 0; ii < nloc; ++ii) { std::vector fmt_nlist_a; - int ret = format_nlist_i_cpu(fmt_nlist_a, d_coord3, ntypes, d_type, ii, d_nlist_a[ii], rcut, sec); + int ret = format_nlist_i_cpu(fmt_nlist_a, d_coord3, d_type, ii, d_nlist_a[ii], rcut, sec); std::vector d_em_a; std::vector d_em_a_deriv; std::vector d_em_r; std::vector d_em_r_deriv; std::vector d_rij_a; - env_mat_a_cpu (d_em_a, d_em_a_deriv, d_rij_a, d_coord3, ntypes, d_type, ii, fmt_nlist_a, sec, rcut_smth, rcut); + env_mat_a_cpu (d_em_a, d_em_a_deriv, d_rij_a, d_coord3, d_type, ii, fmt_nlist_a, sec, rcut_smth, rcut); // check sizes assert (d_em_a.size() == nem); @@ -105,7 +104,6 @@ void prod_env_mat_r_cpu( const FPTYPE * std, const int nloc, const int nall, - const int ntypes, const float rcut, const float rcut_smth, const std::vector sec) @@ -144,13 +142,13 @@ void prod_env_mat_r_cpu( #pragma omp parallel for for (int ii = 0; ii < nloc; ++ii) { std::vector fmt_nlist_a; - int ret = format_nlist_i_cpu(fmt_nlist_a, d_coord3, ntypes, d_type, ii, d_nlist_a[ii], rcut, sec); + int ret = format_nlist_i_cpu(fmt_nlist_a, d_coord3, d_type, ii, d_nlist_a[ii], rcut, sec); std::vector d_em_a; std::vector d_em_a_deriv; std::vector d_em_r; std::vector d_em_r_deriv; std::vector d_rij_a; - env_mat_r_cpu (d_em_a, d_em_a_deriv, d_rij_a, d_coord3, ntypes, d_type, ii, fmt_nlist_a, sec, rcut_smth, rcut); + env_mat_r_cpu (d_em_a, d_em_a_deriv, d_rij_a, d_coord3, d_type, ii, fmt_nlist_a, sec, rcut_smth, rcut); // check sizes assert (d_em_a.size() == nem); @@ -190,7 +188,6 @@ void prod_env_mat_a_cpu( const double * std, const int nloc, const int nall, - const int ntypes, const float rcut, const float rcut_smth, const std::vector sec); @@ -211,7 +208,6 @@ void prod_env_mat_a_cpu( const float * std, const int nloc, const int nall, - const int ntypes, const float rcut, const float rcut_smth, const std::vector sec); @@ -232,7 +228,6 @@ void prod_env_mat_r_cpu( const double * std, const int nloc, const int nall, - const int ntypes, const float rcut, const float rcut_smth, const std::vector sec); @@ -253,7 +248,6 @@ void prod_env_mat_r_cpu( const float * std, const int nloc, const int nall, - const int ntypes, const float rcut, const float rcut_smth, const std::vector sec); @@ -323,4 +317,4 @@ void env_mat_nbor_update( } delete [] mesh_host; } -#endif // GOOGLE_CUDA \ No newline at end of file +#endif // GOOGLE_CUDA diff --git a/source/lib/tests/test_env_mat_a.cc b/source/lib/tests/test_env_mat_a.cc index f616fe6e0b..48f5794f57 100644 --- a/source/lib/tests/test_env_mat_a.cc +++ b/source/lib/tests/test_env_mat_a.cc @@ -124,7 +124,7 @@ TEST_F(TestEnvMatA, orig_cpy) std::vector env, env_deriv, rij_a; bool pbc = false; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); env_mat_a(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]*4); @@ -170,7 +170,7 @@ TEST_F(TestEnvMatA, orig_cpy_equal_pbc) std::vector env_0, env_deriv_0, rij_a_0; std::vector env_1, env_deriv_1, rij_a_1; for(int ii = 0; ii < nloc; ++ii){ - int ret_0 = format_nlist_i_cpu(fmt_nlist_a_0, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret_0 = format_nlist_i_cpu(fmt_nlist_a_0, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_0, -1); env_mat_a(env_0, env_deriv_0, rij_a_0, posi_cpy, ntypes, atype_cpy, region, false, ii, fmt_nlist_a_0, sec_a, rc_smth, rc); int ret_1 = format_nlist_i_fill_a(fmt_nlist_a_1, fmt_nlist_r_1, posi, ntypes, atype, region, true, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); @@ -199,7 +199,7 @@ TEST_F(TestEnvMatA, orig_cpy_num_deriv) bool pbc = false; double hh = 1e-5; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); env_mat_a(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]*4); @@ -237,9 +237,9 @@ TEST_F(TestEnvMatA, cpu) std::vector env, env_deriv, rij_a; bool pbc = false; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); - env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]*4); EXPECT_EQ(env.size(), env_deriv.size()/3); EXPECT_EQ(rij_a.size(), sec_a[2]*3); @@ -258,14 +258,14 @@ TEST_F(TestEnvMatA, cpu_equal_orig_cpy) std::vector env_0, env_deriv_0, rij_a_0; std::vector env_1, env_deriv_1, rij_a_1; for(int ii = 0; ii < nloc; ++ii){ - int ret_0 = format_nlist_i_cpu(fmt_nlist_a_0, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret_0 = format_nlist_i_cpu(fmt_nlist_a_0, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_0, -1); env_mat_a(env_0, env_deriv_0, rij_a_0, posi_cpy, ntypes, atype_cpy, region, false, ii, fmt_nlist_a_0, sec_a, rc_smth, rc); - int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_1, -1); - env_mat_a_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + env_mat_a_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); EXPECT_EQ(env_0.size(), env_1.size()); EXPECT_EQ(env_deriv_0.size(), env_deriv_1.size()); @@ -289,9 +289,9 @@ TEST_F(TestEnvMatA, cpu_num_deriv) bool pbc = false; double hh = 1e-5; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); - env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]*4); EXPECT_EQ(env.size(), env_deriv.size()/3); EXPECT_EQ(rij_a.size(), sec_a[2]*3); @@ -327,7 +327,7 @@ TEST_F(TestEnvMatAShortSel, orig_cpy) std::vector env, env_deriv, rij_a; bool pbc = false; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, 1); env_mat_a(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]*4); @@ -371,9 +371,9 @@ TEST_F(TestEnvMatAShortSel, cpu) std::vector env, env_deriv, rij_a; bool pbc = false; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, 1); - env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]*4); EXPECT_EQ(env.size(), env_deriv.size()/3); EXPECT_EQ(rij_a.size(), sec_a[2]*3); @@ -425,7 +425,6 @@ TEST_F(TestEnvMatA, prod_cpu) &std[0], nloc, nall, - ntypes, rc, rc_smth, sec_a); @@ -481,7 +480,6 @@ TEST_F(TestEnvMatA, prod_cpu_equal_cpu) &std[0], nloc, nall, - ntypes, rc, rc_smth, sec_a); @@ -489,9 +487,9 @@ TEST_F(TestEnvMatA, prod_cpu_equal_cpu) std::vector fmt_nlist_a_1, fmt_nlist_r_1; std::vector env_1, env_deriv_1, rij_a_1; for(int ii = 0; ii < nloc; ++ii){ - int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_1, -1); - env_mat_a_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + env_mat_a_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); EXPECT_EQ(env_1.size(), nnei * 4); EXPECT_EQ(env_deriv_1.size(), nnei * 4 * 3); EXPECT_EQ(rij_a_1.size(), nnei * 3); @@ -723,9 +721,9 @@ TEST_F(TestEnvMatA, prod_gpu_nv_equal_cpu) std::vector fmt_nlist_a_1, fmt_nlist_r_1; std::vector env_1, env_deriv_1, rij_a_1; for(int ii = 0; ii < nloc; ++ii){ - int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_1, -1); - env_mat_a_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + env_mat_a_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); EXPECT_EQ(env_1.size(), nnei * 4); EXPECT_EQ(env_deriv_1.size(), nnei * 4 * 3); EXPECT_EQ(rij_a_1.size(), nnei * 3); @@ -758,4 +756,4 @@ TEST_F(TestEnvMatA, prod_gpu_nv_equal_cpu) // } // } } -#endif //GOOGLE_CUDA \ No newline at end of file +#endif //GOOGLE_CUDA diff --git a/source/lib/tests/test_env_mat_r.cc b/source/lib/tests/test_env_mat_r.cc index cbc2e38a1e..56e61fecdb 100644 --- a/source/lib/tests/test_env_mat_r.cc +++ b/source/lib/tests/test_env_mat_r.cc @@ -63,7 +63,7 @@ TEST_F(TestEnvMatR, orig_cpy) std::vector env, env_deriv, rij_a; bool pbc = false; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); env_mat_r(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]); @@ -101,7 +101,7 @@ TEST_F(TestEnvMatR, orig_cpy_equal_pbc) std::vector env_0, env_deriv_0, rij_a_0; std::vector env_1, env_deriv_1, rij_a_1; for(int ii = 0; ii < nloc; ++ii){ - int ret_0 = format_nlist_i_cpu(fmt_nlist_a_0, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret_0 = format_nlist_i_cpu(fmt_nlist_a_0, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_0, -1); env_mat_r(env_0, env_deriv_0, rij_a_0, posi_cpy, ntypes, atype_cpy, region, false, ii, fmt_nlist_a_0, sec_a, rc_smth, rc); int ret_1 = format_nlist_i_fill_a(fmt_nlist_a_1, fmt_nlist_r_1, posi, ntypes, atype, region, true, ii, nlist_a[ii], nlist_r[ii], rc, sec_a, sec_r); @@ -130,7 +130,7 @@ TEST_F(TestEnvMatR, orig_cpy_num_deriv) bool pbc = false; double hh = 1e-5; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); env_mat_r(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, region, pbc, ii, fmt_nlist_a, sec_a, rc_smth, rc); @@ -163,9 +163,9 @@ TEST_F(TestEnvMatR, cpu) std::vector env, env_deriv, rij_a; bool pbc = false; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); - env_mat_r_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_r_cpu(env, env_deriv, rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < sec_a[2]; ++jj){ EXPECT_LT(fabs(env[jj] - expected_env[ii*sec_a[2] + jj]) , 1e-5); } @@ -179,13 +179,13 @@ TEST_F(TestEnvMatR, cpu_equal_orig_cpy) std::vector env_0, env_deriv_0, rij_a_0; std::vector env_1, env_deriv_1, rij_a_1; for(int ii = 0; ii < nloc; ++ii){ - int ret_0 = format_nlist_i_cpu(fmt_nlist_a_0, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret_0 = format_nlist_i_cpu(fmt_nlist_a_0, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_0, -1); env_mat_r(env_0, env_deriv_0, rij_a_0, posi_cpy, ntypes, atype_cpy, region, false, ii, fmt_nlist_a_0, sec_a, rc_smth, rc); - int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_1, -1); - env_mat_r_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + env_mat_r_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); EXPECT_EQ(env_0.size(), env_1.size()); EXPECT_EQ(env_deriv_0.size(), env_deriv_1.size()); @@ -209,9 +209,9 @@ TEST_F(TestEnvMatR, cpu_num_deriv) bool pbc = false; double hh = 1e-5; for(int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); - env_mat_r_cpu(env, env_deriv, rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_r_cpu(env, env_deriv, rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < sec_a[2]; ++jj){ int j_idx = fmt_nlist_a[jj]; diff --git a/source/lib/tests/test_fmt_nlist.cc b/source/lib/tests/test_fmt_nlist.cc index 019abb55f6..ce8be45a03 100644 --- a/source/lib/tests/test_fmt_nlist.cc +++ b/source/lib/tests/test_fmt_nlist.cc @@ -194,7 +194,7 @@ TEST_F(TestFormatNlist, cpu_equal_orig) for (int ii = 0; ii < nloc; ++ii){ int ret_0 = format_nlist_i_fill_a(fmt_nlist_a_0, fmt_nlist_r_0, posi_cpy, ntypes, atype_cpy, region, false, ii, nlist_a_0[ii], nlist_r_0[ii], rc, sec_a, sec_r); - int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_0[ii], rc, sec_a); + int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, atype_cpy, ii, nlist_a_0[ii], rc, sec_a); EXPECT_EQ(ret_0, -1); EXPECT_EQ(ret_1, -1); for (int jj = 0; jj < sec_a[2]; ++jj){ @@ -233,7 +233,7 @@ TEST_F(TestFormatNlistShortSel, cpu_equal_orig) std::vector fmt_nlist_a_1; for (int ii = 0; ii < nloc; ++ii){ - int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_0[ii], rc, sec_a); + int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, atype_cpy, ii, nlist_a_0[ii], rc, sec_a); EXPECT_EQ(ret_1, 1); for (int jj = 0; jj < sec_a[2]; ++jj){ EXPECT_EQ(fmt_nlist_a_1[jj], expect_nlist_cpy[ii*sec_a[2]+jj]); diff --git a/source/lib/tests/test_map_aparam.cc b/source/lib/tests/test_map_aparam.cc index 43d11d676f..286f878ffe 100644 --- a/source/lib/tests/test_map_aparam.cc +++ b/source/lib/tests/test_map_aparam.cc @@ -54,7 +54,7 @@ class TestMapAparam : public ::testing::Test nlist.resize(nloc * nnei); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } diff --git a/source/lib/tests/test_pair_tab.cc b/source/lib/tests/test_pair_tab.cc index 0f8e5dea38..867956e7ae 100644 --- a/source/lib/tests/test_pair_tab.cc +++ b/source/lib/tests/test_pair_tab.cc @@ -92,13 +92,13 @@ class TestPairTab : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < ndescrpt; ++jj){ env[ii*ndescrpt+jj] = t_env[jj]; for (int dd = 0; dd < 3; ++dd){ @@ -250,8 +250,8 @@ TEST_F(TestPairTab, cpu_f_num_deriv) std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); pair_tab_cpu( @@ -354,8 +354,8 @@ TEST_F(TestPairTab, cpu_f_num_deriv_scale) std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); pair_tab_cpu( @@ -471,8 +471,8 @@ TEST_F(TestPairTab, cpu_v_num_deriv) std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); pair_tab_cpu( @@ -599,8 +599,8 @@ TEST_F(TestPairTab, cpu_v_num_deriv_scale) std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); pair_tab_cpu( @@ -727,8 +727,8 @@ TEST_F(TestPairTabTriBox, cpu_v_num_deriv) std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, ntypes, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); pair_tab_cpu( diff --git a/source/lib/tests/test_prod_force_a.cc b/source/lib/tests/test_prod_force_a.cc index 964181da6f..c15d5f67c5 100644 --- a/source/lib/tests/test_prod_force_a.cc +++ b/source/lib/tests/test_prod_force_a.cc @@ -58,13 +58,13 @@ class TestProdForceA : public ::testing::Test rij_a.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } std::vector t_env, t_env_deriv, t_rij_a; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < ndescrpt; ++jj){ env[ii*ndescrpt+jj] = t_env[jj]; for (int dd = 0; dd < 3; ++dd){ diff --git a/source/lib/tests/test_prod_force_grad_a.cc b/source/lib/tests/test_prod_force_grad_a.cc index 496c0ae98f..b52c1c951e 100644 --- a/source/lib/tests/test_prod_force_grad_a.cc +++ b/source/lib/tests/test_prod_force_grad_a.cc @@ -58,13 +58,13 @@ class TestProdForceGradA : public ::testing::Test rij_a.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } std::vector t_env, t_env_deriv, t_rij_a; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < ndescrpt; ++jj){ env[ii*ndescrpt+jj] = t_env[jj]; for (int dd = 0; dd < 3; ++dd){ diff --git a/source/lib/tests/test_prod_force_grad_r.cc b/source/lib/tests/test_prod_force_grad_r.cc index 843ac2717e..c32ce150e8 100644 --- a/source/lib/tests/test_prod_force_grad_r.cc +++ b/source/lib/tests/test_prod_force_grad_r.cc @@ -58,13 +58,13 @@ class TestProdForceGradR : public ::testing::Test rij_a.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } std::vector t_env, t_env_deriv, t_rij_a; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < ndescrpt; ++jj){ env[ii*ndescrpt+jj] = t_env[jj]; for (int dd = 0; dd < 3; ++dd){ diff --git a/source/lib/tests/test_prod_force_r.cc b/source/lib/tests/test_prod_force_r.cc index 228a7d9d11..fac10764ea 100644 --- a/source/lib/tests/test_prod_force_r.cc +++ b/source/lib/tests/test_prod_force_r.cc @@ -58,13 +58,13 @@ class TestProdForceR : public ::testing::Test rij_a.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } std::vector t_env, t_env_deriv, t_rij_a; // compute env_mat and its deriv, record - env_mat_r_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_r_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < ndescrpt; ++jj){ env[ii*ndescrpt+jj] = t_env[jj]; for (int dd = 0; dd < 3; ++dd){ diff --git a/source/lib/tests/test_prod_virial_a.cc b/source/lib/tests/test_prod_virial_a.cc index 563063f5a4..7692dc813e 100644 --- a/source/lib/tests/test_prod_virial_a.cc +++ b/source/lib/tests/test_prod_virial_a.cc @@ -61,13 +61,13 @@ class TestProdVirialA : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < ndescrpt; ++jj){ env[ii*ndescrpt+jj] = t_env[jj]; for (int dd = 0; dd < 3; ++dd){ diff --git a/source/lib/tests/test_prod_virial_grad_a.cc b/source/lib/tests/test_prod_virial_grad_a.cc index fb75886e34..cba31a10a8 100644 --- a/source/lib/tests/test_prod_virial_grad_a.cc +++ b/source/lib/tests/test_prod_virial_grad_a.cc @@ -58,13 +58,13 @@ class TestProdVirialGradA : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < ndescrpt; ++jj){ env[ii*ndescrpt+jj] = t_env[jj]; for (int dd = 0; dd < 3; ++dd){ diff --git a/source/lib/tests/test_prod_virial_grad_r.cc b/source/lib/tests/test_prod_virial_grad_r.cc index 67d5562712..45e6944590 100644 --- a/source/lib/tests/test_prod_virial_grad_r.cc +++ b/source/lib/tests/test_prod_virial_grad_r.cc @@ -58,13 +58,13 @@ class TestProdVirialGradR : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < ndescrpt; ++jj){ env[ii*ndescrpt+jj] = t_env[jj]; for (int dd = 0; dd < 3; ++dd){ diff --git a/source/lib/tests/test_prod_virial_r.cc b/source/lib/tests/test_prod_virial_r.cc index a25771c397..645130f4a9 100644 --- a/source/lib/tests/test_prod_virial_r.cc +++ b/source/lib/tests/test_prod_virial_r.cc @@ -61,13 +61,13 @@ class TestProdVirialR : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_r_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_r_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < ndescrpt; ++jj){ env[ii*ndescrpt+jj] = t_env[jj]; for (int dd = 0; dd < 3; ++dd){ diff --git a/source/lib/tests/test_soft_min_switch.cc b/source/lib/tests/test_soft_min_switch.cc index 98ef5c05a2..0e9319c183 100644 --- a/source/lib/tests/test_soft_min_switch.cc +++ b/source/lib/tests/test_soft_min_switch.cc @@ -59,13 +59,13 @@ class TestSoftMinSwitch : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < nnei * 3; ++jj){ rij[ii*nnei*3 + jj] = t_rij[jj]; } @@ -111,7 +111,7 @@ TEST_F(TestSoftMinSwitch, cpu_num_deriv) EXPECT_EQ(sw_deriv.size(), nloc * nnei * 3); for (int ii = 0; ii < nloc; ++ii){ - int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); int i_idx = ii; @@ -123,8 +123,8 @@ TEST_F(TestSoftMinSwitch, cpu_num_deriv) std::vector posi_1 = posi_cpy; posi_0[j_idx*3+dd] -= hh; posi_1[j_idx*3+dd] += hh; - env_mat_a_cpu(env, env_deriv, t_rij_0, posi_0, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); - env_mat_a_cpu(env, env_deriv, t_rij_1, posi_1, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a_cpu(env, env_deriv, t_rij_0, posi_0, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a_cpu(env, env_deriv, t_rij_1, posi_1, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(t_rij_0.size(), nnei * 3); EXPECT_EQ(t_rij_1.size(), nnei * 3); rij_0 = rij; diff --git a/source/lib/tests/test_soft_min_switch_force.cc b/source/lib/tests/test_soft_min_switch_force.cc index b2d103c715..ebe1b62dfe 100644 --- a/source/lib/tests/test_soft_min_switch_force.cc +++ b/source/lib/tests/test_soft_min_switch_force.cc @@ -60,13 +60,13 @@ class TestSoftMinSwitchForce : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < nnei * 3; ++jj){ rij[ii*nnei*3 + jj] = t_rij[jj]; } diff --git a/source/lib/tests/test_soft_min_switch_force_grad.cc b/source/lib/tests/test_soft_min_switch_force_grad.cc index 7885f6e33f..66faf0801a 100644 --- a/source/lib/tests/test_soft_min_switch_force_grad.cc +++ b/source/lib/tests/test_soft_min_switch_force_grad.cc @@ -60,13 +60,13 @@ class TestSoftMinSwitchForceGrad : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < nnei * 3; ++jj){ rij[ii*nnei*3 + jj] = t_rij[jj]; } diff --git a/source/lib/tests/test_soft_min_switch_virial.cc b/source/lib/tests/test_soft_min_switch_virial.cc index 6c50b6c743..6132590adf 100644 --- a/source/lib/tests/test_soft_min_switch_virial.cc +++ b/source/lib/tests/test_soft_min_switch_virial.cc @@ -63,13 +63,13 @@ class TestSoftMinSwitchVirial : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < nnei * 3; ++jj){ rij[ii*nnei*3 + jj] = t_rij[jj]; } diff --git a/source/lib/tests/test_soft_min_switch_virial_grad.cc b/source/lib/tests/test_soft_min_switch_virial_grad.cc index 3c4a73fcca..540e846f73 100644 --- a/source/lib/tests/test_soft_min_switch_virial_grad.cc +++ b/source/lib/tests/test_soft_min_switch_virial_grad.cc @@ -60,13 +60,13 @@ class TestSoftMinSwitchVirialGrad : public ::testing::Test rij.resize(nloc * nnei * 3); for(int ii = 0; ii < nloc; ++ii){ // format nlist and record - format_nlist_i_cpu(fmt_nlist_a, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); for (int jj = 0; jj < nnei; ++jj){ nlist[ii*nnei + jj] = fmt_nlist_a[jj]; } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < nnei * 3; ++jj){ rij[ii*nnei*3 + jj] = t_rij[jj]; } diff --git a/source/op/prod_env_mat_multi_device.cc b/source/op/prod_env_mat_multi_device.cc index 54ce6bde1f..a50461a274 100644 --- a/source/op/prod_env_mat_multi_device.cc +++ b/source/op/prod_env_mat_multi_device.cc @@ -180,7 +180,7 @@ class DescrptSeAOp : public OpKernel { // launch the cpu compute function prod_env_mat_a_cpu( em, em_deriv, rij, nlist, - coord, type, ilist, jrange, jlist, max_nbor_size, avg, std, nloc, nall, ntypes, rcut_r, rcut_r_smth, sec_a); + coord, type, ilist, jrange, jlist, max_nbor_size, avg, std, nloc, nall, rcut_r, rcut_r_smth, sec_a); } } @@ -333,7 +333,7 @@ class DescrptSeROp : public OpKernel { // launch the cpu compute function prod_env_mat_r_cpu( em, em_deriv, rij, nlist, - coord, type, ilist, jrange, jlist, max_nbor_size, avg, std, nloc, nall, ntypes, rcut, rcut_smth, sec); + coord, type, ilist, jrange, jlist, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); } } From bd6fbed31426fef75378f3d4d7a78e1258a5646d Mon Sep 17 00:00:00 2001 From: denghuilu Date: Wed, 3 Mar 2021 13:54:24 +0800 Subject: [PATCH 226/562] fix bug of max_nbor_size usage --- source/op/descrpt_se_a_multi_device.cc | 19 +++++++++++++++---- source/op/descrpt_se_r_multi_device.cc | 18 +++++++++++++++--- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/source/op/descrpt_se_a_multi_device.cc b/source/op/descrpt_se_a_multi_device.cc index 93e2cdccac..141b2d89bc 100644 --- a/source/op/descrpt_se_a_multi_device.cc +++ b/source/op/descrpt_se_a_multi_device.cc @@ -21,6 +21,8 @@ REGISTER_OP("DescrptSeA") .Output("nlist: int32"); // only sel_a and rcut_r uesd. +#define GPU_MAX_NBOR_SIZE 4096 + struct DeviceFunctor { void operator()(const CPUDevice& d, std::string& device) { device = "CPU"; @@ -158,14 +160,14 @@ class DescrptSeAOp : public OpKernel { OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); Tensor uint64_temp; TensorShape uint64_shape; - uint64_shape.AddDim(nloc * max_nbor_size * 2); + uint64_shape.AddDim(nloc * GPU_MAX_NBOR_SIZE * 2); OP_REQUIRES_OK(context, context->allocate_temp(DT_UINT64, uint64_shape, &uint64_temp)); array_int = int_temp.flat().data(); array_longlong = uint64_temp.flat().data(); nbor_update(mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); - OP_REQUIRES (context, (max_nbor_size <= 4096), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than 4096, which currently is not supported by deepmd-kit.")); + OP_REQUIRES (context, (max_nbor_size <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than 4096, which currently is not supported by deepmd-kit.")); } else if (device == "CPU") { memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); @@ -267,14 +269,23 @@ class DescrptSeAOp : public OpKernel { cudaErrcheck(cudaMemcpy(jrange, jrange_host, sizeof(int) * mesh_host[2], cudaMemcpyHostToDevice)); cudaErrcheck(cudaMemcpy(jlist, jlist_host, sizeof(int) * mesh_host[3], cudaMemcpyHostToDevice)); - max_nbor_size = 1024; + max_nbor_size = 0; for(int ii = 0; ii < mesh_host[2]; ii++) { max_nbor_size = (jrange_host[ii + 1] - jrange_host[ii]) > max_nbor_size ? (jrange_host[ii + 1] - jrange_host[ii]) : max_nbor_size; } + assert(max_nbor_size <= GPU_MAX_NBOR_SIZE); + if (max_nbor_size <= 1024) { + max_nbor_size = 1024; + } + else if (max_nbor_size <= 2048) { + max_nbor_size = 2048; + } + else { + max_nbor_size = 4096; + } } delete [] mesh_host; } - }; // Register the CPU kernels. diff --git a/source/op/descrpt_se_r_multi_device.cc b/source/op/descrpt_se_r_multi_device.cc index b94f97d6e1..c355e34f12 100644 --- a/source/op/descrpt_se_r_multi_device.cc +++ b/source/op/descrpt_se_r_multi_device.cc @@ -18,6 +18,8 @@ REGISTER_OP("DescrptSeR") .Output("rij: T") .Output("nlist: int32"); +#define GPU_MAX_NBOR_SIZE 4096 + struct DeviceFunctor { void operator()(const CPUDevice& d, std::string& device) { device = "CPU"; @@ -147,14 +149,14 @@ class DescrptSeROp : public OpKernel { OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, int_shape, &int_temp)); Tensor uint64_temp; TensorShape uint64_shape; - uint64_shape.AddDim(nloc * max_nbor_size * 2); + uint64_shape.AddDim(nloc * GPU_MAX_NBOR_SIZE * 2); OP_REQUIRES_OK(context, context->allocate_temp(DT_UINT64, uint64_shape, &uint64_temp)); array_int = int_temp.flat().data(); array_longlong = uint64_temp.flat().data(); nbor_update(mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); - OP_REQUIRES (context, (max_nbor_size <= 4096), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than 4096, which currently is not supported by deepmd-kit.")); + OP_REQUIRES (context, (max_nbor_size <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than 4096, which currently is not supported by deepmd-kit.")); } else if (device == "CPU") { memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); @@ -256,10 +258,20 @@ class DescrptSeROp : public OpKernel { cudaErrcheck(cudaMemcpy(jrange, jrange_host, sizeof(int) * mesh_host[2], cudaMemcpyHostToDevice)); cudaErrcheck(cudaMemcpy(jlist, jlist_host, sizeof(int) * mesh_host[3], cudaMemcpyHostToDevice)); - max_nbor_size = 1024; + max_nbor_size = 0; for(int ii = 0; ii < mesh_host[2]; ii++) { max_nbor_size = (jrange_host[ii + 1] - jrange_host[ii]) > max_nbor_size ? (jrange_host[ii + 1] - jrange_host[ii]) : max_nbor_size; } + assert(max_nbor_size <= GPU_MAX_NBOR_SIZE); + if (max_nbor_size <= 1024) { + max_nbor_size = 1024; + } + else if (max_nbor_size <= 2048) { + max_nbor_size = 2048; + } + else { + max_nbor_size = 4096; + } } delete [] mesh_host; } From 74fb1964d1dfcf4a30f5627f0beadc592fada023 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Wed, 3 Mar 2021 14:01:25 +0800 Subject: [PATCH 227/562] Update CMakeLists.txt --- source/op/cuda/CMakeLists.txt | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/source/op/cuda/CMakeLists.txt b/source/op/cuda/CMakeLists.txt index 0201e50130..8eab370b1d 100644 --- a/source/op/cuda/CMakeLists.txt +++ b/source/op/cuda/CMakeLists.txt @@ -19,7 +19,17 @@ include_directories(cub) message(STATUS "CUDA major version is " ${CUDA_VERSION_MAJOR}) -if (${CUDA_VERSION_MAJOR} GREATER "10") +if (${CUDA_VERSION_MAJOR} GREATER "11") + # nvcc flags + set(CUDA_NVCC_FLAGS -gencode arch=compute_60,code=sm_60; # Pascal – GP100/Tesla P100 – DGX-1 (Generic Pascal) + -gencode arch=compute_61,code=sm_61; # Pascal - GTX 1080, GTX 1070, GTX 1060, GTX 1050, GTX 1030, Titan Xp, Tesla P40, Tesla P4, Discrete GPU on the NVIDIA Drive PX2 + -gencode arch=compute_70,code=sm_70; # Volta - GV100/Tesla V100, GTX 1180 (GV104) + -gencode arch=compute_75,code=sm_75; # Turing - RTX 2080, Titan RTX, Quadro R8000 + -gencode arch=compute_80,code=sm_80; # Anpere - A100 + -gencode arch=compute_86,code=sm_86; # Anpere - RTX 3090 + -O3; -Xcompiler -fPIC; + ) +elseif (${CUDA_VERSION_MAJOR} STREQUAL "11" AND ${CUDA_VERSION_MINOR} GREATER "0") # nvcc flags set(CUDA_NVCC_FLAGS -gencode arch=compute_50,code=sm_50; -gencode arch=compute_52,code=sm_52; # Tesla M40, Tesla M40, Quadro M6000... @@ -32,6 +42,18 @@ if (${CUDA_VERSION_MAJOR} GREATER "10") -gencode arch=compute_86,code=sm_86; # Anpere - RTX 3090 -O3; -Xcompiler -fPIC; ) +elseif (${CUDA_VERSION_MAJOR} STREQUAL "11" AND ${CUDA_VERSION_MINOR} STREQUAL "0") + # nvcc flags + set(CUDA_NVCC_FLAGS -gencode arch=compute_50,code=sm_50; + -gencode arch=compute_52,code=sm_52; # Tesla M40, Tesla M40, Quadro M6000... + -gencode arch=compute_53,code=sm_53; + -gencode arch=compute_60,code=sm_60; # Pascal – GP100/Tesla P100 – DGX-1 (Generic Pascal) + -gencode arch=compute_61,code=sm_61; # Pascal - GTX 1080, GTX 1070, GTX 1060, GTX 1050, GTX 1030, Titan Xp, Tesla P40, Tesla P4, Discrete GPU on the NVIDIA Drive PX2 + -gencode arch=compute_70,code=sm_70; # Volta - GV100/Tesla V100, GTX 1180 (GV104) + -gencode arch=compute_75,code=sm_75; # Turing - RTX 2080, Titan RTX, Quadro R8000 + -gencode arch=compute_80,code=sm_80; # Anpere - A100 + -O3; -Xcompiler -fPIC; + ) elseif (${CUDA_VERSION_MAJOR} STREQUAL "10") set(CUDA_NVCC_FLAGS -gencode arch=compute_30,code=sm_30; # Tesla K10, Quadro K600 K420 K410, -gencode arch=compute_35,code=sm_35; # Tesla K20 K40, TITAN Z Black, GTX 780Ti 780 From f52e28ab75b147d9f4c78f286c41ae38a90b3e10 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 3 Mar 2021 14:30:35 +0800 Subject: [PATCH 228/562] c++ style interface for format_nlist. independent impl. of Region and UT. --- source/lib/include/neighbor_list.h | 30 ++++- source/lib/include/region.h | 31 +++++ source/lib/src/fmt_nlist.cc | 54 ++++++++ source/lib/src/neighbor_list.cc | 27 +++- source/lib/src/region.cc | 148 +++++++++++++++++++++ source/lib/tests/test_fmt_nlist.cc | 62 ++++++++- source/lib/tests/test_simulation_region.cc | 68 +++++++++- 7 files changed, 416 insertions(+), 4 deletions(-) create mode 100644 source/lib/include/region.h create mode 100644 source/lib/src/region.cc diff --git a/source/lib/include/neighbor_list.h b/source/lib/include/neighbor_list.h index 17d7f8d6db..29b476fb3f 100644 --- a/source/lib/include/neighbor_list.h +++ b/source/lib/include/neighbor_list.h @@ -25,11 +25,39 @@ struct InputNlist {} }; -void convert_from( +void convert_nlist( InputNlist & to_nlist, std::vector > & from_nlist ); + +// template +// void +// build_nlist_nopbc( +// InputNlist & nlist, +// const FPTYPE * coord, +// const int & nloc, +// const float & rcut); + +// template +// void +// build_nlist_pbc( +// InputNlist & nlist, +// const FPTYPE * coord, +// const Region & region, +// const int & nloc, +// const float & rcut); + +// template +// void +// build_nlist_pbc( +// InputNlist & nlist, +// const FPTYPE * coord, +// const Region & region, +// const int & nloc, +// const float & rcut); + + // build nlist by an extended grid void build_nlist (std::vector > & nlist0, diff --git a/source/lib/include/region.h b/source/lib/include/region.h new file mode 100644 index 0000000000..e5e0aab5d7 --- /dev/null +++ b/source/lib/include/region.h @@ -0,0 +1,31 @@ +#pragma once + +template +struct Region +{ + FPTYPE * boxt; + FPTYPE * rec_boxt; + Region(); + ~Region(); +}; + +template +void +init_region_cpu( + Region & region, + const FPTYPE * boxt); + +template +void +convert_to_inter_cpu( + FPTYPE * ri, + const Region & region, + const FPTYPE * rp); + +template +void +convert_to_phys_cpu( + FPTYPE * rp, + const Region & region, + const FPTYPE * ri); + diff --git a/source/lib/src/fmt_nlist.cc b/source/lib/src/fmt_nlist.cc index 72e9620c65..0d9b921b1b 100644 --- a/source/lib/src/fmt_nlist.cc +++ b/source/lib/src/fmt_nlist.cc @@ -128,10 +128,41 @@ void format_nlist_cpu ( const InputNlist & in_nlist, const FPTYPE * coord, const int * type, + const int nloc, + const int nall, const float rcut, const std::vector sec) { + std::vector posi_(nall * 3); + std::vector type_(nall); + std::copy(coord, coord + nall * 3, posi_.begin()); + std::copy(type, type + nall, type_.begin()); + std::vector ilist, fmt_ilist; + int nnei = sec.back(); + for(int ii = 0; ii < in_nlist.inum; ++ii){ + int i_idx = in_nlist.ilist[ii]; + int i_num = in_nlist.numneigh[ii]; + ilist.resize(i_num); + std::copy(in_nlist.firstneigh[ii], in_nlist.firstneigh[ii] + i_num, ilist.begin()); + format_nlist_i_cpu( + fmt_ilist, + posi_, + type_, + i_idx, + ilist, + rcut, + sec); + int * cur_nlist = nlist + i_idx * nnei; + if(fmt_ilist.size() != nnei){ + std::cerr << "FATAL: formatted nlist of i have length " + << fmt_ilist.size() + << " which does not match " + << nnei << std::endl; + exit(1); + } + std::copy(fmt_ilist.begin(), fmt_ilist.end(), cur_nlist); + } } template @@ -155,4 +186,27 @@ int format_nlist_i_cpu ( const float & rcut, const std::vector & sec_a); +template +void format_nlist_cpu ( + int * nlist, + const InputNlist & in_nlist, + const double * coord, + const int * type, + const int nloc, + const int nall, + const float rcut, + const std::vector sec); + + +template +void format_nlist_cpu ( + int * nlist, + const InputNlist & in_nlist, + const float * coord, + const int * type, + const int nloc, + const int nall, + const float rcut, + const std::vector sec); + diff --git a/source/lib/src/neighbor_list.cc b/source/lib/src/neighbor_list.cc index 060a92d995..8eb7b6c142 100644 --- a/source/lib/src/neighbor_list.cc +++ b/source/lib/src/neighbor_list.cc @@ -744,7 +744,7 @@ copy_coord (std::vector & out_c, void -convert_from( +convert_nlist( InputNlist & to_nlist, std::vector > & from_nlist ) @@ -757,4 +757,29 @@ convert_from( } } + +// template +// void +// build_nlist_pbc( +// InputNlist & nlist, +// const FPTYPE * coord, +// const Region & region, +// const int & nloc, +// const float & rcut) +// { +// std::vector in_c(nloc); +// std::vector in_t(nloc, 0); +// std::copy(coord, coord + nloc * 3, in_c.begin()); +// SimulationRegion tmpr; +// double tmp_boxt[9]; +// std::copy(region.boxt, region.boxt+9, tmp_boxt); +// tmpr.reinitBox(tmp_boxt); + +// std::vector out_c; +// std::vector out_r, mapping, ncell, ngcell; + +// } + + + diff --git a/source/lib/src/region.cc b/source/lib/src/region.cc new file mode 100644 index 0000000000..b4c1aa2e77 --- /dev/null +++ b/source/lib/src/region.cc @@ -0,0 +1,148 @@ +#include +#include +#include "region.h" +#define BOXT_DIM 9 + +template +Region:: +Region() +{ + boxt = new FPTYPE[BOXT_DIM]; + rec_boxt = new FPTYPE[BOXT_DIM]; +} + +template +Region:: +~Region() +{ + delete [] boxt; + delete [] rec_boxt; +} + +template struct Region; +template struct Region; + +template +inline FPTYPE +compute_volume(const FPTYPE * boxt) +{ + FPTYPE volume = + boxt[0*3+0] * (boxt[1*3+1]*boxt[2*3+2] - boxt[2*3+1]*boxt[1*3+2]) - + boxt[0*3+1] * (boxt[1*3+0]*boxt[2*3+2] - boxt[2*3+0]*boxt[1*3+2]) + + boxt[0*3+2] * (boxt[1*3+0]*boxt[2*3+1] - boxt[2*3+0]*boxt[1*3+1]); + if (volume < 0) { + throw std::runtime_error("Negative volume detected. Please make sure the simulation cell obeys the right-hand rule."); + } + return volume; +} + +template +inline void +compute_rec_boxt( + FPTYPE * rec_boxt, + const FPTYPE * boxt) +{ + FPTYPE volumei = static_cast(1.) / compute_volume(boxt); + rec_boxt[0*3+0] =( boxt[1*3+1]*boxt[2*3+2] - boxt[2*3+1]*boxt[1*3+2]) * volumei; + rec_boxt[1*3+1] =( boxt[0*3+0]*boxt[2*3+2] - boxt[2*3+0]*boxt[0*3+2]) * volumei; + rec_boxt[2*3+2] =( boxt[0*3+0]*boxt[1*3+1] - boxt[1*3+0]*boxt[0*3+1]) * volumei; + rec_boxt[0*3+1] =(-boxt[1*3+0]*boxt[2*3+2] + boxt[2*3+0]*boxt[1*3+2]) * volumei; + rec_boxt[0*3+2] =( boxt[1*3+0]*boxt[2*3+1] - boxt[2*3+0]*boxt[1*3+1]) * volumei; + rec_boxt[1*3+0] =(-boxt[0*3+1]*boxt[2*3+2] + boxt[2*3+1]*boxt[0*3+2]) * volumei; + rec_boxt[1*3+2] =(-boxt[0*3+0]*boxt[2*3+1] + boxt[2*3+0]*boxt[0*3+1]) * volumei; + rec_boxt[2*3+0] =( boxt[0*3+1]*boxt[1*3+2] - boxt[1*3+1]*boxt[0*3+2]) * volumei; + rec_boxt[2*3+1] =(-boxt[0*3+0]*boxt[1*3+2] + boxt[1*3+0]*boxt[0*3+2]) * volumei; +} + +template +inline void +tensor_dot_vec ( + FPTYPE * o_v, + const FPTYPE * i_t, + const FPTYPE * i_v) +{ + o_v[0] = i_v[0] * i_t[0*3+0] + i_v[1] * i_t[0*3+1] + i_v[2] * i_t[0*3+2]; + o_v[1] = i_v[0] * i_t[1*3+0] + i_v[1] * i_t[1*3+1] + i_v[2] * i_t[1*3+2]; + o_v[2] = i_v[0] * i_t[2*3+0] + i_v[1] * i_t[2*3+1] + i_v[2] * i_t[2*3+2]; +} + +template +inline void +tensor_t_dot_vec ( + FPTYPE * o_v, + const FPTYPE * i_t, + const FPTYPE * i_v) +{ + o_v[0] = i_v[0] * i_t[0*3+0] + i_v[1] * i_t[1*3+0] + i_v[2] * i_t[2*3+0]; + o_v[1] = i_v[0] * i_t[0*3+1] + i_v[1] * i_t[1*3+1] + i_v[2] * i_t[2*3+1]; + o_v[2] = i_v[0] * i_t[0*3+2] + i_v[1] * i_t[1*3+2] + i_v[2] * i_t[2*3+2]; +} + +template +void +init_region_cpu( + Region & region, + const FPTYPE * boxt) +{ + std::copy(boxt, boxt+BOXT_DIM, region.boxt); + compute_rec_boxt(region.rec_boxt, region.boxt); +} + +template +void +convert_to_inter_cpu( + FPTYPE * ri, + const Region & region, + const FPTYPE * rp) +{ + tensor_dot_vec(ri, region.rec_boxt, rp); +} + +template +void +convert_to_phys_cpu( + FPTYPE * rp, + const Region & region, + const FPTYPE * ri) +{ + tensor_t_dot_vec(rp, region.boxt, ri); +} + +template +void init_region_cpu( + Region & region, + const double * boxt); + +template +void init_region_cpu( + Region & region, + const float * boxt); + +template +void +convert_to_inter_cpu( + double * ri, + const Region & region, + const double * rp); + +template +void +convert_to_inter_cpu( + float * ri, + const Region & region, + const float * rp); + +template +void +convert_to_phys_cpu( + double * ri, + const Region & region, + const double * rp); + +template +void +convert_to_phys_cpu( + float * ri, + const Region & region, + const float * rp); + diff --git a/source/lib/tests/test_fmt_nlist.cc b/source/lib/tests/test_fmt_nlist.cc index ce8be45a03..a37562a230 100644 --- a/source/lib/tests/test_fmt_nlist.cc +++ b/source/lib/tests/test_fmt_nlist.cc @@ -184,7 +184,7 @@ TEST_F(TestFormatNlist, orig_cpy_equal_pbc) } } -TEST_F(TestFormatNlist, cpu_equal_orig) +TEST_F(TestFormatNlist, cpu_i_equal_orig) { std::vector> nlist_a_0, nlist_r_0; build_nlist(nlist_a_0, nlist_r_0, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); @@ -203,6 +203,36 @@ TEST_F(TestFormatNlist, cpu_equal_orig) } } +TEST_F(TestFormatNlist, cpu) +{ + std::vector> nlist_a_0, nlist_r_0; + build_nlist(nlist_a_0, nlist_r_0, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + // make a input nlist + int inum = nlist_a_0.size(); + std::vector ilist(inum); + std::vector numneigh(inum); + std::vector firstneigh(inum); + InputNlist in_nlist(inum, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(in_nlist, nlist_a_0); + // allocate the mem for the result + std::vector nlist(inum * sec_a.back()); + EXPECT_EQ(nlist.size(), expect_nlist_cpy.size()); + // format nlist + format_nlist_cpu( + &nlist[0], + in_nlist, + &posi_cpy[0], + &atype_cpy[0], + nloc, + nall, + rc, + sec_a); + // validate + for(int ii = 0; ii < nlist.size(); ++ii){ + EXPECT_EQ(nlist[ii], expect_nlist_cpy[ii]); + } +} + // orginal implementation. copy ghost TEST_F(TestFormatNlistShortSel, orig_cpy) @@ -241,3 +271,33 @@ TEST_F(TestFormatNlistShortSel, cpu_equal_orig) } } +TEST_F(TestFormatNlistShortSel, cpu) +{ + std::vector> nlist_a_0, nlist_r_0; + build_nlist(nlist_a_0, nlist_r_0, posi_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); + // make a input nlist + int inum = nlist_a_0.size(); + std::vector ilist(inum); + std::vector numneigh(inum); + std::vector firstneigh(inum); + InputNlist in_nlist(inum, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(in_nlist, nlist_a_0); + // mem + std::vector nlist(inum * sec_a.back()); + EXPECT_EQ(nlist.size(), expect_nlist_cpy.size()); + // format nlist + format_nlist_cpu( + &nlist[0], + in_nlist, + &posi_cpy[0], + &atype_cpy[0], + nloc, + nall, + rc, + sec_a); + // validate + for(int ii = 0; ii < nlist.size(); ++ii){ + EXPECT_EQ(nlist[ii], expect_nlist_cpy[ii]); + } +} + diff --git a/source/lib/tests/test_simulation_region.cc b/source/lib/tests/test_simulation_region.cc index 0e55d9a13c..90424dfd89 100644 --- a/source/lib/tests/test_simulation_region.cc +++ b/source/lib/tests/test_simulation_region.cc @@ -1,8 +1,74 @@ - #include #include +#include +#include "region.h" #include "SimulationRegion.h" +class TestRegion : public ::testing::Test +{ +protected: + std::vector ref_boxt = { + 3.27785716, 0.09190842, 0.14751448, 0.02331264, 4.36482777, -0.2999871 , -0.47510999, -0.38123489, 5.33561809 + }; + // rec_boxt = boxt^{-T} + std::vector ref_rec_boxt = { + 3.0385229041853185e-01, 2.3783430948044884e-04, 2.7073513689027690e-02, -7.1670232142159460e-03, 2.3022911797728179e-01, 1.5811897837543720e-02, -8.8035961973365381e-03, 1.2937710358702505e-02, 1.8756020637229892e-01 + }; + std::vector ref_rp = { + 1.5, 2.5, 3.5 + }; + std::vector ref_ri = { + 0.5511303193130958, 0.6201639025532836, 0.6755996039037975, + }; +}; + +TEST_F(TestRegion, orig) +{ + SimulationRegion region; + region.reinitBox(&ref_boxt[0]); + const double * rec_boxt = region.getRecBoxTensor(); + for(int ii = 0; ii < 9; ++ii){ + EXPECT_LT(fabs(rec_boxt[ii] - ref_rec_boxt[ii]), 1e-10); + } + double ri[3]; + region.phys2Inter(ri, &ref_rp[0]); + for(int ii = 0; ii < 3; ++ii){ + EXPECT_LT(fabs(ri[ii] - ref_ri[ii]), 1e-10); + } +} + +TEST_F(TestRegion, cpu) +{ + // check rec_box + Region region; + init_region_cpu(region, &ref_boxt[0]); + for(int ii = 0; ii < 9; ++ii){ + EXPECT_LT(fabs(region.rec_boxt[ii] - ref_rec_boxt[ii]), 1e-10); + } + // check conversion between phys and inter coords. + double ri[3]; + convert_to_inter_cpu(ri, region, &ref_rp[0]); + for(int ii = 0; ii < 3; ++ii){ + EXPECT_LT(fabs(ri[ii] - ref_ri[ii]), 1e-10); + } + double rp2[3]; + convert_to_phys_cpu(rp2, region, ri); + for(int ii = 0; ii < 3; ++ii){ + EXPECT_LT(fabs(rp2[ii] - ref_rp[ii]), 1e-10); + } + double rp[3]; + convert_to_phys_cpu(rp, region, &ref_ri[0]); + for(int ii = 0; ii < 3; ++ii){ + EXPECT_LT(fabs(rp[ii] - ref_rp[ii]), 1e-10); + } + double ri2[3]; + convert_to_inter_cpu(ri2, region, rp); + for(int ii = 0; ii < 3; ++ii){ + EXPECT_LT(fabs(ri2[ii] - ref_ri[ii]), 1e-10); + } +} + + // double square_root (const double xx) // { // return sqrt(xx); From 6d8dbea55d79d30385be3fc1594aa87de844d855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Wed, 3 Mar 2021 16:04:53 +0100 Subject: [PATCH 229/562] small fix --- source/train/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/train/main.py b/source/train/main.py index ab936dd867..062cca86e8 100644 --- a/source/train/main.py +++ b/source/train/main.py @@ -62,7 +62,7 @@ def parse_args(args: Optional[List[str]] = None): add_help=False, formatter_class=argparse.ArgumentDefaultsHelpFormatter ) parser_log.add_argument( - #"-l", + "-v", "--log-level", choices=["DEBUG", 3, "INFO", 2, "WARNING", 1, "ERROR", 0], default="INFO", From dc785f0da56600ea061561cd5283af9173a1f64d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Wed, 3 Mar 2021 16:25:34 +0100 Subject: [PATCH 230/562] changed ubuntu latest to 18.04 in gh actions --- .github/workflows/test_python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index 469dcd869b..dadd749b36 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -5,7 +5,7 @@ name: Test Python jobs: testpython: name: Test Python - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 strategy: matrix: include: From d50b38a045ec2013f5beacccc764e6e77ea00551 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Thu, 4 Mar 2021 19:30:44 +0800 Subject: [PATCH 231/562] implment coord and neighbor_list, add unittests --- source/lib/include/coord.h | 35 ++++ source/lib/include/neighbor_list.h | 46 +++-- source/lib/src/coord.cc | 110 ++++++++++++ source/lib/src/neighbor_list.cc | 88 +++++++--- source/lib/tests/test_coord.cc | 232 +++++++++++++++++++++++++ source/lib/tests/test_neighbor_list.cc | 118 +++++++++++++ 6 files changed, 581 insertions(+), 48 deletions(-) create mode 100644 source/lib/include/coord.h create mode 100644 source/lib/src/coord.cc create mode 100644 source/lib/tests/test_coord.cc create mode 100644 source/lib/tests/test_neighbor_list.cc diff --git a/source/lib/include/coord.h b/source/lib/include/coord.h new file mode 100644 index 0000000000..dc81efc1b2 --- /dev/null +++ b/source/lib/include/coord.h @@ -0,0 +1,35 @@ +#pragma once + +#include "region.h" + +// normalize coords +template +void +normalize_coord_cpu( + FPTYPE * coord, + const int natom, + const Region & region); + +// copy coordinates +// outputs: +// out_c, out_t, mapping, nall +// inputs: +// in_c, in_t, nloc, mem_nall, rc, region +// mem_nall is the size of allocated memory for out_c, out_t, mapping +// returns +// 0: succssful +// 1: the memory is not large enough to hold all copied coords and types. +// i.e. nall > mem_nall +template +int +copy_coord_cpu( + FPTYPE * out_c, + int * out_t, + int * mapping, + int * nall, + const FPTYPE * in_c, + const int * in_t, + const int & nloc, + const int & mem_nall, + const float & rcut, + const Region & region); diff --git a/source/lib/include/neighbor_list.h b/source/lib/include/neighbor_list.h index 29b476fb3f..44a7fc417b 100644 --- a/source/lib/include/neighbor_list.h +++ b/source/lib/include/neighbor_list.h @@ -5,6 +5,7 @@ #include #include +#include "region.h" #include "utilities.h" #include "SimulationRegion.h" @@ -31,31 +32,28 @@ void convert_nlist( ); -// template -// void -// build_nlist_nopbc( -// InputNlist & nlist, -// const FPTYPE * coord, -// const int & nloc, -// const float & rcut); +// build neighbor list. +// outputs -// template -// void -// build_nlist_pbc( -// InputNlist & nlist, -// const FPTYPE * coord, -// const Region & region, -// const int & nloc, -// const float & rcut); - -// template -// void -// build_nlist_pbc( -// InputNlist & nlist, -// const FPTYPE * coord, -// const Region & region, -// const int & nloc, -// const float & rcut); +// nlist, max_list_size +// max_list_size is the maximal size of jlist. +// inputs +// c_cpy, nloc, nall, mem_size, rcut, region +// mem_size is the size of allocated memory for jlist. +// returns +// 0: succssful +// 1: the memory is not large enough to hold all neighbors. +// i.e. max_list_size > mem_nall +template +int +build_nlist_cpu( + InputNlist & nlist, + int * max_list_size, + const FPTYPE * c_cpy, + const int & nloc, + const int & nall, + const int & mem_size, + const float & rcut); // build nlist by an extended grid diff --git a/source/lib/src/coord.cc b/source/lib/src/coord.cc new file mode 100644 index 0000000000..5066eac2a5 --- /dev/null +++ b/source/lib/src/coord.cc @@ -0,0 +1,110 @@ +#include "coord.h" +#include "neighbor_list.h" +#include "SimulationRegion.h" +#include + +// normalize coords +template +void +normalize_coord_cpu( + FPTYPE * coord, + const int natom, + const Region & region) +{ + for(int ii = 0; ii < natom; ++ii){ + FPTYPE ri[3]; + convert_to_inter_cpu(ri, region, coord+3*ii); + for(int dd = 0; dd < 3; ++dd){ + while(ri[dd] >= 1.) ri[dd] -= 1.; + while(ri[dd] < 0.) ri[dd] += 1.; + } + convert_to_phys_cpu(coord+3*ii, region, ri); + } +} + + +template +int +copy_coord_cpu( + FPTYPE * out_c, + int * out_t, + int * mapping, + int * nall, + const FPTYPE * in_c, + const int * in_t, + const int & nloc, + const int & mem_nall, + const float & rcut, + const Region & region) +{ + std::vector coord(nloc * 3); + std::vector atype(nloc); + std::copy(in_c, in_c+nloc*3, coord.begin()); + std::copy(in_t, in_t+nloc, atype.begin()); + SimulationRegion tmpr; + double tmp_boxt[9]; + std::copy(region.boxt, region.boxt+9, tmp_boxt); + tmpr.reinitBox(tmp_boxt); + + std::vector out_coord; + std::vector out_atype, out_mapping, ncell, ngcell; + copy_coord(out_coord, out_atype, out_mapping, ncell, ngcell, coord, atype, rcut, tmpr); + + *nall = out_atype.size(); + if(*nall > mem_nall){ + // size of the output arrays is not large enough + return 1; + } + else{ + std::copy(out_coord.begin(), out_coord.end(), out_c); + std::copy(out_atype.begin(), out_atype.end(), out_t); + std::copy(out_mapping.begin(), out_mapping.end(), mapping); + } + return 0; +} + + +template +void +normalize_coord_cpu( + double * coord, + const int natom, + const Region & region); + +template +void +normalize_coord_cpu( + float * coord, + const int natom, + const Region & region); + +template +int +copy_coord_cpu( + double * out_c, + int * out_t, + int * mapping, + int * nall, + const double * in_c, + const int * in_t, + const int & nloc, + const int & mem_nall, + const float & rcut, + const Region & region); + +template +int +copy_coord_cpu( + float * out_c, + int * out_t, + int * mapping, + int * nall, + const float * in_c, + const int * in_t, + const int & nloc, + const int & mem_nall, + const float & rcut, + const Region & region); + + + diff --git a/source/lib/src/neighbor_list.cc b/source/lib/src/neighbor_list.cc index 8eb7b6c142..0643037e3f 100644 --- a/source/lib/src/neighbor_list.cc +++ b/source/lib/src/neighbor_list.cc @@ -757,29 +757,69 @@ convert_nlist( } } +template +int +build_nlist_cpu( + InputNlist & nlist, + int * max_list_size, + const FPTYPE * c_cpy, + const int & nloc, + const int & nall, + const int & mem_size, + const float & rcut) +{ + *max_list_size = 0; + nlist.inum = nloc; + FPTYPE rcut2 = rcut * rcut; + std::vector jlist; + jlist.reserve(mem_size); + for(int ii = 0; ii < nlist.inum; ++ii){ + nlist.ilist[ii] = ii; + jlist.clear(); + for(int jj = 0; jj < nall; ++jj){ + if(jj == ii) continue; + FPTYPE diff[3]; + for(int dd = 0; dd < 3; ++dd){ + diff[dd] = c_cpy[ii*3+dd] - c_cpy[jj*3+dd]; + } + FPTYPE diff2 = dot3(diff, diff); + if(diff2 < rcut2){ + jlist.push_back(jj); + } + } + if(jlist.size() > mem_size){ + *max_list_size = jlist.size(); + return 1; + } + else { + int list_size = jlist.size(); + nlist.numneigh[ii] = list_size; + if(list_size > *max_list_size) *max_list_size = list_size; + std::copy(jlist.begin(), jlist.end(), nlist.firstneigh[ii]); + } + } + return 0; +} -// template -// void -// build_nlist_pbc( -// InputNlist & nlist, -// const FPTYPE * coord, -// const Region & region, -// const int & nloc, -// const float & rcut) -// { -// std::vector in_c(nloc); -// std::vector in_t(nloc, 0); -// std::copy(coord, coord + nloc * 3, in_c.begin()); -// SimulationRegion tmpr; -// double tmp_boxt[9]; -// std::copy(region.boxt, region.boxt+9, tmp_boxt); -// tmpr.reinitBox(tmp_boxt); - -// std::vector out_c; -// std::vector out_r, mapping, ncell, ngcell; - -// } - - +template +int +build_nlist_cpu( + InputNlist & nlist, + int * max_list_size, + const double * c_cpy, + const int & nloc, + const int & nall, + const int & mem_size, + const float & rcut); + +template +int +build_nlist_cpu( + InputNlist & nlist, + int * max_list_size, + const float * c_cpy, + const int & nloc, + const int & nall, + const int & mem_size, + const float & rcut); - diff --git a/source/lib/tests/test_coord.cc b/source/lib/tests/test_coord.cc new file mode 100644 index 0000000000..10df1c744d --- /dev/null +++ b/source/lib/tests/test_coord.cc @@ -0,0 +1,232 @@ +#include +#include +#include "coord.h" + +class TestNormCoord : public ::testing::Test +{ +protected: + std::vector posi = { + 1.83, 1.56, 1.18, + 1.09, 1.87, 1.74, + }; + std::vector boxt = { + 3.27785716, 0.09190842, 0.14751448, 0.02331264, 3.36482777, -0.2999871 , -0.47510999, -0.38123489, 3.33561809 + }; + // 10, 11, 12 + std::vector r0 ={ + 29.16369076, 34.91737099, 39.38270378, + 28.42369076, 35.22737099, 39.94270378 + }; + // -10, 11, -12 + std::vector r1 ={ + -24.990812680000005, 42.22883995, -43.622419980000004, + -25.730812680000003, 42.538839949999996, -43.06241998 + }; + // 10, -11, 12 + std::vector r2 ={ + 28.65081268, -39.10883995, 45.98241998, + 27.91081268, -38.79883995, 46.54241998 + }; + int natoms; + void SetUp() override { + natoms = posi.size()/3; + }; +}; + + +TEST_F(TestNormCoord, cpu_case0) +{ + Region region; + init_region_cpu(region, &boxt[0]); + std::vector out_c(r0); + normalize_coord_cpu(&out_c[0], natoms, region); + for(int ii = 0; ii < posi.size(); ++ii){ + EXPECT_LT(fabs(out_c[ii] - posi[ii]), 1e-12); + } +} + +TEST_F(TestNormCoord, cpu_case1) +{ + Region region; + init_region_cpu(region, &boxt[0]); + std::vector out_c(r1); + normalize_coord_cpu(&out_c[0], natoms, region); + for(int ii = 0; ii < posi.size(); ++ii){ + EXPECT_LT(fabs(out_c[ii] - posi[ii]), 1e-12); + } +} + +TEST_F(TestNormCoord, cpu_case2) +{ + Region region; + init_region_cpu(region, &boxt[0]); + std::vector out_c(r2); + normalize_coord_cpu(&out_c[0], natoms, region); + for(int ii = 0; ii < posi.size(); ++ii){ + EXPECT_LT(fabs(out_c[ii] - posi[ii]), 1e-12); + } +} + + +typedef std::pair,std::vector> atom; + +static void +sort_atoms( + std::vector & coord, + std::vector & atype, + std::vector & mapping, + const std::vector & icoord, + const std::vector & iatype, + const std::vector & imapping, + const int start, + const int end + ) +{ + int natoms = end - start; + std::vector atoms(natoms); + for(int ii = start; ii < end; ++ii){ + atom tmp_atom; + tmp_atom.first.resize(3); + for(int dd = 0; dd < 3; ++dd){ + tmp_atom.first[dd] = icoord[ii*3+dd]; + } + tmp_atom.second.resize(2); + tmp_atom.second[0] = iatype[ii]; + tmp_atom.second[1] = imapping[ii]; + atoms[ii-start] = tmp_atom; + } + std::sort(atoms.begin(), atoms.end()); + coord = icoord; + atype = iatype; + mapping = imapping; + for(int ii = start; ii < end; ++ii){ + for(int dd = 0; dd < 3; ++dd){ + coord[ii*3+dd] = atoms[ii-start].first[dd]; + } + atype[ii] = atoms[ii-start].second[0]; + mapping[ii] = atoms[ii-start].second[1]; + } +} + +class TestCopyCoord : public ::testing::Test +{ +protected: + std::vector posi = { + 12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector _expected_posi_cpy = { + 12.83, 2.56, 2.18, 12.09, 2.87, 2.74, 0.25, 3.32, 1.68, 3.36, 3.00, 1.81, 3.51, 2.51, 2.60, 4.27, 3.22, 1.56, -0.17, 2.56, 2.18, -0.91, 2.87, 2.74, -0.17, 2.56, 15.18, -0.91, 2.87, 15.74, -0.17, 15.56, 2.18, -0.91, 15.87, 2.74, -0.17, 15.56, 15.18, -0.91, 15.87, 15.74, 0.25, 3.32, 14.68, 3.36, 3.00, 14.81, 3.51, 2.51, 15.60, 4.27, 3.22, 14.56, 0.25, 16.32, 1.68, 3.36, 16.00, 1.81, 3.51, 15.51, 2.60, 4.27, 16.22, 1.56, 0.25, 16.32, 14.68, 3.36, 16.00, 14.81, 3.51, 15.51, 15.60, 4.27, 16.22, 14.56, 12.83, 2.56, 15.18, 12.09, 2.87, 15.74, 12.83, 15.56, 2.18, 12.09, 15.87, 2.74, 12.83, 15.56, 15.18, 12.09, 15.87, 15.74, 13.25, 3.32, 1.68, 16.36, 3.00, 1.81, 16.51, 2.51, 2.60, 17.27, 3.22, 1.56, 13.25, 3.32, 14.68, 16.36, 3.00, 14.81, 16.51, 2.51, 15.60, 17.27, 3.22, 14.56, 13.25, 16.32, 1.68, 16.36, 16.00, 1.81, 16.51, 15.51, 2.60, 17.27, 16.22, 1.56, 13.25, 16.32, 14.68, 16.36, 16.00, 14.81, 16.51, 15.51, 15.60, 17.27, 16.22, 14.56, + }; + std::vector expected_posi_cpy; + std::vector _expected_atype_cpy = { + 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, + }; + std::vector expected_atype_cpy; + std::vector _expected_mapping = { + 0, 1, 2, 3, 4, 5, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 4, 5, 0, 1, 0, 1, 0, 1, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 4, 5, + }; + std::vector expected_mapping; + int ntypes = 2; + int nloc, expected_nall; + double rc = 6; + std::vector boxt = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + std::vector ncell, ngcell; + + void SetUp() override { + nloc = posi.size() / 3; + expected_nall = _expected_posi_cpy.size() / 3; + EXPECT_EQ(expected_nall, _expected_atype_cpy.size()); + EXPECT_EQ(expected_nall, _expected_mapping.size()); + // sort the atoms between nloc and nall, to remove the uncertainty of the ordering + sort_atoms( + expected_posi_cpy, + expected_atype_cpy, + expected_mapping, + _expected_posi_cpy, + _expected_atype_cpy, + _expected_mapping, + nloc, + expected_nall); + } +}; + + + + +TEST_F(TestCopyCoord, cpu) +{ + int mem_size = 1000; + std::vector out_c(mem_size * 3); + std::vector out_t(mem_size); + std::vector mapping(mem_size); + int nall; + Region region; + init_region_cpu(region, &boxt[0]); + + int ret = copy_coord_cpu( + &out_c[0], + &out_t[0], + &mapping[0], + &nall, + &posi[0], + &atype[0], + nloc, + mem_size, + rc, + region); + EXPECT_EQ(ret, 0); + EXPECT_EQ(nall, expected_nall); + // std::cout << "---------------------" + // << nloc << " " + // << nall << std::endl; + + out_c.resize(nall*3); + out_t.resize(nall); + mapping.resize(nall); + + std::vector out_c_1(mem_size * 3); + std::vector out_t_1(mem_size); + std::vector mapping_1(mem_size); + sort_atoms(out_c_1, out_t_1, mapping_1, out_c, out_t, mapping, nloc, nall); + for(int ii = 0; ii < expected_nall; ++ii){ + for(int dd = 0; dd < 3; ++dd){ + EXPECT_LT(fabs(out_c_1[ii*3+dd] - expected_posi_cpy[ii*3+dd]), 1e-12); + } + EXPECT_EQ(out_t_1[ii], expected_atype_cpy[ii]); + EXPECT_EQ(mapping_1[ii], expected_mapping[ii]); + } +} + +TEST_F(TestCopyCoord, cpu_lessmem) +{ + int mem_size = 40; + std::vector out_c(mem_size * 3); + std::vector out_t(mem_size); + std::vector mapping(mem_size); + int nall; + Region region; + init_region_cpu(region, &boxt[0]); + + int ret = copy_coord_cpu( + &out_c[0], + &out_t[0], + &mapping[0], + &nall, + &posi[0], + &atype[0], + nloc, + mem_size, + rc, + region); + EXPECT_EQ(ret, 1); + // EXPECT_EQ(nall, expected_nall); + // std::cout << "---------------------" + // << nloc << " " + // << nall << std::endl; +} diff --git a/source/lib/tests/test_neighbor_list.cc b/source/lib/tests/test_neighbor_list.cc new file mode 100644 index 0000000000..a0962cecbf --- /dev/null +++ b/source/lib/tests/test_neighbor_list.cc @@ -0,0 +1,118 @@ +#include +#include "fmt_nlist.h" +#include "neighbor_list.h" + +class TestNeighborList : public ::testing::Test +{ +protected: + std::vector posi = { + 12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = {0, 1, 1, 0, 1, 1}; + std::vector posi_cpy; + std::vector atype_cpy; + int ntypes = 2; + int nloc, nall; + double rc = 6; + std::vector boxt = {13., 0., 0., 0., 13., 0., 0., 0., 13.}; + std::vector mapping, ncell, ngcell; + std::vector> expect_nlist_cpy = { + std::vector({33, 1 , 32, 34, 35,}), + std::vector({0 , 33, 32, 34, 35,}), + std::vector({6 , 3 , 7 , 4 , 5 ,}), + std::vector({6 , 4 , 5 , 2 , 7 ,}), + std::vector({3 , 6 , 5 , 2 , 7 ,}), + std::vector({3 , 6 , 4 , 2 , 7 ,}), + }; + + void SetUp() override { + SimulationRegion region; + region.reinitBox(&boxt[0]); + copy_coord(posi_cpy, atype_cpy, mapping, ncell, ngcell, posi, atype, rc, region); + nloc = posi.size() / 3; + nall = posi_cpy.size() / 3; + EXPECT_EQ(expect_nlist_cpy.size(), nloc); + for(int ii = 0; ii < nloc; ++ii){ + std::sort(expect_nlist_cpy[ii].begin(), expect_nlist_cpy[ii].end()); + } + } +}; + + +TEST_F(TestNeighborList, cpu) +{ + int mem_size = 10; + int * ilist = new int[nloc]; + int * numneigh = new int[nloc]; + int ** firstneigh = new int*[nloc]; + for(int ii = 0; ii < nloc; ++ii){ + firstneigh[ii] = new int[mem_size]; + } + + InputNlist nlist(nloc, ilist, numneigh, firstneigh); + int max_list_size; + int ret = build_nlist_cpu( + nlist, + &max_list_size, + &posi_cpy[0], + nloc, + nall, + mem_size, + rc); + EXPECT_EQ(ret, 0); + EXPECT_EQ(nlist.inum, nloc); + EXPECT_EQ(max_list_size, 5); + for(int ii = 0; ii < nloc; ++ii){ + EXPECT_EQ(nlist.ilist[ii], ii); + EXPECT_EQ(nlist.numneigh[ii], expect_nlist_cpy[ii].size()); + std::sort(nlist.firstneigh[ii], nlist.firstneigh[ii] + nlist.numneigh[ii]); + for(int jj = 0; jj < nlist.numneigh[ii]; ++jj){ + EXPECT_EQ(nlist.firstneigh[ii][jj], expect_nlist_cpy[ii][jj]); + } + } + + delete[] ilist; + delete[] numneigh; + for(int ii = 0; ii < nloc; ++ii){ + delete[] firstneigh[ii]; + } + delete[] firstneigh; +} + +TEST_F(TestNeighborList, cpu_lessmem) +{ + int mem_size = 2; + int * ilist = new int[nloc]; + int * numneigh = new int[nloc]; + int ** firstneigh = new int*[nloc]; + for(int ii = 0; ii < nloc; ++ii){ + firstneigh[ii] = new int[mem_size]; + } + + InputNlist nlist(nloc, ilist, numneigh, firstneigh); + int max_list_size; + int ret = build_nlist_cpu( + nlist, + &max_list_size, + &posi_cpy[0], + nloc, + nall, + mem_size, + rc); + EXPECT_EQ(ret, 1); + EXPECT_EQ(nlist.inum, nloc); + EXPECT_EQ(max_list_size, 5); + + delete[] ilist; + delete[] numneigh; + for(int ii = 0; ii < nloc; ++ii){ + delete[] firstneigh[ii]; + } + delete[] firstneigh; +} + From 4ba44fd2187a30f0d136448a0a041bd7eeac6ace Mon Sep 17 00:00:00 2001 From: Han Wang Date: Thu, 4 Mar 2021 20:10:52 +0800 Subject: [PATCH 232/562] change python test OS to ubuntu-18.04 --- .github/workflows/test_python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index 469dcd869b..dadd749b36 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -5,7 +5,7 @@ name: Test Python jobs: testpython: name: Test Python - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 strategy: matrix: include: From bbab355e720a43c31ac1d11c38832c3595c496e1 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Thu, 4 Mar 2021 20:17:22 +0800 Subject: [PATCH 233/562] add missing header file --- source/lib/tests/test_coord.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/source/lib/tests/test_coord.cc b/source/lib/tests/test_coord.cc index 10df1c744d..111b66bb06 100644 --- a/source/lib/tests/test_coord.cc +++ b/source/lib/tests/test_coord.cc @@ -1,5 +1,6 @@ #include #include +#include #include "coord.h" class TestNormCoord : public ::testing::Test From 004683c5c945cbab335b988a14c2d2299a70e02b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Rynik?= Date: Thu, 4 Mar 2021 14:25:48 +0100 Subject: [PATCH 234/562] small fixes to parser --- source/train/main.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/train/main.py b/source/train/main.py index 062cca86e8..bf88a9a1e6 100644 --- a/source/train/main.py +++ b/source/train/main.py @@ -64,7 +64,7 @@ def parse_args(args: Optional[List[str]] = None): parser_log.add_argument( "-v", "--log-level", - choices=["DEBUG", 3, "INFO", 2, "WARNING", 1, "ERROR", 0], + choices=["DEBUG", "3", "INFO", "2", "WARNING", "1", "ERROR", "0"], default="INFO", help="set verbosity level by string or number, 0=ERROR, 1=WARNING, 2=INFO " "and 3=DEBUG", @@ -227,12 +227,14 @@ def parse_args(args: Optional[List[str]] = None): "-d", "--detail-file", type=str, + default=None, help="File where details of energy force and virial accuracy will be written", ) parser_tst.add_argument( "-a", "--atomic-energy", action="store_true", + default=False, help="Test the accuracy of atomic energy", ) From cb201152b9c774f647c9bf7141ce20a21fe94571 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Fri, 5 Mar 2021 01:24:28 +0800 Subject: [PATCH 235/562] add unit test for custom ops --- source/lib/include/gelu.h | 12 +- source/lib/src/cuda/CMakeLists.txt | 28 +- source/lib/src/cuda/gpu_nv.cu | 44 --- source/lib/src/cuda/gpu_nv.cuh | 266 --------------- source/lib/src/cuda/prod_env_mat.cu | 37 +-- source/lib/src/cuda/prod_force.cu | 2 +- source/lib/src/cuda/prod_virial.cu | 2 +- source/lib/src/cuda/tabulate.cu | 6 +- source/lib/tests/test_env_mat_a.cc | 4 +- source/lib/tests/test_env_mat_r.cc | 356 +++++++++++++++++++++ source/lib/tests/test_gelu.cc | 214 +++++++++++++ source/lib/tests/test_prod_force_a.cc | 31 ++ source/lib/tests/test_prod_force_r.cc | 31 ++ source/lib/tests/test_prod_virial_a.cc | 49 +++ source/lib/tests/test_prod_virial_r.cc | 49 +++ source/lib/tests/test_tabulate.cc | 234 ++++++++++++++ source/op/prod_virial_se_r_multi_device.cc | 114 ------- 17 files changed, 1021 insertions(+), 458 deletions(-) delete mode 100644 source/lib/src/cuda/gpu_nv.cu delete mode 100644 source/lib/src/cuda/gpu_nv.cuh create mode 100644 source/lib/tests/test_gelu.cc create mode 100644 source/lib/tests/test_tabulate.cc delete mode 100644 source/op/prod_virial_se_r_multi_device.cc diff --git a/source/lib/include/gelu.h b/source/lib/include/gelu.h index 5e5baffb5c..edf1729c4f 100644 --- a/source/lib/include/gelu.h +++ b/source/lib/include/gelu.h @@ -3,20 +3,20 @@ template void gelu_cpu( FPTYPE * out, - const FPTYPE * x, + const FPTYPE * xx, const int size); template void gelu_grad_cpu( FPTYPE * out, - const FPTYPE * x, + const FPTYPE * xx, const FPTYPE * dy, const int size); template void gelu_grad_grad_cpu( FPTYPE * out, - const FPTYPE * x, + const FPTYPE * xx, const FPTYPE * dy, const FPTYPE * dy_2, const int size); @@ -25,20 +25,20 @@ void gelu_grad_grad_cpu( template void gelu_gpu_cuda( FPTYPE * out, - const FPTYPE * x, + const FPTYPE * xx, const int size); template void gelu_grad_gpu_cuda( FPTYPE * out, - const FPTYPE * x, + const FPTYPE * xx, const FPTYPE * dy, const int size); template void gelu_grad_grad_gpu_cuda( FPTYPE * out, - const FPTYPE * x, + const FPTYPE * xx, const FPTYPE * dy, const FPTYPE * dy_2, const int size); diff --git a/source/lib/src/cuda/CMakeLists.txt b/source/lib/src/cuda/CMakeLists.txt index 953e8d9ea3..da21899dcf 100644 --- a/source/lib/src/cuda/CMakeLists.txt +++ b/source/lib/src/cuda/CMakeLists.txt @@ -19,7 +19,30 @@ include_directories(cub) message(STATUS "CUDA major version is " ${CUDA_VERSION_MAJOR}) -if (${CUDA_VERSION_MAJOR} GREATER "10") +if (${CUDA_VERSION_MAJOR} GREATER "11") + # nvcc flags + set(CUDA_NVCC_FLAGS -gencode arch=compute_60,code=sm_60; # Pascal – GP100/Tesla P100 – DGX-1 (Generic Pascal) + -gencode arch=compute_61,code=sm_61; # Pascal - GTX 1080, GTX 1070, GTX 1060, GTX 1050, GTX 1030, Titan Xp, Tesla P40, Tesla P4, Discrete GPU on the NVIDIA Drive PX2 + -gencode arch=compute_70,code=sm_70; # Volta - GV100/Tesla V100, GTX 1180 (GV104) + -gencode arch=compute_75,code=sm_75; # Turing - RTX 2080, Titan RTX, Quadro R8000 + -gencode arch=compute_80,code=sm_80; # Anpere - A100 + -gencode arch=compute_86,code=sm_86; # Anpere - RTX 3090 + -O3; -Xcompiler -fPIC; + ) +elseif (${CUDA_VERSION_MAJOR} STREQUAL "11" AND ${CUDA_VERSION_MINOR} GREATER "0") + # nvcc flags + set(CUDA_NVCC_FLAGS -gencode arch=compute_50,code=sm_50; + -gencode arch=compute_52,code=sm_52; # Tesla M40, Tesla M40, Quadro M6000... + -gencode arch=compute_53,code=sm_53; + -gencode arch=compute_60,code=sm_60; # Pascal – GP100/Tesla P100 – DGX-1 (Generic Pascal) + -gencode arch=compute_61,code=sm_61; # Pascal - GTX 1080, GTX 1070, GTX 1060, GTX 1050, GTX 1030, Titan Xp, Tesla P40, Tesla P4, Discrete GPU on the NVIDIA Drive PX2 + -gencode arch=compute_70,code=sm_70; # Volta - GV100/Tesla V100, GTX 1180 (GV104) + -gencode arch=compute_75,code=sm_75; # Turing - RTX 2080, Titan RTX, Quadro R8000 + -gencode arch=compute_80,code=sm_80; # Anpere - A100 + -gencode arch=compute_86,code=sm_86; # Anpere - RTX 3090 + -O3; -Xcompiler -fPIC; + ) +elseif (${CUDA_VERSION_MAJOR} STREQUAL "11" AND ${CUDA_VERSION_MINOR} STREQUAL "0") # nvcc flags set(CUDA_NVCC_FLAGS -gencode arch=compute_50,code=sm_50; -gencode arch=compute_52,code=sm_52; # Tesla M40, Tesla M40, Quadro M6000... @@ -28,8 +51,7 @@ if (${CUDA_VERSION_MAJOR} GREATER "10") -gencode arch=compute_61,code=sm_61; # Pascal - GTX 1080, GTX 1070, GTX 1060, GTX 1050, GTX 1030, Titan Xp, Tesla P40, Tesla P4, Discrete GPU on the NVIDIA Drive PX2 -gencode arch=compute_70,code=sm_70; # Volta - GV100/Tesla V100, GTX 1180 (GV104) -gencode arch=compute_75,code=sm_75; # Turing - RTX 2080, Titan RTX, Quadro R8000 - -gencode arch=compute_80,code=sm_80; # Ampere - A100 - -gencode arch=compute_86,code=sm_86; # Ampere - RTX 3090 + -gencode arch=compute_80,code=sm_80; # Anpere - A100 -O3; -Xcompiler -fPIC; ) elseif (${CUDA_VERSION_MAJOR} STREQUAL "10") diff --git a/source/lib/src/cuda/gpu_nv.cu b/source/lib/src/cuda/gpu_nv.cu deleted file mode 100644 index 11bb1a5357..0000000000 --- a/source/lib/src/cuda/gpu_nv.cu +++ /dev/null @@ -1,44 +0,0 @@ -#include "gpu_nv.h" -#include "device.h" -#include -#include -#include - -// common part of prod_env_mat -template < - typename Key, - int BLOCK_THREADS, - int ITEMS_PER_THREAD> -__launch_bounds__ (BLOCK_THREADS) -__global__ void BlockSortKernel( - Key * d_in, - Key * d_out) // Tile of output -{ - enum { TILE_SIZE = BLOCK_THREADS * ITEMS_PER_THREAD }; - // Specialize BlockLoad type for our thread block (uses warp-striped loads for coalescing, then transposes in shared memory to a blocked arrangement) - typedef cub::BlockLoad BlockLoadT; - // Specialize BlockRadixSort type for our thread block - typedef cub::BlockRadixSort BlockRadixSortT; - // Shared memory - __shared__ union TempStorage - { - typename BlockLoadT::TempStorage load; - typename BlockRadixSortT::TempStorage sort; - } temp_storage; - // Per-thread tile items - Key items[ITEMS_PER_THREAD]; - // Our current block's offset - int block_offset = blockIdx.x * TILE_SIZE; - // Load items into a blocked arrangement - BlockLoadT(temp_storage.load).Load(d_in + block_offset, items); - // Barrier for smem reuse - __syncthreads(); - // Sort keys - BlockRadixSortT(temp_storage.sort).SortBlockedToStriped(items); - // Store output in striped fashion - cub::StoreDirectStriped(threadIdx.x, d_out + block_offset, items); -} - -template __global__ void BlockSortKernel(int_64 * d_in, int_64 * d_out); -template __global__ void BlockSortKernel(int_64 * d_in, int_64 * d_out); -template __global__ void BlockSortKernel(int_64 * d_in, int_64 * d_out); diff --git a/source/lib/src/cuda/gpu_nv.cuh b/source/lib/src/cuda/gpu_nv.cuh deleted file mode 100644 index f0d19b86a4..0000000000 --- a/source/lib/src/cuda/gpu_nv.cuh +++ /dev/null @@ -1,266 +0,0 @@ -#pragma once -#include "gpu_nv.h" - -// common part of prod_env_mat -template < - typename Key, - int BLOCK_THREADS, - int ITEMS_PER_THREAD> -__launch_bounds__ (BLOCK_THREADS) -__global__ void BlockSortKernel( - Key * d_in, - Key * d_out); - -template -__device__ inline FPTYPE dev_dot( - FPTYPE * arr1, - FPTYPE * arr2) -{ - return arr1[0] * arr2[0] + arr1[1] * arr2[1] + arr1[2] * arr2[2]; -} - -template -__device__ inline void spline5_switch( - FPTYPE & vv, - FPTYPE & dd, - FPTYPE & xx, - const float & rmin, - const float & rmax) -{ - if (xx < rmin) { - dd = 0; - vv = 1; - } - else if (xx < rmax) { - FPTYPE uu = (xx - rmin) / (rmax - rmin) ; - FPTYPE du = 1. / (rmax - rmin) ; - vv = uu*uu*uu * (-6 * uu*uu + 15 * uu - 10) + 1; - dd = ( 3 * uu*uu * (-6 * uu*uu + 15 * uu - 10) + uu*uu*uu * (-12 * uu + 15) ) * du; - } - else { - dd = 0; - vv = 0; - } -} - -template -__global__ void get_i_idx( - FPTYPE * i_idx, - const int nloc, - const FPTYPE * ilist) -{ - const unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x; - if(idx >= nloc) { - return; - } - i_idx[ilist[idx]] = idx; -} - -template -__global__ void format_nlist_fill_a( - int_64 * key, - const FPTYPE * coord, - const int * type, - const int * jrange, - const int * jlist, - const float rcut, - int * i_idx, - const int MAX_NBOR_SIZE) -{ - // <<>> - const unsigned int idx = blockIdx.x; - const unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y; - - const int nsize = jrange[i_idx[idx] + 1] - jrange[i_idx[idx]]; - if (idy >= nsize) { - return; - } - const int * nei_idx = jlist + jrange[i_idx[idx]]; - // dev_copy(nei_idx, &jlist[jrange[i_idx]], nsize); - int_64 * key_in = key + idx * MAX_NBOR_SIZE; - FPTYPE diff[3]; - const int & j_idx = nei_idx[idy]; - for (int dd = 0; dd < 3; dd++) { - diff[dd] = coord[j_idx * 3 + dd] - coord[idx * 3 + dd]; - } - FPTYPE rr = sqrt(dev_dot(diff, diff)); - if (rr <= rcut) { - key_in[idy] = type[j_idx] * 1E15+ (int_64)(rr * 1.0E13) / 100000 * 100000 + j_idx; - } -} - -template -__global__ void format_nlist_fill_b( - int * nlist, - const int nlist_size, - const int nloc, - const int * jrange, - const int * jlist, - FPTYPE * key, - const int * sec, - const int sec_size, - int * nei_iter_dev, - const int max_nbor_size) -{ - const unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x; - if(idx >= nloc) { - return; - } - - int * row_nlist = nlist + idx * nlist_size; - int * nei_iter = nei_iter_dev + idx * sec_size; - FPTYPE * key_out = key + nloc * max_nbor_size + idx * max_nbor_size; - for (int ii = 0; ii < sec_size; ii++) { - nei_iter[ii] = sec[ii]; - } - - for (unsigned int kk = 0; key_out[kk] != key_out[max_nbor_size - 1]; kk++) { - const int & nei_type = key_out[kk] / 1E15; - if (nei_iter[nei_type] < sec[nei_type + 1]) { - row_nlist[nei_iter[nei_type]++] = key_out[kk] % 100000; - } - } -} - -template -void format_nbor_list_1024 ( - int_64 * key, - const FPTYPE* coord, - const int* type, - const int* jrange, - const int* jlist, - const int& nloc, - const float& rcut, - int * i_idx) -{ - const int LEN = 256; - const int MAX_NBOR_SIZE = 1024; - const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; - dim3 block_grid(nloc, nblock); - dim3 thread_grid(1, LEN); - format_nlist_fill_a<<>> ( - key, - coord, type, jrange, jlist, rcut, i_idx, MAX_NBOR_SIZE); - const int ITEMS_PER_THREAD = 8; - const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; - // BlockSortKernel<<>> ( - BlockSortKernel <<>> ( - key, - key + nloc * MAX_NBOR_SIZE); -} - -template -void format_nbor_list_2048 ( - int_64 * key, - const FPTYPE* coord, - const int* type, - const int* jrange, - const int* jlist, - const int& nloc, - const float& rcut, - int * i_idx) -{ - const int LEN = 256; - const int MAX_NBOR_SIZE = 2048; - const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; - dim3 block_grid(nloc, nblock); - dim3 thread_grid(1, LEN); - format_nlist_fill_a<<>> ( - key, - coord, type, jrange, jlist, rcut, i_idx, MAX_NBOR_SIZE); - const int ITEMS_PER_THREAD = 8; - const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; - // BlockSortKernel<<>> ( - BlockSortKernel <<>> ( - key, - key + nloc * MAX_NBOR_SIZE); -} - -template -void format_nbor_list_4096 ( - int_64 * key, - const FPTYPE* coord, - const int* type, - const int* jrange, - const int* jlist, - const int& nloc, - const float& rcut, - int * i_idx) -{ - const int LEN = 256; - const int MAX_NBOR_SIZE = 4096; - const int nblock = (MAX_NBOR_SIZE + LEN - 1) / LEN; - dim3 block_grid(nloc, nblock); - dim3 thread_grid(1, LEN); - format_nlist_fill_a<<>> ( - key, - coord, type, jrange, jlist, rcut, i_idx, MAX_NBOR_SIZE); - const int ITEMS_PER_THREAD = 16; - const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; - // BlockSortKernel<<>> ( - BlockSortKernel <<>> ( - key, - key + nloc * MAX_NBOR_SIZE); -} - -template -void prod_env_mat_common( - FPTYPE * em, - FPTYPE * em_deriv, - FPTYPE * rij, - int * nlist, - const FPTYPE * coord, - const int * type, - const int * ilist, - const int * jrange, - const int * jlist, - int * array_int, - int_64 * array_longlong, - const int max_nbor_size, - const FPTYPE * avg, - const FPTYPE * std, - const int nloc, - const int nall, - const float rcut, - const float rcut_smth, - const std::vector sec) -{ - const int LEN = 256; - const int nnei = sec.back(); - const int ndescrpt = nnei * 4; - int nblock = (nloc + LEN -1) / LEN; - int * sec_dev = array_int; - int * nei_iter = array_int + sec.size(); // = new int[sec_size]; - int * i_idx = array_int + sec.size() + nloc * sec.size(); - int_64 * key = array_longlong; - assert(max_nbor_size == 1024 || max_nbor_size == 2048 || max_nbor_size == 4096); - cudaErrcheck(cudaMemcpy(sec_dev, &sec[0], sizeof(int) * sec.size(), cudaMemcpyHostToDevice)); - cudaErrcheck(cudaMemset(key, 0xffffffff, sizeof(int_64) * nloc * max_nbor_size)); - cudaErrcheck(cudaMemset(nlist, -1, sizeof(int) * nloc * nnei)); - cudaErrcheck(cudaMemset(em, 0.0, sizeof(FPTYPE) * nloc * ndescrpt)); - cudaErrcheck(cudaMemset(em_deriv, 0.0, sizeof(FPTYPE) * nloc * ndescrpt * 3)); - - get_i_idx<<>>( - i_idx, - nloc, ilist); - - if (max_nbor_size == 1024) { - format_nbor_list_1024 ( - key, - coord, type, jrange, jlist, nloc, rcut, i_idx); - } - else if (max_nbor_size == 2048) { - format_nbor_list_2048 ( - key, - coord, type, jrange, jlist, nloc, rcut, i_idx); - } - else if (max_nbor_size == 4096) { - format_nbor_list_4096 ( - key, - coord, type, jrange, jlist, nloc, rcut, i_idx); - } - - format_nlist_fill_b<<>> ( - nlist, - nnei, nloc, jrange, jlist, key, sec_dev, sec.size(), nei_iter, max_nbor_size); -} \ No newline at end of file diff --git a/source/lib/src/cuda/prod_env_mat.cu b/source/lib/src/cuda/prod_env_mat.cu index 4925e12ff3..0205a92d0a 100644 --- a/source/lib/src/cuda/prod_env_mat.cu +++ b/source/lib/src/cuda/prod_env_mat.cu @@ -233,9 +233,6 @@ void format_nbor_list_4096 ( template void format_nbor_list( - FPTYPE * em, - FPTYPE * em_deriv, - FPTYPE * rij, int * nlist, const FPTYPE * coord, const int * type, @@ -245,28 +242,22 @@ void format_nbor_list( int * array_int, int_64 * array_longlong, const int max_nbor_size, - const FPTYPE * avg, - const FPTYPE * std, const int nloc, const int nall, const float rcut, - const float rcut_smth, const std::vector sec) { const int LEN = 256; const int nnei = sec.back(); - const int ndescrpt = nnei * 4; - int nblock = (nloc + LEN -1) / LEN; + const int nblock = (nloc + LEN -1) / LEN; int * sec_dev = array_int; int * nei_iter = array_int + sec.size(); // = new int[sec_size]; int * i_idx = array_int + sec.size() + nloc * sec.size(); int_64 * key = array_longlong; assert(max_nbor_size == 1024 || max_nbor_size == 2048 || max_nbor_size == 4096); - cudaErrcheck(cudaMemcpy(sec_dev, &sec[0], sizeof(int) * sec.size(), cudaMemcpyHostToDevice)); - cudaErrcheck(cudaMemset(key, 0xffffffff, sizeof(int_64) * nloc * max_nbor_size)); cudaErrcheck(cudaMemset(nlist, -1, sizeof(int) * nloc * nnei)); - cudaErrcheck(cudaMemset(em, 0.0, sizeof(FPTYPE) * nloc * ndescrpt)); - cudaErrcheck(cudaMemset(em_deriv, 0.0, sizeof(FPTYPE) * nloc * ndescrpt * 3)); + cudaErrcheck(cudaMemset(key, 0xffffffff, sizeof(int_64) * nloc * max_nbor_size)); + cudaErrcheck(cudaMemcpy(sec_dev, &sec[0], sizeof(int) * sec.size(), cudaMemcpyHostToDevice)); get_i_idx<<>>( i_idx, @@ -468,13 +459,18 @@ void prod_env_mat_a_gpu_cuda( const float rcut_smth, const std::vector sec) { + const int nnei = sec.back(); + const int ndescrpt = nnei * 4; + cudaErrcheck(cudaMemset(em, 0.0, sizeof(FPTYPE) * nloc * ndescrpt)); + cudaErrcheck(cudaMemset(em_deriv, 0.0, sizeof(FPTYPE) * nloc * ndescrpt * 3)); + format_nbor_list( - em, em_deriv, rij, nlist, - coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); + nlist, + coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, nloc, nall, rcut, sec); compute_env_mat_a <<>> ( em, em_deriv, rij, - coord, avg, std, type, nlist, sec.back(), rcut_smth, rcut); + coord, avg, std, type, nlist, nnei, rcut_smth, rcut); } template @@ -499,13 +495,18 @@ void prod_env_mat_r_gpu_cuda( const float rcut_smth, const std::vector sec) { + const int nnei = sec.back(); + const int ndescrpt = nnei * 1; + cudaErrcheck(cudaMemset(em, 0.0, sizeof(FPTYPE) * nloc * ndescrpt)); + cudaErrcheck(cudaMemset(em_deriv, 0.0, sizeof(FPTYPE) * nloc * ndescrpt * 3)); + format_nbor_list( - em, em_deriv, rij, nlist, - coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); + nlist, + coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, nloc, nall, rcut, sec); compute_env_mat_r <<>> ( em, em_deriv, rij, - coord, avg, std, type, nlist, sec.back(), rcut_smth, rcut); + coord, avg, std, type, nlist, nnei, rcut_smth, rcut); } template void prod_env_mat_a_gpu_cuda(float * em, float * em_deriv, float * rij, int * nlist, const float * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const float * avg, const float * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); diff --git a/source/lib/src/cuda/prod_force.cu b/source/lib/src/cuda/prod_force.cu index 2f6e5f8479..d440d3b153 100644 --- a/source/lib/src/cuda/prod_force.cu +++ b/source/lib/src/cuda/prod_force.cu @@ -162,7 +162,7 @@ void prod_force_r_gpu_cuda( const int LEN = 64; const int nblock = (nloc + LEN -1) / LEN; dim3 block_grid(nblock, nnei); - dim3 thread_grid(LEN, 3, 4); + dim3 thread_grid(LEN, 3); force_deriv_wrt_neighbors_r<<>>( force, net_deriv, in_deriv, nlist, nloc, nnei); diff --git a/source/lib/src/cuda/prod_virial.cu b/source/lib/src/cuda/prod_virial.cu index 95d912e737..19fb6c1b2f 100644 --- a/source/lib/src/cuda/prod_virial.cu +++ b/source/lib/src/cuda/prod_virial.cu @@ -141,7 +141,7 @@ void prod_virial_r_gpu_cuda( const int LEN = 16; int nblock = (nloc + LEN -1) / LEN; dim3 block_grid(nblock, nnei); - dim3 thread_grid(LEN, 9, 4); + dim3 thread_grid(LEN, 9); // compute virial of a frame virial_deriv_wrt_neighbors_r<<>>( virial, atom_virial, diff --git a/source/lib/src/cuda/tabulate.cu b/source/lib/src/cuda/tabulate.cu index f8bdbd45ac..83803733ff 100644 --- a/source/lib/src/cuda/tabulate.cu +++ b/source/lib/src/cuda/tabulate.cu @@ -117,7 +117,7 @@ template < typename FPTYPE, int MTILE, int KTILE> -__global__ void tabulate_fusion__grad_fifth_order_polynomial( +__global__ void tabulate_fusion_grad_fifth_order_polynomial( FPTYPE * dy_dem_x, FPTYPE * dy_dem, const FPTYPE * table, @@ -151,7 +151,7 @@ __global__ void tabulate_fusion__grad_fifth_order_polynomial( FPTYPE xx = em_x[block_idx * nnei + ii + warp_idx]; if (ago == xx) { unloop = true; - breakpoint = ii; + breakpoint = ii + warp_idx; } int table_idx = 0; @@ -229,7 +229,7 @@ void tabulate_fusion_grad_gpu_cuda( dy_dem, 0.0, sizeof(FPTYPE) * nloc * nnei * 4)); - tabulate_fusion__grad_fifth_order_polynomial <<>>( + tabulate_fusion_grad_fifth_order_polynomial <<>>( dy_dem_x, dy_dem, table, em_x, em, dy, table_info[0], table_info[1], table_info[2], table_info[3], table_info[4], nnei, last_layer_size); } diff --git a/source/lib/tests/test_env_mat_a.cc b/source/lib/tests/test_env_mat_a.cc index ffdfb73eba..d3b274d300 100644 --- a/source/lib/tests/test_env_mat_a.cc +++ b/source/lib/tests/test_env_mat_a.cc @@ -527,7 +527,7 @@ TEST_F(TestEnvMatA, prod_cpu_equal_cpu) #if GOOGLE_CUDA -TEST_F(TestEnvMatA, prod_gpu_nv) +TEST_F(TestEnvMatA, prod_gpu_cuda) { EXPECT_EQ(nlist_r_cpy.size(), nloc); int tot_nnei = 0; @@ -628,7 +628,7 @@ TEST_F(TestEnvMatA, prod_gpu_nv) } -TEST_F(TestEnvMatA, prod_gpu_nv_equal_cpu) +TEST_F(TestEnvMatA, prod_gpu_cuda_equal_cpu) { EXPECT_EQ(nlist_r_cpy.size(), nloc); int tot_nnei = 0; diff --git a/source/lib/tests/test_env_mat_r.cc b/source/lib/tests/test_env_mat_r.cc index 9f8e5c62bc..99fde7e890 100644 --- a/source/lib/tests/test_env_mat_r.cc +++ b/source/lib/tests/test_env_mat_r.cc @@ -3,6 +3,7 @@ #include "fmt_nlist.h" #include "env_mat.h" #include "neighbor_list.h" +#include "prod_env_mat.h" class TestEnvMatR : public ::testing::Test { @@ -28,6 +29,8 @@ class TestEnvMatR : public ::testing::Test std::vector nat_stt, ext_stt, ext_end; std::vector> nlist_a, nlist_r; std::vector> nlist_a_cpy, nlist_r_cpy; + int nnei = sec_a.back(); + int ndescrpt = nnei * 1; std::vector expected_env = { 0.12206, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.02167, 0.99745, 0.10564, 0.03103, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.02167, 0.04135, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.59220, 0.03694, 0.00336, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, @@ -234,3 +237,356 @@ TEST_F(TestEnvMatR, cpu_num_deriv) // printf("\n"); } } + +TEST_F(TestEnvMatR, prod_cpu) +{ + EXPECT_EQ(nlist_r_cpy.size(), nloc); + int tot_nnei = 0; + int max_nbor_size = 0; + for(int ii = 0; ii < nlist_a_cpy.size(); ++ii){ + tot_nnei += nlist_a_cpy[ii].size(); + if (nlist_a_cpy[ii].size() > max_nbor_size){ + max_nbor_size = nlist_a_cpy[ii].size(); + } + } + std::vector ilist(nloc), jlist(tot_nnei), jrange(nloc+1, 0); + for (int ii = 0; ii < nloc; ++ii){ + ilist[ii] = ii; + jrange[ii+1] = jrange[ii] + nlist_a_cpy[ii].size(); + int jj, cc; + for (jj = jrange[ii], cc = 0; jj < jrange[ii+1]; ++jj, ++cc){ + jlist[jj] = nlist_a_cpy[ii][cc]; + } + } + std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); + std::vector nlist(nloc * nnei); + std::vector avg(ntypes * ndescrpt, 0); + std::vector std(ntypes * ndescrpt, 1); + prod_env_mat_r_cpu( + &em[0], + &em_deriv[0], + &rij[0], + &nlist[0], + &posi_cpy[0], + &atype_cpy[0], + &ilist[0], + &jrange[0], + &jlist[0], + max_nbor_size, + &avg[0], + &std[0], + nloc, + nall, + ntypes, + rc, + rc_smth, + sec_a); + + for(int ii = 0; ii < nloc; ++ii){ + for (int jj = 0; jj < nnei; ++jj){ + for (int dd = 0; dd < 1; ++dd){ + EXPECT_LT(fabs(em[ii*nnei*1 + jj*1 + dd] - + expected_env[ii*nnei*1 + jj*1 + dd]) , + 1e-5); + } + } + } +} + + +TEST_F(TestEnvMatR, prod_cpu_equal_cpu) +{ + EXPECT_EQ(nlist_r_cpy.size(), nloc); + int tot_nnei = 0; + int max_nbor_size = 0; + for(int ii = 0; ii < nlist_a_cpy.size(); ++ii){ + tot_nnei += nlist_a_cpy[ii].size(); + if (nlist_a_cpy[ii].size() > max_nbor_size){ + max_nbor_size = nlist_a_cpy[ii].size(); + } + } + std::vector ilist(nloc), jlist(tot_nnei), jrange(nloc+1, 0); + for (int ii = 0; ii < nloc; ++ii){ + ilist[ii] = ii; + jrange[ii+1] = jrange[ii] + nlist_a_cpy[ii].size(); + int jj, cc; + for (jj = jrange[ii], cc = 0; jj < jrange[ii+1]; ++jj, ++cc){ + jlist[jj] = nlist_a_cpy[ii][cc]; + } + } + std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); + std::vector nlist(nloc * nnei); + std::vector avg(ntypes * ndescrpt, 0); + std::vector std(ntypes * ndescrpt, 1); + prod_env_mat_r_cpu( + &em[0], + &em_deriv[0], + &rij[0], + &nlist[0], + &posi_cpy[0], + &atype_cpy[0], + &ilist[0], + &jrange[0], + &jlist[0], + max_nbor_size, + &avg[0], + &std[0], + nloc, + nall, + ntypes, + rc, + rc_smth, + sec_a); + + std::vector fmt_nlist_a_1, fmt_nlist_r_1; + std::vector env_1, env_deriv_1, rij_a_1; + for(int ii = 0; ii < nloc; ++ii){ + int ret_1 = format_nlist_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + EXPECT_EQ(ret_1, -1); + env_mat_r_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + EXPECT_EQ(env_1.size(), nnei * 1); + EXPECT_EQ(env_deriv_1.size(), nnei * 1 * 3); + EXPECT_EQ(rij_a_1.size(), nnei * 3); + EXPECT_EQ(fmt_nlist_a_1.size(), nnei); + EXPECT_EQ(env_1.size() * nloc, em.size()); + EXPECT_EQ(env_deriv_1.size() * nloc, em_deriv.size()); + EXPECT_EQ(rij_a_1.size() * nloc, rij.size()); + EXPECT_EQ(fmt_nlist_a_1.size() * nloc, nlist.size()); + for (unsigned jj = 0; jj < env_1.size(); ++jj){ + EXPECT_LT(fabs(em[ii*nnei*1+jj] - env_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < env_deriv_1.size(); ++jj){ + EXPECT_LT(fabs(em_deriv[ii*nnei*1*3+jj] - env_deriv_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < rij_a_1.size(); ++jj){ + EXPECT_LT(fabs(rij[ii*nnei*3+jj] - rij_a_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < fmt_nlist_a_1.size(); ++jj){ + EXPECT_EQ(nlist[ii*nnei+jj], fmt_nlist_a_1[jj]); + } + } +} + + +#if GOOGLE_CUDA +TEST_F(TestEnvMatR, prod_gpu_cuda) +{ + EXPECT_EQ(nlist_r_cpy.size(), nloc); + int tot_nnei = 0; + int max_nbor_size = 0; + for(int ii = 0; ii < nlist_a_cpy.size(); ++ii){ + tot_nnei += nlist_a_cpy[ii].size(); + if (nlist_a_cpy[ii].size() > max_nbor_size){ + max_nbor_size = nlist_a_cpy[ii].size(); + } + } + assert(max_nbor_size <= GPU_MAX_NBOR_SIZE); + if (max_nbor_size <= 1024) { + max_nbor_size = 1024; + } + else if (max_nbor_size <= 2048) { + max_nbor_size = 2048; + } + else { + max_nbor_size = 4096; + } + std::vector ilist(nloc), jlist(tot_nnei), jrange(nloc+1, 0); + for (int ii = 0; ii < nloc; ++ii){ + ilist[ii] = ii; + jrange[ii+1] = jrange[ii] + nlist_a_cpy[ii].size(); + int jj, cc; + for (jj = jrange[ii], cc = 0; jj < jrange[ii+1]; ++jj, ++cc){ + jlist[jj] = nlist_a_cpy[ii][cc]; + } + } + std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); + std::vector nlist(nloc * nnei); + std::vector avg(ntypes * ndescrpt, 0); + std::vector std(ntypes * ndescrpt, 1); + + double * em_dev = NULL, * em_deriv_dev = NULL, * rij_dev = NULL; + double * posi_cpy_dev = NULL, * avg_dev = NULL, * std_dev = NULL; + int * atype_cpy_dev = NULL, * nlist_dev = NULL, * ilist_dev = NULL, * jrange_dev = NULL, * jlist_dev = NULL, * array_int_dev = NULL; + int_64 * array_longlong_dev = NULL; + malloc_device_memory_sync(em_dev, em); + malloc_device_memory_sync(em_deriv_dev, em_deriv); + malloc_device_memory_sync(rij_dev, rij); + malloc_device_memory_sync(posi_cpy_dev, posi_cpy); + malloc_device_memory_sync(avg_dev, avg); + malloc_device_memory_sync(std_dev, std); + + malloc_device_memory_sync(atype_cpy_dev, atype_cpy); + malloc_device_memory_sync(nlist_dev, nlist); + malloc_device_memory_sync(ilist_dev, ilist); + malloc_device_memory_sync(jrange_dev, jrange); + malloc_device_memory_sync(jlist_dev, jlist); + + malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); + malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); + + prod_env_mat_r_gpu_cuda( + em_dev, + em_deriv_dev, + rij_dev, + nlist_dev, + posi_cpy_dev, + atype_cpy_dev, + ilist_dev, + jrange_dev, + jlist_dev, + array_int_dev, + array_longlong_dev, + max_nbor_size, + avg_dev, + std_dev, + nloc, + nall, + rc, + rc_smth, + sec_a); + memcpy_device_to_host(em_dev, em); + delete_device_memory(em_dev); + delete_device_memory(em_deriv_dev); + delete_device_memory(nlist_dev); + delete_device_memory(posi_cpy_dev); + delete_device_memory(atype_cpy_dev); + delete_device_memory(ilist_dev); + delete_device_memory(jrange_dev); + delete_device_memory(jlist_dev); + delete_device_memory(array_int_dev); + delete_device_memory(array_longlong_dev); + delete_device_memory(avg_dev); + delete_device_memory(std_dev); + + for(int ii = 0; ii < nloc; ++ii){ + for (int jj = 0; jj < nnei; ++jj){ + for (int dd = 0; dd < 1; ++dd){ + EXPECT_LT(fabs(em[ii*nnei*1 + jj*1 + dd] - + expected_env[ii*nnei*1 + jj*1 + dd]) , + 1e-5); + } + } + } +} + +TEST_F(TestEnvMatR, prod_gpu_cuda_equal_cpu) +{ + EXPECT_EQ(nlist_r_cpy.size(), nloc); + int tot_nnei = 0; + int max_nbor_size = 0; + for(int ii = 0; ii < nlist_a_cpy.size(); ++ii){ + tot_nnei += nlist_a_cpy[ii].size(); + if (nlist_a_cpy[ii].size() > max_nbor_size){ + max_nbor_size = nlist_a_cpy[ii].size(); + } + } + assert(max_nbor_size <= GPU_MAX_NBOR_SIZE); + if (max_nbor_size <= 1024) { + max_nbor_size = 1024; + } + else if (max_nbor_size <= 2048) { + max_nbor_size = 2048; + } + else { + max_nbor_size = 4096; + } + std::vector ilist(nloc), jlist(tot_nnei), jrange(nloc+1, 0); + for (int ii = 0; ii < nloc; ++ii){ + ilist[ii] = ii; + jrange[ii+1] = jrange[ii] + nlist_a_cpy[ii].size(); + int jj, cc; + for (jj = jrange[ii], cc = 0; jj < jrange[ii+1]; ++jj, ++cc){ + jlist[jj] = nlist_a_cpy[ii][cc]; + } + } + std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); + std::vector nlist(nloc * nnei); + std::vector avg(ntypes * ndescrpt, 0); + std::vector std(ntypes * ndescrpt, 1); + + double * em_dev = NULL, * em_deriv_dev = NULL, * rij_dev = NULL; + double * posi_cpy_dev = NULL, * avg_dev = NULL, * std_dev = NULL; + int * atype_cpy_dev = NULL, * nlist_dev = NULL, * ilist_dev = NULL, * jrange_dev = NULL, * jlist_dev = NULL, * array_int_dev = NULL; + int_64 * array_longlong_dev = NULL; + malloc_device_memory_sync(em_dev, em); + malloc_device_memory_sync(em_deriv_dev, em_deriv); + malloc_device_memory_sync(rij_dev, rij); + malloc_device_memory_sync(posi_cpy_dev, posi_cpy); + malloc_device_memory_sync(avg_dev, avg); + malloc_device_memory_sync(std_dev, std); + + malloc_device_memory_sync(atype_cpy_dev, atype_cpy); + malloc_device_memory_sync(nlist_dev, nlist); + malloc_device_memory_sync(ilist_dev, ilist); + malloc_device_memory_sync(jrange_dev, jrange); + malloc_device_memory_sync(jlist_dev, jlist); + + malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); + malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); + + prod_env_mat_r_gpu_cuda( + em_dev, + em_deriv_dev, + rij_dev, + nlist_dev, + posi_cpy_dev, + atype_cpy_dev, + ilist_dev, + jrange_dev, + jlist_dev, + array_int_dev, + array_longlong_dev, + max_nbor_size, + avg_dev, + std_dev, + nloc, + nall, + rc, + rc_smth, + sec_a); + memcpy_device_to_host(em_dev, em); + memcpy_device_to_host(em_deriv_dev, em_deriv); + memcpy_device_to_host(rij_dev, rij); + memcpy_device_to_host(nlist_dev, nlist); + delete_device_memory(em_dev); + delete_device_memory(em_deriv_dev); + delete_device_memory(nlist_dev); + delete_device_memory(posi_cpy_dev); + delete_device_memory(atype_cpy_dev); + delete_device_memory(ilist_dev); + delete_device_memory(jrange_dev); + delete_device_memory(jlist_dev); + delete_device_memory(array_int_dev); + delete_device_memory(array_longlong_dev); + delete_device_memory(avg_dev); + delete_device_memory(std_dev); + + std::vector fmt_nlist_a_1, fmt_nlist_r_1; + std::vector env_1, env_deriv_1, rij_a_1; + for(int ii = 0; ii < nloc; ++ii){ + int ret_1 = format_nlist_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + EXPECT_EQ(ret_1, -1); + env_mat_r_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + EXPECT_EQ(env_1.size(), nnei * 1); + EXPECT_EQ(env_deriv_1.size(), nnei * 1 * 3); + EXPECT_EQ(rij_a_1.size(), nnei * 3); + EXPECT_EQ(fmt_nlist_a_1.size(), nnei); + EXPECT_EQ(env_1.size() * nloc, em.size()); + EXPECT_EQ(env_deriv_1.size() * nloc, em_deriv.size()); + EXPECT_EQ(rij_a_1.size() * nloc, rij.size()); + EXPECT_EQ(fmt_nlist_a_1.size() * nloc, nlist.size()); + for (unsigned jj = 0; jj < env_1.size(); ++jj){ + EXPECT_LT(fabs(em[ii*nnei*1+jj] - env_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < env_deriv_1.size(); ++jj){ + EXPECT_LT(fabs(em_deriv[ii*nnei*1*3+jj] - env_deriv_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < rij_a_1.size(); ++jj){ + EXPECT_LT(fabs(rij[ii*nnei*3+jj] - rij_a_1[jj]), 1e-10); + } + for (unsigned jj = 0; jj < fmt_nlist_a_1.size(); ++jj){ + EXPECT_EQ(nlist[ii*nnei+jj], fmt_nlist_a_1[jj]); + } + } +} +#endif //GOOGLE_CUDA diff --git a/source/lib/tests/test_gelu.cc b/source/lib/tests/test_gelu.cc new file mode 100644 index 0000000000..fcb580eaeb --- /dev/null +++ b/source/lib/tests/test_gelu.cc @@ -0,0 +1,214 @@ +#include "gelu.h" +#include "device.h" +#include +#include +#include "MathUtilities.h" + +class TestGelu : public ::testing::Test +{ +protected: + // xx = tf.random.uniform([100], minval=-4, maxval=4, dtype = tf.float64) + std::vector xx = { + -0.65412617, -0.74208893, -2.21731157, 0.42540039, -0.20889174, -1.37948692, + 3.36373004, -2.51647562, -2.985111 , -0.53251562, 0.36373729, -3.19052875, + 0.37908265, 0.81605825, 1.66281318, 2.71761869, -0.89313006, 0.11503315, + 2.2010268 , 0.65498149, 1.51153638, 0.71501482, -1.27392131, -2.89503271, + 0.53546578, 1.4564317 , -2.36701143, 1.23009056, 0.20264839, 2.06037292, + 3.41302551, -2.3175205 , -0.27628221, -1.35701656, 2.13781656, -0.52921087, + -1.56774526, 2.92475766, -3.17376756, -2.61726505, -0.89399621, -1.30025318, + -3.98310127, 0.0378038 , -0.59195525, -0.71764632, 2.83774732, -1.83266476, + -3.52590216, 2.7735313 , -1.52387184, -3.57984618, 3.44036277, -1.52546413, + 3.34095372, 1.12462909, 0.64319821, -3.94019443, -0.4976394 , -3.84744725, + 3.32683062, -1.95707363, -1.73538352, -3.32614596, -1.46374614, 3.32600174, + 1.56399235, 3.42035556, 3.029476 , -3.99135473, 2.22774417, -2.27991379, + -0.12769364, 3.27522847, -1.18421457, -2.65598248, 0.37112235, 1.27091438, + 1.82646907, 2.06702457, 2.87834558, 0.63158531, -1.76016732, -0.85704887, + 1.07093632, -2.55155726, 0.60068505, -0.36984068, -1.75685256, 1.2808404, + 3.07005843, 1.11521146, 2.3648244 , -2.79509595, 2.4611316 , 2.95155864, + 3.45913518, 2.71155262, 0.49731474, 0.89416884 + }; + std::vector expected_gelu = { + -1.67837557e-01, -1.70017454e-01, -2.92128115e-02, 2.82765887e-01, + -8.71641062e-02, -1.15934278e-01, 3.36269232e+00, -1.44692661e-02, + -3.81342874e-03, -1.58276988e-01, 2.33504238e-01, -1.93195840e-03, + 2.45520665e-01, 6.46854620e-01, 1.58255340e+00, 2.70915699e+00, + -1.66142311e-01, 6.27839507e-02, 2.17077193e+00, 4.87104731e-01, + 1.41257916e+00, 5.45282609e-01, -1.29333636e-01, -5.04228492e-03, + 3.76858089e-01, 1.35041498e+00, -2.08435518e-02, 1.09538283e+00, + 1.17595324e-01, 2.01997211e+00, 3.41216324e+00, -2.33762781e-02, + -1.08073931e-01, -1.18820554e-01, 2.10325928e+00, -1.57900404e-01, + -9.18635121e-02, 2.92015365e+00, -2.04685946e-03, -1.11316220e-02, + -1.66096393e-01, -1.26039117e-01, -7.61243780e-05, 1.94719045e-02, + -1.63967673e-01, -1.69774465e-01, 2.83175981e+00, -6.13003406e-02, + -5.56239423e-04, 2.76631042e+00, -9.73891862e-02, -4.47898619e-04, + 3.43958593e+00, -9.71871941e-02, 3.33982471e+00, 9.77813916e-01, + 4.75894192e-01, -9.31449548e-05, -1.53971187e-01, -1.42502838e-04, + 3.32564148e+00, -4.91974866e-02, -7.18453399e-02, -1.19212505e-03, + -1.05075731e-01, 3.32480898e+00, 1.47165971e+00, 3.41951698e+00, + 3.02616656e+00, -7.31989124e-05, 2.19918490e+00, -2.54527487e-02, + -5.73595208e-02, 3.27379481e+00, -1.40141518e-01, -1.00297107e-02, + 2.39266857e-01, 1.14120736e+00, 1.76452433e+00, 2.02715079e+00, + 2.87304205e+00, 4.64915551e-01, -6.90746681e-02, -1.67834746e-01, + 9.18580320e-01, -1.32266764e-02, 4.36049337e-01, -1.31576637e-01, + -6.94420205e-02, 1.15236826e+00, 3.06715854e+00, 9.67388918e-01, + 2.34387360e+00, -6.78489313e-03, 2.44451366e+00, 2.94732148e+00, + 3.45841254e+00, 2.70294624e+00, 3.43387119e-01, 7.28081631e-01 + }; + std::vector expected_gelu_grad = { + 4.60449412e-02, 4.50599718e-03, -6.31675690e-02, 8.19672783e-01, + 3.35740612e-01, -1.28672776e-01, 1.00385962e+00, -3.67087198e-02, + -1.20649335e-02, 1.12970546e-01, 7.77739313e-01, -6.68287407e-03, + 7.88372245e-01, 1.02580252e+00, 1.11883773e+00, 1.02368320e+00, + -5.28753300e-02, 5.91377555e-01, 1.06481455e+00, 9.54387332e-01, + 1.12733634e+00, 9.83340637e-01, -1.24278352e-01, -1.53213139e-02, + 8.88777668e-01, 1.12870635e+00, -4.89412880e-02, 1.12076578e+00, + 6.59486509e-01, 1.07959136e+00, 1.00327260e+00, -5.34451698e-02, + 2.85098027e-01, -1.28185394e-01, 1.07135120e+00, 1.14935972e-01, + -1.24907600e-01, 1.01417860e+00, -7.02992824e-03, -2.96883138e-02, + -5.31536587e-02, -1.25891871e-01, -3.60887857e-04, 5.30148635e-01, + 7.89229070e-02, 1.54532953e-02, 1.01772418e+00, -1.03699345e-01, + -2.20978811e-03, 1.02074891e+00, -1.26887416e-01, -1.81810307e-03, + 1.00298141e+00, -1.26825892e-01, 1.00415984e+00, 1.10771369e+00, + 9.48383787e-01, -4.34543288e-04, 1.34084905e-01, -6.41896044e-04, + 1.00435580e+00, -9.07188185e-02, -1.12900642e-01, -4.36549981e-03, + -1.28587248e-01, 1.00436754e+00, 1.12509925e+00, 1.00319222e+00, + 1.01067764e+00, -3.48088477e-04, 1.06212145e+00, -5.70046708e-02, + 3.98669653e-01, 1.00513974e+00, -1.15918449e-01, -2.72566889e-02, + 7.82872230e-01, 1.12407088e+00, 1.10431752e+00, 1.07887693e+00, + 1.01599352e+00, 9.42365429e-01, -1.10671686e-01, -4.07709087e-02, + 1.09835643e+00, -3.41514078e-02, 9.25865272e-01, 2.18016504e-01, + -1.10974960e-01, 1.12473750e+00, 1.00952394e+00, 1.10621038e+00, + 1.04913579e+00, -1.96928674e-02, 1.04098891e+00, 1.01320664e+00, + 1.00279462e+00, 1.02401893e+00, 8.65714727e-01, 1.05320906e+00 + }; + std::vector expected_gelu_grad_grad = { + 0.50571564, 0.43843355, -0.10061714, 0.66240156, 0.76347293, 0.01663728, + -0.01276427, -0.07462592, -0.03281601, 0.59359609, 0.69699731, -0.02027303, + 0.68877611, 0.38103445, -0.07490714, -0.05506099, 0.32166971, 0.78732762, + -0.10164498, 0.5050721 , -0.03437986, 0.4593321 , 0.06819688, -0.0396137, + 0.59156916, -0.01491246, -0.08883747, 0.09234241, 0.7654675 , -0.10747085, + -0.01108326, -0.09311994, 0.7384317 , 0.02681523, -0.10499993, 0.59585922, + -0.05160053, -0.03728553, -0.02114303, -0.06469217, 0.32100942, 0.05445215, + -0.00157624, 0.79673926, 0.55165186, 0.45730633, -0.04432554, -0.10006544, + -0.00789302, -0.04993342, -0.03838479, -0.00665763, -0.01022962, -0.03889244, + -0.01360533, 0.1565692 , 0.51391336, -0.00186407, 0.61706551, -0.00264692, + -0.01414804, -0.10721734, -0.08807903, -0.01417477, -0.01764587, -0.0141804, + -0.05053224, -0.01084901, -0.02975642, -0.00152558, -0.09992717, -0.09614436, + 0.7848912 , -0.01627357, 0.11925413, -0.06092512, 0.69307417, 0.06980313, + -0.09948152, -0.10733955, -0.04095624, 0.52257218, -0.09172304, 0.34933309, + 0.19229249, -0.07116424, 0.54531393, 0.6937595 , -0.09125988, 0.06452926, + -0.02712756, 0.16269737, -0.08903289, -0.04801427, -0.08003338, -0.03525758, + -0.00967444, -0.05562922, 0.61727952, 0.32087784 + }; + + const int nloc = xx.size(); + + void SetUp() override { + } + void TearDown() override { + } +}; + +TEST_F(TestGelu, gelu_cpu) +{ + std::vector gelu(nloc); + gelu_cpu (&gelu[0], &xx[0], nloc); + EXPECT_EQ(gelu.size(), nloc); + EXPECT_EQ(gelu.size(), expected_gelu.size()); + for (int jj = 0; jj < gelu.size(); ++jj){ + EXPECT_LT(fabs(gelu[jj] - expected_gelu[jj]) , 1e-5); + } +} + +TEST_F(TestGelu, gelu_grad_cpu) +{ + std::vector dy(100, 1.0); + std::vector gelu_grad(nloc); + gelu_grad_cpu (&gelu_grad[0], &xx[0], &dy[0], nloc); + EXPECT_EQ(gelu_grad.size(), nloc); + EXPECT_EQ(gelu_grad.size(), expected_gelu_grad.size()); + for (int jj = 0; jj < gelu_grad.size(); ++jj){ + EXPECT_LT(fabs(gelu_grad[jj] - expected_gelu_grad[jj]) , 1e-5); + } +} + +TEST_F(TestGelu, gelu_grad_grad_cpu) +{ + std::vector dy(100, 1.0); + std::vector dy_2(100, 1.0); + std::vector gelu_grad_grad(nloc); + gelu_grad_grad_cpu (&gelu_grad_grad[0], &xx[0], &dy[0], &dy_2[0], nloc); + EXPECT_EQ(gelu_grad_grad.size(), nloc); + EXPECT_EQ(gelu_grad_grad.size(), expected_gelu_grad_grad.size()); + for (int jj = 0; jj < gelu_grad_grad.size(); ++jj){ + EXPECT_LT(fabs(gelu_grad_grad[jj] - expected_gelu_grad_grad[jj]) , 1e-5); + } +} + +#if GOOGLE_CUDA +TEST_F(TestGelu, gelu_gpu_cuda) +{ + std::vector gelu(nloc); + + double * gelu_dev = NULL, * xx_dev = NULL; + malloc_device_memory_sync(gelu_dev, gelu); + malloc_device_memory_sync(xx_dev, xx); + gelu_gpu_cuda (gelu_dev, xx_dev, nloc); + memcpy_device_to_host(gelu_dev, gelu); + delete_device_memory(gelu_dev); + delete_device_memory(xx_dev); + + EXPECT_EQ(gelu.size(), nloc); + EXPECT_EQ(gelu.size(), expected_gelu.size()); + for (int jj = 0; jj < gelu.size(); ++jj){ + EXPECT_LT(fabs(gelu[jj] - expected_gelu[jj]) , 1e-5); + } +} + +TEST_F(TestGelu, gelu_grad_gpu_cuda) +{ + std::vector dy(100, 1.0); + std::vector gelu_grad(nloc); + + double * gelu_grad_dev = NULL, * xx_dev = NULL, * dy_dev = NULL; + malloc_device_memory_sync(gelu_grad_dev, gelu_grad); + malloc_device_memory_sync(xx_dev, xx); + malloc_device_memory_sync(dy_dev, dy); + gelu_grad_gpu_cuda (gelu_grad_dev, xx_dev, dy_dev, nloc); + memcpy_device_to_host(gelu_grad_dev, gelu_grad); + delete_device_memory(gelu_grad_dev); + delete_device_memory(xx_dev); + delete_device_memory(dy_dev); + + EXPECT_EQ(gelu_grad.size(), nloc); + EXPECT_EQ(gelu_grad.size(), expected_gelu_grad.size()); + for (int jj = 0; jj < gelu_grad.size(); ++jj){ + EXPECT_LT(fabs(gelu_grad[jj] - expected_gelu_grad[jj]) , 1e-5); + } +} + +TEST_F(TestGelu, gelu_grad_grad_gpu_cuda) +{ + std::vector dy(100, 1.0); + std::vector dy_2(100, 1.0); + std::vector gelu_grad_grad(nloc); + + double * gelu_grad_grad_dev = NULL, * xx_dev = NULL, * dy_dev = NULL, * dy_2_dev = NULL; + malloc_device_memory_sync(gelu_grad_grad_dev, gelu_grad_grad); + malloc_device_memory_sync(xx_dev, xx); + malloc_device_memory_sync(dy_dev, dy); + malloc_device_memory_sync(dy_2_dev, dy_2); + gelu_grad_grad_gpu_cuda (gelu_grad_grad_dev, xx_dev, dy_dev, dy_2_dev, nloc); + memcpy_device_to_host(gelu_grad_grad_dev, gelu_grad_grad); + delete_device_memory(gelu_grad_grad_dev); + delete_device_memory(xx_dev); + delete_device_memory(dy_dev); + delete_device_memory(dy_2_dev); + + EXPECT_EQ(gelu_grad_grad.size(), nloc); + EXPECT_EQ(gelu_grad_grad.size(), expected_gelu_grad_grad.size()); + for (int jj = 0; jj < gelu_grad_grad.size(); ++jj){ + EXPECT_LT(fabs(gelu_grad_grad[jj] - expected_gelu_grad_grad[jj]) , 1e-5); + } +} +#endif // GOOGLE_CUDA \ No newline at end of file diff --git a/source/lib/tests/test_prod_force_a.cc b/source/lib/tests/test_prod_force_a.cc index 93766e1b78..800e83d79c 100644 --- a/source/lib/tests/test_prod_force_a.cc +++ b/source/lib/tests/test_prod_force_a.cc @@ -4,6 +4,7 @@ #include "env_mat.h" #include "neighbor_list.h" #include "prod_force.h" +#include "device.h" class TestProdForceA : public ::testing::Test { @@ -96,3 +97,33 @@ TEST_F(TestProdForceA, cpu) // } // printf("\n"); } + +#if GOOGLE_CUDA +TEST_F(TestProdForceA, gpu_cuda) +{ + std::vector force(nall * 3); + int n_a_sel = nnei; + + int * nlist_dev = NULL; + double * force_dev = NULL, * net_deriv_dev = NULL, * env_deriv_dev = NULL; + + malloc_device_memory_sync(nlist_dev, nlist); + malloc_device_memory_sync(force_dev, force); + malloc_device_memory_sync(net_deriv_dev, net_deriv); + malloc_device_memory_sync(env_deriv_dev, env_deriv); + + prod_force_a_gpu_cuda (force_dev, net_deriv_dev, env_deriv_dev, nlist_dev, nloc, nall, nnei); + + memcpy_device_to_host(force_dev, force); + delete_device_memory(nlist_dev); + delete_device_memory(force_dev); + delete_device_memory(net_deriv_dev); + delete_device_memory(env_deriv_dev); + + EXPECT_EQ(force.size(), nall * 3); + EXPECT_EQ(force.size(), expected_force.size()); + for (int jj = 0; jj < force.size(); ++jj){ + EXPECT_LT(fabs(force[jj] - expected_force[jj]) , 1e-5); + } +} +#endif // GOOGLE_CUDA \ No newline at end of file diff --git a/source/lib/tests/test_prod_force_r.cc b/source/lib/tests/test_prod_force_r.cc index 93247b2d86..cfb105f1a7 100644 --- a/source/lib/tests/test_prod_force_r.cc +++ b/source/lib/tests/test_prod_force_r.cc @@ -4,6 +4,7 @@ #include "env_mat.h" #include "neighbor_list.h" #include "prod_force.h" +#include "device.h" class TestProdForceR : public ::testing::Test { @@ -96,3 +97,33 @@ TEST_F(TestProdForceR, cpu) // } // printf("\n"); } + +#if GOOGLE_CUDA +TEST_F(TestProdForceR, gpu_cuda) +{ + std::vector force(nall * 3); + int n_a_sel = nnei; + + int * nlist_dev = NULL; + double * force_dev = NULL, * net_deriv_dev = NULL, * env_deriv_dev = NULL; + + malloc_device_memory_sync(nlist_dev, nlist); + malloc_device_memory_sync(force_dev, force); + malloc_device_memory_sync(net_deriv_dev, net_deriv); + malloc_device_memory_sync(env_deriv_dev, env_deriv); + + prod_force_r_gpu_cuda (force_dev, net_deriv_dev, env_deriv_dev, nlist_dev, nloc, nall, nnei); + + memcpy_device_to_host(force_dev, force); + delete_device_memory(nlist_dev); + delete_device_memory(force_dev); + delete_device_memory(net_deriv_dev); + delete_device_memory(env_deriv_dev); + + EXPECT_EQ(force.size(), nall * 3); + EXPECT_EQ(force.size(), expected_force.size()); + for (int jj = 0; jj < force.size(); ++jj){ + EXPECT_LT(fabs(force[jj] - expected_force[jj]) , 1e-5); + } +} +#endif // GOOGLE_CUDA diff --git a/source/lib/tests/test_prod_virial_a.cc b/source/lib/tests/test_prod_virial_a.cc index a8fb5fb914..7cf7f2d789 100644 --- a/source/lib/tests/test_prod_virial_a.cc +++ b/source/lib/tests/test_prod_virial_a.cc @@ -4,6 +4,7 @@ #include "env_mat.h" #include "neighbor_list.h" #include "prod_virial.h" +#include "device.h" class TestProdVirialA : public ::testing::Test { @@ -111,3 +112,51 @@ TEST_F(TestProdVirialA, cpu) // } // printf("\n"); } + +#if GOOGLE_CUDA +TEST_F(TestProdVirialA, gpu_cuda) +{ + std::vector virial(9); + std::vector atom_virial(nall * 9); + int n_a_sel = nnei; + + int * nlist_dev = NULL; + double * virial_dev = NULL, *atom_virial_dev = NULL, * net_deriv_dev = NULL, * env_deriv_dev = NULL, * rij_dev = NULL; + + malloc_device_memory_sync(nlist_dev, nlist); + malloc_device_memory_sync(virial_dev, virial); + malloc_device_memory_sync(atom_virial_dev, atom_virial); + malloc_device_memory_sync(net_deriv_dev, net_deriv); + malloc_device_memory_sync(env_deriv_dev, env_deriv); + malloc_device_memory_sync(rij_dev, rij); + + prod_virial_a_gpu_cuda (virial_dev, atom_virial_dev, net_deriv_dev, env_deriv_dev, rij_dev, nlist_dev, nloc, nall, nnei); + + memcpy_device_to_host(virial_dev, virial); + memcpy_device_to_host(atom_virial_dev, atom_virial); + delete_device_memory(nlist_dev); + delete_device_memory(virial_dev); + delete_device_memory(atom_virial_dev); + delete_device_memory(net_deriv_dev); + delete_device_memory(env_deriv_dev); + delete_device_memory(rij_dev); + // virial are not calculated in gpu currently; + for (int ii = 0; ii < 9; ii++) { + virial[ii] = 0; + } + for (int ii = 0; ii < nall * 9; ii++) { + virial[ii % 9] += atom_virial[ii]; + } + + EXPECT_EQ(virial.size(), 9); + EXPECT_EQ(virial.size(), expected_virial.size()); + EXPECT_EQ(atom_virial.size(), nall * 9); + EXPECT_EQ(atom_virial.size(), expected_atom_virial.size()); + for (int jj = 0; jj < virial.size(); ++jj){ + EXPECT_LT(fabs(virial[jj] - expected_virial[jj]) , 1e-5); + } + for (int jj = 0; jj < atom_virial.size(); ++jj){ + EXPECT_LT(fabs(atom_virial[jj] - expected_atom_virial[jj]) , 1e-5); + } +} +#endif // GOOGLE_CUDA \ No newline at end of file diff --git a/source/lib/tests/test_prod_virial_r.cc b/source/lib/tests/test_prod_virial_r.cc index 359eda8345..5d57427e85 100644 --- a/source/lib/tests/test_prod_virial_r.cc +++ b/source/lib/tests/test_prod_virial_r.cc @@ -4,6 +4,7 @@ #include "env_mat.h" #include "neighbor_list.h" #include "prod_virial.h" +#include "device.h" class TestProdVirialR : public ::testing::Test { @@ -111,3 +112,51 @@ TEST_F(TestProdVirialR, cpu) // } // printf("\n"); } + +#if GOOGLE_CUDA +TEST_F(TestProdVirialR, gpu_cuda) +{ + std::vector virial(9); + std::vector atom_virial(nall * 9); + int n_a_sel = nnei; + + int * nlist_dev = NULL; + double * virial_dev = NULL, *atom_virial_dev = NULL, * net_deriv_dev = NULL, * env_deriv_dev = NULL, * rij_dev = NULL; + + malloc_device_memory_sync(nlist_dev, nlist); + malloc_device_memory_sync(virial_dev, virial); + malloc_device_memory_sync(atom_virial_dev, atom_virial); + malloc_device_memory_sync(net_deriv_dev, net_deriv); + malloc_device_memory_sync(env_deriv_dev, env_deriv); + malloc_device_memory_sync(rij_dev, rij); + + prod_virial_r_gpu_cuda (virial_dev, atom_virial_dev, net_deriv_dev, env_deriv_dev, rij_dev, nlist_dev, nloc, nall, nnei); + + memcpy_device_to_host(virial_dev, virial); + memcpy_device_to_host(atom_virial_dev, atom_virial); + delete_device_memory(nlist_dev); + delete_device_memory(virial_dev); + delete_device_memory(atom_virial_dev); + delete_device_memory(net_deriv_dev); + delete_device_memory(env_deriv_dev); + delete_device_memory(rij_dev); + // virial are not calculated in gpu currently; + for (int ii = 0; ii < 9; ii++) { + virial[ii] = 0; + } + for (int ii = 0; ii < nall * 9; ii++) { + virial[ii % 9] += atom_virial[ii]; + } + + EXPECT_EQ(virial.size(), 9); + EXPECT_EQ(virial.size(), expected_virial.size()); + EXPECT_EQ(atom_virial.size(), nall * 9); + EXPECT_EQ(atom_virial.size(), expected_atom_virial.size()); + for (int jj = 0; jj < virial.size(); ++jj){ + EXPECT_LT(fabs(virial[jj] - expected_virial[jj]) , 1e-5); + } + for (int jj = 0; jj < atom_virial.size(); ++jj){ + EXPECT_LT(fabs(atom_virial[jj] - expected_atom_virial[jj]) , 1e-5); + } +} +#endif // GOOGLE_CUDA \ No newline at end of file diff --git a/source/lib/tests/test_tabulate.cc b/source/lib/tests/test_tabulate.cc new file mode 100644 index 0000000000..8c9d27c33a --- /dev/null +++ b/source/lib/tests/test_tabulate.cc @@ -0,0 +1,234 @@ +#include +#include +#include "device.h" +#include "tabulate.h" +#include +#include "MathUtilities.h" + +class TestTabulate : public ::testing::Test +{ +protected: + // em_x = tf.random.uniform([4, 16], minval=0, maxval=0.2, dtype = tf.float64) + std::vector info = { + 0, 0.2, 0.4, 0.01, 0.1, -1 + }; + std::vector em_x = { + 0.0343909 , + 0.11357423, + 0.0858676 , + 0.19337772, + 0.1935728 , + 0.0477744 , + 0.05845198, + 0.19080509, + 0.16111261, + 0.07179262, + 0.10078013, + 0.04640909, + 0.10433399, + 0.15650861, + 0.17527857, + 0.04249097 + }; + std::vector em = { + 0.0343909 , 0.08394249, 0.06791791, 0.00903334, 0.11357423, 0.10597251, + 0.05738069, 0.10071109, 0.0858676 , 0.17410445, 0.05390256, 0.09495758, + 0.19337772, 0.02045487, 0.04095526, 0.18431305, + 0.1935728 , 0.03930614, 0.0304133 , 0.15261676, 0.0477744, 0.06838737, + 0.12824902, 0.14125861, 0.05845198, 0.12731053, 0.0315968, 0.14927774, + 0.19080509, 0.19206871, 0.14361383, 0.04083437, + 0.16111261, 0.19944826, 0.16563484, 0.00797179, 0.07179262, 0.16993159, + 0.01834742, 0.08405 , 0.10078013, 0.0773945 , 0.09541813, 0.0042979, + 0.04640909, 0.07968697, 0.18046262, 0.11724063, + 0.10433399, 0.16910201, 0.10653732, 0.07434702, 0.15650861, 0.0350976, + 0.04088021, 0.15753491, 0.17527857, 0.03178642, 0.01599623, 0.08095053, + 0.04249097, 0.17082205, 0.18275348, 0.02921504 + }; + std::vector table = { + 6.348551343037398542e-01, 4.209465843706336474e-04, 6.390862740714405368e-03, -1.544448595628262176e-04, -1.891095227974180087e-04, 2.695025951562175852e-05, -1.317549846042939343e+00, -5.624478206903206490e-02, 1.274284553146523905e-02, -6.836227424141475689e-04, -1.438066096020836407e-04, -1.854932873974712940e-06, -9.996964112615246423e-01, 6.928234423723647617e-02, -4.974719973810486084e-03, -2.019584729176823030e-04, 1.077254539742680247e-04, -8.024209768588029797e-06, 3.552689563657350780e-01, -3.578299775339799371e-02, -1.319946251007718743e-03, 1.016701374495701440e-03, -1.057336720791906388e-04, 5.182678943855506567e-06, 1.227750369557627286e+00, 4.100352079064395472e-02, 3.586869164810712295e-03, -4.304540913340443135e-04, -1.269943482892440004e-04, 1.459465404430219674e-05, -1.472642501673147031e+00, -1.611354921283318364e-01, 1.645427874390196360e-02, 2.107392978135091402e-04, -2.193541011180757461e-04, 1.915392497459551146e-05, -2.855174490181606739e-01, 9.774337856626263976e-02, -2.140891880666230714e-03, -7.148328890055103638e-04, 1.965696332267534503e-05,-4.593489654121371453e-06, -1.468441009949382314e+00, -6.360828127262234399e-02, 4.751283295356955282e-03, 8.711899561753186068e-05, -9.937008678852959884e-06, 4.273569346584811685e-07, + 6.348599826995243722e-01, 5.487167506364742930e-04, 6.386116198716365253e-03, -1.619832375568118791e-04, -1.877328309473502049e-04, 2.134130914519164856e-05, -1.318111020264137512e+00, -5.599013082054477008e-02, 1.272225054666903735e-02, -6.893710047488201898e-04, -1.434367581078517366e-04, 3.329508890614227371e-05 , -9.990040854920316793e-01, 6.918278968071900348e-02, -4.980714172967731085e-03, -1.976574487947816198e-04, 1.070037204086153902e-04, -7.859875077388093586e-06, 3.549109954092205532e-01, -3.580909209068139365e-02, -1.289508598157979719e-03, 1.012474257117017967e-03, -1.054418924402112718e-04, -1.245498322204730900e-05, 1.228160763020727630e+00, 4.107512853046493134e-02, 3.573879491390910459e-03, -4.355190226638688713e-04, -1.258433981470396103e-04, 1.610862268100766631e-05, -1.474252210958008291e+00, -1.608063442081248406e-01, 1.646046950167207382e-02, 2.019843636566674109e-04, -2.185756589083626730e-04, 1.978479879983412190e-05, -2.845402300363228942e-01, 9.770034635718018168e-02, -2.162325119197382531e-03, -7.140472215558940627e-04, 1.956302663031799223e-05, 1.932584474244053378e-05, -1.469076617546759334e+00, -6.351322951074317436e-02, 4.753890907276497185e-03, 8.672114560243554321e-05, -1.004574434175897967e-05, -4.345700882560937596e-06, + 6.348661083147921769e-01, 6.763897297752743953e-04, 6.381144275303845745e-03, -1.694690463885140694e-04, -1.868179426353836598e-04, 3.439291082765030046e-05, -1.318669650038090335e+00, -5.573589319299507294e-02, 1.270148368741391351e-02, -6.950749719342792137e-04, -1.422194703304518733e-04, 3.454751241752252323e-05 , -9.983127558632299836e-01, 6.908311652764687061e-02, -4.986579772806746212e-03, -1.933888092529071571e-04, 1.068327546750306073e-04, -2.976978385983384886e-05, 3.545527765488725169e-01, -3.583457894275744043e-02, -1.259197760082061621e-03, 1.008246479193084487e-03, -1.059401869200098984e-04, 1.721968053146218465e-06, 1.228571871257205572e+00, 4.114647496201748883e-02, 3.560738575723638825e-03, -4.405332425718102457e-04, -1.251648759618972115e-04, 3.659080417076460655e-05, -1.475858628153338792e+00, -1.604770750960976822e-01, 1.646639808472218428e-02, 1.932598402043995316e-04, -2.175904819601363058e-04, 1.230256868634094333e-05, -2.835634435191126679e-01, 9.765688571984927624e-02, -2.183734604613508240e-03, -7.132463811570244078e-04, 2.021887442373574272e-05, 1.321401495096886281e-05, -1.469711274366155784e+00, -6.341812571665436660e-02, 4.756486470714936521e-03, 8.631384191910702040e-05, -1.010516500002806932e-05, -1.110874413279218719e-05, + 6.348735101551836735e-01, 8.039610290153098582e-04, 6.375948457075718626e-03, -1.769074132993461279e-04, -1.855677150383903214e-04, 3.421271436711027645e-05, -1.319225739518145257e+00, -5.548207260888919634e-02, 1.268054645200545304e-02, -7.007297564176242621e-04, -1.408885818822980523e-04, 3.124701885930576017e-05 , -9.976224235482542557e-01, 6.898332734138989952e-02, -4.992317635216104131e-03, -1.891404922064061889e-04, 1.053957535708985289e-04, -1.089286646983666076e-06, 3.541943058468561834e-01, -3.585946084769019160e-02, -1.229013912637771933e-03, 1.004009466262262241e-03, -1.059129033455631863e-04, -4.941663399086282537e-06, 1.228983691638902087e+00, 4.121755707472917613e-02, 3.547447845420277635e-03, -4.455036207721562607e-04, -1.239172256532283074e-04, 3.437341080261359686e-05, -1.477461752073406132e+00, -1.601476900261984693e-01, 1.647206544856073471e-02, 1.845724864086241608e-04, -2.173853638475303177e-04, 3.620505631412716563e-05, -2.825870937484175061e-01, 9.761299713537928413e-02, -2.205119732548723246e-03, -7.124245958910824846e-04, 2.074820558303217398e-05, 1.209381466404663338e-05, -1.470344979888463577e+00, -6.332297013406351649e-02, 4.759069711794740656e-03, 8.589935708505183382e-05, -1.045842324058424788e-05, -6.134254562752213537e-06, + 6.348821871815598650e-01, 9.314261853726121809e-04, 6.370530236175125580e-03, -1.842978984547447257e-04, -1.840210089691990327e-04, 2.234897510077387526e-05, -1.319779292891724465e+00, -5.522867246076747227e-02, 1.265944033870337014e-02, -7.063360380236871801e-04, -1.393416734992873119e-04, 1.931167378610719847e-05 , -9.969330896946905218e-01, 6.888342466806646192e-02, -4.997928623431705138e-03, -1.849303524006284602e-04, 1.053651633995249134e-04, -2.870133904891753420e-05, 3.538355893399378616e-01, -3.588374034700148041e-02, -1.198957225773849763e-03, 9.997681359810027708e-04, -1.060678155548662341e-04, -4.107776618240329050e-06, 1.229396221507694564e+00, 4.128837188660083868e-02, 3.534008730169808672e-03, -4.504275777948374090e-04, -1.224778886969254976e-04, 2.455513266683544498e-05, -1.479061581584721008e+00, -1.598181942132129441e-01, 1.647747255391585064e-02, 1.759082956613747337e-04, -2.158335508261176197e-04, 6.406725844410341030e-06, -2.816111850012528728e-01, 9.756868109694678826e-02, -2.226479900633348240e-03, -7.115823288942964460e-04, 2.121038517729223415e-05, 1.358027318850170435e-05, -1.470977733597038872e+00, -6.322776301216057049e-02, 4.761640356162846754e-03, 8.547576468445008296e-05, -1.081874527005240631e-05, -8.845528475774308509e-07, + 6.348921383103013349e-01, 1.058780765759985421e-03, 6.364891110105044131e-03, -1.916363332792569681e-04, -1.827768871456785058e-04, 2.275707291847725182e-05, -1.320330314380025793e+00, -5.497569611120622923e-02, 1.263816684562326688e-02, -7.118908987616576157e-04, -1.380182662155302303e-04, 1.630252530406085050e-05 , -9.962447554247517711e-01, 6.878341103651769428e-02, -5.003413601927745452e-03, -1.807403991329658622e-04, 1.040363362483998831e-04, -4.422604643727719699e-06, 3.534766330394523148e-01, -3.590741998555346121e-02, -1.169027863565602274e-03, 9.955202772264954043e-04, -1.060447700647724903e-04, -1.021743279826507342e-05, 1.229809458175783687e+00, 4.135891644424664892e-02, 3.520422661584679015e-03, -4.553035794622276055e-04, -1.210679214963379874e-04, 1.595827246550979495e-05, -1.480658115605847147e+00, -1.594885928526604546e-01, 1.648262036665308974e-02, 1.672799673730459213e-04, -2.148155690753495697e-04,-1.867405535452657550e-06, -2.806357215496423363e-01, 9.752393810975558408e-02, -2.247814508535729908e-03, -7.107227883497464890e-04, 2.207595560206285042e-05,-1.137331983229785190e-06, -1.471609534977757372e+00, -6.313250460562676303e-02, 4.764198129054059844e-03, 8.503999275315992160e-05, -1.072692568096017848e-05, -1.373273803695183988e-05, + 6.349033624136081189e-01, 1.186020367092407990e-03, 6.359032581545111251e-03, -1.989262833250400370e-04, -1.812752661309344573e-04, 1.302837915648187095e-05, -1.320878808237722746e+00, -5.472314689282183064e-02, 1.261672747063919374e-02, -7.173917679890315846e-04, -1.373052781380030543e-04, 3.768455339511444900e-05 , -9.955574218354472649e-01, 6.868328895828368363e-02, -5.008773436308684712e-03, -1.765844799686671349e-04, 1.034810966435298563e-04, -1.111176255155353207e-05, 3.531174429312692320e-01, -3.593050231143132822e-02, -1.139225984250480384e-03, 9.912704081392112714e-04, -1.064918174657224404e-04, 2.680738443515978403e-06, 1.230223398925979650e+00, 4.142918782293085467e-02, 3.506691073047987512e-03, -4.601302388532728274e-04, -1.198865987378785417e-04, 1.656386182477533959e-05, -1.482251353107205460e+00, -1.591588911206925361e-01, 1.648750985769346228e-02, 1.586901819247656846e-04, -2.147074421644348298e-04, 2.641762503224190698e-05, -2.796607076604977760e-01, 9.747876869099537933e-02, -2.269122958003529523e-03, -7.098388532529275848e-04, 2.226701915637888804e-05, 1.106237844209756009e-05, -1.472240383519069384e+00, -6.303719517464229094e-02, 4.766742755353862819e-03, 8.459962202271287246e-05, -1.132218730142039535e-05, 8.958476322974335592e-07, + 6.349158583197994643e-01, 1.313140616388666637e-03, 6.352956158169477396e-03, -2.061601622854974502e-04, -1.806298821034440756e-04, 3.770936817966389514e-05, -1.321424778752664952e+00, -5.447102810827629538e-02, 1.259512371128685033e-02, -7.228490733933210606e-04, -1.356407402355522122e-04, 2.099832634320949299e-05 , -9.948710899987588396e-01, 6.858306092758209571e-02, -5.014008993202081696e-03, -1.724573933478598642e-04, 1.029144894329912032e-04, -1.738522780636760158e-05, 3.527580249757622521e-01, -3.595298987582695727e-02, -1.109551740263377793e-03, 9.870126155001155040e-04, -1.064931456292656029e-04, -2.059910396978558087e-06, 1.230638041011988815e+00, 4.149918312660194619e-02, 3.492815399561766294e-03, -4.649051157564728157e-04, -1.192927614880224277e-04, 4.072077917749542957e-05, -1.483841293110880866e+00, -1.588290941739924356e-01, 1.649214200293154520e-02, 1.501282794678792006e-04, -2.138853834118830831e-04, 2.633111784219914963e-05, -2.786861475954987011e-01, 9.743317336979973042e-02, -2.290404652904617314e-03, -7.089360554728917595e-04, 2.260180638238835256e-05, 1.741828165826791135e-05, -1.472870278712053782e+00, -6.294183498489253070e-02, 4.769273959660644442e-03, 8.414681093302789892e-05, -1.142905205912834352e-05, -4.014065121916994726e-06, + 6.349296248136164778e-01, 1.440137170869312810e-03, 6.346663352465874847e-03, -2.133510744796659759e-04, -1.788513201196447670e-04, 1.721163944875696416e-05, -1.321968230245579967e+00, -5.421934303028537461e-02, 1.257335706466754244e-02, -7.282542863230233527e-04, -1.343059033644905889e-04, 1.747822893445653714e-05 , -9.941857609618123259e-01, 6.848272942128874607e-02, -5.019121140152461337e-03, -1.683596869525186377e-04, 1.024142382012053007e-04, -2.632719129544749384e-05, 3.523983851077774343e-01, -3.597488523292310947e-02, -1.080005278271846739e-03, 9.827512175914082399e-04, -1.066680880078371994e-04, 3.403258606315080555e-07, 1.231053381658700818e+00, 4.156889948792314576e-02, 3.478797077596604108e-03, -4.696409807358484993e-04, -1.173636798436718986e-04, 1.149931408689037458e-05, -1.485427934690428442e+00, -1.584992071496764965e-01, 1.649651778315383566e-02, 1.415960091521040870e-04, -2.125888038426753843e-04, 7.384582528889821378e-06, -2.777120456109742896e-01, 9.738715268720327112e-02, -2.311658999267464203e-03, -7.080165982958596923e-04, 2.340034491729013294e-05, 5.174033942788913380e-06, -1.473499220050474623e+00, -6.284642430757329812e-02, 4.771791466347353149e-03, 8.368540130389298475e-05, -1.162498575113560591e-05, -5.381585801785509468e-06, + 6.349446606365225509e-01, 1.567005718051586727e-03, 6.340155681555815353e-03, -2.204854663573854625e-04, -1.779502948888764897e-04, 3.196283450610521294e-05, -1.322509167069771951e+00, -5.396809490162747525e-02, 1.255142902735281209e-02, -7.336077414823606981e-04, -1.332538502428148267e-04, 2.525523713666122703e-05 , -9.935014357470516311e-01, 6.838229689892011409e-02, -5.024110745516051704e-03, -1.642860423419652261e-04, 1.011792892256958577e-04, -5.902237032851650630e-06, 3.520385292366049468e-01, -3.599619093977864809e-02, -1.050586739210998023e-03, 9.784837539753422735e-04, -1.066187407206570670e-04, -6.052991441884039902e-06, 1.231469418062474341e+00, 4.163833406830096812e-02, 3.464637544942418459e-03, -4.743218246565151001e-04, -1.164951133813105271e-04, 2.473911917278243621e-05, -1.487011276970676033e+00, -1.581692351651968476e-01, 1.650063818395723983e-02, 1.331001312464952355e-04, -2.118074389246019866e-04, 9.192428068946771109e-06, -2.767384059577842614e-01, 9.734070719609828892e-02, -2.332885405321092481e-03, -7.070743922828596519e-04, 2.373777250910882265e-05, 1.127700884024945933e-05, -1.474127207030835107e+00, -6.275096341939470634e-02, 4.774294999622533293e-03, 8.321347296773265077e-05, -1.162225195759229858e-05, -1.468175407624093560e-05, + 6.349609644870094494e-01, 1.693741975839754832e-03, 6.333434667015966531e-03, -2.275719866012916918e-04, -1.766077012712487378e-04, 2.919052022666632077e-05, -1.323047593610823247e+00, -5.371728693515605280e-02, 1.252934109528984138e-02, -7.389107006611626187e-04, -1.322992615601379437e-04, 3.689337377145077536e-05 , -9.928181153524118230e-01, 6.828176580261838269e-02, -5.028978678356570489e-03, -1.602449667799085492e-04, 1.004819833385002965e-04, -7.012859043909368637e-06, 3.516784632459502014e-01, -3.601690955621394963e-02, -1.021296258318379370e-03, 9.742140050919662845e-04, -1.068837890347894775e-04, 3.261791903209577241e-07, 1.231886147391427544e+00, 4.170748405790913882e-02, 3.450338240560582581e-03, -4.789562532735843967e-04, -1.153902983973557932e-04, 2.856018069496295048e-05, -1.488591319127526624e+00, -1.578391833182464787e-01, 1.650450419566778376e-02, 1.246407552546250339e-04, -2.115332183818513349e-04, 3.149345367837511192e-05, -2.757652328811996956e-01, 9.729383746118988596e-02, -2.354083281534554220e-03, -7.061133365182417328e-04, 2.418809213597686327e-05, 1.280494807360028992e-05, -1.474754239152433311e+00, -6.265545260258377491e-02, 4.776784283590801948e-03, 8.273687806363864625e-05, -1.229952261449745124e-05, 3.204146150058887708e-06, + 6.349785350208994039e-01, 1.820341692612803541e-03, 6.326501834700739083e-03, -2.346100929840904846e-04, -1.748840426396014729e-04, 1.130785525935554482e-05, -1.323583514286295282e+00, -5.346692231381247606e-02, 1.250709476370755191e-02, -7.441705970339035966e-04, -1.303302437099287372e-04, 7.935577538626925858e-06 , -9.921358007514943234e-01, 6.818113855713830995e-02, -5.033725808341922223e-03, -1.562353718150353687e-04, 1.001568149392305130e-04, -2.302258383924021595e-05, 3.513181929939074299e-01, -3.603704364469759169e-02, -9.921339651685744804e-04, 9.699384566370250092e-04, -1.069081013817698415e-04, -2.744679484186812129e-06, 1.232303566785723392e+00, 4.177634667571154814e-02, 3.435900604437185177e-03, -4.835440426346156498e-04, -1.140781768005934266e-04, 2.411509316948267986e-05, -1.490168060387760951e+00, -1.575090566866652331e-01, 1.650811681325956015e-02, 1.162064642248029450e-04, -2.100324946396962247e-04, 4.868837971279583202e-06, -2.747925306207861240e-01, 9.724654405895133413e-02, -2.375252040655950400e-03, -7.051355614741510987e-04, 2.505903781065493165e-05,-2.569082101323676566e-06, -1.475380315917416585e+00, -6.255989214488603956e-02, 4.779259042312647421e-03, 8.224491253736542200e-05, -1.205054378062991984e-05, -1.594987943813344381e-05, + 6.349973708516511994e-01, 1.946800647308156995e-03, 6.319358714566076195e-03, -2.415904693897710526e-04, -1.741570105122868483e-04, 3.342152683043006766e-05, -1.324116933545430141e+00, -5.321700419064152865e-02, 1.248469152702344660e-02, -7.493727578058629766e-04, -1.295525827398787404e-04, 2.659942231629285135e-05 , -9.914544928937398804e-01, 6.808041756983601589e-02, -5.038353005641925050e-03, -1.522500103683389601e-04, 9.911425811568465554e-05, -1.035676665958809070e-05, 3.509577243129330393e-01, -3.605659577023319351e-02, -9.630999837076988784e-04, 9.656594578503095369e-04, -1.070158919994286978e-04, -2.281503112307771063e-06, 1.232721673357858538e+00, 4.184491916948063911e-02, 3.421326077437690516e-03, -4.880823132679394552e-04, -1.129872290747681817e-04, 2.854952342195995698e-05, -1.491741500028839651e+00, -1.571788603283475749e-01, 1.651147703627379656e-02, 1.078118218043548068e-04, -2.094656285123614196e-04, 1.573608604543182341e-05, -2.738203034102859035e-01, 9.719882757757769554e-02, -2.396391097750961291e-03, -7.041328812172977002e-04, 2.511128111671661627e-05, 1.472819566023977703e-05, -1.476005436830838402e+00, -6.246428233956573262e-02, 4.781718999863710830e-03, 8.175246233396933941e-05, -1.310850420537104008e-05, 1.717274673157189222e-05, + 6.350174705506670403e-01, 2.073114649501703322e-03, 6.312006840494438151e-03, -2.485262001215581039e-04, -1.724445833892894095e-04, 1.623821996891234705e-05, -1.324647855868849478e+00, -5.296753568880858964e-02, 1.246213287875118370e-02, -7.545274547770323926e-04, -1.284298383236558551e-04, 3.142127009671183137e-05 , -9.907741927046019859e-01, 6.797960523066012839e-02, -5.042861140826992473e-03, -1.482946605870891395e-04, 9.821987974303589589e-05, -3.593831829470692349e-06, 3.505970630098214080e-01, -3.607556850024738748e-02, -9.341944322877257512e-04, 9.613773761737330267e-04, -1.072343182304808093e-04, 2.791451096706449119e-06, 1.233140464192951757e+00, 4.191319881581374862e-02, 3.406616101162745613e-03, -4.925758895926437772e-04, -1.113902906060245713e-04, 1.275308331152581608e-05, -1.493311637378700762e+00, -1.568485992811522733e-01, 1.651458586873823589e-02, 9.944841367174414462e-05, -2.085492230796830474e-04, 1.276456024245067926e-05, -2.728485554775001987e-01, 9.715068861693920699e-02, -2.417499870240937074e-03, -7.031148500958378164e-04, 2.576543833825076558e-05, 7.841889896124507091e-06, -1.476629601400710978e+00, -6.236862348540499201e-02, 4.784163880393361643e-03, 8.124213252544174404e-05, -1.286332078849730127e-05, -1.821996546344873330e-06, + 6.350388326475970846e-01, 2.199279539485121671e-03, 6.304447750121061969e-03, -2.554047701160370044e-04, -1.716061813901302753e-04, 3.413524324276134592e-05, -1.325176285768258300e+00, -5.271851990161838253e-02, 1.243942031140890699e-02, -7.596346042592860793e-04, -1.269803855069738714e-04, 2.314478643438959578e-05 , -9.900949010857222898e-01, 6.787870391214460841e-02, -5.047251084767826433e-03, -1.443753107913585767e-04, 9.837034053479728221e-05, -3.865274593462701621e-05, 3.502362148656810170e-01, -3.609396440447816545e-02, -9.054174237006253068e-04, 9.570894530963515055e-04, -1.071221722792567601e-04, -5.180134097885568801e-06, 1.233559936349031494e+00, 4.198118292014653419e-02, 3.391772117805412056e-03, -4.970162819604460663e-04, -1.105584293158747960e-04, 2.757032189173095048e-05, -1.494878471815561216e+00, -1.565182785628131401e-01, 1.651744431908664865e-02, 9.112268062696188113e-05, -2.082277461664644284e-04, 3.370820636496137736e-05, -2.718772910441742408e-01, 9.710212778853387350e-02, -2.438577777940475859e-03, -7.020756635958485484e-04, 2.613933618298708639e-05, 1.211520684095310762e-05, -1.477252809138063672e+00, -6.227291588670166161e-02, 4.786593408182711167e-03, 8.072392747742672100e-05, -1.281499371544444526e-05, -1.293175202324119235e-05, + 6.350614556306495295e-01, 2.325291188338546311e-03, 6.296682984661446623e-03, -2.622362895631248896e-04, -1.701076322674243866e-04, 2.573454296903621253e-05, -1.325702227786145437e+00, -5.246995989253622206e-02, 1.241655531642829255e-02, -7.646904682589584622e-04, -1.257704658362481128e-04, 2.439373356208127567e-05 , -9.894166189151047952e-01, 6.777771596940393439e-02, -5.051523708536139086e-03, -1.404733355821404265e-04, 9.677082285072928253e-05, -3.720510878458014501e-06, 3.498751856359115786e-01, -3.611178605486395354e-02, -8.767690652124425499e-04, 9.527998576480508275e-04, -1.072771816869139909e-04, -2.281376475091892258e-06, 1.233980086857325631e+00, 4.204886881676297983e-02, 3.376795570009583514e-03, -5.014114486109571937e-04, -1.092957353261917852e-04, 2.516456964431257380e-05, -1.496442002767713664e+00, -1.561879031708521548e-01, 1.652005340007862977e-02, 8.282284133744905071e-05, -2.067123325224875000e-04, 7.057486539657783089e-06, -2.709065143258797548e-01, 9.705314571543909030e-02, -2.459624243094573216e-03, -7.010187162791577066e-04, 2.672975399789282626e-05, 7.629793933874534523e-06, -1.477875059556995385e+00, -6.217715985326619649e-02, 4.789007307701962507e-03, 8.019935829649041371e-05, -1.318861260046749971e-05, -7.150339348059032240e-06, + 6.350853379468965887e-01, 2.451145498001100487e-03, 6.288714088740080324e-03, -2.690159202421790068e-04, -1.686584359429067433e-04, 1.941481480743946700e-05, -1.326225686495484890e+00, -5.222185869521017709e-02, 1.239353938406437261e-02, -7.696964132049412353e-04, -1.246012242240120604e-04, 2.724071141974432252e-05 , -9.887393470472876089e-01, 6.767664374012982709e-02, -5.055679883306329545e-03, -1.366074591188833347e-04, 9.623033677044332457e-05, -1.113456896173822779e-05, 3.495139810501832756e-01, -3.612903602543367232e-02, -8.482494585971035728e-04, 9.485064841097947883e-04, -1.073561607316583907e-04, -2.239996380309942211e-06, 1.234400912722548371e+00, 4.211625386880359784e-02, 3.361687900729734210e-03, -5.057597926077623488e-04, -1.078411892315765344e-04, 1.508800592977199686e-05, -1.498002229713325750e+00, -1.558574780824932282e-01, 1.652241412871961052e-02, 7.456368677257522147e-05, -2.062001731191939454e-04, 2.069621557469772063e-05, -2.699362295319003291e-01, 9.700374303226286243e-02, -2.480638690415259105e-03, -6.999405672986690023e-04, 2.700789474676622474e-05, 1.556143061449123430e-05, -1.478496352174730522e+00, -6.208135570041733303e-02, 4.791405303667145565e-03, 7.966538051836852740e-05, -1.352687841609079228e-05, -2.789411930543395566e-06, + 6.351104780025849106e-01, 2.576838401336829787e-03, 6.280542610220480118e-03, -2.757414391158645754e-04, -1.675762649448408429e-04, 2.787462665161048641e-05, -1.326746666499438287e+00, -5.197421931349595348e-02, 1.237037400330611749e-02, -7.746541492504023475e-04, -1.232228491818352083e-04, 2.166599538617633252e-05 , -9.880630863135209108e-01, 6.757548954459043078e-02, -5.059720480258220535e-03, -1.327693574508429343e-04, 9.550030312894054513e-05, -1.096549240339310371e-05, 3.491526068124157778e-01, -3.614571689219699124e-02, -8.198587001702131727e-04, 9.442100079790295610e-04, -1.074330339280879455e-04, -2.103241190440061311e-06, 1.234822410923189784e+00, 4.218333546826981417e-02, 3.346450553092000530e-03, -5.100549148199152614e-04, -1.071543306169886722e-04, 3.572075491055831030e-05, -1.499559152180234056e+00, -1.555270082545787691e-01, 1.652452752618108200e-02, 6.633607063542407416e-05, -2.052990867644106118e-04, 1.891505702101457936e-05, -2.689664408651156746e-01, 9.695392038509384469e-02, -2.501620547117759490e-03, -6.988464710389351081e-04, 2.774961528830105395e-05, 4.843681010028069226e-06, -1.479116686511674494e+00, -6.198550374897651011e-02, 4.793787121096219732e-03, 7.912045955652986253e-05, -1.359696279035538403e-05, -9.132339849453571562e-06, + 6.351368741634448867e-01, 2.702365862198193025e-03, 6.272170100036473551e-03, -2.824171711189519380e-04, -1.661976899287730559e-04, 2.457347650017094835e-05, -1.327265172431057128e+00, -5.172704472148267896e-02, 1.234706066178771662e-02, -7.795630288411945592e-04, -1.217395799935142969e-04, 1.184741714306808905e-05 , -9.873878375219384829e-01, 6.747425568563097942e-02, -5.063646370480812467e-03, -1.289626891970745083e-04, 9.513074838211379970e-05, -2.521433322545949321e-05, 3.487910686007592576e-01, -3.616183123303555458e-02, -7.915968808226425679e-04, 9.399119246579864433e-04, -1.077055728285351480e-04, 6.031191175422362627e-06, 1.235244578411804905e+00, 4.225011103602600848e-02, 3.331084970256580589e-03, -5.143079026275864784e-04, -1.055716785023949844e-04, 2.051193936812822612e-05, -1.501112769745742259e+00, -1.551964986234863897e-01, 1.652639461772111712e-02, 5.814089462644928566e-05, -2.041249358339155683e-04, 6.311073191969795411e-06, -2.679971525218879380e-01, 9.690367843145115956e-02, -2.522569242956208650e-03, -6.977319783847560700e-04, 2.827424678587480721e-05, 2.739673941330651616e-06, -1.479736062091468574e+00, -6.188960432526132566e-02, 4.796152485364500034e-03, 7.856828747830194362e-05, -1.395147193446202365e-05, -4.087221013031299888e-06, + 6.351645247550001816e-01, 2.827723875485507743e-03, 6.263598112024793517e-03, -2.890409134869928735e-04, -1.648390823803598971e-04, 2.215887759642637032e-05, -1.327781208952985015e+00, -5.148033786352124164e-02, 1.232360084570068709e-02, -7.844171563535663055e-04, -1.210428935521009746e-04, 3.344327592646507844e-05 , -9.867136014577331249e-01, 6.737294444867666932e-02, -5.067458424877044516e-03, -1.251812701937470213e-04, 9.419473244264059593e-05, -1.679002076268449654e-05, 3.484293720675762929e-01, -3.617738162759492893e-02, -7.634640860539731316e-04, 9.356082122653546981e-04, -1.075431084112703954e-04, -3.044614041061100766e-06, 1.235667412115300623e+00, 4.231657802179918798e-02, 3.315592595281378029e-03, -5.185116053649769336e-04, -1.041674655671950871e-04, 1.242766263135090892e-05, -1.502663082036415076e+00, -1.548659541050484978e-01, 1.652801643260504508e-02, 4.998556989557471122e-05, -2.037688261998792680e-04, 2.657243869390409541e-05, -2.670283686919466826e-01, 9.685301784023310490e-02, -2.543484210258855835e-03, -6.965966582328896994e-04, 2.850491087748043708e-05, 1.232179636112698650e-05, -1.480354478441044286e+00, -6.179365776107784841e-02, 4.798501122259496952e-03, 7.800586916120723585e-05, -1.413851691566035862e-05, -5.727587674967719880e-06, + 6.351934280628791507e-01, 2.952908467203564646e-03, 6.254828202758994093e-03, -2.956111985445306826e-04, -1.636502852942454153e-04, 2.616921494951480123e-05, -1.328294780757159899e+00, -5.123410165425365537e-02, 1.229999603970671068e-02, -7.892274520450543677e-04, -1.195721301312790567e-04, 2.454197033093738297e-05 , -9.860403788833298488e-01, 6.727155810173718331e-02, -5.071157514069617352e-03, -1.214296539729165295e-04, 9.340570341953608358e-05, -1.444050153586573228e-05, 3.480675228394242149e-01, -3.619237065717702262e-02, -7.354603960058733389e-04, 9.313051737393654526e-04, -1.076930273455606579e-04, -7.696053039474192446e-07, 1.236090908935226107e+00, 4.238273390417521269e-02, 3.299974870987111650e-03, -5.226642260988254756e-04, -1.032474625011560351e-04, 2.396475265799989632e-05, -1.504210088727871764e+00, -1.545353795944727493e-01, 1.652939400402650763e-02, 4.186078937618800693e-05, -2.027012231708198600e-04, 1.761148452766873776e-05, -2.660600935582757565e-01, 9.680193929166537592e-02, -2.564364883962782712e-03, -6.954454205710857090e-04, 2.907017700829073683e-05, 9.120785771591908463e-06, -1.480971935090678926e+00, -6.169766439371183325e-02, 4.800832758035045861e-03, 7.743502257440657043e-05, -1.440171540732098418e-05, -4.489324897938611976e-06, + 6.355509554770921721e-01, 4.194364255265300989e-03, 6.156587518227093006e-03, -3.584539136959086518e-04, -1.505562336471176987e-04, 2.631189526673375584e-05, -1.333295991901433553e+00, -4.879824528740911438e-02, 1.205629889598585497e-02, -8.346035033896359156e-04, -1.072962342948566929e-04, 2.412331753624817981e-05 , -9.793640468817854661e-01, 6.625405011186732973e-02, -5.102126473064734317e-03, -8.551069374443776396e-05, 8.618032279329005427e-05, -1.422030758858379208e-05, 3.444418516979214084e-01, -3.631195473807800889e-02, -4.625381215785304145e-04, 8.881537622047225473e-04, -1.080757789189670570e-04, 5.820590714360855199e-08, 1.240361649325028681e+00, 4.302664794411619614e-02, 3.137220402938139478e-03, -5.615677039256951981e-04, -9.125763978623760322e-05, 2.367398552885374808e-05, -1.519498310980496925e+00, -1.512290469691385253e-01, 1.652996628226939199e-02,-3.745688059096337011e-05, -1.938906911473592626e-04, 1.811217640451412989e-05, -2.564062357251438717e-01, 9.626832379335603651e-02, -2.771163091665611831e-03, -6.829069315554202020e-04, 3.363238372709415958e-05, 8.623099725596635004e-06, -1.487093617252511990e+00, -6.073523464295225993e-02, 4.823154268625621383e-03, 7.122599345182346051e-05, -1.664931178025436733e-05, -4.312450972708557703e-06 + }; + std::vector expected_xyz_scatter = { + 0.2713011, -0.56606281, -0.42305039, 0.14965803, 0.52695372, + -0.63845663, -0.11624505, -0.63103203, + 0.24412213, -0.50842224, -0.38203148, 0.1353771, 0.47343798, + -0.57158622, -0.10647548, -0.56671287, + 0.13979394, -0.29123603, -0.21862063, 0.07744574, 0.27118433, + -0.32761487, -0.06077287, -0.32463492, + 0.24704819, -0.51555848, -0.38509326, 0.1362072, 0.47992214, + -0.58168358, -0.10566162, -0.57473633, + 0.31158834, -0.65068838, -0.48501479, 0.17143258, 0.60565326, + -0.73506803, -0.13233106, -0.72541595, + 0.27121003, -0.5656669 , -0.42318034, 0.14974857, 0.52662422, + -0.637633 , -0.11658482, -0.6305842 , + 0.21202135, -0.44212972, -0.33094666, 0.11713047, 0.41162829, + -0.4982129 , -0.0913087 , -0.49286515, + 0.30733526, -0.64054639, -0.48022212, 0.17004692, 0.59640929, + -0.72111726, -0.13304347, -0.71402776, + 0.24135931, -0.50316388, -0.37699907, 0.13347531, 0.46846154, + -0.56664651, -0.10429212, -0.56088123, + 0.33429479, -0.69669061, -0.52246841, 0.18502927, 0.64867706, + -0.78417021, -0.14487244, -0.77659533, + 0.29200237, -0.60840668, -0.45656557, 0.16172246, 0.56650319, + -0.68453038, -0.12681616, -0.67817995, + 0.13559139, -0.28210652, -0.21258614, 0.07539812, 0.26274303, + -0.3166084 , -0.05968776, -0.31443544, + 0.30394432, -0.63428311, -0.47381417, 0.16759396, 0.59043739, + -0.71559513, -0.13003802, -0.70708354, + 0.25830471, -0.53796239, -0.40421268, 0.14323456, 0.50094757, + -0.6048126 , -0.11264426, -0.59964242, + 0.21979687, -0.45763438, -0.34413143, 0.12197404, 0.42616899, + -0.51425659, -0.09609854, -0.51009828, + 0.2172166 , -0.45326447, -0.33866506, 0.11979851, 0.421936, + -0.51130404, -0.09300045, -0.50528542 + }; + std::vector expected_dy_dem_x = { + -0.02067741, + -0.03787612, + -0.04180199, + -0.04158797, + -0.03938578, + -0.04047081, + -0.03819692, + -0.05383372, + -0.05179508, + -0.03552708, + -0.02812173, + -0.04451295, + -0.04586229, + -0.03794369, + -0.02917727, + -0.04478649 + }; + std::vector expected_dy_dem = { + -3.32965609, -3.32965609, -3.32965609, -3.32965609, -3.33781886, -3.33781886, + -3.33781886, -3.33781886, -3.33501296, -3.33501296, -3.33501296, -3.33501296, + -3.34559974, -3.34559974, -3.34559974, -3.34559974, + -3.34561821, -3.34561821, -3.34561821, -3.34561821, -3.33106684, -3.33106684, + -3.33106684, -3.33106684, -3.33218328, -3.33218328, -3.33218328, -3.33218328, + -3.34535585, -3.34535585, -3.34535585, -3.34535585, + -3.34250754, -3.34250754, -3.34250754, -3.34250754, -3.33356685, -3.33356685, + -3.33356685, -3.33356685, -3.33652989, -3.33652989, -3.33652989, -3.33652989, + -3.3309235 , -3.3309235 , -3.3309235 , -3.3309235 , + -3.33688909, -3.33688909, -3.33688909, -3.33688909, -3.34206038, -3.34206038, + -3.34206038, -3.34206038, -3.34387412, -3.34387412, -3.34387412, -3.34387412, + -3.33051143, -3.33051143, -3.33051143, -3.33051143 + }; + const int nloc = 4; + const int nnei = 4; + const int last_layer_size = 8; + + void SetUp() override { + } + void TearDown() override { + } +}; + +TEST_F(TestTabulate, tabulate_fusion_cpu) +{ + std::vector xyz_scatter(nloc * nnei * last_layer_size); + tabulate_fusion_cpu(&xyz_scatter[0], &table[0], &info[0], &em_x[0], &em[0], nloc, nnei, last_layer_size); + EXPECT_EQ(xyz_scatter.size(), nloc * nnei * last_layer_size); + EXPECT_EQ(xyz_scatter.size(), expected_xyz_scatter.size()); + for (int jj = 0; jj < xyz_scatter.size(); ++jj){ + EXPECT_LT(fabs(xyz_scatter[jj] - expected_xyz_scatter[jj]) , 1e-5); + } +} + +TEST_F(TestTabulate, tabulate_fusion_grad_cpu) +{ + std::vector dy_dem_x(em_x.size()); + std::vector dy_dem(em.size()); + std::vector dy(nloc * nnei * last_layer_size, 1.0); + tabulate_fusion_grad_cpu(&dy_dem_x[0], &dy_dem[0], &table[0], &info[0], &em_x[0], &em[0], &dy[0], nloc, nnei, last_layer_size); + EXPECT_EQ(dy_dem_x.size(), nloc * nnei); + EXPECT_EQ(dy_dem.size(), nloc * nnei * 4); + EXPECT_EQ(dy_dem_x.size(), expected_dy_dem_x.size()); + EXPECT_EQ(dy_dem.size(), expected_dy_dem.size()); + for (int jj = 0; jj < dy_dem_x.size(); ++jj){ + EXPECT_LT(fabs(dy_dem_x[jj] - expected_dy_dem_x[jj]) , 1e-5); + } + for (int jj = 0; jj < dy_dem.size(); ++jj){ + EXPECT_LT(fabs(dy_dem[jj] - expected_dy_dem[jj]) , 1e-5); + } +} + +#if GOOGLE_CUDA +TEST_F(TestTabulate, tabulate_fusion_gpu_cuda) +{ + std::vector xyz_scatter(nloc * nnei * last_layer_size); + + double * xyz_scatter_dev = NULL, * table_dev = NULL, * em_x_dev = NULL, * em_dev = NULL; + malloc_device_memory_sync(xyz_scatter_dev, xyz_scatter); + malloc_device_memory_sync(table_dev, table); + malloc_device_memory_sync(em_x_dev, em_x); + malloc_device_memory_sync(em_dev, em); + tabulate_fusion_gpu_cuda(xyz_scatter_dev, table_dev, &info[0], em_x_dev, em_dev, nloc, nnei, last_layer_size); + memcpy_device_to_host(xyz_scatter_dev, xyz_scatter); + delete_device_memory(xyz_scatter_dev); + delete_device_memory(table_dev); + delete_device_memory(em_x_dev); + delete_device_memory(em_dev); + + EXPECT_EQ(xyz_scatter.size(), nloc * nnei * last_layer_size); + EXPECT_EQ(xyz_scatter.size(), expected_xyz_scatter.size()); + for (int jj = 0; jj < xyz_scatter.size(); ++jj){ + EXPECT_LT(fabs(xyz_scatter[jj] - expected_xyz_scatter[jj]) , 1e-5); + } +} + +TEST_F(TestTabulate, tabulate_fusion_grad_gpu_cuda) +{ + std::vector dy_dem_x(em_x.size()); + std::vector dy_dem(em.size()); + std::vector dy(nloc * nnei * last_layer_size, 1.0); + + double * dy_dem_x_dev = NULL, * dy_dem_dev = NULL, * table_dev = NULL, * em_x_dev = NULL, * em_dev = NULL, * dy_dev = NULL; + malloc_device_memory_sync(dy_dem_x_dev, dy_dem_x); + malloc_device_memory_sync(dy_dem_dev, dy_dem); + malloc_device_memory_sync(table_dev, table); + malloc_device_memory_sync(em_x_dev, em_x); + malloc_device_memory_sync(em_dev, em); + malloc_device_memory_sync(dy_dev, dy); + tabulate_fusion_grad_gpu_cuda(dy_dem_x_dev, dy_dem_dev, table_dev, &info[0], em_x_dev, em_dev, dy_dev, nloc, nnei, last_layer_size); + memcpy_device_to_host(dy_dem_x_dev, dy_dem_x); + memcpy_device_to_host(dy_dem_dev, dy_dem); + delete_device_memory(dy_dem_x_dev); + delete_device_memory(dy_dem_dev); + delete_device_memory(table_dev); + delete_device_memory(em_x_dev); + delete_device_memory(em_dev); + delete_device_memory(dy_dev); + + EXPECT_EQ(dy_dem_x.size(), nloc * nnei); + EXPECT_EQ(dy_dem.size(), nloc * nnei * 4); + EXPECT_EQ(dy_dem_x.size(), expected_dy_dem_x.size()); + EXPECT_EQ(dy_dem.size(), expected_dy_dem.size()); + for (int jj = 0; jj < dy_dem_x.size(); ++jj){ + EXPECT_LT(fabs(dy_dem_x[jj] - expected_dy_dem_x[jj]) , 1e-5); + } + for (int jj = 0; jj < dy_dem.size(); ++jj){ + EXPECT_LT(fabs(dy_dem[jj] - expected_dy_dem[jj]) , 1e-5); + } +} +#endif // GOOGLE_CUDA \ No newline at end of file diff --git a/source/op/prod_virial_se_r_multi_device.cc b/source/op/prod_virial_se_r_multi_device.cc deleted file mode 100644 index bb74cc0500..0000000000 --- a/source/op/prod_virial_se_r_multi_device.cc +++ /dev/null @@ -1,114 +0,0 @@ -#include "custom_op.h" -#include "CustomeOperation.h" - -REGISTER_OP("ProdVirialSeR") - .Attr("T: {float, double}") - .Input("net_deriv: T") - .Input("in_deriv: T") - .Input("rij: T") - .Input("nlist: int32") - .Input("natoms: int32") - .Output("virial: T") - .Output("atom_virial: T"); - -template -struct ProdVirialSeRFunctor { - void operator()(const CPUDevice& d, T * virial, T * atom_virial, const T * net_deriv, const T * in_deriv, const T * rij, const int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt) { - ProdVirialSeRCPULauncher(virial, atom_virial, net_deriv, in_deriv, rij, nlist, nloc, nall, nnei, ndescrpt); - } - #if GOOGLE_CUDA - void operator()(const GPUDevice& d, T * virial, T * atom_virial, const T * net_deriv, const T * in_deriv, const T * rij, const int * nlist, const int nloc, const int nall, const int nnei, const int ndescrpt) { - ProdVirialSeRGPULauncher(virial, atom_virial, net_deriv, in_deriv, rij, nlist, nloc, nall, nnei, ndescrpt); - } - #endif // GOOGLE_CUDA -}; - -template -class ProdVirialSeROp : public OpKernel { - public: - explicit ProdVirialSeROp(OpKernelConstruction* context) : OpKernel(context) {} - - void Compute(OpKernelContext* context) override { - // Grab the input tensor - int context_input_index = 0; - const Tensor& net_deriv_tensor = context->input(context_input_index++); - const Tensor& in_deriv_tensor = context->input(context_input_index++); - const Tensor& rij_tensor = context->input(context_input_index++); - const Tensor& nlist_tensor = context->input(context_input_index++); - const Tensor& natoms_tensor = context->input(context_input_index++); - - // set size of the sample - OP_REQUIRES (context, (net_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of net deriv should be 2")); - OP_REQUIRES (context, (in_deriv_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); - OP_REQUIRES (context, (rij_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of rij should be 2")); - OP_REQUIRES (context, (nlist_tensor.shape().dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); - OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); - - OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); - const int * natoms = natoms_tensor.flat().data(); - int nloc = natoms[0]; - int nall = natoms[1]; - int nnei = nlist_tensor.shape().dim_size(1) / nloc; - int nframes = net_deriv_tensor.shape().dim_size(0); - int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; - - // check the sizes - OP_REQUIRES (context, (nframes == in_deriv_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (nframes == rij_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - OP_REQUIRES (context, (nframes == nlist_tensor.shape().dim_size(0)), errors::InvalidArgument ("number of samples should match")); - - OP_REQUIRES (context, (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of descriptors should match")); - OP_REQUIRES (context, (nloc * nnei * 3 == rij_tensor.shape().dim_size(1)), errors::InvalidArgument ("dim of rij should be nnei * 3")); - - // Create an output tensor - TensorShape virial_shape ; - virial_shape.AddDim (nframes); - virial_shape.AddDim (9); - Tensor* virial_tensor = NULL; - OP_REQUIRES_OK(context, context->allocate_output(0, virial_shape, &virial_tensor)); - TensorShape atom_virial_shape; - atom_virial_shape.AddDim (nframes); - atom_virial_shape.AddDim (9 * nall); - Tensor* atom_virial_tensor = NULL; - OP_REQUIRES_OK(context, context->allocate_output(1, atom_virial_shape, &atom_virial_tensor)); - - // flat the tensors - auto net_deriv = net_deriv_tensor.flat(); - auto in_deriv = in_deriv_tensor.flat(); - auto rij = rij_tensor.flat(); - auto nlist = nlist_tensor.flat(); - auto virial = virial_tensor->flat(); - auto atom_virial = atom_virial_tensor->flat(); - - ProdVirialSeRFunctor()( - context->eigen_device(), - virial_tensor->flat().data(), - atom_virial_tensor->flat().data(), - net_deriv_tensor.flat().data(), - in_deriv_tensor.flat().data(), - rij_tensor.flat().data(), - nlist_tensor.flat().data(), - nloc, - nall, - nnei, - ndescrpt - ); - } -}; - -// Register the CPU kernels. -#define REGISTER_CPU(T) \ -REGISTER_KERNEL_BUILDER( \ - Name("ProdVirialSeR").Device(DEVICE_CPU).TypeConstraint("T"), \ - ProdVirialSeROp); -REGISTER_CPU(float); -REGISTER_CPU(double); -// Register the GPU kernels. -#if GOOGLE_CUDA -#define REGISTER_GPU(T) \ -REGISTER_KERNEL_BUILDER( \ - Name("ProdVirialSeR").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ - ProdVirialSeROp); -REGISTER_GPU(float); -REGISTER_GPU(double); -#endif // GOOGLE_CUDA \ No newline at end of file From 30a2abf66b0a38ce18a1faa876559906cde4673e Mon Sep 17 00:00:00 2001 From: denghuilu Date: Fri, 5 Mar 2021 02:26:15 +0800 Subject: [PATCH 236/562] fix conflicts --- source/lib/tests/test_env_mat_r.cc | 14 ++++++-------- source/lib/tests/test_gelu.cc | 2 +- source/lib/tests/test_tabulate.cc | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/source/lib/tests/test_env_mat_r.cc b/source/lib/tests/test_env_mat_r.cc index d22180d142..b3947936a3 100644 --- a/source/lib/tests/test_env_mat_r.cc +++ b/source/lib/tests/test_env_mat_r.cc @@ -1,9 +1,9 @@ #include #include -#include "fmt_nlist.h" #include "env_mat.h" -#include "neighbor_list.h" +#include "fmt_nlist.h" #include "prod_env_mat.h" +#include "neighbor_list.h" class TestEnvMatR : public ::testing::Test { @@ -277,7 +277,6 @@ TEST_F(TestEnvMatR, prod_cpu) &std[0], nloc, nall, - ntypes, rc, rc_smth, sec_a); @@ -333,7 +332,6 @@ TEST_F(TestEnvMatR, prod_cpu_equal_cpu) &std[0], nloc, nall, - ntypes, rc, rc_smth, sec_a); @@ -341,9 +339,9 @@ TEST_F(TestEnvMatR, prod_cpu_equal_cpu) std::vector fmt_nlist_a_1, fmt_nlist_r_1; std::vector env_1, env_deriv_1, rij_a_1; for(int ii = 0; ii < nloc; ++ii){ - int ret_1 = format_nlist_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_1, -1); - env_mat_r_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + env_mat_r_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); EXPECT_EQ(env_1.size(), nnei * 1); EXPECT_EQ(env_deriv_1.size(), nnei * 1 * 3); EXPECT_EQ(rij_a_1.size(), nnei * 3); @@ -564,9 +562,9 @@ TEST_F(TestEnvMatR, prod_gpu_cuda_equal_cpu) std::vector fmt_nlist_a_1, fmt_nlist_r_1; std::vector env_1, env_deriv_1, rij_a_1; for(int ii = 0; ii < nloc; ++ii){ - int ret_1 = format_nlist_cpu(fmt_nlist_a_1, posi_cpy, ntypes, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); + int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_1, -1); - env_mat_r_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, ntypes, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + env_mat_r_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); EXPECT_EQ(env_1.size(), nnei * 1); EXPECT_EQ(env_deriv_1.size(), nnei * 1 * 3); EXPECT_EQ(rij_a_1.size(), nnei * 3); diff --git a/source/lib/tests/test_gelu.cc b/source/lib/tests/test_gelu.cc index fcb580eaeb..e9f84f3fee 100644 --- a/source/lib/tests/test_gelu.cc +++ b/source/lib/tests/test_gelu.cc @@ -2,7 +2,7 @@ #include "device.h" #include #include -#include "MathUtilities.h" +#include "utilities.h" class TestGelu : public ::testing::Test { diff --git a/source/lib/tests/test_tabulate.cc b/source/lib/tests/test_tabulate.cc index 8c9d27c33a..bf31cfb325 100644 --- a/source/lib/tests/test_tabulate.cc +++ b/source/lib/tests/test_tabulate.cc @@ -3,7 +3,7 @@ #include "device.h" #include "tabulate.h" #include -#include "MathUtilities.h" +#include "utilities.h" class TestTabulate : public ::testing::Test { From cdf4664bd54d3c96928e78422e40ca134a8a3aac Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 5 Mar 2021 08:28:51 +0800 Subject: [PATCH 237/562] changing neighbor list interface. add unittests for op prod_env_mat --- source/lib/include/neighbor_list.h | 4 +- source/lib/include/prod_env_mat.h | 9 +- source/lib/src/neighbor_list.cc | 12 ++ source/lib/src/prod_env_mat.cc | 42 +++--- source/lib/tests/test_env_mat_a.cc | 35 ++--- source/lib/tests/test_pair_tab.cc | 136 ++++++++++-------- source/tests/test_prod_env_mat.py | 214 +++++++++++++++++++++++++++++ 7 files changed, 337 insertions(+), 115 deletions(-) create mode 100644 source/tests/test_prod_env_mat.py diff --git a/source/lib/include/neighbor_list.h b/source/lib/include/neighbor_list.h index 44a7fc417b..3dfed7ab40 100644 --- a/source/lib/include/neighbor_list.h +++ b/source/lib/include/neighbor_list.h @@ -31,10 +31,12 @@ void convert_nlist( std::vector > & from_nlist ); +int max_numneigh( + const InputNlist & to_nlist + ); // build neighbor list. // outputs - // nlist, max_list_size // max_list_size is the maximal size of jlist. // inputs diff --git a/source/lib/include/prod_env_mat.h b/source/lib/include/prod_env_mat.h index 2b09d07d22..ff12ba1710 100644 --- a/source/lib/include/prod_env_mat.h +++ b/source/lib/include/prod_env_mat.h @@ -1,6 +1,7 @@ #pragma once #include #include "device.h" +#include "neighbor_list.h" template void prod_env_mat_a_cpu( @@ -10,9 +11,7 @@ void prod_env_mat_a_cpu( int * nlist, const FPTYPE * coord, const int * type, - const int * ilist, - const int * jrange, - const int * jlist, + const InputNlist & inlist, const int max_nbor_size, const FPTYPE * avg, const FPTYPE * std, @@ -30,9 +29,7 @@ void prod_env_mat_r_cpu( int * nlist, const FPTYPE * coord, const int * type, - const int * ilist, - const int * jrange, - const int * jlist, + const InputNlist & inlist, const int max_nbor_size, const FPTYPE * avg, const FPTYPE * std, diff --git a/source/lib/src/neighbor_list.cc b/source/lib/src/neighbor_list.cc index 0643037e3f..76eeb4ec17 100644 --- a/source/lib/src/neighbor_list.cc +++ b/source/lib/src/neighbor_list.cc @@ -757,6 +757,18 @@ convert_nlist( } } +int +max_numneigh( + const InputNlist & nlist + ) +{ + int max_num = 0; + for(int ii = 0; ii < nlist.inum; ++ii){ + if(nlist.numneigh[ii] > max_num) max_num = nlist.numneigh[ii]; + } + return max_num; +} + template int build_nlist_cpu( diff --git a/source/lib/src/prod_env_mat.cc b/source/lib/src/prod_env_mat.cc index ce052b3df0..6bad611ed7 100644 --- a/source/lib/src/prod_env_mat.cc +++ b/source/lib/src/prod_env_mat.cc @@ -13,9 +13,7 @@ void prod_env_mat_a_cpu( int * nlist, const FPTYPE * coord, const int * type, - const int * ilist, - const int * jrange, - const int * jlist, + const InputNlist & inlist, const int max_nbor_size, const FPTYPE * avg, const FPTYPE * std, @@ -45,13 +43,14 @@ void prod_env_mat_a_cpu( // build nlist std::vector > d_nlist_a(nloc); + assert(nloc == inlist.inum); for (unsigned ii = 0; ii < nloc; ++ii) { - d_nlist_a.reserve (jrange[nloc] / nloc + 10); + d_nlist_a[ii].reserve(max_nbor_size); } for (unsigned ii = 0; ii < nloc; ++ii) { - int i_idx = ilist[ii]; - for (unsigned jj = jrange[ii]; jj < jrange[ii+1]; ++jj) { - int j_idx = jlist[jj]; + int i_idx = inlist.ilist[ii]; + for(unsigned jj = 0; jj < inlist.numneigh[ii]; ++jj){ + int j_idx = inlist.firstneigh[ii][jj]; d_nlist_a[i_idx].push_back (j_idx); } } @@ -96,9 +95,7 @@ void prod_env_mat_r_cpu( int * nlist, const FPTYPE * coord, const int * type, - const int * ilist, - const int * jrange, - const int * jlist, + const InputNlist & inlist, const int max_nbor_size, const FPTYPE * avg, const FPTYPE * std, @@ -128,13 +125,14 @@ void prod_env_mat_r_cpu( // build nlist std::vector > d_nlist_a(nloc); + assert(nloc == inlist.inum); for (unsigned ii = 0; ii < nloc; ++ii) { - d_nlist_a.reserve (jrange[nloc] / nloc + 10); + d_nlist_a[ii].reserve(max_nbor_size); } for (unsigned ii = 0; ii < nloc; ++ii) { - int i_idx = ilist[ii]; - for (unsigned jj = jrange[ii]; jj < jrange[ii+1]; ++jj) { - int j_idx = jlist[jj]; + int i_idx = inlist.ilist[ii]; + for(unsigned jj = 0; jj < inlist.numneigh[ii]; ++jj){ + int j_idx = inlist.firstneigh[ii][jj]; d_nlist_a[i_idx].push_back (j_idx); } } @@ -180,9 +178,7 @@ void prod_env_mat_a_cpu( int * nlist, const double * coord, const int * type, - const int * ilist, - const int * jrange, - const int * jlist, + const InputNlist & inlist, const int max_nbor_size, const double * avg, const double * std, @@ -200,9 +196,7 @@ void prod_env_mat_a_cpu( int * nlist, const float * coord, const int * type, - const int * ilist, - const int * jrange, - const int * jlist, + const InputNlist & inlist, const int max_nbor_size, const float * avg, const float * std, @@ -220,9 +214,7 @@ void prod_env_mat_r_cpu( int * nlist, const double * coord, const int * type, - const int * ilist, - const int * jrange, - const int * jlist, + const InputNlist & inlist, const int max_nbor_size, const double * avg, const double * std, @@ -240,9 +232,7 @@ void prod_env_mat_r_cpu( int * nlist, const float * coord, const int * type, - const int * ilist, - const int * jrange, - const int * jlist, + const InputNlist & inlist, const int max_nbor_size, const float * avg, const float * std, diff --git a/source/lib/tests/test_env_mat_a.cc b/source/lib/tests/test_env_mat_a.cc index 48f5794f57..c8fe242536 100644 --- a/source/lib/tests/test_env_mat_a.cc +++ b/source/lib/tests/test_env_mat_a.cc @@ -397,15 +397,11 @@ TEST_F(TestEnvMatA, prod_cpu) max_nbor_size = nlist_a_cpy[ii].size(); } } - std::vector ilist(nloc), jlist(tot_nnei), jrange(nloc+1, 0); - for (int ii = 0; ii < nloc; ++ii){ - ilist[ii] = ii; - jrange[ii+1] = jrange[ii] + nlist_a_cpy[ii].size(); - int jj, cc; - for (jj = jrange[ii], cc = 0; jj < jrange[ii+1]; ++jj, ++cc){ - jlist[jj] = nlist_a_cpy[ii][cc]; - } - } + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_a_cpy); + std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); std::vector nlist(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); @@ -417,9 +413,7 @@ TEST_F(TestEnvMatA, prod_cpu) &nlist[0], &posi_cpy[0], &atype_cpy[0], - &ilist[0], - &jrange[0], - &jlist[0], + inlist, max_nbor_size, &avg[0], &std[0], @@ -452,15 +446,10 @@ TEST_F(TestEnvMatA, prod_cpu_equal_cpu) max_nbor_size = nlist_a_cpy[ii].size(); } } - std::vector ilist(nloc), jlist(tot_nnei), jrange(nloc+1, 0); - for (int ii = 0; ii < nloc; ++ii){ - ilist[ii] = ii; - jrange[ii+1] = jrange[ii] + nlist_a_cpy[ii].size(); - int jj, cc; - for (jj = jrange[ii], cc = 0; jj < jrange[ii+1]; ++jj, ++cc){ - jlist[jj] = nlist_a_cpy[ii][cc]; - } - } + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_a_cpy); std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); std::vector nlist(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); @@ -472,9 +461,7 @@ TEST_F(TestEnvMatA, prod_cpu_equal_cpu) &nlist[0], &posi_cpy[0], &atype_cpy[0], - &ilist[0], - &jrange[0], - &jlist[0], + inlist, max_nbor_size, &avg[0], &std[0], diff --git a/source/lib/tests/test_pair_tab.cc b/source/lib/tests/test_pair_tab.cc index 867956e7ae..0c7cf5ea6f 100644 --- a/source/lib/tests/test_pair_tab.cc +++ b/source/lib/tests/test_pair_tab.cc @@ -160,34 +160,34 @@ TEST_F(TestPairTab, cpu) } -int make_inter_nlist( - std::vector &ilist, - std::vector &jrange, - std::vector &jlist, - const int & nloc, - const std::vector> & nlist_cpy) -{ - ilist.resize(nloc); - jrange.resize(nloc+1); - int tot_nnei = 0; - int max_nbor_size = 0; - for(int ii = 0; ii < nlist_cpy.size(); ++ii){ - tot_nnei += nlist_cpy[ii].size(); - if (nlist_cpy[ii].size() > max_nbor_size){ - max_nbor_size = nlist_cpy[ii].size(); - } - } - jlist.resize(tot_nnei); - for (int ii = 0; ii < nloc; ++ii){ - ilist[ii] = ii; - jrange[ii+1] = jrange[ii] + nlist_cpy[ii].size(); - int jj, cc; - for (jj = jrange[ii], cc = 0; jj < jrange[ii+1]; ++jj, ++cc){ - jlist[jj] = nlist_cpy[ii][cc]; - } - } - return max_nbor_size; -} +// int make_inter_nlist( +// std::vector &ilist, +// std::vector &jrange, +// std::vector &jlist, +// const int & nloc, +// const std::vector> & nlist_cpy) +// { +// ilist.resize(nloc); +// jrange.resize(nloc+1); +// int tot_nnei = 0; +// int max_nbor_size = 0; +// for(int ii = 0; ii < nlist_cpy.size(); ++ii){ +// tot_nnei += nlist_cpy[ii].size(); +// if (nlist_cpy[ii].size() > max_nbor_size){ +// max_nbor_size = nlist_cpy[ii].size(); +// } +// } +// jlist.resize(tot_nnei); +// for (int ii = 0; ii < nloc; ++ii){ +// ilist[ii] = ii; +// jrange[ii+1] = jrange[ii] + nlist_cpy[ii].size(); +// int jj, cc; +// for (jj = jrange[ii], cc = 0; jj < jrange[ii+1]; ++jj, ++cc){ +// jlist[jj] = nlist_cpy[ii][cc]; +// } +// } +// return max_nbor_size; +// } TEST_F(TestPairTab, cpu_f_num_deriv) @@ -240,18 +240,22 @@ TEST_F(TestPairTab, cpu_f_num_deriv) std::vector> nlist_cpy_0, nlist_cpy_1, t_nlist; build_nlist(nlist_cpy_0, t_nlist, posi_cpy_0, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); build_nlist(nlist_cpy_1, t_nlist, posi_cpy_1, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); - std::vector ilist_0, jlist_0, jrange_0; - std::vector ilist_1, jlist_1, jrange_1; - int max_nnei_0 = make_inter_nlist(ilist_0, jrange_0, jlist_0, nloc, nlist_cpy_0); - int max_nnei_1 = make_inter_nlist(ilist_1, jrange_1, jlist_1, nloc, nlist_cpy_1); + std::vector ilist_0(nloc), numneigh_0(nloc), ilist_1(nloc), numneigh_1(nloc);; + std::vector firstneigh_0(nloc), firstneigh_1(nloc); + InputNlist inlist_0(nloc, &ilist_0[0], &numneigh_0[0], &firstneigh_0[0]); + InputNlist inlist_1(nloc, &ilist_1[0], &numneigh_1[0], &firstneigh_1[0]); + convert_nlist(inlist_0, nlist_cpy_0); + convert_nlist(inlist_1, nlist_cpy_1); + int max_nnei_0 = max_numneigh(inlist_0); + int max_nnei_1 = max_numneigh(inlist_1); EXPECT_EQ(max_nnei_0, max_nnei_1); std::vector t_em(nloc * ndescrpt), t_em_deriv(nloc * ndescrpt * 3); std::vector rij_0(nloc * nnei * 3), rij_1(nloc * nnei * 3); std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], inlist_0, max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], inlist_1, max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); pair_tab_cpu( @@ -344,18 +348,22 @@ TEST_F(TestPairTab, cpu_f_num_deriv_scale) std::vector> nlist_cpy_0, nlist_cpy_1, t_nlist; build_nlist(nlist_cpy_0, t_nlist, posi_cpy_0, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); build_nlist(nlist_cpy_1, t_nlist, posi_cpy_1, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); - std::vector ilist_0, jlist_0, jrange_0; - std::vector ilist_1, jlist_1, jrange_1; - int max_nnei_0 = make_inter_nlist(ilist_0, jrange_0, jlist_0, nloc, nlist_cpy_0); - int max_nnei_1 = make_inter_nlist(ilist_1, jrange_1, jlist_1, nloc, nlist_cpy_1); + std::vector ilist_0(nloc), numneigh_0(nloc), ilist_1(nloc), numneigh_1(nloc);; + std::vector firstneigh_0(nloc), firstneigh_1(nloc); + InputNlist inlist_0(nloc, &ilist_0[0], &numneigh_0[0], &firstneigh_0[0]); + InputNlist inlist_1(nloc, &ilist_1[0], &numneigh_1[0], &firstneigh_1[0]); + convert_nlist(inlist_0, nlist_cpy_0); + convert_nlist(inlist_1, nlist_cpy_1); + int max_nnei_0 = max_numneigh(inlist_0); + int max_nnei_1 = max_numneigh(inlist_1); EXPECT_EQ(max_nnei_0, max_nnei_1); std::vector t_em(nloc * ndescrpt), t_em_deriv(nloc * ndescrpt * 3); std::vector rij_0(nloc * nnei * 3), rij_1(nloc * nnei * 3); std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], inlist_0, max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], inlist_1, max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); pair_tab_cpu( @@ -461,18 +469,22 @@ TEST_F(TestPairTab, cpu_v_num_deriv) std::vector> nlist_cpy_0, nlist_cpy_1, t_nlist; build_nlist(nlist_cpy_0, t_nlist, posi_cpy_0, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region_0, ncell); build_nlist(nlist_cpy_1, t_nlist, posi_cpy_1, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region_1, ncell); - std::vector ilist_0, jlist_0, jrange_0; - std::vector ilist_1, jlist_1, jrange_1; - int max_nnei_0 = make_inter_nlist(ilist_0, jrange_0, jlist_0, nloc, nlist_cpy_0); - int max_nnei_1 = make_inter_nlist(ilist_1, jrange_1, jlist_1, nloc, nlist_cpy_1); + std::vector ilist_0(nloc), numneigh_0(nloc), ilist_1(nloc), numneigh_1(nloc);; + std::vector firstneigh_0(nloc), firstneigh_1(nloc); + InputNlist inlist_0(nloc, &ilist_0[0], &numneigh_0[0], &firstneigh_0[0]); + InputNlist inlist_1(nloc, &ilist_1[0], &numneigh_1[0], &firstneigh_1[0]); + convert_nlist(inlist_0, nlist_cpy_0); + convert_nlist(inlist_1, nlist_cpy_1); + int max_nnei_0 = max_numneigh(inlist_0); + int max_nnei_1 = max_numneigh(inlist_1); EXPECT_EQ(max_nnei_0, max_nnei_1); std::vector t_em(nloc * ndescrpt), t_em_deriv(nloc * ndescrpt * 3); std::vector rij_0(nloc * nnei * 3), rij_1(nloc * nnei * 3); std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], inlist_0, max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], inlist_1, max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); pair_tab_cpu( @@ -589,18 +601,22 @@ TEST_F(TestPairTab, cpu_v_num_deriv_scale) std::vector> nlist_cpy_0, nlist_cpy_1, t_nlist; build_nlist(nlist_cpy_0, t_nlist, posi_cpy_0, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region_0, ncell); build_nlist(nlist_cpy_1, t_nlist, posi_cpy_1, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region_1, ncell); - std::vector ilist_0, jlist_0, jrange_0; - std::vector ilist_1, jlist_1, jrange_1; - int max_nnei_0 = make_inter_nlist(ilist_0, jrange_0, jlist_0, nloc, nlist_cpy_0); - int max_nnei_1 = make_inter_nlist(ilist_1, jrange_1, jlist_1, nloc, nlist_cpy_1); + std::vector ilist_0(nloc), numneigh_0(nloc), ilist_1(nloc), numneigh_1(nloc);; + std::vector firstneigh_0(nloc), firstneigh_1(nloc); + InputNlist inlist_0(nloc, &ilist_0[0], &numneigh_0[0], &firstneigh_0[0]); + InputNlist inlist_1(nloc, &ilist_1[0], &numneigh_1[0], &firstneigh_1[0]); + convert_nlist(inlist_0, nlist_cpy_0); + convert_nlist(inlist_1, nlist_cpy_1); + int max_nnei_0 = max_numneigh(inlist_0); + int max_nnei_1 = max_numneigh(inlist_1); EXPECT_EQ(max_nnei_0, max_nnei_1); std::vector t_em(nloc * ndescrpt), t_em_deriv(nloc * ndescrpt * 3); std::vector rij_0(nloc * nnei * 3), rij_1(nloc * nnei * 3); std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], inlist_0, max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], inlist_1, max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); pair_tab_cpu( @@ -717,18 +733,22 @@ TEST_F(TestPairTabTriBox, cpu_v_num_deriv) std::vector> nlist_cpy_0, nlist_cpy_1, t_nlist; build_nlist(nlist_cpy_0, t_nlist, posi_cpy_0, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region_0, ncell); build_nlist(nlist_cpy_1, t_nlist, posi_cpy_1, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region_1, ncell); - std::vector ilist_0, jlist_0, jrange_0; - std::vector ilist_1, jlist_1, jrange_1; - int max_nnei_0 = make_inter_nlist(ilist_0, jrange_0, jlist_0, nloc, nlist_cpy_0); - int max_nnei_1 = make_inter_nlist(ilist_1, jrange_1, jlist_1, nloc, nlist_cpy_1); + std::vector ilist_0(nloc), numneigh_0(nloc), ilist_1(nloc), numneigh_1(nloc);; + std::vector firstneigh_0(nloc), firstneigh_1(nloc); + InputNlist inlist_0(nloc, &ilist_0[0], &numneigh_0[0], &firstneigh_0[0]); + InputNlist inlist_1(nloc, &ilist_1[0], &numneigh_1[0], &firstneigh_1[0]); + convert_nlist(inlist_0, nlist_cpy_0); + convert_nlist(inlist_1, nlist_cpy_1); + int max_nnei_0 = max_numneigh(inlist_0); + int max_nnei_1 = max_numneigh(inlist_1); EXPECT_EQ(max_nnei_0, max_nnei_1); std::vector t_em(nloc * ndescrpt), t_em_deriv(nloc * ndescrpt * 3); std::vector rij_0(nloc * nnei * 3), rij_1(nloc * nnei * 3); std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], &ilist_0[0], &jrange_0[0], &jlist_0[0], max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], &ilist_1[0], &jrange_1[0], &jlist_1[0], max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], inlist_0, max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], inlist_1, max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); pair_tab_cpu( diff --git a/source/tests/test_prod_env_mat.py b/source/tests/test_prod_env_mat.py new file mode 100644 index 0000000000..df1d441caa --- /dev/null +++ b/source/tests/test_prod_env_mat.py @@ -0,0 +1,214 @@ +import os,sys +import numpy as np +import unittest + +import deepmd.op +from deepmd.env import tf +from deepmd.env import op_module +from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION + +class TestProdEnvMat(unittest.TestCase): + def setUp(self): + self.sess = tf.Session() + self.nframes = 2 + self.dcoord = [ + 12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56] + self.dtype = [0, 1, 1, 0, 1, 1] + self.dbox = [13., 0., 0., 0., 13., 0., 0., 0., 13.] + self.dcoord = np.reshape(self.dcoord, [1, -1]) + self.dtype = np.reshape(self.dtype, [1, -1]) + self.dbox = np.reshape(self.dbox, [1, -1]) + self.dcoord = np.tile(self.dcoord, [self.nframes, 1]) + self.dtype = np.tile(self.dtype, [self.nframes, 1]) + self.dbox = np.tile(self.dbox, [self.nframes, 1]) + self.pbc_expected_output = [ + 0.12206, 0.12047, 0.01502, -0.01263, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.02167, -0.77271, 0.32370, 0.58475, 0.99745, 0.41810, 0.75655, -0.49773, 0.10564, 0.10495, -0.00143, 0.01198, 0.03103, 0.03041, 0.00452, -0.00425, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + 1.02167, 0.77271, -0.32370, -0.58475, 0.04135, 0.04039, 0.00123, -0.00880, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.59220, 0.42028, 0.16304, -0.38405, 0.03694, 0.03680, -0.00300, -0.00117, 0.00336, 0.00327, 0.00022, -0.00074, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + 0.99745, -0.41810, -0.75655, 0.49773, 0.19078, 0.18961, -0.01951, 0.00793, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.59220, -0.42028, -0.16304, 0.38405, 0.13499, 0.12636, -0.03140, 0.03566, 0.07054, 0.07049, -0.00175, -0.00210, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + 0.12206, -0.12047, -0.01502, 0.01263, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.06176, 0.16913, -0.55250, 0.89077, 1.03163, 0.96880, 0.23422, -0.26615, 0.19078, -0.18961, 0.01951, -0.00793, 0.04135, -0.04039, -0.00123, 0.00880, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + 1.06176, -0.16913, 0.55250, -0.89077, 0.10564, -0.10495, 0.00143, -0.01198, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.66798, 0.34516, 0.32245, -0.47232, 0.13499, -0.12636, 0.03140, -0.03566, 0.03694, -0.03680, 0.00300, 0.00117, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + 1.03163, -0.96880, -0.23422, 0.26615, 0.03103, -0.03041, -0.00452, 0.00425, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.66798, -0.34516, -0.32245, 0.47232, 0.07054, -0.07049, 0.00175, 0.00210, 0.00336, -0.00327, -0.00022, 0.00074, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000] + self.nopbc_expected_output = [ + 0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,1.02167,-0.77271,0.32370,0.58475,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000, + 1.02167,0.77271,-0.32370,-0.58475,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000, + 0.19078,0.18961,-0.01951,0.00793,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.13499,0.12636,-0.03140,0.03566,0.07054,0.07049,-0.00175,-0.00210,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000, + 0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,1.06176,0.16913,-0.55250,0.89077,1.03163,0.96880,0.23422,-0.26615,0.19078,-0.18961,0.01951,-0.00793,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000, + 1.06176,-0.16913,0.55250,-0.89077,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.66798,0.34516,0.32245,-0.47232,0.13499,-0.12636,0.03140,-0.03566,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000, +1.03163,-0.96880,-0.23422,0.26615,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.66798,-0.34516,-0.32245,0.47232,0.07054,-0.07049,0.00175,0.00210,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000] + self.sel = [10, 10] + self.sec = np.array([0, 0, 0], dtype = int) + self.sec[1:3] = np.cumsum(self.sel) + self.rcut = 6. + self.rcut_smth = 0.8 + self.dnatoms = [6, 6, 2, 4] + self.tcoord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, self.dnatoms[0] * 3], name='t_coord') + self.tbox = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, 9], name='t_box') + self.ttype = tf.placeholder(tf.int32, [None, self.dnatoms[0]], name = "t_type") + self.tnatoms = tf.placeholder(tf.int32, [None], name = "t_natoms") + self.nloc = self.dnatoms[0] + self.nall = self.dnatoms[1] + self.nnei = self.sec[-1] + self.ndescrpt = 4 * self.nnei + self.ntypes = np.max(self.dtype) + 1 + davg = np.zeros ([self.ntypes, self.ndescrpt]) + dstd = np.ones ([self.ntypes, self.ndescrpt]) + self.t_avg = tf.constant(davg.astype(GLOBAL_NP_FLOAT_PRECISION)) + self.t_std = tf.constant(dstd.astype(GLOBAL_NP_FLOAT_PRECISION)) + + def test_pbc_self_built_nlist(self): + tem, tem_deriv, trij, tnlist \ + = op_module.descrpt_se_a ( + self.tcoord, + self.ttype, + self.tnatoms, + self.tbox, + tf.constant(np.zeros(6, dtype = np.int32)), + self.t_avg, + self.t_std, + rcut_a = -1, + rcut_r = self.rcut, + rcut_r_smth = self.rcut_smth, + sel_a = self.sel, + sel_r = [0, 0]) + self.sess.run (tf.global_variables_initializer()) + dem, dem_deriv, drij, dnlist = self.sess.run( + [tem, tem_deriv, trij, tnlist], + feed_dict = { + self.tcoord: self.dcoord, + self.ttype: self.dtype, + self.tbox: self.dbox, + self.tnatoms: self.dnatoms} + ) + self.assertEqual(dem.shape, (self.nframes, self.nloc*self.ndescrpt)) + self.assertEqual(dem_deriv.shape, (self.nframes, self.nloc*self.ndescrpt*3)) + self.assertEqual(drij.shape, (self.nframes, self.nloc*self.nnei*3)) + self.assertEqual(dnlist.shape, (self.nframes, self.nloc*self.nnei)) + for ff in range(self.nframes): + for ii in range(self.ndescrpt): + self.assertAlmostEqual(dem[ff][ii], self.pbc_expected_output[ii], places=5) + + def test_pbc_self_built_nlist_deriv(self): + hh = 1e-4 + tem, tem_deriv, trij, tnlist \ + = op_module.descrpt_se_a ( + self.tcoord, + self.ttype, + self.tnatoms, + self.tbox, + tf.constant(np.zeros(6, dtype = np.int32)), + self.t_avg, + self.t_std, + rcut_a = -1, + rcut_r = self.rcut, + rcut_r_smth = self.rcut_smth, + sel_a = self.sel, + sel_r = [0, 0]) + self.sess.run (tf.global_variables_initializer()) + self.check_deriv_numerical_deriv(hh, tem, tem_deriv, trij, tnlist) + + def test_nopbc_self_built_nlist(self): + tem, tem_deriv, trij, tnlist \ + = op_module.descrpt_se_a ( + self.tcoord, + self.ttype, + self.tnatoms, + self.tbox, + tf.constant(np.zeros(0, dtype = np.int32)), + self.t_avg, + self.t_std, + rcut_a = -1, + rcut_r = self.rcut, + rcut_r_smth = self.rcut_smth, + sel_a = self.sel, + sel_r = [0, 0]) + self.sess.run (tf.global_variables_initializer()) + dem, dem_deriv, drij, dnlist = self.sess.run( + [tem, tem_deriv, trij, tnlist], + feed_dict = { + self.tcoord: self.dcoord, + self.ttype: self.dtype, + self.tbox: self.dbox, + self.tnatoms: self.dnatoms} + ) + self.assertEqual(dem.shape, (self.nframes, self.nloc*self.ndescrpt)) + self.assertEqual(dem_deriv.shape, (self.nframes, self.nloc*self.ndescrpt*3)) + self.assertEqual(drij.shape, (self.nframes, self.nloc*self.nnei*3)) + self.assertEqual(dnlist.shape, (self.nframes, self.nloc*self.nnei)) + for ff in range(self.nframes): + for ii in range(self.ndescrpt): + self.assertAlmostEqual(dem[ff][ii], self.nopbc_expected_output[ii], places=5) + + + def test_nopbc_self_built_nlist_deriv(self): + hh = 1e-4 + tem, tem_deriv, trij, tnlist \ + = op_module.descrpt_se_a ( + self.tcoord, + self.ttype, + self.tnatoms, + self.tbox, + tf.constant(np.zeros(0, dtype = np.int32)), + self.t_avg, + self.t_std, + rcut_a = -1, + rcut_r = self.rcut, + rcut_r_smth = self.rcut_smth, + sel_a = self.sel, + sel_r = [0, 0]) + self.sess.run (tf.global_variables_initializer()) + self.check_deriv_numerical_deriv(hh, tem, tem_deriv, trij, tnlist) + + + def check_deriv_numerical_deriv(self, + hh, + tem, tem_deriv, trij, tnlist): + dem_, dem_deriv_, drij_, dnlist_ = self.sess.run( + [tem, tem_deriv, trij, tnlist], + feed_dict = { + self.tcoord: self.dcoord, + self.ttype: self.dtype, + self.tbox: self.dbox, + self.tnatoms: self.dnatoms} + ) + ff = 0 + dem = dem_[ff] + dem_deriv = dem_deriv_[ff] + dnlist = dnlist_[ff] + for ii in range(self.dnatoms[0]): + for jj in range(self.nnei): + j_idx = dnlist[ii*self.nnei+jj] + if j_idx < 0: + continue + for kk in range(4): + for dd in range(3): + dcoord_0 = np.copy(self.dcoord) + dcoord_1 = np.copy(self.dcoord) + dcoord_0[ff][j_idx*3+dd] -= hh + dcoord_1[ff][j_idx*3+dd] += hh + dem_0, dem_deriv_0, drij_0, dnlist_0 = self.sess.run( + [tem, tem_deriv, trij, tnlist], + feed_dict = { + self.tcoord: dcoord_0, + self.ttype: self.dtype, + self.tbox: self.dbox, + self.tnatoms: self.dnatoms} + ) + dem_1, dem_deriv_1, drij_1, dnlist_1 = self.sess.run( + [tem, tem_deriv, trij, tnlist], + feed_dict = { + self.tcoord: dcoord_1, + self.ttype: self.dtype, + self.tbox: self.dbox, + self.tnatoms: self.dnatoms} + ) + num_deriv = (dem_1[0][ii*self.nnei*4+jj*4+kk] - dem_0[0][ii*self.ndescrpt+jj*4+kk]) / (2.*hh) + ana_deriv = -dem_deriv[ii*self.nnei*4*3+jj*4*3+kk*3+dd] + self.assertAlmostEqual(num_deriv, ana_deriv, places = 5) + From 226e79f12ee9517ae80a84fa24252c270b74fc62 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Fri, 5 Mar 2021 09:41:49 +0800 Subject: [PATCH 238/562] initialize cpu memory before it copies to the device --- source/lib/tests/test_env_mat_a.cc | 8 ++++---- source/lib/tests/test_env_mat_r.cc | 8 ++++---- source/lib/tests/test_gelu.cc | 6 +++--- source/lib/tests/test_prod_force_a.cc | 2 +- source/lib/tests/test_prod_force_r.cc | 2 +- source/lib/tests/test_prod_virial_a.cc | 4 ++-- source/lib/tests/test_prod_virial_r.cc | 4 ++-- source/lib/tests/test_tabulate.cc | 6 +++--- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/source/lib/tests/test_env_mat_a.cc b/source/lib/tests/test_env_mat_a.cc index af3160ebf3..85d66ec5dd 100644 --- a/source/lib/tests/test_env_mat_a.cc +++ b/source/lib/tests/test_env_mat_a.cc @@ -555,8 +555,8 @@ TEST_F(TestEnvMatA, prod_gpu_cuda) jlist[jj] = nlist_a_cpy[ii][cc]; } } - std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); - std::vector nlist(nloc * nnei); + std::vector em(nloc * ndescrpt, 0.0), em_deriv(nloc * ndescrpt * 3, 0.0), rij(nloc * nnei * 3, 0.0); + std::vector nlist(nloc * nnei, 0); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); @@ -656,8 +656,8 @@ TEST_F(TestEnvMatA, prod_gpu_cuda_equal_cpu) jlist[jj] = nlist_a_cpy[ii][cc]; } } - std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); - std::vector nlist(nloc * nnei); + std::vector em(nloc * ndescrpt, 0.0), em_deriv(nloc * ndescrpt * 3, 0.0), rij(nloc * nnei * 3, 0.0); + std::vector nlist(nloc * nnei, 0); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); diff --git a/source/lib/tests/test_env_mat_r.cc b/source/lib/tests/test_env_mat_r.cc index b3947936a3..d70e5ef0fe 100644 --- a/source/lib/tests/test_env_mat_r.cc +++ b/source/lib/tests/test_env_mat_r.cc @@ -397,8 +397,8 @@ TEST_F(TestEnvMatR, prod_gpu_cuda) jlist[jj] = nlist_a_cpy[ii][cc]; } } - std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); - std::vector nlist(nloc * nnei); + std::vector em(nloc * ndescrpt, 0.0), em_deriv(nloc * ndescrpt * 3, 0.0), rij(nloc * nnei * 3, 0.0); + std::vector nlist(nloc * nnei, 0); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); @@ -497,8 +497,8 @@ TEST_F(TestEnvMatR, prod_gpu_cuda_equal_cpu) jlist[jj] = nlist_a_cpy[ii][cc]; } } - std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); - std::vector nlist(nloc * nnei); + std::vector em(nloc * ndescrpt, 0.0), em_deriv(nloc * ndescrpt * 3, 0.0), rij(nloc * nnei * 3, 0.0); + std::vector nlist(nloc * nnei, 0); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); diff --git a/source/lib/tests/test_gelu.cc b/source/lib/tests/test_gelu.cc index e9f84f3fee..f8a65ae308 100644 --- a/source/lib/tests/test_gelu.cc +++ b/source/lib/tests/test_gelu.cc @@ -148,7 +148,7 @@ TEST_F(TestGelu, gelu_grad_grad_cpu) #if GOOGLE_CUDA TEST_F(TestGelu, gelu_gpu_cuda) { - std::vector gelu(nloc); + std::vector gelu(nloc, 0.0); double * gelu_dev = NULL, * xx_dev = NULL; malloc_device_memory_sync(gelu_dev, gelu); @@ -168,7 +168,7 @@ TEST_F(TestGelu, gelu_gpu_cuda) TEST_F(TestGelu, gelu_grad_gpu_cuda) { std::vector dy(100, 1.0); - std::vector gelu_grad(nloc); + std::vector gelu_grad(nloc, 0.0); double * gelu_grad_dev = NULL, * xx_dev = NULL, * dy_dev = NULL; malloc_device_memory_sync(gelu_grad_dev, gelu_grad); @@ -191,7 +191,7 @@ TEST_F(TestGelu, gelu_grad_grad_gpu_cuda) { std::vector dy(100, 1.0); std::vector dy_2(100, 1.0); - std::vector gelu_grad_grad(nloc); + std::vector gelu_grad_grad(nloc, 0.0); double * gelu_grad_grad_dev = NULL, * xx_dev = NULL, * dy_dev = NULL, * dy_2_dev = NULL; malloc_device_memory_sync(gelu_grad_grad_dev, gelu_grad_grad); diff --git a/source/lib/tests/test_prod_force_a.cc b/source/lib/tests/test_prod_force_a.cc index ba24a7c85b..7cd76e6ed7 100644 --- a/source/lib/tests/test_prod_force_a.cc +++ b/source/lib/tests/test_prod_force_a.cc @@ -101,7 +101,7 @@ TEST_F(TestProdForceA, cpu) #if GOOGLE_CUDA TEST_F(TestProdForceA, gpu_cuda) { - std::vector force(nall * 3); + std::vector force(nall * 3, 0.0); int n_a_sel = nnei; int * nlist_dev = NULL; diff --git a/source/lib/tests/test_prod_force_r.cc b/source/lib/tests/test_prod_force_r.cc index 87eb331cdf..6a3d68576b 100644 --- a/source/lib/tests/test_prod_force_r.cc +++ b/source/lib/tests/test_prod_force_r.cc @@ -101,7 +101,7 @@ TEST_F(TestProdForceR, cpu) #if GOOGLE_CUDA TEST_F(TestProdForceR, gpu_cuda) { - std::vector force(nall * 3); + std::vector force(nall * 3, 0.0); int n_a_sel = nnei; int * nlist_dev = NULL; diff --git a/source/lib/tests/test_prod_virial_a.cc b/source/lib/tests/test_prod_virial_a.cc index 56a8512b43..aa0e7bfac9 100644 --- a/source/lib/tests/test_prod_virial_a.cc +++ b/source/lib/tests/test_prod_virial_a.cc @@ -116,8 +116,8 @@ TEST_F(TestProdVirialA, cpu) #if GOOGLE_CUDA TEST_F(TestProdVirialA, gpu_cuda) { - std::vector virial(9); - std::vector atom_virial(nall * 9); + std::vector virial(9, 0.0); + std::vector atom_virial(nall * 9, 0.0); int n_a_sel = nnei; int * nlist_dev = NULL; diff --git a/source/lib/tests/test_prod_virial_r.cc b/source/lib/tests/test_prod_virial_r.cc index 176d1f2f64..c09a2f04ad 100644 --- a/source/lib/tests/test_prod_virial_r.cc +++ b/source/lib/tests/test_prod_virial_r.cc @@ -116,8 +116,8 @@ TEST_F(TestProdVirialR, cpu) #if GOOGLE_CUDA TEST_F(TestProdVirialR, gpu_cuda) { - std::vector virial(9); - std::vector atom_virial(nall * 9); + std::vector virial(9, 0.0); + std::vector atom_virial(nall * 9, 0.0); int n_a_sel = nnei; int * nlist_dev = NULL; diff --git a/source/lib/tests/test_tabulate.cc b/source/lib/tests/test_tabulate.cc index bf31cfb325..a17f2474b7 100644 --- a/source/lib/tests/test_tabulate.cc +++ b/source/lib/tests/test_tabulate.cc @@ -176,7 +176,7 @@ TEST_F(TestTabulate, tabulate_fusion_grad_cpu) #if GOOGLE_CUDA TEST_F(TestTabulate, tabulate_fusion_gpu_cuda) { - std::vector xyz_scatter(nloc * nnei * last_layer_size); + std::vector xyz_scatter(nloc * nnei * last_layer_size, 0.0); double * xyz_scatter_dev = NULL, * table_dev = NULL, * em_x_dev = NULL, * em_dev = NULL; malloc_device_memory_sync(xyz_scatter_dev, xyz_scatter); @@ -199,8 +199,8 @@ TEST_F(TestTabulate, tabulate_fusion_gpu_cuda) TEST_F(TestTabulate, tabulate_fusion_grad_gpu_cuda) { - std::vector dy_dem_x(em_x.size()); - std::vector dy_dem(em.size()); + std::vector dy_dem_x(em_x.size(), 0.0); + std::vector dy_dem(em.size(), 0.0); std::vector dy(nloc * nnei * last_layer_size, 1.0); double * dy_dem_x_dev = NULL, * dy_dem_dev = NULL, * table_dev = NULL, * em_x_dev = NULL, * em_dev = NULL, * dy_dev = NULL; From 08a14c172501ebe943c0ef23f7ba0fb6637216e4 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 5 Mar 2021 11:54:02 +0800 Subject: [PATCH 239/562] CPU implementation of op prod_env_mat --- source/lib/include/neighbor_list.h | 5 +- source/op/CMakeLists.txt | 2 +- source/op/prod_env_mat_multi_device.cc | 225 +++++++++++++++++++++---- source/tests/test_prod_env_mat.py | 8 +- 4 files changed, 202 insertions(+), 38 deletions(-) diff --git a/source/lib/include/neighbor_list.h b/source/lib/include/neighbor_list.h index 3dfed7ab40..58d5f150ed 100644 --- a/source/lib/include/neighbor_list.h +++ b/source/lib/include/neighbor_list.h @@ -16,6 +16,9 @@ struct InputNlist int * ilist; int * numneigh; int ** firstneigh; + InputNlist () + : inum(0), ilist(NULL), numneigh(NULL), firstneigh(NULL) + {}; InputNlist ( int inum_, int * ilist_, @@ -23,7 +26,7 @@ struct InputNlist int ** firstneigh_ ) : inum(inum_), ilist(ilist_), numneigh(numneigh_), firstneigh(firstneigh_) - {} + {}; }; void convert_nlist( diff --git a/source/op/CMakeLists.txt b/source/op/CMakeLists.txt index 67ffc7f844..ced3cd0bf5 100644 --- a/source/op/CMakeLists.txt +++ b/source/op/CMakeLists.txt @@ -3,7 +3,7 @@ set(OP_LIB ${PROJECT_SOURCE_DIR}/lib/src/SimulationRegion.cpp ${PROJECT_SOURCE_DIR}/lib/src/neighbor_list.cc) set (OP_CXX_FLAG -D_GLIBCXX_USE_CXX11_ABI=${OP_CXX_ABI} ) -file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc descrpt_se_r.cc pair_tab.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc gelu_multi_device.cc map_aparam.cc neighbor_stat.cc unaggregated_grad.cc tabulate_multi_device.cc) +file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc descrpt_se_r.cc pair_tab.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc gelu_multi_device.cc map_aparam.cc neighbor_stat.cc unaggregated_grad.cc tabulate_multi_device.cc prod_env_mat_multi_device.cc) file(GLOB OP_CUDA_SRC prod_force.cc prod_virial.cc descrpt.cc prod_env_mat_multi_device.cc pair_tab.cc prod_force_multi_device.cc prod_virial_multi_device.cc soft_min.cc soft_min_force.cc soft_min_virial.cc gelu_multi_device.cc tabulate_multi_device.cc) file(GLOB OP_GRADS_SRC prod_force_grad.cc prod_force_se_a_grad.cc prod_force_se_r_grad.cc prod_virial_grad.cc prod_virial_se_a_grad.cc prod_virial_se_r_grad.cc soft_min_force_grad.cc soft_min_virial_grad.cc ) file(GLOB OP_PY *.py) diff --git a/source/op/prod_env_mat_multi_device.cc b/source/op/prod_env_mat_multi_device.cc index a50461a274..d332d492b1 100644 --- a/source/op/prod_env_mat_multi_device.cc +++ b/source/op/prod_env_mat_multi_device.cc @@ -1,8 +1,11 @@ #include "custom_op.h" #include "utilities.h" +#include "coord.h" +#include "region.h" +#include "neighbor_list.h" #include "prod_env_mat.h" -REGISTER_OP("DescrptSeA") +REGISTER_OP("ProdEnvMatA") .Attr("T: {float, double}") .Input("coord: T") //atomic coordinates .Input("type: int32") //atomic type @@ -22,7 +25,7 @@ REGISTER_OP("DescrptSeA") .Output("nlist: int32"); // only sel_a and rcut_r uesd. -REGISTER_OP("DescrptSeR") +REGISTER_OP("ProdEnvMatR") .Attr("T: {float, double}") .Input("coord: T") .Input("type: int32") @@ -40,9 +43,9 @@ REGISTER_OP("DescrptSeR") .Output("nlist: int32"); template -class DescrptSeAOp : public OpKernel { +class ProdEnvMatAOp : public OpKernel { public: - explicit DescrptSeAOp(OpKernelConstruction* context) : OpKernel(context) { + explicit ProdEnvMatAOp(OpKernelConstruction* context) : OpKernel(context) { float nloc_f, nall_f; OP_REQUIRES_OK(context, context->GetAttr("rcut_a", &rcut_a)); OP_REQUIRES_OK(context, context->GetAttr("rcut_r", &rcut_r)); @@ -60,6 +63,10 @@ class DescrptSeAOp : public OpKernel { nnei_r = sec_r.back(); nnei = nnei_a + nnei_r; max_nbor_size = 1024; + max_cpy_trial = 100; + mem_cpy = 256; + max_nnei_trial = 100; + mem_nnei = 256; } void Compute(OpKernelContext* context) override { @@ -105,6 +112,28 @@ class DescrptSeAOp : public OpKernel { OP_REQUIRES (context, (ntypes == int(sel_a.size())), errors::InvalidArgument ("number of types should match the length of sel array")); OP_REQUIRES (context, (ntypes == int(sel_r.size())), errors::InvalidArgument ("number of types should match the length of sel array")); + + int nei_mode = 0; + bool b_nlist_map = false; + if (mesh_tensor.shape().dim_size(0) == 16) { + // lammps neighbor list + nei_mode = 3; + } + else if (mesh_tensor.shape().dim_size(0) == 6) { + // manual copied pbc + assert (nloc == nall); + nei_mode = 1; + b_nlist_map = true; + } + else if (mesh_tensor.shape().dim_size(0) == 0) { + // no pbc + assert (nloc == nall); + nei_mode = -1; + } + else { + throw std::runtime_error("invalid mesh tensor"); + } + // Create output tensors TensorShape descrpt_shape ; descrpt_shape.AddDim (nsamples); @@ -141,16 +170,29 @@ class DescrptSeAOp : public OpKernel { nlist_shape, &nlist_tensor)); - FPTYPE * em = descrpt_tensor->flat().data(); - FPTYPE * em_deriv = descrpt_deriv_tensor->flat().data(); - FPTYPE * rij = rij_tensor->flat().data(); - int * nlist = nlist_tensor->flat().data(); - const FPTYPE * coord = coord_tensor.flat().data(); + FPTYPE * p_em = descrpt_tensor->flat().data(); + FPTYPE * p_em_deriv = descrpt_deriv_tensor->flat().data(); + FPTYPE * p_rij = rij_tensor->flat().data(); + int * p_nlist = nlist_tensor->flat().data(); + const FPTYPE * p_coord = coord_tensor.flat().data(); + const FPTYPE * p_box = box_tensor.flat().data(); const FPTYPE * avg = avg_tensor.flat().data(); const FPTYPE * std = std_tensor.flat().data(); - const int * type = type_tensor.flat().data(); + const int * p_type = type_tensor.flat().data(); + + // loop over samples + for(int ff = 0; ff < nsamples; ++ff){ + FPTYPE * em = p_em + ff*nloc*ndescrpt; + FPTYPE * em_deriv = p_em_deriv + ff*nloc*ndescrpt*3; + FPTYPE * rij = p_rij + ff*nloc*nnei*3; + int * nlist = p_nlist + ff*nloc*nnei; + const FPTYPE * coord = p_coord + ff*nall*3; + const FPTYPE * box = p_box + ff*9; + const int * type = p_type + ff*nall; + std::vector idx_mapping; if(device == "GPU") { + #if GOOGLE_CUDA // allocate temp memory, temp memory must not be used after this operation! Tensor int_temp; TensorShape int_shape; @@ -166,7 +208,6 @@ class DescrptSeAOp : public OpKernel { init, ilist, jrange, jlist, ilist_size, jrange_size, jlist_size, max_nbor_size, mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); OP_REQUIRES (context, (max_nbor_size <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than " + std::to_string(GPU_MAX_NBOR_SIZE) + ", which currently is not supported by deepmd-kit.")); - #if GOOGLE_CUDA // launch the gpu(nv) compute function prod_env_mat_a_gpu_cuda( em, em_deriv, rij, nlist, @@ -174,13 +215,95 @@ class DescrptSeAOp : public OpKernel { #endif //GOOGLE_CUDA } else if (device == "CPU") { - memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy (&jrange, 8 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy (&jlist, 12 + mesh_tensor.flat().data(), sizeof(int *)); + // build nlist by myself + if(nei_mode != 3){ + std::vector coord_cpy; + std::vector type_cpy; + int new_nall = nall; + // normalize and copy coord + if(nei_mode == 1){ + std::vector tmp_coord(nall*3); + std::copy(coord, coord+nall*3, tmp_coord.begin()); + Region region; + init_region_cpu(region, box); + normalize_coord_cpu(&tmp_coord[0], nall, region); + int tt; + for(tt = 0; tt < max_cpy_trial; ++tt){ + coord_cpy.resize(mem_cpy*3); + type_cpy.resize(mem_cpy); + idx_mapping.resize(mem_cpy); + int ret = copy_coord_cpu( + &coord_cpy[0], &type_cpy[0], &idx_mapping[0], &new_nall, + &tmp_coord[0], type, nloc, mem_cpy, rcut_r, region); + if(ret == 0){ + break; + } + else{ + mem_cpy *= 2; + } + } + OP_REQUIRES (context, (tt != max_cpy_trial), + errors::Aborted("cannot allocate mem for copied coords")); + coord = &coord_cpy[0]; + type = &type_cpy[0]; + } + // build nlist + int tt; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + std::vector> jlist(nloc); + for(tt = 0; tt < max_nnei_trial; ++tt){ + for(int ii = 0; ii < nloc; ++ii){ + jlist[ii].resize(mem_nnei); + firstneigh[ii] = &jlist[ii][0]; + } + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + int new_mem_nnei = 0; + int ret = build_nlist_cpu( + inlist, &new_mem_nnei, + coord, nloc, new_nall, mem_nnei, rcut_r); + if(ret == 0){ + break; + } + else{ + mem_nnei *= 2; + } + } + OP_REQUIRES (context, (tt != max_nnei_trial), + errors::Aborted("cannot allocate mem for nlist")); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + max_nbor_size = max_numneigh(inlist); + // prod env mat + prod_env_mat_a_cpu( + em, em_deriv, rij, nlist, + coord, type, inlist, max_nbor_size, avg, std, nloc, new_nall, rcut_r, rcut_r_smth, sec_a); + // do nlist mapping if coords were copied + if(b_nlist_map){ + for (int ii = 0; ii < nloc; ++ii){ + for (int jj = 0; jj < nnei; ++jj){ + int record = nlist[ii*nnei+jj]; + if (record >= 0) { + nlist[ii*nnei+jj] = idx_mapping[record]; + } + } + } + } + } + else{ + // copy pointers to nlist data + InputNlist inlist; + inlist.inum = nloc; + memcpy(&inlist.ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); + memcpy(&inlist.numneigh, 8 + mesh_tensor.flat().data(), sizeof(int *)); + memcpy(&inlist.firstneigh, 12 + mesh_tensor.flat().data(), sizeof(int **)); + max_nbor_size = max_numneigh(inlist); + // prod env mat + prod_env_mat_a_cpu( + em, em_deriv, rij, nlist, + coord, type, inlist, max_nbor_size, avg, std, nloc, nall, rcut_r, rcut_r_smth, sec_a); + } // launch the cpu compute function - prod_env_mat_a_cpu( - em, em_deriv, rij, nlist, - coord, type, ilist, jrange, jlist, max_nbor_size, avg, std, nloc, nall, rcut_r, rcut_r_smth, sec_a); + } } } @@ -195,18 +318,20 @@ class DescrptSeAOp : public OpKernel { std::vector sec_r; int ndescrpt, ndescrpt_a, ndescrpt_r; int nnei, nnei_a, nnei_r, nloc, nall, max_nbor_size; + int mem_cpy, max_cpy_trial; + int mem_nnei, max_nnei_trial; std::string device; int * array_int = NULL; unsigned long long * array_longlong = NULL; bool init = false; - int * ilist = NULL, * jrange = NULL, * jlist = NULL; + InputNlist inlist; int ilist_size = 0, jrange_size = 0, jlist_size = 0; }; template -class DescrptSeROp : public OpKernel { +class ProdEnvMatROp : public OpKernel { public: - explicit DescrptSeROp(OpKernelConstruction* context) : OpKernel(context) { + explicit ProdEnvMatROp(OpKernelConstruction* context) : OpKernel(context) { OP_REQUIRES_OK(context, context->GetAttr("rcut", &rcut)); OP_REQUIRES_OK(context, context->GetAttr("rcut_smth", &rcut_smth)); OP_REQUIRES_OK(context, context->GetAttr("sel", &sel)); @@ -304,6 +429,7 @@ class DescrptSeROp : public OpKernel { const int * type = type_tensor.flat().data(); if(device == "GPU") { + #if GOOGLE_CUDA // allocate temp memory, temp memory must not be used after this operation! Tensor int_temp; TensorShape int_shape; @@ -319,7 +445,6 @@ class DescrptSeROp : public OpKernel { init, ilist, jrange, jlist, ilist_size, jrange_size, jlist_size, max_nbor_size, mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); OP_REQUIRES (context, (max_nbor_size <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than " + std::to_string(GPU_MAX_NBOR_SIZE) + ", which currently is not supported by deepmd-kit.")); - #if GOOGLE_CUDA // launch the gpu(nv) compute function prod_env_mat_r_gpu_cuda( em, em_deriv, rij, nlist, @@ -331,9 +456,9 @@ class DescrptSeROp : public OpKernel { memcpy (&jrange, 8 + mesh_tensor.flat().data(), sizeof(int *)); memcpy (&jlist, 12 + mesh_tensor.flat().data(), sizeof(int *)); // launch the cpu compute function - prod_env_mat_r_cpu( - em, em_deriv, rij, nlist, - coord, type, ilist, jrange, jlist, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); + // prod_env_mat_r_cpu( + // em, em_deriv, rij, nlist, + // coord, type, ilist, jrange, jlist, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); } } @@ -355,14 +480,50 @@ class DescrptSeROp : public OpKernel { int ilist_size = 0, jrange_size = 0, jlist_size = 0; }; +// template +// static int +// norm_copy_coord( +// std::vector & coord_cpy, +// std::vector & type_cpy, +// std::vector & mapping, +// int & mem_cpy, +// const FPTYPE * coord, +// const FPTYPE * box, +// const int * type, +// const int &nloc, +// const int &max_cpy_trial) +// { +// std::vector tmp_coord(nall*3); +// std::copy(coord, coord+nall*3, tmp_coord.begin()); +// Region region; +// init_region_cpu(region, box); +// normalize_coord_cpu(&tmp_coord[0], nall, region); +// int tt; +// for(tt = 0; tt < max_cpy_trial; ++tt){ +// coord_cpy.resize(mem_cpy*3); +// type_cpy.resize(mem_cpy); +// idx_mapping.resize(mem_cpy); +// int ret = copy_coord_cpu( +// &coord_cpy[0], &type_cpy[0], &idx_mapping[0], &new_nall, +// &tmp_coord[0], type, nloc, mem_cpy, rcut_r, region); +// if(ret == 0){ +// break; +// } +// else{ +// mem_cpy *= 2; +// } +// } +// return (tt != max_cpy_trial) +// } + // Register the CPU kernels. #define REGISTER_CPU(T) \ REGISTER_KERNEL_BUILDER( \ - Name("DescrptSeA").Device(DEVICE_CPU).TypeConstraint("T"), \ - DescrptSeAOp); \ + Name("ProdEnvMatA").Device(DEVICE_CPU).TypeConstraint("T"), \ + ProdEnvMatAOp); \ REGISTER_KERNEL_BUILDER( \ - Name("DescrptSeR").Device(DEVICE_CPU).TypeConstraint("T"), \ - DescrptSeROp); + Name("ProdEnvMatR").Device(DEVICE_CPU).TypeConstraint("T"), \ + ProdEnvMatROp); REGISTER_CPU(float); REGISTER_CPU(double); @@ -370,11 +531,11 @@ REGISTER_CPU(double); #if GOOGLE_CUDA #define REGISTER_GPU(T) \ REGISTER_KERNEL_BUILDER( \ - Name("DescrptSeA").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ - DescrptSeAOp); \ + Name("ProdEnvMatA").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ + ProdEnvMatAOp); \ REGISTER_KERNEL_BUILDER( \ - Name("DescrptSeR").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ - DescrptSeROp); + Name("ProdEnvMatR").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ + ProdEnvMatROp); REGISTER_GPU(float); REGISTER_GPU(double); #endif // GOOGLE_CUDA diff --git a/source/tests/test_prod_env_mat.py b/source/tests/test_prod_env_mat.py index df1d441caa..347eb913ea 100644 --- a/source/tests/test_prod_env_mat.py +++ b/source/tests/test_prod_env_mat.py @@ -64,7 +64,7 @@ def setUp(self): def test_pbc_self_built_nlist(self): tem, tem_deriv, trij, tnlist \ - = op_module.descrpt_se_a ( + = op_module.prod_env_mat_a ( self.tcoord, self.ttype, self.tnatoms, @@ -97,7 +97,7 @@ def test_pbc_self_built_nlist(self): def test_pbc_self_built_nlist_deriv(self): hh = 1e-4 tem, tem_deriv, trij, tnlist \ - = op_module.descrpt_se_a ( + = op_module.prod_env_mat_a ( self.tcoord, self.ttype, self.tnatoms, @@ -115,7 +115,7 @@ def test_pbc_self_built_nlist_deriv(self): def test_nopbc_self_built_nlist(self): tem, tem_deriv, trij, tnlist \ - = op_module.descrpt_se_a ( + = op_module.prod_env_mat_a ( self.tcoord, self.ttype, self.tnatoms, @@ -149,7 +149,7 @@ def test_nopbc_self_built_nlist(self): def test_nopbc_self_built_nlist_deriv(self): hh = 1e-4 tem, tem_deriv, trij, tnlist \ - = op_module.descrpt_se_a ( + = op_module.prod_env_mat_a ( self.tcoord, self.ttype, self.tnatoms, From 2cd76847c6c42b48b88c981e43a0862613e3f133 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 5 Mar 2021 14:24:43 +0800 Subject: [PATCH 240/562] shutdown the verbose debug information in test --- source/tests/test_data_modifier.py | 2 +- source/tests/test_data_modifier_shuffle.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/tests/test_data_modifier.py b/source/tests/test_data_modifier.py index d6574e39c8..70999f5734 100644 --- a/source/tests/test_data_modifier.py +++ b/source/tests/test_data_modifier.py @@ -43,7 +43,7 @@ def _setUp(self): restart=None, init_model=None, log_path=None, - log_level=0, + log_level=30, mpi_log="master", try_distrib=False ) diff --git a/source/tests/test_data_modifier_shuffle.py b/source/tests/test_data_modifier_shuffle.py index 9057ba5836..39269c2ff5 100644 --- a/source/tests/test_data_modifier_shuffle.py +++ b/source/tests/test_data_modifier_shuffle.py @@ -48,7 +48,7 @@ def _setUp(self): restart=None, init_model=None, log_path=None, - log_level=0, + log_level=30, mpi_log="master", try_distrib=False ) From b49add0092f4d3bec6a6b22c6971aaeadd620837 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 5 Mar 2021 14:26:17 +0800 Subject: [PATCH 241/562] cleanup the code. switch to prod_env_mat_a in training --- deepmd/descriptor/se_a.py | 4 +- source/lib/src/coord.cc | 3 +- source/lib/src/neighbor_list.cc | 3 +- source/op/prod_env_mat_multi_device.cc | 227 +++++++++++++++---------- source/tests/test_descrpt_smooth.py | 2 +- 5 files changed, 146 insertions(+), 93 deletions(-) diff --git a/deepmd/descriptor/se_a.py b/deepmd/descriptor/se_a.py index 2d03635e00..3d502730de 100644 --- a/deepmd/descriptor/se_a.py +++ b/deepmd/descriptor/se_a.py @@ -112,7 +112,7 @@ def __init__ (self, self.place_holders['natoms_vec'] = tf.placeholder(tf.int32, [self.ntypes+2], name=name_pfx+'t_natoms') self.place_holders['default_mesh'] = tf.placeholder(tf.int32, [None], name=name_pfx+'t_mesh') self.stat_descrpt, descrpt_deriv, rij, nlist \ - = op_module.descrpt_se_a(self.place_holders['coord'], + = op_module.prod_env_mat_a(self.place_holders['coord'], self.place_holders['type'], self.place_holders['natoms_vec'], self.place_holders['box'], @@ -340,7 +340,7 @@ def build (self, atype = tf.reshape (atype_, [-1, natoms[1]]) self.descrpt, self.descrpt_deriv, self.rij, self.nlist \ - = op_module.descrpt_se_a (coord, + = op_module.prod_env_mat_a (coord, atype, natoms, box, diff --git a/source/lib/src/coord.cc b/source/lib/src/coord.cc index 5066eac2a5..fb57b2c403 100644 --- a/source/lib/src/coord.cc +++ b/source/lib/src/coord.cc @@ -33,10 +33,11 @@ copy_coord_cpu( const FPTYPE * in_c, const int * in_t, const int & nloc, - const int & mem_nall, + const int & mem_nall_, const float & rcut, const Region & region) { + const int mem_nall = mem_nall_; std::vector coord(nloc * 3); std::vector atype(nloc); std::copy(in_c, in_c+nloc*3, coord.begin()); diff --git a/source/lib/src/neighbor_list.cc b/source/lib/src/neighbor_list.cc index 76eeb4ec17..6a603dc94e 100644 --- a/source/lib/src/neighbor_list.cc +++ b/source/lib/src/neighbor_list.cc @@ -777,9 +777,10 @@ build_nlist_cpu( const FPTYPE * c_cpy, const int & nloc, const int & nall, - const int & mem_size, + const int & mem_size_, const float & rcut) { + const int mem_size = mem_size_; *max_list_size = 0; nlist.inum = nloc; FPTYPE rcut2 = rcut * rcut; diff --git a/source/op/prod_env_mat_multi_device.cc b/source/op/prod_env_mat_multi_device.cc index d332d492b1..56f50e75b1 100644 --- a/source/op/prod_env_mat_multi_device.cc +++ b/source/op/prod_env_mat_multi_device.cc @@ -42,6 +42,45 @@ REGISTER_OP("ProdEnvMatR") .Output("rij: T") .Output("nlist: int32"); + +template +static int +_norm_copy_coord_cpu( + std::vector & coord_cpy, + std::vector & type_cpy, + std::vector & mapping, + int & nall, + int & mem_cpy, + const FPTYPE * coord, + const FPTYPE * box, + const int * type, + const int &nloc, + const int &max_cpy_trial, + const float & rcut_r); + +template +static int +_build_nlist_cpu( + std::vector &firstneigh, + std::vector> &jlist, + int & max_nnei, + int & mem_nnei, + std::vector &ilist, + std::vector &numneigh, + const FPTYPE *coord, + const int & nloc, + const int & new_nall, + const int & max_nnei_trial, + const float & rcut_r); + +static void +_map_nlist( + int * nlist, + const int * idx_mapping, + const int & nloc, + const int & nnei); + + template class ProdEnvMatAOp : public OpKernel { public: @@ -222,72 +261,28 @@ class ProdEnvMatAOp : public OpKernel { int new_nall = nall; // normalize and copy coord if(nei_mode == 1){ - std::vector tmp_coord(nall*3); - std::copy(coord, coord+nall*3, tmp_coord.begin()); - Region region; - init_region_cpu(region, box); - normalize_coord_cpu(&tmp_coord[0], nall, region); - int tt; - for(tt = 0; tt < max_cpy_trial; ++tt){ - coord_cpy.resize(mem_cpy*3); - type_cpy.resize(mem_cpy); - idx_mapping.resize(mem_cpy); - int ret = copy_coord_cpu( - &coord_cpy[0], &type_cpy[0], &idx_mapping[0], &new_nall, - &tmp_coord[0], type, nloc, mem_cpy, rcut_r, region); - if(ret == 0){ - break; - } - else{ - mem_cpy *= 2; - } - } - OP_REQUIRES (context, (tt != max_cpy_trial), - errors::Aborted("cannot allocate mem for copied coords")); + int copy_ok = _norm_copy_coord_cpu( + coord_cpy, type_cpy, idx_mapping, new_nall, mem_cpy, + coord, box, type, nloc, max_cpy_trial, rcut_r); + OP_REQUIRES (context, copy_ok, errors::Aborted("cannot allocate mem for copied coords")); coord = &coord_cpy[0]; type = &type_cpy[0]; } // build nlist - int tt; std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); std::vector> jlist(nloc); - for(tt = 0; tt < max_nnei_trial; ++tt){ - for(int ii = 0; ii < nloc; ++ii){ - jlist[ii].resize(mem_nnei); - firstneigh[ii] = &jlist[ii][0]; - } - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); - int new_mem_nnei = 0; - int ret = build_nlist_cpu( - inlist, &new_mem_nnei, - coord, nloc, new_nall, mem_nnei, rcut_r); - if(ret == 0){ - break; - } - else{ - mem_nnei *= 2; - } - } - OP_REQUIRES (context, (tt != max_nnei_trial), - errors::Aborted("cannot allocate mem for nlist")); + int build_ok = _build_nlist_cpu( + firstneigh, jlist, max_nbor_size, mem_nnei, + ilist, numneigh, coord, nloc, new_nall, max_nnei_trial, rcut_r); + OP_REQUIRES (context, build_ok, errors::Aborted("cannot allocate mem for nlist")); InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); - max_nbor_size = max_numneigh(inlist); // prod env mat prod_env_mat_a_cpu( em, em_deriv, rij, nlist, coord, type, inlist, max_nbor_size, avg, std, nloc, new_nall, rcut_r, rcut_r_smth, sec_a); // do nlist mapping if coords were copied - if(b_nlist_map){ - for (int ii = 0; ii < nloc; ++ii){ - for (int jj = 0; jj < nnei; ++jj){ - int record = nlist[ii*nnei+jj]; - if (record >= 0) { - nlist[ii*nnei+jj] = idx_mapping[record]; - } - } - } - } + if(b_nlist_map) _map_nlist(nlist, &idx_mapping[0], nloc, nnei); } else{ // copy pointers to nlist data @@ -480,41 +475,97 @@ class ProdEnvMatROp : public OpKernel { int ilist_size = 0, jrange_size = 0, jlist_size = 0; }; -// template -// static int -// norm_copy_coord( -// std::vector & coord_cpy, -// std::vector & type_cpy, -// std::vector & mapping, -// int & mem_cpy, -// const FPTYPE * coord, -// const FPTYPE * box, -// const int * type, -// const int &nloc, -// const int &max_cpy_trial) -// { -// std::vector tmp_coord(nall*3); -// std::copy(coord, coord+nall*3, tmp_coord.begin()); -// Region region; -// init_region_cpu(region, box); -// normalize_coord_cpu(&tmp_coord[0], nall, region); -// int tt; -// for(tt = 0; tt < max_cpy_trial; ++tt){ -// coord_cpy.resize(mem_cpy*3); -// type_cpy.resize(mem_cpy); -// idx_mapping.resize(mem_cpy); -// int ret = copy_coord_cpu( -// &coord_cpy[0], &type_cpy[0], &idx_mapping[0], &new_nall, -// &tmp_coord[0], type, nloc, mem_cpy, rcut_r, region); -// if(ret == 0){ -// break; -// } -// else{ -// mem_cpy *= 2; -// } -// } -// return (tt != max_cpy_trial) -// } +template +static int +_norm_copy_coord_cpu( + std::vector & coord_cpy, + std::vector & type_cpy, + std::vector & idx_mapping, + int & nall, + int & mem_cpy, + const FPTYPE * coord, + const FPTYPE * box, + const int * type, + const int &nloc, + const int &max_cpy_trial, + const float & rcut_r) +{ + std::vector tmp_coord(nall*3); + std::copy(coord, coord+nall*3, tmp_coord.begin()); + Region region; + init_region_cpu(region, box); + normalize_coord_cpu(&tmp_coord[0], nall, region); + int tt; + for(tt = 0; tt < max_cpy_trial; ++tt){ + coord_cpy.resize(mem_cpy*3); + type_cpy.resize(mem_cpy); + idx_mapping.resize(mem_cpy); + int ret = copy_coord_cpu( + &coord_cpy[0], &type_cpy[0], &idx_mapping[0], &nall, + &tmp_coord[0], type, nloc, mem_cpy, rcut_r, region); + if(ret == 0){ + break; + } + else{ + mem_cpy *= 2; + } + } + return (tt != max_cpy_trial); +} + +template +static int +_build_nlist_cpu( + std::vector &firstneigh, + std::vector> &jlist, + int & max_nnei, + int & mem_nnei, + std::vector &ilist, + std::vector &numneigh, + const FPTYPE *coord, + const int & nloc, + const int & new_nall, + const int & max_nnei_trial, + const float & rcut_r) +{ + int tt; + for(tt = 0; tt < max_nnei_trial; ++tt){ + for(int ii = 0; ii < nloc; ++ii){ + jlist[ii].resize(mem_nnei); + firstneigh[ii] = &jlist[ii][0]; + } + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + int ret = build_nlist_cpu( + inlist, &max_nnei, + coord, nloc, new_nall, mem_nnei, rcut_r); + if(ret == 0){ + break; + } + else{ + mem_nnei *= 2; + } + } + return (tt != max_nnei_trial); +} + +static void +_map_nlist( + int * nlist, + const int * idx_mapping, + const int & nloc, + const int & nnei) +{ + for (int ii = 0; ii < nloc; ++ii){ + for (int jj = 0; jj < nnei; ++jj){ + int record = nlist[ii*nnei+jj]; + if (record >= 0) { + nlist[ii*nnei+jj] = idx_mapping[record]; + } + } + } +} + + // Register the CPU kernels. #define REGISTER_CPU(T) \ diff --git a/source/tests/test_descrpt_smooth.py b/source/tests/test_descrpt_smooth.py index c9c796799a..6a72af7db5 100644 --- a/source/tests/test_descrpt_smooth.py +++ b/source/tests/test_descrpt_smooth.py @@ -78,7 +78,7 @@ def comp_ef (self, name, reuse = None) : descrpt, descrpt_deriv, rij, nlist \ - = op_module.descrpt_se_a (dcoord, + = op_module.prod_env_mat_a (dcoord, dtype, tnatoms, dbox, From a3b1ca224a52d6bc8619473f60c5a90a0bce026a Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 5 Mar 2021 14:45:28 +0800 Subject: [PATCH 242/562] add old style nlist vars. Waiting for the update of gpu part --- source/op/prod_env_mat_multi_device.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/op/prod_env_mat_multi_device.cc b/source/op/prod_env_mat_multi_device.cc index 56f50e75b1..458ed35c7c 100644 --- a/source/op/prod_env_mat_multi_device.cc +++ b/source/op/prod_env_mat_multi_device.cc @@ -319,7 +319,7 @@ class ProdEnvMatAOp : public OpKernel { int * array_int = NULL; unsigned long long * array_longlong = NULL; bool init = false; - InputNlist inlist; + int * ilist = NULL, * jrange = NULL, * jlist = NULL; int ilist_size = 0, jrange_size = 0, jlist_size = 0; }; From bb3ae4f52a8dac13862306ece755f2b618c6f093 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 5 Mar 2021 21:58:14 +0800 Subject: [PATCH 243/562] better impl. call prod_env_mat_a only once --- source/op/prod_env_mat_multi_device.cc | 54 +++++++++++++------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/source/op/prod_env_mat_multi_device.cc b/source/op/prod_env_mat_multi_device.cc index 458ed35c7c..42310ed30b 100644 --- a/source/op/prod_env_mat_multi_device.cc +++ b/source/op/prod_env_mat_multi_device.cc @@ -61,12 +61,12 @@ _norm_copy_coord_cpu( template static int _build_nlist_cpu( + std::vector &ilist, + std::vector &numneigh, std::vector &firstneigh, std::vector> &jlist, int & max_nnei, int & mem_nnei, - std::vector &ilist, - std::vector &numneigh, const FPTYPE *coord, const int & nloc, const int & new_nall, @@ -74,7 +74,7 @@ _build_nlist_cpu( const float & rcut_r); static void -_map_nlist( +_map_nlist_cpu( int * nlist, const int * idx_mapping, const int & nloc, @@ -254,11 +254,17 @@ class ProdEnvMatAOp : public OpKernel { #endif //GOOGLE_CUDA } else if (device == "CPU") { - // build nlist by myself + int new_nall = nall; + InputNlist inlist; + inlist.inum = nloc; + // some buffers, be free after prod_env_mat_a_cpu + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + std::vector> jlist(nloc); + std::vector coord_cpy; + std::vector type_cpy; if(nei_mode != 3){ - std::vector coord_cpy; - std::vector type_cpy; - int new_nall = nall; + // build nlist by myself // normalize and copy coord if(nei_mode == 1){ int copy_ok = _norm_copy_coord_cpu( @@ -269,35 +275,27 @@ class ProdEnvMatAOp : public OpKernel { type = &type_cpy[0]; } // build nlist - std::vector ilist(nloc), numneigh(nloc); - std::vector firstneigh(nloc); - std::vector> jlist(nloc); int build_ok = _build_nlist_cpu( - firstneigh, jlist, max_nbor_size, mem_nnei, - ilist, numneigh, coord, nloc, new_nall, max_nnei_trial, rcut_r); + ilist, numneigh, firstneigh, jlist, max_nbor_size, mem_nnei, + coord, nloc, new_nall, max_nnei_trial, rcut_r); OP_REQUIRES (context, build_ok, errors::Aborted("cannot allocate mem for nlist")); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); - // prod env mat - prod_env_mat_a_cpu( - em, em_deriv, rij, nlist, - coord, type, inlist, max_nbor_size, avg, std, nloc, new_nall, rcut_r, rcut_r_smth, sec_a); - // do nlist mapping if coords were copied - if(b_nlist_map) _map_nlist(nlist, &idx_mapping[0], nloc, nnei); + inlist.ilist = &ilist[0]; + inlist.numneigh = &numneigh[0]; + inlist.firstneigh = &firstneigh[0]; } else{ // copy pointers to nlist data - InputNlist inlist; - inlist.inum = nloc; memcpy(&inlist.ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); memcpy(&inlist.numneigh, 8 + mesh_tensor.flat().data(), sizeof(int *)); memcpy(&inlist.firstneigh, 12 + mesh_tensor.flat().data(), sizeof(int **)); max_nbor_size = max_numneigh(inlist); - // prod env mat - prod_env_mat_a_cpu( - em, em_deriv, rij, nlist, - coord, type, inlist, max_nbor_size, avg, std, nloc, nall, rcut_r, rcut_r_smth, sec_a); } // launch the cpu compute function + prod_env_mat_a_cpu( + em, em_deriv, rij, nlist, + coord, type, inlist, max_nbor_size, avg, std, nloc, new_nall, rcut_r, rcut_r_smth, sec_a); + // do nlist mapping if coords were copied + if(b_nlist_map) _map_nlist_cpu(nlist, &idx_mapping[0], nloc, nnei); } } } @@ -516,12 +514,12 @@ _norm_copy_coord_cpu( template static int _build_nlist_cpu( + std::vector &ilist, + std::vector &numneigh, std::vector &firstneigh, std::vector> &jlist, int & max_nnei, int & mem_nnei, - std::vector &ilist, - std::vector &numneigh, const FPTYPE *coord, const int & nloc, const int & new_nall, @@ -549,7 +547,7 @@ _build_nlist_cpu( } static void -_map_nlist( +_map_nlist_cpu( int * nlist, const int * idx_mapping, const int & nloc, From 3c268cb88501d74e270d5178d89aa32d851cf903 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 7 Mar 2021 15:34:10 +0800 Subject: [PATCH 244/562] adjust the UT of prod_env_mat_r to new input nlist --- source/lib/tests/test_env_mat_r.cc | 35 ++++++++++-------------------- 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/source/lib/tests/test_env_mat_r.cc b/source/lib/tests/test_env_mat_r.cc index d70e5ef0fe..153c10d582 100644 --- a/source/lib/tests/test_env_mat_r.cc +++ b/source/lib/tests/test_env_mat_r.cc @@ -249,15 +249,11 @@ TEST_F(TestEnvMatR, prod_cpu) max_nbor_size = nlist_a_cpy[ii].size(); } } - std::vector ilist(nloc), jlist(tot_nnei), jrange(nloc+1, 0); - for (int ii = 0; ii < nloc; ++ii){ - ilist[ii] = ii; - jrange[ii+1] = jrange[ii] + nlist_a_cpy[ii].size(); - int jj, cc; - for (jj = jrange[ii], cc = 0; jj < jrange[ii+1]; ++jj, ++cc){ - jlist[jj] = nlist_a_cpy[ii][cc]; - } - } + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_a_cpy); + std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); std::vector nlist(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); @@ -269,9 +265,7 @@ TEST_F(TestEnvMatR, prod_cpu) &nlist[0], &posi_cpy[0], &atype_cpy[0], - &ilist[0], - &jrange[0], - &jlist[0], + inlist, max_nbor_size, &avg[0], &std[0], @@ -304,15 +298,10 @@ TEST_F(TestEnvMatR, prod_cpu_equal_cpu) max_nbor_size = nlist_a_cpy[ii].size(); } } - std::vector ilist(nloc), jlist(tot_nnei), jrange(nloc+1, 0); - for (int ii = 0; ii < nloc; ++ii){ - ilist[ii] = ii; - jrange[ii+1] = jrange[ii] + nlist_a_cpy[ii].size(); - int jj, cc; - for (jj = jrange[ii], cc = 0; jj < jrange[ii+1]; ++jj, ++cc){ - jlist[jj] = nlist_a_cpy[ii][cc]; - } - } + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_a_cpy); std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); std::vector nlist(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); @@ -324,9 +313,7 @@ TEST_F(TestEnvMatR, prod_cpu_equal_cpu) &nlist[0], &posi_cpy[0], &atype_cpy[0], - &ilist[0], - &jrange[0], - &jlist[0], + inlist, max_nbor_size, &avg[0], &std[0], From ae1dfca7f00d6e3dffb2f75ed7ec2b4f3a052eb6 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Mon, 8 Mar 2021 17:33:48 +0800 Subject: [PATCH 245/562] fix bug of illegal device memory access --- source/lib/src/prod_env_mat.cc | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/source/lib/src/prod_env_mat.cc b/source/lib/src/prod_env_mat.cc index ce052b3df0..8352d95d30 100644 --- a/source/lib/src/prod_env_mat.cc +++ b/source/lib/src/prod_env_mat.cc @@ -271,29 +271,20 @@ void env_mat_nbor_update( memcpy (&jrange_host, 8 + mesh_host, sizeof(int *)); memcpy (&jlist_host, 12 + mesh_host, sizeof(int *)); int const ago = mesh_host[0]; - if (!init) { - ilist_size = (int)(mesh_host[1] * 1.2); - jrange_size = (int)(mesh_host[2] * 1.2); - jlist_size = (int)(mesh_host[3] * 1.2); - cudaErrcheck(cudaMalloc((void **)&ilist, sizeof(int) * ilist_size)); - cudaErrcheck(cudaMalloc((void **)&jrange, sizeof(int) * jrange_size)); - cudaErrcheck(cudaMalloc((void **)&jlist, sizeof(int) * jlist_size)); - init = true; - } - if (ago == 0) { + if (!init || ago == 0) { if (ilist_size < mesh_host[1]) { ilist_size = (int)(mesh_host[1] * 1.2); - cudaErrcheck(cudaFree(ilist)); + if (ilist != NULL) {cudaErrcheck(cudaFree(ilist));} cudaErrcheck(cudaMalloc((void **)&ilist, sizeof(int) * ilist_size)); } if (jrange_size < mesh_host[2]) { jrange_size = (int)(mesh_host[2] * 1.2); - cudaErrcheck(cudaFree(jrange)); + if (jrange != NULL) {cudaErrcheck(cudaFree(jrange));} cudaErrcheck(cudaMalloc((void **)&jrange,sizeof(int) * jrange_size)); } if (jlist_size < mesh_host[3]) { jlist_size = (int)(mesh_host[3] * 1.2); - cudaErrcheck(cudaFree(jlist)); + if (jlist != NULL) {cudaErrcheck(cudaFree(jlist));} cudaErrcheck(cudaMalloc((void **)&jlist, sizeof(int) * jlist_size)); } cudaErrcheck(cudaMemcpy(ilist, ilist_host, sizeof(int) * mesh_host[1], cudaMemcpyHostToDevice)); @@ -315,6 +306,7 @@ void env_mat_nbor_update( max_nbor_size = 4096; } } + init = true; delete [] mesh_host; } #endif // GOOGLE_CUDA From e61bd701e143a6003b66417d3152f3567939cf47 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 10 Mar 2021 14:32:29 +0800 Subject: [PATCH 246/562] fix bug of cmake script for finding tensorflow --- source/cmake/Findtensorflow.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/cmake/Findtensorflow.cmake b/source/cmake/Findtensorflow.cmake index 9281b67ac8..8901c698b9 100644 --- a/source/cmake/Findtensorflow.cmake +++ b/source/cmake/Findtensorflow.cmake @@ -29,7 +29,9 @@ if (BUILD_CPP_IF AND INSTALL_TENSORFLOW) ) endif () -string(REPLACE "lib64" "lib" TENSORFLOW_ROOT_NO64 ${TENSORFLOW_ROOT}) +if(DEFINED TENSORFLOW_ROOT) + string(REPLACE "lib64" "lib" TENSORFLOW_ROOT_NO64 ${TENSORFLOW_ROOT}) +endif(DEFINED TENSORFLOW_ROOT) # define the search path list(APPEND TensorFlow_search_PATHS ${TENSORFLOW_ROOT}) From 3ab5cbb0595c9479d3cbbdd6350cc06b7f1ce637 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 10 Mar 2021 14:34:37 +0800 Subject: [PATCH 247/562] change pb files to test ProdEnvMat --- source/tests/infer/deepdipole.pbtxt | 12 +- source/tests/infer/deeppolar.pbtxt | 27 +- source/tests/infer/deeppot.pbtxt | 12 +- source/tests/infer/dipolecharge_d.pbtxt | 12819 +++ source/tests/infer/dipolecharge_e.pbtxt | 104104 +++++++++++++++++++++ source/tests/test_dipolecharge.py | 112 + 6 files changed, 117071 insertions(+), 15 deletions(-) create mode 100644 source/tests/infer/dipolecharge_d.pbtxt create mode 100644 source/tests/infer/dipolecharge_e.pbtxt create mode 100644 source/tests/test_dipolecharge.py diff --git a/source/tests/infer/deepdipole.pbtxt b/source/tests/infer/deepdipole.pbtxt index 354de0cb98..a8f09a3331 100644 --- a/source/tests/infer/deepdipole.pbtxt +++ b/source/tests/infer/deepdipole.pbtxt @@ -7382,8 +7382,8 @@ node { } } node { - name: "DescrptSeA" - op: "DescrptSeA" + name: "ProdEnvMatA" + op: "ProdEnvMatA" input: "Reshape" input: "Reshape_2" input: "t_natoms" @@ -7437,7 +7437,7 @@ node { node { name: "o_nlist" op: "Identity" - input: "DescrptSeA:3" + input: "ProdEnvMatA:3" attr { key: "T" value { @@ -7448,7 +7448,7 @@ node { node { name: "o_rij" op: "Identity" - input: "DescrptSeA:2" + input: "ProdEnvMatA:2" attr { key: "T" value { @@ -7459,7 +7459,7 @@ node { node { name: "o_rmat_deriv" op: "Identity" - input: "DescrptSeA:1" + input: "ProdEnvMatA:1" attr { key: "T" value { @@ -7470,7 +7470,7 @@ node { node { name: "Reshape_3" op: "Reshape" - input: "DescrptSeA" + input: "ProdEnvMatA" input: "Reshape_3/shape" attr { key: "T" diff --git a/source/tests/infer/deeppolar.pbtxt b/source/tests/infer/deeppolar.pbtxt index 64288c2e80..d7f29bdd87 100644 --- a/source/tests/infer/deeppolar.pbtxt +++ b/source/tests/infer/deeppolar.pbtxt @@ -6136,6 +6136,27 @@ node { } } } +node { + name: "model_attr/output_dim" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 9 + } + } + } +} node { name: "model_attr/model_type" op: "Const" @@ -7639,8 +7660,8 @@ node { } } node { - name: "DescrptSeA" - op: "DescrptSeA" + name: "ProdEnvMatA" + op: "ProdEnvMatA" input: "Reshape" input: "Reshape_2" input: "t_natoms" @@ -7694,7 +7715,7 @@ node { node { name: "Reshape_3" op: "Reshape" - input: "DescrptSeA" + input: "ProdEnvMatA" input: "Reshape_3/shape" attr { key: "T" diff --git a/source/tests/infer/deeppot.pbtxt b/source/tests/infer/deeppot.pbtxt index 5ca6c76d70..7a5ba00f78 100644 --- a/source/tests/infer/deeppot.pbtxt +++ b/source/tests/infer/deeppot.pbtxt @@ -10515,8 +10515,8 @@ node { } } node { - name: "DescrptSeA" - op: "DescrptSeA" + name: "ProdEnvMatA" + op: "ProdEnvMatA" input: "Reshape_2" input: "Reshape_4" input: "t_natoms" @@ -10570,7 +10570,7 @@ node { node { name: "o_nlist" op: "Identity" - input: "DescrptSeA:3" + input: "ProdEnvMatA:3" attr { key: "T" value { @@ -10581,7 +10581,7 @@ node { node { name: "o_rij" op: "Identity" - input: "DescrptSeA:2" + input: "ProdEnvMatA:2" attr { key: "T" value { @@ -10592,7 +10592,7 @@ node { node { name: "o_rmat_deriv" op: "Identity" - input: "DescrptSeA:1" + input: "ProdEnvMatA:1" attr { key: "T" value { @@ -10603,7 +10603,7 @@ node { node { name: "Reshape_5" op: "Reshape" - input: "DescrptSeA" + input: "ProdEnvMatA" input: "Reshape_5/shape" attr { key: "T" diff --git a/source/tests/infer/dipolecharge_d.pbtxt b/source/tests/infer/dipolecharge_d.pbtxt new file mode 100644 index 0000000000..6bd2b430e3 --- /dev/null +++ b/source/tests/infer/dipolecharge_d.pbtxt @@ -0,0 +1,12819 @@ +node { + name: "Reshape_24/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: -1 + } + } + } +} +node { + name: "concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "Reshape_21/shape/2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_28/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_28/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "strided_slice_28/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "strided_slice_27/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_27/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_27/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_20/shape/2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "Reshape_20/shape/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_26/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_26/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "strided_slice_26/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "strided_slice_25/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_25/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_25/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "final_layer_type_3/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "\010f=#\350\341\316?\264\215\323\207\016\261\326\277b&\350Mp\321\352\277\215l\303eV`\317\277\234\336\\\233A\211\376?\"\n\273\244\031\274\327\277\2068M7\371\361\326?S\336g\265\360{\373\277" + } + } + } +} +node { + name: "final_layer_type_3/bias/read" + op: "Identity" + input: "final_layer_type_3/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_3/bias" + } + } + } +} +node { + name: "final_layer_type_3/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\325\322\201\247\324\213\261?Z\266\325\277^|\272\277c\335\271\230\331\033\317\277\377\027\001\014\037f\262\277G\260\034\3056\230\341?\360\317\343\362\271\260\273\277\317\235\304J\0106\272?\333U\303\367\220\316\337\277U\307\252c\320\375\307?(\340\325|\341\007\314\277\2624\234\"}\212\247?@2\262\332\240\312\322\277\362?\345n\323\026\225?\217\274\026\364V\371\333?]\374Ef\353\353\313?\232\257\246u`c\300\277Ofh#kI\323\277\362 @\220m\223\346?\252\217f\024\277\377\270\277\357\275\001\371\312\010\303?\227\273\202\315\322\217\311?\374\2533\327\370E\306?\212\"\007p\356;\260?/\324r\002\030C\272\277@\257q5\200\222\276\277\277\365\256\205\301\321\255?\006\222\365\207b\024\211?t\250h\233\220_\343\277\210\023\3031j\352\323\277\314\304xd\016\262\302\277\374\353\353\3279\001\316\277(\235&\010\334\336\302\277" + } + } + } +} +node { + name: "final_layer_type_3/matrix/read" + op: "Identity" + input: "final_layer_type_3/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_3/matrix" + } + } + } +} +node { + name: "layer_2_type_3/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "layer_2_type_3/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\240\267\320ZqC\271?\343s\376\214\224\350\271?\254|\247\333\356\310\271?\200T\350\244\211#\271?" + } + } + } +} +node { + name: "layer_2_type_3/idt/read" + op: "Identity" + input: "layer_2_type_3/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_3/idt" + } + } + } +} +node { + name: "layer_2_type_3/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\214\355O\033\357\341\316?R\375QC\r\261\326\277\231\272\202\361\320\277\020z\273\242d\233\256?\n\354\200\347\014\376\326\277\242mr\345\324`\235?\223_y\257\316=\341?\224\230\205\221\377Q\321?*\364!\346\307\006\304\277" + } + } + } +} +node { + name: "layer_2_type_3/matrix/read" + op: "Identity" + input: "layer_2_type_3/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_3/matrix" + } + } + } +} +node { + name: "layer_1_type_3/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "layer_1_type_3/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\010$\315\236pC\271?2H\373\343\224\350\271?\247\177\230o\356\310\271? HA5\207#\271?" + } + } + } +} +node { + name: "layer_1_type_3/idt/read" + op: "Identity" + input: "layer_1_type_3/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_3/idt" + } + } + } +} +node { + name: "layer_1_type_3/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "^M\244g\357\341\316?#\324l*\r\261\326\277L9\377\334p\321\352\277V\034Q\0256\372\316\277" + } + } + } +} +node { + name: "layer_1_type_3/bias/read" + op: "Identity" + input: "layer_1_type_3/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_3/bias" + } + } + } +} +node { + name: "layer_1_type_3/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 4 + } + } + tensor_content: "W\265e\230Z\224\265?\'\330\272\034\240,\300\277~\220\267\332\033\007\323\277S8S>~\245\265\277\335\266\313\244c\217\345?\324\350\356\020t\351\300\277\214U\346X\201\030\300?\326+?\367\341]\343\277\316\000\303\360\273\323\315?\026e9\354\202\361\320\277\252se\336b\233\256?\260\250n\320\014\376\326\277h\251\353\000\324`\235?t\027\212\255\316=\341?\254\236^\177\377Q\321?\222\333\030\023\310\006\304\277" + } + } + } +} +node { + name: "layer_1_type_3/matrix/read" + op: "Identity" + input: "layer_1_type_3/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_3/matrix" + } + } + } +} +node { + name: "layer_0_type_3/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "layer_0_type_3/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "k8-Tv\344\316?h\007\225\326\205\227\326\277ET\321\207\355\320\352\277\315[\376\006E-\317\277" + } + } + } +} +node { + name: "layer_0_type_3/bias/read" + op: "Identity" + input: "layer_0_type_3/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_3/bias" + } + } + } +} +node { + name: "layer_0_type_3/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 32 + } + dim { + size: 4 + } + } + tensor_content: "\035\031\3517v\357\243?\340\t\034\036]\037\256\277K?\357\227\177\t\302\2773=T\257\330\310\244\277\010\302\324\241\240F\324?\021\203\273\316k\203\257\277\273+\375+\307\365\255?\263\305c\006_N\322\277#\1773\254e\212\273?\245x\310{\203\021\300\277\034\370\315\0025\222\232?\212\3060 Z\225\305\2772\274_\241\204\016\207?\230\340\007\331W5\320?&\377\354\222G\013\300?\301\'\261\014p\261\262\277\354\317\217\004\375\224\306\277Lt|%\304\002\332?\243\016\302\316\365\027\256\277\264\202\251\240\245\277\265?\204\0224\352\274\344\274?\271\310\'\206\031}\271?j\227\273\252\250\204\241?\336*N`\031\311\256\277&\021\340\247\tF\262\277\316J?\342j\301\240?\212\354\347\350&$s?\321\013\216\314\215m\326\277z\255\013\315\304N\307\277\331\333\303\350m\321\265\277y\365\264\307M\241\301\277\252\263\324\252)\005\266\277\350\245\257\220\241\320\234\277\t\265\243%Y\244\306\277\\S\301\363$e\301\277\326\216\202\337N\206\251\277\ne%O\270[\306?\252\227 \345\200\320\245?KY\367\372L>\221\277\374\303\275\253\036%\301\277\237m\304h\253F\274\277V\227q\243\310\031\324?\377\014\201\370?\323\312\277\266\337\322xE\266\254\277wv\346cQ\302\275?\241c\342\023\237\331\270\277T\230QWTU\315\277\264ifCO\266\203\277\232X\227\224\360\314\234?\260\276\263\341\036~\310?L\\\037\242\247\'\256\277\004\227\035\301\r\304\257\2778\354\3518\371\360\322?\265\202\254/\323\374\240\277\002\031>\263o\312\331\277\230\277:\'Z\222\266?C\037\252\231\017Y\230?\316\360\031a\223~\260\277\'\276\367\274\3610X\277P\265\362\355\213\350r?h\363\2116>\301\306?\245v\207\352\310\232\213?\317\367\244\344\200\034\314\277\325V\252\330e\324\247? \346\0253\316\341\271\277\021\023\257\327*\t|?\224\210\265\212\346\321\267\277\231\356\023\036\022\340\316?I\003\334\337\301\215\240?\005p+\370#\321\325?\216\345\363\365F\007\225\277\370\306\340m\200:\225?\004eT\025s\023\262\277\262L0\227\023%\271\277g\225\315\334\202+\305?\335G \3653\221\231?/;\231m|r\320\277\036\364\322,(\006\314\277Z\203gv\326\302\314?\037\205\303Z\230\226\303?\200\311R\005\263\247\303?\206>\027=\307\203\205?\234\355\204\206\232\213\267\277\376\227\003\204,\300\277\277\205\231\020\"U\337\304\277I\246\004j\025\251\330?\364}\006:\005\272\271?\270N]-\240\026\242?\371\343~\324u\000\325?Jd\217\005\262\r\320?GW/\262\201\221\302\277\t\314?QN\246\302\277\315\231\352\247>?\255\277\005\305\303m\353\242\225?\266\203sI\311Y\243\2779\200\034\250\351\301\304\277\250\344V\352\226\002\204\277K\t\213\021\327\035\305?\205{l-(\361\312?u1\013W\315X\306\277\327\222\005*\364h\267\2771\321\217np\022\310\277\357\245;\3666\025\270?\210\246\302\2345\333\244?\333\364iQ%\372b\277\274\023\303\020\304\030\300\277_\035\214\316\201\037\303?\222w}T\320\227\315\277+\323\'\232i\\\272\277\027\317\320\3779\010\321?\376y`\010\024w\306?\366\271C\206\220\362\217?(\031O\366\324\001\262?\332!\311\'\360\342\300?\tZ\315Mg\227\311\277\342V\326S\276\207\324\277P\261\245\373%5\250\277q\3555o\230V\244\277\354\'s\226T\264\271\277R<\020\226\243k\300\277J\323q\036\331:\272?\205\325\254\330\274[\265\277\246\365qh\342p\274?B\320\003\3154\251\241\277*\317e\212\034\020\310?\204#\232\371$\367\265?g\022=\273\361\t\244\277ZO|\030$\255\300?" + } + } + } +} +node { + name: "layer_0_type_3/matrix/read" + op: "Identity" + input: "layer_0_type_3/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_3/matrix" + } + } + } +} +node { + name: "Reshape_19/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\010\000\000\000\003\000\000\000" + } + } + } +} +node { + name: "Slice_7/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_7/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_21/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 24 + } + } + } +} +node { + name: "strided_slice_23/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_23/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "strided_slice_23/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "mul_20/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 24 + } + } + } +} +node { + name: "Reshape_18/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "Slice_6/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_6/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_19/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_22/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_22/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "strided_slice_22/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "mul_18/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_21/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_21/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "strided_slice_21/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "Reshape_15/shape/2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_18/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_18/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_18/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_17/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_17/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_17/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_14/shape/2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "Reshape_14/shape/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_16/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_16/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_16/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_15/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_15/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_15/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "final_layer_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "q\031x\225\350\341\316?3\202\350S\016\261\326\277w>H0p\321\352\2774m\001\362U`\317\277\030\247h\250A\211\376?\313+=w\031\274\327\277-t\332p\371\361\326?\326\335\026\246\360{\373\277" + } + } + } +} +node { + name: "final_layer_type_1/bias/read" + op: "Identity" + input: "final_layer_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_1/bias" + } + } + } +} +node { + name: "final_layer_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "4\325\343\277\325\213\261?c3w\313]|\272\277(\375(\027\331\033\317\277\007\315\003\027\036f\262\277\257\370\355\3456\230\341?\215\021\327\036\271\260\273\277\350\'\375V\t6\272?\244\317`\272\220\316\337\277*\0146\372\320\375\307?\035X\252\373\340\007\314\277\342\351\2431\177\212\247?R\246(\235\240\312\322\277\n;I\341\327\026\225?\"w\330+W\371\333?\223\213\301\362\353\353\313?:p\t\376_c\300\277\n3\036YkI\323\277\346N\247wm\223\346?\036\374k\362\277\377\270\277S\213\324\213\312\010\303?xl\231k\322\217\311?\213\2643\201\370E\306?.ob\230\355;\260?\275k\036\350\030C\272\277Q\257\217E\201\222\276\277\241}\016\252\277\321\255?lF\242\226Z\024\211?U\362\206\271\220_\343\277\005\237Hqj\352\323\277\217Y\225\313\016\262\302\277\267\013\256Z:\001\316\277\352\331\227\201\334\336\302\277" + } + } + } +} +node { + name: "final_layer_type_1/matrix/read" + op: "Identity" + input: "final_layer_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_1/matrix" + } + } + } +} +node { + name: "layer_2_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "layer_2_type_1/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\206\357\242\315qC\271?\234\311\304\277\223\350\271?\342M~3\356\310\271?\242B\372\"\213#\271?" + } + } + } +} +node { + name: "layer_2_type_1/idt/read" + op: "Identity" + input: "layer_2_type_1/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_1/idt" + } + } + } +} +node { + name: "layer_2_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "6\234\020\r\356\341\316?\254KF5\r\261\326\277\241\316T\336p\321\352\277\336*(\2256\372\316\277" + } + } + } +} +node { + name: "layer_2_type_1/bias/read" + op: "Identity" + input: "layer_2_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_1/bias" + } + } + } +} +node { + name: "layer_2_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 4 + } + } + tensor_content: "[\006r2\372\316\277" + } + } + } +} +node { + name: "layer_0_type_1/bias/read" + op: "Identity" + input: "layer_0_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_1/bias" + } + } + } +} +node { + name: "layer_0_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 32 + } + dim { + size: 4 + } + } + tensor_content: "s\246\366QO\354\243?\347\025\177\327\230\353\256\277\267vK@\246\n\302\277\300\026%o\223\374\243\277X\201\256\3725F\324?\352p\033\261\326\'\260\277\300@~\353\323\361\255?\003\334p\264\3254\322\277\230^+\334\270\210\273?\000\211\336\234\222D\300\277\243w\253\370\301\212\232?\"-7\251Hb\305\277\360\002O\202\241\003\207?\342|\013\332\315\033\320?Y|\367[\255\n\300?{0w\212JK\262\277NQ\334R\322\225\306\277t\010\r\363;\351\331?\236\371@\017\351\033\256\277y)u\350\312%\266?.\362\275\034\374\342\274?Q_\222\002\367\026\271?\357\024\006\235\306\200\241?/Q\333\264\313\374\255\277s\241\000\361\314G\262\277B=;-R\352\237?c\177-\014$\006s?7kHw\004T\326\277\007\331n\334\267O\307\277\034\366 \342\2177\266\277\365\270\214\363\362\241\301\277\374\020L\272\004\237\265\277\020(\320\320T\327\234\277d\305\271Fh\327\306\277l\243\005U\023f\301\2776)\234\003\t\272\250\277\344\034\225\252\326Z\306?}\353~\031?\004\245?\225\364%\262\315E\221\277\307\2022\001\014\362\300\277t\023\350eqH\274\2770\314?\305@\000\324?\327\266U\345(\324\312\277?\221ix\375\351\253\277\325\234\323cg\300\275?&qV\"\277?\271\277 +C?\371U\315\277\306:\371S6\205\200\277\370\373\016\005\177\307\234?C\367\272\343\nK\310?~g\365}\020*\256\277u\250\251\274\302\367\256\277uV8\261\177\360\322?9\267f\"\027\311\241\277\302\372)I\302\312\331\277Fb\303\027\177\370\266?\265\270^\231gQ\230?S\376\215o\263\344\260\277\375#\301\265e\203X\277(\023\315\314\275Jy?\t\345\237\375X\300\306?\277\277<\t+k\210?\007\337\206\340\032\035\314\277\026\002\007fK\240\250?W\264\317#\\\343\271\277\300\023\356*<\247u?.o\002N4\324\267\277\374\317\241\353#\023\317?\236m\032\217z\212\240?\230 \273q\233\267\325?V\375\312\271\374\016\225\277X0\264h\032\323\226?bpH\321\030\025\262\277BS\212\0043\213\271\2776\023\376S\233*\305?D>\003\005\304)\233?\303\021\343\373\262r\320\277\315\231\301\301w8\314\277\036.\362n?\302\314?i\345\337\007\334\310\303?\345\007\024\024\332\246\303?\266}\271\036\262R\202?\343\231\354\211_\215\267\277\026J\030\223\005Z\277\2779\312h\n8\340\304\277\212E\251\244\214\217\330?ko\226\r3\270\271?w-n\324\356\342\242?g\247I\276\003\000\325?0\275\235>S\350\317?\035]\222\252d\222\302\277\330\205\200X;s\302\277\016\227\233\351\020C\255\277(\354\355\266n\n\224?\t[\036C\\\\\243\277\242\206\323~\330\216\304\277\364\214\262:]\017\204\277\006\241V\n\310\352\304?\213\246\350$\031\360\312?\377\210\251\361\273%\306\277\203\326\025h\243j\267\2772\177\303\342\200E\310\277\364\344\354\336O\023\270?\177\261\315]\200\247\245?\022\026,\321V0c\277%\306\213r\323K\300\277m\270V\270\231\036\303?\0005\215\243\276d\315\277\352\355\257I\t^\272\277\021\375\n&\260\356\320?\262&\205zvv\306?\274\353\322(\353\221\221?\3564J\271\026\000\262?\201s\007E\342\257\300?m\330\377=\010\230\311\277\355\247A}6n\324\277c\246T\024\3778\250\277\003V\320J\327\"\245\277\251\340Ec\363\265\271\277]\270O\261\2218\300\2774:\330\037\3518\272?\367ZH\366\333\301\265\277o\365\316\302Co\274?m\373\345\324\355\334\240\277g-\\\337\t\017\310?\330\262\000$\016\221\265??\355\036\337\215\014\244\2775\267P:1\340\300?" + } + } + } +} +node { + name: "layer_0_type_1/matrix/read" + op: "Identity" + input: "layer_0_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_1/matrix" + } + } + } +} +node { + name: "strided_slice_14/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_14/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_14/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "Reshape_13/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\010\000\000\000\003\000\000\000" + } + } + } +} +node { + name: "Slice_3/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_3/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_12/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 24 + } + } + } +} +node { + name: "strided_slice_13/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_13/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_13/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "mul_11/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 24 + } + } + } +} +node { + name: "Reshape_12/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "Slice_2/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_2/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_10/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_12/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_12/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_12/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "mul_9/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "add/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "strided_slice_11/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_11/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_11/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "Reshape_9/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_6/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 24 + } + } + } +} +node { + name: "strided_slice_8/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_8/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_8/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_8/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_5/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_7/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_7/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_7/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "mul_4/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "mul_3/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "strided_slice_6/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_6/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_6/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "strided_slice_5/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_5/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_5/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "mul_2/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_4/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_4/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_4/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "strided_slice_3/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_3/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_3/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "filter_type_all/Reshape_35/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "filter_type_all/transpose/perm" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\000\000\000\000\002\000\000\000\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_11/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\003\000\000\000\377\377\377\377" + } + } + } +} +node { + name: "filter_type_all/Slice_11/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\000\000\000\000\001\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_10/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_10/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\000\000\000\000\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_all/mul/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.04 + } + } + } +} +node { + name: "filter_type_all/Reshape_34/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Reshape_33/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/concat_14/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_all/Reshape_32/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_3_4" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\006\330\001<\361\341\316?\254t\013\\\002~\326\2772\335^\351\345\267\352\277\304\332\003\372;\372\316\277\201\250!\200\326\225\376?\032\000m\014\t\211\327\277\200W/\240\365\361\326?\212\355\307\225>o\373\277" + } + } + } +} +node { + name: "filter_type_all/bias_3_4/read" + op: "Identity" + input: "filter_type_all/bias_3_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_3_4" + } + } + } +} +node { + name: "filter_type_all/matrix_3_4" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\261Z\2731\346\213\261?\305C\260)/\260\271\277 R/?\256\265\316\277\266\315Vh\323\231\261\277N5\350\234<\230\341?\230|C*x\344\272\277`\335\342n\3715\272?\301\260\272\3212\234\337\277\267)\253\354\330\375\307??\375\350\265\311\241\313\277\2740\034\365*#\251?\023J\371\320\275\227\322\277\214\362?B\r\030\225?N^\232fg,\334?\026\n4\321\343\353\313?Cs\025\206Yb\300\277\004I\347\264w|\323\277\271\312\034\317j\223\346?E\374\357:\255\377\270\277\344\0374\237\276\010\303?\035\321\357\200\315)\311?\310\006Y\222\366E\306?\234%\315\3175\337\256?6SG\376H\014\273\277\224_\247m\261^\277\277H#\343w\230\321\255?T\344\006\005\373\024\211?\037W\324+\224_\343\277c\022][e\035\324\277i\363\034\361\017\262\302\277\337\376J\tcg\316\277\334\244\221\037\344B\303\277" + } + } + } +} +node { + name: "filter_type_all/matrix_3_4/read" + op: "Identity" + input: "filter_type_all/matrix_3_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_3_4" + } + } + } +} +node { + name: "filter_type_all/concat_13/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_all/Reshape_31/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_2_4" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\232+_o\007H\317?\336\243\276\035\372}\326\277\247\321Ae\346\267\352\277N\305\3411<\372\316\277" + } + } + } +} +node { + name: "filter_type_all/bias_2_4/read" + op: "Identity" + input: "filter_type_all/bias_2_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_2_4" + } + } + } +} +node { + name: "filter_type_all/matrix_2_4" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "T\371\334\177\266\372\270?\266\304\271\032\"?\302\277\312K\255t\242\301\325\277E\314\346\214\205\016\271\2778\317\260\2045\347\350?/\010\314,,\031\303\277q\262\231u\006\004\303?&Ty;\327^\346\277" + } + } + } +} +node { + name: "filter_type_all/matrix_2_4/read" + op: "Identity" + input: "filter_type_all/matrix_2_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_2_4" + } + } + } +} +node { + name: "filter_type_all/concat_12/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_all/Reshape_30/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_1_4" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "1\373~<\346\341\316?!\212*F\373}\326\277" + } + } + } +} +node { + name: "filter_type_all/bias_1_4/read" + op: "Identity" + input: "filter_type_all/bias_1_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_1_4" + } + } + } +} +node { + name: "filter_type_all/matrix_1_4" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\005d \014\343\276\301?\325\033\376u\'\343\311\277" + } + } + } +} +node { + name: "filter_type_all/matrix_1_4/read" + op: "Identity" + input: "filter_type_all/matrix_1_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_1_4" + } + } + } +} +node { + name: "filter_type_all/Reshape_29/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_9/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_9/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Reshape_28/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_8/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\024\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_8/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000P\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Reshape_27/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Reshape_26/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/concat_11/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_all/Reshape_25/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_3_3" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\221*\337:\010H\317?\027\363\322A\377}\326\277}\261Zt\350\267\352\277\221!A\026G\372\316\277\345{\t\350Z\211\376?tq&O\n\211\327\277OV3\335\311$\327?\246+\tY0o\373\277" + } + } + } +} +node { + name: "filter_type_all/bias_3_3/read" + op: "Identity" + input: "filter_type_all/bias_3_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_3_3" + } + } + } +} +node { + name: "filter_type_all/matrix_3_3" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\303=8\200\027\214\261?!Xch\033|\272\277\205/\317\252\261\033\317\277\361\375\311\365\350d\262\277\3359JI\023\260\341?F\201\021\332P\260\273\277\202\361\022\351O8\272?\307\017\236b\363\315\337\277\352\234I@\323\375\307?w\243~F\334\007\314\277{\001\215\241\216\212\247?\353\350z\226\224\312\322\277A\342\2010\217?\230?\277\"\347\006Z\371\333?^\322J\326r\354\313?Y\t \3655c\300\2779w\315qz|\323\277\351+\364D\346y\346?Y\016P^\372\313\271\277\233\0014\356\302\242\302?Lu[\346\254\216\311?\247C\357\206\334\337\305?\3538\250\326x\341\256?\002\366\002q\377\016\273\277\217\301\344\332\264^\277\277\310jW\343\\9\254?e\030\230\245\330\262\202?\336b \010\016y\343\277\031\007\206\263n\353\323\277\230\3512#$\030\303\277\225\241H\240\274f\316\277\021\223\020\216\250D\303\277" + } + } + } +} +node { + name: "filter_type_all/matrix_3_3/read" + op: "Identity" + input: "filter_type_all/matrix_3_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_3_3" + } + } + } +} +node { + name: "filter_type_all/concat_10/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_all/Reshape_24/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_2_3" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\001\320P6\376G\317?\013\274\325\211\376}\326\277\203\267,\257\351\267\352\277x\254\310\2666\372\316\277" + } + } + } +} +node { + name: "filter_type_all/bias_2_3/read" + op: "Identity" + input: "filter_type_all/bias_2_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_2_3" + } + } + } +} +node { + name: "filter_type_all/matrix_2_3" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "/|\010\214\243\305\271?\346}p$K?\302\277 1\341S\332\301\325\277`H\037oA\021\271\277\215fT\2709\347\350?ym\021,Q\177\303\277\\\321\r\277\347\235\302?\225\026N\341\\x\346\277" + } + } + } +} +node { + name: "filter_type_all/matrix_2_3/read" + op: "Identity" + input: "filter_type_all/matrix_2_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_2_3" + } + } + } +} +node { + name: "filter_type_all/concat_9/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_all/Reshape_23/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_1_3" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\353W\301\230\001H\317?\225z\037\333\376}\326\277" + } + } + } +} +node { + name: "filter_type_all/bias_1_3/read" + op: "Identity" + input: "filter_type_all/bias_1_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_1_3" + } + } + } +} +node { + name: "filter_type_all/matrix_1_3" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\224f{\001\364\276\301?\366\361\330\036FI\312\277" + } + } + } +} +node { + name: "filter_type_all/matrix_1_3/read" + op: "Identity" + input: "filter_type_all/matrix_1_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_1_3" + } + } + } +} +node { + name: "filter_type_all/Reshape_22/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_7/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_7/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Reshape_21/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_6/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\024\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_6/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000<\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Reshape_20/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Reshape_19/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/concat_8/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_all/Reshape_18/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_3_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: ">\022uq\360\341\316?M\230&#\002~\326\277\215#r1\346\267\352\277\217T\\UB\372\316\277L\367\002\262N\211\376?r\326Z)\t\211\327\277\2267\332/\366\361\326?\372DCY0o\373\277" + } + } + } +} +node { + name: "filter_type_all/bias_3_2/read" + op: "Identity" + input: "filter_type_all/bias_3_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_3_2" + } + } + } +} +node { + name: "filter_type_all/matrix_3_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "Z\350\244\240\344\213\261?\232\321\247\276.\260\271\277\254\236\254\004\257\265\316\277J\030\236\310\317\231\261\277\262\237\333\245<\230\341?x\360\367\240x\344\272\277\273\030\307\261\3735\272?-\352\231\332e\315\337\277\360yN\037\330\375\307?\344\323\334\204\311\241\313\277h\301\245B(#\251?\357\354\014Y\242\227\322\277\364\264\326Y\325\030\225?\302;\374Jg,\334?\377\026\307\356\344\353\313?\255k\230\2504c\300\277~k\020\031x|\323\277V\343\275\332j\223\346?j\351\354\254\256\377\270\277s\303\313\022\310\010\303?\"\336C\262\330)\311?\023\251dV\366E\306?\356\322>X:\337\256?\374?\007y\373\016\273\277wt\021\005\263^\277\277\360\257\353H\231\321\255?\266=96\357\024\211?\203\355\030\303\221_\343\277\354\031\213o_\035\324\277\365Z\315)\020\262\302\277\312\215\243\352ag\316\277\233z\346\356\242D\303\277" + } + } + } +} +node { + name: "filter_type_all/matrix_3_2/read" + op: "Identity" + input: "filter_type_all/matrix_3_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_3_2" + } + } + } +} +node { + name: "filter_type_all/concat_7/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_all/Reshape_17/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_2_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\2515l\244\372G\317?\206b:\210\372}\326\277\001+\205\233\346\267\352\277\024\031\330\1774\372\316\277" + } + } + } +} +node { + name: "filter_type_all/bias_2_2/read" + op: "Identity" + input: "filter_type_all/bias_2_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_2_2" + } + } + } +} +node { + name: "filter_type_all/matrix_2_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "?\356\305#\264\372\270?!\032\377\324\"?\302\277\303D>\277\242\301\325\277\360l\250z\205\016\271\277\010\255\304\3205\347\350?G\263d\340,\031\303\277#C(\361\005\004\303?\377\344\307\025\327^\346\277" + } + } + } +} +node { + name: "filter_type_all/matrix_2_2/read" + op: "Identity" + input: "filter_type_all/matrix_2_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_2_2" + } + } + } +} +node { + name: "filter_type_all/concat_6/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_all/Reshape_16/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_1_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\302I\345\314\346\341\316?B\265\350\244\373}\326\277" + } + } + } +} +node { + name: "filter_type_all/bias_1_2/read" + op: "Identity" + input: "filter_type_all/bias_1_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_1_2" + } + } + } +} +node { + name: "filter_type_all/matrix_1_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\304\267\305\236\343\276\301?\264\207\255.(\343\311\277" + } + } + } +} +node { + name: "filter_type_all/matrix_1_2/read" + op: "Identity" + input: "filter_type_all/matrix_1_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_1_2" + } + } + } +} +node { + name: "filter_type_all/Reshape_15/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_5/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_5/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Reshape_14/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_4/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\024\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_4/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000(\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Reshape_13/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Reshape_12/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/concat_5/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_all/Reshape_11/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\366)\337:\010H\317?\355\363\322A\377}\326\277\326\260Zt\350\267\352\277\225\"A\026G\372\316\277e{\t\350Z\211\376?\361p&O\n\211\327\277:V3\335\311$\327?\224*\tY0o\373\277" + } + } + } +} +node { + name: "filter_type_all/bias_3_1/read" + op: "Identity" + input: "filter_type_all/bias_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_3_1" + } + } + } +} +node { + name: "filter_type_all/matrix_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\031\2427\200\027\214\261?-\364ch\033|\272\277\336\200\317\252\261\033\317\277\326\254\312\365\350d\262\277#OJI\023\260\341?\313\037\022\332P\260\273\277\215\357\021\351O8\272?\334<\236b\363\315\337\277\221\234I@\323\375\307?\274\242~F\334\007\314\277\025\363\214\241\216\212\247?\362\350z\226\224\312\322\277_\010\2020\217?\230?\302!\347\006Z\371\333?\345\320J\326r\354\313?\355\022 \3655c\300\277\377x\315qz|\323\277E+\364D\346y\346?\370\033P^\372\313\271\277\374\3753\356\302\242\302?g|[\346\254\216\311?z>\357\206\334\337\305?#\035\250\326x\341\256?x\017\003q\377\016\273\277\215\334\344\332\264^\277\277\3627W\343\\9\254?\377\013\227\245\330\262\202?\212f \010\016y\343\277\203\377\205\263n\353\323\277\251\3702#$\030\303\277\203\271H\240\274f\316\277\274\251\020\216\250D\303\277" + } + } + } +} +node { + name: "filter_type_all/matrix_3_1/read" + op: "Identity" + input: "filter_type_all/matrix_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_3_1" + } + } + } +} +node { + name: "filter_type_all/concat_4/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_all/Reshape_10/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "T\351\255*\376G\317?\256\247\350\212\376}\326\277\2477\376\257\351\267\352\277\nX\312\3056\372\316\277" + } + } + } +} +node { + name: "filter_type_all/bias_2_1/read" + op: "Identity" + input: "filter_type_all/bias_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_2_1" + } + } + } +} +node { + name: "filter_type_all/matrix_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "g\324\332w\243\305\271?\025}(&K?\302\277\351xFU\332\301\325\277?\247]\207A\021\271\277ncF\2739\347\350?\275\307\344)Q\177\303\277A\257]\302\347\235\302?\205\321t\335\\x\346\277" + } + } + } +} +node { + name: "filter_type_all/matrix_2_1/read" + op: "Identity" + input: "filter_type_all/matrix_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_2_1" + } + } + } +} +node { + name: "filter_type_all/concat_3/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_all/Reshape_9/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "&\250\235\216\001H\317?\257E\367\333\376}\326\277" + } + } + } +} +node { + name: "filter_type_all/bias_1_1/read" + op: "Identity" + input: "filter_type_all/bias_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_1_1" + } + } + } +} +node { + name: "filter_type_all/matrix_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\336\243\244\013\364\276\301?#\004(\035FI\312\277" + } + } + } +} +node { + name: "filter_type_all/matrix_1_1/read" + op: "Identity" + input: "filter_type_all/matrix_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_1_1" + } + } + } +} +node { + name: "filter_type_all/Reshape_8/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_3/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_3/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Reshape_7/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_2/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\024\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_2/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\024\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Reshape_6/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_all/Reshape_4/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\210\235\221\342\350\341\316?\020\217\2249\373}\326\277\002a0\303\346\267\352\2776\216=\245(\372\316\277\000\225\246\007E\211\376?\347@\373\256\005\211\327\2777(N~\370\361\326?4\363\353).o\373\277" + } + } + } +} +node { + name: "filter_type_all/bias_3_0/read" + op: "Identity" + input: "filter_type_all/bias_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_3_0" + } + } + } +} +node { + name: "filter_type_all/matrix_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\345\233\361L\325\213\261?\377\240D\245\021\260\271\277H1W.\262\265\316\277f\225H\313\301\231\261\277J.f_8\230\341?\026\020\314pj\344\272\277\321\306-}\0066\272?\2573\017\030\202\233\337\277>\247|\200\317\375\307?\277\264\335\353\271\241\313\277\342q5\236\035#\251?\347i\241\377\211\227\322\277\2023\331\375\231\030\225?g\237\2606k,\334?\r1\202\227\352\353\313?b\016\226\233\230\373\277\277\273\235\377\360{|\323\277\344\373\312\206n\223\346?\216b\0132\265\377\270\277\256](\224\326\010\303?MB\002\221\304)\311?\2615\346r\375E\306?\334!\340\265Q\337\256?\355\343\267\313BC\272\277\223=d\262\303^\277\277\257\242\036\037\326\321\255?\207\344M\303\263\024\211?\216\216G\330\215_\343\277#\324\372AY\035\324\277\324N*\236\010\262\302\2778)*8\\g\316\277\020\307\336\275:\337\302\277" + } + } + } +} +node { + name: "filter_type_all/matrix_3_0/read" + op: "Identity" + input: "filter_type_all/matrix_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_3_0" + } + } + } +} +node { + name: "filter_type_all/concat_1/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_all/Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "=\377\373\306\345\341\316?\372\303\351>\372}\326\277;L\251h\346\267\352\277R\320f\0220\372\316\277" + } + } + } +} +node { + name: "filter_type_all/bias_2_0/read" + op: "Identity" + input: "filter_type_all/bias_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_2_0" + } + } + } +} +node { + name: "filter_type_all/matrix_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "`v\201C\261\372\270?\372-\367\357!?\302\277\353}e\371\242\301\325\277\241\302\306Y\204\016\271\277\246\354c\3164\347\350?\234\313\330\204+\031\303\277\206\213\345\324\005\004\303?\006\272\370\256\326^\346\277" + } + } + } +} +node { + name: "filter_type_all/matrix_2_0/read" + op: "Identity" + input: "filter_type_all/matrix_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_2_0" + } + } + } +} +node { + name: "filter_type_all/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "filter_type_all/Reshape_2/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\256tQX\350\341\316?\257\246\353\020\373}\326\277" + } + } + } +} +node { + name: "filter_type_all/bias_1_0/read" + op: "Identity" + input: "filter_type_all/bias_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_1_0" + } + } + } +} +node { + name: "filter_type_all/matrix_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\351\004\003L\345\276\301?\356\2304\304&\343\311\277" + } + } + } +} +node { + name: "filter_type_all/matrix_1_0/read" + op: "Identity" + input: "filter_type_all/matrix_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_1_0" + } + } + } +} +node { + name: "filter_type_all/Reshape_1/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_1/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_1/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\024\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377d\000\000\000" + } + } + } +} +node { + name: "Reshape_4/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_1/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_2/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_2/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_2/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377d\000\000\000" + } + } + } +} +node { + name: "Reshape_2/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "strided_slice_1/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_1/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_1/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "Reshape_1/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\t\000\000\000" + } + } + } +} +node { + name: "Reshape/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "descrpt_attr/t_std" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 5 + } + dim { + size: 100 + } + } + tensor_content: "\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?" + } + } + } +} +node { + name: "descrpt_attr/t_std/read" + op: "Identity" + input: "descrpt_attr/t_std" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@descrpt_attr/t_std" + } + } + } +} +node { + name: "descrpt_attr/t_avg" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 5 + } + dim { + size: 100 + } + } + tensor_content: "\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "descrpt_attr/t_avg/read" + op: "Identity" + input: "descrpt_attr/t_avg" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@descrpt_attr/t_avg" + } + } + } +} +node { + name: "descrpt_attr/sel" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 5 + } + } + tensor_content: "\005\000\000\000\005\000\000\000\005\000\000\000\005\000\000\000\005\000\000\000" + } + } + } +} +node { + name: "descrpt_attr/ndescrpt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "descrpt_attr/ntypes" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 5 + } + } + } +} +node { + name: "descrpt_attr/rcut" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 4.0 + } + } + } +} +node { + name: "model_attr/output_dim" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "model_attr/model_type" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "dipole" + } + } + } +} +node { + name: "model_attr/sel_type" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\003\000\000\000" + } + } + } +} +node { + name: "model_attr/tmap" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "A B C D E" + } + } + } +} +node { + name: "t_mesh" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "t_natoms" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: 7 + } + } + } + } +} +node { + name: "strided_slice_28" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_28/stack" + input: "strided_slice_28/stack_1" + input: "strided_slice_28/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_26" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_26/stack" + input: "strided_slice_26/stack_1" + input: "strided_slice_26/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_23" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_23/stack" + input: "strided_slice_23/stack_1" + input: "strided_slice_23/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_21" + op: "Mul" + input: "strided_slice_23" + input: "mul_21/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_7/size" + op: "Pack" + input: "Slice_7/size/0" + input: "mul_21" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_22" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_22/stack" + input: "strided_slice_22/stack_1" + input: "strided_slice_22/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_19" + op: "Mul" + input: "strided_slice_22" + input: "mul_19/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_6/size" + op: "Pack" + input: "Slice_6/size/0" + input: "mul_19" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_21" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_21/stack" + input: "strided_slice_21/stack_1" + input: "strided_slice_21/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_18" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_18/stack" + input: "strided_slice_18/stack_1" + input: "strided_slice_18/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_16" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_16/stack" + input: "strided_slice_16/stack_1" + input: "strided_slice_16/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_14" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_14/stack" + input: "strided_slice_14/stack_1" + input: "strided_slice_14/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_13" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_13/stack" + input: "strided_slice_13/stack_1" + input: "strided_slice_13/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_12" + op: "Mul" + input: "strided_slice_13" + input: "mul_12/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_3/size" + op: "Pack" + input: "Slice_3/size/0" + input: "mul_12" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_12" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_12/stack" + input: "strided_slice_12/stack_1" + input: "strided_slice_12/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_10" + op: "Mul" + input: "strided_slice_12" + input: "mul_10/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_2/size" + op: "Pack" + input: "Slice_2/size/0" + input: "mul_10" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_11" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_11/stack" + input: "strided_slice_11/stack_1" + input: "strided_slice_11/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "add" + op: "Add" + input: "add/x" + input: "strided_slice_11" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_1" + op: "Add" + input: "add" + input: "strided_slice_14" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_4" + op: "Add" + input: "add_1" + input: "strided_slice_21" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_20" + op: "Mul" + input: "add_4" + input: "mul_20/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_7/begin" + op: "Pack" + input: "Slice_7/begin/0" + input: "mul_20" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "mul_18" + op: "Mul" + input: "add_4" + input: "mul_18/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_6/begin" + op: "Pack" + input: "Slice_6/begin/0" + input: "mul_18" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "mul_11" + op: "Mul" + input: "add" + input: "mul_11/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_3/begin" + op: "Pack" + input: "Slice_3/begin/0" + input: "mul_11" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "mul_9" + op: "Mul" + input: "add" + input: "mul_9/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_2/begin" + op: "Pack" + input: "Slice_2/begin/0" + input: "mul_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_8" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_8/stack" + input: "strided_slice_8/stack_1" + input: "strided_slice_8/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_6" + op: "Mul" + input: "mul_6/x" + input: "strided_slice_8" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_9/shape" + op: "Pack" + input: "Reshape_9/shape/0" + input: "mul_6" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_7" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_7/stack" + input: "strided_slice_7/stack_1" + input: "strided_slice_7/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_5" + op: "Mul" + input: "mul_5/x" + input: "strided_slice_7" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_8/shape" + op: "Pack" + input: "Reshape_8/shape/0" + input: "mul_5" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_6" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_6/stack" + input: "strided_slice_6/stack_1" + input: "strided_slice_6/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_3" + op: "Mul" + input: "strided_slice_6" + input: "mul_3/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_4" + op: "Mul" + input: "mul_3" + input: "mul_4/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_4" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_4/stack" + input: "strided_slice_4/stack_1" + input: "strided_slice_4/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_2" + op: "Mul" + input: "strided_slice_4" + input: "mul_2/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_2" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_2/stack" + input: "strided_slice_2/stack_1" + input: "strided_slice_2/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_1" + op: "Mul" + input: "mul_1/x" + input: "strided_slice_2" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_4/shape" + op: "Pack" + input: "Reshape_4/shape/0" + input: "mul_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_1" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_1/stack" + input: "strided_slice_1/stack_1" + input: "strided_slice_1/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_2/shape" + op: "Pack" + input: "Reshape_2/shape/0" + input: "strided_slice_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice/stack" + input: "strided_slice/stack_1" + input: "strided_slice/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul" + op: "Mul" + input: "strided_slice" + input: "mul/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape/shape" + op: "Pack" + input: "Reshape/shape/0" + input: "mul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "t_type" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_2" + op: "Reshape" + input: "t_type" + input: "Reshape_2/shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "t_coord" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape" + op: "Reshape" + input: "t_coord" + input: "Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "t_box" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_1" + op: "Reshape" + input: "t_box" + input: "Reshape_1/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "ProdEnvMatA" + op: "ProdEnvMatA" + input: "Reshape" + input: "Reshape_2" + input: "t_natoms" + input: "Reshape_1" + input: "t_mesh" + input: "descrpt_attr/t_avg/read" + input: "descrpt_attr/t_std/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "rcut_a" + value { + f: -1.0 + } + } + attr { + key: "rcut_r" + value { + f: 4.0 + } + } + attr { + key: "rcut_r_smth" + value { + f: 0.80000001 + } + } + attr { + key: "sel_a" + value { + list { + i: 5 + i: 5 + i: 5 + i: 5 + i: 5 + } + } + } + attr { + key: "sel_r" + value { + list { + i: 0 + i: 0 + i: 0 + i: 0 + i: 0 + } + } + } +} +node { + name: "o_nlist" + op: "Identity" + input: "ProdEnvMatA:3" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "o_rij" + op: "Identity" + input: "ProdEnvMatA:2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "o_rmat_deriv" + op: "Identity" + input: "ProdEnvMatA:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_3" + op: "Reshape" + input: "ProdEnvMatA" + input: "Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_rmat" + op: "Identity" + input: "Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_4" + op: "Reshape" + input: "o_rmat" + input: "Reshape_4/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_1" + op: "Shape" + input: "Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_5" + op: "StridedSlice" + input: "Shape_1" + input: "strided_slice_5/stack" + input: "strided_slice_5/stack_1" + input: "strided_slice_5/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_7/shape" + op: "Pack" + input: "strided_slice_5" + input: "mul_4" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Shape" + op: "Shape" + input: "Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_3" + op: "StridedSlice" + input: "Shape" + input: "strided_slice_3/stack" + input: "strided_slice_3/stack_1" + input: "strided_slice_3/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_6/shape" + op: "Pack" + input: "strided_slice_3" + input: "mul_2" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Reshape_5" + op: "Reshape" + input: "Reshape_4" + input: "Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Slice_8" + op: "Slice" + input: "Reshape_5" + input: "filter_type_all/Slice_8/begin" + input: "filter_type_all/Slice_8/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_34" + op: "Reshape" + input: "filter_type_all/Slice_8" + input: "filter_type_all/Reshape_34/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_28" + op: "Reshape" + input: "filter_type_all/Slice_8" + input: "filter_type_all/Reshape_28/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Slice_9" + op: "Slice" + input: "filter_type_all/Reshape_28" + input: "filter_type_all/Slice_9/begin" + input: "filter_type_all/Slice_9/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_29" + op: "Reshape" + input: "filter_type_all/Slice_9" + input: "filter_type_all/Reshape_29/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/concat_12" + op: "ConcatV2" + input: "filter_type_all/Reshape_29" + input: "filter_type_all/Reshape_29" + input: "filter_type_all/concat_12/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_16" + op: "MatMul" + input: "filter_type_all/Reshape_29" + input: "filter_type_all/matrix_1_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_all/add_27" + op: "Add" + input: "filter_type_all/MatMul_16" + input: "filter_type_all/bias_1_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_12" + op: "Tanh" + input: "filter_type_all/add_27" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_30" + op: "Reshape" + input: "filter_type_all/Tanh_12" + input: "filter_type_all/Reshape_30/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_28" + op: "Add" + input: "filter_type_all/concat_12" + input: "filter_type_all/Reshape_30" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/concat_13" + op: "ConcatV2" + input: "filter_type_all/add_28" + input: "filter_type_all/add_28" + input: "filter_type_all/concat_13/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_17" + op: "MatMul" + input: "filter_type_all/add_28" + input: "filter_type_all/matrix_2_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_all/add_29" + op: "Add" + input: "filter_type_all/MatMul_17" + input: "filter_type_all/bias_2_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_13" + op: "Tanh" + input: "filter_type_all/add_29" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_31" + op: "Reshape" + input: "filter_type_all/Tanh_13" + input: "filter_type_all/Reshape_31/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_30" + op: "Add" + input: "filter_type_all/concat_13" + input: "filter_type_all/Reshape_31" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/concat_14" + op: "ConcatV2" + input: "filter_type_all/add_30" + input: "filter_type_all/add_30" + input: "filter_type_all/concat_14/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_18" + op: "MatMul" + input: "filter_type_all/add_30" + input: "filter_type_all/matrix_3_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_all/add_31" + op: "Add" + input: "filter_type_all/MatMul_18" + input: "filter_type_all/bias_3_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_14" + op: "Tanh" + input: "filter_type_all/add_31" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_32" + op: "Reshape" + input: "filter_type_all/Tanh_14" + input: "filter_type_all/Reshape_32/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_32" + op: "Add" + input: "filter_type_all/concat_14" + input: "filter_type_all/Reshape_32" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_33" + op: "Reshape" + input: "filter_type_all/add_32" + input: "filter_type_all/Reshape_33/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_19" + op: "BatchMatMul" + input: "filter_type_all/Reshape_34" + input: "filter_type_all/Reshape_33" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "filter_type_all/Slice_6" + op: "Slice" + input: "Reshape_5" + input: "filter_type_all/Slice_6/begin" + input: "filter_type_all/Slice_6/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_27" + op: "Reshape" + input: "filter_type_all/Slice_6" + input: "filter_type_all/Reshape_27/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_21" + op: "Reshape" + input: "filter_type_all/Slice_6" + input: "filter_type_all/Reshape_21/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Slice_7" + op: "Slice" + input: "filter_type_all/Reshape_21" + input: "filter_type_all/Slice_7/begin" + input: "filter_type_all/Slice_7/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_22" + op: "Reshape" + input: "filter_type_all/Slice_7" + input: "filter_type_all/Reshape_22/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/concat_9" + op: "ConcatV2" + input: "filter_type_all/Reshape_22" + input: "filter_type_all/Reshape_22" + input: "filter_type_all/concat_9/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_12" + op: "MatMul" + input: "filter_type_all/Reshape_22" + input: "filter_type_all/matrix_1_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_all/add_20" + op: "Add" + input: "filter_type_all/MatMul_12" + input: "filter_type_all/bias_1_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_9" + op: "Tanh" + input: "filter_type_all/add_20" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_23" + op: "Reshape" + input: "filter_type_all/Tanh_9" + input: "filter_type_all/Reshape_23/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_21" + op: "Add" + input: "filter_type_all/concat_9" + input: "filter_type_all/Reshape_23" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/concat_10" + op: "ConcatV2" + input: "filter_type_all/add_21" + input: "filter_type_all/add_21" + input: "filter_type_all/concat_10/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_13" + op: "MatMul" + input: "filter_type_all/add_21" + input: "filter_type_all/matrix_2_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_all/add_22" + op: "Add" + input: "filter_type_all/MatMul_13" + input: "filter_type_all/bias_2_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_10" + op: "Tanh" + input: "filter_type_all/add_22" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_24" + op: "Reshape" + input: "filter_type_all/Tanh_10" + input: "filter_type_all/Reshape_24/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_23" + op: "Add" + input: "filter_type_all/concat_10" + input: "filter_type_all/Reshape_24" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/concat_11" + op: "ConcatV2" + input: "filter_type_all/add_23" + input: "filter_type_all/add_23" + input: "filter_type_all/concat_11/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_14" + op: "MatMul" + input: "filter_type_all/add_23" + input: "filter_type_all/matrix_3_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_all/add_24" + op: "Add" + input: "filter_type_all/MatMul_14" + input: "filter_type_all/bias_3_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_11" + op: "Tanh" + input: "filter_type_all/add_24" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_25" + op: "Reshape" + input: "filter_type_all/Tanh_11" + input: "filter_type_all/Reshape_25/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_25" + op: "Add" + input: "filter_type_all/concat_11" + input: "filter_type_all/Reshape_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_26" + op: "Reshape" + input: "filter_type_all/add_25" + input: "filter_type_all/Reshape_26/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_15" + op: "BatchMatMul" + input: "filter_type_all/Reshape_27" + input: "filter_type_all/Reshape_26" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "filter_type_all/Slice_4" + op: "Slice" + input: "Reshape_5" + input: "filter_type_all/Slice_4/begin" + input: "filter_type_all/Slice_4/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_20" + op: "Reshape" + input: "filter_type_all/Slice_4" + input: "filter_type_all/Reshape_20/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_14" + op: "Reshape" + input: "filter_type_all/Slice_4" + input: "filter_type_all/Reshape_14/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Slice_5" + op: "Slice" + input: "filter_type_all/Reshape_14" + input: "filter_type_all/Slice_5/begin" + input: "filter_type_all/Slice_5/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_15" + op: "Reshape" + input: "filter_type_all/Slice_5" + input: "filter_type_all/Reshape_15/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/concat_6" + op: "ConcatV2" + input: "filter_type_all/Reshape_15" + input: "filter_type_all/Reshape_15" + input: "filter_type_all/concat_6/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_8" + op: "MatMul" + input: "filter_type_all/Reshape_15" + input: "filter_type_all/matrix_1_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_all/add_13" + op: "Add" + input: "filter_type_all/MatMul_8" + input: "filter_type_all/bias_1_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_6" + op: "Tanh" + input: "filter_type_all/add_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_16" + op: "Reshape" + input: "filter_type_all/Tanh_6" + input: "filter_type_all/Reshape_16/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_14" + op: "Add" + input: "filter_type_all/concat_6" + input: "filter_type_all/Reshape_16" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/concat_7" + op: "ConcatV2" + input: "filter_type_all/add_14" + input: "filter_type_all/add_14" + input: "filter_type_all/concat_7/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_9" + op: "MatMul" + input: "filter_type_all/add_14" + input: "filter_type_all/matrix_2_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_all/add_15" + op: "Add" + input: "filter_type_all/MatMul_9" + input: "filter_type_all/bias_2_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_7" + op: "Tanh" + input: "filter_type_all/add_15" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_17" + op: "Reshape" + input: "filter_type_all/Tanh_7" + input: "filter_type_all/Reshape_17/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_16" + op: "Add" + input: "filter_type_all/concat_7" + input: "filter_type_all/Reshape_17" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/concat_8" + op: "ConcatV2" + input: "filter_type_all/add_16" + input: "filter_type_all/add_16" + input: "filter_type_all/concat_8/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_10" + op: "MatMul" + input: "filter_type_all/add_16" + input: "filter_type_all/matrix_3_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_all/add_17" + op: "Add" + input: "filter_type_all/MatMul_10" + input: "filter_type_all/bias_3_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_8" + op: "Tanh" + input: "filter_type_all/add_17" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_18" + op: "Reshape" + input: "filter_type_all/Tanh_8" + input: "filter_type_all/Reshape_18/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_18" + op: "Add" + input: "filter_type_all/concat_8" + input: "filter_type_all/Reshape_18" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_19" + op: "Reshape" + input: "filter_type_all/add_18" + input: "filter_type_all/Reshape_19/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_11" + op: "BatchMatMul" + input: "filter_type_all/Reshape_20" + input: "filter_type_all/Reshape_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "filter_type_all/Slice_2" + op: "Slice" + input: "Reshape_5" + input: "filter_type_all/Slice_2/begin" + input: "filter_type_all/Slice_2/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_13" + op: "Reshape" + input: "filter_type_all/Slice_2" + input: "filter_type_all/Reshape_13/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_7" + op: "Reshape" + input: "filter_type_all/Slice_2" + input: "filter_type_all/Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Slice_3" + op: "Slice" + input: "filter_type_all/Reshape_7" + input: "filter_type_all/Slice_3/begin" + input: "filter_type_all/Slice_3/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_8" + op: "Reshape" + input: "filter_type_all/Slice_3" + input: "filter_type_all/Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/concat_3" + op: "ConcatV2" + input: "filter_type_all/Reshape_8" + input: "filter_type_all/Reshape_8" + input: "filter_type_all/concat_3/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_4" + op: "MatMul" + input: "filter_type_all/Reshape_8" + input: "filter_type_all/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_all/add_6" + op: "Add" + input: "filter_type_all/MatMul_4" + input: "filter_type_all/bias_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_3" + op: "Tanh" + input: "filter_type_all/add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_9" + op: "Reshape" + input: "filter_type_all/Tanh_3" + input: "filter_type_all/Reshape_9/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_7" + op: "Add" + input: "filter_type_all/concat_3" + input: "filter_type_all/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/concat_4" + op: "ConcatV2" + input: "filter_type_all/add_7" + input: "filter_type_all/add_7" + input: "filter_type_all/concat_4/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_5" + op: "MatMul" + input: "filter_type_all/add_7" + input: "filter_type_all/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_all/add_8" + op: "Add" + input: "filter_type_all/MatMul_5" + input: "filter_type_all/bias_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_4" + op: "Tanh" + input: "filter_type_all/add_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_10" + op: "Reshape" + input: "filter_type_all/Tanh_4" + input: "filter_type_all/Reshape_10/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_9" + op: "Add" + input: "filter_type_all/concat_4" + input: "filter_type_all/Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/concat_5" + op: "ConcatV2" + input: "filter_type_all/add_9" + input: "filter_type_all/add_9" + input: "filter_type_all/concat_5/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_6" + op: "MatMul" + input: "filter_type_all/add_9" + input: "filter_type_all/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_all/add_10" + op: "Add" + input: "filter_type_all/MatMul_6" + input: "filter_type_all/bias_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_5" + op: "Tanh" + input: "filter_type_all/add_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_11" + op: "Reshape" + input: "filter_type_all/Tanh_5" + input: "filter_type_all/Reshape_11/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_11" + op: "Add" + input: "filter_type_all/concat_5" + input: "filter_type_all/Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_12" + op: "Reshape" + input: "filter_type_all/add_11" + input: "filter_type_all/Reshape_12/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_7" + op: "BatchMatMul" + input: "filter_type_all/Reshape_13" + input: "filter_type_all/Reshape_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "filter_type_all/Slice" + op: "Slice" + input: "Reshape_5" + input: "filter_type_all/Slice/begin" + input: "filter_type_all/Slice/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_6" + op: "Reshape" + input: "filter_type_all/Slice" + input: "filter_type_all/Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape" + op: "Reshape" + input: "filter_type_all/Slice" + input: "filter_type_all/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Slice_1" + op: "Slice" + input: "filter_type_all/Reshape" + input: "filter_type_all/Slice_1/begin" + input: "filter_type_all/Slice_1/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_1" + op: "Reshape" + input: "filter_type_all/Slice_1" + input: "filter_type_all/Reshape_1/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/concat" + op: "ConcatV2" + input: "filter_type_all/Reshape_1" + input: "filter_type_all/Reshape_1" + input: "filter_type_all/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul" + op: "MatMul" + input: "filter_type_all/Reshape_1" + input: "filter_type_all/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_all/add" + op: "Add" + input: "filter_type_all/MatMul" + input: "filter_type_all/bias_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh" + op: "Tanh" + input: "filter_type_all/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_2" + op: "Reshape" + input: "filter_type_all/Tanh" + input: "filter_type_all/Reshape_2/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_1" + op: "Add" + input: "filter_type_all/concat" + input: "filter_type_all/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/concat_1" + op: "ConcatV2" + input: "filter_type_all/add_1" + input: "filter_type_all/add_1" + input: "filter_type_all/concat_1/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_1" + op: "MatMul" + input: "filter_type_all/add_1" + input: "filter_type_all/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_all/add_2" + op: "Add" + input: "filter_type_all/MatMul_1" + input: "filter_type_all/bias_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_1" + op: "Tanh" + input: "filter_type_all/add_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_3" + op: "Reshape" + input: "filter_type_all/Tanh_1" + input: "filter_type_all/Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_3" + op: "Add" + input: "filter_type_all/concat_1" + input: "filter_type_all/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/concat_2" + op: "ConcatV2" + input: "filter_type_all/add_3" + input: "filter_type_all/add_3" + input: "filter_type_all/concat_2/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_2" + op: "MatMul" + input: "filter_type_all/add_3" + input: "filter_type_all/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "filter_type_all/add_4" + op: "Add" + input: "filter_type_all/MatMul_2" + input: "filter_type_all/bias_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_2" + op: "Tanh" + input: "filter_type_all/add_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_4" + op: "Reshape" + input: "filter_type_all/Tanh_2" + input: "filter_type_all/Reshape_4/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_5" + op: "Add" + input: "filter_type_all/concat_2" + input: "filter_type_all/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Reshape_5" + op: "Reshape" + input: "filter_type_all/add_5" + input: "filter_type_all/Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_3" + op: "BatchMatMul" + input: "filter_type_all/Reshape_6" + input: "filter_type_all/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "filter_type_all/add_12" + op: "Add" + input: "filter_type_all/MatMul_3" + input: "filter_type_all/MatMul_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/add_19" + op: "Add" + input: "filter_type_all/add_12" + input: "filter_type_all/MatMul_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/add_26" + op: "Add" + input: "filter_type_all/add_19" + input: "filter_type_all/MatMul_15" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/add_33" + op: "Add" + input: "filter_type_all/add_26" + input: "filter_type_all/MatMul_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/mul" + op: "Mul" + input: "filter_type_all/add_33" + input: "filter_type_all/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Slice_11" + op: "Slice" + input: "filter_type_all/mul" + input: "filter_type_all/Slice_11/begin" + input: "filter_type_all/Slice_11/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/transpose" + op: "Transpose" + input: "filter_type_all/Slice_11" + input: "filter_type_all/transpose/perm" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tperm" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_7" + op: "Reshape" + input: "filter_type_all/transpose" + input: "Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "concat_1" + op: "Identity" + input: "Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "o_rot_mat" + op: "Identity" + input: "concat_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_9" + op: "Reshape" + input: "o_rot_mat" + input: "Reshape_9/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_7" + op: "Slice" + input: "Reshape_9" + input: "Slice_7/begin" + input: "Slice_7/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_19" + op: "Reshape" + input: "Slice_7" + input: "Reshape_19/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_3" + op: "Slice" + input: "Reshape_9" + input: "Slice_3/begin" + input: "Slice_3/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_13" + op: "Reshape" + input: "Slice_3" + input: "Reshape_13/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Slice_10" + op: "Slice" + input: "filter_type_all/mul" + input: "filter_type_all/Slice_10/begin" + input: "filter_type_all/Slice_10/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/MatMul_20" + op: "BatchMatMul" + input: "filter_type_all/mul" + input: "filter_type_all/Slice_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "filter_type_all/Reshape_35" + op: "Reshape" + input: "filter_type_all/MatMul_20" + input: "filter_type_all/Reshape_35/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_6" + op: "Reshape" + input: "filter_type_all/Reshape_35" + input: "Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "concat" + op: "Identity" + input: "Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "o_descriptor" + op: "Identity" + input: "concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_8" + op: "Reshape" + input: "o_descriptor" + input: "Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_5" + op: "Shape" + input: "Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_27" + op: "StridedSlice" + input: "Shape_5" + input: "strided_slice_27/stack" + input: "strided_slice_27/stack_1" + input: "strided_slice_27/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_21/shape" + op: "Pack" + input: "strided_slice_27" + input: "strided_slice_28" + input: "Reshape_21/shape/2" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Shape_4" + op: "Shape" + input: "Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_25" + op: "StridedSlice" + input: "Shape_4" + input: "strided_slice_25/stack" + input: "strided_slice_25/stack_1" + input: "strided_slice_25/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_22" + op: "Mul" + input: "strided_slice_25" + input: "strided_slice_26" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_20/shape" + op: "Pack" + input: "mul_22" + input: "Reshape_20/shape/1" + input: "Reshape_20/shape/2" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_6" + op: "Slice" + input: "Reshape_8" + input: "Slice_6/begin" + input: "Slice_6/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_18" + op: "Reshape" + input: "Slice_6" + input: "Reshape_18/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_3/MatMul" + op: "MatMul" + input: "Reshape_18" + input: "layer_0_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "layer_0_type_3/add" + op: "Add" + input: "layer_0_type_3/MatMul" + input: "layer_0_type_3/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_0_type_3/Tanh" + op: "Tanh" + input: "layer_0_type_3/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_0_type_3/Reshape" + op: "Reshape" + input: "layer_0_type_3/Tanh" + input: "layer_0_type_3/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_3/MatMul" + op: "MatMul" + input: "layer_0_type_3/Reshape" + input: "layer_1_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "layer_1_type_3/add" + op: "Add" + input: "layer_1_type_3/MatMul" + input: "layer_1_type_3/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_1_type_3/Tanh" + op: "Tanh" + input: "layer_1_type_3/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_1_type_3/Reshape" + op: "Reshape" + input: "layer_1_type_3/Tanh" + input: "layer_1_type_3/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_3/mul" + op: "Mul" + input: "layer_1_type_3/Reshape" + input: "layer_1_type_3/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "add_6" + op: "Add" + input: "layer_0_type_3/Reshape" + input: "layer_1_type_3/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_3/MatMul" + op: "MatMul" + input: "add_6" + input: "layer_2_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "layer_2_type_3/add" + op: "Add" + input: "layer_2_type_3/MatMul" + input: "layer_2_type_3/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_3/Tanh" + op: "Tanh" + input: "layer_2_type_3/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_3/Reshape" + op: "Reshape" + input: "layer_2_type_3/Tanh" + input: "layer_2_type_3/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_3/mul" + op: "Mul" + input: "layer_2_type_3/Reshape" + input: "layer_2_type_3/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "add_7" + op: "Add" + input: "add_6" + input: "layer_2_type_3/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "final_layer_type_3/MatMul" + op: "MatMul" + input: "add_7" + input: "final_layer_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "final_layer_type_3/add" + op: "Add" + input: "final_layer_type_3/MatMul" + input: "final_layer_type_3/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_20" + op: "Reshape" + input: "final_layer_type_3/add" + input: "Reshape_20/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "MatMul_1" + op: "BatchMatMul" + input: "Reshape_20" + input: "Reshape_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "Reshape_21" + op: "Reshape" + input: "MatMul_1" + input: "Reshape_21/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_3" + op: "Shape" + input: "Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_17" + op: "StridedSlice" + input: "Shape_3" + input: "strided_slice_17/stack" + input: "strided_slice_17/stack_1" + input: "strided_slice_17/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_15/shape" + op: "Pack" + input: "strided_slice_17" + input: "strided_slice_18" + input: "Reshape_15/shape/2" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Shape_2" + op: "Shape" + input: "Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_15" + op: "StridedSlice" + input: "Shape_2" + input: "strided_slice_15/stack" + input: "strided_slice_15/stack_1" + input: "strided_slice_15/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_13" + op: "Mul" + input: "strided_slice_15" + input: "strided_slice_16" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_14/shape" + op: "Pack" + input: "mul_13" + input: "Reshape_14/shape/1" + input: "Reshape_14/shape/2" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_2" + op: "Slice" + input: "Reshape_8" + input: "Slice_2/begin" + input: "Slice_2/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_12" + op: "Reshape" + input: "Slice_2" + input: "Reshape_12/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_1/MatMul" + op: "MatMul" + input: "Reshape_12" + input: "layer_0_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "layer_0_type_1/add" + op: "Add" + input: "layer_0_type_1/MatMul" + input: "layer_0_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_0_type_1/Tanh" + op: "Tanh" + input: "layer_0_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_0_type_1/Reshape" + op: "Reshape" + input: "layer_0_type_1/Tanh" + input: "layer_0_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/MatMul" + op: "MatMul" + input: "layer_0_type_1/Reshape" + input: "layer_1_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "layer_1_type_1/add" + op: "Add" + input: "layer_1_type_1/MatMul" + input: "layer_1_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_1_type_1/Tanh" + op: "Tanh" + input: "layer_1_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_1_type_1/Reshape" + op: "Reshape" + input: "layer_1_type_1/Tanh" + input: "layer_1_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/mul" + op: "Mul" + input: "layer_1_type_1/Reshape" + input: "layer_1_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "add_2" + op: "Add" + input: "layer_0_type_1/Reshape" + input: "layer_1_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_1/MatMul" + op: "MatMul" + input: "add_2" + input: "layer_2_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "layer_2_type_1/add" + op: "Add" + input: "layer_2_type_1/MatMul" + input: "layer_2_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_1/Tanh" + op: "Tanh" + input: "layer_2_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_1/Reshape" + op: "Reshape" + input: "layer_2_type_1/Tanh" + input: "layer_2_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/mul" + op: "Mul" + input: "layer_2_type_1/Reshape" + input: "layer_2_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "add_3" + op: "Add" + input: "add_2" + input: "layer_2_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "final_layer_type_1/MatMul" + op: "MatMul" + input: "add_3" + input: "final_layer_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "final_layer_type_1/add" + op: "Add" + input: "final_layer_type_1/MatMul" + input: "final_layer_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_14" + op: "Reshape" + input: "final_layer_type_1/add" + input: "Reshape_14/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "MatMul" + op: "BatchMatMul" + input: "Reshape_14" + input: "Reshape_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "Reshape_15" + op: "Reshape" + input: "MatMul" + input: "Reshape_15/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "concat_2" + op: "ConcatV2" + input: "Reshape_15" + input: "Reshape_21" + input: "concat_2/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_24" + op: "Reshape" + input: "concat_2" + input: "Reshape_24/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_dipole" + op: "Identity" + input: "Reshape_24" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +library { +} diff --git a/source/tests/infer/dipolecharge_e.pbtxt b/source/tests/infer/dipolecharge_e.pbtxt new file mode 100644 index 0000000000..61326137aa --- /dev/null +++ b/source/tests/infer/dipolecharge_e.pbtxt @@ -0,0 +1,104104 @@ +node { + name: "o_atom_virial/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_46/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 9 + } + } + } +} +node { + name: "strided_slice_79/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_79/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_79/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "o_virial/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\t\000\000\000" + } + } + } +} +node { + name: "o_force/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_45/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_78/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_78/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_78/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "Reshape_37/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_44/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_77/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_77/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_77/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_2_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_2_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_2_grad/stack" + op: "Pack" + input: "gradients_3/filter_type_all/Slice_2_grad/Rank" + input: "gradients_3/filter_type_all/Slice_2_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_grad/stack" + op: "Pack" + input: "gradients_3/filter_type_all/Slice_grad/Rank" + input: "gradients_3/filter_type_all/Slice_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_4_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_4_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_4_grad/stack" + op: "Pack" + input: "gradients_3/filter_type_all/Slice_4_grad/Rank" + input: "gradients_3/filter_type_all/Slice_4_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_6_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_6_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_6_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_6_grad/stack" + op: "Pack" + input: "gradients_3/filter_type_all/Slice_6_grad/Rank" + input: "gradients_3/filter_type_all/Slice_6_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_3_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_3_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_3_grad/stack" + op: "Pack" + input: "gradients_3/filter_type_all/Slice_3_grad/Rank" + input: "gradients_3/filter_type_all/Slice_3_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_1_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_1_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_1_grad/stack" + op: "Pack" + input: "gradients_3/filter_type_all/Slice_1_grad/Rank" + input: "gradients_3/filter_type_all/Slice_1_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_8_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_8_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_8_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_8_grad/stack" + op: "Pack" + input: "gradients_3/filter_type_all/Slice_8_grad/Rank" + input: "gradients_3/filter_type_all/Slice_8_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_5_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_5_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_5_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_5_grad/stack" + op: "Pack" + input: "gradients_3/filter_type_all/Slice_5_grad/Rank" + input: "gradients_3/filter_type_all/Slice_5_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_7_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_7_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_7_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_7_grad/stack" + op: "Pack" + input: "gradients_3/filter_type_all/Slice_7_grad/Rank" + input: "gradients_3/filter_type_all/Slice_7_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_9_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_9_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_9_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_9_grad/stack" + op: "Pack" + input: "gradients_3/filter_type_all/Slice_9_grad/Rank" + input: "gradients_3/filter_type_all/Slice_9_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/filter_type_all/add_6_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_13_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_20_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_27_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_6_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_9_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_12_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_8_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_2_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_15_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_22_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_29_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_7_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_10_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_13_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_10_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_4_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_17_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_24_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_5_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_31_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_8_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_11_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_14_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/filter_type_all/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + } + } + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_10_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_10_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_10_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_10_grad/stack" + op: "Pack" + input: "gradients_3/filter_type_all/Slice_10_grad/Rank" + input: "gradients_3/filter_type_all/Slice_10_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/Slice_14_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/Slice_14_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/Slice_14_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/Slice_14_grad/stack" + op: "Pack" + input: "gradients_3/Slice_14_grad/Rank" + input: "gradients_3/Slice_14_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/Slice_13_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/Slice_13_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/Slice_13_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/Slice_13_grad/stack" + op: "Pack" + input: "gradients_3/Slice_13_grad/Rank" + input: "gradients_3/Slice_13_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/Slice_15_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/Slice_15_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/Slice_15_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/Slice_15_grad/stack" + op: "Pack" + input: "gradients_3/Slice_15_grad/Rank" + input: "gradients_3/Slice_15_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/Slice_16_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/Slice_16_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/Slice_16_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/Slice_16_grad/stack" + op: "Pack" + input: "gradients_3/Slice_16_grad/Rank" + input: "gradients_3/Slice_16_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/Slice_17_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/Slice_17_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/Slice_17_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/Slice_17_grad/stack" + op: "Pack" + input: "gradients_3/Slice_17_grad/Rank" + input: "gradients_3/Slice_17_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/layer_0_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_0_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_0_type_2/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_0_type_3/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_0_type_4/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_1_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_1_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_1_type_2/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_1_type_3/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_1_type_4/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_1_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_1_type_0/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_1_type_2/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_1_type_3/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_1_type_4/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_2_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_2_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_2_type_2/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_2_type_3/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_2_type_4/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_2_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_2_type_0/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_2_type_2/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_2_type_3/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/layer_2_type_4/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_3/final_layer_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/final_layer_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/final_layer_type_2/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/final_layer_type_3/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/concat_8_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/final_layer_type_4/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/concat_9_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/concat_10_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/concat_11_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_3/grad_ys_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 1.0 + } + } + } +} +node { + name: "o_energy/reduction_indices" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "o_atom_energy/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "strided_slice_76/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_76/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_76/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_36/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: -1 + } + } + } +} +node { + name: "concat_11/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/concat_11_grad/mod" + op: "FloorMod" + input: "concat_11/axis" + input: "gradients_3/concat_11_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_75/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_75/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 7 + } + } + } +} +node { + name: "strided_slice_75/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "strided_slice_74/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_74/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_74/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "final_layer_type_4/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + } + double_val: -0.12484880574654916 + } + } + } +} +node { + name: "final_layer_type_4/bias/read" + op: "Identity" + input: "final_layer_type_4/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_4/bias" + } + } + } +} +node { + name: "final_layer_type_4/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + dim { + size: 1 + } + } + tensor_content: "\021G\037\23257\254?\265c6\035\370g\302\277}\323lO\3610\320\277\035\317Cz\214V\254\277q%\360l\351\213\343?\007P\265\335B\027\303\277\256B\327\257\351\266\302?tp\336E\314\243\341\277" + } + } + } +} +node { + name: "final_layer_type_4/matrix/read" + op: "Identity" + input: "final_layer_type_4/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_4/matrix" + } + } + } +} +node { + name: "layer_2_type_4/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "layer_2_type_4/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "V\261\013\021\261(\263?f\221g\322\370\330\262?\355\247?\355\236\311\262?Wd\016Tx3\263?\r\205r\362\255w\263?\272wR)\r\371\262?\364\027\030\004>\"\263?.\240\n\3151\212\262?" + } + } + } +} +node { + name: "layer_2_type_4/idt/read" + op: "Identity" + input: "layer_2_type_4/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_4/idt" + } + } + } +} +node { + name: "layer_2_type_4/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "\320&&j\312\325\313?\263^Q.\317\357\324\277Kx#V\373\361\351\277j\264\363C)\357\313\277\233aE\213\t\'\376?\264\204\200C1\373\325\277\274i\236k\320^\325?\266\232\025\006\252\013\373\277" + } + } + } +} +node { + name: "layer_2_type_4/bias/read" + op: "Identity" + input: "layer_2_type_4/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_4/bias" + } + } + } +} +node { + name: "layer_2_type_4/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + dim { + size: 8 + } + } + tensor_content: "\364\0367\202V\037\242?<\031n\003\216\002\260\277\271\0056\340rz\307\277\253e\340U\352:\242\277N\357\007Y\024\367\334?Z{v\371\253\010\261\277\242\274\3145RP\260?\260\251\271\340\021\316\331\277\207\312P\376\255\256\301?\335\322A\320\212\337\304\277b\304\250\277#K\261?\356\303w6\271\034\315\277C\006\r\307W}\214?\243\345`P\"\370\331?\231\302N\230o\272\307?\031u\253\344x\302\276\277\341\345\002\307\021V\316\277\340\256\322)\254\256\342?\246I\263.\307\222\274\277zr\'5u%\272?\223!y\035\3556\311?\300\342\024\376Z\240\277?,\023\262\231\nk\264?\346\304\367_\315\263\275\277\007\216\3630#W\264\277\267\341g\004W\355\227?)c\260\233\266\331\220\277\2605\347\223\\\241\341\277\223\016V\177\315x\317\277P\325\331\270,\252\303\277f\244\231\331\242\312\306\277$\3301\3411\323\303\277\375\036\025\321\246\276\277\250\023\302\261\231E\326\277\357e\332w\334\246\220\277\336\225\344\245\217\357\261?\240\2352\330R\275\320?(\333\327\'Q\313\274\277\1773\241_i\\\276\277L\204\000\350i\374\334?;\240\371\343~`\263\277 \206\247\232x\025\343\277\257\350\340sq\235\301?\3359\013\204\t\212\255?\201W\314\342\026\337\276\277T\033\313YU\263\227\277\021\0106\007\264X\207\277\3201\222\256\270\316\322?\245J\373A2\267s?\002\024Z0\244\223\323\277\226\270\310/Z1\247?" + } + } + } +} +node { + name: "layer_2_type_4/matrix/read" + op: "Identity" + input: "layer_2_type_4/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_4/matrix" + } + } + } +} +node { + name: "layer_1_type_4/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "layer_1_type_4/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "Z\356\026\256\204\'\263?\245\362Z[:\330\262?\334\326\322\017\355\311\262?`\374\362\\\3051\263?@f|\226\302w\263?s\255\225\001}\372\262?\371\r\2279\360\"\263?;\237s\000,\212\262?" + } + } + } +} +node { + name: "layer_1_type_4/idt/read" + op: "Identity" + input: "layer_1_type_4/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_4/idt" + } + } + } +} +node { + name: "layer_1_type_4/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "}\264\014\366\024\326\313?\025\356\206\243\031\360\324\277\231.~.$\362\351\277c|\335\0379\357\313\277\037\311\341\375?\'\376?\364\375\277\022:\373\325\277\301\267n%\322^\325?\332c\201\346\243\013\373\277" + } + } + } +} +node { + name: "layer_1_type_4/bias/read" + op: "Identity" + input: "layer_1_type_4/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_4/bias" + } + } + } +} +node { + name: "layer_1_type_4/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + dim { + size: 8 + } + } + tensor_content: "\014\203\216\016V\036\242?*X4\025\236\002\260\277\277&\215\235^z\307\277\263\366o\321\3677\242\277\032\376.\273\007\370\334?\177\277\241l\222\007\261\277\255\205\367;\323N\260?\334\241\344j\234\314\331\277\006!\314\017P\262\301?[\310G\300|\331\304\277\027\024\371\177A4\261?\007vLm5\037\315\2776\202_\3605\031u?A\202\257Lf\367\331?\245oaRx\360\306?\'}8\234KM\265\277G\305s}\244U\316\277{\266K+\250\256\342?m6\003\007\345\222\274\277H\262\216\354\375#\272?f\205\215\306\3135\311?%x\347\333&\237\277?\0349\201s@l\264?.\351\342\020\177\266\275\277f\355\3116\311V\264\277\277\324\331\355\023\356\227?i\024\t*\377\330\220\277)\234\230\177\206\241\341\277\304\220\351\306sz\317\277\271\367i\315\254\252\303\277\344\326\242\265\032\312\306\277\363\t\341\274\307\325\303\277\277T\237(\032\265\260\277\303k\250F\323\247\316\277\243\t\376R\010\204\306\277\243\313\314\265xQ\251\277\256]\"\003F\222\316?\216\340\220\022\234\371\266?+E|W~.\251\277\2033\250[Mh\306\277\230\345\222u\262*\310\277y\357\230*w\306\337?\036\217\327\210\254N\322\277\256Ol\264\214\r\256\277\266\260\275\366\261\005\305?oZ\270\257\322\250\276\277\365\213\034\234@\\\326\277\264\215\363\034V\367l?sFy\203o\345\261?\357\233\231\201z\276\320?$2\317\357\316\265\274\277 A\031\232\343T\276\277+\342\021lVf\335?P\324\370\236:[\263\277&JG \014\376\342\277\020S\010\207\026|\273?\320\366\304$y\367\254?\332(\260\017y\304\276\277\244Q\326Gr\346\226\277\332\362\263\215^-\203\277\255|\245\t\367\313\322?\306*\246&\346\207~?\212;\006r\033\264\323\277\253\260\305\371\265\255\247?" + } + } + } +} +node { + name: "layer_1_type_4/matrix/read" + op: "Identity" + input: "layer_1_type_4/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_4/matrix" + } + } + } +} +node { + name: "layer_0_type_4/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "layer_0_type_4/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "\213\373\334\2566\316\313?5O\230z\r\354\324\277r\371\316\334\327\360\351\277%E\032i\007\347\313\277\013\367\366\234o%\376?\r+\300+P\367\325\277]B\275\367K`\325?y\322b\034\004\037\373\277" + } + } + } +} +node { + name: "layer_0_type_4/bias/read" + op: "Identity" + input: "layer_0_type_4/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_4/bias" + } + } + } +} +node { + name: "layer_0_type_4/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 32 + } + dim { + size: 8 + } + } + tensor_content: "\226\375\243\233\236X\212?\333d$\247\'\177\236\277\323\n\360\351\214A\273\277\347RUT\244\240\212\277\225\254\003\251\\\254\321?\272\377\356\342\037\223\240\277\271Y*C\340\250\237?\275\237-\365\002?\320\277y%\316\204\315\351\263?\251m\343\311\366\307\267\277\203\003\003\336\240\241\252?\240\205#\267\333/\301\277m`k\234\007q\214\277\226\224*\026q\r\321?\307\014\254\221=\032\270?\241\207\222\231.\213\252\277\263\214fo\217|\310\277\002_3GgU\332?_\016\343\315\306_\235\277+\311<\324\004\036\273?\312^?\374\3154\265?x\035\253\213\316\316\276?#\267J\007Fa\200?b8W\306\rI\244\277\264\030\350D\211\335\244\277\031\257Ib\020\226t?\374\024#%\362k\224\277\0078\212\351\262\350\326\277\3079\244\344\227\236\302\277\272\002\221aU[\273\277G\027X\267\016n\272\277;\375e\345\306p\260\277vu\0235\240\030\252\277-\0050\210u \302\277\254k\201\333\267\375\271\277\233\205\000\317^\036\226\277\365\276T[\371\020\302?\225\313\031R\024\r\261?C2\245@i\333\244\277tw\332\331~\021\274\277\022\361{\201\030\203\300\277y\231\034z+\276\324?\342e\276\273\317\362\305\277z&\223`<6\234\277\313C*\245]\363\265?\222\362f\3430\342\260\277\014\311\315\231\323\375\316\277\265\036\002\341`0\201?bD\325o\235?d?%s\037\232\030\225\312?\'\327\014\327!8\235\277O\346nY\200\001\241\277\034\314e\274:f\320?&\367\320X\362\342u\277\002\315\247\226v\014\332\277\343\321b\370m\346\271?6\232\313\365\313\035^\277l\344v\337\201\325\241\277\314\231\222\335}\274\232?mOa\366o\352\236?Y\303\2321\032n\302?\351\363\025\024\376\000\244?u\340\224\013\276\331\315\277j\321\370\2740\211\257?\225J\300],\256\276\277\321\315\200B\332\225\240?R\257:\3349U\257\277\200\2330R@D\320?h\324>/T^z?a\244M\376\252Z\326?!\3211\244\267\177\246\277k!\202}l\375\242?\321\031#\027\177X\267\277\331!\177\260E)\261\277\245\177&\tD\225\307?\253\026\243\220\347A\251?\364M\261\243I,\321\277\0166D8\256=\307\277~\264e!Q\037\310?\352\356\327x\220\323\304?2sV\377\037\030\277?\251v\231\214\264}\242?\376\341\306\370\220\254\256\277Z\313G\274\"\216\267\277\201\027\2305\001\361\306\277\240\3342vV\021\331?\224p\030ss\024\262?\'\3153\002\220\"\252?\313\202\373\270\206\\\322?\024\225?\211\345\351\320?\343\"3r\324.\274\277\314\231\306\215c\305\274\277;\343\031\272+1\264\277\327\237\210\203\320\272\247??k\244\322?\030\257\277=\3642T\236u\301\277\243\231\021\220\203\037\222?\353L\213\207\313\263\300?\204\361\301\346qp\306?\267 \237i\313v\310\277\207U-\256xr\256\277[Xz\327w*\312\277\273{$\"+\336\275?{\311v\343m\257\254?)s\222\314C:\233\277T\\\254[x\317\267\277\252\036q\354\276\251\305?\346\211\021v?\305\310\277X\010\233\2371R\277\277\022\371\275\001\030\327\321?\260D)\217i!\302?\215\033D\316\217\201\240?3\366\022~A\252\245?\211\267\232-Kc\303?5!\271 \017\301\304\277\273p\252*\273\322\321\277\347\320h\3372\315\261\277\0230c_\276O\207\277\203T\355M\376\300\276\277\022\3334\004\244\260\272\277\317\207\227\031 \247\262?\311\2347-\371\027\253\277\314\207\261~\321\001\301?\352\027\002C\254\251|\277\"\203\213\366\336\257\303?Gn,\315d\215\273?;\356\000?\356\264\257\277<\237\224y\032\r\302?\302\336\225\360\nt\262\277\360\232E\356v\020\232\277\353}\034t\003G\224\277*\"\000/i}\235\277F\007\253\330\214\301\253?\307n\335\300Uc\233\277\312KF\226\344\217\277\2772!\222\t\377d\260?\221\376\263o\240-\321\277-e\220j\033\033\274\277\260\0064%\305l\317\2779\332\007\357\271\026\255\277\345\301`X\213\205\306?\350{\302\025\206\014\306?\202\330/V-i\313\277\303\263 kLk\316?`y\267\262\210\207\240?V\352\240i\263]\252\277\322\024\242\342n}\271?\351}\304Y?\253\263\277\006\267\234\337\200\242\214?J\211\270\220\244\325\300\277\320\362e\313j\005\243?\235I\241\267\201\350\221\277\251c\353?1x\316?\243,\005}\'\035\275?\221\271R\335\357\246\320\277-\035TYZ\000\242\277\213E\3563\363\tA?\314\342\014B1\222\245\277C\265\305\354\335B\323?\244\017p\242Jw\230?\372\360\352o\347\303\314?\272\210\013\032\373{\305?\262\326\005e8\\\264?\243\340\261\021\364\003\307\277\337p\265\307\261\377\312?\356\025\327\3059G\255?\030v`h\263N\323\277\336Y\272\024\220\303\264\277C\344vb\372x\273?\233\244h\236\263\203\325?\237:\333\275\320\263\254?42\363\2737\031\265?>L\013\232\002\014\320?\327\235Z\310\377\r\273?\376\361\374\2419i\243?-\244\215\2050s\322\277G\326\233\243`g\215\277\352\352\034\252\354;\263?\221\'\320\373\300\372\027\277\351\350Y\343?\305\275\277\234\353,\276\302\326\302\277U_Dw\322\325\305?Q]\271\365V\272\311?T\033\005\372\340\237\263?\313\277~-\371\302\232\277\376ux\377\207K\237?K2\006\214\003\266\314\277\007C\340~\327=\313?%\000\354W\024\211\315\277\377z\366Hd\343\311?\rn]o_\355\274\277\334\027y\001{\244\265\277\314p\330\250\005\307\307?\273\271f\264\337E\222\277\376I\374>vk\320\277h`(\005h\304\222?\362\264|\250\003&\257\277\037\027\201\263zw\304\277#\007y\017Y\247\261\277\010\331\260\240\301p\313?\n1\2459m|\263\277\033n\331q\370\204\264?\216\373\252/\250\367\304\277\264\000(\252\324Z\273?x\004\375\257\035?\315\277\300+\344\036(\215\274\277\237\362]\020\371g\\\277b\3378\266\330\227\232\277\276CD,\377\212\306?\225\356\347\254\343{\306\277\3663\340Z\226\354\300\277\206d\343c\2321\260\277\207\027\360l(\263\312\277f\327G\241\243R\274?uI\332\243y\363\236\277\2141\004\217S^\262\277\365\005(\013\2038\301?T\203{\310\217\357\277?9\335=q\317>\240?\360+\235\203\214O\306\277A\217\350J\334C\320?\325\337\313\377rD\305?\202\340F\277\354?\301\277\265\207\033x\217O\302?\363\266!\026\251Y\302?\327\221\352\250\323\006\312?v\325\221\026Z\354\270\277A8\003\031\262Q\306?H\226\3010I>\226?c\272IPT\203\242\277i\005\361\\\332\017\264\277\025\025\024\307\000^\307?\330\023\312\014\nQ\260?H;\344o\214\265\264?\300c\244/\305\363\303\277\202\374?\243\\\362\265?4\315_D\017\370\301\277\324mw\231x\247\223?\225v\211\256\325\261\275\277\t\014}J8\225\265\277\314\022n\360FZ\260?\227 \307\331\364\005\263\277\216A\307.\250\266\257\277\346vJ\333F\214\327\277\250\361\355\007X\253\263?\277\355\032\255\014\375\311?\300N\334c\326\267\267?\266%n\376#\030\303?\302\010\337iX\250\302\277\312\001\001<\335\350\305\277f\356\367\035\366\375\310?\305\321\224v\224m\305\277Ub\377\026\316D\316?; F\357=\225\301\277\235\372W\236\232\020\275\277\035\230\262\235F#\301?" + } + } + } +} +node { + name: "layer_0_type_4/matrix/read" + op: "Identity" + input: "layer_0_type_4/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_4/matrix" + } + } + } +} +node { + name: "Reshape_34/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "Slice_17/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_17/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_43/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_72/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_72/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 7 + } + } + } +} +node { + name: "strided_slice_72/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "mul_42/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "concat_10/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/concat_10_grad/mod" + op: "FloorMod" + input: "concat_10/axis" + input: "gradients_3/concat_10_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_71/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_71/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "strided_slice_71/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "strided_slice_70/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_70/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_70/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "final_layer_type_3/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + } + double_val: -0.12484880574654916 + } + } + } +} +node { + name: "final_layer_type_3/bias/read" + op: "Identity" + input: "final_layer_type_3/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_3/bias" + } + } + } +} +node { + name: "final_layer_type_3/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + dim { + size: 1 + } + } + tensor_content: "V\343\307>\3136\254?\n\305c\350zg\302\277\003?\377W\3610\320\277\211`6+bV\254\277\230\237\230t\351\213\343?+\245\372\017\363\026\303\277\021n\365\266\262\266\302?\300\032I\235\371\243\341\277" + } + } + } +} +node { + name: "final_layer_type_3/matrix/read" + op: "Identity" + input: "final_layer_type_3/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_3/matrix" + } + } + } +} +node { + name: "layer_2_type_3/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "layer_2_type_3/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "\261\350\212\343\213)\263?&\033\231g\306\330\262?4C8\361\303\311\262?\330\223|8\2163\263?;B\204O\303w\263?\026\375\021[\201\370\262?i\306\320tv!\263?\232\212m\241?\212\262?" + } + } + } +} +node { + name: "layer_2_type_3/idt/read" + op: "Identity" + input: "layer_2_type_3/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_3/idt" + } + } + } +} +node { + name: "layer_2_type_3/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "#|\231$\035\326\313?\237\n\274g\255\357\324\277\031\354K\276\005\362\351\277Q\034\304\303\213\357\313\277E\231h\321\376&\376?\227N,\3340\373\325\277qP\302\262\t_\325?j\r\231\033\262\013\373\277" + } + } + } +} +node { + name: "layer_2_type_3/bias/read" + op: "Identity" + input: "layer_2_type_3/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_3/bias" + } + } + } +} +node { + name: "layer_2_type_3/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + dim { + size: 8 + } + } + tensor_content: "\023\233\211w\301\037\242?\276p<\221\026\001\260\277=\264\274=gz\307\277\261=EV\372;\242\277\273\005\247\313<\366\334?\361\217\247@l\010\261\277\362F\'\253\265Q\260?\370F\243\253\034\316\331\277\355\356b;\033\257\301?;@\366\021\'\336\304\277\263\303\2556zH\261?\353\241\371\313\203\035\315\277\236A\331\3769u\214?\000HDM\022\370\331?,\241j\036L\236\307?\215i\020\376a\373\275\2777\032\240$]V\316\277\255P\255\372\230\256\342?Fh\346\375\210\222\274\277\201@\356\2007&\272?\371H\302}<7\311?\347\374\005\375V\240\277?g\030\315\242(j\264?\224A\302v[\263\275\277Z\341\005\375\177W\264\277#\30368\346\350\227?\216\304\273\315\201\331\220\277v\260\247UG\241\341\277\272\302\252\255\317w\317\277\005\255\007p=\252\303\277\305i\273\005K\313\306\277GS\034k\007\323\303\277\374qA\347\242\263\260\277(`@\024\227\247\316\277\223\240T\2173\204\306\277\027\026\021\263\240U\251\277\310\203\275\202\351\220\316?/\310#Z\206\370\266?\310\005\027\264\233*\251\277\r2\032zji\306\277\343%\202\374\325,\310\277;%N1M\306\337?\300\266z+\266K\322\277\222r\323i\223\n\256\277\'\006\0023(\257\305?\0208\004*\031\247\276\277\333Y\254P^E\326\277\023\356\311\016@\312\217\277\271\032O;\032\357\261?\017\r|FK\276\320?NA\216Tr\314\274\277\341\222ay$[\276\277\204\031\330\177\327\343\334?\310S\216\2546`\263\277\253O\307tr\030\343\277\260|\235\275\324\335\301?,\246\2756z\203\255?\373\035\267\342\237\347\276\277\365\022Li%\275\227\277$G=\250\232\363\206\277\227\343\370`\237\317\322?\322\202\3354\226_u?\351\337\305\033\377\223\323\277\304\303\345A\023/\247?" + } + } + } +} +node { + name: "layer_2_type_3/matrix/read" + op: "Identity" + input: "layer_2_type_3/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_3/matrix" + } + } + } +} +node { + name: "layer_1_type_3/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "layer_1_type_3/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "\206X\361\tT(\263?\212\325\353\201\000\330\262?;\306\364\272\020\312\262?it*1\3571\263?_\302,d\330w\263?\254<\010\032\344\371\262?0]\220\023a\"\263?\202Pl\0038\212\262?" + } + } + } +} +node { + name: "layer_1_type_3/idt/read" + op: "Identity" + input: "layer_1_type_3/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_3/idt" + } + } + } +} +node { + name: "layer_1_type_3/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "\200\277G\307I\326\313?\020M\311n\353\357\324\277\356%\2029(\362\351\277xWyx}\357\313\277!k\370\2332\'\376?E\'\367\'-\373\325\277\307\317\315\205\372^\325?\353\355\232\217\254\013\373\277" + } + } + } +} +node { + name: "layer_1_type_3/bias/read" + op: "Identity" + input: "layer_1_type_3/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_3/bias" + } + } + } +} +node { + name: "layer_1_type_3/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + dim { + size: 8 + } + } + tensor_content: "\326\366\326\002&\036\242?fZ\367\231\360\000\260\277\256\027\252&7z\307\277\301\361j\030\2018\242\277\310\377\036G\030\367\334?vD\321#\034\007\261\277O\256\370\301\351O\260?\233\024\323g\305\314\331\277.\270\342\225\224\262\301?\226R>\240d\330\304\277\224d18\2552\261?)\356\'\217\321\037\315\277(\223\366\240\222Er?\223j5\000c\367\331?\310\226\003\346\365\034\306?\207\202\314g\377@\265\277\024\034n\254\316U\316\277,\0173\254\216\256\342?\235\304\022\003\340\222\274\277\316\375\016^}$\272?\372\215\321a06\311?U\024\025\277\355\236\277?^-\017\251\255k\264?\361\237}\333\377\265\275\277\361\036\002\244\334V\264\277\264\372dS\341\350\227?\277\364\342H\267\331\220\277\344GS\274y\241\341\277\262n}\254Wy\317\277\322\265O)\330\252\303\2777\211,\031\230\312\306\27753>\306t\325\303\277\010\230D=\264\264\260\277\027\243N\353t\247\316\277{K\tR\026\204\306\277\301p\300\277\205R\251\277\240\237\244\262\331\221\316?t\006\026A\321\371\266?2\200g\221@-\251\277=\271\336\207\221h\306\277\311\302\340\265n*\310\277\244Mx\363z\306\337?p\030\303e\347N\322\277\030&Uq\364\017\256\277;\327\363H\205\027\305?j\255\351\212\355\250\276\277rE^\251,]\326\277\207%\374\277\030Pj?\335\023m\037\016\345\261?Rl\352\014\377\276\320?$\252\003X\004\266\274\277\003\357\016\302\331S\276\277U\023\227\3402J\335?\271\377\253\227$[\263\277\262\232]\242n\007\343\277\214T:\004%\202\276?\256_\260:\247\345\254?O\000k>m\316\276\277\2409\213\330Y\354\226\277\353\305lg\215e\202\277\232A\027\311\364\314\322?\021t@\021\257t\200?\177[-\016]\270\323\277p\371\355\'F\234\247?" + } + } + } +} +node { + name: "layer_1_type_3/matrix/read" + op: "Identity" + input: "layer_1_type_3/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_3/matrix" + } + } + } +} +node { + name: "layer_0_type_3/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "layer_0_type_3/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "\211\016\233<\212\316\313?\362\004\303y\007\354\324\277,\331\316X\347\360\351\2772\240\030\316Z\347\313\277\r\023\355Ly%\376?Py\346\207L\367\325\277\023\316\t\313D`\325?\345=\265\331V \373\277" + } + } + } +} +node { + name: "layer_0_type_3/bias/read" + op: "Identity" + input: "layer_0_type_3/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_3/bias" + } + } + } +} +node { + name: "layer_0_type_3/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 32 + } + dim { + size: 8 + } + } + tensor_content: ")\013\t\226\330\333\211?-\350\213\213\255K\236\277,\354\357\362\3450\273\277\036\006:\356\3262\212\277\022\033\\\342W\252\321?V\250\270\356`x\240\277\202\351%4%u\237?q\272\217\027fJ\320\277\035\301\233\311\350\212\300?\001\024G0\375\230\302\277\237u\371\263\371*\014?\320\177\rP\373\303\307\277c\250\200\225\273\210\243?1\367\270\206\241f\313?9\354\211\317 \301\302?\213\331t\371!\337\252\277\320H\213P\r\361\301\277\253Y\352\366\200\377\326?$)4\354F\221\264\2776\223\327\r\210\030\254?8m\333Bd9\301?\233\374\3407\304x\261?\215\244\267\264;\303\256?\370\225\352S\013\234\244\277Z8+\314\007\266\244\277\365\222\355\216\235\217s?\261\272\270\211\220\272\224\277\253\323U\177\367\354\326\277*\344\027\317s\230\302\277@\242\234\232\'l\273\277\322G\306\231\254]\272\277\256\206h\376s\226\260\277\233\014\242\337\363\263??^b\205Sw\325\310\277\0307\246u\201\245\303\277\276\025\224\345\326\257\262\277\034\237{\2728\272\310?=<\0137\230$\215?I\224\251h{\322\207?e\240\313\211x;\274\277\020\023\000^\322\200\300\277\013\315\371(e\275\324?\307\032\202\307\303\364\305\277\2532\305\220\350G\234\277[\177\200\252^\367\265?f\031\341\277V\345\260\277}A\362\034F\374\316\277gV \337\257\357\177?\266\2474\205\261\230d?\353\212}zL\224\312?\335o\206\377:A\235\277B\237#\036\311\006\241\277\343\212\335+\324f\320?\214XB)#\375u\277iE4\247\020\014\332\277\303\354\020qz\277\271?\237\302\3139[\016]\277\332r2\306y\332\241\277B\377f#K\257\232?\356\016\273\246W\334\236?T\273\3415|o\302?\301\255[v\336\373\243?\341c)\037}\330\315\277.\332n\031\243<\257?\323\302\t (\227\261\277\267\271\216\177\2602\224\2778\275\330&\362\343\274\277<\267\270=\240\377\311?\334\321\326\230\277\307\255?$\034[i(\005\323?\211\226\314:\312\254\200?\325\303\356\357n\252\242?\271\036xv\266U\267\277]\362\302\357\335*\261\277\211L\027\344 \224\307?\270]\356\313\236<\251?.\21794\260+\321\277\027\301\307\276\177>\307\277\271\303L\000\035 \310?W\374.\265\026\300\304?N\310\366\340\320\031\277?\346;\371\260_|\242?\356n\017M\031\257\256\277K\215\376\345\255\217\267\277\266Q\252\275M\360\306\277\322\363\265l)\021\331?\260\244;\017\034\025\262?q\350u\034\321\324\251?\305\001u\250\244]\322?\326\325\002\3669\351\320?`\007\261KV2\274\277v\362\203@>\311\274\277\247\004\rb\022.\264\277]\205\364TN\265\247?a\3057\246\323\022\257\277\021Qq\331\324\210\301\277VZ\213\201\206n\222?\021l\360\360\227\253\300?\323\372\304\277\032\310e<\222T\273?\252v\257\303%<\315\277,\005\2730\240\221\274\277\222\264\342%\376H[\277\277\300Q\276+:\233\277\016\277\232\277\035\214\306?\336 \240\362W|\306\277\373\335|:A\355\300\277|\223r2\2413\260\277\332\313i3\033\262\312\277(;1\033\271Q\274?\221p\023<\311\357\236\277\'\354\036\367\236\206\262\277\251?w\264\250\036\266?\273\222\250{\272K\306?sQ2\210-\256\264?\310\n\205 \033 \300\277\332\251$\"&G\312?ag\232\340\031\230\313?\242\254m\025\300\222\307\277K5i\331}<\302??\247\2706&_\302?2\367iO+\002\312?n\326W\363\200\366\270\277\226\252\211\302\202L\306?\340[m\321\ta\226?\'h\234; \226\242\277\224\0304\013w\006\264\277\320|9\367\256K\307?r\337\313\027\342Q\260?\355\022\273L\232\265\264?\215U\371\003\007\364\303\277\232\024#{\254\361\265?R\261yC\304\367\301\277\3059\022\334\207\247\223?\205\344S\202\346\261\275\277\361\276\200\t\231\272\265\277\226\363\331\030\250[\260?\n\201N\347\\\006\263\277XA\020e\257\270\257\277w\326\275/\226\214\327\277\3407\036\327l\254\263?\332T\321_\323\374\311?\n49|<\270\267?!Ft\013Z\005\303?\014*n$\036\251\302\277\330\202\216\347\275\347\305\277\257&\371\223\366\376\310?\2539g\207\255l\305\277L\213\353H\372C\316?\020}\257\333 \224\301\277\243u\240l\326\022\275\277O\311\350?\311\017\301?" + } + } + } +} +node { + name: "layer_0_type_3/matrix/read" + op: "Identity" + input: "layer_0_type_3/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_3/matrix" + } + } + } +} +node { + name: "strided_slice_69/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_69/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "strided_slice_69/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "Reshape_32/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "Slice_16/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_16/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_41/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_68/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_68/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "strided_slice_68/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "mul_40/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "concat_9/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/concat_9_grad/mod" + op: "FloorMod" + input: "concat_9/axis" + input: "gradients_3/concat_9_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_67/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_67/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "strided_slice_67/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_66/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_66/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_66/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "final_layer_type_2/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + } + double_val: 0.04604106977730521 + } + } + } +} +node { + name: "final_layer_type_2/bias/read" + op: "Identity" + input: "final_layer_type_2/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_2/bias" + } + } + } +} +node { + name: "final_layer_type_2/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + dim { + size: 1 + } + } + tensor_content: "\365\316[X\217?\255?\357i\345\2402b\302\277sK\027\256\3500\320\277\214mx{qV\254\277\265r\376\014\361\213\343?L7\224X\033\024\303\277\201\262\371\250\346\260\302?\375LM\023\311\232\341\277" + } + } + } +} +node { + name: "final_layer_type_2/matrix/read" + op: "Identity" + input: "final_layer_type_2/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_2/matrix" + } + } + } +} +node { + name: "layer_2_type_2/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "layer_2_type_2/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "\223\306y\007\3452\263?\252\245\007\324\223\331\262?|6W\252\372\317\262?P;\255\227\003\325\263?\207&\373\300\314x\263?\253\226\243m\361\342\265?\272\320\217\257V#\263?>o;$\311\214\262?" + } + } + } +} +node { + name: "layer_2_type_2/idt/read" + op: "Identity" + input: "layer_2_type_2/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_2/idt" + } + } + } +} +node { + name: "layer_2_type_2/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "\010{\254\264\005\323\313?l\206\031\217Q\356\324\277_0\322]\263\356\351\277\334\246\312hQ\356\313\277\203$G\307\272$\376?^h\201\224\245\371\325\2771\341\341Y\224V\325?\265\n\371[\007\010\373\277" + } + } + } +} +node { + name: "layer_2_type_2/bias/read" + op: "Identity" + input: "layer_2_type_2/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_2/bias" + } + } + } +} +node { + name: "layer_2_type_2/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + dim { + size: 8 + } + } + tensor_content: "RP}\271\376+\243?\254wu\270\233\177\260\277J\001\232\361\003\264\307\277\323\303+7\245P\243\277\343xFx\024\010\335?vu\315T5\217\261\277\274\260\240\256\302\275\260?\203E\nR_\341\331\2778\033\021\267\373\257\301?[\304\311\250\334\306\304\277_\217\024G\322;\261?\324\307\212\310\305\037\315\277\035\362g\237\333s|\277\353\035\227k{\371\331?A\245\250\'\333\357\304?\321f\001l\0350\265\277y\354\311\362\007S\316\277\376g>\022\251\255\342?\2068\n>\027\255\274\277\326m\223\264h#\272?\323:\364\216oM\311?n\022\305q\217\231\277?\332\356\345GF\211\264?\376\226\251}.\356\275\277\306\320Z_AQ\264\277\'\321\tK\245\272\227?\227\323\306\250m;\221\2772\003\225\035\215\241\341\277\205[\351\t\326T\317\277Q\245\000\312\253\255\303\277\032B\005|p\277\306\277S\201}\322.\357\303\277\273\022\311\220\247\271\260\277x?\311-\324\244\316\277\230\035\306\256\363v\306\277\241\253\376:%Q\251\277\177\356%\016T~\316?\263fo\303\212\376\266?\350\360\260K\234m\251\277\250\277t\204\371K\306\277\303G\0169\332,\310\277\335\373\"3a\320\337?1\277\366\3441M\322\277\023#d\256\213\020\256\277\"\324][\251D\303?\022\273|k\235\240\276\277\204>\242\213\206\220\327\277+\306\023\231\001?\211?\364`B\r/\353\261?\361@#\031\226\264\320?\262\017\360[\201\275\274\277\361f\256\034\340T\276\277\241U\357\337~;\336?\263\275\353\'\254d\263\277\262\374Ab\250j\342\277d\333W\n\251\000\273?\3251\030\214\300>\256?\207\245Y\371\3019\276\277\207\233[*\341\326\225\277\026\306m\330\207\356\214\277\032\351\317\370\250\223\322?\356\236\206l\307=Q\277\027\361\350\213\304\216\323\277\226\'\270\347n\305\250?" + } + } + } +} +node { + name: "layer_2_type_2/matrix/read" + op: "Identity" + input: "layer_2_type_2/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_2/matrix" + } + } + } +} +node { + name: "layer_1_type_2/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "layer_1_type_2/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "x\321\307\315%.\263?\274\327\005Q\334\330\262?\240U\372k\330\320\262?\316\304\363\366\033\333\263?P\225p\255\305x\263?m-\322\342\3077\267?\226m\303\345\365\"\263?\342\201\351\271\277\214\262?" + } + } + } +} +node { + name: "layer_1_type_2/idt/read" + op: "Identity" + input: "layer_1_type_2/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_2/idt" + } + } + } +} +node { + name: "layer_1_type_2/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "\3327h\001\377\321\313?\017:\253\034\276\356\324\277Iz%\224\336\356\351\277\367C\373\3765\356\313\277\016G\355J\351$\376?\213\221\222\367n\370\325\277\2707\001\032lV\325?>\024\363\275\013\010\373\277" + } + } + } +} +node { + name: "layer_1_type_2/bias/read" + op: "Identity" + input: "layer_1_type_2/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_2/bias" + } + } + } +} +node { + name: "layer_1_type_2/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + dim { + size: 8 + } + } + tensor_content: "V\222\025\02075\243?\020\336\021\033[\210\260\277\013\t\253\023\205\270\307\277\314\227\202f#\\\243\277P+\001\000\310\n\335?\337\215M\237]\221\261\277\264\301\300C\337\305\260?\232q\214\016\340\343\331\277\0108\214B\300\257\301?\004\257\371\213Y\310\304\277\344\3107\310/9\261?;v\013W| \315\277\353\274\325]@1|\277\240\234\232\213X\372\331?\253\377\206\326\006\360\304?\010aW\372S1\265\277\245\215k\363\033Q\316\277DX\022H\257\255\342?\374\301;\3606\255\274\277\031\032\266\257Z!\272?\350L\342\236\267L\311?:\034\375\000\037\223\277?\312\260W\002\007\213\264?\3518z\214\377\356\275\277%c\253\034\366M\264\277\000\363r`^\275\227?y\367\244\223\005:\221\277\334>\255\257\274\241\341\277\217G&\247\312U\317\277Y\005\333\030\247\260\303\277\267Q\2721\275\276\306\277\357\203M\350m\357\303\277g]%A \275\260\277),\357z\027\245\316\277\244\323\361\035\014w\306\277W\234\031\255\313M\251\277\351\2464\2065\177\316?\263V\004f\247\004\267?R\001u\347\235p\251\277o\260\264\372\260K\306\277\035\204\244Q\016-\310\277\261\206\334\221\234\317\337?\341\0149\237\336M\322\277X\265\317\002\177\023\256\277.\211\252\026\312F\303?@\014\010\2616\235\276\277\341)\254\202k\220\327\277\235\276<\377{4\211?/\031\357\254\014\352\261?\330\374\253\256\257\265\320?\337\\\014(\206\271\274\277B-\037\356\322Q\276\277u\031\024i\034:\336? \247f4\262f\263\277\300x\332E\325j\342\277\236\376\230\327\346\002\273?\2477\3258\025\354\255?\303;\261\245\326\n\276\277U\022x\3516\017\225\277wx\353cM\257\213\277\230\206\254\2166\207\322?O;\305\345\346N5\277\027\323\207Cb\235\323\277\005w\224{{=\251?" + } + } + } +} +node { + name: "layer_1_type_2/matrix/read" + op: "Identity" + input: "layer_1_type_2/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_2/matrix" + } + } + } +} +node { + name: "layer_0_type_2/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "layer_0_type_2/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "\267\243\370\233I\232\313?\253\351x\254\3717\325\277\325\033\367\362?4\352\277\003d\361)\346\271\313\277\247\301\327\366\216!\376?:X\201Q\013F\326\277J\353\352\257\246\257\325?.M\245\273\270\007\373\277" + } + } + } +} +node { + name: "layer_0_type_2/bias/read" + op: "Identity" + input: "layer_0_type_2/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_2/bias" + } + } + } +} +node { + name: "layer_0_type_2/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 32 + } + dim { + size: 8 + } + } + tensor_content: "\242E\3258\022\366\206?m\024\225c\277\246\241\277\343\021\251\023\316A\274\277u\007\312\000\026~\206\277\303\227=\337\033\221\321?(V\257T\265\020\243\277\200\312!\002\275V\242?\240\252?WZM\317\277=\n\227\353<\212\263?0\353\354\364;\001\271\277D\265Ka\221\026\250?/H\261\261a\365\300\277y\366>\316\213e\217\277\332\263C\250K\274\320?o\371\340}$a\271?\354\231e\3339\275\245\277x\352\337D\224\267\310\277g\364 \2661\014\332?^\305{\310\275-\241\277\201k\006C\325\251\273?q\256Ey\271\301\264?\347\332e\373\263\236\275?D\202\347\276\362\363\211?\372\267^\231u\363\236\277\273\263\217E\234\354\267\277\343\270h\374\311\337\252?\007\366\020a\t\253\231?`\334\026\021\236\207\323\277F\350/\222?j\311\277G\345\372\304T\203\256\277\274m\025\263iB\303\277\321\367c4h\014\254\277\321\253\201g\301\327\252\277\372\303\264\035\030\275\302\277\324\022\335\231?C\273\277)\232n\243\216J\224\277\230\2057\030\261\341\301?\333\220\3744\375\220\257?\362X;h\233M\242\277\253\000\304z\204\252\271\277i\370;\260\360\264\300\277\223j>\n\363q\324?\340\3716\010\231\255\306\2773vW\032\216g\232\277\325\312T\354\270\227\265?C0\222LO\036\262\277\217\202E\263\215^\316\277\317QX\231\372\034\222?<\266\024\312\025\346N?\271\305\036\224M\375\311?\311\244\235\377\275\241\241\277\265y\341\324\003\034\240\277\360_\226\273\235O\320?5\321\007\365\037\310\204\2771\246\343\230%\275\331\277\275Z\203^\264G\274?\030\274Bv\027\026j\277\010\031A\024fF\244\277\305\367\246\261*\366\222?\212\275\313\016j\'\240?0>\255\254xM\302?\324\351L\3124y\241?\010\341\215O\2406\315\277\206\270\262\306\311+\262?\032\006\263\0106$\277\277\023\362\332s[\230\234?\303v\342\036\212\351\260\277\024\004\343m4g\320?\337\316\243\377\013-s?\266S\335\304?\303\023\253\345\243\010\263?\326\311Y*\301\305\306\277g\264m09\312\312?\325\354XH\337\264\252?\005\001f\205\000\374\322\277\212\251.r\212\\\262\277\375\312\351\302\221\022\273?]c\313i\2525\325?\305H\216\245\363\254\251?\274z\311$\016\217\265?\211/)c\035\351\317?\n\\Z\355\255\312\271?y0\326\010\233\364\245?\357@\036\351*\333\321\277\206\306\374r\260L\220\277\316\003\375\231\202\004\262?~\312\027R#ry\277V\335AV!Q\275\277\001\303\355\223\263\004\303\277zD\372P\2054\305?\231\271\340\245\324\\\312?\23163<\371\377\265?LL\013\020\366/\234\277\232\000\215\240IM\232?\237\0161\270P\265\315\277\277\212\270\200\317j\313?\255\nX\377\363\251\315\277\t`\334\336\354=\311?\302\311\362c \240\273\2772x:\332\300>\263\277:6\377\"m\220\307?\244\022\2511\300\370\226\277\242\333\301,\205\256\320\277\213_4k\232\325\224?8\235\253\266\377\376\257\277\233X\346\000q\023\305\277\020\256G\355\013m\260\277\366:\233R\310\242\314?\277\332\336@e\335\263\277\345\177\376\013\002S\263?\242\247\220XM\237\305\277 \360\351\320;\317\273?{\'>\276\270m\315\277\365 \"\264b\312\275\277\246`F\305d\300i?\306l\214\301i\003\221\277\344\347u\252\017Y\306?\2433\376\3123\023\307\277b\223W\013\030\232\301\277\340Q==\302v\257\277D^$\360q\342\312\277\320\031\263\001\277\030\273?\001\316\022\353F\002\232\277\033\272\351\200\254\361\257\277\304\213a\236(\277\265?\341\002\354\225\215\262\305?\230\036a\365\207\346\262?\244\003){\251\330\277\277g%\300\004`\036\312?\261\317\236\242\036\371\312?q\027\331\323\276\362\306\277\026\323P\2251\204\303?\272\025W\"\3141\267?`wx\200\224\r\320?\214\344a\367\363\247\252\277\315\212\242\254\306\026\315?\247K\314\0216\035\240\2771\372@,\252\320\206?\205$\304\244c\024\300\277\271c\201W\227\224\310?\200\306(\362B\325\257?\372\307?\r\233\207\263?\023\274\006\271\206\334\304\277,Nt,c\\\266?\014\255\252\003\034 \302\277\002\252\303\275\\\205\215?\353\2472\3270v\274\277.1\201n\3434\263\277\007I\037/W\353\257?)(\303r\2124\264\277F\355\337\270\251\272\261\277Pb*\334\322r\327\277\216\367t\r\231_\263?\206\2116\365\036`\311?\341\307zR\'\364\270?\232\"G>(H\304?\212\320|\204\332\326\302\277s\005\345\370\300\202\306\277F\230zM\332\333\307?\322\315pq\307J\305\277q\364c\371\250/\316?^\271\305\370\3304\302\277H\352\250\005\364\316\273\277\240\202\227\362\025V\302?" + } + } + } +} +node { + name: "layer_0_type_2/matrix/read" + op: "Identity" + input: "layer_0_type_2/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_2/matrix" + } + } + } +} +node { + name: "strided_slice_65/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_65/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "strided_slice_65/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "Reshape_30/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "Slice_15/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_15/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_39/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_64/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_64/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "strided_slice_64/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "mul_38/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "concat_8/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/concat_8_grad/mod" + op: "FloorMod" + input: "concat_8/axis" + input: "gradients_3/concat_8_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_63/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_63/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_63/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_62/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_62/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_62/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "final_layer_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + } + double_val: -0.12484880574654916 + } + } + } +} +node { + name: "final_layer_type_1/bias/read" + op: "Identity" + input: "final_layer_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_1/bias" + } + } + } +} +node { + name: "final_layer_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + dim { + size: 1 + } + } + tensor_content: "\207\032\317\263\235D\254?i\330\035.\034l\302\277\263\021\374r\0141\320\277\335\373\0054\304Z\254\277\3174p\354\354\213\343?\355\273\367\021\032\032\303\277\257\274\235\305\273\270\302?\340\236\340\250\301\242\341\277" + } + } + } +} +node { + name: "final_layer_type_1/matrix/read" + op: "Identity" + input: "final_layer_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_1/matrix" + } + } + } +} +node { + name: "layer_2_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "layer_2_type_1/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "\021y\312\024\357*\263?}2\253\325\304\330\262?S\007\257\264\036\312\262?s\025\257@\253.\263?\225\026\3502\355w\263?\302U\356\270~\377\262?\0168\353\336\231\"\263?\351\356\272\336n\212\262?" + } + } + } +} +node { + name: "layer_2_type_1/idt/read" + op: "Identity" + input: "layer_2_type_1/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_1/idt" + } + } + } +} +node { + name: "layer_2_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "\3410\031\264\312\325\313?\253\010\'/{\357\324\277w\3644#\344\361\351\277\204\254\327v\277\357\313\277\375\363v\032\222&\376?n\215I\034\350\372\325\277kp\321\373;^\325?\231\377A\312x\013\373\277" + } + } + } +} +node { + name: "layer_2_type_1/bias/read" + op: "Identity" + input: "layer_2_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_1/bias" + } + } + } +} +node { + name: "layer_2_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + dim { + size: 8 + } + } + tensor_content: "\032\333\361\362L0\242?\263^~\t\177\013\260\277\265\255]6{~\307\2778\001\007\311\370K\242\277jy\341$Y\371\334?\274/\304\325\240\016\261\277`\005\205\3721S\260?\r\373~h\214\316\331\277\255;\342M\346\252\301?\0031U\325*\316\304\277\216\207\217\203\307S\261?\314|E\224\277\030\315\277\307\260\274%\027:\206?\326;\223_\210\371\331?\272_.i6g\307?\3516\265\354.\300\272\277\360\317dzlV\316\277\372)\240f\213\256\342?`\204v\027\216\222\274\277\204\013\341\3127\'\272?\3569\237y\232;\311?\355n\212f\251\237\277?\006\255\274\313\346k\264?z\207p u\266\275\277\314a\023\315\202Z\264\277\310+\365r\260\366\227?\'\250\215\275&\315\220\277\251J\254r\345\240\341\277\217>[\242\244u\317\277\250\226\375\025\213\251\303\277\3736\210\274\265\312\306\277\376\230W\300=\324\303\277i\362\245\270\037\264\260\277h\313\212\265C\247\316\277\336D\244\217\304\203\306\277 /\021X\264V\251\277ad\253\375}\215\316?G\332=\027\217\371\266?T\244\202E\2670\251\277\t\271\367\205\253g\306\277\"y\361\005\0210\310\277\236\350\032\273R\315\337?\217\232S\021\216J\322\277\262N\240|\267\373\255\277\271`QQ\024A\304?\266\010s#\333\241\276\277\364\231\344\376Y@\327\277F\324S\212\214\275\177?\300,\312R\271\363\261?\3577\340}/\266\320?\314Z=\233\364\306\274\277\217\266\244`\014a\276\277\242\022\253\246\357\363\335?D\377$\363>e\263\277T(\212\006\304k\342\277\005\0222\232\371\005\273?\325\337\333D\260\237\255?\311\0142\005\022\310\276\277\367q\252\363\272\252\227\277\304\n\r?m\034\210\277\320\242\206n\025\321\322?S\336\347\217\370.n?A6\211\201]\245\323\277\307\321?\324%l\247?" + } + } + } +} +node { + name: "layer_2_type_1/matrix/read" + op: "Identity" + input: "layer_2_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_1/matrix" + } + } + } +} +node { + name: "layer_1_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "layer_1_type_1/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "-\263\225\361\202)\263?n\241\252\'\004\330\262?\024\212\365(r\312\262?\212nl\341\207,\263?\206\262\353\330\001x\263?\306\3410\305\'\002\263?\335\006\031f\010$\263?Sw\"\324b\212\262?" + } + } + } +} +node { + name: "layer_1_type_1/idt/read" + op: "Identity" + input: "layer_1_type_1/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_1/idt" + } + } + } +} +node { + name: "layer_1_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "\372\023\250\355\324\325\313?\360/\225\354\274\357\324\277I\254\251\202\006\362\351\277\201N\367|\250\357\313\277\270\346Iw\276&\376?wb\035\313\340\372\325\277\233<\323\275%^\325?4\307\2421z\013\373\277" + } + } + } +} +node { + name: "layer_1_type_1/bias/read" + op: "Identity" + input: "layer_1_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_1/bias" + } + } + } +} +node { + name: "layer_1_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + dim { + size: 8 + } + } + tensor_content: "\211\371\241\202^/\242?\304\374\365:\346\013\260\277.\224\325\353p~\307\277\313\001n(\002I\242\277)\336H\262\244\372\334?\374I;\346\177\r\261\277I6\213\017eQ\260?n\261\034\253\355\315\331\277D\226\236M\211\256\301?{\024,\262]\317\304\277\355\363\2161\277>\261?\226\375\301\223\273\033\315\2770\361\337\023\275\363\'?\2744\361\225\305\370\331?\250\216^\036E\375\304?6\320\026\302@<\265\277y\304xY\314U\316\277\303!I\340\205\256\342?\264:G\214\276\222\274\277\223\013\203\225\223%\272?k\0317\301\304:\311?;9\310nJ\236\277?\270\300\351\234Om\264? \373\304r\271\267\275\277\275dw\322\014Z\264\277\270B\221\357\031\370\227?\332}\343B\006\314\220\277\213\n\374`\017\241\341\277\315l\271\030sw\317\277I\006+k\025\252\303\277\2462\223m\022\312\306\277\306o\226\226\r\325\303\277\203u\265\277q\265\260\277\024\340\237+*\247\316\277\231\233\033\273\250\203\306\277\214\277\236\030}S\251\277\325\344\251\0346\216\316?$\374\355\237\344\372\266?,Fb7{3\251\277\031x+\371\030g\306\277\353\274\304\375\027.\310\277Bw1\303\177\314\337?\217\317N\216\031M\322\277\276e\240}c\001\256\277k\355\027 \366\354\303?\266\"\375\353~\243\276\277p\376h@\252\217\327\277X\273&5\271\023\211?\360\243\347\365\236\353\261?\373\374uS\032\270\320?\304\0026\024\264\270\274\277p\327\237\206#Z\276\277\306\334\211\233\356\010\336?Y\202\237\"\206`\263\277\256\000\035\257\304j\342\277\333Y)\217\371\014\273?0\213\025\325o\035\255?\002\237}\214h\246\276\277m\215\333\3321\347\226\277P]\275\217%\213\204\277\321_\016\020\037\317\322?G\204\2438W\014y?\266{\216/6\320\323\277\277\367G\310z\275\247?" + } + } + } +} +node { + name: "layer_1_type_1/matrix/read" + op: "Identity" + input: "layer_1_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_1/matrix" + } + } + } +} +node { + name: "layer_0_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "layer_0_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "\t\313\\\327\357\311\313?\335\217\372rd\353\324\277\315|&\231\004\360\351\277\343\t\303t\307\345\313\277\232MX8\345$\376?\335I \273\317\366\325\2772\010\224\356\000`\325?\014J\304\370\007\034\373\277" + } + } + } +} +node { + name: "layer_0_type_1/bias/read" + op: "Identity" + input: "layer_0_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_1/bias" + } + } + } +} +node { + name: "layer_0_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 32 + } + dim { + size: 8 + } + } + tensor_content: "#\305\344\027\255\254\207?E6BJ}x\236\277l\033f\360\371;\273\277K\343\336P\364\225\212\277\314\212\016\\\020\252\321?l\312f\316!\221\240\277\272\234 \\I\250\237?)\345uV\341&\320\277\\\340\007\242\226\217\263?\026\314\257\033\345\310\267\277\'\235\360Hp\246\252?9\362\276\036V0\301\277\325H\021A\002\257\214\277\341\357n\034\010\r\321?\014yi\024\233\034\270?\t\2575\253G\315\251\277\317a\336\317\377\266\310\277i\314\016\220N?\242\330\253\215\335\227\312?\363\360I\035\021\022\235\277\335\327\206\256n\365\240\277vhp5\323b\320?\024&*\002\007\224u\277z\2563Y\200\r\332\277\364[\361E\237=\272?\023+\204\264B\"o\277~\350N\352\360\266\241\277\255N\270\231<\010\233?\246\221\333\304\3410\237?\341\203_\343\303^\302?\227\223\006\311\214\036\244?\303\221bU\325\340\315\277XN\275We\025\260?\322\364\257\036\r#\277\277\271\017\341F\336\262\240?Jr\320Y\312.\257\277\370o\005\'\300H\320?\203Yo\326\337\301x?4\371M[\037^\326?-\375\323\314\010\232\246\277:\344\243h\270\267\243?t\361\010\345[\275\267\277\342Vf\311\273#\261\277s\334^ \006\232\307?\036%\213;\371M\251?\231\261\246*\261/\321\277~\377\216\3356;\307\277\215\361M\234=\035\310?\3563\237\037)\377\304?G\007x\366-\261\276?0\02238\025\204\242?\314\317\270\214\232\236\256\277\274\360\322x\356\212\267\277\'\257\233\351\277\366\306\277\340\325\204l\372\021\331?~\364@\371\256\022\262?\320\021\005\241\202\316\252?\326g\313P\271<\322?H_\273\t\306\354\320?E\277\304j\363\037\274\277\016\317o\234`\270\274\277io\307\007(L\264\277\215t%\003\311\320\247?Y7\222\327\373,\257\277: 4\311GM\301\277\222\226\024\271\263,\241\277!b~\346\021G\307?z\037#\362\275\370\314?\336\252\331RI\000\302\277\247\267\2132\023U\274\277\327\021\250\025\306\227\303\277\371bc\3325\272\260?0j\230\303\306c\257<\235\277\\^\030\341/\300\267\277>\325\365\3036\263\305?\242AB#\262?\210\373\266j\366\376\252\277\240\315\327\325\326\010\301?\251\035\025\212\\\330{\277\344\345\366\021+\235\303?V_\010\351\240\231\273?y\035\371\336\203\314\257\277\322\341\322(#5\302?\336\204H\311U\310\262\277n\t\177\377|\010\232\277\240\321\265Au/\224\277Y\333\027<\200v\235\277An\307\236\314\256\253?6\220S\343\373]\233\277\367\351\226ud\220\277\277/Vk\255\224\305\260?\\1\321\367\033B\324\277%\024z\257\241\275\257\277^k\326\310oX\311\277v\217\374\256\301-\204\277\326n\347\321mn\300?v\t$\014\314)\314?v\362Q(\326\302\320\277Q;\302\303\\\233\316?\333\323\303\310\375\364\224\277uK\202+\201\002G?\010\033\213\2728`\303?g\032Z\3531F\232\277?\354\270\231Ft\243\2779(\352\271\246P\264\2773B\363\202B\265\216\277 X\274>L\302\231?\331\313\272\356\260\220\314?D\300\200\006i~\305?~\030\332\024/b\264?K\251P<\201\000\307\277\253|-\352\'\365\312?#\211\327v\241N\255?\332e\374\373\231O\323\277\334\000\001DLh\264\277\206F\271f\355\016\273?\364\351o\276\366\205\325?M\304!\013s\316\254?\356\313\245\227T#\265?3\313\3106\247\007\320?$\016XRu\026\273?\037\256E\300\335Y\243?\2459\251u\320]\322\277\362\277\377\212\250b\220\277\275\250\261\217WB\263?\316L\r\216\307\363\021?\326\363k\005L\276\275\277\327B\272QD\336\302\277\354\332/\205\271\330\305?P#\266\276\325\267\311?\221\355\377\017O\364\263?f\214\305\3350\324\234\277o\016\360(\354\200\237?\033\231\035\263\202\255\314\277e2\023\313_E\313?\302\0309\241\252\227\315\277*\300y\215\316\351\311?\221$U\n\216\371\274\277\374P\374\310\204T\265\277\013\027\34769\227\307?\266\311\010\tK5\222\277\037\275\033Uhi\320\277?\351\321\346\372\325\222?\202\377\362t\203>\257\277/(\347\372\273u\304\277\357\320Uq\003\252\261\277_\004~#L\240\313?\256\0041\000\276\334\263\277\036\377\216\304\021\207\264?\212j\320\315\312\364\304\277\220\337\350\204\346\\\273?\233\014]*=D\315\277Z^7\251\263\213\274\277\307\016\303<\323\223\\\277\027\346\366\364?)\231\277\021\026\001P\240W\306?\257\255SN<{\306\277\340\256@|#\352\300\277\003;\0205~0\260\277~\337\272)0\270\312\277\355\206Q\032HS\274?W\316q/\351\362\236\2775Y\371[@\004\262\277S\267\352N+\233\265?\0057\301\'\301[\306?\241\261\317\275\203\322\264?\250\245|\310\377\013\300\2774\2664\355M+\312?R\331\237\312\351\247\313?K\241P|k\242\307\277\217\325\333\223ox\302?\"\204Q\367\202\010\267?k\227\037N%^\320?\336>n\310\3405\247\277\202|\203\"\206\346\314?,o+!\204^\237\277\336$\2417\247\234\220?\263\034\267\337\276\273\300\2779f\032\2164\211\307?\260\225\212B\307\270\257?\212z\303\244\363\274\264?\203hXX\004\356\303\277\232\247\004\267\215\372\265?\244\272\263\236j\000\302\277B\331\205\232\273\302\223?g\343\031\262\337\267\275\277?$~c]D\265\277\221\000\304}\323\316\257?\0228\225\356\277\000\263\277\301\0245\231i\244\257\277\367r\037\016\342\212\327\277\310mO\010\350\234\263?8\342ycZ\377\311?\305\350G.\003\264\267?\265\032j\273b@\303?\250\302Xe+\352\302\277)\r0\360\362\344\305\277\000\215\n\364\223\003\311?\357\377\263\233Zi\305\277\354\326q\220\3319\316?\034\237\327\205\225\221\301\277y\\\326r<\027\275\277\211\310\207\344\001K\301?" + } + } + } +} +node { + name: "layer_0_type_1/matrix/read" + op: "Identity" + input: "layer_0_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_1/matrix" + } + } + } +} +node { + name: "strided_slice_61/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_61/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_61/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "Reshape_28/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "Slice_14/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_14/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_37/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_60/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_60/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_60/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "mul_36/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_59/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_59/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_59/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_58/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_58/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_58/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "final_layer_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + } + double_val: 0.04604106977730532 + } + } + } +} +node { + name: "final_layer_type_0/bias/read" + op: "Identity" + input: "final_layer_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_0/bias" + } + } + } +} +node { + name: "final_layer_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + dim { + size: 1 + } + } + tensor_content: "9\303z`\tc\255?\347%\356>\201b\302\2775\302\356\036\3530\320\277k\241\'\020~W\254\277\002U\324P\362\213\343?\310wN\244O\024\303\277A\272\000\234\340\260\302?\261\371\310\252\"\224\341\277" + } + } + } +} +node { + name: "final_layer_type_0/matrix/read" + op: "Identity" + input: "final_layer_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_0/matrix" + } + } + } +} +node { + name: "layer_2_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "layer_2_type_0/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "qh\037x\2574\263?v\206/H\030\332\262?\034\240\351\326d\320\262?\0135+\010z\324\263?F\035\233\204 y\263?\312_\347\326b\372\265?\312\223\257?\256 \263?\340\256\203\366\361\214\262?" + } + } + } +} +node { + name: "layer_2_type_0/idt/read" + op: "Identity" + input: "layer_2_type_0/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_0/idt" + } + } + } +} +node { + name: "layer_2_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "L\334\030@\242\322\313?\240\022\205?\313\355\324\277\312\000\3269\233\356\351\277VW\377,V\356\313\277\241T\312YL$\376?\262\221\217\312\217\371\325\277E\320d\307\032W\325?jv\265Y\000\010\373\277" + } + } + } +} +node { + name: "layer_2_type_0/bias/read" + op: "Identity" + input: "layer_2_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_0/bias" + } + } + } +} +node { + name: "layer_2_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + dim { + size: 8 + } + } + tensor_content: "I\024\336\234\320N\243?\326D\205\353\366\217\260\277\273\341\260\357^\275\307\277\275V\362\342\257t\243\277\244\273\360\264\336\n\335?\002\rB\301t\242\261\277Y>)\315\035\326\260?Y\354\0034\253\346\331\277J\222\236iJ\257\301?\330\350=EP\311?&\266\363L\331\222\277?F\377\242\224\357\210\264?\214Q\374\036\\\357\275\277\364\005\013\317\207M\264\277\367\276U\315]\267\227?&i\355\276\356:\221\277\327\\\313\245\250\241\341\2770F\037PzR\317\277\"\250\251w\204\260\303\277\0074\034\270\002\300\306\277\034\\;~g\357\303\277]z\236C*\276\260\277\2264\\|\021\244\316\277\236x)n\253v\306\277\243F*\205\314M\251\277\263~@g\246{\316?P>R1\356\004\267?\035X\204\303ol\251\277\313\n\355 \202K\306\277\"\336\220m\307-\310\277:\034\253W3\320\337?L\300\320\277\230M\322\277\253m\302H\243\022\256\277*\327\177\200\025C\303?e\032\222\214\226\234\276\277{h\244\247\367\217\327\277\010\357\271\222\2359\211?j&\210\362G\353\261?j\037\204s#\265\320?\037\025\324\363o\272\274\277W\0240\363\006R\276\277T\376\016(\354;\336?\216\370\2047#g\263\277^(Y\326\023k\342\277\007\027J\243h\002\273?\300\315\275\r.h\256?\267@\270\257KP\276\277\313&\301H\0358\226\277\277\370x\t-\216\215\277\220\304\017?\241\232\322?\241CMW\277\304\330\261\327D\210\323\277`\223>\247\337\207\250?" + } + } + } +} +node { + name: "layer_1_type_0/matrix/read" + op: "Identity" + input: "layer_1_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_0/matrix" + } + } + } +} +node { + name: "layer_0_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "layer_0_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "\250B\303\335{\234\313?g\272,\216\3353\325\277\2047fj\313\'\352\277x%\370\210=\261\313\277o\233\226\303\362 \376?\233\027\233\214\335A\326\277\314\233\331\014B\253\325?t\375\33621\007\373\277" + } + } + } +} +node { + name: "layer_0_type_0/bias/read" + op: "Identity" + input: "layer_0_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_0/bias" + } + } + } +} +node { + name: "layer_0_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 32 + } + dim { + size: 8 + } + } + tensor_content: "\204#\335U\215\034\207?\234H\233\333\031\206\241\277\364\220\307\030\265\325\273\277\010PlY\306o\206\277\030C[f\237\220\321?0$H\\\207\357\242\277\\\230D\344\3303\242?\002dN\372\035I\317\277\372\003\241\177\331\216\263?\023@\3706\312\360\270\277\033\014\216\227\302\352\250?\206\340\033\201\325\363\300\277\345\'S\004\350x\217\277\262\362\007Hy\300\320?E\210\343\024\221O\271?\214&\272\366D\254\245\277#2\336\321J\265\310\277\345;\204YP\020\332?=\021\263\010.[\240\277\311(i\027S\255\273?_\247\3245)\277\264?\032N\004\251s\257\275?\\\315\005\024\013g\211?\211\334 -\231\321\236\277h\266\n\202%\350\267\277\365}\346\"k\001\253?8 \324\332\230*\233?\303+)\251\302\205\323\277\005\351\237\0222l\311\277vhj5(a\256\277\313\336R\305bK\303\277@\034\304\006d\373\253\277\\\270m?\210\316\252\277in\272>\337\264\302\277b\347\273\376&\331\272\277\267\\\303\036->\224\277\201B\326T{\340\301?\342\207\0363j\262\257?7;6:\302p\242\277\366Fn\010\n\242\271\277\277\266\307=\274\262\300\277\007U\246\254\030v\324?\231\364\310\200\345z\306\277\002\333\275\215\322T\232\277\204\212\365$\307\224\265?SxQCs\r\262\277sH\n\002kg\316\277\271\261\336\351\350>\222?1\225\277\362\260\212P?\033\307\354\343\236\005\312?\253Cw\205\307\331\240\277\245u\231\314\246\021\240\277 \336\251\001\327N\320?T\213\263\252\333@\204\277\244ids\227\301\331\277\216\2452\312,P\274?\344\234R\226]\216i\277.CI\243b$\244\277\r\3773/!W\224?\313cr\273\331;\240?\006\024\026\275:K\302?\235\r\247H\305\233\241?\302\301\330\274\262?\315\277\tN\215\'N4\262?e\225\257\"\243\037\277\277Sj\017\252E\332\234?\253\034\376>B\200\260\277h\263\373\342\023h\320?\325]\223\310\007\004s?\212\360\243E\324\022\326?\221\013\003aF>\244\277\211\353H\255\255\335\247?\230\305\326>Q\270\267\277\014z\344\0349H\262\277\235I\252b\326\005\307?U\207x\035\3011\252?\357;m^\255C\321\277\001\347(`\244\322\307\277A{\354g\017\265\310?\264\330\277\341o\010\306?R\225\221\211l\270\276?\211l\355\204`A\240?\006I\035\300R\204\260\277\rZD\300a\027\267\277\3765)\005\351\036\307\277R\267\377!\r\307\330?bk2\263*?\263?\000\021\'4\031\366\256?\254\264\225\227\335G\322?I\334\'c\371\237\320?g\005\316\021\'\327\275\277\262\016c\202ne\274\277\316\343\214\357\247r\264\277\205\320)\247\021U\245?\233*\231;\201\257\254\277\001\237\374\303\315=\300\277B\207$\367\377\342\241\277\365\2362\315u\317\306?5\330\300FCc\314?5\010\335\350\352\260\301\277&\t\016\263p\324\274\277%q\0144\027\025\304\277e\325\326Nt\265\261?\312S\277\323\313\312\260?\037\r\000\3002\212\234\277\257\213\225\275\350\366\270\277JK\245V\023\335\304?\352\032\001\006\227\223\310\277\002g\244\210\360\227\277\277K\034P\350p\212\321?cc\345\335t\273\302?>\346e`\373`\245?L\205\344r\370\004\245?\313Ek\341r\317\302?v\222\206p8\225\305\277\362\215\321\347\275\272\321\277z\321\333\024\257\016\262\277\2716o\350\\s\220\277.\264g\002\237\214\275\277\2010\310\343\002A\270\277\315\004*\200pO\262?^m%rK[\255\277\263\370>\230z\377\277?\014\032\361\206\361iw\277\237\261BW\300\230\303?\313wm\3626`\272?1\250\271\016\002X\255\277\257\345\371\301\224E\303?\244\205\350Ae\331\262\277\030\010\363\323\276\223\236\277\204\273P\020\025\"\226\277r`\001\236\314k\233\277ea\2263\027\346\252?\254\233u4/\t\240\277I\210*o\235b\276\277\277\240\347\204\261\316\262?C\266tpsA\324\277\263\376\235c/\005\261\277\322\264\246\211\207\270\311\277W\351\373\026ez\200\277\016O\356\365\244B\300?@@\222io\221\313?\177\360\310.wv\320\277\n\365^\340\021\244\317?\367\343\246\2739\330\224\277\016\270\355f\326fn\277\323{b\224\315\372\302?\257\251}\017KZ\230\277*h\242\026\024)\244\277C\202\306\3634|\265\277\343(\2348\356R\205\277\3355u\033\201>\200\277\244\365\237\023\220\270\307?\236hpK\327\256\304?\030\273@\001\350G\313\277i\024&\031XN\222?5u\277s\255\004\253\277:.\016\321f\255v?\267\373\001\215a6\320?\366\200\002hc#\241?<\323\242g\233\225\314?\324\232m\215A\345\304?\362\240\370\270rq\263?\\\353)\275\037\304\306\277\316yq\363\007\311\312?;91\227p\325\252?T\r\206\200H\000\323\277\236\002F\343\002T\262\2778\270\035\260`\027\273?v\314\035\036\2719\325?gx2\266(t\252?\316\226\nS\005\224\265?S\317jC\247\347\317?\376\036\003\371*\333\271?K7L\337\356\321\245?W\2735\342\007\331\321\277Rl\343\002\2429\220\277$\001\013\214\313\024\262?\351\354\242]\227Ps\277R\273\007X\241K\275\277\375\313d\216>\006\303\277\213Z\273\024\313<\305?\377z\2606\"T\312?\177\026\212\257\202\010\266?\326\332\275fl\035\234\277\260\356\337<\331\217\232?\2650{\277\355\211\315\277\212e\224k>p\313?\255\0258\256*\254\315\277\243\226\356Z`F\311?Tr\030\021\336\261\273\277\326M\236b+6\263\277-8K\230\267\222\307?\202M\347\242\016\267\226\277G\245%\032\320\223\320\277|\246\331\365#\336\224?\304ww\001\221\001\260\277\310\300\347H\030\013\305\277U7\371E\233~\260\277\330:g\005\003\247\314?]\326\260\200\003\331\263\277\220\005c\335\222c\263?\321\317\020\235Bk\305\277\264g\006\305\266\322\273?\274?\347\357\374n\315\277\007\203\236\030\214\271\275\277\251\275\2413\234\211g?\373\304<\326\215\341\220\277!\030\367\245;[\306?aCDN\346\n\307\277_\3008\207\213f\301\2779\n\004\357\370n\257\277\214\350\311@\310\343\312\277\204w\022-\240)\273?\261\255\245\225KI\232\277\225aS\033\305\340\257\277\217\"5dd\303\265?\002\013\014\225\005\273\305?\013\237\3034MC\263?\006SP\233\242\320\277\277\373\215\207\266d\034\312?\353\025Y\007\272\001\313?\272\3610g\311\373\306\277H\"\265\304p\210\303?\347\312\033\346V6\267?j\247\264U\273\021\320?\312\244\2574\363\350\251\277*\252\311#\000\032\315?\"~\341\n\362#\240\277\213\031\261s\256W\207?D\036\031\265A\035\300\277\246m\253\003\326\230\310?\311.&0\355\335\257?4\r\271\301_\230\263?\251*\001\250\331\257\304\277\274\206\262.@e\266?\223\005\\d\032\"\302\277\r(\266\244\262\r\216?~\223\206D\030\210\274\277\313\313\326\207e,\263\277l\350\014\377\352\363\257?!N[\027\267#\264\277\'{\305\342\324b\261\277\364\232!\204jp\327\277\202$\211Bn[\263?\"\206\214\336\253h\311?s\004\333\2700\342\270?-\331\303\255eL\304?\200P\010\272\311\324\302\277z7:\333\"z\306\277\375\222c4:\004\310?{PM\0214B\305\277\010\237P\276\377,\316?\336{uV\027,\302\277\355E1\370N\341\273\277\207X*oYZ\302?" + } + } + } +} +node { + name: "layer_0_type_0/matrix/read" + op: "Identity" + input: "layer_0_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_0/matrix" + } + } + } +} +node { + name: "add_19/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "strided_slice_57/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_57/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_57/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "Reshape_26/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "Slice_13/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_13/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients_3/Slice_13_grad/Reshape" + op: "Reshape" + input: "Slice_13/begin" + input: "gradients_3/Slice_13_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_35/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_56/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_56/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_56/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "Reshape_25/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_34/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_55/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_55/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_55/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "fitting_attr/daparam" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "fitting_attr/dfparam" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_31/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "strided_slice_52/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_52/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_52/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "strided_slice_51/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_51/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_51/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "filter_type_all/Reshape_35/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_10/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_10/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\000\000\000\000\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_10_grad/Reshape" + op: "Reshape" + input: "filter_type_all/Slice_10/begin" + input: "gradients_3/filter_type_all/Slice_10_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/mul/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.04 + } + } + } +} +node { + name: "filter_type_all/Reshape_34/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Reshape_33/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/concat_14/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_14_grad/mod" + op: "FloorMod" + input: "filter_type_all/concat_14/axis" + input: "gradients_3/filter_type_all/concat_14_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_32/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_3_4" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\332\317oE\005f\315?\006\314\020\216#\003\330\2770\304Y\304i\222\353\277:k\377\346\277X\320\277<\215+Z6+\376?m\231\332\337\021m\330\277\036\371n\036F\352\327?\030\327\336\351\017\260\373\277" + } + } + } +} +node { + name: "filter_type_all/bias_3_4/read" + op: "Identity" + input: "filter_type_all/bias_3_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_3_4" + } + } + } +} +node { + name: "filter_type_all/matrix_3_4" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\200t)\352\237;\253?\307\333\313\240\212A\263\277\330\224\277\302\020\365\313\277\331\214\255|kr\246\277\334\306\2206\272x\342?\037\366\016\027b\254\277\277\312D\300\346\034\363\276?\254\366V\373\230\013\336\277\025:\272{\364\t\306?\t/\201~\314{\310\277\206]\344\302xB\262?\265\320\260\022\345\303\321\277\376!-\263\320\360\247?\253-\023\022E\372\332?\227\346hm\030N\315?i\226jHQu\274\277\r2\310\370&w\324\277\016\014q9L`\347?Y\307\210:1O\263\277\221\033\204\272\2349\305?\346\301\250\027k\211\314?\217\263\365\004g\341\303?\244~\243\200\t\200\262?\305i\321\216Qp\266\277\346\313\2123\321\236\301\277!\304Z\313\333\347\264?\376>\036\231\310\034\241?\353\007M\262F\375\342\277\365\204\321\340\325r\322\277l\266\363\267\351\022\305\277IrQKP\330\314\277\364i\007\001\273\"\301\277" + } + } + } +} +node { + name: "filter_type_all/matrix_3_4/read" + op: "Identity" + input: "filter_type_all/matrix_3_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_3_4" + } + } + } +} +node { + name: "filter_type_all/concat_13/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_13_grad/mod" + op: "FloorMod" + input: "filter_type_all/concat_13/axis" + input: "gradients_3/filter_type_all/concat_13_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_31/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_2_4" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\324XR\270A1\320?\232\016\240\207\344\307\325\277\371(\347\367\2357\353\277@\207\220\321\265g\320\277" + } + } + } +} +node { + name: "filter_type_all/bias_2_4/read" + op: "Identity" + input: "filter_type_all/bias_2_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_2_4" + } + } + } +} +node { + name: "filter_type_all/matrix_2_4" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\235305\001\025\263?\270\222\311\311\241^\304\277g\233\263\341\"\237\324\2770%\007\307w\205\262\277\270\300\255\231\343l\350?\217\212\020[\3274\305\277\200\306#14L\305?\323x-;\310\245\345\277" + } + } + } +} +node { + name: "filter_type_all/matrix_2_4/read" + op: "Identity" + input: "filter_type_all/matrix_2_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_2_4" + } + } + } +} +node { + name: "filter_type_all/concat_12/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_12_grad/mod" + op: "FloorMod" + input: "filter_type_all/concat_12/axis" + input: "gradients_3/filter_type_all/concat_12_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_30/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_1_4" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\304\350\253\241\232?\320?\237.<\260\364\217\325\277" + } + } + } +} +node { + name: "filter_type_all/bias_1_4/read" + op: "Identity" + input: "filter_type_all/bias_1_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_1_4" + } + } + } +} +node { + name: "filter_type_all/matrix_1_4" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "N\235\256HU3\304?\332\201\nsre\311\277" + } + } + } +} +node { + name: "filter_type_all/matrix_1_4/read" + op: "Identity" + input: "filter_type_all/matrix_1_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_1_4" + } + } + } +} +node { + name: "filter_type_all/Reshape_29/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_9/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_9/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_9_grad/Reshape" + op: "Reshape" + input: "filter_type_all/Slice_9/begin" + input: "gradients_3/filter_type_all/Slice_9_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_28/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_8/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\024\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_8/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000P\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_8_grad/Reshape" + op: "Reshape" + input: "filter_type_all/Slice_8/begin" + input: "gradients_3/filter_type_all/Slice_8_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_27/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Reshape_26/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/concat_11/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_11_grad/mod" + op: "FloorMod" + input: "filter_type_all/concat_11/axis" + input: "gradients_3/filter_type_all/concat_11_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_25/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_3_3" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "b\347\237\322\267!\316?=\215\001\377\"T\330\277$d\2536+\231\353\277\007>\ti#\205\320\277\2522\353\251V)\376?\254\307I\341Ab\330\2775\242<\373x\244\327?\007\177\260\200\247\272\373\277" + } + } + } +} +node { + name: "filter_type_all/bias_3_3/read" + op: "Identity" + input: "filter_type_all/bias_3_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_3_3" + } + } + } +} +node { + name: "filter_type_all/matrix_3_3" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\220{\032\370\033\034\253?\037\360[\363\016C\265\277\006\327}\365\256F\314\277t\026{\010\212G\250\277\r\"\023I\265u\342?\206\020\024/\375\311\277\277\312($\205k\365\276?\253\361\324y\346\036\336\277\033d\360O\251\364\305?\033\217\354%\326n\310\277MO\323=6o\262?\353\003\250(\377\301\321\277a6+1@\037\250?\3357j\236\242\357\332?\367\030\254)\260^\315?\177\024\362K)\362\273\277\374f\204/z\177\324\277\362\034!\376i^\347?\200\221\220\"D9\263\277R[\207\323\322\271\304?NqFV\037\222\314?v_E\202{\316\303?u\\\016#\313\220\262?h\003\035\032\031\025\266\277\001\022v\260\177\263\301\277#\264>B\2172\265?\217\004\000~\272\236\241?^&\347\263^\364\342\277m\022\212\265Tl\322\277\244\007\246\334@(\305\277\210\247U\364\201\304\314\277\262\245\274\351\004\332\300\277" + } + } + } +} +node { + name: "filter_type_all/matrix_3_3/read" + op: "Identity" + input: "filter_type_all/matrix_3_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_3_3" + } + } + } +} +node { + name: "filter_type_all/concat_10/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_10_grad/mod" + op: "FloorMod" + input: "filter_type_all/concat_10/axis" + input: "gradients_3/filter_type_all/concat_10_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_24/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_2_3" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\3533\266k\345\221\320?E\271\211\260\223\256\325\277/\373\247bf\220\353\277\261\021\007\314\022\034\321\277" + } + } + } +} +node { + name: "filter_type_all/bias_2_3/read" + op: "Identity" + input: "filter_type_all/bias_2_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_2_3" + } + } + } +} +node { + name: "filter_type_all/matrix_2_3" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\"\n\"9\023\313\272?\273r\274yT\244\304\277\343\233\373g\223\270\324\277h\275\354\242B\354\272\277p!\353\250.p\350?i\353\273\311\350C\305\277Q\314\352\274JT\305?\312$\244\211\215\247\345\277" + } + } + } +} +node { + name: "filter_type_all/matrix_2_3/read" + op: "Identity" + input: "filter_type_all/matrix_2_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_2_3" + } + } + } +} +node { + name: "filter_type_all/concat_9/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_9_grad/mod" + op: "FloorMod" + input: "filter_type_all/concat_9/axis" + input: "gradients_3/filter_type_all/concat_9_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_23/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_1_3" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "P\237\3715\223\036\320?o\220a\203I\211\325\277" + } + } + } +} +node { + name: "filter_type_all/bias_1_3/read" + op: "Identity" + input: "filter_type_all/bias_1_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_1_3" + } + } + } +} +node { + name: "filter_type_all/matrix_1_3" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\323\027D\327\237\201\303?\375h\025\217P\273\311\277" + } + } + } +} +node { + name: "filter_type_all/matrix_1_3/read" + op: "Identity" + input: "filter_type_all/matrix_1_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_1_3" + } + } + } +} +node { + name: "filter_type_all/Reshape_22/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_7/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_7/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_7_grad/Reshape" + op: "Reshape" + input: "filter_type_all/Slice_7/begin" + input: "gradients_3/filter_type_all/Slice_7_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_21/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_6/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\024\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_6/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000<\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_6_grad/Reshape" + op: "Reshape" + input: "filter_type_all/Slice_6/begin" + input: "gradients_3/filter_type_all/Slice_6_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_20/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Reshape_19/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/concat_8/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_8_grad/mod" + op: "FloorMod" + input: "filter_type_all/concat_8/axis" + input: "gradients_3/filter_type_all/concat_8_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_18/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_3_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "2\005\367\352\345\303\315?\210\301\032+lT\330\277j\025\357\207\342\230\353\277\213\230\010\200\024\204\320\277\314\240_tq)\376?1i\325\222\341\300\330\277Q\322Md\354\304\327?\320\3104t8\272\373\277" + } + } + } +} +node { + name: "filter_type_all/bias_3_2/read" + op: "Identity" + input: "filter_type_all/bias_3_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_3_2" + } + } + } +} +node { + name: "filter_type_all/matrix_3_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "E\354\230\3562\215\252?V:\005\352H\320\264\277\031\207\251\304_.\314\277\271\245\023.\252]\250\277kL\226_\260u\342?\n\305\006\332\315\021\300\277Zg\2015tB\277?\026\200\206\321!\037\336\277u\220\323Q\007\323\305?\255\307\214\231\202q\310\277\201wM\211Cy\262?-X\323\033b\302\321\277e;*&\t\034\250?\305\020\231\266,\332\332?\237o3Db\217\315?\242\316}pi\371\273\277\323\306\024\022\230\220\324\277\244e\320\n|]\347?\217U\377\211\325,\263\277d<\307\307u\271\304?2~\320\216L\221\314?\340\030\274\310\373\242\303?\215\000O\005\274\000\263?RHr3\244\034\266\277\310<#\313\'\326\301\277T]\372\302B+\265?\256\016wc\330\277\241?\365K\237\005L\364\342\277\264\231q\032\271l\322\277<\357+j T\305\277 \360\362\334\366\210\314\277\030\033}\370v\335\300\277" + } + } + } +} +node { + name: "filter_type_all/matrix_3_2/read" + op: "Identity" + input: "filter_type_all/matrix_3_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_3_2" + } + } + } +} +node { + name: "filter_type_all/concat_7/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_7_grad/mod" + op: "FloorMod" + input: "filter_type_all/concat_7/axis" + input: "gradients_3/filter_type_all/concat_7_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_17/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_2_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\361o(\252}\220\320?7\022\240\372W\273\325\277@\\,]n\214\353\277\356\204(\276\213\033\321\277" + } + } + } +} +node { + name: "filter_type_all/bias_2_2/read" + op: "Identity" + input: "filter_type_all/bias_2_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_2_2" + } + } + } +} +node { + name: "filter_type_all/matrix_2_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\353z\261\032\311\250\272?_j\303.\037\307\304\277\337-\320\266\354\245\324\277\213\353\023\255[\264\272\277\347\327\356\346\324p\350?\323j3Hb\245\305\277G\305\003K)o\305?\346gk[\330\247\345\277" + } + } + } +} +node { + name: "filter_type_all/matrix_2_2/read" + op: "Identity" + input: "filter_type_all/matrix_2_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_2_2" + } + } + } +} +node { + name: "filter_type_all/concat_6/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_6_grad/mod" + op: "FloorMod" + input: "filter_type_all/concat_6/axis" + input: "gradients_3/filter_type_all/concat_6_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_16/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_1_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "(`D0\310I\320?\006oY\271\334\201\325\277" + } + } + } +} +node { + name: "filter_type_all/bias_1_2/read" + op: "Identity" + input: "filter_type_all/bias_1_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_1_2" + } + } + } +} +node { + name: "filter_type_all/matrix_1_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "k~\317\0262\265\303?\334=S\253\274\237\311\277" + } + } + } +} +node { + name: "filter_type_all/matrix_1_2/read" + op: "Identity" + input: "filter_type_all/matrix_1_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_1_2" + } + } + } +} +node { + name: "filter_type_all/Reshape_15/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_5/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_5/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_5_grad/Reshape" + op: "Reshape" + input: "filter_type_all/Slice_5/begin" + input: "gradients_3/filter_type_all/Slice_5_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_14/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_4/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\024\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_4/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000(\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_4_grad/Reshape" + op: "Reshape" + input: "filter_type_all/Slice_4/begin" + input: "gradients_3/filter_type_all/Slice_4_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_13/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Reshape_12/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/concat_5/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_5_grad/mod" + op: "FloorMod" + input: "filter_type_all/concat_5/axis" + input: "gradients_3/filter_type_all/concat_5_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_11/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "6\313%\005L\256\313?\270>\013\316e\027\326\277\334\023p\364\205m\353\277ll\367d\200\256\320\277\333\3115\202\330+\376?\"\311F\035\014M\331\277\030\013Z\016\364\327\327?\365\2477\022\377\261\373\277" + } + } + } +} +node { + name: "filter_type_all/bias_3_1/read" + op: "Identity" + input: "filter_type_all/bias_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_3_1" + } + } + } +} +node { + name: "filter_type_all/matrix_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "r\260M\021\266c\246?\232[$\211\343>\263\277\324\355mn\220l\313\277\302o\334\230\374i\246\277\250\304Y=\364s\342?;\235\350\3778\372\300\277\303\353\264dj\244\300?\304\311\032\247\375\037\336\277S\000KVz\323\304?NRl6\374e\310\277\274\2372\207,\021\263?\021\223n\220\350\001\321\277\365%\034\0365\326\247?8\277b\366\245h\332?\360\362\267T\002\357\316?f\177N\0173q\274\277\242\373\314\017I\022\325\277 \3212\021\035b\347?q\234\273d{t\262\277%\027f\350^?\306?\017F\177a#\201\314?\230\245G\256.\276\302?&\255\211\242\263\312\265?\310\217\000K\273\210\266\277:@\177V\n\333\302\277\263\314\210\264\341]\265?02\315\035C\\\243?\245\263S\345\355\220\342\277\026ys\001\363t\322\277,>BC\3309\306\277\ro8\3441\001\313\277\260\322\342\333\'\032\301\277" + } + } + } +} +node { + name: "filter_type_all/matrix_3_1/read" + op: "Identity" + input: "filter_type_all/matrix_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_3_1" + } + } + } +} +node { + name: "filter_type_all/concat_4/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_4_grad/mod" + op: "FloorMod" + input: "filter_type_all/concat_4/axis" + input: "gradients_3/filter_type_all/concat_4_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_10/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\031\220\021\035hn\317?\356\362V\232\311E\326\277\271\014\370\005\224\244\352\277\327\311\243T<\260\320\277" + } + } + } +} +node { + name: "filter_type_all/bias_2_1/read" + op: "Identity" + input: "filter_type_all/bias_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_2_1" + } + } + } +} +node { + name: "filter_type_all/matrix_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\373\242\036\004\036\265\263?\371\032%\237\304\307\304\277~\2065\002\246\035\324\277\317\365R\325\014\261\262\277\006\311\331}\307s\350?\321|\327\335\237\220\305\277xGn\210\267H\306?\032\006\035\237\371\237\345\277" + } + } + } +} +node { + name: "filter_type_all/matrix_2_1/read" + op: "Identity" + input: "filter_type_all/matrix_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_2_1" + } + } + } +} +node { + name: "filter_type_all/concat_3/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_3_grad/mod" + op: "FloorMod" + input: "filter_type_all/concat_3/axis" + input: "gradients_3/filter_type_all/concat_3_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_9/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "_\212\240\201\341\230\320?s\016P\350,\355\324\277" + } + } + } +} +node { + name: "filter_type_all/bias_1_1/read" + op: "Identity" + input: "filter_type_all/bias_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_1_1" + } + } + } +} +node { + name: "filter_type_all/matrix_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\336\001\010~ac\305?\0176\362r\r\001\307\277" + } + } + } +} +node { + name: "filter_type_all/matrix_1_1/read" + op: "Identity" + input: "filter_type_all/matrix_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_1_1" + } + } + } +} +node { + name: "filter_type_all/Reshape_8/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_3/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_3/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_3_grad/Reshape" + op: "Reshape" + input: "filter_type_all/Slice_3/begin" + input: "gradients_3/filter_type_all/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_7/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_2/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\024\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_2/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\024\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_2_grad/Reshape" + op: "Reshape" + input: "filter_type_all/Slice_2/begin" + input: "gradients_3/filter_type_all/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_6/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_2_grad/mod" + op: "FloorMod" + input: "filter_type_all/concat_2/axis" + input: "gradients_3/filter_type_all/concat_2_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_4/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "{\022*\030\365\004\317?X\002\026\014\013\372\324\277\3223/\035\356\014\353\277r\230\031\\=.\321\277\225B\225\006\"*\376?\365\302\004\335\016=\326\277\256\032n\371\374x\325?\3005&\034\341\273\373\277" + } + } + } +} +node { + name: "filter_type_all/bias_3_0/read" + op: "Identity" + input: "filter_type_all/bias_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_3_0" + } + } + } +} +node { + name: "filter_type_all/matrix_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: ",\363\354}`I\247?NJ>\036\302@\263\2777s\262\327\266\177\313\277\311:\270\343\364\305?\322\335\227\026\372\355\251?v2\253p\312\"\265\277\036\365\351\240\003\207\302\277\216\316\222\255\326c\265?\374\026r\227\303\322\242?b\276\200\027\202,\343\277Nc\315\320\272n\322\277\246\271K\t\023G\304\277\276|\336\206,\r\316\277\203{\227<7\244\300\277" + } + } + } +} +node { + name: "filter_type_all/matrix_3_0/read" + op: "Identity" + input: "filter_type_all/matrix_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_3_0" + } + } + } +} +node { + name: "filter_type_all/concat_1/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_1_grad/mod" + op: "FloorMod" + input: "filter_type_all/concat_1/axis" + input: "gradients_3/filter_type_all/concat_1_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\255\251\323\232\023\246\316??\366i\233@\253\325\277\270$\242\353\201\006\353\277\274\021P\313Q\204\320\277" + } + } + } +} +node { + name: "filter_type_all/bias_2_0/read" + op: "Identity" + input: "filter_type_all/bias_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_2_0" + } + } + } +} +node { + name: "filter_type_all/matrix_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\251\251\037\003k\030\263?\304T\266I~9\300\277\rS\333\3470#\324\277\301\212Rn<\205\262\277\367\373\025\033\326K\350?:\231p\003\322\324\303\277\210\371\005\010\357&\306?\302\337\221\254\233\237\345\277" + } + } + } +} +node { + name: "filter_type_all/matrix_2_0/read" + op: "Identity" + input: "filter_type_all/matrix_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_2_0" + } + } + } +} +node { + name: "filter_type_all/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_3/filter_type_all/concat_grad/mod" + op: "FloorMod" + input: "filter_type_all/concat/axis" + input: "gradients_3/filter_type_all/concat_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_2/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_all/bias_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: ")lJX-\360\313?\211\367\306\311\027\265\325\277" + } + } + } +} +node { + name: "filter_type_all/bias_1_0/read" + op: "Identity" + input: "filter_type_all/bias_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/bias_1_0" + } + } + } +} +node { + name: "filter_type_all/matrix_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\274\341\333\262\\\341\302?\276\240\333;\277\341\307\277" + } + } + } +} +node { + name: "filter_type_all/matrix_1_0/read" + op: "Identity" + input: "filter_type_all/matrix_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_all/matrix_1_0" + } + } + } +} +node { + name: "filter_type_all/Reshape_1/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_1/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice_1/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_1_grad/Reshape" + op: "Reshape" + input: "filter_type_all/Slice_1/begin" + input: "gradients_3/filter_type_all/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\024\000\000\000" + } + } + } +} +node { + name: "filter_type_all/Slice/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_grad/Reshape" + op: "Reshape" + input: "filter_type_all/Slice/begin" + input: "gradients_3/filter_type_all/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_22/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377d\000\000\000" + } + } + } +} +node { + name: "Reshape_21/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_30/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_50/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_50/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_50/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_20/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377d\000\000\000" + } + } + } +} +node { + name: "Reshape_19/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "strided_slice_49/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_49/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_49/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "Reshape_18/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\t\000\000\000" + } + } + } +} +node { + name: "Reshape_17/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_29/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_48/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_48/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_48/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "descrpt_attr/t_std" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 5 + } + dim { + size: 100 + } + } + tensor_content: "\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?" + } + } + } +} +node { + name: "descrpt_attr/t_std/read" + op: "Identity" + input: "descrpt_attr/t_std" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@descrpt_attr/t_std" + } + } + } +} +node { + name: "descrpt_attr/t_avg" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 5 + } + dim { + size: 100 + } + } + tensor_content: "\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "descrpt_attr/t_avg/read" + op: "Identity" + input: "descrpt_attr/t_avg" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@descrpt_attr/t_avg" + } + } + } +} +node { + name: "descrpt_attr/ntypes" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 5 + } + } + } +} +node { + name: "descrpt_attr/rcut" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 4.0 + } + } + } +} +node { + name: "model_attr/model_type" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "ener" + } + } + } +} +node { + name: "model_attr/tmap" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "A B C D E" + } + } + } +} +node { + name: "t_mesh" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "t_natoms" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: 7 + } + } + } + } +} +node { + name: "strided_slice_79" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_79/stack" + input: "strided_slice_79/stack_1" + input: "strided_slice_79/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_46" + op: "Mul" + input: "mul_46/x" + input: "strided_slice_79" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "o_atom_virial/shape" + op: "Pack" + input: "o_atom_virial/shape/0" + input: "mul_46" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_78" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_78/stack" + input: "strided_slice_78/stack_1" + input: "strided_slice_78/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_45" + op: "Mul" + input: "mul_45/x" + input: "strided_slice_78" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "o_force/shape" + op: "Pack" + input: "o_force/shape/0" + input: "mul_45" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_77" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_77/stack" + input: "strided_slice_77/stack_1" + input: "strided_slice_77/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_44" + op: "Mul" + input: "strided_slice_77" + input: "mul_44/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_37/shape" + op: "Pack" + input: "Reshape_37/shape/0" + input: "mul_44" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_76" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_76/stack" + input: "strided_slice_76/stack_1" + input: "strided_slice_76/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "o_atom_energy/shape" + op: "Pack" + input: "o_atom_energy/shape/0" + input: "strided_slice_76" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_75" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_75/stack" + input: "strided_slice_75/stack_1" + input: "strided_slice_75/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_72" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_72/stack" + input: "strided_slice_72/stack_1" + input: "strided_slice_72/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_43" + op: "Mul" + input: "strided_slice_72" + input: "mul_43/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_17/size" + op: "Pack" + input: "Slice_17/size/0" + input: "mul_43" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_71" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_71/stack" + input: "strided_slice_71/stack_1" + input: "strided_slice_71/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_69" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_69/stack" + input: "strided_slice_69/stack_1" + input: "strided_slice_69/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_68" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_68/stack" + input: "strided_slice_68/stack_1" + input: "strided_slice_68/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_41" + op: "Mul" + input: "strided_slice_68" + input: "mul_41/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_16/size" + op: "Pack" + input: "Slice_16/size/0" + input: "mul_41" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_67" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_67/stack" + input: "strided_slice_67/stack_1" + input: "strided_slice_67/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_65" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_65/stack" + input: "strided_slice_65/stack_1" + input: "strided_slice_65/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_64" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_64/stack" + input: "strided_slice_64/stack_1" + input: "strided_slice_64/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_39" + op: "Mul" + input: "strided_slice_64" + input: "mul_39/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_15/size" + op: "Pack" + input: "Slice_15/size/0" + input: "mul_39" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_63" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_63/stack" + input: "strided_slice_63/stack_1" + input: "strided_slice_63/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_61" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_61/stack" + input: "strided_slice_61/stack_1" + input: "strided_slice_61/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_60" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_60/stack" + input: "strided_slice_60/stack_1" + input: "strided_slice_60/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_37" + op: "Mul" + input: "strided_slice_60" + input: "mul_37/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_14/size" + op: "Pack" + input: "Slice_14/size/0" + input: "mul_37" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_59" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_59/stack" + input: "strided_slice_59/stack_1" + input: "strided_slice_59/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_57" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_57/stack" + input: "strided_slice_57/stack_1" + input: "strided_slice_57/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "add_19" + op: "Add" + input: "add_19/x" + input: "strided_slice_57" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_22" + op: "Add" + input: "add_19" + input: "strided_slice_61" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_25" + op: "Add" + input: "add_22" + input: "strided_slice_65" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_28" + op: "Add" + input: "add_25" + input: "strided_slice_69" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_42" + op: "Mul" + input: "add_28" + input: "mul_42/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_17/begin" + op: "Pack" + input: "Slice_17/begin/0" + input: "mul_42" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/Slice_17_grad/Reshape" + op: "Reshape" + input: "Slice_17/begin" + input: "gradients_3/Slice_17_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_40" + op: "Mul" + input: "add_25" + input: "mul_40/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_16/begin" + op: "Pack" + input: "Slice_16/begin/0" + input: "mul_40" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/Slice_16_grad/Reshape" + op: "Reshape" + input: "Slice_16/begin" + input: "gradients_3/Slice_16_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_38" + op: "Mul" + input: "add_22" + input: "mul_38/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_15/begin" + op: "Pack" + input: "Slice_15/begin/0" + input: "mul_38" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/Slice_15_grad/Reshape" + op: "Reshape" + input: "Slice_15/begin" + input: "gradients_3/Slice_15_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_36" + op: "Mul" + input: "add_19" + input: "mul_36/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_14/begin" + op: "Pack" + input: "Slice_14/begin/0" + input: "mul_36" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_3/Slice_14_grad/Reshape" + op: "Reshape" + input: "Slice_14/begin" + input: "gradients_3/Slice_14_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_56" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_56/stack" + input: "strided_slice_56/stack_1" + input: "strided_slice_56/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_35" + op: "Mul" + input: "strided_slice_56" + input: "mul_35/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_13/size" + op: "Pack" + input: "Slice_13/size/0" + input: "mul_35" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_55" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_55/stack" + input: "strided_slice_55/stack_1" + input: "strided_slice_55/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_34" + op: "Mul" + input: "mul_34/x" + input: "strided_slice_55" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_25/shape" + op: "Pack" + input: "Reshape_25/shape/0" + input: "mul_34" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_52" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_52/stack" + input: "strided_slice_52/stack_1" + input: "strided_slice_52/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_31" + op: "Mul" + input: "strided_slice_52" + input: "mul_31/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_50" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_50/stack" + input: "strided_slice_50/stack_1" + input: "strided_slice_50/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_30" + op: "Mul" + input: "mul_30/x" + input: "strided_slice_50" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_21/shape" + op: "Pack" + input: "Reshape_21/shape/0" + input: "mul_30" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_49" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_49/stack" + input: "strided_slice_49/stack_1" + input: "strided_slice_49/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_19/shape" + op: "Pack" + input: "Reshape_19/shape/0" + input: "strided_slice_49" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_48" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_48/stack" + input: "strided_slice_48/stack_1" + input: "strided_slice_48/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_29" + op: "Mul" + input: "strided_slice_48" + input: "mul_29/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_17/shape" + op: "Pack" + input: "Reshape_17/shape/0" + input: "mul_29" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "t_type" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_19" + op: "Reshape" + input: "t_type" + input: "Reshape_19/shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "t_coord" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_17" + op: "Reshape" + input: "t_coord" + input: "Reshape_17/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "t_box" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_18" + op: "Reshape" + input: "t_box" + input: "Reshape_18/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "ProdEnvMatA" + op: "ProdEnvMatA" + input: "Reshape_17" + input: "Reshape_19" + input: "t_natoms" + input: "Reshape_18" + input: "t_mesh" + input: "descrpt_attr/t_avg/read" + input: "descrpt_attr/t_std/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "rcut_a" + value { + f: -1.0 + } + } + attr { + key: "rcut_r" + value { + f: 4.0 + } + } + attr { + key: "rcut_r_smth" + value { + f: 0.80000001 + } + } + attr { + key: "sel_a" + value { + list { + i: 5 + i: 5 + i: 5 + i: 5 + i: 5 + } + } + } + attr { + key: "sel_r" + value { + list { + i: 0 + i: 0 + i: 0 + i: 0 + i: 0 + } + } + } +} +node { + name: "o_nlist" + op: "Identity" + input: "ProdEnvMatA:3" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "o_rij" + op: "Identity" + input: "ProdEnvMatA:2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "o_rmat_deriv" + op: "Identity" + input: "ProdEnvMatA:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_20" + op: "Reshape" + input: "ProdEnvMatA" + input: "Reshape_20/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_rmat" + op: "Identity" + input: "Reshape_20" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/Reshape_21_grad/Shape" + op: "Shape" + input: "o_rmat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_21" + op: "Reshape" + input: "o_rmat" + input: "Reshape_21/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Reshape_22_grad/Shape" + op: "Shape" + input: "Reshape_21" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_7" + op: "Shape" + input: "Reshape_21" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_51" + op: "StridedSlice" + input: "Shape_7" + input: "strided_slice_51/stack" + input: "strided_slice_51/stack_1" + input: "strided_slice_51/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_23/shape" + op: "Pack" + input: "strided_slice_51" + input: "mul_31" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Reshape_22" + op: "Reshape" + input: "Reshape_21" + input: "Reshape_22/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_2_grad/Shape_1" + op: "Shape" + input: "Reshape_22" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_grad/Shape_1" + op: "Shape" + input: "Reshape_22" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_4_grad/Shape_1" + op: "Shape" + input: "Reshape_22" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_6_grad/Shape_1" + op: "Shape" + input: "Reshape_22" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_8_grad/Shape_1" + op: "Shape" + input: "Reshape_22" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Slice_8" + op: "Slice" + input: "Reshape_22" + input: "filter_type_all/Slice_8/begin" + input: "filter_type_all/Slice_8/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_8_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_8_grad/sub" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_8_grad/Shape_1" + input: "gradients_3/filter_type_all/Slice_8_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_8_grad/sub_1" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_8_grad/sub" + input: "filter_type_all/Slice_8/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_8_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/Slice_8_grad/sub_1" + input: "gradients_3/filter_type_all/Slice_8_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_8_grad/concat" + op: "ConcatV2" + input: "gradients_3/filter_type_all/Slice_8_grad/Reshape" + input: "gradients_3/filter_type_all/Slice_8_grad/Reshape_1" + input: "gradients_3/filter_type_all/Slice_8_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_28_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_34_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_34" + op: "Reshape" + input: "filter_type_all/Slice_8" + input: "filter_type_all/Reshape_34/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_28" + op: "Reshape" + input: "filter_type_all/Slice_8" + input: "filter_type_all/Reshape_28/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_9_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape_28" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Slice_9" + op: "Slice" + input: "filter_type_all/Reshape_28" + input: "filter_type_all/Slice_9/begin" + input: "filter_type_all/Slice_9/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_9_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_9_grad/sub" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_9_grad/Shape_1" + input: "gradients_3/filter_type_all/Slice_9_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_9_grad/sub_1" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_9_grad/sub" + input: "filter_type_all/Slice_9/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_9_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/Slice_9_grad/sub_1" + input: "gradients_3/filter_type_all/Slice_9_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_9_grad/concat" + op: "ConcatV2" + input: "gradients_3/filter_type_all/Slice_9_grad/Reshape" + input: "gradients_3/filter_type_all/Slice_9_grad/Reshape_1" + input: "gradients_3/filter_type_all/Slice_9_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_29_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_29" + op: "Reshape" + input: "filter_type_all/Slice_9" + input: "filter_type_all/Reshape_29/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_12_grad/ShapeN" + op: "ShapeN" + input: "filter_type_all/Reshape_29" + input: "filter_type_all/Reshape_29" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_12_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_3/filter_type_all/concat_12_grad/mod" + input: "gradients_3/filter_type_all/concat_12_grad/ShapeN" + input: "gradients_3/filter_type_all/concat_12_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_all/concat_12" + op: "ConcatV2" + input: "filter_type_all/Reshape_29" + input: "filter_type_all/Reshape_29" + input: "filter_type_all/concat_12/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_28_grad/Shape" + op: "Shape" + input: "filter_type_all/concat_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_16" + op: "MatMul" + input: "filter_type_all/Reshape_29" + input: "filter_type_all/matrix_1_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_27_grad/Shape" + op: "Shape" + input: "filter_type_all/MatMul_16" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_27_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_27_grad/Shape" + input: "gradients_3/filter_type_all/add_27_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_27" + op: "Add" + input: "filter_type_all/MatMul_16" + input: "filter_type_all/bias_1_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_12" + op: "Tanh" + input: "filter_type_all/add_27" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_30_grad/Shape" + op: "Shape" + input: "filter_type_all/Tanh_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_30" + op: "Reshape" + input: "filter_type_all/Tanh_12" + input: "filter_type_all/Reshape_30/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_28_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape_30" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_28_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_28_grad/Shape" + input: "gradients_3/filter_type_all/add_28_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_28" + op: "Add" + input: "filter_type_all/concat_12" + input: "filter_type_all/Reshape_30" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_13_grad/ShapeN" + op: "ShapeN" + input: "filter_type_all/add_28" + input: "filter_type_all/add_28" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_13_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_3/filter_type_all/concat_13_grad/mod" + input: "gradients_3/filter_type_all/concat_13_grad/ShapeN" + input: "gradients_3/filter_type_all/concat_13_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_all/concat_13" + op: "ConcatV2" + input: "filter_type_all/add_28" + input: "filter_type_all/add_28" + input: "filter_type_all/concat_13/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_30_grad/Shape" + op: "Shape" + input: "filter_type_all/concat_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_17" + op: "MatMul" + input: "filter_type_all/add_28" + input: "filter_type_all/matrix_2_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_29_grad/Shape" + op: "Shape" + input: "filter_type_all/MatMul_17" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_29_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_29_grad/Shape" + input: "gradients_3/filter_type_all/add_29_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_29" + op: "Add" + input: "filter_type_all/MatMul_17" + input: "filter_type_all/bias_2_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_13" + op: "Tanh" + input: "filter_type_all/add_29" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_31_grad/Shape" + op: "Shape" + input: "filter_type_all/Tanh_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_31" + op: "Reshape" + input: "filter_type_all/Tanh_13" + input: "filter_type_all/Reshape_31/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_30_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape_31" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_30_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_30_grad/Shape" + input: "gradients_3/filter_type_all/add_30_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_30" + op: "Add" + input: "filter_type_all/concat_13" + input: "filter_type_all/Reshape_31" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_14_grad/ShapeN" + op: "ShapeN" + input: "filter_type_all/add_30" + input: "filter_type_all/add_30" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_14_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_3/filter_type_all/concat_14_grad/mod" + input: "gradients_3/filter_type_all/concat_14_grad/ShapeN" + input: "gradients_3/filter_type_all/concat_14_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_all/concat_14" + op: "ConcatV2" + input: "filter_type_all/add_30" + input: "filter_type_all/add_30" + input: "filter_type_all/concat_14/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_32_grad/Shape" + op: "Shape" + input: "filter_type_all/concat_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_18" + op: "MatMul" + input: "filter_type_all/add_30" + input: "filter_type_all/matrix_3_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_31_grad/Shape" + op: "Shape" + input: "filter_type_all/MatMul_18" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_31_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_31_grad/Shape" + input: "gradients_3/filter_type_all/add_31_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_31" + op: "Add" + input: "filter_type_all/MatMul_18" + input: "filter_type_all/bias_3_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_14" + op: "Tanh" + input: "filter_type_all/add_31" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_32_grad/Shape" + op: "Shape" + input: "filter_type_all/Tanh_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_32" + op: "Reshape" + input: "filter_type_all/Tanh_14" + input: "filter_type_all/Reshape_32/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_32_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape_32" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_32_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_32_grad/Shape" + input: "gradients_3/filter_type_all/add_32_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_32" + op: "Add" + input: "filter_type_all/concat_14" + input: "filter_type_all/Reshape_32" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_33_grad/Shape" + op: "Shape" + input: "filter_type_all/add_32" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_33" + op: "Reshape" + input: "filter_type_all/add_32" + input: "filter_type_all/Reshape_33/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_19" + op: "BatchMatMul" + input: "filter_type_all/Reshape_34" + input: "filter_type_all/Reshape_33" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_33_grad/Shape_1" + op: "Shape" + input: "filter_type_all/MatMul_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Slice_6" + op: "Slice" + input: "Reshape_22" + input: "filter_type_all/Slice_6/begin" + input: "filter_type_all/Slice_6/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_6_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_6_grad/sub" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_6_grad/Shape_1" + input: "gradients_3/filter_type_all/Slice_6_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_6_grad/sub_1" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_6_grad/sub" + input: "filter_type_all/Slice_6/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_6_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/Slice_6_grad/sub_1" + input: "gradients_3/filter_type_all/Slice_6_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_6_grad/concat" + op: "ConcatV2" + input: "gradients_3/filter_type_all/Slice_6_grad/Reshape" + input: "gradients_3/filter_type_all/Slice_6_grad/Reshape_1" + input: "gradients_3/filter_type_all/Slice_6_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_21_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_27_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_27" + op: "Reshape" + input: "filter_type_all/Slice_6" + input: "filter_type_all/Reshape_27/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_21" + op: "Reshape" + input: "filter_type_all/Slice_6" + input: "filter_type_all/Reshape_21/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_7_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape_21" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Slice_7" + op: "Slice" + input: "filter_type_all/Reshape_21" + input: "filter_type_all/Slice_7/begin" + input: "filter_type_all/Slice_7/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_7_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_7_grad/sub" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_7_grad/Shape_1" + input: "gradients_3/filter_type_all/Slice_7_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_7_grad/sub_1" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_7_grad/sub" + input: "filter_type_all/Slice_7/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_7_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/Slice_7_grad/sub_1" + input: "gradients_3/filter_type_all/Slice_7_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_7_grad/concat" + op: "ConcatV2" + input: "gradients_3/filter_type_all/Slice_7_grad/Reshape" + input: "gradients_3/filter_type_all/Slice_7_grad/Reshape_1" + input: "gradients_3/filter_type_all/Slice_7_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_22_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_22" + op: "Reshape" + input: "filter_type_all/Slice_7" + input: "filter_type_all/Reshape_22/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_9_grad/ShapeN" + op: "ShapeN" + input: "filter_type_all/Reshape_22" + input: "filter_type_all/Reshape_22" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_9_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_3/filter_type_all/concat_9_grad/mod" + input: "gradients_3/filter_type_all/concat_9_grad/ShapeN" + input: "gradients_3/filter_type_all/concat_9_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_all/concat_9" + op: "ConcatV2" + input: "filter_type_all/Reshape_22" + input: "filter_type_all/Reshape_22" + input: "filter_type_all/concat_9/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_21_grad/Shape" + op: "Shape" + input: "filter_type_all/concat_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_12" + op: "MatMul" + input: "filter_type_all/Reshape_22" + input: "filter_type_all/matrix_1_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_20_grad/Shape" + op: "Shape" + input: "filter_type_all/MatMul_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_20_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_20_grad/Shape" + input: "gradients_3/filter_type_all/add_20_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_20" + op: "Add" + input: "filter_type_all/MatMul_12" + input: "filter_type_all/bias_1_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_9" + op: "Tanh" + input: "filter_type_all/add_20" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_23_grad/Shape" + op: "Shape" + input: "filter_type_all/Tanh_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_23" + op: "Reshape" + input: "filter_type_all/Tanh_9" + input: "filter_type_all/Reshape_23/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_21_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape_23" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_21_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_21_grad/Shape" + input: "gradients_3/filter_type_all/add_21_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_21" + op: "Add" + input: "filter_type_all/concat_9" + input: "filter_type_all/Reshape_23" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_10_grad/ShapeN" + op: "ShapeN" + input: "filter_type_all/add_21" + input: "filter_type_all/add_21" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_10_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_3/filter_type_all/concat_10_grad/mod" + input: "gradients_3/filter_type_all/concat_10_grad/ShapeN" + input: "gradients_3/filter_type_all/concat_10_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_all/concat_10" + op: "ConcatV2" + input: "filter_type_all/add_21" + input: "filter_type_all/add_21" + input: "filter_type_all/concat_10/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_23_grad/Shape" + op: "Shape" + input: "filter_type_all/concat_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_13" + op: "MatMul" + input: "filter_type_all/add_21" + input: "filter_type_all/matrix_2_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_22_grad/Shape" + op: "Shape" + input: "filter_type_all/MatMul_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_22_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_22_grad/Shape" + input: "gradients_3/filter_type_all/add_22_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_22" + op: "Add" + input: "filter_type_all/MatMul_13" + input: "filter_type_all/bias_2_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_10" + op: "Tanh" + input: "filter_type_all/add_22" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_24_grad/Shape" + op: "Shape" + input: "filter_type_all/Tanh_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_24" + op: "Reshape" + input: "filter_type_all/Tanh_10" + input: "filter_type_all/Reshape_24/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_23_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape_24" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_23_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_23_grad/Shape" + input: "gradients_3/filter_type_all/add_23_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_23" + op: "Add" + input: "filter_type_all/concat_10" + input: "filter_type_all/Reshape_24" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_11_grad/ShapeN" + op: "ShapeN" + input: "filter_type_all/add_23" + input: "filter_type_all/add_23" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_11_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_3/filter_type_all/concat_11_grad/mod" + input: "gradients_3/filter_type_all/concat_11_grad/ShapeN" + input: "gradients_3/filter_type_all/concat_11_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_all/concat_11" + op: "ConcatV2" + input: "filter_type_all/add_23" + input: "filter_type_all/add_23" + input: "filter_type_all/concat_11/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_25_grad/Shape" + op: "Shape" + input: "filter_type_all/concat_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_14" + op: "MatMul" + input: "filter_type_all/add_23" + input: "filter_type_all/matrix_3_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_24_grad/Shape" + op: "Shape" + input: "filter_type_all/MatMul_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_24_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_24_grad/Shape" + input: "gradients_3/filter_type_all/add_24_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_24" + op: "Add" + input: "filter_type_all/MatMul_14" + input: "filter_type_all/bias_3_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_11" + op: "Tanh" + input: "filter_type_all/add_24" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_25_grad/Shape" + op: "Shape" + input: "filter_type_all/Tanh_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_25" + op: "Reshape" + input: "filter_type_all/Tanh_11" + input: "filter_type_all/Reshape_25/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_25_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_25_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_25_grad/Shape" + input: "gradients_3/filter_type_all/add_25_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_25" + op: "Add" + input: "filter_type_all/concat_11" + input: "filter_type_all/Reshape_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_26_grad/Shape" + op: "Shape" + input: "filter_type_all/add_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_26" + op: "Reshape" + input: "filter_type_all/add_25" + input: "filter_type_all/Reshape_26/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_15" + op: "BatchMatMul" + input: "filter_type_all/Reshape_27" + input: "filter_type_all/Reshape_26" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_26_grad/Shape_1" + op: "Shape" + input: "filter_type_all/MatMul_15" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Slice_4" + op: "Slice" + input: "Reshape_22" + input: "filter_type_all/Slice_4/begin" + input: "filter_type_all/Slice_4/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_4_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_4_grad/sub" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_4_grad/Shape_1" + input: "gradients_3/filter_type_all/Slice_4_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_4_grad/sub_1" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_4_grad/sub" + input: "filter_type_all/Slice_4/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_4_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/Slice_4_grad/sub_1" + input: "gradients_3/filter_type_all/Slice_4_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_4_grad/concat" + op: "ConcatV2" + input: "gradients_3/filter_type_all/Slice_4_grad/Reshape" + input: "gradients_3/filter_type_all/Slice_4_grad/Reshape_1" + input: "gradients_3/filter_type_all/Slice_4_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_14_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_20_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_20" + op: "Reshape" + input: "filter_type_all/Slice_4" + input: "filter_type_all/Reshape_20/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_14" + op: "Reshape" + input: "filter_type_all/Slice_4" + input: "filter_type_all/Reshape_14/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_5_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Slice_5" + op: "Slice" + input: "filter_type_all/Reshape_14" + input: "filter_type_all/Slice_5/begin" + input: "filter_type_all/Slice_5/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_5_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_5_grad/sub" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_5_grad/Shape_1" + input: "gradients_3/filter_type_all/Slice_5_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_5_grad/sub_1" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_5_grad/sub" + input: "filter_type_all/Slice_5/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_5_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/Slice_5_grad/sub_1" + input: "gradients_3/filter_type_all/Slice_5_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_5_grad/concat" + op: "ConcatV2" + input: "gradients_3/filter_type_all/Slice_5_grad/Reshape" + input: "gradients_3/filter_type_all/Slice_5_grad/Reshape_1" + input: "gradients_3/filter_type_all/Slice_5_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_15_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_15" + op: "Reshape" + input: "filter_type_all/Slice_5" + input: "filter_type_all/Reshape_15/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_6_grad/ShapeN" + op: "ShapeN" + input: "filter_type_all/Reshape_15" + input: "filter_type_all/Reshape_15" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_6_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_3/filter_type_all/concat_6_grad/mod" + input: "gradients_3/filter_type_all/concat_6_grad/ShapeN" + input: "gradients_3/filter_type_all/concat_6_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_all/concat_6" + op: "ConcatV2" + input: "filter_type_all/Reshape_15" + input: "filter_type_all/Reshape_15" + input: "filter_type_all/concat_6/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_14_grad/Shape" + op: "Shape" + input: "filter_type_all/concat_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_8" + op: "MatMul" + input: "filter_type_all/Reshape_15" + input: "filter_type_all/matrix_1_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_13_grad/Shape" + op: "Shape" + input: "filter_type_all/MatMul_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_13_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_13_grad/Shape" + input: "gradients_3/filter_type_all/add_13_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_13" + op: "Add" + input: "filter_type_all/MatMul_8" + input: "filter_type_all/bias_1_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_6" + op: "Tanh" + input: "filter_type_all/add_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_16_grad/Shape" + op: "Shape" + input: "filter_type_all/Tanh_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_16" + op: "Reshape" + input: "filter_type_all/Tanh_6" + input: "filter_type_all/Reshape_16/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_14_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape_16" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_14_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_14_grad/Shape" + input: "gradients_3/filter_type_all/add_14_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_14" + op: "Add" + input: "filter_type_all/concat_6" + input: "filter_type_all/Reshape_16" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_7_grad/ShapeN" + op: "ShapeN" + input: "filter_type_all/add_14" + input: "filter_type_all/add_14" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_7_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_3/filter_type_all/concat_7_grad/mod" + input: "gradients_3/filter_type_all/concat_7_grad/ShapeN" + input: "gradients_3/filter_type_all/concat_7_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_all/concat_7" + op: "ConcatV2" + input: "filter_type_all/add_14" + input: "filter_type_all/add_14" + input: "filter_type_all/concat_7/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_16_grad/Shape" + op: "Shape" + input: "filter_type_all/concat_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_9" + op: "MatMul" + input: "filter_type_all/add_14" + input: "filter_type_all/matrix_2_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_15_grad/Shape" + op: "Shape" + input: "filter_type_all/MatMul_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_15_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_15_grad/Shape" + input: "gradients_3/filter_type_all/add_15_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_15" + op: "Add" + input: "filter_type_all/MatMul_9" + input: "filter_type_all/bias_2_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_7" + op: "Tanh" + input: "filter_type_all/add_15" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_17_grad/Shape" + op: "Shape" + input: "filter_type_all/Tanh_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_17" + op: "Reshape" + input: "filter_type_all/Tanh_7" + input: "filter_type_all/Reshape_17/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_16_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape_17" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_16_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_16_grad/Shape" + input: "gradients_3/filter_type_all/add_16_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_16" + op: "Add" + input: "filter_type_all/concat_7" + input: "filter_type_all/Reshape_17" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_8_grad/ShapeN" + op: "ShapeN" + input: "filter_type_all/add_16" + input: "filter_type_all/add_16" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_8_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_3/filter_type_all/concat_8_grad/mod" + input: "gradients_3/filter_type_all/concat_8_grad/ShapeN" + input: "gradients_3/filter_type_all/concat_8_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_all/concat_8" + op: "ConcatV2" + input: "filter_type_all/add_16" + input: "filter_type_all/add_16" + input: "filter_type_all/concat_8/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_18_grad/Shape" + op: "Shape" + input: "filter_type_all/concat_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_10" + op: "MatMul" + input: "filter_type_all/add_16" + input: "filter_type_all/matrix_3_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_17_grad/Shape" + op: "Shape" + input: "filter_type_all/MatMul_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_17_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_17_grad/Shape" + input: "gradients_3/filter_type_all/add_17_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_17" + op: "Add" + input: "filter_type_all/MatMul_10" + input: "filter_type_all/bias_3_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_8" + op: "Tanh" + input: "filter_type_all/add_17" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_18_grad/Shape" + op: "Shape" + input: "filter_type_all/Tanh_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_18" + op: "Reshape" + input: "filter_type_all/Tanh_8" + input: "filter_type_all/Reshape_18/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_18_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape_18" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_18_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_18_grad/Shape" + input: "gradients_3/filter_type_all/add_18_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_18" + op: "Add" + input: "filter_type_all/concat_8" + input: "filter_type_all/Reshape_18" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_19_grad/Shape" + op: "Shape" + input: "filter_type_all/add_18" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_19" + op: "Reshape" + input: "filter_type_all/add_18" + input: "filter_type_all/Reshape_19/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_11" + op: "BatchMatMul" + input: "filter_type_all/Reshape_20" + input: "filter_type_all/Reshape_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_19_grad/Shape_1" + op: "Shape" + input: "filter_type_all/MatMul_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Slice_2" + op: "Slice" + input: "Reshape_22" + input: "filter_type_all/Slice_2/begin" + input: "filter_type_all/Slice_2/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_2_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_2_grad/sub" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_2_grad/Shape_1" + input: "gradients_3/filter_type_all/Slice_2_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_2_grad/sub_1" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_2_grad/sub" + input: "filter_type_all/Slice_2/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_2_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/Slice_2_grad/sub_1" + input: "gradients_3/filter_type_all/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_2_grad/concat" + op: "ConcatV2" + input: "gradients_3/filter_type_all/Slice_2_grad/Reshape" + input: "gradients_3/filter_type_all/Slice_2_grad/Reshape_1" + input: "gradients_3/filter_type_all/Slice_2_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_7_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_13_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_13" + op: "Reshape" + input: "filter_type_all/Slice_2" + input: "filter_type_all/Reshape_13/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_7" + op: "Reshape" + input: "filter_type_all/Slice_2" + input: "filter_type_all/Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_3_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Slice_3" + op: "Slice" + input: "filter_type_all/Reshape_7" + input: "filter_type_all/Slice_3/begin" + input: "filter_type_all/Slice_3/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_3_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_3_grad/sub" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_3_grad/Shape_1" + input: "gradients_3/filter_type_all/Slice_3_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_3_grad/sub_1" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_3_grad/sub" + input: "filter_type_all/Slice_3/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_3_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/Slice_3_grad/sub_1" + input: "gradients_3/filter_type_all/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_3_grad/concat" + op: "ConcatV2" + input: "gradients_3/filter_type_all/Slice_3_grad/Reshape" + input: "gradients_3/filter_type_all/Slice_3_grad/Reshape_1" + input: "gradients_3/filter_type_all/Slice_3_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_8_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_8" + op: "Reshape" + input: "filter_type_all/Slice_3" + input: "filter_type_all/Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_3_grad/ShapeN" + op: "ShapeN" + input: "filter_type_all/Reshape_8" + input: "filter_type_all/Reshape_8" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_3_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_3/filter_type_all/concat_3_grad/mod" + input: "gradients_3/filter_type_all/concat_3_grad/ShapeN" + input: "gradients_3/filter_type_all/concat_3_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_all/concat_3" + op: "ConcatV2" + input: "filter_type_all/Reshape_8" + input: "filter_type_all/Reshape_8" + input: "filter_type_all/concat_3/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_7_grad/Shape" + op: "Shape" + input: "filter_type_all/concat_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_4" + op: "MatMul" + input: "filter_type_all/Reshape_8" + input: "filter_type_all/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_6_grad/Shape" + op: "Shape" + input: "filter_type_all/MatMul_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_6_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_6_grad/Shape" + input: "gradients_3/filter_type_all/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_6" + op: "Add" + input: "filter_type_all/MatMul_4" + input: "filter_type_all/bias_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_3" + op: "Tanh" + input: "filter_type_all/add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_9_grad/Shape" + op: "Shape" + input: "filter_type_all/Tanh_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_9" + op: "Reshape" + input: "filter_type_all/Tanh_3" + input: "filter_type_all/Reshape_9/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_7_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_7_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_7_grad/Shape" + input: "gradients_3/filter_type_all/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_7" + op: "Add" + input: "filter_type_all/concat_3" + input: "filter_type_all/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_4_grad/ShapeN" + op: "ShapeN" + input: "filter_type_all/add_7" + input: "filter_type_all/add_7" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_4_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_3/filter_type_all/concat_4_grad/mod" + input: "gradients_3/filter_type_all/concat_4_grad/ShapeN" + input: "gradients_3/filter_type_all/concat_4_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_all/concat_4" + op: "ConcatV2" + input: "filter_type_all/add_7" + input: "filter_type_all/add_7" + input: "filter_type_all/concat_4/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_9_grad/Shape" + op: "Shape" + input: "filter_type_all/concat_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_5" + op: "MatMul" + input: "filter_type_all/add_7" + input: "filter_type_all/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_8_grad/Shape" + op: "Shape" + input: "filter_type_all/MatMul_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_8_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_8_grad/Shape" + input: "gradients_3/filter_type_all/add_8_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_8" + op: "Add" + input: "filter_type_all/MatMul_5" + input: "filter_type_all/bias_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_4" + op: "Tanh" + input: "filter_type_all/add_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_10_grad/Shape" + op: "Shape" + input: "filter_type_all/Tanh_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_10" + op: "Reshape" + input: "filter_type_all/Tanh_4" + input: "filter_type_all/Reshape_10/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_9_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_9_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_9_grad/Shape" + input: "gradients_3/filter_type_all/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_9" + op: "Add" + input: "filter_type_all/concat_4" + input: "filter_type_all/Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_5_grad/ShapeN" + op: "ShapeN" + input: "filter_type_all/add_9" + input: "filter_type_all/add_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_5_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_3/filter_type_all/concat_5_grad/mod" + input: "gradients_3/filter_type_all/concat_5_grad/ShapeN" + input: "gradients_3/filter_type_all/concat_5_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_all/concat_5" + op: "ConcatV2" + input: "filter_type_all/add_9" + input: "filter_type_all/add_9" + input: "filter_type_all/concat_5/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_11_grad/Shape" + op: "Shape" + input: "filter_type_all/concat_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_6" + op: "MatMul" + input: "filter_type_all/add_9" + input: "filter_type_all/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_10_grad/Shape" + op: "Shape" + input: "filter_type_all/MatMul_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_10_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_10_grad/Shape" + input: "gradients_3/filter_type_all/add_10_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_10" + op: "Add" + input: "filter_type_all/MatMul_6" + input: "filter_type_all/bias_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_5" + op: "Tanh" + input: "filter_type_all/add_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_11_grad/Shape" + op: "Shape" + input: "filter_type_all/Tanh_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_11" + op: "Reshape" + input: "filter_type_all/Tanh_5" + input: "filter_type_all/Reshape_11/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_11_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_11_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_11_grad/Shape" + input: "gradients_3/filter_type_all/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_11" + op: "Add" + input: "filter_type_all/concat_5" + input: "filter_type_all/Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_12_grad/Shape" + op: "Shape" + input: "filter_type_all/add_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_12" + op: "Reshape" + input: "filter_type_all/add_11" + input: "filter_type_all/Reshape_12/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_7" + op: "BatchMatMul" + input: "filter_type_all/Reshape_13" + input: "filter_type_all/Reshape_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_12_grad/Shape_1" + op: "Shape" + input: "filter_type_all/MatMul_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Slice" + op: "Slice" + input: "Reshape_22" + input: "filter_type_all/Slice/begin" + input: "filter_type_all/Slice/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_grad/sub" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_grad/Shape_1" + input: "gradients_3/filter_type_all/Slice_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_grad/sub_1" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_grad/sub" + input: "filter_type_all/Slice/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/Slice_grad/sub_1" + input: "gradients_3/filter_type_all/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_grad/concat" + op: "ConcatV2" + input: "gradients_3/filter_type_all/Slice_grad/Reshape" + input: "gradients_3/filter_type_all/Slice_grad/Reshape_1" + input: "gradients_3/filter_type_all/Slice_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_6_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_6" + op: "Reshape" + input: "filter_type_all/Slice" + input: "filter_type_all/Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape" + op: "Reshape" + input: "filter_type_all/Slice" + input: "filter_type_all/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_1_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Slice_1" + op: "Slice" + input: "filter_type_all/Reshape" + input: "filter_type_all/Slice_1/begin" + input: "filter_type_all/Slice_1/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_1_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_1_grad/sub" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_1_grad/Shape_1" + input: "gradients_3/filter_type_all/Slice_1_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_1_grad/sub_1" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_1_grad/sub" + input: "filter_type_all/Slice_1/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_1_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/Slice_1_grad/sub_1" + input: "gradients_3/filter_type_all/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_1_grad/concat" + op: "ConcatV2" + input: "gradients_3/filter_type_all/Slice_1_grad/Reshape" + input: "gradients_3/filter_type_all/Slice_1_grad/Reshape_1" + input: "gradients_3/filter_type_all/Slice_1_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_1_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_1" + op: "Reshape" + input: "filter_type_all/Slice_1" + input: "filter_type_all/Reshape_1/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_grad/ShapeN" + op: "ShapeN" + input: "filter_type_all/Reshape_1" + input: "filter_type_all/Reshape_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_3/filter_type_all/concat_grad/mod" + input: "gradients_3/filter_type_all/concat_grad/ShapeN" + input: "gradients_3/filter_type_all/concat_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_all/concat" + op: "ConcatV2" + input: "filter_type_all/Reshape_1" + input: "filter_type_all/Reshape_1" + input: "filter_type_all/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_1_grad/Shape" + op: "Shape" + input: "filter_type_all/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul" + op: "MatMul" + input: "filter_type_all/Reshape_1" + input: "filter_type_all/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_grad/Shape" + op: "Shape" + input: "filter_type_all/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_grad/Shape" + input: "gradients_3/filter_type_all/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add" + op: "Add" + input: "filter_type_all/MatMul" + input: "filter_type_all/bias_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh" + op: "Tanh" + input: "filter_type_all/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_2_grad/Shape" + op: "Shape" + input: "filter_type_all/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_2" + op: "Reshape" + input: "filter_type_all/Tanh" + input: "filter_type_all/Reshape_2/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_1_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_1_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_1_grad/Shape" + input: "gradients_3/filter_type_all/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_1" + op: "Add" + input: "filter_type_all/concat" + input: "filter_type_all/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_1_grad/ShapeN" + op: "ShapeN" + input: "filter_type_all/add_1" + input: "filter_type_all/add_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_1_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_3/filter_type_all/concat_1_grad/mod" + input: "gradients_3/filter_type_all/concat_1_grad/ShapeN" + input: "gradients_3/filter_type_all/concat_1_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_all/concat_1" + op: "ConcatV2" + input: "filter_type_all/add_1" + input: "filter_type_all/add_1" + input: "filter_type_all/concat_1/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_3_grad/Shape" + op: "Shape" + input: "filter_type_all/concat_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_1" + op: "MatMul" + input: "filter_type_all/add_1" + input: "filter_type_all/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_2_grad/Shape" + op: "Shape" + input: "filter_type_all/MatMul_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_2_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_2_grad/Shape" + input: "gradients_3/filter_type_all/add_2_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_2" + op: "Add" + input: "filter_type_all/MatMul_1" + input: "filter_type_all/bias_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_1" + op: "Tanh" + input: "filter_type_all/add_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_3_grad/Shape" + op: "Shape" + input: "filter_type_all/Tanh_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_3" + op: "Reshape" + input: "filter_type_all/Tanh_1" + input: "filter_type_all/Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_3_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_3_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_3_grad/Shape" + input: "gradients_3/filter_type_all/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_3" + op: "Add" + input: "filter_type_all/concat_1" + input: "filter_type_all/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_2_grad/ShapeN" + op: "ShapeN" + input: "filter_type_all/add_3" + input: "filter_type_all/add_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_2_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_3/filter_type_all/concat_2_grad/mod" + input: "gradients_3/filter_type_all/concat_2_grad/ShapeN" + input: "gradients_3/filter_type_all/concat_2_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_all/concat_2" + op: "ConcatV2" + input: "filter_type_all/add_3" + input: "filter_type_all/add_3" + input: "filter_type_all/concat_2/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_5_grad/Shape" + op: "Shape" + input: "filter_type_all/concat_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_2" + op: "MatMul" + input: "filter_type_all/add_3" + input: "filter_type_all/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_4_grad/Shape" + op: "Shape" + input: "filter_type_all/MatMul_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_4_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_4_grad/Shape" + input: "gradients_3/filter_type_all/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_4" + op: "Add" + input: "filter_type_all/MatMul_2" + input: "filter_type_all/bias_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_all/Tanh_2" + op: "Tanh" + input: "filter_type_all/add_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_4_grad/Shape" + op: "Shape" + input: "filter_type_all/Tanh_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_4" + op: "Reshape" + input: "filter_type_all/Tanh_2" + input: "filter_type_all/Reshape_4/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_5_grad/Shape_1" + op: "Shape" + input: "filter_type_all/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_5_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_5_grad/Shape" + input: "gradients_3/filter_type_all/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_5" + op: "Add" + input: "filter_type_all/concat_2" + input: "filter_type_all/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_5_grad/Shape" + op: "Shape" + input: "filter_type_all/add_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_5" + op: "Reshape" + input: "filter_type_all/add_5" + input: "filter_type_all/Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_3" + op: "BatchMatMul" + input: "filter_type_all/Reshape_6" + input: "filter_type_all/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_12_grad/Shape" + op: "Shape" + input: "filter_type_all/MatMul_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_12_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_12_grad/Shape" + input: "gradients_3/filter_type_all/add_12_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_12" + op: "Add" + input: "filter_type_all/MatMul_3" + input: "filter_type_all/MatMul_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/add_19_grad/Shape" + op: "Shape" + input: "filter_type_all/add_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_19_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_19_grad/Shape" + input: "gradients_3/filter_type_all/add_19_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_19" + op: "Add" + input: "filter_type_all/add_12" + input: "filter_type_all/MatMul_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/add_26_grad/Shape" + op: "Shape" + input: "filter_type_all/add_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_26_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_26_grad/Shape" + input: "gradients_3/filter_type_all/add_26_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_26" + op: "Add" + input: "filter_type_all/add_19" + input: "filter_type_all/MatMul_15" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/add_33_grad/Shape" + op: "Shape" + input: "filter_type_all/add_26" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_33_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/add_33_grad/Shape" + input: "gradients_3/filter_type_all/add_33_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/add_33" + op: "Add" + input: "filter_type_all/add_26" + input: "filter_type_all/MatMul_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/mul_grad/Shape" + op: "Shape" + input: "filter_type_all/add_33" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/filter_type_all/mul_grad/Shape" + input: "gradients_3/filter_type_all/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/mul" + op: "Mul" + input: "filter_type_all/add_33" + input: "filter_type_all/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_10_grad/Shape_1" + op: "Shape" + input: "filter_type_all/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Slice_10" + op: "Slice" + input: "filter_type_all/mul" + input: "filter_type_all/Slice_10/begin" + input: "filter_type_all/Slice_10/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_10_grad/Shape" + op: "Shape" + input: "filter_type_all/Slice_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_10_grad/sub" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_10_grad/Shape_1" + input: "gradients_3/filter_type_all/Slice_10_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_10_grad/sub_1" + op: "Sub" + input: "gradients_3/filter_type_all/Slice_10_grad/sub" + input: "filter_type_all/Slice_10/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_10_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/Slice_10_grad/sub_1" + input: "gradients_3/filter_type_all/Slice_10_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_10_grad/concat" + op: "ConcatV2" + input: "gradients_3/filter_type_all/Slice_10_grad/Reshape" + input: "gradients_3/filter_type_all/Slice_10_grad/Reshape_1" + input: "gradients_3/filter_type_all/Slice_10_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/MatMul_20" + op: "BatchMatMul" + input: "filter_type_all/mul" + input: "filter_type_all/Slice_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_35_grad/Shape" + op: "Shape" + input: "filter_type_all/MatMul_20" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_all/Reshape_35" + op: "Reshape" + input: "filter_type_all/MatMul_20" + input: "filter_type_all/Reshape_35/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Reshape_23_grad/Shape" + op: "Shape" + input: "filter_type_all/Reshape_35" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_23" + op: "Reshape" + input: "filter_type_all/Reshape_35" + input: "Reshape_23/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "concat_6" + op: "Identity" + input: "Reshape_23" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "o_descriptor" + op: "Identity" + input: "concat_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/Reshape_25_grad/Shape" + op: "Shape" + input: "o_descriptor" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_25" + op: "Reshape" + input: "o_descriptor" + input: "Reshape_25/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_14_grad/Shape_1" + op: "Shape" + input: "Reshape_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_13_grad/Shape_1" + op: "Shape" + input: "Reshape_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_15_grad/Shape_1" + op: "Shape" + input: "Reshape_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_16_grad/Shape_1" + op: "Shape" + input: "Reshape_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_17_grad/Shape_1" + op: "Shape" + input: "Reshape_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_13" + op: "Shape" + input: "Reshape_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_74" + op: "StridedSlice" + input: "Shape_13" + input: "strided_slice_74/stack" + input: "strided_slice_74/stack_1" + input: "strided_slice_74/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_35/shape" + op: "Pack" + input: "strided_slice_74" + input: "strided_slice_75" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_17" + op: "Slice" + input: "Reshape_25" + input: "Slice_17/begin" + input: "Slice_17/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/Slice_17_grad/Shape" + op: "Shape" + input: "Slice_17" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_17_grad/sub" + op: "Sub" + input: "gradients_3/Slice_17_grad/Shape_1" + input: "gradients_3/Slice_17_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_17_grad/sub_1" + op: "Sub" + input: "gradients_3/Slice_17_grad/sub" + input: "Slice_17/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_17_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/Slice_17_grad/sub_1" + input: "gradients_3/Slice_17_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_17_grad/concat" + op: "ConcatV2" + input: "gradients_3/Slice_17_grad/Reshape" + input: "gradients_3/Slice_17_grad/Reshape_1" + input: "gradients_3/Slice_17_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Reshape_34_grad/Shape" + op: "Shape" + input: "Slice_17" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_34" + op: "Reshape" + input: "Slice_17" + input: "Reshape_34/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_4/MatMul" + op: "MatMul" + input: "Reshape_34" + input: "layer_0_type_4/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_0_type_4/add_grad/Shape" + op: "Shape" + input: "layer_0_type_4/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_0_type_4/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_0_type_4/add_grad/Shape" + input: "gradients_3/layer_0_type_4/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_4/add" + op: "Add" + input: "layer_0_type_4/MatMul" + input: "layer_0_type_4/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_0_type_4/Tanh" + op: "Tanh" + input: "layer_0_type_4/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_0_type_4/Reshape_grad/Shape" + op: "Shape" + input: "layer_0_type_4/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_4/Reshape" + op: "Reshape" + input: "layer_0_type_4/Tanh" + input: "layer_0_type_4/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/add_32_grad/Shape" + op: "Shape" + input: "layer_0_type_4/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_4/MatMul" + op: "MatMul" + input: "layer_0_type_4/Reshape" + input: "layer_1_type_4/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_1_type_4/add_grad/Shape" + op: "Shape" + input: "layer_1_type_4/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_4/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_1_type_4/add_grad/Shape" + input: "gradients_3/layer_1_type_4/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_4/add" + op: "Add" + input: "layer_1_type_4/MatMul" + input: "layer_1_type_4/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_1_type_4/Tanh" + op: "Tanh" + input: "layer_1_type_4/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_1_type_4/Reshape_grad/Shape" + op: "Shape" + input: "layer_1_type_4/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_4/Reshape" + op: "Reshape" + input: "layer_1_type_4/Tanh" + input: "layer_1_type_4/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_4/mul_grad/Shape" + op: "Shape" + input: "layer_1_type_4/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_4/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_1_type_4/mul_grad/Shape" + input: "gradients_3/layer_1_type_4/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_4/mul" + op: "Mul" + input: "layer_1_type_4/Reshape" + input: "layer_1_type_4/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/add_32_grad/Shape_1" + op: "Shape" + input: "layer_1_type_4/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/add_32_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/add_32_grad/Shape" + input: "gradients_3/add_32_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_32" + op: "Add" + input: "layer_0_type_4/Reshape" + input: "layer_1_type_4/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/add_33_grad/Shape" + op: "Shape" + input: "add_32" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_4/MatMul" + op: "MatMul" + input: "add_32" + input: "layer_2_type_4/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_2_type_4/add_grad/Shape" + op: "Shape" + input: "layer_2_type_4/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_4/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_2_type_4/add_grad/Shape" + input: "gradients_3/layer_2_type_4/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_4/add" + op: "Add" + input: "layer_2_type_4/MatMul" + input: "layer_2_type_4/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_4/Tanh" + op: "Tanh" + input: "layer_2_type_4/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_2_type_4/Reshape_grad/Shape" + op: "Shape" + input: "layer_2_type_4/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_4/Reshape" + op: "Reshape" + input: "layer_2_type_4/Tanh" + input: "layer_2_type_4/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_4/mul_grad/Shape" + op: "Shape" + input: "layer_2_type_4/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_4/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_2_type_4/mul_grad/Shape" + input: "gradients_3/layer_2_type_4/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_4/mul" + op: "Mul" + input: "layer_2_type_4/Reshape" + input: "layer_2_type_4/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/add_33_grad/Shape_1" + op: "Shape" + input: "layer_2_type_4/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/add_33_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/add_33_grad/Shape" + input: "gradients_3/add_33_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_33" + op: "Add" + input: "add_32" + input: "layer_2_type_4/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "final_layer_type_4/MatMul" + op: "MatMul" + input: "add_33" + input: "final_layer_type_4/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/final_layer_type_4/add_grad/Shape" + op: "Shape" + input: "final_layer_type_4/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/final_layer_type_4/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/final_layer_type_4/add_grad/Shape" + input: "gradients_3/final_layer_type_4/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "final_layer_type_4/add" + op: "Add" + input: "final_layer_type_4/MatMul" + input: "final_layer_type_4/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/Reshape_35_grad/Shape" + op: "Shape" + input: "final_layer_type_4/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_35" + op: "Reshape" + input: "final_layer_type_4/add" + input: "Reshape_35/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_12" + op: "Shape" + input: "Reshape_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_70" + op: "StridedSlice" + input: "Shape_12" + input: "strided_slice_70/stack" + input: "strided_slice_70/stack_1" + input: "strided_slice_70/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_33/shape" + op: "Pack" + input: "strided_slice_70" + input: "strided_slice_71" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_16" + op: "Slice" + input: "Reshape_25" + input: "Slice_16/begin" + input: "Slice_16/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/Slice_16_grad/Shape" + op: "Shape" + input: "Slice_16" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_16_grad/sub" + op: "Sub" + input: "gradients_3/Slice_16_grad/Shape_1" + input: "gradients_3/Slice_16_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_16_grad/sub_1" + op: "Sub" + input: "gradients_3/Slice_16_grad/sub" + input: "Slice_16/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_16_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/Slice_16_grad/sub_1" + input: "gradients_3/Slice_16_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_16_grad/concat" + op: "ConcatV2" + input: "gradients_3/Slice_16_grad/Reshape" + input: "gradients_3/Slice_16_grad/Reshape_1" + input: "gradients_3/Slice_16_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Reshape_32_grad/Shape" + op: "Shape" + input: "Slice_16" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_32" + op: "Reshape" + input: "Slice_16" + input: "Reshape_32/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_3/MatMul" + op: "MatMul" + input: "Reshape_32" + input: "layer_0_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_0_type_3/add_grad/Shape" + op: "Shape" + input: "layer_0_type_3/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_0_type_3/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_0_type_3/add_grad/Shape" + input: "gradients_3/layer_0_type_3/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_3/add" + op: "Add" + input: "layer_0_type_3/MatMul" + input: "layer_0_type_3/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_0_type_3/Tanh" + op: "Tanh" + input: "layer_0_type_3/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_0_type_3/Reshape_grad/Shape" + op: "Shape" + input: "layer_0_type_3/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_3/Reshape" + op: "Reshape" + input: "layer_0_type_3/Tanh" + input: "layer_0_type_3/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/add_29_grad/Shape" + op: "Shape" + input: "layer_0_type_3/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_3/MatMul" + op: "MatMul" + input: "layer_0_type_3/Reshape" + input: "layer_1_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_1_type_3/add_grad/Shape" + op: "Shape" + input: "layer_1_type_3/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_3/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_1_type_3/add_grad/Shape" + input: "gradients_3/layer_1_type_3/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_3/add" + op: "Add" + input: "layer_1_type_3/MatMul" + input: "layer_1_type_3/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_1_type_3/Tanh" + op: "Tanh" + input: "layer_1_type_3/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_1_type_3/Reshape_grad/Shape" + op: "Shape" + input: "layer_1_type_3/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_3/Reshape" + op: "Reshape" + input: "layer_1_type_3/Tanh" + input: "layer_1_type_3/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_3/mul_grad/Shape" + op: "Shape" + input: "layer_1_type_3/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_3/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_1_type_3/mul_grad/Shape" + input: "gradients_3/layer_1_type_3/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_3/mul" + op: "Mul" + input: "layer_1_type_3/Reshape" + input: "layer_1_type_3/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/add_29_grad/Shape_1" + op: "Shape" + input: "layer_1_type_3/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/add_29_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/add_29_grad/Shape" + input: "gradients_3/add_29_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_29" + op: "Add" + input: "layer_0_type_3/Reshape" + input: "layer_1_type_3/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/add_30_grad/Shape" + op: "Shape" + input: "add_29" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_3/MatMul" + op: "MatMul" + input: "add_29" + input: "layer_2_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_2_type_3/add_grad/Shape" + op: "Shape" + input: "layer_2_type_3/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_3/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_2_type_3/add_grad/Shape" + input: "gradients_3/layer_2_type_3/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_3/add" + op: "Add" + input: "layer_2_type_3/MatMul" + input: "layer_2_type_3/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_3/Tanh" + op: "Tanh" + input: "layer_2_type_3/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_2_type_3/Reshape_grad/Shape" + op: "Shape" + input: "layer_2_type_3/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_3/Reshape" + op: "Reshape" + input: "layer_2_type_3/Tanh" + input: "layer_2_type_3/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_3/mul_grad/Shape" + op: "Shape" + input: "layer_2_type_3/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_3/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_2_type_3/mul_grad/Shape" + input: "gradients_3/layer_2_type_3/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_3/mul" + op: "Mul" + input: "layer_2_type_3/Reshape" + input: "layer_2_type_3/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/add_30_grad/Shape_1" + op: "Shape" + input: "layer_2_type_3/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/add_30_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/add_30_grad/Shape" + input: "gradients_3/add_30_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_30" + op: "Add" + input: "add_29" + input: "layer_2_type_3/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "final_layer_type_3/MatMul" + op: "MatMul" + input: "add_30" + input: "final_layer_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/final_layer_type_3/add_grad/Shape" + op: "Shape" + input: "final_layer_type_3/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/final_layer_type_3/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/final_layer_type_3/add_grad/Shape" + input: "gradients_3/final_layer_type_3/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "final_layer_type_3/add" + op: "Add" + input: "final_layer_type_3/MatMul" + input: "final_layer_type_3/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/Reshape_33_grad/Shape" + op: "Shape" + input: "final_layer_type_3/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_33" + op: "Reshape" + input: "final_layer_type_3/add" + input: "Reshape_33/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_11" + op: "Shape" + input: "Reshape_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_66" + op: "StridedSlice" + input: "Shape_11" + input: "strided_slice_66/stack" + input: "strided_slice_66/stack_1" + input: "strided_slice_66/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_31/shape" + op: "Pack" + input: "strided_slice_66" + input: "strided_slice_67" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_15" + op: "Slice" + input: "Reshape_25" + input: "Slice_15/begin" + input: "Slice_15/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/Slice_15_grad/Shape" + op: "Shape" + input: "Slice_15" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_15_grad/sub" + op: "Sub" + input: "gradients_3/Slice_15_grad/Shape_1" + input: "gradients_3/Slice_15_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_15_grad/sub_1" + op: "Sub" + input: "gradients_3/Slice_15_grad/sub" + input: "Slice_15/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_15_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/Slice_15_grad/sub_1" + input: "gradients_3/Slice_15_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_15_grad/concat" + op: "ConcatV2" + input: "gradients_3/Slice_15_grad/Reshape" + input: "gradients_3/Slice_15_grad/Reshape_1" + input: "gradients_3/Slice_15_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Reshape_30_grad/Shape" + op: "Shape" + input: "Slice_15" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_30" + op: "Reshape" + input: "Slice_15" + input: "Reshape_30/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_2/MatMul" + op: "MatMul" + input: "Reshape_30" + input: "layer_0_type_2/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_0_type_2/add_grad/Shape" + op: "Shape" + input: "layer_0_type_2/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_0_type_2/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_0_type_2/add_grad/Shape" + input: "gradients_3/layer_0_type_2/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_2/add" + op: "Add" + input: "layer_0_type_2/MatMul" + input: "layer_0_type_2/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_0_type_2/Tanh" + op: "Tanh" + input: "layer_0_type_2/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_0_type_2/Reshape_grad/Shape" + op: "Shape" + input: "layer_0_type_2/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_2/Reshape" + op: "Reshape" + input: "layer_0_type_2/Tanh" + input: "layer_0_type_2/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/add_26_grad/Shape" + op: "Shape" + input: "layer_0_type_2/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_2/MatMul" + op: "MatMul" + input: "layer_0_type_2/Reshape" + input: "layer_1_type_2/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_1_type_2/add_grad/Shape" + op: "Shape" + input: "layer_1_type_2/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_2/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_1_type_2/add_grad/Shape" + input: "gradients_3/layer_1_type_2/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_2/add" + op: "Add" + input: "layer_1_type_2/MatMul" + input: "layer_1_type_2/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_1_type_2/Tanh" + op: "Tanh" + input: "layer_1_type_2/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_1_type_2/Reshape_grad/Shape" + op: "Shape" + input: "layer_1_type_2/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_2/Reshape" + op: "Reshape" + input: "layer_1_type_2/Tanh" + input: "layer_1_type_2/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_2/mul_grad/Shape" + op: "Shape" + input: "layer_1_type_2/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_2/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_1_type_2/mul_grad/Shape" + input: "gradients_3/layer_1_type_2/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_2/mul" + op: "Mul" + input: "layer_1_type_2/Reshape" + input: "layer_1_type_2/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/add_26_grad/Shape_1" + op: "Shape" + input: "layer_1_type_2/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/add_26_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/add_26_grad/Shape" + input: "gradients_3/add_26_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_26" + op: "Add" + input: "layer_0_type_2/Reshape" + input: "layer_1_type_2/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/add_27_grad/Shape" + op: "Shape" + input: "add_26" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_2/MatMul" + op: "MatMul" + input: "add_26" + input: "layer_2_type_2/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_2_type_2/add_grad/Shape" + op: "Shape" + input: "layer_2_type_2/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_2/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_2_type_2/add_grad/Shape" + input: "gradients_3/layer_2_type_2/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_2/add" + op: "Add" + input: "layer_2_type_2/MatMul" + input: "layer_2_type_2/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_2/Tanh" + op: "Tanh" + input: "layer_2_type_2/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_2_type_2/Reshape_grad/Shape" + op: "Shape" + input: "layer_2_type_2/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_2/Reshape" + op: "Reshape" + input: "layer_2_type_2/Tanh" + input: "layer_2_type_2/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_2/mul_grad/Shape" + op: "Shape" + input: "layer_2_type_2/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_2/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_2_type_2/mul_grad/Shape" + input: "gradients_3/layer_2_type_2/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_2/mul" + op: "Mul" + input: "layer_2_type_2/Reshape" + input: "layer_2_type_2/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/add_27_grad/Shape_1" + op: "Shape" + input: "layer_2_type_2/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/add_27_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/add_27_grad/Shape" + input: "gradients_3/add_27_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_27" + op: "Add" + input: "add_26" + input: "layer_2_type_2/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "final_layer_type_2/MatMul" + op: "MatMul" + input: "add_27" + input: "final_layer_type_2/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/final_layer_type_2/add_grad/Shape" + op: "Shape" + input: "final_layer_type_2/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/final_layer_type_2/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/final_layer_type_2/add_grad/Shape" + input: "gradients_3/final_layer_type_2/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "final_layer_type_2/add" + op: "Add" + input: "final_layer_type_2/MatMul" + input: "final_layer_type_2/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/Reshape_31_grad/Shape" + op: "Shape" + input: "final_layer_type_2/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_31" + op: "Reshape" + input: "final_layer_type_2/add" + input: "Reshape_31/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_10" + op: "Shape" + input: "Reshape_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_62" + op: "StridedSlice" + input: "Shape_10" + input: "strided_slice_62/stack" + input: "strided_slice_62/stack_1" + input: "strided_slice_62/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_29/shape" + op: "Pack" + input: "strided_slice_62" + input: "strided_slice_63" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_14" + op: "Slice" + input: "Reshape_25" + input: "Slice_14/begin" + input: "Slice_14/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/Slice_14_grad/Shape" + op: "Shape" + input: "Slice_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_14_grad/sub" + op: "Sub" + input: "gradients_3/Slice_14_grad/Shape_1" + input: "gradients_3/Slice_14_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_14_grad/sub_1" + op: "Sub" + input: "gradients_3/Slice_14_grad/sub" + input: "Slice_14/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_14_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/Slice_14_grad/sub_1" + input: "gradients_3/Slice_14_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_14_grad/concat" + op: "ConcatV2" + input: "gradients_3/Slice_14_grad/Reshape" + input: "gradients_3/Slice_14_grad/Reshape_1" + input: "gradients_3/Slice_14_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Reshape_28_grad/Shape" + op: "Shape" + input: "Slice_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_28" + op: "Reshape" + input: "Slice_14" + input: "Reshape_28/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_1/MatMul" + op: "MatMul" + input: "Reshape_28" + input: "layer_0_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_0_type_1/add_grad/Shape" + op: "Shape" + input: "layer_0_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_0_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_0_type_1/add_grad/Shape" + input: "gradients_3/layer_0_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_1/add" + op: "Add" + input: "layer_0_type_1/MatMul" + input: "layer_0_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_0_type_1/Tanh" + op: "Tanh" + input: "layer_0_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_0_type_1/Reshape_grad/Shape" + op: "Shape" + input: "layer_0_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_1/Reshape" + op: "Reshape" + input: "layer_0_type_1/Tanh" + input: "layer_0_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/add_23_grad/Shape" + op: "Shape" + input: "layer_0_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/MatMul" + op: "MatMul" + input: "layer_0_type_1/Reshape" + input: "layer_1_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_1_type_1/add_grad/Shape" + op: "Shape" + input: "layer_1_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_1_type_1/add_grad/Shape" + input: "gradients_3/layer_1_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/add" + op: "Add" + input: "layer_1_type_1/MatMul" + input: "layer_1_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_1_type_1/Tanh" + op: "Tanh" + input: "layer_1_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_1_type_1/Reshape_grad/Shape" + op: "Shape" + input: "layer_1_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/Reshape" + op: "Reshape" + input: "layer_1_type_1/Tanh" + input: "layer_1_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_1/mul_grad/Shape" + op: "Shape" + input: "layer_1_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_1_type_1/mul_grad/Shape" + input: "gradients_3/layer_1_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/mul" + op: "Mul" + input: "layer_1_type_1/Reshape" + input: "layer_1_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/add_23_grad/Shape_1" + op: "Shape" + input: "layer_1_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/add_23_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/add_23_grad/Shape" + input: "gradients_3/add_23_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_23" + op: "Add" + input: "layer_0_type_1/Reshape" + input: "layer_1_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/add_24_grad/Shape" + op: "Shape" + input: "add_23" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/MatMul" + op: "MatMul" + input: "add_23" + input: "layer_2_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_2_type_1/add_grad/Shape" + op: "Shape" + input: "layer_2_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_2_type_1/add_grad/Shape" + input: "gradients_3/layer_2_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/add" + op: "Add" + input: "layer_2_type_1/MatMul" + input: "layer_2_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_1/Tanh" + op: "Tanh" + input: "layer_2_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_2_type_1/Reshape_grad/Shape" + op: "Shape" + input: "layer_2_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/Reshape" + op: "Reshape" + input: "layer_2_type_1/Tanh" + input: "layer_2_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_1/mul_grad/Shape" + op: "Shape" + input: "layer_2_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_2_type_1/mul_grad/Shape" + input: "gradients_3/layer_2_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/mul" + op: "Mul" + input: "layer_2_type_1/Reshape" + input: "layer_2_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/add_24_grad/Shape_1" + op: "Shape" + input: "layer_2_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/add_24_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/add_24_grad/Shape" + input: "gradients_3/add_24_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_24" + op: "Add" + input: "add_23" + input: "layer_2_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "final_layer_type_1/MatMul" + op: "MatMul" + input: "add_24" + input: "final_layer_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/final_layer_type_1/add_grad/Shape" + op: "Shape" + input: "final_layer_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/final_layer_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/final_layer_type_1/add_grad/Shape" + input: "gradients_3/final_layer_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "final_layer_type_1/add" + op: "Add" + input: "final_layer_type_1/MatMul" + input: "final_layer_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/Reshape_29_grad/Shape" + op: "Shape" + input: "final_layer_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_29" + op: "Reshape" + input: "final_layer_type_1/add" + input: "Reshape_29/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_9" + op: "Shape" + input: "Reshape_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_58" + op: "StridedSlice" + input: "Shape_9" + input: "strided_slice_58/stack" + input: "strided_slice_58/stack_1" + input: "strided_slice_58/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_27/shape" + op: "Pack" + input: "strided_slice_58" + input: "strided_slice_59" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_13" + op: "Slice" + input: "Reshape_25" + input: "Slice_13/begin" + input: "Slice_13/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/Slice_13_grad/Shape" + op: "Shape" + input: "Slice_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_13_grad/sub" + op: "Sub" + input: "gradients_3/Slice_13_grad/Shape_1" + input: "gradients_3/Slice_13_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_13_grad/sub_1" + op: "Sub" + input: "gradients_3/Slice_13_grad/sub" + input: "Slice_13/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_13_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/Slice_13_grad/sub_1" + input: "gradients_3/Slice_13_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_13_grad/concat" + op: "ConcatV2" + input: "gradients_3/Slice_13_grad/Reshape" + input: "gradients_3/Slice_13_grad/Reshape_1" + input: "gradients_3/Slice_13_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Reshape_26_grad/Shape" + op: "Shape" + input: "Slice_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_26" + op: "Reshape" + input: "Slice_13" + input: "Reshape_26/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_0/MatMul" + op: "MatMul" + input: "Reshape_26" + input: "layer_0_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_0_type_0/add_grad/Shape" + op: "Shape" + input: "layer_0_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_0_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_0_type_0/add_grad/Shape" + input: "gradients_3/layer_0_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_0/add" + op: "Add" + input: "layer_0_type_0/MatMul" + input: "layer_0_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_0_type_0/Tanh" + op: "Tanh" + input: "layer_0_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_0_type_0/Reshape_grad/Shape" + op: "Shape" + input: "layer_0_type_0/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_0/Reshape" + op: "Reshape" + input: "layer_0_type_0/Tanh" + input: "layer_0_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/add_20_grad/Shape" + op: "Shape" + input: "layer_0_type_0/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/MatMul" + op: "MatMul" + input: "layer_0_type_0/Reshape" + input: "layer_1_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_1_type_0/add_grad/Shape" + op: "Shape" + input: "layer_1_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_1_type_0/add_grad/Shape" + input: "gradients_3/layer_1_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/add" + op: "Add" + input: "layer_1_type_0/MatMul" + input: "layer_1_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_1_type_0/Tanh" + op: "Tanh" + input: "layer_1_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_1_type_0/Reshape_grad/Shape" + op: "Shape" + input: "layer_1_type_0/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/Reshape" + op: "Reshape" + input: "layer_1_type_0/Tanh" + input: "layer_1_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_0/mul_grad/Shape" + op: "Shape" + input: "layer_1_type_0/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_0/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_1_type_0/mul_grad/Shape" + input: "gradients_3/layer_1_type_0/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/mul" + op: "Mul" + input: "layer_1_type_0/Reshape" + input: "layer_1_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/add_20_grad/Shape_1" + op: "Shape" + input: "layer_1_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/add_20_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/add_20_grad/Shape" + input: "gradients_3/add_20_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_20" + op: "Add" + input: "layer_0_type_0/Reshape" + input: "layer_1_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/add_21_grad/Shape" + op: "Shape" + input: "add_20" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/MatMul" + op: "MatMul" + input: "add_20" + input: "layer_2_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_2_type_0/add_grad/Shape" + op: "Shape" + input: "layer_2_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_2_type_0/add_grad/Shape" + input: "gradients_3/layer_2_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/add" + op: "Add" + input: "layer_2_type_0/MatMul" + input: "layer_2_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_0/Tanh" + op: "Tanh" + input: "layer_2_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_2_type_0/Reshape_grad/Shape" + op: "Shape" + input: "layer_2_type_0/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/Reshape" + op: "Reshape" + input: "layer_2_type_0/Tanh" + input: "layer_2_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_0/mul_grad/Shape" + op: "Shape" + input: "layer_2_type_0/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_0/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/layer_2_type_0/mul_grad/Shape" + input: "gradients_3/layer_2_type_0/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/mul" + op: "Mul" + input: "layer_2_type_0/Reshape" + input: "layer_2_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/add_21_grad/Shape_1" + op: "Shape" + input: "layer_2_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/add_21_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/add_21_grad/Shape" + input: "gradients_3/add_21_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_21" + op: "Add" + input: "add_20" + input: "layer_2_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "final_layer_type_0/MatMul" + op: "MatMul" + input: "add_21" + input: "final_layer_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_3/final_layer_type_0/add_grad/Shape" + op: "Shape" + input: "final_layer_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/final_layer_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_3/final_layer_type_0/add_grad/Shape" + input: "gradients_3/final_layer_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "final_layer_type_0/add" + op: "Add" + input: "final_layer_type_0/MatMul" + input: "final_layer_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/Reshape_27_grad/Shape" + op: "Shape" + input: "final_layer_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_27" + op: "Reshape" + input: "final_layer_type_0/add" + input: "Reshape_27/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/concat_8_grad/ShapeN" + op: "ShapeN" + input: "Reshape_27" + input: "Reshape_29" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/concat_8_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_3/concat_8_grad/mod" + input: "gradients_3/concat_8_grad/ShapeN" + input: "gradients_3/concat_8_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "concat_8" + op: "ConcatV2" + input: "Reshape_27" + input: "Reshape_29" + input: "concat_8/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/concat_9_grad/ShapeN" + op: "ShapeN" + input: "concat_8" + input: "Reshape_31" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/concat_9_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_3/concat_9_grad/mod" + input: "gradients_3/concat_9_grad/ShapeN" + input: "gradients_3/concat_9_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "concat_9" + op: "ConcatV2" + input: "concat_8" + input: "Reshape_31" + input: "concat_9/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/concat_10_grad/ShapeN" + op: "ShapeN" + input: "concat_9" + input: "Reshape_33" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/concat_10_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_3/concat_10_grad/mod" + input: "gradients_3/concat_10_grad/ShapeN" + input: "gradients_3/concat_10_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "concat_10" + op: "ConcatV2" + input: "concat_9" + input: "Reshape_33" + input: "concat_10/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/concat_11_grad/ShapeN" + op: "ShapeN" + input: "concat_10" + input: "Reshape_35" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/concat_11_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_3/concat_11_grad/mod" + input: "gradients_3/concat_11_grad/ShapeN" + input: "gradients_3/concat_11_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "concat_11" + op: "ConcatV2" + input: "concat_10" + input: "Reshape_35" + input: "concat_11/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Reshape_36_grad/Shape" + op: "Shape" + input: "concat_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_36" + op: "Reshape" + input: "concat_11" + input: "Reshape_36/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Shape" + op: "Shape" + input: "Reshape_36" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Fill" + op: "Fill" + input: "gradients_3/Shape" + input: "gradients_3/grad_ys_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "index_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Reshape_36_grad/Reshape" + op: "Reshape" + input: "gradients_3/Fill" + input: "gradients_3/Reshape_36_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/concat_11_grad/Slice_1" + op: "Slice" + input: "gradients_3/Reshape_36_grad/Reshape" + input: "gradients_3/concat_11_grad/ConcatOffset:1" + input: "gradients_3/concat_11_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/Reshape_35_grad/Reshape" + op: "Reshape" + input: "gradients_3/concat_11_grad/Slice_1" + input: "gradients_3/Reshape_35_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/final_layer_type_4/add_grad/Sum" + op: "Sum" + input: "gradients_3/Reshape_35_grad/Reshape" + input: "gradients_3/final_layer_type_4/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/final_layer_type_4/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/final_layer_type_4/add_grad/Sum" + input: "gradients_3/final_layer_type_4/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/final_layer_type_4/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/final_layer_type_4/add_grad/Reshape" + input: "final_layer_type_4/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/add_33_grad/Sum_1" + op: "Sum" + input: "gradients_3/final_layer_type_4/MatMul_grad/MatMul" + input: "gradients_3/add_33_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_33_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/add_33_grad/Sum_1" + input: "gradients_3/add_33_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_4/mul_grad/Mul" + op: "Mul" + input: "gradients_3/add_33_grad/Reshape_1" + input: "layer_2_type_4/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_2_type_4/mul_grad/Sum" + op: "Sum" + input: "gradients_3/layer_2_type_4/mul_grad/Mul" + input: "gradients_3/layer_2_type_4/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_2_type_4/mul_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_2_type_4/mul_grad/Sum" + input: "gradients_3/layer_2_type_4/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_4/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_2_type_4/mul_grad/Reshape" + input: "gradients_3/layer_2_type_4/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_4/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_2_type_4/Tanh" + input: "gradients_3/layer_2_type_4/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_2_type_4/add_grad/Sum" + op: "Sum" + input: "gradients_3/layer_2_type_4/Tanh_grad/TanhGrad" + input: "gradients_3/layer_2_type_4/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_2_type_4/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_2_type_4/add_grad/Sum" + input: "gradients_3/layer_2_type_4/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_4/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/layer_2_type_4/add_grad/Reshape" + input: "layer_2_type_4/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/add_33_grad/Sum" + op: "Sum" + input: "gradients_3/final_layer_type_4/MatMul_grad/MatMul" + input: "gradients_3/add_33_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_33_grad/Reshape" + op: "Reshape" + input: "gradients_3/add_33_grad/Sum" + input: "gradients_3/add_33_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/AddN" + op: "AddN" + input: "gradients_3/add_33_grad/Reshape" + input: "gradients_3/layer_2_type_4/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/add_33_grad/Reshape" + } + } + } +} +node { + name: "gradients_3/add_32_grad/Sum_1" + op: "Sum" + input: "gradients_3/AddN" + input: "gradients_3/add_32_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_32_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/add_32_grad/Sum_1" + input: "gradients_3/add_32_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_4/mul_grad/Mul" + op: "Mul" + input: "gradients_3/add_32_grad/Reshape_1" + input: "layer_1_type_4/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_1_type_4/mul_grad/Sum" + op: "Sum" + input: "gradients_3/layer_1_type_4/mul_grad/Mul" + input: "gradients_3/layer_1_type_4/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_1_type_4/mul_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_1_type_4/mul_grad/Sum" + input: "gradients_3/layer_1_type_4/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_4/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_1_type_4/mul_grad/Reshape" + input: "gradients_3/layer_1_type_4/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_4/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_1_type_4/Tanh" + input: "gradients_3/layer_1_type_4/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_1_type_4/add_grad/Sum" + op: "Sum" + input: "gradients_3/layer_1_type_4/Tanh_grad/TanhGrad" + input: "gradients_3/layer_1_type_4/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_1_type_4/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_1_type_4/add_grad/Sum" + input: "gradients_3/layer_1_type_4/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_4/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/layer_1_type_4/add_grad/Reshape" + input: "layer_1_type_4/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/add_32_grad/Sum" + op: "Sum" + input: "gradients_3/AddN" + input: "gradients_3/add_32_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_32_grad/Reshape" + op: "Reshape" + input: "gradients_3/add_32_grad/Sum" + input: "gradients_3/add_32_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/AddN_5" + op: "AddN" + input: "gradients_3/add_32_grad/Reshape" + input: "gradients_3/layer_1_type_4/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/add_32_grad/Reshape" + } + } + } +} +node { + name: "gradients_3/layer_0_type_4/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_3/AddN_5" + input: "gradients_3/layer_0_type_4/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_0_type_4/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_0_type_4/Tanh" + input: "gradients_3/layer_0_type_4/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_0_type_4/add_grad/Sum" + op: "Sum" + input: "gradients_3/layer_0_type_4/Tanh_grad/TanhGrad" + input: "gradients_3/layer_0_type_4/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_0_type_4/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_0_type_4/add_grad/Sum" + input: "gradients_3/layer_0_type_4/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_0_type_4/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/layer_0_type_4/add_grad/Reshape" + input: "layer_0_type_4/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/Reshape_34_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_0_type_4/MatMul_grad/MatMul" + input: "gradients_3/Reshape_34_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_17_grad/Pad" + op: "Pad" + input: "gradients_3/Reshape_34_grad/Reshape" + input: "gradients_3/Slice_17_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/concat_11_grad/Slice" + op: "Slice" + input: "gradients_3/Reshape_36_grad/Reshape" + input: "gradients_3/concat_11_grad/ConcatOffset" + input: "gradients_3/concat_11_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/concat_10_grad/Slice_1" + op: "Slice" + input: "gradients_3/concat_11_grad/Slice" + input: "gradients_3/concat_10_grad/ConcatOffset:1" + input: "gradients_3/concat_10_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/Reshape_33_grad/Reshape" + op: "Reshape" + input: "gradients_3/concat_10_grad/Slice_1" + input: "gradients_3/Reshape_33_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/final_layer_type_3/add_grad/Sum" + op: "Sum" + input: "gradients_3/Reshape_33_grad/Reshape" + input: "gradients_3/final_layer_type_3/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/final_layer_type_3/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/final_layer_type_3/add_grad/Sum" + input: "gradients_3/final_layer_type_3/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/final_layer_type_3/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/final_layer_type_3/add_grad/Reshape" + input: "final_layer_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/add_30_grad/Sum_1" + op: "Sum" + input: "gradients_3/final_layer_type_3/MatMul_grad/MatMul" + input: "gradients_3/add_30_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_30_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/add_30_grad/Sum_1" + input: "gradients_3/add_30_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_3/mul_grad/Mul" + op: "Mul" + input: "gradients_3/add_30_grad/Reshape_1" + input: "layer_2_type_3/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_2_type_3/mul_grad/Sum" + op: "Sum" + input: "gradients_3/layer_2_type_3/mul_grad/Mul" + input: "gradients_3/layer_2_type_3/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_2_type_3/mul_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_2_type_3/mul_grad/Sum" + input: "gradients_3/layer_2_type_3/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_3/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_2_type_3/mul_grad/Reshape" + input: "gradients_3/layer_2_type_3/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_3/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_2_type_3/Tanh" + input: "gradients_3/layer_2_type_3/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_2_type_3/add_grad/Sum" + op: "Sum" + input: "gradients_3/layer_2_type_3/Tanh_grad/TanhGrad" + input: "gradients_3/layer_2_type_3/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_2_type_3/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_2_type_3/add_grad/Sum" + input: "gradients_3/layer_2_type_3/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_3/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/layer_2_type_3/add_grad/Reshape" + input: "layer_2_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/add_30_grad/Sum" + op: "Sum" + input: "gradients_3/final_layer_type_3/MatMul_grad/MatMul" + input: "gradients_3/add_30_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_30_grad/Reshape" + op: "Reshape" + input: "gradients_3/add_30_grad/Sum" + input: "gradients_3/add_30_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/AddN_1" + op: "AddN" + input: "gradients_3/add_30_grad/Reshape" + input: "gradients_3/layer_2_type_3/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/add_30_grad/Reshape" + } + } + } +} +node { + name: "gradients_3/add_29_grad/Sum_1" + op: "Sum" + input: "gradients_3/AddN_1" + input: "gradients_3/add_29_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_29_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/add_29_grad/Sum_1" + input: "gradients_3/add_29_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_3/mul_grad/Mul" + op: "Mul" + input: "gradients_3/add_29_grad/Reshape_1" + input: "layer_1_type_3/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_1_type_3/mul_grad/Sum" + op: "Sum" + input: "gradients_3/layer_1_type_3/mul_grad/Mul" + input: "gradients_3/layer_1_type_3/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_1_type_3/mul_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_1_type_3/mul_grad/Sum" + input: "gradients_3/layer_1_type_3/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_3/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_1_type_3/mul_grad/Reshape" + input: "gradients_3/layer_1_type_3/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_3/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_1_type_3/Tanh" + input: "gradients_3/layer_1_type_3/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_1_type_3/add_grad/Sum" + op: "Sum" + input: "gradients_3/layer_1_type_3/Tanh_grad/TanhGrad" + input: "gradients_3/layer_1_type_3/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_1_type_3/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_1_type_3/add_grad/Sum" + input: "gradients_3/layer_1_type_3/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_3/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/layer_1_type_3/add_grad/Reshape" + input: "layer_1_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/add_29_grad/Sum" + op: "Sum" + input: "gradients_3/AddN_1" + input: "gradients_3/add_29_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_29_grad/Reshape" + op: "Reshape" + input: "gradients_3/add_29_grad/Sum" + input: "gradients_3/add_29_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/AddN_6" + op: "AddN" + input: "gradients_3/add_29_grad/Reshape" + input: "gradients_3/layer_1_type_3/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/add_29_grad/Reshape" + } + } + } +} +node { + name: "gradients_3/layer_0_type_3/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_3/AddN_6" + input: "gradients_3/layer_0_type_3/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_0_type_3/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_0_type_3/Tanh" + input: "gradients_3/layer_0_type_3/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_0_type_3/add_grad/Sum" + op: "Sum" + input: "gradients_3/layer_0_type_3/Tanh_grad/TanhGrad" + input: "gradients_3/layer_0_type_3/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_0_type_3/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_0_type_3/add_grad/Sum" + input: "gradients_3/layer_0_type_3/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_0_type_3/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/layer_0_type_3/add_grad/Reshape" + input: "layer_0_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/Reshape_32_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_0_type_3/MatMul_grad/MatMul" + input: "gradients_3/Reshape_32_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_16_grad/Pad" + op: "Pad" + input: "gradients_3/Reshape_32_grad/Reshape" + input: "gradients_3/Slice_16_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/concat_10_grad/Slice" + op: "Slice" + input: "gradients_3/concat_11_grad/Slice" + input: "gradients_3/concat_10_grad/ConcatOffset" + input: "gradients_3/concat_10_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/concat_9_grad/Slice_1" + op: "Slice" + input: "gradients_3/concat_10_grad/Slice" + input: "gradients_3/concat_9_grad/ConcatOffset:1" + input: "gradients_3/concat_9_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/Reshape_31_grad/Reshape" + op: "Reshape" + input: "gradients_3/concat_9_grad/Slice_1" + input: "gradients_3/Reshape_31_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/final_layer_type_2/add_grad/Sum" + op: "Sum" + input: "gradients_3/Reshape_31_grad/Reshape" + input: "gradients_3/final_layer_type_2/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/final_layer_type_2/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/final_layer_type_2/add_grad/Sum" + input: "gradients_3/final_layer_type_2/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/final_layer_type_2/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/final_layer_type_2/add_grad/Reshape" + input: "final_layer_type_2/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/add_27_grad/Sum_1" + op: "Sum" + input: "gradients_3/final_layer_type_2/MatMul_grad/MatMul" + input: "gradients_3/add_27_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_27_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/add_27_grad/Sum_1" + input: "gradients_3/add_27_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_2/mul_grad/Mul" + op: "Mul" + input: "gradients_3/add_27_grad/Reshape_1" + input: "layer_2_type_2/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_2_type_2/mul_grad/Sum" + op: "Sum" + input: "gradients_3/layer_2_type_2/mul_grad/Mul" + input: "gradients_3/layer_2_type_2/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_2_type_2/mul_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_2_type_2/mul_grad/Sum" + input: "gradients_3/layer_2_type_2/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_2/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_2_type_2/mul_grad/Reshape" + input: "gradients_3/layer_2_type_2/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_2/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_2_type_2/Tanh" + input: "gradients_3/layer_2_type_2/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_2_type_2/add_grad/Sum" + op: "Sum" + input: "gradients_3/layer_2_type_2/Tanh_grad/TanhGrad" + input: "gradients_3/layer_2_type_2/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_2_type_2/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_2_type_2/add_grad/Sum" + input: "gradients_3/layer_2_type_2/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_2/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/layer_2_type_2/add_grad/Reshape" + input: "layer_2_type_2/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/add_27_grad/Sum" + op: "Sum" + input: "gradients_3/final_layer_type_2/MatMul_grad/MatMul" + input: "gradients_3/add_27_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_27_grad/Reshape" + op: "Reshape" + input: "gradients_3/add_27_grad/Sum" + input: "gradients_3/add_27_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/AddN_2" + op: "AddN" + input: "gradients_3/add_27_grad/Reshape" + input: "gradients_3/layer_2_type_2/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/add_27_grad/Reshape" + } + } + } +} +node { + name: "gradients_3/add_26_grad/Sum_1" + op: "Sum" + input: "gradients_3/AddN_2" + input: "gradients_3/add_26_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_26_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/add_26_grad/Sum_1" + input: "gradients_3/add_26_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_2/mul_grad/Mul" + op: "Mul" + input: "gradients_3/add_26_grad/Reshape_1" + input: "layer_1_type_2/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_1_type_2/mul_grad/Sum" + op: "Sum" + input: "gradients_3/layer_1_type_2/mul_grad/Mul" + input: "gradients_3/layer_1_type_2/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_1_type_2/mul_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_1_type_2/mul_grad/Sum" + input: "gradients_3/layer_1_type_2/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_2/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_1_type_2/mul_grad/Reshape" + input: "gradients_3/layer_1_type_2/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_2/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_1_type_2/Tanh" + input: "gradients_3/layer_1_type_2/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_1_type_2/add_grad/Sum" + op: "Sum" + input: "gradients_3/layer_1_type_2/Tanh_grad/TanhGrad" + input: "gradients_3/layer_1_type_2/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_1_type_2/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_1_type_2/add_grad/Sum" + input: "gradients_3/layer_1_type_2/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_2/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/layer_1_type_2/add_grad/Reshape" + input: "layer_1_type_2/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/add_26_grad/Sum" + op: "Sum" + input: "gradients_3/AddN_2" + input: "gradients_3/add_26_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_26_grad/Reshape" + op: "Reshape" + input: "gradients_3/add_26_grad/Sum" + input: "gradients_3/add_26_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/AddN_7" + op: "AddN" + input: "gradients_3/add_26_grad/Reshape" + input: "gradients_3/layer_1_type_2/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/add_26_grad/Reshape" + } + } + } +} +node { + name: "gradients_3/layer_0_type_2/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_3/AddN_7" + input: "gradients_3/layer_0_type_2/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_0_type_2/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_0_type_2/Tanh" + input: "gradients_3/layer_0_type_2/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_0_type_2/add_grad/Sum" + op: "Sum" + input: "gradients_3/layer_0_type_2/Tanh_grad/TanhGrad" + input: "gradients_3/layer_0_type_2/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_0_type_2/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_0_type_2/add_grad/Sum" + input: "gradients_3/layer_0_type_2/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_0_type_2/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/layer_0_type_2/add_grad/Reshape" + input: "layer_0_type_2/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/Reshape_30_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_0_type_2/MatMul_grad/MatMul" + input: "gradients_3/Reshape_30_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_15_grad/Pad" + op: "Pad" + input: "gradients_3/Reshape_30_grad/Reshape" + input: "gradients_3/Slice_15_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/concat_9_grad/Slice" + op: "Slice" + input: "gradients_3/concat_10_grad/Slice" + input: "gradients_3/concat_9_grad/ConcatOffset" + input: "gradients_3/concat_9_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/concat_8_grad/Slice_1" + op: "Slice" + input: "gradients_3/concat_9_grad/Slice" + input: "gradients_3/concat_8_grad/ConcatOffset:1" + input: "gradients_3/concat_8_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/Reshape_29_grad/Reshape" + op: "Reshape" + input: "gradients_3/concat_8_grad/Slice_1" + input: "gradients_3/Reshape_29_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/final_layer_type_1/add_grad/Sum" + op: "Sum" + input: "gradients_3/Reshape_29_grad/Reshape" + input: "gradients_3/final_layer_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/final_layer_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/final_layer_type_1/add_grad/Sum" + input: "gradients_3/final_layer_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/final_layer_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/final_layer_type_1/add_grad/Reshape" + input: "final_layer_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/add_24_grad/Sum_1" + op: "Sum" + input: "gradients_3/final_layer_type_1/MatMul_grad/MatMul" + input: "gradients_3/add_24_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_24_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/add_24_grad/Sum_1" + input: "gradients_3/add_24_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients_3/add_24_grad/Reshape_1" + input: "layer_2_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_2_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients_3/layer_2_type_1/mul_grad/Mul" + input: "gradients_3/layer_2_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_2_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_2_type_1/mul_grad/Sum" + input: "gradients_3/layer_2_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_2_type_1/mul_grad/Reshape" + input: "gradients_3/layer_2_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_2_type_1/Tanh" + input: "gradients_3/layer_2_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_2_type_1/add_grad/Sum" + op: "Sum" + input: "gradients_3/layer_2_type_1/Tanh_grad/TanhGrad" + input: "gradients_3/layer_2_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_2_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_2_type_1/add_grad/Sum" + input: "gradients_3/layer_2_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/layer_2_type_1/add_grad/Reshape" + input: "layer_2_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/add_24_grad/Sum" + op: "Sum" + input: "gradients_3/final_layer_type_1/MatMul_grad/MatMul" + input: "gradients_3/add_24_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_24_grad/Reshape" + op: "Reshape" + input: "gradients_3/add_24_grad/Sum" + input: "gradients_3/add_24_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/AddN_4" + op: "AddN" + input: "gradients_3/add_24_grad/Reshape" + input: "gradients_3/layer_2_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/add_24_grad/Reshape" + } + } + } +} +node { + name: "gradients_3/add_23_grad/Sum_1" + op: "Sum" + input: "gradients_3/AddN_4" + input: "gradients_3/add_23_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_23_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/add_23_grad/Sum_1" + input: "gradients_3/add_23_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients_3/add_23_grad/Reshape_1" + input: "layer_1_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_1_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients_3/layer_1_type_1/mul_grad/Mul" + input: "gradients_3/layer_1_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_1_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_1_type_1/mul_grad/Sum" + input: "gradients_3/layer_1_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_1_type_1/mul_grad/Reshape" + input: "gradients_3/layer_1_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_1_type_1/Tanh" + input: "gradients_3/layer_1_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_1_type_1/add_grad/Sum" + op: "Sum" + input: "gradients_3/layer_1_type_1/Tanh_grad/TanhGrad" + input: "gradients_3/layer_1_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_1_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_1_type_1/add_grad/Sum" + input: "gradients_3/layer_1_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/layer_1_type_1/add_grad/Reshape" + input: "layer_1_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/add_23_grad/Sum" + op: "Sum" + input: "gradients_3/AddN_4" + input: "gradients_3/add_23_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_23_grad/Reshape" + op: "Reshape" + input: "gradients_3/add_23_grad/Sum" + input: "gradients_3/add_23_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/AddN_9" + op: "AddN" + input: "gradients_3/add_23_grad/Reshape" + input: "gradients_3/layer_1_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/add_23_grad/Reshape" + } + } + } +} +node { + name: "gradients_3/layer_0_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_3/AddN_9" + input: "gradients_3/layer_0_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_0_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_0_type_1/Tanh" + input: "gradients_3/layer_0_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_0_type_1/add_grad/Sum" + op: "Sum" + input: "gradients_3/layer_0_type_1/Tanh_grad/TanhGrad" + input: "gradients_3/layer_0_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_0_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_0_type_1/add_grad/Sum" + input: "gradients_3/layer_0_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_0_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/layer_0_type_1/add_grad/Reshape" + input: "layer_0_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/Reshape_28_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_0_type_1/MatMul_grad/MatMul" + input: "gradients_3/Reshape_28_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_14_grad/Pad" + op: "Pad" + input: "gradients_3/Reshape_28_grad/Reshape" + input: "gradients_3/Slice_14_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/concat_8_grad/Slice" + op: "Slice" + input: "gradients_3/concat_9_grad/Slice" + input: "gradients_3/concat_8_grad/ConcatOffset" + input: "gradients_3/concat_8_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/Reshape_27_grad/Reshape" + op: "Reshape" + input: "gradients_3/concat_8_grad/Slice" + input: "gradients_3/Reshape_27_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/final_layer_type_0/add_grad/Sum" + op: "Sum" + input: "gradients_3/Reshape_27_grad/Reshape" + input: "gradients_3/final_layer_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/final_layer_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/final_layer_type_0/add_grad/Sum" + input: "gradients_3/final_layer_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/final_layer_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/final_layer_type_0/add_grad/Reshape" + input: "final_layer_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/add_21_grad/Sum_1" + op: "Sum" + input: "gradients_3/final_layer_type_0/MatMul_grad/MatMul" + input: "gradients_3/add_21_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_21_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/add_21_grad/Sum_1" + input: "gradients_3/add_21_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_0/mul_grad/Mul" + op: "Mul" + input: "gradients_3/add_21_grad/Reshape_1" + input: "layer_2_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_2_type_0/mul_grad/Sum" + op: "Sum" + input: "gradients_3/layer_2_type_0/mul_grad/Mul" + input: "gradients_3/layer_2_type_0/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_2_type_0/mul_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_2_type_0/mul_grad/Sum" + input: "gradients_3/layer_2_type_0/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_0/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_2_type_0/mul_grad/Reshape" + input: "gradients_3/layer_2_type_0/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_0/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_2_type_0/Tanh" + input: "gradients_3/layer_2_type_0/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_2_type_0/add_grad/Sum" + op: "Sum" + input: "gradients_3/layer_2_type_0/Tanh_grad/TanhGrad" + input: "gradients_3/layer_2_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_2_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_2_type_0/add_grad/Sum" + input: "gradients_3/layer_2_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_2_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/layer_2_type_0/add_grad/Reshape" + input: "layer_2_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/add_21_grad/Sum" + op: "Sum" + input: "gradients_3/final_layer_type_0/MatMul_grad/MatMul" + input: "gradients_3/add_21_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_21_grad/Reshape" + op: "Reshape" + input: "gradients_3/add_21_grad/Sum" + input: "gradients_3/add_21_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/AddN_3" + op: "AddN" + input: "gradients_3/add_21_grad/Reshape" + input: "gradients_3/layer_2_type_0/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/add_21_grad/Reshape" + } + } + } +} +node { + name: "gradients_3/add_20_grad/Sum_1" + op: "Sum" + input: "gradients_3/AddN_3" + input: "gradients_3/add_20_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_20_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/add_20_grad/Sum_1" + input: "gradients_3/add_20_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_0/mul_grad/Mul" + op: "Mul" + input: "gradients_3/add_20_grad/Reshape_1" + input: "layer_1_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_1_type_0/mul_grad/Sum" + op: "Sum" + input: "gradients_3/layer_1_type_0/mul_grad/Mul" + input: "gradients_3/layer_1_type_0/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_1_type_0/mul_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_1_type_0/mul_grad/Sum" + input: "gradients_3/layer_1_type_0/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_0/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_1_type_0/mul_grad/Reshape" + input: "gradients_3/layer_1_type_0/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_0/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_1_type_0/Tanh" + input: "gradients_3/layer_1_type_0/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_1_type_0/add_grad/Sum" + op: "Sum" + input: "gradients_3/layer_1_type_0/Tanh_grad/TanhGrad" + input: "gradients_3/layer_1_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_1_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_1_type_0/add_grad/Sum" + input: "gradients_3/layer_1_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_1_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/layer_1_type_0/add_grad/Reshape" + input: "layer_1_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/add_20_grad/Sum" + op: "Sum" + input: "gradients_3/AddN_3" + input: "gradients_3/add_20_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/add_20_grad/Reshape" + op: "Reshape" + input: "gradients_3/add_20_grad/Sum" + input: "gradients_3/add_20_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/AddN_8" + op: "AddN" + input: "gradients_3/add_20_grad/Reshape" + input: "gradients_3/layer_1_type_0/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/add_20_grad/Reshape" + } + } + } +} +node { + name: "gradients_3/layer_0_type_0/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_3/AddN_8" + input: "gradients_3/layer_0_type_0/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_0_type_0/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_0_type_0/Tanh" + input: "gradients_3/layer_0_type_0/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/layer_0_type_0/add_grad/Sum" + op: "Sum" + input: "gradients_3/layer_0_type_0/Tanh_grad/TanhGrad" + input: "gradients_3/layer_0_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/layer_0_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_0_type_0/add_grad/Sum" + input: "gradients_3/layer_0_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/layer_0_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/layer_0_type_0/add_grad/Reshape" + input: "layer_0_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/Reshape_26_grad/Reshape" + op: "Reshape" + input: "gradients_3/layer_0_type_0/MatMul_grad/MatMul" + input: "gradients_3/Reshape_26_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Slice_13_grad/Pad" + op: "Pad" + input: "gradients_3/Reshape_26_grad/Reshape" + input: "gradients_3/Slice_13_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/AddN_10" + op: "AddN" + input: "gradients_3/Slice_17_grad/Pad" + input: "gradients_3/Slice_16_grad/Pad" + input: "gradients_3/Slice_15_grad/Pad" + input: "gradients_3/Slice_13_grad/Pad" + input: "gradients_3/Slice_14_grad/Pad" + attr { + key: "N" + value { + i: 5 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/Slice_17_grad/Pad" + } + } + } +} +node { + name: "gradients_3/Reshape_25_grad/Reshape" + op: "Reshape" + input: "gradients_3/AddN_10" + input: "gradients_3/Reshape_25_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Reshape_23_grad/Reshape" + op: "Reshape" + input: "gradients_3/Reshape_25_grad/Reshape" + input: "gradients_3/Reshape_23_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_35_grad/Reshape" + op: "Reshape" + input: "gradients_3/Reshape_23_grad/Reshape" + input: "gradients_3/filter_type_all/Reshape_35_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_20_grad/MatMul_1" + op: "BatchMatMul" + input: "filter_type_all/mul" + input: "gradients_3/filter_type_all/Reshape_35_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_10_grad/Pad" + op: "Pad" + input: "gradients_3/filter_type_all/MatMul_20_grad/MatMul_1" + input: "gradients_3/filter_type_all/Slice_10_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_20_grad/MatMul" + op: "BatchMatMul" + input: "filter_type_all/Slice_10" + input: "gradients_3/filter_type_all/Reshape_35_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_3/AddN_11" + op: "AddN" + input: "gradients_3/filter_type_all/MatMul_20_grad/MatMul" + input: "gradients_3/filter_type_all/Slice_10_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/MatMul_20_grad/MatMul" + } + } + } +} +node { + name: "gradients_3/filter_type_all/mul_grad/Mul" + op: "Mul" + input: "gradients_3/AddN_11" + input: "filter_type_all/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/mul_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/mul_grad/Mul" + input: "gradients_3/filter_type_all/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/mul_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/mul_grad/Sum" + input: "gradients_3/filter_type_all/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_33_grad/Sum_1" + op: "Sum" + input: "gradients_3/filter_type_all/mul_grad/Reshape" + input: "gradients_3/filter_type_all/add_33_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_33_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/add_33_grad/Sum_1" + input: "gradients_3/filter_type_all/add_33_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_19_grad/MatMul_1" + op: "BatchMatMul" + input: "filter_type_all/Reshape_34" + input: "gradients_3/filter_type_all/add_33_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_33_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/MatMul_19_grad/MatMul_1" + input: "gradients_3/filter_type_all/Reshape_33_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_32_grad/Sum_1" + op: "Sum" + input: "gradients_3/filter_type_all/Reshape_33_grad/Reshape" + input: "gradients_3/filter_type_all/add_32_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_32_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/add_32_grad/Sum_1" + input: "gradients_3/filter_type_all/add_32_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_32_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_32_grad/Reshape_1" + input: "gradients_3/filter_type_all/Reshape_32_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Tanh_14_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_all/Tanh_14" + input: "gradients_3/filter_type_all/Reshape_32_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/add_31_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Tanh_14_grad/TanhGrad" + input: "gradients_3/filter_type_all/add_31_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_31_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_31_grad/Sum" + input: "gradients_3/filter_type_all/add_31_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_18_grad/MatMul" + op: "MatMul" + input: "gradients_3/filter_type_all/add_31_grad/Reshape" + input: "filter_type_all/matrix_3_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/add_32_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Reshape_33_grad/Reshape" + input: "gradients_3/filter_type_all/add_32_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_32_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_32_grad/Sum" + input: "gradients_3/filter_type_all/add_32_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_14_grad/Slice_1" + op: "Slice" + input: "gradients_3/filter_type_all/add_32_grad/Reshape" + input: "gradients_3/filter_type_all/concat_14_grad/ConcatOffset:1" + input: "gradients_3/filter_type_all/concat_14_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_14_grad/Slice" + op: "Slice" + input: "gradients_3/filter_type_all/add_32_grad/Reshape" + input: "gradients_3/filter_type_all/concat_14_grad/ConcatOffset" + input: "gradients_3/filter_type_all/concat_14_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/AddN_12" + op: "AddN" + input: "gradients_3/filter_type_all/concat_14_grad/Slice" + input: "gradients_3/filter_type_all/concat_14_grad/Slice_1" + input: "gradients_3/filter_type_all/MatMul_18_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/concat_14_grad/Slice" + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_30_grad/Sum_1" + op: "Sum" + input: "gradients_3/AddN_12" + input: "gradients_3/filter_type_all/add_30_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_30_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/add_30_grad/Sum_1" + input: "gradients_3/filter_type_all/add_30_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_31_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_30_grad/Reshape_1" + input: "gradients_3/filter_type_all/Reshape_31_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Tanh_13_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_all/Tanh_13" + input: "gradients_3/filter_type_all/Reshape_31_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/add_29_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Tanh_13_grad/TanhGrad" + input: "gradients_3/filter_type_all/add_29_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_29_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_29_grad/Sum" + input: "gradients_3/filter_type_all/add_29_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_17_grad/MatMul" + op: "MatMul" + input: "gradients_3/filter_type_all/add_29_grad/Reshape" + input: "filter_type_all/matrix_2_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/add_30_grad/Sum" + op: "Sum" + input: "gradients_3/AddN_12" + input: "gradients_3/filter_type_all/add_30_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_30_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_30_grad/Sum" + input: "gradients_3/filter_type_all/add_30_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_13_grad/Slice_1" + op: "Slice" + input: "gradients_3/filter_type_all/add_30_grad/Reshape" + input: "gradients_3/filter_type_all/concat_13_grad/ConcatOffset:1" + input: "gradients_3/filter_type_all/concat_13_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_13_grad/Slice" + op: "Slice" + input: "gradients_3/filter_type_all/add_30_grad/Reshape" + input: "gradients_3/filter_type_all/concat_13_grad/ConcatOffset" + input: "gradients_3/filter_type_all/concat_13_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/AddN_17" + op: "AddN" + input: "gradients_3/filter_type_all/concat_13_grad/Slice" + input: "gradients_3/filter_type_all/concat_13_grad/Slice_1" + input: "gradients_3/filter_type_all/MatMul_17_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/concat_13_grad/Slice" + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_28_grad/Sum_1" + op: "Sum" + input: "gradients_3/AddN_17" + input: "gradients_3/filter_type_all/add_28_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_28_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/add_28_grad/Sum_1" + input: "gradients_3/filter_type_all/add_28_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_30_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_28_grad/Reshape_1" + input: "gradients_3/filter_type_all/Reshape_30_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Tanh_12_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_all/Tanh_12" + input: "gradients_3/filter_type_all/Reshape_30_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/add_27_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Tanh_12_grad/TanhGrad" + input: "gradients_3/filter_type_all/add_27_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_27_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_27_grad/Sum" + input: "gradients_3/filter_type_all/add_27_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_16_grad/MatMul" + op: "MatMul" + input: "gradients_3/filter_type_all/add_27_grad/Reshape" + input: "filter_type_all/matrix_1_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/add_28_grad/Sum" + op: "Sum" + input: "gradients_3/AddN_17" + input: "gradients_3/filter_type_all/add_28_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_28_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_28_grad/Sum" + input: "gradients_3/filter_type_all/add_28_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_12_grad/Slice_1" + op: "Slice" + input: "gradients_3/filter_type_all/add_28_grad/Reshape" + input: "gradients_3/filter_type_all/concat_12_grad/ConcatOffset:1" + input: "gradients_3/filter_type_all/concat_12_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_12_grad/Slice" + op: "Slice" + input: "gradients_3/filter_type_all/add_28_grad/Reshape" + input: "gradients_3/filter_type_all/concat_12_grad/ConcatOffset" + input: "gradients_3/filter_type_all/concat_12_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/AddN_22" + op: "AddN" + input: "gradients_3/filter_type_all/concat_12_grad/Slice" + input: "gradients_3/filter_type_all/concat_12_grad/Slice_1" + input: "gradients_3/filter_type_all/MatMul_16_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/concat_12_grad/Slice" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_29_grad/Reshape" + op: "Reshape" + input: "gradients_3/AddN_22" + input: "gradients_3/filter_type_all/Reshape_29_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_9_grad/Pad" + op: "Pad" + input: "gradients_3/filter_type_all/Reshape_29_grad/Reshape" + input: "gradients_3/filter_type_all/Slice_9_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_28_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/Slice_9_grad/Pad" + input: "gradients_3/filter_type_all/Reshape_28_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_19_grad/MatMul" + op: "BatchMatMul" + input: "filter_type_all/Reshape_33" + input: "gradients_3/filter_type_all/add_33_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_34_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/MatMul_19_grad/MatMul" + input: "gradients_3/filter_type_all/Reshape_34_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/AddN_27" + op: "AddN" + input: "gradients_3/filter_type_all/Reshape_34_grad/Reshape" + input: "gradients_3/filter_type_all/Reshape_28_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/Reshape_34_grad/Reshape" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_8_grad/Pad" + op: "Pad" + input: "gradients_3/AddN_27" + input: "gradients_3/filter_type_all/Slice_8_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_33_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/mul_grad/Reshape" + input: "gradients_3/filter_type_all/add_33_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_33_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_33_grad/Sum" + input: "gradients_3/filter_type_all/add_33_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_26_grad/Sum_1" + op: "Sum" + input: "gradients_3/filter_type_all/add_33_grad/Reshape" + input: "gradients_3/filter_type_all/add_26_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_26_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/add_26_grad/Sum_1" + input: "gradients_3/filter_type_all/add_26_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_15_grad/MatMul_1" + op: "BatchMatMul" + input: "filter_type_all/Reshape_27" + input: "gradients_3/filter_type_all/add_26_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_26_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/MatMul_15_grad/MatMul_1" + input: "gradients_3/filter_type_all/Reshape_26_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_25_grad/Sum_1" + op: "Sum" + input: "gradients_3/filter_type_all/Reshape_26_grad/Reshape" + input: "gradients_3/filter_type_all/add_25_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_25_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/add_25_grad/Sum_1" + input: "gradients_3/filter_type_all/add_25_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_25_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_25_grad/Reshape_1" + input: "gradients_3/filter_type_all/Reshape_25_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Tanh_11_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_all/Tanh_11" + input: "gradients_3/filter_type_all/Reshape_25_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/add_24_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Tanh_11_grad/TanhGrad" + input: "gradients_3/filter_type_all/add_24_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_24_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_24_grad/Sum" + input: "gradients_3/filter_type_all/add_24_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_14_grad/MatMul" + op: "MatMul" + input: "gradients_3/filter_type_all/add_24_grad/Reshape" + input: "filter_type_all/matrix_3_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/add_25_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Reshape_26_grad/Reshape" + input: "gradients_3/filter_type_all/add_25_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_25_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_25_grad/Sum" + input: "gradients_3/filter_type_all/add_25_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_11_grad/Slice_1" + op: "Slice" + input: "gradients_3/filter_type_all/add_25_grad/Reshape" + input: "gradients_3/filter_type_all/concat_11_grad/ConcatOffset:1" + input: "gradients_3/filter_type_all/concat_11_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_11_grad/Slice" + op: "Slice" + input: "gradients_3/filter_type_all/add_25_grad/Reshape" + input: "gradients_3/filter_type_all/concat_11_grad/ConcatOffset" + input: "gradients_3/filter_type_all/concat_11_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/AddN_13" + op: "AddN" + input: "gradients_3/filter_type_all/concat_11_grad/Slice" + input: "gradients_3/filter_type_all/concat_11_grad/Slice_1" + input: "gradients_3/filter_type_all/MatMul_14_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/concat_11_grad/Slice" + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_23_grad/Sum_1" + op: "Sum" + input: "gradients_3/AddN_13" + input: "gradients_3/filter_type_all/add_23_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_23_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/add_23_grad/Sum_1" + input: "gradients_3/filter_type_all/add_23_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_24_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_23_grad/Reshape_1" + input: "gradients_3/filter_type_all/Reshape_24_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Tanh_10_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_all/Tanh_10" + input: "gradients_3/filter_type_all/Reshape_24_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/add_22_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Tanh_10_grad/TanhGrad" + input: "gradients_3/filter_type_all/add_22_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_22_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_22_grad/Sum" + input: "gradients_3/filter_type_all/add_22_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_13_grad/MatMul" + op: "MatMul" + input: "gradients_3/filter_type_all/add_22_grad/Reshape" + input: "filter_type_all/matrix_2_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/add_23_grad/Sum" + op: "Sum" + input: "gradients_3/AddN_13" + input: "gradients_3/filter_type_all/add_23_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_23_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_23_grad/Sum" + input: "gradients_3/filter_type_all/add_23_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_10_grad/Slice_1" + op: "Slice" + input: "gradients_3/filter_type_all/add_23_grad/Reshape" + input: "gradients_3/filter_type_all/concat_10_grad/ConcatOffset:1" + input: "gradients_3/filter_type_all/concat_10_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_10_grad/Slice" + op: "Slice" + input: "gradients_3/filter_type_all/add_23_grad/Reshape" + input: "gradients_3/filter_type_all/concat_10_grad/ConcatOffset" + input: "gradients_3/filter_type_all/concat_10_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/AddN_18" + op: "AddN" + input: "gradients_3/filter_type_all/concat_10_grad/Slice" + input: "gradients_3/filter_type_all/concat_10_grad/Slice_1" + input: "gradients_3/filter_type_all/MatMul_13_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/concat_10_grad/Slice" + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_21_grad/Sum_1" + op: "Sum" + input: "gradients_3/AddN_18" + input: "gradients_3/filter_type_all/add_21_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_21_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/add_21_grad/Sum_1" + input: "gradients_3/filter_type_all/add_21_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_23_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_21_grad/Reshape_1" + input: "gradients_3/filter_type_all/Reshape_23_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Tanh_9_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_all/Tanh_9" + input: "gradients_3/filter_type_all/Reshape_23_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/add_20_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Tanh_9_grad/TanhGrad" + input: "gradients_3/filter_type_all/add_20_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_20_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_20_grad/Sum" + input: "gradients_3/filter_type_all/add_20_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_12_grad/MatMul" + op: "MatMul" + input: "gradients_3/filter_type_all/add_20_grad/Reshape" + input: "filter_type_all/matrix_1_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/add_21_grad/Sum" + op: "Sum" + input: "gradients_3/AddN_18" + input: "gradients_3/filter_type_all/add_21_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_21_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_21_grad/Sum" + input: "gradients_3/filter_type_all/add_21_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_9_grad/Slice_1" + op: "Slice" + input: "gradients_3/filter_type_all/add_21_grad/Reshape" + input: "gradients_3/filter_type_all/concat_9_grad/ConcatOffset:1" + input: "gradients_3/filter_type_all/concat_9_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_9_grad/Slice" + op: "Slice" + input: "gradients_3/filter_type_all/add_21_grad/Reshape" + input: "gradients_3/filter_type_all/concat_9_grad/ConcatOffset" + input: "gradients_3/filter_type_all/concat_9_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/AddN_23" + op: "AddN" + input: "gradients_3/filter_type_all/concat_9_grad/Slice" + input: "gradients_3/filter_type_all/concat_9_grad/Slice_1" + input: "gradients_3/filter_type_all/MatMul_12_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/concat_9_grad/Slice" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_22_grad/Reshape" + op: "Reshape" + input: "gradients_3/AddN_23" + input: "gradients_3/filter_type_all/Reshape_22_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_7_grad/Pad" + op: "Pad" + input: "gradients_3/filter_type_all/Reshape_22_grad/Reshape" + input: "gradients_3/filter_type_all/Slice_7_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_21_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/Slice_7_grad/Pad" + input: "gradients_3/filter_type_all/Reshape_21_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_15_grad/MatMul" + op: "BatchMatMul" + input: "filter_type_all/Reshape_26" + input: "gradients_3/filter_type_all/add_26_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_27_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/MatMul_15_grad/MatMul" + input: "gradients_3/filter_type_all/Reshape_27_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/AddN_28" + op: "AddN" + input: "gradients_3/filter_type_all/Reshape_27_grad/Reshape" + input: "gradients_3/filter_type_all/Reshape_21_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/Reshape_27_grad/Reshape" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_6_grad/Pad" + op: "Pad" + input: "gradients_3/AddN_28" + input: "gradients_3/filter_type_all/Slice_6_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_26_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/add_33_grad/Reshape" + input: "gradients_3/filter_type_all/add_26_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_26_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_26_grad/Sum" + input: "gradients_3/filter_type_all/add_26_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_19_grad/Sum_1" + op: "Sum" + input: "gradients_3/filter_type_all/add_26_grad/Reshape" + input: "gradients_3/filter_type_all/add_19_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_19_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/add_19_grad/Sum_1" + input: "gradients_3/filter_type_all/add_19_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_11_grad/MatMul_1" + op: "BatchMatMul" + input: "filter_type_all/Reshape_20" + input: "gradients_3/filter_type_all/add_19_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_19_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/MatMul_11_grad/MatMul_1" + input: "gradients_3/filter_type_all/Reshape_19_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_18_grad/Sum_1" + op: "Sum" + input: "gradients_3/filter_type_all/Reshape_19_grad/Reshape" + input: "gradients_3/filter_type_all/add_18_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_18_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/add_18_grad/Sum_1" + input: "gradients_3/filter_type_all/add_18_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_18_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_18_grad/Reshape_1" + input: "gradients_3/filter_type_all/Reshape_18_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Tanh_8_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_all/Tanh_8" + input: "gradients_3/filter_type_all/Reshape_18_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/add_17_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Tanh_8_grad/TanhGrad" + input: "gradients_3/filter_type_all/add_17_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_17_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_17_grad/Sum" + input: "gradients_3/filter_type_all/add_17_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_10_grad/MatMul" + op: "MatMul" + input: "gradients_3/filter_type_all/add_17_grad/Reshape" + input: "filter_type_all/matrix_3_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/add_18_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Reshape_19_grad/Reshape" + input: "gradients_3/filter_type_all/add_18_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_18_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_18_grad/Sum" + input: "gradients_3/filter_type_all/add_18_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_8_grad/Slice_1" + op: "Slice" + input: "gradients_3/filter_type_all/add_18_grad/Reshape" + input: "gradients_3/filter_type_all/concat_8_grad/ConcatOffset:1" + input: "gradients_3/filter_type_all/concat_8_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_8_grad/Slice" + op: "Slice" + input: "gradients_3/filter_type_all/add_18_grad/Reshape" + input: "gradients_3/filter_type_all/concat_8_grad/ConcatOffset" + input: "gradients_3/filter_type_all/concat_8_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/AddN_14" + op: "AddN" + input: "gradients_3/filter_type_all/concat_8_grad/Slice" + input: "gradients_3/filter_type_all/concat_8_grad/Slice_1" + input: "gradients_3/filter_type_all/MatMul_10_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/concat_8_grad/Slice" + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_16_grad/Sum_1" + op: "Sum" + input: "gradients_3/AddN_14" + input: "gradients_3/filter_type_all/add_16_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_16_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/add_16_grad/Sum_1" + input: "gradients_3/filter_type_all/add_16_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_17_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_16_grad/Reshape_1" + input: "gradients_3/filter_type_all/Reshape_17_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Tanh_7_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_all/Tanh_7" + input: "gradients_3/filter_type_all/Reshape_17_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/add_15_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Tanh_7_grad/TanhGrad" + input: "gradients_3/filter_type_all/add_15_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_15_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_15_grad/Sum" + input: "gradients_3/filter_type_all/add_15_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_9_grad/MatMul" + op: "MatMul" + input: "gradients_3/filter_type_all/add_15_grad/Reshape" + input: "filter_type_all/matrix_2_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/add_16_grad/Sum" + op: "Sum" + input: "gradients_3/AddN_14" + input: "gradients_3/filter_type_all/add_16_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_16_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_16_grad/Sum" + input: "gradients_3/filter_type_all/add_16_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_7_grad/Slice_1" + op: "Slice" + input: "gradients_3/filter_type_all/add_16_grad/Reshape" + input: "gradients_3/filter_type_all/concat_7_grad/ConcatOffset:1" + input: "gradients_3/filter_type_all/concat_7_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_7_grad/Slice" + op: "Slice" + input: "gradients_3/filter_type_all/add_16_grad/Reshape" + input: "gradients_3/filter_type_all/concat_7_grad/ConcatOffset" + input: "gradients_3/filter_type_all/concat_7_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/AddN_19" + op: "AddN" + input: "gradients_3/filter_type_all/concat_7_grad/Slice" + input: "gradients_3/filter_type_all/concat_7_grad/Slice_1" + input: "gradients_3/filter_type_all/MatMul_9_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/concat_7_grad/Slice" + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_14_grad/Sum_1" + op: "Sum" + input: "gradients_3/AddN_19" + input: "gradients_3/filter_type_all/add_14_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_14_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/add_14_grad/Sum_1" + input: "gradients_3/filter_type_all/add_14_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_16_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_14_grad/Reshape_1" + input: "gradients_3/filter_type_all/Reshape_16_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Tanh_6_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_all/Tanh_6" + input: "gradients_3/filter_type_all/Reshape_16_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/add_13_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Tanh_6_grad/TanhGrad" + input: "gradients_3/filter_type_all/add_13_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_13_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_13_grad/Sum" + input: "gradients_3/filter_type_all/add_13_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_8_grad/MatMul" + op: "MatMul" + input: "gradients_3/filter_type_all/add_13_grad/Reshape" + input: "filter_type_all/matrix_1_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/add_14_grad/Sum" + op: "Sum" + input: "gradients_3/AddN_19" + input: "gradients_3/filter_type_all/add_14_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_14_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_14_grad/Sum" + input: "gradients_3/filter_type_all/add_14_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_6_grad/Slice_1" + op: "Slice" + input: "gradients_3/filter_type_all/add_14_grad/Reshape" + input: "gradients_3/filter_type_all/concat_6_grad/ConcatOffset:1" + input: "gradients_3/filter_type_all/concat_6_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_6_grad/Slice" + op: "Slice" + input: "gradients_3/filter_type_all/add_14_grad/Reshape" + input: "gradients_3/filter_type_all/concat_6_grad/ConcatOffset" + input: "gradients_3/filter_type_all/concat_6_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/AddN_24" + op: "AddN" + input: "gradients_3/filter_type_all/concat_6_grad/Slice" + input: "gradients_3/filter_type_all/concat_6_grad/Slice_1" + input: "gradients_3/filter_type_all/MatMul_8_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/concat_6_grad/Slice" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_15_grad/Reshape" + op: "Reshape" + input: "gradients_3/AddN_24" + input: "gradients_3/filter_type_all/Reshape_15_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_5_grad/Pad" + op: "Pad" + input: "gradients_3/filter_type_all/Reshape_15_grad/Reshape" + input: "gradients_3/filter_type_all/Slice_5_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_14_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/Slice_5_grad/Pad" + input: "gradients_3/filter_type_all/Reshape_14_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_11_grad/MatMul" + op: "BatchMatMul" + input: "filter_type_all/Reshape_19" + input: "gradients_3/filter_type_all/add_19_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_20_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/MatMul_11_grad/MatMul" + input: "gradients_3/filter_type_all/Reshape_20_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/AddN_29" + op: "AddN" + input: "gradients_3/filter_type_all/Reshape_20_grad/Reshape" + input: "gradients_3/filter_type_all/Reshape_14_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/Reshape_20_grad/Reshape" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_4_grad/Pad" + op: "Pad" + input: "gradients_3/AddN_29" + input: "gradients_3/filter_type_all/Slice_4_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_19_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/add_26_grad/Reshape" + input: "gradients_3/filter_type_all/add_19_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_19_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_19_grad/Sum" + input: "gradients_3/filter_type_all/add_19_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_12_grad/Sum_1" + op: "Sum" + input: "gradients_3/filter_type_all/add_19_grad/Reshape" + input: "gradients_3/filter_type_all/add_12_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_12_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/add_12_grad/Sum_1" + input: "gradients_3/filter_type_all/add_12_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_7_grad/MatMul_1" + op: "BatchMatMul" + input: "filter_type_all/Reshape_13" + input: "gradients_3/filter_type_all/add_12_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_12_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/MatMul_7_grad/MatMul_1" + input: "gradients_3/filter_type_all/Reshape_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_11_grad/Sum_1" + op: "Sum" + input: "gradients_3/filter_type_all/Reshape_12_grad/Reshape" + input: "gradients_3/filter_type_all/add_11_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_11_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/add_11_grad/Sum_1" + input: "gradients_3/filter_type_all/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_11_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_11_grad/Reshape_1" + input: "gradients_3/filter_type_all/Reshape_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Tanh_5_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_all/Tanh_5" + input: "gradients_3/filter_type_all/Reshape_11_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/add_10_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Tanh_5_grad/TanhGrad" + input: "gradients_3/filter_type_all/add_10_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_10_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_10_grad/Sum" + input: "gradients_3/filter_type_all/add_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_6_grad/MatMul" + op: "MatMul" + input: "gradients_3/filter_type_all/add_10_grad/Reshape" + input: "filter_type_all/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/add_11_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Reshape_12_grad/Reshape" + input: "gradients_3/filter_type_all/add_11_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_11_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_11_grad/Sum" + input: "gradients_3/filter_type_all/add_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_5_grad/Slice_1" + op: "Slice" + input: "gradients_3/filter_type_all/add_11_grad/Reshape" + input: "gradients_3/filter_type_all/concat_5_grad/ConcatOffset:1" + input: "gradients_3/filter_type_all/concat_5_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_5_grad/Slice" + op: "Slice" + input: "gradients_3/filter_type_all/add_11_grad/Reshape" + input: "gradients_3/filter_type_all/concat_5_grad/ConcatOffset" + input: "gradients_3/filter_type_all/concat_5_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/AddN_16" + op: "AddN" + input: "gradients_3/filter_type_all/concat_5_grad/Slice" + input: "gradients_3/filter_type_all/concat_5_grad/Slice_1" + input: "gradients_3/filter_type_all/MatMul_6_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/concat_5_grad/Slice" + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_9_grad/Sum_1" + op: "Sum" + input: "gradients_3/AddN_16" + input: "gradients_3/filter_type_all/add_9_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_9_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/add_9_grad/Sum_1" + input: "gradients_3/filter_type_all/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_10_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_9_grad/Reshape_1" + input: "gradients_3/filter_type_all/Reshape_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Tanh_4_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_all/Tanh_4" + input: "gradients_3/filter_type_all/Reshape_10_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/add_8_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Tanh_4_grad/TanhGrad" + input: "gradients_3/filter_type_all/add_8_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_8_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_8_grad/Sum" + input: "gradients_3/filter_type_all/add_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_5_grad/MatMul" + op: "MatMul" + input: "gradients_3/filter_type_all/add_8_grad/Reshape" + input: "filter_type_all/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/add_9_grad/Sum" + op: "Sum" + input: "gradients_3/AddN_16" + input: "gradients_3/filter_type_all/add_9_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_9_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_9_grad/Sum" + input: "gradients_3/filter_type_all/add_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_4_grad/Slice_1" + op: "Slice" + input: "gradients_3/filter_type_all/add_9_grad/Reshape" + input: "gradients_3/filter_type_all/concat_4_grad/ConcatOffset:1" + input: "gradients_3/filter_type_all/concat_4_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_4_grad/Slice" + op: "Slice" + input: "gradients_3/filter_type_all/add_9_grad/Reshape" + input: "gradients_3/filter_type_all/concat_4_grad/ConcatOffset" + input: "gradients_3/filter_type_all/concat_4_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/AddN_21" + op: "AddN" + input: "gradients_3/filter_type_all/concat_4_grad/Slice" + input: "gradients_3/filter_type_all/concat_4_grad/Slice_1" + input: "gradients_3/filter_type_all/MatMul_5_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/concat_4_grad/Slice" + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_7_grad/Sum_1" + op: "Sum" + input: "gradients_3/AddN_21" + input: "gradients_3/filter_type_all/add_7_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_7_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/add_7_grad/Sum_1" + input: "gradients_3/filter_type_all/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_9_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_7_grad/Reshape_1" + input: "gradients_3/filter_type_all/Reshape_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Tanh_3_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_all/Tanh_3" + input: "gradients_3/filter_type_all/Reshape_9_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/add_6_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Tanh_3_grad/TanhGrad" + input: "gradients_3/filter_type_all/add_6_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_6_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_6_grad/Sum" + input: "gradients_3/filter_type_all/add_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_4_grad/MatMul" + op: "MatMul" + input: "gradients_3/filter_type_all/add_6_grad/Reshape" + input: "filter_type_all/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/add_7_grad/Sum" + op: "Sum" + input: "gradients_3/AddN_21" + input: "gradients_3/filter_type_all/add_7_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_7_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_7_grad/Sum" + input: "gradients_3/filter_type_all/add_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_3_grad/Slice_1" + op: "Slice" + input: "gradients_3/filter_type_all/add_7_grad/Reshape" + input: "gradients_3/filter_type_all/concat_3_grad/ConcatOffset:1" + input: "gradients_3/filter_type_all/concat_3_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_3_grad/Slice" + op: "Slice" + input: "gradients_3/filter_type_all/add_7_grad/Reshape" + input: "gradients_3/filter_type_all/concat_3_grad/ConcatOffset" + input: "gradients_3/filter_type_all/concat_3_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/AddN_26" + op: "AddN" + input: "gradients_3/filter_type_all/concat_3_grad/Slice" + input: "gradients_3/filter_type_all/concat_3_grad/Slice_1" + input: "gradients_3/filter_type_all/MatMul_4_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/concat_3_grad/Slice" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_8_grad/Reshape" + op: "Reshape" + input: "gradients_3/AddN_26" + input: "gradients_3/filter_type_all/Reshape_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_3_grad/Pad" + op: "Pad" + input: "gradients_3/filter_type_all/Reshape_8_grad/Reshape" + input: "gradients_3/filter_type_all/Slice_3_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_7_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/Slice_3_grad/Pad" + input: "gradients_3/filter_type_all/Reshape_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_7_grad/MatMul" + op: "BatchMatMul" + input: "filter_type_all/Reshape_12" + input: "gradients_3/filter_type_all/add_12_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_13_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/MatMul_7_grad/MatMul" + input: "gradients_3/filter_type_all/Reshape_13_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/AddN_31" + op: "AddN" + input: "gradients_3/filter_type_all/Reshape_13_grad/Reshape" + input: "gradients_3/filter_type_all/Reshape_7_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/Reshape_13_grad/Reshape" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_2_grad/Pad" + op: "Pad" + input: "gradients_3/AddN_31" + input: "gradients_3/filter_type_all/Slice_2_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_12_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/add_19_grad/Reshape" + input: "gradients_3/filter_type_all/add_12_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_12_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_12_grad/Sum" + input: "gradients_3/filter_type_all/add_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_3_grad/MatMul_1" + op: "BatchMatMul" + input: "filter_type_all/Reshape_6" + input: "gradients_3/filter_type_all/add_12_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_5_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/MatMul_3_grad/MatMul_1" + input: "gradients_3/filter_type_all/Reshape_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/add_5_grad/Sum_1" + op: "Sum" + input: "gradients_3/filter_type_all/Reshape_5_grad/Reshape" + input: "gradients_3/filter_type_all/add_5_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_5_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/add_5_grad/Sum_1" + input: "gradients_3/filter_type_all/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_4_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_5_grad/Reshape_1" + input: "gradients_3/filter_type_all/Reshape_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Tanh_2_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_all/Tanh_2" + input: "gradients_3/filter_type_all/Reshape_4_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/add_4_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Tanh_2_grad/TanhGrad" + input: "gradients_3/filter_type_all/add_4_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_4_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_4_grad/Sum" + input: "gradients_3/filter_type_all/add_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_2_grad/MatMul" + op: "MatMul" + input: "gradients_3/filter_type_all/add_4_grad/Reshape" + input: "filter_type_all/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/add_5_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Reshape_5_grad/Reshape" + input: "gradients_3/filter_type_all/add_5_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_5_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_5_grad/Sum" + input: "gradients_3/filter_type_all/add_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_2_grad/Slice_1" + op: "Slice" + input: "gradients_3/filter_type_all/add_5_grad/Reshape" + input: "gradients_3/filter_type_all/concat_2_grad/ConcatOffset:1" + input: "gradients_3/filter_type_all/concat_2_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_2_grad/Slice" + op: "Slice" + input: "gradients_3/filter_type_all/add_5_grad/Reshape" + input: "gradients_3/filter_type_all/concat_2_grad/ConcatOffset" + input: "gradients_3/filter_type_all/concat_2_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/AddN_15" + op: "AddN" + input: "gradients_3/filter_type_all/concat_2_grad/Slice" + input: "gradients_3/filter_type_all/concat_2_grad/Slice_1" + input: "gradients_3/filter_type_all/MatMul_2_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/concat_2_grad/Slice" + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_3_grad/Sum_1" + op: "Sum" + input: "gradients_3/AddN_15" + input: "gradients_3/filter_type_all/add_3_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_3_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/add_3_grad/Sum_1" + input: "gradients_3/filter_type_all/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_3_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_3_grad/Reshape_1" + input: "gradients_3/filter_type_all/Reshape_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Tanh_1_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_all/Tanh_1" + input: "gradients_3/filter_type_all/Reshape_3_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/add_2_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Tanh_1_grad/TanhGrad" + input: "gradients_3/filter_type_all/add_2_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_2_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_2_grad/Sum" + input: "gradients_3/filter_type_all/add_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_1_grad/MatMul" + op: "MatMul" + input: "gradients_3/filter_type_all/add_2_grad/Reshape" + input: "filter_type_all/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/add_3_grad/Sum" + op: "Sum" + input: "gradients_3/AddN_15" + input: "gradients_3/filter_type_all/add_3_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_3_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_3_grad/Sum" + input: "gradients_3/filter_type_all/add_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_1_grad/Slice_1" + op: "Slice" + input: "gradients_3/filter_type_all/add_3_grad/Reshape" + input: "gradients_3/filter_type_all/concat_1_grad/ConcatOffset:1" + input: "gradients_3/filter_type_all/concat_1_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_1_grad/Slice" + op: "Slice" + input: "gradients_3/filter_type_all/add_3_grad/Reshape" + input: "gradients_3/filter_type_all/concat_1_grad/ConcatOffset" + input: "gradients_3/filter_type_all/concat_1_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/AddN_20" + op: "AddN" + input: "gradients_3/filter_type_all/concat_1_grad/Slice" + input: "gradients_3/filter_type_all/concat_1_grad/Slice_1" + input: "gradients_3/filter_type_all/MatMul_1_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/concat_1_grad/Slice" + } + } + } +} +node { + name: "gradients_3/filter_type_all/add_1_grad/Sum_1" + op: "Sum" + input: "gradients_3/AddN_20" + input: "gradients_3/filter_type_all/add_1_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_1_grad/Reshape_1" + op: "Reshape" + input: "gradients_3/filter_type_all/add_1_grad/Sum_1" + input: "gradients_3/filter_type_all/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_2_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_1_grad/Reshape_1" + input: "gradients_3/filter_type_all/Reshape_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_all/Tanh" + input: "gradients_3/filter_type_all/Reshape_2_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/add_grad/Sum" + op: "Sum" + input: "gradients_3/filter_type_all/Tanh_grad/TanhGrad" + input: "gradients_3/filter_type_all/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_grad/Sum" + input: "gradients_3/filter_type_all/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_3/filter_type_all/add_grad/Reshape" + input: "filter_type_all/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/add_1_grad/Sum" + op: "Sum" + input: "gradients_3/AddN_20" + input: "gradients_3/filter_type_all/add_1_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_3/filter_type_all/add_1_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/add_1_grad/Sum" + input: "gradients_3/filter_type_all/add_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/concat_grad/Slice_1" + op: "Slice" + input: "gradients_3/filter_type_all/add_1_grad/Reshape" + input: "gradients_3/filter_type_all/concat_grad/ConcatOffset:1" + input: "gradients_3/filter_type_all/concat_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/filter_type_all/concat_grad/Slice" + op: "Slice" + input: "gradients_3/filter_type_all/add_1_grad/Reshape" + input: "gradients_3/filter_type_all/concat_grad/ConcatOffset" + input: "gradients_3/filter_type_all/concat_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_3/AddN_25" + op: "AddN" + input: "gradients_3/filter_type_all/concat_grad/Slice" + input: "gradients_3/filter_type_all/concat_grad/Slice_1" + input: "gradients_3/filter_type_all/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/concat_grad/Slice" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_1_grad/Reshape" + op: "Reshape" + input: "gradients_3/AddN_25" + input: "gradients_3/filter_type_all/Reshape_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_1_grad/Pad" + op: "Pad" + input: "gradients_3/filter_type_all/Reshape_1_grad/Reshape" + input: "gradients_3/filter_type_all/Slice_1_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/Slice_1_grad/Pad" + input: "gradients_3/filter_type_all/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/filter_type_all/MatMul_3_grad/MatMul" + op: "BatchMatMul" + input: "filter_type_all/Reshape_5" + input: "gradients_3/filter_type_all/add_12_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_3/filter_type_all/Reshape_6_grad/Reshape" + op: "Reshape" + input: "gradients_3/filter_type_all/MatMul_3_grad/MatMul" + input: "gradients_3/filter_type_all/Reshape_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/AddN_30" + op: "AddN" + input: "gradients_3/filter_type_all/Reshape_6_grad/Reshape" + input: "gradients_3/filter_type_all/Reshape_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/Reshape_6_grad/Reshape" + } + } + } +} +node { + name: "gradients_3/filter_type_all/Slice_grad/Pad" + op: "Pad" + input: "gradients_3/AddN_30" + input: "gradients_3/filter_type_all/Slice_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/AddN_32" + op: "AddN" + input: "gradients_3/filter_type_all/Slice_8_grad/Pad" + input: "gradients_3/filter_type_all/Slice_6_grad/Pad" + input: "gradients_3/filter_type_all/Slice_4_grad/Pad" + input: "gradients_3/filter_type_all/Slice_grad/Pad" + input: "gradients_3/filter_type_all/Slice_2_grad/Pad" + attr { + key: "N" + value { + i: 5 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_3/filter_type_all/Slice_8_grad/Pad" + } + } + } +} +node { + name: "gradients_3/Reshape_22_grad/Reshape" + op: "Reshape" + input: "gradients_3/AddN_32" + input: "gradients_3/Reshape_22_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_3/Reshape_21_grad/Reshape" + op: "Reshape" + input: "gradients_3/Reshape_22_grad/Reshape" + input: "gradients_3/Reshape_21_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_37" + op: "Reshape" + input: "gradients_3/Reshape_21_grad/Reshape" + input: "Reshape_37/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "ProdVirialSeA_1" + op: "ProdVirialSeA" + input: "Reshape_37" + input: "o_rmat_deriv" + input: "o_rij" + input: "o_nlist" + input: "t_natoms" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "n_a_sel" + value { + i: 25 + } + } + attr { + key: "n_r_sel" + value { + i: 0 + } + } +} +node { + name: "o_atom_virial" + op: "Reshape" + input: "ProdVirialSeA_1:1" + input: "o_atom_virial/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_virial" + op: "Reshape" + input: "ProdVirialSeA_1" + input: "o_virial/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "ProdForceSeA_1" + op: "ProdForceSeA" + input: "Reshape_37" + input: "o_rmat_deriv" + input: "o_nlist" + input: "t_natoms" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "n_a_sel" + value { + i: 25 + } + } + attr { + key: "n_r_sel" + value { + i: 0 + } + } +} +node { + name: "o_force" + op: "Reshape" + input: "ProdForceSeA_1" + input: "o_force/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_atom_energy" + op: "Reshape" + input: "Reshape_36" + input: "o_atom_energy/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_energy" + op: "Sum" + input: "o_atom_energy" + input: "o_energy/reduction_indices" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "Reshape_14/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_27/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_45/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_45/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_45/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "concat_5/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "zeros_5/Const" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.0 + } + } + } +} +node { + name: "mul_26/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_44/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_44/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 7 + } + } + } +} +node { + name: "strided_slice_44/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "strided_slice_43/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_43/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_43/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Slice_12/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_12/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_25/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_41/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_41/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "strided_slice_41/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "mul_24/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "zeros_4/Const" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.0 + } + } + } +} +node { + name: "mul_23/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_40/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_40/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "strided_slice_40/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_39/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_39/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_39/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "add_17/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "strided_slice_38/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_38/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_38/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "Slice_11/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_11/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "mul_22/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_37/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_37/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_37/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "zeros_3/Const" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.0 + } + } + } +} +node { + name: "mul_21/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_36/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_36/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_36/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_35/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_35/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_35/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_13/shape/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Reshape_12/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\003\000\000\000d\000\000\000" + } + } + } +} +node { + name: "Reshape_11/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377,\001\000\000" + } + } + } +} +node { + name: "concat_4/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "Reshape_10/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377d\000\000\000" + } + } + } +} +node { + name: "Reshape_9/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377d\000\000\000" + } + } + } +} +node { + name: "Reshape_8/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377d\000\000\000" + } + } + } +} +node { + name: "concat_3/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "Slice_10/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_10/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_20/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_32/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_32/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "strided_slice_32/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "mul_19/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_31/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_31/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "strided_slice_31/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_30/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_30/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_30/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "Slice_9/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_9/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_18/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_29/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_29/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_29/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "mul_17/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "add_12/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "strided_slice_28/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_28/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_28/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "Slice_8/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_8/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_16/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_25/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_25/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "strided_slice_25/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "mul_15/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_24/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_24/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "strided_slice_24/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_23/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_23/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_23/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "Slice_7/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_7/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_14/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_22/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_22/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_22/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "mul_13/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "add_7/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "strided_slice_21/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_21/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_21/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "concat_1/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "Slice_6/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_6/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_12/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_18/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_18/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "strided_slice_18/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "mul_11/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_17/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_17/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "strided_slice_17/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_16/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_16/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_16/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "Slice_5/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_5/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_10/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_15/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_15/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_15/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "mul_9/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "add_2/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "strided_slice_14/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_14/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_14/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "Reshape_7/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_8/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_13/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_13/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_13/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_6/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_7/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_12/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_12/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_12/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_5/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_6/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "strided_slice_11/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_11/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_11/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/stack" + op: "Pack" + input: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/Rank" + input: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_grad/stack" + op: "Pack" + input: "gradients_2/dipole_charge/filter_type_all/Slice_grad/Rank" + input: "gradients_2/dipole_charge/filter_type_all/Slice_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/stack" + op: "Pack" + input: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/Rank" + input: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/stack" + op: "Pack" + input: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/Rank" + input: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/stack" + op: "Pack" + input: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/Rank" + input: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/stack" + op: "Pack" + input: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/Rank" + input: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/stack" + op: "Pack" + input: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/Rank" + input: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/stack" + op: "Pack" + input: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/Rank" + input: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/stack" + op: "Pack" + input: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/Rank" + input: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/stack" + op: "Pack" + input: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/Rank" + input: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_6_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_13_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_20_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_27_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_6_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_9_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_12_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_8_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_2_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_15_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_22_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_29_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_7_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_10_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_13_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_10_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_4_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_17_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_24_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_5_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_31_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_8_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_11_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_14_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + } + } + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/stack" + op: "Pack" + input: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/Rank" + input: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_6_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_6_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_6_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_6_grad/stack" + op: "Pack" + input: "gradients_2/dipole_charge/Slice_6_grad/Rank" + input: "gradients_2/dipole_charge/Slice_6_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_2_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_2_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_2_grad/stack" + op: "Pack" + input: "gradients_2/dipole_charge/Slice_2_grad/Rank" + input: "gradients_2/dipole_charge/Slice_2_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_0_type_3/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_2/dipole_charge/layer_0_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_3/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_3/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/stack" + op: "Pack" + input: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/Rank" + input: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_3/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_3/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_7_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_7_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_7_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_7_grad/stack" + op: "Pack" + input: "gradients_2/dipole_charge/Slice_7_grad/Rank" + input: "gradients_2/dipole_charge/Slice_7_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/final_layer_type_3/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_3_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_3_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_3_grad/stack" + op: "Pack" + input: "gradients_2/dipole_charge/Slice_3_grad/Rank" + input: "gradients_2/dipole_charge/Slice_3_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/final_layer_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_2/dipole_charge/concat_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients_2/Slice_1_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/Slice_1_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/Slice_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/Slice_1_grad/stack" + op: "Pack" + input: "gradients_2/Slice_1_grad/Rank" + input: "gradients_2/Slice_1_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/Slice_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/Slice_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/Slice_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/Slice_grad/stack" + op: "Pack" + input: "gradients_2/Slice_grad/Rank" + input: "gradients_2/Slice_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/concat_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/Slice_4_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/Slice_4_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/Slice_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_2/Slice_4_grad/stack" + op: "Pack" + input: "gradients_2/Slice_4_grad/Rank" + input: "gradients_2/Slice_4_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/grad_ys_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 1.0 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/stack" + op: "Pack" + input: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/Rank" + input: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_grad/stack" + op: "Pack" + input: "gradients_1/dipole_charge/filter_type_all/Slice_grad/Rank" + input: "gradients_1/dipole_charge/filter_type_all/Slice_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/stack" + op: "Pack" + input: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/Rank" + input: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/stack" + op: "Pack" + input: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/Rank" + input: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/stack" + op: "Pack" + input: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/Rank" + input: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/stack" + op: "Pack" + input: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/Rank" + input: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/stack" + op: "Pack" + input: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/Rank" + input: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/stack" + op: "Pack" + input: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/Rank" + input: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/stack" + op: "Pack" + input: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/Rank" + input: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/stack" + op: "Pack" + input: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/Rank" + input: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_6_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_13_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_20_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_27_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_6_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_9_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_12_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_8_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_2_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_15_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_22_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_29_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_7_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_10_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_13_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_10_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_4_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_17_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_24_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_5_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_31_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_8_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_11_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_14_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + } + } + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/stack" + op: "Pack" + input: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/Rank" + input: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_6_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_6_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_6_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_6_grad/stack" + op: "Pack" + input: "gradients_1/dipole_charge/Slice_6_grad/Rank" + input: "gradients_1/dipole_charge/Slice_6_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_2_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_2_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_2_grad/stack" + op: "Pack" + input: "gradients_1/dipole_charge/Slice_2_grad/Rank" + input: "gradients_1/dipole_charge/Slice_2_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_0_type_3/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_1/dipole_charge/layer_0_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_3/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_3/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/stack" + op: "Pack" + input: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/Rank" + input: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_3/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_3/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_7_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_7_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_7_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_7_grad/stack" + op: "Pack" + input: "gradients_1/dipole_charge/Slice_7_grad/Rank" + input: "gradients_1/dipole_charge/Slice_7_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_1/dipole_charge/final_layer_type_3/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_3_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_3_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_3_grad/stack" + op: "Pack" + input: "gradients_1/dipole_charge/Slice_3_grad/Rank" + input: "gradients_1/dipole_charge/Slice_3_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_1/dipole_charge/final_layer_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients_1/dipole_charge/concat_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients_1/Slice_1_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/Slice_1_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/Slice_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/Slice_1_grad/stack" + op: "Pack" + input: "gradients_1/Slice_1_grad/Rank" + input: "gradients_1/Slice_1_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_1/Slice_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/Slice_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/Slice_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/Slice_grad/stack" + op: "Pack" + input: "gradients_1/Slice_grad/Rank" + input: "gradients_1/Slice_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_1/concat_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/Slice_3_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/Slice_3_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_1/Slice_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients_1/Slice_3_grad/stack" + op: "Pack" + input: "gradients_1/Slice_3_grad/Rank" + input: "gradients_1/Slice_3_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_1/grad_ys_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 1.0 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_2_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_2_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_2_grad/stack" + op: "Pack" + input: "gradients/dipole_charge/filter_type_all/Slice_2_grad/Rank" + input: "gradients/dipole_charge/filter_type_all/Slice_2_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_grad/stack" + op: "Pack" + input: "gradients/dipole_charge/filter_type_all/Slice_grad/Rank" + input: "gradients/dipole_charge/filter_type_all/Slice_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_4_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_4_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_4_grad/stack" + op: "Pack" + input: "gradients/dipole_charge/filter_type_all/Slice_4_grad/Rank" + input: "gradients/dipole_charge/filter_type_all/Slice_4_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_6_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_6_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_6_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_6_grad/stack" + op: "Pack" + input: "gradients/dipole_charge/filter_type_all/Slice_6_grad/Rank" + input: "gradients/dipole_charge/filter_type_all/Slice_6_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_3_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_3_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_3_grad/stack" + op: "Pack" + input: "gradients/dipole_charge/filter_type_all/Slice_3_grad/Rank" + input: "gradients/dipole_charge/filter_type_all/Slice_3_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_1_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_1_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_1_grad/stack" + op: "Pack" + input: "gradients/dipole_charge/filter_type_all/Slice_1_grad/Rank" + input: "gradients/dipole_charge/filter_type_all/Slice_1_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_8_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_8_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_8_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_8_grad/stack" + op: "Pack" + input: "gradients/dipole_charge/filter_type_all/Slice_8_grad/Rank" + input: "gradients/dipole_charge/filter_type_all/Slice_8_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_5_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_5_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_5_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_5_grad/stack" + op: "Pack" + input: "gradients/dipole_charge/filter_type_all/Slice_5_grad/Rank" + input: "gradients/dipole_charge/filter_type_all/Slice_5_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_7_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_7_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_7_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_7_grad/stack" + op: "Pack" + input: "gradients/dipole_charge/filter_type_all/Slice_7_grad/Rank" + input: "gradients/dipole_charge/filter_type_all/Slice_7_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_9_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_9_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_9_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_9_grad/stack" + op: "Pack" + input: "gradients/dipole_charge/filter_type_all/Slice_9_grad/Rank" + input: "gradients/dipole_charge/filter_type_all/Slice_9_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_6_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_13_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_20_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_27_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_6_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_9_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_12_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_8_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_2_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_15_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_22_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_29_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_7_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_10_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_13_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_10_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_4_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_17_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_24_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_5_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_31_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_8_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_11_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_14_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + } + } + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_10_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_10_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_10_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_10_grad/stack" + op: "Pack" + input: "gradients/dipole_charge/filter_type_all/Slice_10_grad/Rank" + input: "gradients/dipole_charge/filter_type_all/Slice_10_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/dipole_charge/Slice_6_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/Slice_6_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/Slice_6_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/Slice_6_grad/stack" + op: "Pack" + input: "gradients/dipole_charge/Slice_6_grad/Rank" + input: "gradients/dipole_charge/Slice_6_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/dipole_charge/Slice_2_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/Slice_2_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/Slice_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/Slice_2_grad/stack" + op: "Pack" + input: "gradients/dipole_charge/Slice_2_grad/Rank" + input: "gradients/dipole_charge/Slice_2_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/dipole_charge/layer_0_type_3/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/dipole_charge/layer_0_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_3/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_3/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_11_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_11_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_11_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_11_grad/stack" + op: "Pack" + input: "gradients/dipole_charge/filter_type_all/Slice_11_grad/Rank" + input: "gradients/dipole_charge/filter_type_all/Slice_11_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_3/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_3/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/dipole_charge/Slice_7_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/Slice_7_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/Slice_7_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/Slice_7_grad/stack" + op: "Pack" + input: "gradients/dipole_charge/Slice_7_grad/Rank" + input: "gradients/dipole_charge/Slice_7_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/dipole_charge/final_layer_type_3/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients/dipole_charge/Slice_3_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/Slice_3_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/dipole_charge/Slice_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/dipole_charge/Slice_3_grad/stack" + op: "Pack" + input: "gradients/dipole_charge/Slice_3_grad/Rank" + input: "gradients/dipole_charge/Slice_3_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/dipole_charge/final_layer_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 8 + } + } + } +} +node { + name: "gradients/dipole_charge/concat_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients/Slice_1_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_1_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_1_grad/stack" + op: "Pack" + input: "gradients/Slice_1_grad/Rank" + input: "gradients/Slice_1_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/Slice_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_grad/stack" + op: "Pack" + input: "gradients/Slice_grad/Rank" + input: "gradients/Slice_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/concat_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_2_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_2_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_2_grad/stack" + op: "Pack" + input: "gradients/Slice_2_grad/Rank" + input: "gradients/Slice_2_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/grad_ys_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 1.0 + } + } + } +} +node { + name: "Reshape_4/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "Slice_4/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "Slice_4/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients_2/Slice_4_grad/Reshape" + op: "Reshape" + input: "Slice_4/begin" + input: "gradients_2/Slice_4_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_3/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "Slice_3/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\001\000\000\000" + } + } + } +} +node { + name: "gradients_1/Slice_3_grad/Reshape" + op: "Reshape" + input: "Slice_3/begin" + input: "gradients_1/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_2/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "Slice_2/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/Slice_2_grad/Reshape" + op: "Reshape" + input: "Slice_2/begin" + input: "gradients/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\003\000\000\000" + } + } + } +} +node { + name: "concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/concat_grad/mod" + op: "FloorMod" + input: "concat/axis" + input: "gradients_2/concat_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/concat_grad/mod" + op: "FloorMod" + input: "concat/axis" + input: "gradients_1/concat_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/mod" + op: "FloorMod" + input: "concat/axis" + input: "gradients/concat_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "zeros_2/Const" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.0 + } + } + } +} +node { + name: "mul_5/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_10/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_10/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 7 + } + } + } +} +node { + name: "strided_slice_10/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "strided_slice_9/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_9/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_9/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Slice_1/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_1/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_4/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_7/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_7/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "strided_slice_7/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "mul_3/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "zeros_1/Const" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.0 + } + } + } +} +node { + name: "mul_2/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_6/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_6/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "strided_slice_6/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_5/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_5/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_5/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "add/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "strided_slice_4/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_4/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_4/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "Slice/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients_2/Slice_grad/Reshape" + op: "Reshape" + input: "Slice/begin" + input: "gradients_2/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_grad/Reshape" + op: "Reshape" + input: "Slice/begin" + input: "gradients_1/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/Reshape" + op: "Reshape" + input: "Slice/begin" + input: "gradients/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_1/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_3/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_3/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_3/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "zeros/Const" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.0 + } + } + } +} +node { + name: "mul/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_2/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_2/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_2/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_1/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_1/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_1/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_2/shape/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Reshape_1/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\001\000\000\000\003\000\000\000" + } + } + } +} +node { + name: "strided_slice/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\t\000\000\000" + } + } + } +} +node { + name: "t_ef" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_1" + op: "Reshape" + input: "t_ef" + input: "Reshape_1/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "modifier_attr/ewald_beta" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.2 + } + } + } +} +node { + name: "modifier_attr/ewald_h" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 4.0 + } + } + } +} +node { + name: "modifier_attr/sys_charge_map" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "1 1 1 1 1" + } + } + } +} +node { + name: "modifier_attr/mdl_charge_map" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "-1 -3" + } + } + } +} +node { + name: "modifier_attr/type" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "dipole_charge" + } + } + } +} +node { + name: "modifier_attr/mdl_name" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "dipole.pb" + } + } + } +} +node { + name: "dipole_charge/Reshape_24/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: -1 + } + } + } +} +node { + name: "dipole_charge/concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/concat_2_grad/mod" + op: "FloorMod" + input: "dipole_charge/concat_2/axis" + input: "gradients_2/dipole_charge/concat_2_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/concat_2_grad/mod" + op: "FloorMod" + input: "dipole_charge/concat_2/axis" + input: "gradients_1/dipole_charge/concat_2_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/concat_2_grad/mod" + op: "FloorMod" + input: "dipole_charge/concat_2/axis" + input: "gradients/dipole_charge/concat_2_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Reshape_21/shape/2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "dipole_charge/strided_slice_28/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_28/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "dipole_charge/strided_slice_28/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "dipole_charge/strided_slice_27/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_27/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_27/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "dipole_charge/Reshape_20/shape/2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "dipole_charge/Reshape_20/shape/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_26/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_26/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "dipole_charge/strided_slice_26/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "dipole_charge/strided_slice_25/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_25/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_25/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "dipole_charge/final_layer_type_3/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "\010f=#\350\341\316?\264\215\323\207\016\261\326\277b&\350Mp\321\352\277\215l\303eV`\317\277\234\336\\\233A\211\376?\"\n\273\244\031\274\327\277\2068M7\371\361\326?S\336g\265\360{\373\277" + } + } + } +} +node { + name: "dipole_charge/final_layer_type_3/bias/read" + op: "Identity" + input: "dipole_charge/final_layer_type_3/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/final_layer_type_3/bias" + } + } + } +} +node { + name: "dipole_charge/final_layer_type_3/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\325\322\201\247\324\213\261?Z\266\325\277^|\272\277c\335\271\230\331\033\317\277\377\027\001\014\037f\262\277G\260\034\3056\230\341?\360\317\343\362\271\260\273\277\317\235\304J\0106\272?\333U\303\367\220\316\337\277U\307\252c\320\375\307?(\340\325|\341\007\314\277\2624\234\"}\212\247?@2\262\332\240\312\322\277\362?\345n\323\026\225?\217\274\026\364V\371\333?]\374Ef\353\353\313?\232\257\246u`c\300\277Ofh#kI\323\277\362 @\220m\223\346?\252\217f\024\277\377\270\277\357\275\001\371\312\010\303?\227\273\202\315\322\217\311?\374\2533\327\370E\306?\212\"\007p\356;\260?/\324r\002\030C\272\277@\257q5\200\222\276\277\277\365\256\205\301\321\255?\006\222\365\207b\024\211?t\250h\233\220_\343\277\210\023\3031j\352\323\277\314\304xd\016\262\302\277\374\353\353\3279\001\316\277(\235&\010\334\336\302\277" + } + } + } +} +node { + name: "dipole_charge/final_layer_type_3/matrix/read" + op: "Identity" + input: "dipole_charge/final_layer_type_3/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/final_layer_type_3/matrix" + } + } + } +} +node { + name: "dipole_charge/layer_2_type_3/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/layer_2_type_3/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\240\267\320ZqC\271?\343s\376\214\224\350\271?\254|\247\333\356\310\271?\200T\350\244\211#\271?" + } + } + } +} +node { + name: "dipole_charge/layer_2_type_3/idt/read" + op: "Identity" + input: "dipole_charge/layer_2_type_3/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/layer_2_type_3/idt" + } + } + } +} +node { + name: "dipole_charge/layer_2_type_3/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\214\355O\033\357\341\316?R\375QC\r\261\326\277\231\272\202\361\320\277\020z\273\242d\233\256?\n\354\200\347\014\376\326\277\242mr\345\324`\235?\223_y\257\316=\341?\224\230\205\221\377Q\321?*\364!\346\307\006\304\277" + } + } + } +} +node { + name: "dipole_charge/layer_2_type_3/matrix/read" + op: "Identity" + input: "dipole_charge/layer_2_type_3/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/layer_2_type_3/matrix" + } + } + } +} +node { + name: "dipole_charge/layer_1_type_3/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/layer_1_type_3/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\010$\315\236pC\271?2H\373\343\224\350\271?\247\177\230o\356\310\271? HA5\207#\271?" + } + } + } +} +node { + name: "dipole_charge/layer_1_type_3/idt/read" + op: "Identity" + input: "dipole_charge/layer_1_type_3/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/layer_1_type_3/idt" + } + } + } +} +node { + name: "dipole_charge/layer_1_type_3/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "^M\244g\357\341\316?#\324l*\r\261\326\277L9\377\334p\321\352\277V\034Q\0256\372\316\277" + } + } + } +} +node { + name: "dipole_charge/layer_1_type_3/bias/read" + op: "Identity" + input: "dipole_charge/layer_1_type_3/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/layer_1_type_3/bias" + } + } + } +} +node { + name: "dipole_charge/layer_1_type_3/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 4 + } + } + tensor_content: "W\265e\230Z\224\265?\'\330\272\034\240,\300\277~\220\267\332\033\007\323\277S8S>~\245\265\277\335\266\313\244c\217\345?\324\350\356\020t\351\300\277\214U\346X\201\030\300?\326+?\367\341]\343\277\316\000\303\360\273\323\315?\026e9\354\202\361\320\277\252se\336b\233\256?\260\250n\320\014\376\326\277h\251\353\000\324`\235?t\027\212\255\316=\341?\254\236^\177\377Q\321?\222\333\030\023\310\006\304\277" + } + } + } +} +node { + name: "dipole_charge/layer_1_type_3/matrix/read" + op: "Identity" + input: "dipole_charge/layer_1_type_3/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/layer_1_type_3/matrix" + } + } + } +} +node { + name: "dipole_charge/layer_0_type_3/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/layer_0_type_3/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "k8-Tv\344\316?h\007\225\326\205\227\326\277ET\321\207\355\320\352\277\315[\376\006E-\317\277" + } + } + } +} +node { + name: "dipole_charge/layer_0_type_3/bias/read" + op: "Identity" + input: "dipole_charge/layer_0_type_3/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/layer_0_type_3/bias" + } + } + } +} +node { + name: "dipole_charge/layer_0_type_3/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 32 + } + dim { + size: 4 + } + } + tensor_content: "\035\031\3517v\357\243?\340\t\034\036]\037\256\277K?\357\227\177\t\302\2773=T\257\330\310\244\277\010\302\324\241\240F\324?\021\203\273\316k\203\257\277\273+\375+\307\365\255?\263\305c\006_N\322\277#\1773\254e\212\273?\245x\310{\203\021\300\277\034\370\315\0025\222\232?\212\3060 Z\225\305\2772\274_\241\204\016\207?\230\340\007\331W5\320?&\377\354\222G\013\300?\301\'\261\014p\261\262\277\354\317\217\004\375\224\306\277Lt|%\304\002\332?\243\016\302\316\365\027\256\277\264\202\251\240\245\277\265?\204\0224\352\274\344\274?\271\310\'\206\031}\271?j\227\273\252\250\204\241?\336*N`\031\311\256\277&\021\340\247\tF\262\277\316J?\342j\301\240?\212\354\347\350&$s?\321\013\216\314\215m\326\277z\255\013\315\304N\307\277\331\333\303\350m\321\265\277y\365\264\307M\241\301\277\252\263\324\252)\005\266\277\350\245\257\220\241\320\234\277\t\265\243%Y\244\306\277\\S\301\363$e\301\277\326\216\202\337N\206\251\277\ne%O\270[\306?\252\227 \345\200\320\245?KY\367\372L>\221\277\374\303\275\253\036%\301\277\237m\304h\253F\274\277V\227q\243\310\031\324?\377\014\201\370?\323\312\277\266\337\322xE\266\254\277wv\346cQ\302\275?\241c\342\023\237\331\270\277T\230QWTU\315\277\264ifCO\266\203\277\232X\227\224\360\314\234?\260\276\263\341\036~\310?L\\\037\242\247\'\256\277\004\227\035\301\r\304\257\2778\354\3518\371\360\322?\265\202\254/\323\374\240\277\002\031>\263o\312\331\277\230\277:\'Z\222\266?C\037\252\231\017Y\230?\316\360\031a\223~\260\277\'\276\367\274\3610X\277P\265\362\355\213\350r?h\363\2116>\301\306?\245v\207\352\310\232\213?\317\367\244\344\200\034\314\277\325V\252\330e\324\247? \346\0253\316\341\271\277\021\023\257\327*\t|?\224\210\265\212\346\321\267\277\231\356\023\036\022\340\316?I\003\334\337\301\215\240?\005p+\370#\321\325?\216\345\363\365F\007\225\277\370\306\340m\200:\225?\004eT\025s\023\262\277\262L0\227\023%\271\277g\225\315\334\202+\305?\335G \3653\221\231?/;\231m|r\320\277\036\364\322,(\006\314\277Z\203gv\326\302\314?\037\205\303Z\230\226\303?\200\311R\005\263\247\303?\206>\027=\307\203\205?\234\355\204\206\232\213\267\277\376\227\003\204,\300\277\277\205\231\020\"U\337\304\277I\246\004j\025\251\330?\364}\006:\005\272\271?\270N]-\240\026\242?\371\343~\324u\000\325?Jd\217\005\262\r\320?GW/\262\201\221\302\277\t\314?QN\246\302\277\315\231\352\247>?\255\277\005\305\303m\353\242\225?\266\203sI\311Y\243\2779\200\034\250\351\301\304\277\250\344V\352\226\002\204\277K\t\213\021\327\035\305?\205{l-(\361\312?u1\013W\315X\306\277\327\222\005*\364h\267\2771\321\217np\022\310\277\357\245;\3666\025\270?\210\246\302\2345\333\244?\333\364iQ%\372b\277\274\023\303\020\304\030\300\277_\035\214\316\201\037\303?\222w}T\320\227\315\277+\323\'\232i\\\272\277\027\317\320\3779\010\321?\376y`\010\024w\306?\366\271C\206\220\362\217?(\031O\366\324\001\262?\332!\311\'\360\342\300?\tZ\315Mg\227\311\277\342V\326S\276\207\324\277P\261\245\373%5\250\277q\3555o\230V\244\277\354\'s\226T\264\271\277R<\020\226\243k\300\277J\323q\036\331:\272?\205\325\254\330\274[\265\277\246\365qh\342p\274?B\320\003\3154\251\241\277*\317e\212\034\020\310?\204#\232\371$\367\265?g\022=\273\361\t\244\277ZO|\030$\255\300?" + } + } + } +} +node { + name: "dipole_charge/layer_0_type_3/matrix/read" + op: "Identity" + input: "dipole_charge/layer_0_type_3/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/layer_0_type_3/matrix" + } + } + } +} +node { + name: "dipole_charge/Reshape_19/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\010\000\000\000\003\000\000\000" + } + } + } +} +node { + name: "dipole_charge/Slice_7/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "dipole_charge/Slice_7/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "dipole_charge/mul_21/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 24 + } + } + } +} +node { + name: "dipole_charge/strided_slice_23/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_23/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "dipole_charge/strided_slice_23/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "dipole_charge/mul_20/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 24 + } + } + } +} +node { + name: "dipole_charge/Reshape_18/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "dipole_charge/Slice_6/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "dipole_charge/Slice_6/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "dipole_charge/mul_19/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "dipole_charge/strided_slice_22/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_22/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 6 + } + } + } +} +node { + name: "dipole_charge/strided_slice_22/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "dipole_charge/mul_18/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "dipole_charge/strided_slice_21/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_21/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 5 + } + } + } +} +node { + name: "dipole_charge/strided_slice_21/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "dipole_charge/Reshape_15/shape/2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "dipole_charge/strided_slice_18/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_18/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "dipole_charge/strided_slice_18/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "dipole_charge/strided_slice_17/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_17/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_17/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "dipole_charge/Reshape_14/shape/2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "dipole_charge/Reshape_14/shape/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_16/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_16/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "dipole_charge/strided_slice_16/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "dipole_charge/strided_slice_15/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_15/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_15/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "dipole_charge/final_layer_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + } + tensor_content: "q\031x\225\350\341\316?3\202\350S\016\261\326\277w>H0p\321\352\2774m\001\362U`\317\277\030\247h\250A\211\376?\313+=w\031\274\327\277-t\332p\371\361\326?\326\335\026\246\360{\373\277" + } + } + } +} +node { + name: "dipole_charge/final_layer_type_1/bias/read" + op: "Identity" + input: "dipole_charge/final_layer_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/final_layer_type_1/bias" + } + } + } +} +node { + name: "dipole_charge/final_layer_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "4\325\343\277\325\213\261?c3w\313]|\272\277(\375(\027\331\033\317\277\007\315\003\027\036f\262\277\257\370\355\3456\230\341?\215\021\327\036\271\260\273\277\350\'\375V\t6\272?\244\317`\272\220\316\337\277*\0146\372\320\375\307?\035X\252\373\340\007\314\277\342\351\2431\177\212\247?R\246(\235\240\312\322\277\n;I\341\327\026\225?\"w\330+W\371\333?\223\213\301\362\353\353\313?:p\t\376_c\300\277\n3\036YkI\323\277\346N\247wm\223\346?\036\374k\362\277\377\270\277S\213\324\213\312\010\303?xl\231k\322\217\311?\213\2643\201\370E\306?.ob\230\355;\260?\275k\036\350\030C\272\277Q\257\217E\201\222\276\277\241}\016\252\277\321\255?lF\242\226Z\024\211?U\362\206\271\220_\343\277\005\237Hqj\352\323\277\217Y\225\313\016\262\302\277\267\013\256Z:\001\316\277\352\331\227\201\334\336\302\277" + } + } + } +} +node { + name: "dipole_charge/final_layer_type_1/matrix/read" + op: "Identity" + input: "dipole_charge/final_layer_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/final_layer_type_1/matrix" + } + } + } +} +node { + name: "dipole_charge/layer_2_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/layer_2_type_1/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\206\357\242\315qC\271?\234\311\304\277\223\350\271?\342M~3\356\310\271?\242B\372\"\213#\271?" + } + } + } +} +node { + name: "dipole_charge/layer_2_type_1/idt/read" + op: "Identity" + input: "dipole_charge/layer_2_type_1/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/layer_2_type_1/idt" + } + } + } +} +node { + name: "dipole_charge/layer_2_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "6\234\020\r\356\341\316?\254KF5\r\261\326\277\241\316T\336p\321\352\277\336*(\2256\372\316\277" + } + } + } +} +node { + name: "dipole_charge/layer_2_type_1/bias/read" + op: "Identity" + input: "dipole_charge/layer_2_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/layer_2_type_1/bias" + } + } + } +} +node { + name: "dipole_charge/layer_2_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 4 + } + } + tensor_content: "[\006r2\372\316\277" + } + } + } +} +node { + name: "dipole_charge/layer_0_type_1/bias/read" + op: "Identity" + input: "dipole_charge/layer_0_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/layer_0_type_1/bias" + } + } + } +} +node { + name: "dipole_charge/layer_0_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 32 + } + dim { + size: 4 + } + } + tensor_content: "s\246\366QO\354\243?\347\025\177\327\230\353\256\277\267vK@\246\n\302\277\300\026%o\223\374\243\277X\201\256\3725F\324?\352p\033\261\326\'\260\277\300@~\353\323\361\255?\003\334p\264\3254\322\277\230^+\334\270\210\273?\000\211\336\234\222D\300\277\243w\253\370\301\212\232?\"-7\251Hb\305\277\360\002O\202\241\003\207?\342|\013\332\315\033\320?Y|\367[\255\n\300?{0w\212JK\262\277NQ\334R\322\225\306\277t\010\r\363;\351\331?\236\371@\017\351\033\256\277y)u\350\312%\266?.\362\275\034\374\342\274?Q_\222\002\367\026\271?\357\024\006\235\306\200\241?/Q\333\264\313\374\255\277s\241\000\361\314G\262\277B=;-R\352\237?c\177-\014$\006s?7kHw\004T\326\277\007\331n\334\267O\307\277\034\366 \342\2177\266\277\365\270\214\363\362\241\301\277\374\020L\272\004\237\265\277\020(\320\320T\327\234\277d\305\271Fh\327\306\277l\243\005U\023f\301\2776)\234\003\t\272\250\277\344\034\225\252\326Z\306?}\353~\031?\004\245?\225\364%\262\315E\221\277\307\2022\001\014\362\300\277t\023\350eqH\274\2770\314?\305@\000\324?\327\266U\345(\324\312\277?\221ix\375\351\253\277\325\234\323cg\300\275?&qV\"\277?\271\277 +C?\371U\315\277\306:\371S6\205\200\277\370\373\016\005\177\307\234?C\367\272\343\nK\310?~g\365}\020*\256\277u\250\251\274\302\367\256\277uV8\261\177\360\322?9\267f\"\027\311\241\277\302\372)I\302\312\331\277Fb\303\027\177\370\266?\265\270^\231gQ\230?S\376\215o\263\344\260\277\375#\301\265e\203X\277(\023\315\314\275Jy?\t\345\237\375X\300\306?\277\277<\t+k\210?\007\337\206\340\032\035\314\277\026\002\007fK\240\250?W\264\317#\\\343\271\277\300\023\356*<\247u?.o\002N4\324\267\277\374\317\241\353#\023\317?\236m\032\217z\212\240?\230 \273q\233\267\325?V\375\312\271\374\016\225\277X0\264h\032\323\226?bpH\321\030\025\262\277BS\212\0043\213\271\2776\023\376S\233*\305?D>\003\005\304)\233?\303\021\343\373\262r\320\277\315\231\301\301w8\314\277\036.\362n?\302\314?i\345\337\007\334\310\303?\345\007\024\024\332\246\303?\266}\271\036\262R\202?\343\231\354\211_\215\267\277\026J\030\223\005Z\277\2779\312h\n8\340\304\277\212E\251\244\214\217\330?ko\226\r3\270\271?w-n\324\356\342\242?g\247I\276\003\000\325?0\275\235>S\350\317?\035]\222\252d\222\302\277\330\205\200X;s\302\277\016\227\233\351\020C\255\277(\354\355\266n\n\224?\t[\036C\\\\\243\277\242\206\323~\330\216\304\277\364\214\262:]\017\204\277\006\241V\n\310\352\304?\213\246\350$\031\360\312?\377\210\251\361\273%\306\277\203\326\025h\243j\267\2772\177\303\342\200E\310\277\364\344\354\336O\023\270?\177\261\315]\200\247\245?\022\026,\321V0c\277%\306\213r\323K\300\277m\270V\270\231\036\303?\0005\215\243\276d\315\277\352\355\257I\t^\272\277\021\375\n&\260\356\320?\262&\205zvv\306?\274\353\322(\353\221\221?\3564J\271\026\000\262?\201s\007E\342\257\300?m\330\377=\010\230\311\277\355\247A}6n\324\277c\246T\024\3778\250\277\003V\320J\327\"\245\277\251\340Ec\363\265\271\277]\270O\261\2218\300\2774:\330\037\3518\272?\367ZH\366\333\301\265\277o\365\316\302Co\274?m\373\345\324\355\334\240\277g-\\\337\t\017\310?\330\262\000$\016\221\265??\355\036\337\215\014\244\2775\267P:1\340\300?" + } + } + } +} +node { + name: "dipole_charge/layer_0_type_1/matrix/read" + op: "Identity" + input: "dipole_charge/layer_0_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/layer_0_type_1/matrix" + } + } + } +} +node { + name: "dipole_charge/strided_slice_14/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_14/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "dipole_charge/strided_slice_14/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "dipole_charge/Reshape_13/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\010\000\000\000\003\000\000\000" + } + } + } +} +node { + name: "dipole_charge/Slice_3/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "dipole_charge/Slice_3/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "dipole_charge/mul_12/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 24 + } + } + } +} +node { + name: "dipole_charge/strided_slice_13/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_13/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "dipole_charge/strided_slice_13/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "dipole_charge/mul_11/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 24 + } + } + } +} +node { + name: "dipole_charge/Reshape_12/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "dipole_charge/Slice_2/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "dipole_charge/Slice_2/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "dipole_charge/mul_10/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "dipole_charge/strided_slice_12/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_12/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "dipole_charge/strided_slice_12/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "dipole_charge/mul_9/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "dipole_charge/add/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "dipole_charge/strided_slice_11/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_11/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "dipole_charge/strided_slice_11/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "dipole_charge/Reshape_9/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "dipole_charge/mul_6/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 24 + } + } + } +} +node { + name: "dipole_charge/strided_slice_8/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_8/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_8/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "dipole_charge/Reshape_8/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "dipole_charge/mul_5/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "dipole_charge/strided_slice_7/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_7/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_7/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "dipole_charge/mul_4/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "dipole_charge/mul_3/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "dipole_charge/strided_slice_6/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_6/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_6/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "dipole_charge/strided_slice_5/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_5/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_5/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "dipole_charge/mul_2/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 32 + } + } + } +} +node { + name: "dipole_charge/strided_slice_4/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_4/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_4/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "dipole_charge/strided_slice_3/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_3/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_3/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_35/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377 \000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/transpose/perm" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\000\000\000\000\002\000\000\000\001\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/transpose_grad/InvertPermutation" + op: "InvertPermutation" + input: "dipole_charge/filter_type_all/transpose/perm" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/transpose_grad/InvertPermutation" + op: "InvertPermutation" + input: "dipole_charge/filter_type_all/transpose/perm" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/transpose_grad/InvertPermutation" + op: "InvertPermutation" + input: "dipole_charge/filter_type_all/transpose/perm" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_11/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\003\000\000\000\377\377\377\377" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_11/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\000\000\000\000\001\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_11/begin" + input: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_11/begin" + input: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_11_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_11/begin" + input: "gradients/dipole_charge/filter_type_all/Slice_11_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_10/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_10/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\000\000\000\000\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_10/begin" + input: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_10/begin" + input: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_10_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_10/begin" + input: "gradients/dipole_charge/filter_type_all/Slice_10_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/mul/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.04 + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_34/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_33/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_14/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_14_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_14/axis" + input: "gradients_2/dipole_charge/filter_type_all/concat_14_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_14_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_14/axis" + input: "gradients_1/dipole_charge/filter_type_all/concat_14_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_14_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_14/axis" + input: "gradients/dipole_charge/filter_type_all/concat_14_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_32/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_3_4" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\006\330\001<\361\341\316?\254t\013\\\002~\326\2772\335^\351\345\267\352\277\304\332\003\372;\372\316\277\201\250!\200\326\225\376?\032\000m\014\t\211\327\277\200W/\240\365\361\326?\212\355\307\225>o\373\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_3_4/read" + op: "Identity" + input: "dipole_charge/filter_type_all/bias_3_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/bias_3_4" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_3_4" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\261Z\2731\346\213\261?\305C\260)/\260\271\277 R/?\256\265\316\277\266\315Vh\323\231\261\277N5\350\234<\230\341?\230|C*x\344\272\277`\335\342n\3715\272?\301\260\272\3212\234\337\277\267)\253\354\330\375\307??\375\350\265\311\241\313\277\2740\034\365*#\251?\023J\371\320\275\227\322\277\214\362?B\r\030\225?N^\232fg,\334?\026\n4\321\343\353\313?Cs\025\206Yb\300\277\004I\347\264w|\323\277\271\312\034\317j\223\346?E\374\357:\255\377\270\277\344\0374\237\276\010\303?\035\321\357\200\315)\311?\310\006Y\222\366E\306?\234%\315\3175\337\256?6SG\376H\014\273\277\224_\247m\261^\277\277H#\343w\230\321\255?T\344\006\005\373\024\211?\037W\324+\224_\343\277c\022][e\035\324\277i\363\034\361\017\262\302\277\337\376J\tcg\316\277\334\244\221\037\344B\303\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_3_4/read" + op: "Identity" + input: "dipole_charge/filter_type_all/matrix_3_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/matrix_3_4" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_13/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_13_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_13/axis" + input: "gradients_2/dipole_charge/filter_type_all/concat_13_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_13_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_13/axis" + input: "gradients_1/dipole_charge/filter_type_all/concat_13_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_13_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_13/axis" + input: "gradients/dipole_charge/filter_type_all/concat_13_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_31/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_2_4" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\232+_o\007H\317?\336\243\276\035\372}\326\277\247\321Ae\346\267\352\277N\305\3411<\372\316\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_2_4/read" + op: "Identity" + input: "dipole_charge/filter_type_all/bias_2_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/bias_2_4" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_2_4" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "T\371\334\177\266\372\270?\266\304\271\032\"?\302\277\312K\255t\242\301\325\277E\314\346\214\205\016\271\2778\317\260\2045\347\350?/\010\314,,\031\303\277q\262\231u\006\004\303?&Ty;\327^\346\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_2_4/read" + op: "Identity" + input: "dipole_charge/filter_type_all/matrix_2_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/matrix_2_4" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_12/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_12_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_12/axis" + input: "gradients_2/dipole_charge/filter_type_all/concat_12_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_12_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_12/axis" + input: "gradients_1/dipole_charge/filter_type_all/concat_12_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_12_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_12/axis" + input: "gradients/dipole_charge/filter_type_all/concat_12_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_30/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_1_4" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "1\373~<\346\341\316?!\212*F\373}\326\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_1_4/read" + op: "Identity" + input: "dipole_charge/filter_type_all/bias_1_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/bias_1_4" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_1_4" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\005d \014\343\276\301?\325\033\376u\'\343\311\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_1_4/read" + op: "Identity" + input: "dipole_charge/filter_type_all/matrix_1_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/matrix_1_4" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_29/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_9/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_9/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_9/begin" + input: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_9/begin" + input: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_9_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_9/begin" + input: "gradients/dipole_charge/filter_type_all/Slice_9_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_28/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_8/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\024\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_8/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000P\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_8/begin" + input: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_8/begin" + input: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_8_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_8/begin" + input: "gradients/dipole_charge/filter_type_all/Slice_8_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_27/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_26/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_11/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_11_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_11/axis" + input: "gradients_2/dipole_charge/filter_type_all/concat_11_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_11_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_11/axis" + input: "gradients_1/dipole_charge/filter_type_all/concat_11_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_11_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_11/axis" + input: "gradients/dipole_charge/filter_type_all/concat_11_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_25/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_3_3" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\221*\337:\010H\317?\027\363\322A\377}\326\277}\261Zt\350\267\352\277\221!A\026G\372\316\277\345{\t\350Z\211\376?tq&O\n\211\327\277OV3\335\311$\327?\246+\tY0o\373\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_3_3/read" + op: "Identity" + input: "dipole_charge/filter_type_all/bias_3_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/bias_3_3" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_3_3" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\303=8\200\027\214\261?!Xch\033|\272\277\205/\317\252\261\033\317\277\361\375\311\365\350d\262\277\3359JI\023\260\341?F\201\021\332P\260\273\277\202\361\022\351O8\272?\307\017\236b\363\315\337\277\352\234I@\323\375\307?w\243~F\334\007\314\277{\001\215\241\216\212\247?\353\350z\226\224\312\322\277A\342\2010\217?\230?\277\"\347\006Z\371\333?^\322J\326r\354\313?Y\t \3655c\300\2779w\315qz|\323\277\351+\364D\346y\346?Y\016P^\372\313\271\277\233\0014\356\302\242\302?Lu[\346\254\216\311?\247C\357\206\334\337\305?\3538\250\326x\341\256?\002\366\002q\377\016\273\277\217\301\344\332\264^\277\277\310jW\343\\9\254?e\030\230\245\330\262\202?\336b \010\016y\343\277\031\007\206\263n\353\323\277\230\3512#$\030\303\277\225\241H\240\274f\316\277\021\223\020\216\250D\303\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_3_3/read" + op: "Identity" + input: "dipole_charge/filter_type_all/matrix_3_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/matrix_3_3" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_10/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_10_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_10/axis" + input: "gradients_2/dipole_charge/filter_type_all/concat_10_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_10_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_10/axis" + input: "gradients_1/dipole_charge/filter_type_all/concat_10_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_10_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_10/axis" + input: "gradients/dipole_charge/filter_type_all/concat_10_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_24/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_2_3" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\001\320P6\376G\317?\013\274\325\211\376}\326\277\203\267,\257\351\267\352\277x\254\310\2666\372\316\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_2_3/read" + op: "Identity" + input: "dipole_charge/filter_type_all/bias_2_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/bias_2_3" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_2_3" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "/|\010\214\243\305\271?\346}p$K?\302\277 1\341S\332\301\325\277`H\037oA\021\271\277\215fT\2709\347\350?ym\021,Q\177\303\277\\\321\r\277\347\235\302?\225\026N\341\\x\346\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_2_3/read" + op: "Identity" + input: "dipole_charge/filter_type_all/matrix_2_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/matrix_2_3" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_9/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_9_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_9/axis" + input: "gradients_2/dipole_charge/filter_type_all/concat_9_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_9_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_9/axis" + input: "gradients_1/dipole_charge/filter_type_all/concat_9_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_9_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_9/axis" + input: "gradients/dipole_charge/filter_type_all/concat_9_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_23/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_1_3" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\353W\301\230\001H\317?\225z\037\333\376}\326\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_1_3/read" + op: "Identity" + input: "dipole_charge/filter_type_all/bias_1_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/bias_1_3" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_1_3" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\224f{\001\364\276\301?\366\361\330\036FI\312\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_1_3/read" + op: "Identity" + input: "dipole_charge/filter_type_all/matrix_1_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/matrix_1_3" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_22/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_7/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_7/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_7/begin" + input: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_7/begin" + input: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_7_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_7/begin" + input: "gradients/dipole_charge/filter_type_all/Slice_7_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_21/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_6/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\024\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_6/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000<\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_6/begin" + input: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_6/begin" + input: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_6_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_6/begin" + input: "gradients/dipole_charge/filter_type_all/Slice_6_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_20/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_19/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_8/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_8_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_8/axis" + input: "gradients_2/dipole_charge/filter_type_all/concat_8_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_8_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_8/axis" + input: "gradients_1/dipole_charge/filter_type_all/concat_8_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_8_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_8/axis" + input: "gradients/dipole_charge/filter_type_all/concat_8_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_18/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_3_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: ">\022uq\360\341\316?M\230&#\002~\326\277\215#r1\346\267\352\277\217T\\UB\372\316\277L\367\002\262N\211\376?r\326Z)\t\211\327\277\2267\332/\366\361\326?\372DCY0o\373\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_3_2/read" + op: "Identity" + input: "dipole_charge/filter_type_all/bias_3_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/bias_3_2" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_3_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "Z\350\244\240\344\213\261?\232\321\247\276.\260\271\277\254\236\254\004\257\265\316\277J\030\236\310\317\231\261\277\262\237\333\245<\230\341?x\360\367\240x\344\272\277\273\030\307\261\3735\272?-\352\231\332e\315\337\277\360yN\037\330\375\307?\344\323\334\204\311\241\313\277h\301\245B(#\251?\357\354\014Y\242\227\322\277\364\264\326Y\325\030\225?\302;\374Jg,\334?\377\026\307\356\344\353\313?\255k\230\2504c\300\277~k\020\031x|\323\277V\343\275\332j\223\346?j\351\354\254\256\377\270\277s\303\313\022\310\010\303?\"\336C\262\330)\311?\023\251dV\366E\306?\356\322>X:\337\256?\374?\007y\373\016\273\277wt\021\005\263^\277\277\360\257\353H\231\321\255?\266=96\357\024\211?\203\355\030\303\221_\343\277\354\031\213o_\035\324\277\365Z\315)\020\262\302\277\312\215\243\352ag\316\277\233z\346\356\242D\303\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_3_2/read" + op: "Identity" + input: "dipole_charge/filter_type_all/matrix_3_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/matrix_3_2" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_7/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_7_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_7/axis" + input: "gradients_2/dipole_charge/filter_type_all/concat_7_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_7_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_7/axis" + input: "gradients_1/dipole_charge/filter_type_all/concat_7_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_7_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_7/axis" + input: "gradients/dipole_charge/filter_type_all/concat_7_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_17/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_2_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\2515l\244\372G\317?\206b:\210\372}\326\277\001+\205\233\346\267\352\277\024\031\330\1774\372\316\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_2_2/read" + op: "Identity" + input: "dipole_charge/filter_type_all/bias_2_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/bias_2_2" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_2_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "?\356\305#\264\372\270?!\032\377\324\"?\302\277\303D>\277\242\301\325\277\360l\250z\205\016\271\277\010\255\304\3205\347\350?G\263d\340,\031\303\277#C(\361\005\004\303?\377\344\307\025\327^\346\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_2_2/read" + op: "Identity" + input: "dipole_charge/filter_type_all/matrix_2_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/matrix_2_2" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_6/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_6_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_6/axis" + input: "gradients_2/dipole_charge/filter_type_all/concat_6_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_6_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_6/axis" + input: "gradients_1/dipole_charge/filter_type_all/concat_6_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_6_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_6/axis" + input: "gradients/dipole_charge/filter_type_all/concat_6_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_16/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_1_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\302I\345\314\346\341\316?B\265\350\244\373}\326\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_1_2/read" + op: "Identity" + input: "dipole_charge/filter_type_all/bias_1_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/bias_1_2" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_1_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\304\267\305\236\343\276\301?\264\207\255.(\343\311\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_1_2/read" + op: "Identity" + input: "dipole_charge/filter_type_all/matrix_1_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/matrix_1_2" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_15/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_5/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_5/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_5/begin" + input: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_5/begin" + input: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_5_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_5/begin" + input: "gradients/dipole_charge/filter_type_all/Slice_5_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_14/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_4/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\024\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_4/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000(\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_4/begin" + input: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_4/begin" + input: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_4_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_4/begin" + input: "gradients/dipole_charge/filter_type_all/Slice_4_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_13/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_12/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_5/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_5_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_5/axis" + input: "gradients_2/dipole_charge/filter_type_all/concat_5_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_5_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_5/axis" + input: "gradients_1/dipole_charge/filter_type_all/concat_5_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_5_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_5/axis" + input: "gradients/dipole_charge/filter_type_all/concat_5_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_11/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\366)\337:\010H\317?\355\363\322A\377}\326\277\326\260Zt\350\267\352\277\225\"A\026G\372\316\277e{\t\350Z\211\376?\361p&O\n\211\327\277:V3\335\311$\327?\224*\tY0o\373\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_3_1/read" + op: "Identity" + input: "dipole_charge/filter_type_all/bias_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/bias_3_1" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\031\2427\200\027\214\261?-\364ch\033|\272\277\336\200\317\252\261\033\317\277\326\254\312\365\350d\262\277#OJI\023\260\341?\313\037\022\332P\260\273\277\215\357\021\351O8\272?\334<\236b\363\315\337\277\221\234I@\323\375\307?\274\242~F\334\007\314\277\025\363\214\241\216\212\247?\362\350z\226\224\312\322\277_\010\2020\217?\230?\302!\347\006Z\371\333?\345\320J\326r\354\313?\355\022 \3655c\300\277\377x\315qz|\323\277E+\364D\346y\346?\370\033P^\372\313\271\277\374\3753\356\302\242\302?g|[\346\254\216\311?z>\357\206\334\337\305?#\035\250\326x\341\256?x\017\003q\377\016\273\277\215\334\344\332\264^\277\277\3627W\343\\9\254?\377\013\227\245\330\262\202?\212f \010\016y\343\277\203\377\205\263n\353\323\277\251\3702#$\030\303\277\203\271H\240\274f\316\277\274\251\020\216\250D\303\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_3_1/read" + op: "Identity" + input: "dipole_charge/filter_type_all/matrix_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/matrix_3_1" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_4/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_4_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_4/axis" + input: "gradients_2/dipole_charge/filter_type_all/concat_4_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_4_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_4/axis" + input: "gradients_1/dipole_charge/filter_type_all/concat_4_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_4_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_4/axis" + input: "gradients/dipole_charge/filter_type_all/concat_4_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_10/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "T\351\255*\376G\317?\256\247\350\212\376}\326\277\2477\376\257\351\267\352\277\nX\312\3056\372\316\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_2_1/read" + op: "Identity" + input: "dipole_charge/filter_type_all/bias_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/bias_2_1" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "g\324\332w\243\305\271?\025}(&K?\302\277\351xFU\332\301\325\277?\247]\207A\021\271\277ncF\2739\347\350?\275\307\344)Q\177\303\277A\257]\302\347\235\302?\205\321t\335\\x\346\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_2_1/read" + op: "Identity" + input: "dipole_charge/filter_type_all/matrix_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/matrix_2_1" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_3/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_3_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_3/axis" + input: "gradients_2/dipole_charge/filter_type_all/concat_3_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_3_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_3/axis" + input: "gradients_1/dipole_charge/filter_type_all/concat_3_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_3_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_3/axis" + input: "gradients/dipole_charge/filter_type_all/concat_3_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_9/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "&\250\235\216\001H\317?\257E\367\333\376}\326\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_1_1/read" + op: "Identity" + input: "dipole_charge/filter_type_all/bias_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/bias_1_1" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\336\243\244\013\364\276\301?#\004(\035FI\312\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_1_1/read" + op: "Identity" + input: "dipole_charge/filter_type_all/matrix_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/matrix_1_1" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_8/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_3/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_3/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_3/begin" + input: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_3/begin" + input: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_3_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_3/begin" + input: "gradients/dipole_charge/filter_type_all/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_7/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_2/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\024\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_2/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\024\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_2/begin" + input: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_2/begin" + input: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_2_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_2/begin" + input: "gradients/dipole_charge/filter_type_all/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_6/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\005\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_2_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_2/axis" + input: "gradients_2/dipole_charge/filter_type_all/concat_2_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_2_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_2/axis" + input: "gradients_1/dipole_charge/filter_type_all/concat_2_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_2_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_2/axis" + input: "gradients/dipole_charge/filter_type_all/concat_2_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_4/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\210\235\221\342\350\341\316?\020\217\2249\373}\326\277\002a0\303\346\267\352\2776\216=\245(\372\316\277\000\225\246\007E\211\376?\347@\373\256\005\211\327\2777(N~\370\361\326?4\363\353).o\373\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_3_0/read" + op: "Identity" + input: "dipole_charge/filter_type_all/bias_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/bias_3_0" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\345\233\361L\325\213\261?\377\240D\245\021\260\271\277H1W.\262\265\316\277f\225H\313\301\231\261\277J.f_8\230\341?\026\020\314pj\344\272\277\321\306-}\0066\272?\2573\017\030\202\233\337\277>\247|\200\317\375\307?\277\264\335\353\271\241\313\277\342q5\236\035#\251?\347i\241\377\211\227\322\277\2023\331\375\231\030\225?g\237\2606k,\334?\r1\202\227\352\353\313?b\016\226\233\230\373\277\277\273\235\377\360{|\323\277\344\373\312\206n\223\346?\216b\0132\265\377\270\277\256](\224\326\010\303?MB\002\221\304)\311?\2615\346r\375E\306?\334!\340\265Q\337\256?\355\343\267\313BC\272\277\223=d\262\303^\277\277\257\242\036\037\326\321\255?\207\344M\303\263\024\211?\216\216G\330\215_\343\277#\324\372AY\035\324\277\324N*\236\010\262\302\2778)*8\\g\316\277\020\307\336\275:\337\302\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_3_0/read" + op: "Identity" + input: "dipole_charge/filter_type_all/matrix_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/matrix_3_0" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_1/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_1_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_1/axis" + input: "gradients_2/dipole_charge/filter_type_all/concat_1_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_1_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_1/axis" + input: "gradients_1/dipole_charge/filter_type_all/concat_1_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_1_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat_1/axis" + input: "gradients/dipole_charge/filter_type_all/concat_1_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "=\377\373\306\345\341\316?\372\303\351>\372}\326\277;L\251h\346\267\352\277R\320f\0220\372\316\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_2_0/read" + op: "Identity" + input: "dipole_charge/filter_type_all/bias_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/bias_2_0" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "`v\201C\261\372\270?\372-\367\357!?\302\277\353}e\371\242\301\325\277\241\302\306Y\204\016\271\277\246\354c\3164\347\350?\234\313\330\204+\031\303\277\206\213\345\324\005\004\303?\006\272\370\256\326^\346\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_2_0/read" + op: "Identity" + input: "dipole_charge/filter_type_all/matrix_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/matrix_2_0" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat/axis" + input: "gradients_2/dipole_charge/filter_type_all/concat_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat/axis" + input: "gradients_1/dipole_charge/filter_type_all/concat_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_grad/mod" + op: "FloorMod" + input: "dipole_charge/filter_type_all/concat/axis" + input: "gradients/dipole_charge/filter_type_all/concat_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_2/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\256tQX\350\341\316?\257\246\353\020\373}\326\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/bias_1_0/read" + op: "Identity" + input: "dipole_charge/filter_type_all/bias_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/bias_1_0" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\351\004\003L\345\276\301?\356\2304\304&\343\311\277" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/matrix_1_0/read" + op: "Identity" + input: "dipole_charge/filter_type_all/matrix_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/filter_type_all/matrix_1_0" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_1/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_1/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_1/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_1/begin" + input: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_1/begin" + input: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_1_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_1/begin" + input: "gradients/dipole_charge/filter_type_all/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\024\000\000\000" + } + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice/begin" + input: "gradients_2/dipole_charge/filter_type_all/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice/begin" + input: "gradients_1/dipole_charge/filter_type_all/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_grad/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice/begin" + input: "gradients/dipole_charge/filter_type_all/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377d\000\000\000" + } + } + } +} +node { + name: "dipole_charge/Reshape_4/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "dipole_charge/mul_1/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 100 + } + } + } +} +node { + name: "dipole_charge/strided_slice_2/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_2/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_2/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "dipole_charge/Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377d\000\000\000" + } + } + } +} +node { + name: "dipole_charge/Reshape_2/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_1/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice_1/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "dipole_charge/strided_slice_1/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/Reshape_1/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\t\000\000\000" + } + } + } +} +node { + name: "dipole_charge/Reshape/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "dipole_charge/mul/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "dipole_charge/strided_slice/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/strided_slice/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "dipole_charge/strided_slice/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "dipole_charge/descrpt_attr/t_std" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 5 + } + dim { + size: 100 + } + } + tensor_content: "\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?\225\331\\v\302Q\237?&\322\337\257r\221\222?&\322\337\257r\221\222?&\322\337\257r\221\222?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?3\315\005\256\250\244\260?`\312\337\323gw\243?`\312\337\323gw\243?`\312\337\323gw\243?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\307\210\025\363\200!\266?\344t|M\016\352\251?\344t|M\016\352\251?\344t|M\016\352\251?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\000y\326\033\205\337\224?\327\372\214TG5\210?\327\372\214TG5\210?\327\372\214TG5\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?\327GP\271N-\225?\347WF>\366\271\210?\347WF>\366\271\210?\347WF>\366\271\210?" + } + } + } +} +node { + name: "dipole_charge/descrpt_attr/t_std/read" + op: "Identity" + input: "dipole_charge/descrpt_attr/t_std" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/descrpt_attr/t_std" + } + } + } +} +node { + name: "dipole_charge/descrpt_attr/t_avg" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 5 + } + dim { + size: 100 + } + } + tensor_content: "\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\3242\311\205\346}?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034lb#\255\306\210?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336\336\323I\335\021\222?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\006\333\210\244\336g?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\254jY\240\342m?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "dipole_charge/descrpt_attr/t_avg/read" + op: "Identity" + input: "dipole_charge/descrpt_attr/t_avg" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@dipole_charge/descrpt_attr/t_avg" + } + } + } +} +node { + name: "dipole_charge/descrpt_attr/ntypes" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 5 + } + } + } +} +node { + name: "dipole_charge/descrpt_attr/rcut" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 4.0 + } + } + } +} +node { + name: "dipole_charge/model_attr/output_dim" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "dipole_charge/model_attr/model_type" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "dipole" + } + } + } +} +node { + name: "dipole_charge/model_attr/sel_type" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\003\000\000\000" + } + } + } +} +node { + name: "dipole_charge/model_attr/tmap" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "A B C D E" + } + } + } +} +node { + name: "dipole_charge/t_mesh" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "dipole_charge/t_natoms" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: 7 + } + } + } + } +} +node { + name: "strided_slice_45" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_45/stack" + input: "strided_slice_45/stack_1" + input: "strided_slice_45/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_27" + op: "Mul" + input: "strided_slice_45" + input: "mul_27/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_14/shape" + op: "Pack" + input: "Reshape_14/shape/0" + input: "mul_27" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_44" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_44/stack" + input: "strided_slice_44/stack_1" + input: "strided_slice_44/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_26" + op: "Mul" + input: "strided_slice_44" + input: "mul_26/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_41" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_41/stack" + input: "strided_slice_41/stack_1" + input: "strided_slice_41/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_25" + op: "Mul" + input: "strided_slice_41" + input: "mul_25/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_12/size" + op: "Pack" + input: "Slice_12/size/0" + input: "mul_25" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_40" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_40/stack" + input: "strided_slice_40/stack_1" + input: "strided_slice_40/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_23" + op: "Mul" + input: "strided_slice_40" + input: "mul_23/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_38" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_38/stack" + input: "strided_slice_38/stack_1" + input: "strided_slice_38/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "add_17" + op: "Add" + input: "add_17/x" + input: "strided_slice_38" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_24" + op: "Mul" + input: "add_17" + input: "mul_24/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_12/begin" + op: "Pack" + input: "Slice_12/begin/0" + input: "mul_24" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_37" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_37/stack" + input: "strided_slice_37/stack_1" + input: "strided_slice_37/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_22" + op: "Mul" + input: "strided_slice_37" + input: "mul_22/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_11/size" + op: "Pack" + input: "Slice_11/size/0" + input: "mul_22" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_36" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_36/stack" + input: "strided_slice_36/stack_1" + input: "strided_slice_36/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_21" + op: "Mul" + input: "strided_slice_36" + input: "mul_21/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_32" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_32/stack" + input: "strided_slice_32/stack_1" + input: "strided_slice_32/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_20" + op: "Mul" + input: "strided_slice_32" + input: "mul_20/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_10/size" + op: "Pack" + input: "Slice_10/size/0" + input: "mul_20" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_31" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_31/stack" + input: "strided_slice_31/stack_1" + input: "strided_slice_31/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_30" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_30/stack" + input: "strided_slice_30/stack_1" + input: "strided_slice_30/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_29" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_29/stack" + input: "strided_slice_29/stack_1" + input: "strided_slice_29/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_18" + op: "Mul" + input: "strided_slice_29" + input: "mul_18/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_9/size" + op: "Pack" + input: "Slice_9/size/0" + input: "mul_18" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_28" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_28/stack" + input: "strided_slice_28/stack_1" + input: "strided_slice_28/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "add_12" + op: "Add" + input: "add_12/x" + input: "strided_slice_28" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_13" + op: "Add" + input: "add_12" + input: "strided_slice_30" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_14" + op: "Add" + input: "add_13" + input: "strided_slice_31" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_19" + op: "Mul" + input: "add_14" + input: "mul_19/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_10/begin" + op: "Pack" + input: "Slice_10/begin/0" + input: "mul_19" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "mul_17" + op: "Mul" + input: "add_12" + input: "mul_17/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_9/begin" + op: "Pack" + input: "Slice_9/begin/0" + input: "mul_17" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_25" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_25/stack" + input: "strided_slice_25/stack_1" + input: "strided_slice_25/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_16" + op: "Mul" + input: "strided_slice_25" + input: "mul_16/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_8/size" + op: "Pack" + input: "Slice_8/size/0" + input: "mul_16" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_24" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_24/stack" + input: "strided_slice_24/stack_1" + input: "strided_slice_24/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_23" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_23/stack" + input: "strided_slice_23/stack_1" + input: "strided_slice_23/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_22" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_22/stack" + input: "strided_slice_22/stack_1" + input: "strided_slice_22/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_14" + op: "Mul" + input: "strided_slice_22" + input: "mul_14/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_7/size" + op: "Pack" + input: "Slice_7/size/0" + input: "mul_14" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_21" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_21/stack" + input: "strided_slice_21/stack_1" + input: "strided_slice_21/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "add_7" + op: "Add" + input: "add_7/x" + input: "strided_slice_21" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_8" + op: "Add" + input: "add_7" + input: "strided_slice_23" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_9" + op: "Add" + input: "add_8" + input: "strided_slice_24" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_15" + op: "Mul" + input: "add_9" + input: "mul_15/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_8/begin" + op: "Pack" + input: "Slice_8/begin/0" + input: "mul_15" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "mul_13" + op: "Mul" + input: "add_7" + input: "mul_13/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_7/begin" + op: "Pack" + input: "Slice_7/begin/0" + input: "mul_13" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_18" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_18/stack" + input: "strided_slice_18/stack_1" + input: "strided_slice_18/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_12" + op: "Mul" + input: "strided_slice_18" + input: "mul_12/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_6/size" + op: "Pack" + input: "Slice_6/size/0" + input: "mul_12" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_17" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_17/stack" + input: "strided_slice_17/stack_1" + input: "strided_slice_17/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_16" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_16/stack" + input: "strided_slice_16/stack_1" + input: "strided_slice_16/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_15" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_15/stack" + input: "strided_slice_15/stack_1" + input: "strided_slice_15/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_10" + op: "Mul" + input: "strided_slice_15" + input: "mul_10/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_5/size" + op: "Pack" + input: "Slice_5/size/0" + input: "mul_10" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_14" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_14/stack" + input: "strided_slice_14/stack_1" + input: "strided_slice_14/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "add_2" + op: "Add" + input: "add_2/x" + input: "strided_slice_14" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_3" + op: "Add" + input: "add_2" + input: "strided_slice_16" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_4" + op: "Add" + input: "add_3" + input: "strided_slice_17" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_11" + op: "Mul" + input: "add_4" + input: "mul_11/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_6/begin" + op: "Pack" + input: "Slice_6/begin/0" + input: "mul_11" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "mul_9" + op: "Mul" + input: "add_2" + input: "mul_9/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_5/begin" + op: "Pack" + input: "Slice_5/begin/0" + input: "mul_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_13" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_13/stack" + input: "strided_slice_13/stack_1" + input: "strided_slice_13/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_8" + op: "Mul" + input: "strided_slice_13" + input: "mul_8/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_7/shape" + op: "Pack" + input: "Reshape_7/shape/0" + input: "mul_8" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_12" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_12/stack" + input: "strided_slice_12/stack_1" + input: "strided_slice_12/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_7" + op: "Mul" + input: "strided_slice_12" + input: "mul_7/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_6/shape" + op: "Pack" + input: "Reshape_6/shape/0" + input: "mul_7" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_11" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_11/stack" + input: "strided_slice_11/stack_1" + input: "strided_slice_11/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_6" + op: "Mul" + input: "strided_slice_11" + input: "mul_6/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_5/shape" + op: "Pack" + input: "Reshape_5/shape/0" + input: "mul_6" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_10" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_10/stack" + input: "strided_slice_10/stack_1" + input: "strided_slice_10/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_5" + op: "Mul" + input: "strided_slice_10" + input: "mul_5/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_7" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_7/stack" + input: "strided_slice_7/stack_1" + input: "strided_slice_7/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_4" + op: "Mul" + input: "strided_slice_7" + input: "mul_4/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_1/size" + op: "Pack" + input: "Slice_1/size/0" + input: "mul_4" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_6" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_6/stack" + input: "strided_slice_6/stack_1" + input: "strided_slice_6/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_2" + op: "Mul" + input: "strided_slice_6" + input: "mul_2/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_4" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_4/stack" + input: "strided_slice_4/stack_1" + input: "strided_slice_4/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "add" + op: "Add" + input: "add/x" + input: "strided_slice_4" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_3" + op: "Mul" + input: "add" + input: "mul_3/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_1/begin" + op: "Pack" + input: "Slice_1/begin/0" + input: "mul_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/Slice_1_grad/Reshape" + op: "Reshape" + input: "Slice_1/begin" + input: "gradients_2/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_1_grad/Reshape" + op: "Reshape" + input: "Slice_1/begin" + input: "gradients_1/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/Reshape" + op: "Reshape" + input: "Slice_1/begin" + input: "gradients/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_3" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_3/stack" + input: "strided_slice_3/stack_1" + input: "strided_slice_3/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_1" + op: "Mul" + input: "strided_slice_3" + input: "mul_1/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice/size" + op: "Pack" + input: "Slice/size/0" + input: "mul_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_2" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "strided_slice_2/stack" + input: "strided_slice_2/stack_1" + input: "strided_slice_2/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul" + op: "Mul" + input: "strided_slice_2" + input: "mul/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/strided_slice_28" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "dipole_charge/strided_slice_28/stack" + input: "dipole_charge/strided_slice_28/stack_1" + input: "dipole_charge/strided_slice_28/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/strided_slice_26" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "dipole_charge/strided_slice_26/stack" + input: "dipole_charge/strided_slice_26/stack_1" + input: "dipole_charge/strided_slice_26/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/strided_slice_23" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "dipole_charge/strided_slice_23/stack" + input: "dipole_charge/strided_slice_23/stack_1" + input: "dipole_charge/strided_slice_23/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/mul_21" + op: "Mul" + input: "dipole_charge/strided_slice_23" + input: "dipole_charge/mul_21/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Slice_7/size" + op: "Pack" + input: "dipole_charge/Slice_7/size/0" + input: "dipole_charge/mul_21" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "dipole_charge/strided_slice_22" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "dipole_charge/strided_slice_22/stack" + input: "dipole_charge/strided_slice_22/stack_1" + input: "dipole_charge/strided_slice_22/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/mul_19" + op: "Mul" + input: "dipole_charge/strided_slice_22" + input: "dipole_charge/mul_19/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Slice_6/size" + op: "Pack" + input: "dipole_charge/Slice_6/size/0" + input: "dipole_charge/mul_19" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "dipole_charge/strided_slice_21" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "dipole_charge/strided_slice_21/stack" + input: "dipole_charge/strided_slice_21/stack_1" + input: "dipole_charge/strided_slice_21/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/strided_slice_18" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "dipole_charge/strided_slice_18/stack" + input: "dipole_charge/strided_slice_18/stack_1" + input: "dipole_charge/strided_slice_18/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/strided_slice_16" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "dipole_charge/strided_slice_16/stack" + input: "dipole_charge/strided_slice_16/stack_1" + input: "dipole_charge/strided_slice_16/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/strided_slice_14" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "dipole_charge/strided_slice_14/stack" + input: "dipole_charge/strided_slice_14/stack_1" + input: "dipole_charge/strided_slice_14/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/strided_slice_13" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "dipole_charge/strided_slice_13/stack" + input: "dipole_charge/strided_slice_13/stack_1" + input: "dipole_charge/strided_slice_13/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/mul_12" + op: "Mul" + input: "dipole_charge/strided_slice_13" + input: "dipole_charge/mul_12/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Slice_3/size" + op: "Pack" + input: "dipole_charge/Slice_3/size/0" + input: "dipole_charge/mul_12" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "dipole_charge/strided_slice_12" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "dipole_charge/strided_slice_12/stack" + input: "dipole_charge/strided_slice_12/stack_1" + input: "dipole_charge/strided_slice_12/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/mul_10" + op: "Mul" + input: "dipole_charge/strided_slice_12" + input: "dipole_charge/mul_10/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Slice_2/size" + op: "Pack" + input: "dipole_charge/Slice_2/size/0" + input: "dipole_charge/mul_10" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "dipole_charge/strided_slice_11" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "dipole_charge/strided_slice_11/stack" + input: "dipole_charge/strided_slice_11/stack_1" + input: "dipole_charge/strided_slice_11/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/add" + op: "Add" + input: "dipole_charge/add/x" + input: "dipole_charge/strided_slice_11" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/add_1" + op: "Add" + input: "dipole_charge/add" + input: "dipole_charge/strided_slice_14" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/add_4" + op: "Add" + input: "dipole_charge/add_1" + input: "dipole_charge/strided_slice_21" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/mul_20" + op: "Mul" + input: "dipole_charge/add_4" + input: "dipole_charge/mul_20/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Slice_7/begin" + op: "Pack" + input: "dipole_charge/Slice_7/begin/0" + input: "dipole_charge/mul_20" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_7_grad/Reshape" + op: "Reshape" + input: "dipole_charge/Slice_7/begin" + input: "gradients_2/dipole_charge/Slice_7_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_7_grad/Reshape" + op: "Reshape" + input: "dipole_charge/Slice_7/begin" + input: "gradients_1/dipole_charge/Slice_7_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_7_grad/Reshape" + op: "Reshape" + input: "dipole_charge/Slice_7/begin" + input: "gradients/dipole_charge/Slice_7_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/mul_18" + op: "Mul" + input: "dipole_charge/add_4" + input: "dipole_charge/mul_18/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Slice_6/begin" + op: "Pack" + input: "dipole_charge/Slice_6/begin/0" + input: "dipole_charge/mul_18" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_6_grad/Reshape" + op: "Reshape" + input: "dipole_charge/Slice_6/begin" + input: "gradients_2/dipole_charge/Slice_6_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_6_grad/Reshape" + op: "Reshape" + input: "dipole_charge/Slice_6/begin" + input: "gradients_1/dipole_charge/Slice_6_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_6_grad/Reshape" + op: "Reshape" + input: "dipole_charge/Slice_6/begin" + input: "gradients/dipole_charge/Slice_6_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/mul_11" + op: "Mul" + input: "dipole_charge/add" + input: "dipole_charge/mul_11/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Slice_3/begin" + op: "Pack" + input: "dipole_charge/Slice_3/begin/0" + input: "dipole_charge/mul_11" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_3_grad/Reshape" + op: "Reshape" + input: "dipole_charge/Slice_3/begin" + input: "gradients_2/dipole_charge/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_3_grad/Reshape" + op: "Reshape" + input: "dipole_charge/Slice_3/begin" + input: "gradients_1/dipole_charge/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_3_grad/Reshape" + op: "Reshape" + input: "dipole_charge/Slice_3/begin" + input: "gradients/dipole_charge/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/mul_9" + op: "Mul" + input: "dipole_charge/add" + input: "dipole_charge/mul_9/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Slice_2/begin" + op: "Pack" + input: "dipole_charge/Slice_2/begin/0" + input: "dipole_charge/mul_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_2_grad/Reshape" + op: "Reshape" + input: "dipole_charge/Slice_2/begin" + input: "gradients_2/dipole_charge/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_2_grad/Reshape" + op: "Reshape" + input: "dipole_charge/Slice_2/begin" + input: "gradients_1/dipole_charge/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_2_grad/Reshape" + op: "Reshape" + input: "dipole_charge/Slice_2/begin" + input: "gradients/dipole_charge/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/strided_slice_8" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "dipole_charge/strided_slice_8/stack" + input: "dipole_charge/strided_slice_8/stack_1" + input: "dipole_charge/strided_slice_8/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/mul_6" + op: "Mul" + input: "dipole_charge/mul_6/x" + input: "dipole_charge/strided_slice_8" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Reshape_9/shape" + op: "Pack" + input: "dipole_charge/Reshape_9/shape/0" + input: "dipole_charge/mul_6" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "dipole_charge/strided_slice_7" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "dipole_charge/strided_slice_7/stack" + input: "dipole_charge/strided_slice_7/stack_1" + input: "dipole_charge/strided_slice_7/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/mul_5" + op: "Mul" + input: "dipole_charge/mul_5/x" + input: "dipole_charge/strided_slice_7" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Reshape_8/shape" + op: "Pack" + input: "dipole_charge/Reshape_8/shape/0" + input: "dipole_charge/mul_5" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "dipole_charge/strided_slice_6" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "dipole_charge/strided_slice_6/stack" + input: "dipole_charge/strided_slice_6/stack_1" + input: "dipole_charge/strided_slice_6/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/mul_3" + op: "Mul" + input: "dipole_charge/strided_slice_6" + input: "dipole_charge/mul_3/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/mul_4" + op: "Mul" + input: "dipole_charge/mul_3" + input: "dipole_charge/mul_4/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/strided_slice_4" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "dipole_charge/strided_slice_4/stack" + input: "dipole_charge/strided_slice_4/stack_1" + input: "dipole_charge/strided_slice_4/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/mul_2" + op: "Mul" + input: "dipole_charge/strided_slice_4" + input: "dipole_charge/mul_2/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/strided_slice_2" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "dipole_charge/strided_slice_2/stack" + input: "dipole_charge/strided_slice_2/stack_1" + input: "dipole_charge/strided_slice_2/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/mul_1" + op: "Mul" + input: "dipole_charge/mul_1/x" + input: "dipole_charge/strided_slice_2" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Reshape_4/shape" + op: "Pack" + input: "dipole_charge/Reshape_4/shape/0" + input: "dipole_charge/mul_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "dipole_charge/strided_slice_1" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "dipole_charge/strided_slice_1/stack" + input: "dipole_charge/strided_slice_1/stack_1" + input: "dipole_charge/strided_slice_1/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/Reshape_2/shape" + op: "Pack" + input: "dipole_charge/Reshape_2/shape/0" + input: "dipole_charge/strided_slice_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "dipole_charge/strided_slice" + op: "StridedSlice" + input: "dipole_charge/t_natoms" + input: "dipole_charge/strided_slice/stack" + input: "dipole_charge/strided_slice/stack_1" + input: "dipole_charge/strided_slice/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/mul" + op: "Mul" + input: "dipole_charge/strided_slice" + input: "dipole_charge/mul/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Reshape/shape" + op: "Pack" + input: "dipole_charge/Reshape/shape/0" + input: "dipole_charge/mul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "dipole_charge/t_type" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "dipole_charge/Reshape_2" + op: "Reshape" + input: "dipole_charge/t_type" + input: "dipole_charge/Reshape_2/shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/t_coord" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "dipole_charge/Reshape" + op: "Reshape" + input: "dipole_charge/t_coord" + input: "dipole_charge/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/t_box" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape" + op: "Reshape" + input: "dipole_charge/t_box" + input: "Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape" + op: "Shape" + input: "Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice" + op: "StridedSlice" + input: "Shape" + input: "strided_slice/stack" + input: "strided_slice/stack_1" + input: "strided_slice/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_13/shape" + op: "Pack" + input: "strided_slice" + input: "Reshape_13/shape/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Reshape_2/shape" + op: "Pack" + input: "strided_slice" + input: "Reshape_2/shape/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "dipole_charge/Reshape_1" + op: "Reshape" + input: "dipole_charge/t_box" + input: "dipole_charge/Reshape_1/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/ProdEnvMatA" + op: "ProdEnvMatA" + input: "dipole_charge/Reshape" + input: "dipole_charge/Reshape_2" + input: "dipole_charge/t_natoms" + input: "dipole_charge/Reshape_1" + input: "dipole_charge/t_mesh" + input: "dipole_charge/descrpt_attr/t_avg/read" + input: "dipole_charge/descrpt_attr/t_std/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "rcut_a" + value { + f: -1.0 + } + } + attr { + key: "rcut_r" + value { + f: 4.0 + } + } + attr { + key: "rcut_r_smth" + value { + f: 0.80000001 + } + } + attr { + key: "sel_a" + value { + list { + i: 5 + i: 5 + i: 5 + i: 5 + i: 5 + } + } + } + attr { + key: "sel_r" + value { + list { + i: 0 + i: 0 + i: 0 + i: 0 + i: 0 + } + } + } +} +node { + name: "dipole_charge/Reshape_3" + op: "Reshape" + input: "dipole_charge/ProdEnvMatA" + input: "dipole_charge/Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/o_rmat" + op: "Identity" + input: "dipole_charge/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_4_grad/Shape" + op: "Shape" + input: "dipole_charge/o_rmat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_4_grad/Shape" + op: "Shape" + input: "dipole_charge/o_rmat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Reshape_4_grad/Shape" + op: "Shape" + input: "dipole_charge/o_rmat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Reshape_4" + op: "Reshape" + input: "dipole_charge/o_rmat" + input: "dipole_charge/Reshape_4/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_5_grad/Shape" + op: "Shape" + input: "dipole_charge/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_5_grad/Shape" + op: "Shape" + input: "dipole_charge/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Reshape_5_grad/Shape" + op: "Shape" + input: "dipole_charge/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Reshape_5" + op: "Reshape" + input: "dipole_charge/Reshape_4" + input: "dipole_charge/Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_2_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_4_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_6_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_8_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_8" + op: "Slice" + input: "dipole_charge/Reshape_5" + input: "dipole_charge/filter_type_all/Slice_8/begin" + input: "dipole_charge/filter_type_all/Slice_8/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/sub" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/Shape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/sub_1" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/sub" + input: "dipole_charge/filter_type_all/Slice_8/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/sub_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/concat" + op: "ConcatV2" + input: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_28_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_34_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/sub" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/Shape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/sub_1" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/sub" + input: "dipole_charge/filter_type_all/Slice_8/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/sub_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/concat" + op: "ConcatV2" + input: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_28_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_34_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_8_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_8_grad/sub" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_8_grad/Shape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_8_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_8_grad/sub_1" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_8_grad/sub" + input: "dipole_charge/filter_type_all/Slice_8/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_8_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_8_grad/sub_1" + input: "gradients/dipole_charge/filter_type_all/Slice_8_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_8_grad/concat" + op: "ConcatV2" + input: "gradients/dipole_charge/filter_type_all/Slice_8_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_8_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_8_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_28_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_34_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_34" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_8" + input: "dipole_charge/filter_type_all/Reshape_34/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_28" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_8" + input: "dipole_charge/filter_type_all/Reshape_28/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_28" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_28" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_9_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_28" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_9" + op: "Slice" + input: "dipole_charge/filter_type_all/Reshape_28" + input: "dipole_charge/filter_type_all/Slice_9/begin" + input: "dipole_charge/filter_type_all/Slice_9/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/sub" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/Shape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/sub_1" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/sub" + input: "dipole_charge/filter_type_all/Slice_9/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/sub_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/concat" + op: "ConcatV2" + input: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_29_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/sub" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/Shape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/sub_1" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/sub" + input: "dipole_charge/filter_type_all/Slice_9/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/sub_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/concat" + op: "ConcatV2" + input: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_29_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_9_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_9_grad/sub" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_9_grad/Shape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_9_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_9_grad/sub_1" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_9_grad/sub" + input: "dipole_charge/filter_type_all/Slice_9/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_9_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_9_grad/sub_1" + input: "gradients/dipole_charge/filter_type_all/Slice_9_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_9_grad/concat" + op: "ConcatV2" + input: "gradients/dipole_charge/filter_type_all/Slice_9_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_9_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_9_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_29_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_29" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_9" + input: "dipole_charge/filter_type_all/Reshape_29/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_12_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/Reshape_29" + input: "dipole_charge/filter_type_all/Reshape_29" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_12_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_12_grad/mod" + input: "gradients_2/dipole_charge/filter_type_all/concat_12_grad/ShapeN" + input: "gradients_2/dipole_charge/filter_type_all/concat_12_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_12_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/Reshape_29" + input: "dipole_charge/filter_type_all/Reshape_29" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_12_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_12_grad/mod" + input: "gradients_1/dipole_charge/filter_type_all/concat_12_grad/ShapeN" + input: "gradients_1/dipole_charge/filter_type_all/concat_12_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_12_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/Reshape_29" + input: "dipole_charge/filter_type_all/Reshape_29" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_12_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_12_grad/mod" + input: "gradients/dipole_charge/filter_type_all/concat_12_grad/ShapeN" + input: "gradients/dipole_charge/filter_type_all/concat_12_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_12" + op: "ConcatV2" + input: "dipole_charge/filter_type_all/Reshape_29" + input: "dipole_charge/filter_type_all/Reshape_29" + input: "dipole_charge/filter_type_all/concat_12/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_28_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_28_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_28_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_16" + op: "MatMul" + input: "dipole_charge/filter_type_all/Reshape_29" + input: "dipole_charge/filter_type_all/matrix_1_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_27_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_16" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_27_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_27_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_27_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_27_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_16" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_27_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_27_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_27_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_27_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_16" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_27_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_27_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_27_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_27" + op: "Add" + input: "dipole_charge/filter_type_all/MatMul_16" + input: "dipole_charge/filter_type_all/bias_1_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/filter_type_all/Tanh_12" + op: "Tanh" + input: "dipole_charge/filter_type_all/add_27" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_30_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_30_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_30_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_30" + op: "Reshape" + input: "dipole_charge/filter_type_all/Tanh_12" + input: "dipole_charge/filter_type_all/Reshape_30/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_28_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_30" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_28_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_28_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_28_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_28_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_30" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_28_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_28_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_28_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_28_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_30" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_28_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_28_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_28_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_28" + op: "Add" + input: "dipole_charge/filter_type_all/concat_12" + input: "dipole_charge/filter_type_all/Reshape_30" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_13_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_28" + input: "dipole_charge/filter_type_all/add_28" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_13_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_13_grad/mod" + input: "gradients_2/dipole_charge/filter_type_all/concat_13_grad/ShapeN" + input: "gradients_2/dipole_charge/filter_type_all/concat_13_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_13_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_28" + input: "dipole_charge/filter_type_all/add_28" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_13_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_13_grad/mod" + input: "gradients_1/dipole_charge/filter_type_all/concat_13_grad/ShapeN" + input: "gradients_1/dipole_charge/filter_type_all/concat_13_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_13_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_28" + input: "dipole_charge/filter_type_all/add_28" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_13_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_13_grad/mod" + input: "gradients/dipole_charge/filter_type_all/concat_13_grad/ShapeN" + input: "gradients/dipole_charge/filter_type_all/concat_13_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_13" + op: "ConcatV2" + input: "dipole_charge/filter_type_all/add_28" + input: "dipole_charge/filter_type_all/add_28" + input: "dipole_charge/filter_type_all/concat_13/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_30_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_30_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_30_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_17" + op: "MatMul" + input: "dipole_charge/filter_type_all/add_28" + input: "dipole_charge/filter_type_all/matrix_2_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_29_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_17" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_29_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_29_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_29_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_29_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_17" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_29_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_29_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_29_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_29_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_17" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_29_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_29_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_29_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_29" + op: "Add" + input: "dipole_charge/filter_type_all/MatMul_17" + input: "dipole_charge/filter_type_all/bias_2_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/filter_type_all/Tanh_13" + op: "Tanh" + input: "dipole_charge/filter_type_all/add_29" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_31_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_31_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_31_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_31" + op: "Reshape" + input: "dipole_charge/filter_type_all/Tanh_13" + input: "dipole_charge/filter_type_all/Reshape_31/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_30_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_31" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_30_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_30_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_30_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_30_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_31" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_30_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_30_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_30_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_30_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_31" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_30_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_30_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_30_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_30" + op: "Add" + input: "dipole_charge/filter_type_all/concat_13" + input: "dipole_charge/filter_type_all/Reshape_31" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_14_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_30" + input: "dipole_charge/filter_type_all/add_30" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_14_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_14_grad/mod" + input: "gradients_2/dipole_charge/filter_type_all/concat_14_grad/ShapeN" + input: "gradients_2/dipole_charge/filter_type_all/concat_14_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_14_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_30" + input: "dipole_charge/filter_type_all/add_30" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_14_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_14_grad/mod" + input: "gradients_1/dipole_charge/filter_type_all/concat_14_grad/ShapeN" + input: "gradients_1/dipole_charge/filter_type_all/concat_14_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_14_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_30" + input: "dipole_charge/filter_type_all/add_30" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_14_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_14_grad/mod" + input: "gradients/dipole_charge/filter_type_all/concat_14_grad/ShapeN" + input: "gradients/dipole_charge/filter_type_all/concat_14_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_14" + op: "ConcatV2" + input: "dipole_charge/filter_type_all/add_30" + input: "dipole_charge/filter_type_all/add_30" + input: "dipole_charge/filter_type_all/concat_14/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_32_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_32_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_32_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_18" + op: "MatMul" + input: "dipole_charge/filter_type_all/add_30" + input: "dipole_charge/filter_type_all/matrix_3_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_31_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_18" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_31_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_31_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_31_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_31_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_18" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_31_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_31_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_31_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_31_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_18" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_31_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_31_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_31_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_31" + op: "Add" + input: "dipole_charge/filter_type_all/MatMul_18" + input: "dipole_charge/filter_type_all/bias_3_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/filter_type_all/Tanh_14" + op: "Tanh" + input: "dipole_charge/filter_type_all/add_31" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_32_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_32_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_32_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_32" + op: "Reshape" + input: "dipole_charge/filter_type_all/Tanh_14" + input: "dipole_charge/filter_type_all/Reshape_32/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_32_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_32" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_32_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_32_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_32_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_32_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_32" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_32_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_32_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_32_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_32_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_32" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_32_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_32_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_32_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_32" + op: "Add" + input: "dipole_charge/filter_type_all/concat_14" + input: "dipole_charge/filter_type_all/Reshape_32" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_33_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_32" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_33_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_32" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_33_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_32" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_33" + op: "Reshape" + input: "dipole_charge/filter_type_all/add_32" + input: "dipole_charge/filter_type_all/Reshape_33/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_19" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_34" + input: "dipole_charge/filter_type_all/Reshape_33" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_33_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_33_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_33_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_6" + op: "Slice" + input: "dipole_charge/Reshape_5" + input: "dipole_charge/filter_type_all/Slice_6/begin" + input: "dipole_charge/filter_type_all/Slice_6/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/sub" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/Shape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/sub_1" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/sub" + input: "dipole_charge/filter_type_all/Slice_6/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/sub_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/concat" + op: "ConcatV2" + input: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_21_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_27_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/sub" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/Shape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/sub_1" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/sub" + input: "dipole_charge/filter_type_all/Slice_6/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/sub_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/concat" + op: "ConcatV2" + input: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_21_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_27_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_6_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_6_grad/sub" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_6_grad/Shape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_6_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_6_grad/sub_1" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_6_grad/sub" + input: "dipole_charge/filter_type_all/Slice_6/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_6_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_6_grad/sub_1" + input: "gradients/dipole_charge/filter_type_all/Slice_6_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_6_grad/concat" + op: "ConcatV2" + input: "gradients/dipole_charge/filter_type_all/Slice_6_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_6_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_6_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_21_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_27_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_27" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_6" + input: "dipole_charge/filter_type_all/Reshape_27/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_21" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_6" + input: "dipole_charge/filter_type_all/Reshape_21/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_21" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_21" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_7_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_21" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_7" + op: "Slice" + input: "dipole_charge/filter_type_all/Reshape_21" + input: "dipole_charge/filter_type_all/Slice_7/begin" + input: "dipole_charge/filter_type_all/Slice_7/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/sub" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/Shape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/sub_1" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/sub" + input: "dipole_charge/filter_type_all/Slice_7/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/sub_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/concat" + op: "ConcatV2" + input: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_22_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/sub" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/Shape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/sub_1" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/sub" + input: "dipole_charge/filter_type_all/Slice_7/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/sub_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/concat" + op: "ConcatV2" + input: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_22_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_7_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_7_grad/sub" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_7_grad/Shape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_7_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_7_grad/sub_1" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_7_grad/sub" + input: "dipole_charge/filter_type_all/Slice_7/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_7_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_7_grad/sub_1" + input: "gradients/dipole_charge/filter_type_all/Slice_7_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_7_grad/concat" + op: "ConcatV2" + input: "gradients/dipole_charge/filter_type_all/Slice_7_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_7_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_7_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_22_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_22" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_7" + input: "dipole_charge/filter_type_all/Reshape_22/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_9_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/Reshape_22" + input: "dipole_charge/filter_type_all/Reshape_22" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_9_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_9_grad/mod" + input: "gradients_2/dipole_charge/filter_type_all/concat_9_grad/ShapeN" + input: "gradients_2/dipole_charge/filter_type_all/concat_9_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_9_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/Reshape_22" + input: "dipole_charge/filter_type_all/Reshape_22" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_9_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_9_grad/mod" + input: "gradients_1/dipole_charge/filter_type_all/concat_9_grad/ShapeN" + input: "gradients_1/dipole_charge/filter_type_all/concat_9_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_9_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/Reshape_22" + input: "dipole_charge/filter_type_all/Reshape_22" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_9_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_9_grad/mod" + input: "gradients/dipole_charge/filter_type_all/concat_9_grad/ShapeN" + input: "gradients/dipole_charge/filter_type_all/concat_9_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_9" + op: "ConcatV2" + input: "dipole_charge/filter_type_all/Reshape_22" + input: "dipole_charge/filter_type_all/Reshape_22" + input: "dipole_charge/filter_type_all/concat_9/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_21_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_21_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_21_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_12" + op: "MatMul" + input: "dipole_charge/filter_type_all/Reshape_22" + input: "dipole_charge/filter_type_all/matrix_1_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_20_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_20_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_20_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_20_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_20_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_20_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_20_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_20_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_20_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_20_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_20_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_20_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_20" + op: "Add" + input: "dipole_charge/filter_type_all/MatMul_12" + input: "dipole_charge/filter_type_all/bias_1_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/filter_type_all/Tanh_9" + op: "Tanh" + input: "dipole_charge/filter_type_all/add_20" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_23_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_23_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_23_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_23" + op: "Reshape" + input: "dipole_charge/filter_type_all/Tanh_9" + input: "dipole_charge/filter_type_all/Reshape_23/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_21_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_23" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_21_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_21_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_21_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_21_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_23" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_21_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_21_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_21_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_21_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_23" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_21_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_21_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_21_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_21" + op: "Add" + input: "dipole_charge/filter_type_all/concat_9" + input: "dipole_charge/filter_type_all/Reshape_23" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_10_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_21" + input: "dipole_charge/filter_type_all/add_21" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_10_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_10_grad/mod" + input: "gradients_2/dipole_charge/filter_type_all/concat_10_grad/ShapeN" + input: "gradients_2/dipole_charge/filter_type_all/concat_10_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_10_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_21" + input: "dipole_charge/filter_type_all/add_21" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_10_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_10_grad/mod" + input: "gradients_1/dipole_charge/filter_type_all/concat_10_grad/ShapeN" + input: "gradients_1/dipole_charge/filter_type_all/concat_10_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_10_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_21" + input: "dipole_charge/filter_type_all/add_21" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_10_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_10_grad/mod" + input: "gradients/dipole_charge/filter_type_all/concat_10_grad/ShapeN" + input: "gradients/dipole_charge/filter_type_all/concat_10_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_10" + op: "ConcatV2" + input: "dipole_charge/filter_type_all/add_21" + input: "dipole_charge/filter_type_all/add_21" + input: "dipole_charge/filter_type_all/concat_10/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_23_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_23_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_23_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_13" + op: "MatMul" + input: "dipole_charge/filter_type_all/add_21" + input: "dipole_charge/filter_type_all/matrix_2_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_22_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_22_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_22_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_22_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_22_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_22_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_22_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_22_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_22_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_22_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_22_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_22_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_22" + op: "Add" + input: "dipole_charge/filter_type_all/MatMul_13" + input: "dipole_charge/filter_type_all/bias_2_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/filter_type_all/Tanh_10" + op: "Tanh" + input: "dipole_charge/filter_type_all/add_22" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_24_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_24_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_24_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_24" + op: "Reshape" + input: "dipole_charge/filter_type_all/Tanh_10" + input: "dipole_charge/filter_type_all/Reshape_24/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_23_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_24" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_23_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_23_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_23_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_23_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_24" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_23_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_23_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_23_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_23_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_24" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_23_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_23_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_23_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_23" + op: "Add" + input: "dipole_charge/filter_type_all/concat_10" + input: "dipole_charge/filter_type_all/Reshape_24" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_11_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_23" + input: "dipole_charge/filter_type_all/add_23" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_11_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_11_grad/mod" + input: "gradients_2/dipole_charge/filter_type_all/concat_11_grad/ShapeN" + input: "gradients_2/dipole_charge/filter_type_all/concat_11_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_11_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_23" + input: "dipole_charge/filter_type_all/add_23" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_11_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_11_grad/mod" + input: "gradients_1/dipole_charge/filter_type_all/concat_11_grad/ShapeN" + input: "gradients_1/dipole_charge/filter_type_all/concat_11_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_11_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_23" + input: "dipole_charge/filter_type_all/add_23" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_11_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_11_grad/mod" + input: "gradients/dipole_charge/filter_type_all/concat_11_grad/ShapeN" + input: "gradients/dipole_charge/filter_type_all/concat_11_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_11" + op: "ConcatV2" + input: "dipole_charge/filter_type_all/add_23" + input: "dipole_charge/filter_type_all/add_23" + input: "dipole_charge/filter_type_all/concat_11/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_25_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_25_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_25_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_14" + op: "MatMul" + input: "dipole_charge/filter_type_all/add_23" + input: "dipole_charge/filter_type_all/matrix_3_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_24_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_24_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_24_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_24_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_24_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_24_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_24_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_24_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_24_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_24_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_24_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_24_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_24" + op: "Add" + input: "dipole_charge/filter_type_all/MatMul_14" + input: "dipole_charge/filter_type_all/bias_3_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/filter_type_all/Tanh_11" + op: "Tanh" + input: "dipole_charge/filter_type_all/add_24" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_25_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_25_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_25_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_25" + op: "Reshape" + input: "dipole_charge/filter_type_all/Tanh_11" + input: "dipole_charge/filter_type_all/Reshape_25/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_25_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_25_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_25_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_25_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_25_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_25_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_25_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_25_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_25_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_25_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_25_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_25_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_25" + op: "Add" + input: "dipole_charge/filter_type_all/concat_11" + input: "dipole_charge/filter_type_all/Reshape_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_26_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_26_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_26_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_25" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_26" + op: "Reshape" + input: "dipole_charge/filter_type_all/add_25" + input: "dipole_charge/filter_type_all/Reshape_26/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_15" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_27" + input: "dipole_charge/filter_type_all/Reshape_26" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_26_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_15" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_26_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_15" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_26_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_15" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_4" + op: "Slice" + input: "dipole_charge/Reshape_5" + input: "dipole_charge/filter_type_all/Slice_4/begin" + input: "dipole_charge/filter_type_all/Slice_4/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/sub" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/Shape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/sub_1" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/sub" + input: "dipole_charge/filter_type_all/Slice_4/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/sub_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/concat" + op: "ConcatV2" + input: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_14_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_20_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/sub" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/Shape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/sub_1" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/sub" + input: "dipole_charge/filter_type_all/Slice_4/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/sub_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/concat" + op: "ConcatV2" + input: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_14_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_20_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_4_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_4_grad/sub" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_4_grad/Shape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_4_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_4_grad/sub_1" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_4_grad/sub" + input: "dipole_charge/filter_type_all/Slice_4/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_4_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_4_grad/sub_1" + input: "gradients/dipole_charge/filter_type_all/Slice_4_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_4_grad/concat" + op: "ConcatV2" + input: "gradients/dipole_charge/filter_type_all/Slice_4_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_4_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_4_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_14_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_20_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_20" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_4" + input: "dipole_charge/filter_type_all/Reshape_20/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_14" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_4" + input: "dipole_charge/filter_type_all/Reshape_14/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_5_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_5" + op: "Slice" + input: "dipole_charge/filter_type_all/Reshape_14" + input: "dipole_charge/filter_type_all/Slice_5/begin" + input: "dipole_charge/filter_type_all/Slice_5/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/sub" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/Shape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/sub_1" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/sub" + input: "dipole_charge/filter_type_all/Slice_5/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/sub_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/concat" + op: "ConcatV2" + input: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_15_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/sub" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/Shape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/sub_1" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/sub" + input: "dipole_charge/filter_type_all/Slice_5/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/sub_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/concat" + op: "ConcatV2" + input: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_15_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_5_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_5_grad/sub" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_5_grad/Shape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_5_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_5_grad/sub_1" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_5_grad/sub" + input: "dipole_charge/filter_type_all/Slice_5/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_5_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_5_grad/sub_1" + input: "gradients/dipole_charge/filter_type_all/Slice_5_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_5_grad/concat" + op: "ConcatV2" + input: "gradients/dipole_charge/filter_type_all/Slice_5_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_5_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_5_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_15_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_15" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_5" + input: "dipole_charge/filter_type_all/Reshape_15/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_6_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/Reshape_15" + input: "dipole_charge/filter_type_all/Reshape_15" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_6_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_6_grad/mod" + input: "gradients_2/dipole_charge/filter_type_all/concat_6_grad/ShapeN" + input: "gradients_2/dipole_charge/filter_type_all/concat_6_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_6_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/Reshape_15" + input: "dipole_charge/filter_type_all/Reshape_15" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_6_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_6_grad/mod" + input: "gradients_1/dipole_charge/filter_type_all/concat_6_grad/ShapeN" + input: "gradients_1/dipole_charge/filter_type_all/concat_6_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_6_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/Reshape_15" + input: "dipole_charge/filter_type_all/Reshape_15" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_6_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_6_grad/mod" + input: "gradients/dipole_charge/filter_type_all/concat_6_grad/ShapeN" + input: "gradients/dipole_charge/filter_type_all/concat_6_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_6" + op: "ConcatV2" + input: "dipole_charge/filter_type_all/Reshape_15" + input: "dipole_charge/filter_type_all/Reshape_15" + input: "dipole_charge/filter_type_all/concat_6/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_14_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_14_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_14_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_8" + op: "MatMul" + input: "dipole_charge/filter_type_all/Reshape_15" + input: "dipole_charge/filter_type_all/matrix_1_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_13_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_13_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_13_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_13_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_13_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_13_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_13_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_13_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_13_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_13_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_13_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_13_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_13" + op: "Add" + input: "dipole_charge/filter_type_all/MatMul_8" + input: "dipole_charge/filter_type_all/bias_1_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/filter_type_all/Tanh_6" + op: "Tanh" + input: "dipole_charge/filter_type_all/add_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_16_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_16_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_16_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_16" + op: "Reshape" + input: "dipole_charge/filter_type_all/Tanh_6" + input: "dipole_charge/filter_type_all/Reshape_16/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_14_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_16" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_14_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_14_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_14_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_14_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_16" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_14_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_14_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_14_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_14_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_16" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_14_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_14_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_14_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_14" + op: "Add" + input: "dipole_charge/filter_type_all/concat_6" + input: "dipole_charge/filter_type_all/Reshape_16" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_7_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_14" + input: "dipole_charge/filter_type_all/add_14" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_7_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_7_grad/mod" + input: "gradients_2/dipole_charge/filter_type_all/concat_7_grad/ShapeN" + input: "gradients_2/dipole_charge/filter_type_all/concat_7_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_7_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_14" + input: "dipole_charge/filter_type_all/add_14" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_7_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_7_grad/mod" + input: "gradients_1/dipole_charge/filter_type_all/concat_7_grad/ShapeN" + input: "gradients_1/dipole_charge/filter_type_all/concat_7_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_7_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_14" + input: "dipole_charge/filter_type_all/add_14" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_7_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_7_grad/mod" + input: "gradients/dipole_charge/filter_type_all/concat_7_grad/ShapeN" + input: "gradients/dipole_charge/filter_type_all/concat_7_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_7" + op: "ConcatV2" + input: "dipole_charge/filter_type_all/add_14" + input: "dipole_charge/filter_type_all/add_14" + input: "dipole_charge/filter_type_all/concat_7/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_16_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_16_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_16_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_9" + op: "MatMul" + input: "dipole_charge/filter_type_all/add_14" + input: "dipole_charge/filter_type_all/matrix_2_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_15_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_15_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_15_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_15_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_15_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_15_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_15_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_15_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_15_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_15_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_15_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_15_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_15" + op: "Add" + input: "dipole_charge/filter_type_all/MatMul_9" + input: "dipole_charge/filter_type_all/bias_2_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/filter_type_all/Tanh_7" + op: "Tanh" + input: "dipole_charge/filter_type_all/add_15" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_17_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_17_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_17_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_17" + op: "Reshape" + input: "dipole_charge/filter_type_all/Tanh_7" + input: "dipole_charge/filter_type_all/Reshape_17/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_16_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_17" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_16_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_16_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_16_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_16_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_17" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_16_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_16_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_16_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_16_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_17" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_16_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_16_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_16_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_16" + op: "Add" + input: "dipole_charge/filter_type_all/concat_7" + input: "dipole_charge/filter_type_all/Reshape_17" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_8_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_16" + input: "dipole_charge/filter_type_all/add_16" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_8_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_8_grad/mod" + input: "gradients_2/dipole_charge/filter_type_all/concat_8_grad/ShapeN" + input: "gradients_2/dipole_charge/filter_type_all/concat_8_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_8_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_16" + input: "dipole_charge/filter_type_all/add_16" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_8_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_8_grad/mod" + input: "gradients_1/dipole_charge/filter_type_all/concat_8_grad/ShapeN" + input: "gradients_1/dipole_charge/filter_type_all/concat_8_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_8_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_16" + input: "dipole_charge/filter_type_all/add_16" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_8_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_8_grad/mod" + input: "gradients/dipole_charge/filter_type_all/concat_8_grad/ShapeN" + input: "gradients/dipole_charge/filter_type_all/concat_8_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_8" + op: "ConcatV2" + input: "dipole_charge/filter_type_all/add_16" + input: "dipole_charge/filter_type_all/add_16" + input: "dipole_charge/filter_type_all/concat_8/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_18_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_18_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_18_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_10" + op: "MatMul" + input: "dipole_charge/filter_type_all/add_16" + input: "dipole_charge/filter_type_all/matrix_3_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_17_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_17_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_17_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_17_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_17_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_17_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_17_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_17_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_17_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_17_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_17_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_17_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_17" + op: "Add" + input: "dipole_charge/filter_type_all/MatMul_10" + input: "dipole_charge/filter_type_all/bias_3_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/filter_type_all/Tanh_8" + op: "Tanh" + input: "dipole_charge/filter_type_all/add_17" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_18_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_18_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_18_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_18" + op: "Reshape" + input: "dipole_charge/filter_type_all/Tanh_8" + input: "dipole_charge/filter_type_all/Reshape_18/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_18_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_18" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_18_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_18_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_18_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_18_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_18" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_18_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_18_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_18_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_18_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_18" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_18_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_18_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_18_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_18" + op: "Add" + input: "dipole_charge/filter_type_all/concat_8" + input: "dipole_charge/filter_type_all/Reshape_18" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_19_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_18" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_19_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_18" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_19_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_18" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_19" + op: "Reshape" + input: "dipole_charge/filter_type_all/add_18" + input: "dipole_charge/filter_type_all/Reshape_19/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_11" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_20" + input: "dipole_charge/filter_type_all/Reshape_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_19_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_19_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_19_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_2" + op: "Slice" + input: "dipole_charge/Reshape_5" + input: "dipole_charge/filter_type_all/Slice_2/begin" + input: "dipole_charge/filter_type_all/Slice_2/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/sub" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/Shape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/sub_1" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/sub" + input: "dipole_charge/filter_type_all/Slice_2/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/sub_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/concat" + op: "ConcatV2" + input: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_7_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_13_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/sub" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/Shape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/sub_1" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/sub" + input: "dipole_charge/filter_type_all/Slice_2/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/sub_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/concat" + op: "ConcatV2" + input: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_7_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_13_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_2_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_2_grad/sub" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_2_grad/Shape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_2_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_2_grad/sub_1" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_2_grad/sub" + input: "dipole_charge/filter_type_all/Slice_2/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_2_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_2_grad/sub_1" + input: "gradients/dipole_charge/filter_type_all/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_2_grad/concat" + op: "ConcatV2" + input: "gradients/dipole_charge/filter_type_all/Slice_2_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_2_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_2_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_7_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_13_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_13" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_2" + input: "dipole_charge/filter_type_all/Reshape_13/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_7" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_2" + input: "dipole_charge/filter_type_all/Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_3_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_3" + op: "Slice" + input: "dipole_charge/filter_type_all/Reshape_7" + input: "dipole_charge/filter_type_all/Slice_3/begin" + input: "dipole_charge/filter_type_all/Slice_3/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/sub" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/Shape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/sub_1" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/sub" + input: "dipole_charge/filter_type_all/Slice_3/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/sub_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/concat" + op: "ConcatV2" + input: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_8_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/sub" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/Shape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/sub_1" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/sub" + input: "dipole_charge/filter_type_all/Slice_3/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/sub_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/concat" + op: "ConcatV2" + input: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_8_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_3_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_3_grad/sub" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_3_grad/Shape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_3_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_3_grad/sub_1" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_3_grad/sub" + input: "dipole_charge/filter_type_all/Slice_3/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_3_grad/sub_1" + input: "gradients/dipole_charge/filter_type_all/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_3_grad/concat" + op: "ConcatV2" + input: "gradients/dipole_charge/filter_type_all/Slice_3_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_3_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_3_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_8_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_8" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_3" + input: "dipole_charge/filter_type_all/Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_3_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/Reshape_8" + input: "dipole_charge/filter_type_all/Reshape_8" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_3_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_3_grad/mod" + input: "gradients_2/dipole_charge/filter_type_all/concat_3_grad/ShapeN" + input: "gradients_2/dipole_charge/filter_type_all/concat_3_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_3_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/Reshape_8" + input: "dipole_charge/filter_type_all/Reshape_8" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_3_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_3_grad/mod" + input: "gradients_1/dipole_charge/filter_type_all/concat_3_grad/ShapeN" + input: "gradients_1/dipole_charge/filter_type_all/concat_3_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_3_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/Reshape_8" + input: "dipole_charge/filter_type_all/Reshape_8" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_3_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_3_grad/mod" + input: "gradients/dipole_charge/filter_type_all/concat_3_grad/ShapeN" + input: "gradients/dipole_charge/filter_type_all/concat_3_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_3" + op: "ConcatV2" + input: "dipole_charge/filter_type_all/Reshape_8" + input: "dipole_charge/filter_type_all/Reshape_8" + input: "dipole_charge/filter_type_all/concat_3/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_7_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_7_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_7_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_4" + op: "MatMul" + input: "dipole_charge/filter_type_all/Reshape_8" + input: "dipole_charge/filter_type_all/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_6_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_6_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_6_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_6_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_6_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_6_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_6_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_6_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_6_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_6" + op: "Add" + input: "dipole_charge/filter_type_all/MatMul_4" + input: "dipole_charge/filter_type_all/bias_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/filter_type_all/Tanh_3" + op: "Tanh" + input: "dipole_charge/filter_type_all/add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_9_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_9_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_9_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_9" + op: "Reshape" + input: "dipole_charge/filter_type_all/Tanh_3" + input: "dipole_charge/filter_type_all/Reshape_9/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_7_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_7_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_7_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_7_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_7_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_7_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_7_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_7_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_7_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_7" + op: "Add" + input: "dipole_charge/filter_type_all/concat_3" + input: "dipole_charge/filter_type_all/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_4_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_7" + input: "dipole_charge/filter_type_all/add_7" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_4_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_4_grad/mod" + input: "gradients_2/dipole_charge/filter_type_all/concat_4_grad/ShapeN" + input: "gradients_2/dipole_charge/filter_type_all/concat_4_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_4_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_7" + input: "dipole_charge/filter_type_all/add_7" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_4_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_4_grad/mod" + input: "gradients_1/dipole_charge/filter_type_all/concat_4_grad/ShapeN" + input: "gradients_1/dipole_charge/filter_type_all/concat_4_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_4_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_7" + input: "dipole_charge/filter_type_all/add_7" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_4_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_4_grad/mod" + input: "gradients/dipole_charge/filter_type_all/concat_4_grad/ShapeN" + input: "gradients/dipole_charge/filter_type_all/concat_4_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_4" + op: "ConcatV2" + input: "dipole_charge/filter_type_all/add_7" + input: "dipole_charge/filter_type_all/add_7" + input: "dipole_charge/filter_type_all/concat_4/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_9_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_9_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_9_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_5" + op: "MatMul" + input: "dipole_charge/filter_type_all/add_7" + input: "dipole_charge/filter_type_all/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_8_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_8_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_8_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_8_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_8_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_8_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_8_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_8_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_8_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_8_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_8_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_8_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_8" + op: "Add" + input: "dipole_charge/filter_type_all/MatMul_5" + input: "dipole_charge/filter_type_all/bias_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/filter_type_all/Tanh_4" + op: "Tanh" + input: "dipole_charge/filter_type_all/add_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_10_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_10_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_10_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_10" + op: "Reshape" + input: "dipole_charge/filter_type_all/Tanh_4" + input: "dipole_charge/filter_type_all/Reshape_10/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_9_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_9_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_9_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_9_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_9_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_9_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_9_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_9_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_9_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_9" + op: "Add" + input: "dipole_charge/filter_type_all/concat_4" + input: "dipole_charge/filter_type_all/Reshape_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_5_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_9" + input: "dipole_charge/filter_type_all/add_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_5_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_5_grad/mod" + input: "gradients_2/dipole_charge/filter_type_all/concat_5_grad/ShapeN" + input: "gradients_2/dipole_charge/filter_type_all/concat_5_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_5_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_9" + input: "dipole_charge/filter_type_all/add_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_5_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_5_grad/mod" + input: "gradients_1/dipole_charge/filter_type_all/concat_5_grad/ShapeN" + input: "gradients_1/dipole_charge/filter_type_all/concat_5_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_5_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_9" + input: "dipole_charge/filter_type_all/add_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_5_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_5_grad/mod" + input: "gradients/dipole_charge/filter_type_all/concat_5_grad/ShapeN" + input: "gradients/dipole_charge/filter_type_all/concat_5_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_5" + op: "ConcatV2" + input: "dipole_charge/filter_type_all/add_9" + input: "dipole_charge/filter_type_all/add_9" + input: "dipole_charge/filter_type_all/concat_5/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_11_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_11_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_11_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_6" + op: "MatMul" + input: "dipole_charge/filter_type_all/add_9" + input: "dipole_charge/filter_type_all/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_10_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_10_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_10_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_10_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_10_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_10_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_10_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_10_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_10_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_10_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_10_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_10_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_10" + op: "Add" + input: "dipole_charge/filter_type_all/MatMul_6" + input: "dipole_charge/filter_type_all/bias_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/filter_type_all/Tanh_5" + op: "Tanh" + input: "dipole_charge/filter_type_all/add_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_11_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_11_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_11_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_11" + op: "Reshape" + input: "dipole_charge/filter_type_all/Tanh_5" + input: "dipole_charge/filter_type_all/Reshape_11/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_11_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_11_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_11_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_11_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_11_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_11_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_11_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_11_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_11_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_11" + op: "Add" + input: "dipole_charge/filter_type_all/concat_5" + input: "dipole_charge/filter_type_all/Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_12_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_12_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_12_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_12" + op: "Reshape" + input: "dipole_charge/filter_type_all/add_11" + input: "dipole_charge/filter_type_all/Reshape_12/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_7" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_13" + input: "dipole_charge/filter_type_all/Reshape_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_12_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_12_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_12_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice" + op: "Slice" + input: "dipole_charge/Reshape_5" + input: "dipole_charge/filter_type_all/Slice/begin" + input: "dipole_charge/filter_type_all/Slice/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_grad/sub" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_grad/Shape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_grad/sub_1" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_grad/sub" + input: "dipole_charge/filter_type_all/Slice/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_grad/sub_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_grad/concat" + op: "ConcatV2" + input: "gradients_2/dipole_charge/filter_type_all/Slice_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_6_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_grad/sub" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_grad/Shape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_grad/sub_1" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_grad/sub" + input: "dipole_charge/filter_type_all/Slice/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_grad/sub_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_grad/concat" + op: "ConcatV2" + input: "gradients_1/dipole_charge/filter_type_all/Slice_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_6_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_grad/sub" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_grad/Shape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_grad/sub_1" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_grad/sub" + input: "dipole_charge/filter_type_all/Slice/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_grad/sub_1" + input: "gradients/dipole_charge/filter_type_all/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_grad/concat" + op: "ConcatV2" + input: "gradients/dipole_charge/filter_type_all/Slice_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_6_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_6" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice" + input: "dipole_charge/filter_type_all/Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice" + input: "dipole_charge/filter_type_all/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_1_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_1" + op: "Slice" + input: "dipole_charge/filter_type_all/Reshape" + input: "dipole_charge/filter_type_all/Slice_1/begin" + input: "dipole_charge/filter_type_all/Slice_1/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/sub" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/Shape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/sub_1" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/sub" + input: "dipole_charge/filter_type_all/Slice_1/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/sub_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/concat" + op: "ConcatV2" + input: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_1_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/sub" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/Shape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/sub_1" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/sub" + input: "dipole_charge/filter_type_all/Slice_1/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/sub_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/concat" + op: "ConcatV2" + input: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_1_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_1_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_1_grad/sub" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_1_grad/Shape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_1_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_1_grad/sub_1" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_1_grad/sub" + input: "dipole_charge/filter_type_all/Slice_1/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_1_grad/sub_1" + input: "gradients/dipole_charge/filter_type_all/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_1_grad/concat" + op: "ConcatV2" + input: "gradients/dipole_charge/filter_type_all/Slice_1_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_1_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_1_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_1_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_1" + op: "Reshape" + input: "dipole_charge/filter_type_all/Slice_1" + input: "dipole_charge/filter_type_all/Reshape_1/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/Reshape_1" + input: "dipole_charge/filter_type_all/Reshape_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_grad/mod" + input: "gradients_2/dipole_charge/filter_type_all/concat_grad/ShapeN" + input: "gradients_2/dipole_charge/filter_type_all/concat_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/Reshape_1" + input: "dipole_charge/filter_type_all/Reshape_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_grad/mod" + input: "gradients_1/dipole_charge/filter_type_all/concat_grad/ShapeN" + input: "gradients_1/dipole_charge/filter_type_all/concat_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/Reshape_1" + input: "dipole_charge/filter_type_all/Reshape_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_grad/mod" + input: "gradients/dipole_charge/filter_type_all/concat_grad/ShapeN" + input: "gradients/dipole_charge/filter_type_all/concat_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "dipole_charge/filter_type_all/concat" + op: "ConcatV2" + input: "dipole_charge/filter_type_all/Reshape_1" + input: "dipole_charge/filter_type_all/Reshape_1" + input: "dipole_charge/filter_type_all/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_1_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_1_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_1_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul" + op: "MatMul" + input: "dipole_charge/filter_type_all/Reshape_1" + input: "dipole_charge/filter_type_all/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add" + op: "Add" + input: "dipole_charge/filter_type_all/MatMul" + input: "dipole_charge/filter_type_all/bias_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/filter_type_all/Tanh" + op: "Tanh" + input: "dipole_charge/filter_type_all/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_2_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_2_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_2_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_2" + op: "Reshape" + input: "dipole_charge/filter_type_all/Tanh" + input: "dipole_charge/filter_type_all/Reshape_2/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_1_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_1_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_1_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_1_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_1_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_1_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_1_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_1_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_1_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_1" + op: "Add" + input: "dipole_charge/filter_type_all/concat" + input: "dipole_charge/filter_type_all/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_1_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_1" + input: "dipole_charge/filter_type_all/add_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_1_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_1_grad/mod" + input: "gradients_2/dipole_charge/filter_type_all/concat_1_grad/ShapeN" + input: "gradients_2/dipole_charge/filter_type_all/concat_1_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_1_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_1" + input: "dipole_charge/filter_type_all/add_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_1_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_1_grad/mod" + input: "gradients_1/dipole_charge/filter_type_all/concat_1_grad/ShapeN" + input: "gradients_1/dipole_charge/filter_type_all/concat_1_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_1_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_1" + input: "dipole_charge/filter_type_all/add_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_1_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_1_grad/mod" + input: "gradients/dipole_charge/filter_type_all/concat_1_grad/ShapeN" + input: "gradients/dipole_charge/filter_type_all/concat_1_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_1" + op: "ConcatV2" + input: "dipole_charge/filter_type_all/add_1" + input: "dipole_charge/filter_type_all/add_1" + input: "dipole_charge/filter_type_all/concat_1/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_3_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_3_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_3_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_1" + op: "MatMul" + input: "dipole_charge/filter_type_all/add_1" + input: "dipole_charge/filter_type_all/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_2_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_2_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_2_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_2_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_2_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_2_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_2_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_2_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_2_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_2_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_2_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_2_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_2" + op: "Add" + input: "dipole_charge/filter_type_all/MatMul_1" + input: "dipole_charge/filter_type_all/bias_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/filter_type_all/Tanh_1" + op: "Tanh" + input: "dipole_charge/filter_type_all/add_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_3_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_3_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_3_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_3" + op: "Reshape" + input: "dipole_charge/filter_type_all/Tanh_1" + input: "dipole_charge/filter_type_all/Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_3_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_3_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_3_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_3_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_3_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_3_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_3_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_3_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_3_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_3" + op: "Add" + input: "dipole_charge/filter_type_all/concat_1" + input: "dipole_charge/filter_type_all/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_2_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_3" + input: "dipole_charge/filter_type_all/add_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_2_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_2_grad/mod" + input: "gradients_2/dipole_charge/filter_type_all/concat_2_grad/ShapeN" + input: "gradients_2/dipole_charge/filter_type_all/concat_2_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_2_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_3" + input: "dipole_charge/filter_type_all/add_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_2_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_2_grad/mod" + input: "gradients_1/dipole_charge/filter_type_all/concat_2_grad/ShapeN" + input: "gradients_1/dipole_charge/filter_type_all/concat_2_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_2_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/filter_type_all/add_3" + input: "dipole_charge/filter_type_all/add_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_2_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_2_grad/mod" + input: "gradients/dipole_charge/filter_type_all/concat_2_grad/ShapeN" + input: "gradients/dipole_charge/filter_type_all/concat_2_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "dipole_charge/filter_type_all/concat_2" + op: "ConcatV2" + input: "dipole_charge/filter_type_all/add_3" + input: "dipole_charge/filter_type_all/add_3" + input: "dipole_charge/filter_type_all/concat_2/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_5_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_5_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_5_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/concat_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_2" + op: "MatMul" + input: "dipole_charge/filter_type_all/add_3" + input: "dipole_charge/filter_type_all/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_4_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_4_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_4_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_4_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_4_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_4_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_4_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_4_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_4_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_4" + op: "Add" + input: "dipole_charge/filter_type_all/MatMul_2" + input: "dipole_charge/filter_type_all/bias_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/filter_type_all/Tanh_2" + op: "Tanh" + input: "dipole_charge/filter_type_all/add_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_4_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_4_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_4_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Tanh_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_4" + op: "Reshape" + input: "dipole_charge/filter_type_all/Tanh_2" + input: "dipole_charge/filter_type_all/Reshape_4/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_5_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_5_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_5_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_5_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_5_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_5_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_5_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_5_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_5_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_5" + op: "Add" + input: "dipole_charge/filter_type_all/concat_2" + input: "dipole_charge/filter_type_all/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_5_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_5_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_5_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_5" + op: "Reshape" + input: "dipole_charge/filter_type_all/add_5" + input: "dipole_charge/filter_type_all/Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_3" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_6" + input: "dipole_charge/filter_type_all/Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_12_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_12_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_12_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_12_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_12_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_12_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_12_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_12_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_12_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_12_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_12_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_12_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_12" + op: "Add" + input: "dipole_charge/filter_type_all/MatMul_3" + input: "dipole_charge/filter_type_all/MatMul_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_19_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_19_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_19_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_19_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_19_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_19_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_19_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_19_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_19_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_19_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_19_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_19_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_19" + op: "Add" + input: "dipole_charge/filter_type_all/add_12" + input: "dipole_charge/filter_type_all/MatMul_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_26_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_26_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_26_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_26_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_26_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_26_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_26_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_26_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_26_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_26_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_26_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_26_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_26" + op: "Add" + input: "dipole_charge/filter_type_all/add_19" + input: "dipole_charge/filter_type_all/MatMul_15" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_33_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_26" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_33_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/add_33_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/add_33_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_33_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_26" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_33_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/add_33_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/add_33_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_33_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_26" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_33_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/add_33_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/add_33_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/add_33" + op: "Add" + input: "dipole_charge/filter_type_all/add_26" + input: "dipole_charge/filter_type_all/MatMul_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/mul_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_33" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/filter_type_all/mul_grad/Shape" + input: "gradients_2/dipole_charge/filter_type_all/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/mul_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_33" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/filter_type_all/mul_grad/Shape" + input: "gradients_1/dipole_charge/filter_type_all/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/mul_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/add_33" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/filter_type_all/mul_grad/Shape" + input: "gradients/dipole_charge/filter_type_all/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/mul" + op: "Mul" + input: "dipole_charge/filter_type_all/add_33" + input: "dipole_charge/filter_type_all/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_10_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_11_grad/Shape_1" + op: "Shape" + input: "dipole_charge/filter_type_all/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_11" + op: "Slice" + input: "dipole_charge/filter_type_all/mul" + input: "dipole_charge/filter_type_all/Slice_11/begin" + input: "dipole_charge/filter_type_all/Slice_11/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/sub" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/Shape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/sub_1" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/sub" + input: "dipole_charge/filter_type_all/Slice_11/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/sub_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/concat" + op: "ConcatV2" + input: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/sub" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/Shape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/sub_1" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/sub" + input: "dipole_charge/filter_type_all/Slice_11/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/sub_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/concat" + op: "ConcatV2" + input: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_11_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_11_grad/sub" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_11_grad/Shape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_11_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_11_grad/sub_1" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_11_grad/sub" + input: "dipole_charge/filter_type_all/Slice_11/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_11_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_11_grad/sub_1" + input: "gradients/dipole_charge/filter_type_all/Slice_11_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_11_grad/concat" + op: "ConcatV2" + input: "gradients/dipole_charge/filter_type_all/Slice_11_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_11_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_11_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/transpose" + op: "Transpose" + input: "dipole_charge/filter_type_all/Slice_11" + input: "dipole_charge/filter_type_all/transpose/perm" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tperm" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_7_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/transpose" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_7_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/transpose" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Reshape_7_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/transpose" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Slice_10" + op: "Slice" + input: "dipole_charge/filter_type_all/mul" + input: "dipole_charge/filter_type_all/Slice_10/begin" + input: "dipole_charge/filter_type_all/Slice_10/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/sub" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/Shape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/sub_1" + op: "Sub" + input: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/sub" + input: "dipole_charge/filter_type_all/Slice_10/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/sub_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/concat" + op: "ConcatV2" + input: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/sub" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/Shape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/sub_1" + op: "Sub" + input: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/sub" + input: "dipole_charge/filter_type_all/Slice_10/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/sub_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/concat" + op: "ConcatV2" + input: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_10_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Slice_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_10_grad/sub" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_10_grad/Shape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_10_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_10_grad/sub_1" + op: "Sub" + input: "gradients/dipole_charge/filter_type_all/Slice_10_grad/sub" + input: "dipole_charge/filter_type_all/Slice_10/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_10_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_10_grad/sub_1" + input: "gradients/dipole_charge/filter_type_all/Slice_10_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_10_grad/concat" + op: "ConcatV2" + input: "gradients/dipole_charge/filter_type_all/Slice_10_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_10_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Slice_10_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/MatMul_20" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/mul" + input: "dipole_charge/filter_type_all/Slice_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_35_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_20" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_35_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_20" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_35_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/MatMul_20" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/filter_type_all/Reshape_35" + op: "Reshape" + input: "dipole_charge/filter_type_all/MatMul_20" + input: "dipole_charge/filter_type_all/Reshape_35/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_6_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_35" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_6_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_35" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Reshape_6_grad/Shape" + op: "Shape" + input: "dipole_charge/filter_type_all/Reshape_35" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/strided_slice_5" + op: "StridedSlice" + input: "dipole_charge/Shape_1" + input: "dipole_charge/strided_slice_5/stack" + input: "dipole_charge/strided_slice_5/stack_1" + input: "dipole_charge/strided_slice_5/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/Reshape_7/shape" + op: "Pack" + input: "dipole_charge/strided_slice_5" + input: "dipole_charge/mul_4" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "dipole_charge/Reshape_7" + op: "Reshape" + input: "dipole_charge/filter_type_all/transpose" + input: "dipole_charge/Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/concat_1" + op: "Identity" + input: "dipole_charge/Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/o_rot_mat" + op: "Identity" + input: "dipole_charge/concat_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_9_grad/Shape" + op: "Shape" + input: "dipole_charge/o_rot_mat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_9_grad/Shape" + op: "Shape" + input: "dipole_charge/o_rot_mat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Reshape_9_grad/Shape" + op: "Shape" + input: "dipole_charge/o_rot_mat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Reshape_9" + op: "Reshape" + input: "dipole_charge/o_rot_mat" + input: "dipole_charge/Reshape_9/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_7_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_3_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_7_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_3_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_7_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_3_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Slice_7" + op: "Slice" + input: "dipole_charge/Reshape_9" + input: "dipole_charge/Slice_7/begin" + input: "dipole_charge/Slice_7/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_7_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_7_grad/sub" + op: "Sub" + input: "gradients_2/dipole_charge/Slice_7_grad/Shape_1" + input: "gradients_2/dipole_charge/Slice_7_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_7_grad/sub_1" + op: "Sub" + input: "gradients_2/dipole_charge/Slice_7_grad/sub" + input: "dipole_charge/Slice_7/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_7_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/Slice_7_grad/sub_1" + input: "gradients_2/dipole_charge/Slice_7_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_7_grad/concat" + op: "ConcatV2" + input: "gradients_2/dipole_charge/Slice_7_grad/Reshape" + input: "gradients_2/dipole_charge/Slice_7_grad/Reshape_1" + input: "gradients_2/dipole_charge/Slice_7_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_19_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_7_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_7_grad/sub" + op: "Sub" + input: "gradients_1/dipole_charge/Slice_7_grad/Shape_1" + input: "gradients_1/dipole_charge/Slice_7_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_7_grad/sub_1" + op: "Sub" + input: "gradients_1/dipole_charge/Slice_7_grad/sub" + input: "dipole_charge/Slice_7/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_7_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/Slice_7_grad/sub_1" + input: "gradients_1/dipole_charge/Slice_7_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_7_grad/concat" + op: "ConcatV2" + input: "gradients_1/dipole_charge/Slice_7_grad/Reshape" + input: "gradients_1/dipole_charge/Slice_7_grad/Reshape_1" + input: "gradients_1/dipole_charge/Slice_7_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_19_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_7_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_7_grad/sub" + op: "Sub" + input: "gradients/dipole_charge/Slice_7_grad/Shape_1" + input: "gradients/dipole_charge/Slice_7_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_7_grad/sub_1" + op: "Sub" + input: "gradients/dipole_charge/Slice_7_grad/sub" + input: "dipole_charge/Slice_7/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_7_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/Slice_7_grad/sub_1" + input: "gradients/dipole_charge/Slice_7_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_7_grad/concat" + op: "ConcatV2" + input: "gradients/dipole_charge/Slice_7_grad/Reshape" + input: "gradients/dipole_charge/Slice_7_grad/Reshape_1" + input: "gradients/dipole_charge/Slice_7_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Reshape_19_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Reshape_19" + op: "Reshape" + input: "dipole_charge/Slice_7" + input: "dipole_charge/Reshape_19/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Slice_3" + op: "Slice" + input: "dipole_charge/Reshape_9" + input: "dipole_charge/Slice_3/begin" + input: "dipole_charge/Slice_3/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_3_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_3_grad/sub" + op: "Sub" + input: "gradients_2/dipole_charge/Slice_3_grad/Shape_1" + input: "gradients_2/dipole_charge/Slice_3_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_3_grad/sub_1" + op: "Sub" + input: "gradients_2/dipole_charge/Slice_3_grad/sub" + input: "dipole_charge/Slice_3/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_3_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/Slice_3_grad/sub_1" + input: "gradients_2/dipole_charge/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_3_grad/concat" + op: "ConcatV2" + input: "gradients_2/dipole_charge/Slice_3_grad/Reshape" + input: "gradients_2/dipole_charge/Slice_3_grad/Reshape_1" + input: "gradients_2/dipole_charge/Slice_3_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_13_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_3_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_3_grad/sub" + op: "Sub" + input: "gradients_1/dipole_charge/Slice_3_grad/Shape_1" + input: "gradients_1/dipole_charge/Slice_3_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_3_grad/sub_1" + op: "Sub" + input: "gradients_1/dipole_charge/Slice_3_grad/sub" + input: "dipole_charge/Slice_3/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_3_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/Slice_3_grad/sub_1" + input: "gradients_1/dipole_charge/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_3_grad/concat" + op: "ConcatV2" + input: "gradients_1/dipole_charge/Slice_3_grad/Reshape" + input: "gradients_1/dipole_charge/Slice_3_grad/Reshape_1" + input: "gradients_1/dipole_charge/Slice_3_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_13_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_3_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_3_grad/sub" + op: "Sub" + input: "gradients/dipole_charge/Slice_3_grad/Shape_1" + input: "gradients/dipole_charge/Slice_3_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_3_grad/sub_1" + op: "Sub" + input: "gradients/dipole_charge/Slice_3_grad/sub" + input: "dipole_charge/Slice_3/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/Slice_3_grad/sub_1" + input: "gradients/dipole_charge/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_3_grad/concat" + op: "ConcatV2" + input: "gradients/dipole_charge/Slice_3_grad/Reshape" + input: "gradients/dipole_charge/Slice_3_grad/Reshape_1" + input: "gradients/dipole_charge/Slice_3_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Reshape_13_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Reshape_13" + op: "Reshape" + input: "dipole_charge/Slice_3" + input: "dipole_charge/Reshape_13/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Shape" + op: "Shape" + input: "dipole_charge/Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/strided_slice_3" + op: "StridedSlice" + input: "dipole_charge/Shape" + input: "dipole_charge/strided_slice_3/stack" + input: "dipole_charge/strided_slice_3/stack_1" + input: "dipole_charge/strided_slice_3/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/Reshape_6/shape" + op: "Pack" + input: "dipole_charge/strided_slice_3" + input: "dipole_charge/mul_2" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "dipole_charge/Reshape_6" + op: "Reshape" + input: "dipole_charge/filter_type_all/Reshape_35" + input: "dipole_charge/Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/concat" + op: "Identity" + input: "dipole_charge/Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/o_descriptor" + op: "Identity" + input: "dipole_charge/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_8_grad/Shape" + op: "Shape" + input: "dipole_charge/o_descriptor" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_8_grad/Shape" + op: "Shape" + input: "dipole_charge/o_descriptor" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Reshape_8_grad/Shape" + op: "Shape" + input: "dipole_charge/o_descriptor" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Reshape_8" + op: "Reshape" + input: "dipole_charge/o_descriptor" + input: "dipole_charge/Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_6_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_2_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_6_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_2_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_6_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_2_grad/Shape_1" + op: "Shape" + input: "dipole_charge/Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Slice_6" + op: "Slice" + input: "dipole_charge/Reshape_8" + input: "dipole_charge/Slice_6/begin" + input: "dipole_charge/Slice_6/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_6_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_6_grad/sub" + op: "Sub" + input: "gradients_2/dipole_charge/Slice_6_grad/Shape_1" + input: "gradients_2/dipole_charge/Slice_6_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_6_grad/sub_1" + op: "Sub" + input: "gradients_2/dipole_charge/Slice_6_grad/sub" + input: "dipole_charge/Slice_6/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_6_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/Slice_6_grad/sub_1" + input: "gradients_2/dipole_charge/Slice_6_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_6_grad/concat" + op: "ConcatV2" + input: "gradients_2/dipole_charge/Slice_6_grad/Reshape" + input: "gradients_2/dipole_charge/Slice_6_grad/Reshape_1" + input: "gradients_2/dipole_charge/Slice_6_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_18_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_6_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_6_grad/sub" + op: "Sub" + input: "gradients_1/dipole_charge/Slice_6_grad/Shape_1" + input: "gradients_1/dipole_charge/Slice_6_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_6_grad/sub_1" + op: "Sub" + input: "gradients_1/dipole_charge/Slice_6_grad/sub" + input: "dipole_charge/Slice_6/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_6_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/Slice_6_grad/sub_1" + input: "gradients_1/dipole_charge/Slice_6_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_6_grad/concat" + op: "ConcatV2" + input: "gradients_1/dipole_charge/Slice_6_grad/Reshape" + input: "gradients_1/dipole_charge/Slice_6_grad/Reshape_1" + input: "gradients_1/dipole_charge/Slice_6_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_18_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_6_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_6_grad/sub" + op: "Sub" + input: "gradients/dipole_charge/Slice_6_grad/Shape_1" + input: "gradients/dipole_charge/Slice_6_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_6_grad/sub_1" + op: "Sub" + input: "gradients/dipole_charge/Slice_6_grad/sub" + input: "dipole_charge/Slice_6/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_6_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/Slice_6_grad/sub_1" + input: "gradients/dipole_charge/Slice_6_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_6_grad/concat" + op: "ConcatV2" + input: "gradients/dipole_charge/Slice_6_grad/Reshape" + input: "gradients/dipole_charge/Slice_6_grad/Reshape_1" + input: "gradients/dipole_charge/Slice_6_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Reshape_18_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Reshape_18" + op: "Reshape" + input: "dipole_charge/Slice_6" + input: "dipole_charge/Reshape_18/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_0_type_3/MatMul" + op: "MatMul" + input: "dipole_charge/Reshape_18" + input: "dipole_charge/layer_0_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/layer_0_type_3/add_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_0_type_3/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_0_type_3/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/layer_0_type_3/add_grad/Shape" + input: "gradients_2/dipole_charge/layer_0_type_3/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_0_type_3/add_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_0_type_3/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_0_type_3/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/layer_0_type_3/add_grad/Shape" + input: "gradients_1/dipole_charge/layer_0_type_3/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_0_type_3/add_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_0_type_3/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_0_type_3/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/layer_0_type_3/add_grad/Shape" + input: "gradients/dipole_charge/layer_0_type_3/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_0_type_3/add" + op: "Add" + input: "dipole_charge/layer_0_type_3/MatMul" + input: "dipole_charge/layer_0_type_3/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/layer_0_type_3/Tanh" + op: "Tanh" + input: "dipole_charge/layer_0_type_3/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/layer_0_type_3/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_0_type_3/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_0_type_3/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_0_type_3/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_0_type_3/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_0_type_3/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_0_type_3/Reshape" + op: "Reshape" + input: "dipole_charge/layer_0_type_3/Tanh" + input: "dipole_charge/layer_0_type_3/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/add_6_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_0_type_3/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/add_6_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_0_type_3/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/add_6_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_0_type_3/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_1_type_3/MatMul" + op: "MatMul" + input: "dipole_charge/layer_0_type_3/Reshape" + input: "dipole_charge/layer_1_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_3/add_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_1_type_3/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_3/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/layer_1_type_3/add_grad/Shape" + input: "gradients_2/dipole_charge/layer_1_type_3/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_3/add_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_1_type_3/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_3/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/layer_1_type_3/add_grad/Shape" + input: "gradients_1/dipole_charge/layer_1_type_3/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_3/add_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_1_type_3/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_3/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/layer_1_type_3/add_grad/Shape" + input: "gradients/dipole_charge/layer_1_type_3/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_1_type_3/add" + op: "Add" + input: "dipole_charge/layer_1_type_3/MatMul" + input: "dipole_charge/layer_1_type_3/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/layer_1_type_3/Tanh" + op: "Tanh" + input: "dipole_charge/layer_1_type_3/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_3/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_1_type_3/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_3/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_1_type_3/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_3/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_1_type_3/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_1_type_3/Reshape" + op: "Reshape" + input: "dipole_charge/layer_1_type_3/Tanh" + input: "dipole_charge/layer_1_type_3/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_3/mul_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_1_type_3/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_3/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/layer_1_type_3/mul_grad/Shape" + input: "gradients_2/dipole_charge/layer_1_type_3/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_3/mul_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_1_type_3/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_3/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/layer_1_type_3/mul_grad/Shape" + input: "gradients_1/dipole_charge/layer_1_type_3/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_3/mul_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_1_type_3/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_3/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/layer_1_type_3/mul_grad/Shape" + input: "gradients/dipole_charge/layer_1_type_3/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_1_type_3/mul" + op: "Mul" + input: "dipole_charge/layer_1_type_3/Reshape" + input: "dipole_charge/layer_1_type_3/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/add_6_grad/Shape_1" + op: "Shape" + input: "dipole_charge/layer_1_type_3/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/add_6_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/add_6_grad/Shape" + input: "gradients_2/dipole_charge/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/add_6_grad/Shape_1" + op: "Shape" + input: "dipole_charge/layer_1_type_3/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/add_6_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/add_6_grad/Shape" + input: "gradients_1/dipole_charge/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/add_6_grad/Shape_1" + op: "Shape" + input: "dipole_charge/layer_1_type_3/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/add_6_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/add_6_grad/Shape" + input: "gradients/dipole_charge/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/add_6" + op: "Add" + input: "dipole_charge/layer_0_type_3/Reshape" + input: "dipole_charge/layer_1_type_3/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/add_7_grad/Shape" + op: "Shape" + input: "dipole_charge/add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/add_7_grad/Shape" + op: "Shape" + input: "dipole_charge/add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/add_7_grad/Shape" + op: "Shape" + input: "dipole_charge/add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_2_type_3/MatMul" + op: "MatMul" + input: "dipole_charge/add_6" + input: "dipole_charge/layer_2_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_3/add_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_2_type_3/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_3/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/layer_2_type_3/add_grad/Shape" + input: "gradients_2/dipole_charge/layer_2_type_3/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_3/add_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_2_type_3/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_3/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/layer_2_type_3/add_grad/Shape" + input: "gradients_1/dipole_charge/layer_2_type_3/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_3/add_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_2_type_3/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_3/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/layer_2_type_3/add_grad/Shape" + input: "gradients/dipole_charge/layer_2_type_3/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_2_type_3/add" + op: "Add" + input: "dipole_charge/layer_2_type_3/MatMul" + input: "dipole_charge/layer_2_type_3/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/layer_2_type_3/Tanh" + op: "Tanh" + input: "dipole_charge/layer_2_type_3/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_3/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_2_type_3/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_3/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_2_type_3/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_3/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_2_type_3/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_2_type_3/Reshape" + op: "Reshape" + input: "dipole_charge/layer_2_type_3/Tanh" + input: "dipole_charge/layer_2_type_3/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_3/mul_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_2_type_3/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_3/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/layer_2_type_3/mul_grad/Shape" + input: "gradients_2/dipole_charge/layer_2_type_3/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_3/mul_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_2_type_3/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_3/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/layer_2_type_3/mul_grad/Shape" + input: "gradients_1/dipole_charge/layer_2_type_3/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_3/mul_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_2_type_3/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_3/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/layer_2_type_3/mul_grad/Shape" + input: "gradients/dipole_charge/layer_2_type_3/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_2_type_3/mul" + op: "Mul" + input: "dipole_charge/layer_2_type_3/Reshape" + input: "dipole_charge/layer_2_type_3/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/add_7_grad/Shape_1" + op: "Shape" + input: "dipole_charge/layer_2_type_3/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/add_7_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/add_7_grad/Shape" + input: "gradients_2/dipole_charge/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/add_7_grad/Shape_1" + op: "Shape" + input: "dipole_charge/layer_2_type_3/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/add_7_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/add_7_grad/Shape" + input: "gradients_1/dipole_charge/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/add_7_grad/Shape_1" + op: "Shape" + input: "dipole_charge/layer_2_type_3/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/add_7_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/add_7_grad/Shape" + input: "gradients/dipole_charge/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/add_7" + op: "Add" + input: "dipole_charge/add_6" + input: "dipole_charge/layer_2_type_3/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/final_layer_type_3/MatMul" + op: "MatMul" + input: "dipole_charge/add_7" + input: "dipole_charge/final_layer_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/final_layer_type_3/add_grad/Shape" + op: "Shape" + input: "dipole_charge/final_layer_type_3/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/final_layer_type_3/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/final_layer_type_3/add_grad/Shape" + input: "gradients_2/dipole_charge/final_layer_type_3/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/final_layer_type_3/add_grad/Shape" + op: "Shape" + input: "dipole_charge/final_layer_type_3/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/final_layer_type_3/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/final_layer_type_3/add_grad/Shape" + input: "gradients_1/dipole_charge/final_layer_type_3/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/final_layer_type_3/add_grad/Shape" + op: "Shape" + input: "dipole_charge/final_layer_type_3/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/final_layer_type_3/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/final_layer_type_3/add_grad/Shape" + input: "gradients/dipole_charge/final_layer_type_3/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/final_layer_type_3/add" + op: "Add" + input: "dipole_charge/final_layer_type_3/MatMul" + input: "dipole_charge/final_layer_type_3/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_20_grad/Shape" + op: "Shape" + input: "dipole_charge/final_layer_type_3/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_20_grad/Shape" + op: "Shape" + input: "dipole_charge/final_layer_type_3/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Reshape_20_grad/Shape" + op: "Shape" + input: "dipole_charge/final_layer_type_3/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Slice_2" + op: "Slice" + input: "dipole_charge/Reshape_8" + input: "dipole_charge/Slice_2/begin" + input: "dipole_charge/Slice_2/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_2_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_2_grad/sub" + op: "Sub" + input: "gradients_2/dipole_charge/Slice_2_grad/Shape_1" + input: "gradients_2/dipole_charge/Slice_2_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_2_grad/sub_1" + op: "Sub" + input: "gradients_2/dipole_charge/Slice_2_grad/sub" + input: "dipole_charge/Slice_2/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_2_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/Slice_2_grad/sub_1" + input: "gradients_2/dipole_charge/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_2_grad/concat" + op: "ConcatV2" + input: "gradients_2/dipole_charge/Slice_2_grad/Reshape" + input: "gradients_2/dipole_charge/Slice_2_grad/Reshape_1" + input: "gradients_2/dipole_charge/Slice_2_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_12_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_2_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_2_grad/sub" + op: "Sub" + input: "gradients_1/dipole_charge/Slice_2_grad/Shape_1" + input: "gradients_1/dipole_charge/Slice_2_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_2_grad/sub_1" + op: "Sub" + input: "gradients_1/dipole_charge/Slice_2_grad/sub" + input: "dipole_charge/Slice_2/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_2_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/Slice_2_grad/sub_1" + input: "gradients_1/dipole_charge/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_2_grad/concat" + op: "ConcatV2" + input: "gradients_1/dipole_charge/Slice_2_grad/Reshape" + input: "gradients_1/dipole_charge/Slice_2_grad/Reshape_1" + input: "gradients_1/dipole_charge/Slice_2_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_12_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_2_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_2_grad/sub" + op: "Sub" + input: "gradients/dipole_charge/Slice_2_grad/Shape_1" + input: "gradients/dipole_charge/Slice_2_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_2_grad/sub_1" + op: "Sub" + input: "gradients/dipole_charge/Slice_2_grad/sub" + input: "dipole_charge/Slice_2/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_2_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/Slice_2_grad/sub_1" + input: "gradients/dipole_charge/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_2_grad/concat" + op: "ConcatV2" + input: "gradients/dipole_charge/Slice_2_grad/Reshape" + input: "gradients/dipole_charge/Slice_2_grad/Reshape_1" + input: "gradients/dipole_charge/Slice_2_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Reshape_12_grad/Shape" + op: "Shape" + input: "dipole_charge/Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Reshape_12" + op: "Reshape" + input: "dipole_charge/Slice_2" + input: "dipole_charge/Reshape_12/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_0_type_1/MatMul" + op: "MatMul" + input: "dipole_charge/Reshape_12" + input: "dipole_charge/layer_0_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/layer_0_type_1/add_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_0_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_0_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/layer_0_type_1/add_grad/Shape" + input: "gradients_2/dipole_charge/layer_0_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_0_type_1/add_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_0_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_0_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/layer_0_type_1/add_grad/Shape" + input: "gradients_1/dipole_charge/layer_0_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_0_type_1/add_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_0_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_0_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/layer_0_type_1/add_grad/Shape" + input: "gradients/dipole_charge/layer_0_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_0_type_1/add" + op: "Add" + input: "dipole_charge/layer_0_type_1/MatMul" + input: "dipole_charge/layer_0_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/layer_0_type_1/Tanh" + op: "Tanh" + input: "dipole_charge/layer_0_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/layer_0_type_1/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_0_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_0_type_1/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_0_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_0_type_1/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_0_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_0_type_1/Reshape" + op: "Reshape" + input: "dipole_charge/layer_0_type_1/Tanh" + input: "dipole_charge/layer_0_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/add_2_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_0_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/add_2_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_0_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/add_2_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_0_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_1_type_1/MatMul" + op: "MatMul" + input: "dipole_charge/layer_0_type_1/Reshape" + input: "dipole_charge/layer_1_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_1/add_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_1_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/layer_1_type_1/add_grad/Shape" + input: "gradients_2/dipole_charge/layer_1_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_1/add_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_1_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/layer_1_type_1/add_grad/Shape" + input: "gradients_1/dipole_charge/layer_1_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_1/add_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_1_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/layer_1_type_1/add_grad/Shape" + input: "gradients/dipole_charge/layer_1_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_1_type_1/add" + op: "Add" + input: "dipole_charge/layer_1_type_1/MatMul" + input: "dipole_charge/layer_1_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/layer_1_type_1/Tanh" + op: "Tanh" + input: "dipole_charge/layer_1_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_1/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_1_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_1/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_1_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_1/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_1_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_1_type_1/Reshape" + op: "Reshape" + input: "dipole_charge/layer_1_type_1/Tanh" + input: "dipole_charge/layer_1_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_1/mul_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_1_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/layer_1_type_1/mul_grad/Shape" + input: "gradients_2/dipole_charge/layer_1_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_1/mul_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_1_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/layer_1_type_1/mul_grad/Shape" + input: "gradients_1/dipole_charge/layer_1_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_1/mul_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_1_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/layer_1_type_1/mul_grad/Shape" + input: "gradients/dipole_charge/layer_1_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_1_type_1/mul" + op: "Mul" + input: "dipole_charge/layer_1_type_1/Reshape" + input: "dipole_charge/layer_1_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/add_2_grad/Shape_1" + op: "Shape" + input: "dipole_charge/layer_1_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/add_2_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/add_2_grad/Shape" + input: "gradients_2/dipole_charge/add_2_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/add_2_grad/Shape_1" + op: "Shape" + input: "dipole_charge/layer_1_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/add_2_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/add_2_grad/Shape" + input: "gradients_1/dipole_charge/add_2_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/add_2_grad/Shape_1" + op: "Shape" + input: "dipole_charge/layer_1_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/add_2_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/add_2_grad/Shape" + input: "gradients/dipole_charge/add_2_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/add_2" + op: "Add" + input: "dipole_charge/layer_0_type_1/Reshape" + input: "dipole_charge/layer_1_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/add_3_grad/Shape" + op: "Shape" + input: "dipole_charge/add_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/add_3_grad/Shape" + op: "Shape" + input: "dipole_charge/add_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/add_3_grad/Shape" + op: "Shape" + input: "dipole_charge/add_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_2_type_1/MatMul" + op: "MatMul" + input: "dipole_charge/add_2" + input: "dipole_charge/layer_2_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_1/add_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_2_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/layer_2_type_1/add_grad/Shape" + input: "gradients_2/dipole_charge/layer_2_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_1/add_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_2_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/layer_2_type_1/add_grad/Shape" + input: "gradients_1/dipole_charge/layer_2_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_1/add_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_2_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/layer_2_type_1/add_grad/Shape" + input: "gradients/dipole_charge/layer_2_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_2_type_1/add" + op: "Add" + input: "dipole_charge/layer_2_type_1/MatMul" + input: "dipole_charge/layer_2_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/layer_2_type_1/Tanh" + op: "Tanh" + input: "dipole_charge/layer_2_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_1/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_2_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_1/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_2_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_1/Reshape_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_2_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_2_type_1/Reshape" + op: "Reshape" + input: "dipole_charge/layer_2_type_1/Tanh" + input: "dipole_charge/layer_2_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_1/mul_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_2_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/layer_2_type_1/mul_grad/Shape" + input: "gradients_2/dipole_charge/layer_2_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_1/mul_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_2_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/layer_2_type_1/mul_grad/Shape" + input: "gradients_1/dipole_charge/layer_2_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_1/mul_grad/Shape" + op: "Shape" + input: "dipole_charge/layer_2_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/layer_2_type_1/mul_grad/Shape" + input: "gradients/dipole_charge/layer_2_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/layer_2_type_1/mul" + op: "Mul" + input: "dipole_charge/layer_2_type_1/Reshape" + input: "dipole_charge/layer_2_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/add_3_grad/Shape_1" + op: "Shape" + input: "dipole_charge/layer_2_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/add_3_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/add_3_grad/Shape" + input: "gradients_2/dipole_charge/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/add_3_grad/Shape_1" + op: "Shape" + input: "dipole_charge/layer_2_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/add_3_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/add_3_grad/Shape" + input: "gradients_1/dipole_charge/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/add_3_grad/Shape_1" + op: "Shape" + input: "dipole_charge/layer_2_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/add_3_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/add_3_grad/Shape" + input: "gradients/dipole_charge/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/add_3" + op: "Add" + input: "dipole_charge/add_2" + input: "dipole_charge/layer_2_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/final_layer_type_1/MatMul" + op: "MatMul" + input: "dipole_charge/add_3" + input: "dipole_charge/final_layer_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/final_layer_type_1/add_grad/Shape" + op: "Shape" + input: "dipole_charge/final_layer_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/final_layer_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_2/dipole_charge/final_layer_type_1/add_grad/Shape" + input: "gradients_2/dipole_charge/final_layer_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/final_layer_type_1/add_grad/Shape" + op: "Shape" + input: "dipole_charge/final_layer_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/final_layer_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients_1/dipole_charge/final_layer_type_1/add_grad/Shape" + input: "gradients_1/dipole_charge/final_layer_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/final_layer_type_1/add_grad/Shape" + op: "Shape" + input: "dipole_charge/final_layer_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/final_layer_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/dipole_charge/final_layer_type_1/add_grad/Shape" + input: "gradients/dipole_charge/final_layer_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/final_layer_type_1/add" + op: "Add" + input: "dipole_charge/final_layer_type_1/MatMul" + input: "dipole_charge/final_layer_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_14_grad/Shape" + op: "Shape" + input: "dipole_charge/final_layer_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_14_grad/Shape" + op: "Shape" + input: "dipole_charge/final_layer_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Reshape_14_grad/Shape" + op: "Shape" + input: "dipole_charge/final_layer_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Shape_5" + op: "Shape" + input: "dipole_charge/Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/strided_slice_27" + op: "StridedSlice" + input: "dipole_charge/Shape_5" + input: "dipole_charge/strided_slice_27/stack" + input: "dipole_charge/strided_slice_27/stack_1" + input: "dipole_charge/strided_slice_27/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/Reshape_21/shape" + op: "Pack" + input: "dipole_charge/strided_slice_27" + input: "dipole_charge/strided_slice_28" + input: "dipole_charge/Reshape_21/shape/2" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "dipole_charge/Shape_4" + op: "Shape" + input: "dipole_charge/Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/strided_slice_25" + op: "StridedSlice" + input: "dipole_charge/Shape_4" + input: "dipole_charge/strided_slice_25/stack" + input: "dipole_charge/strided_slice_25/stack_1" + input: "dipole_charge/strided_slice_25/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/mul_22" + op: "Mul" + input: "dipole_charge/strided_slice_25" + input: "dipole_charge/strided_slice_26" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Reshape_20/shape" + op: "Pack" + input: "dipole_charge/mul_22" + input: "dipole_charge/Reshape_20/shape/1" + input: "dipole_charge/Reshape_20/shape/2" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "dipole_charge/Reshape_20" + op: "Reshape" + input: "dipole_charge/final_layer_type_3/add" + input: "dipole_charge/Reshape_20/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/Reshape_20" + input: "dipole_charge/Reshape_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_21_grad/Shape" + op: "Shape" + input: "dipole_charge/MatMul_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_21_grad/Shape" + op: "Shape" + input: "dipole_charge/MatMul_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Reshape_21_grad/Shape" + op: "Shape" + input: "dipole_charge/MatMul_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Reshape_21" + op: "Reshape" + input: "dipole_charge/MatMul_1" + input: "dipole_charge/Reshape_21/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Shape_3" + op: "Shape" + input: "dipole_charge/Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/strided_slice_17" + op: "StridedSlice" + input: "dipole_charge/Shape_3" + input: "dipole_charge/strided_slice_17/stack" + input: "dipole_charge/strided_slice_17/stack_1" + input: "dipole_charge/strided_slice_17/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/Reshape_15/shape" + op: "Pack" + input: "dipole_charge/strided_slice_17" + input: "dipole_charge/strided_slice_18" + input: "dipole_charge/Reshape_15/shape/2" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "dipole_charge/Shape_2" + op: "Shape" + input: "dipole_charge/Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/strided_slice_15" + op: "StridedSlice" + input: "dipole_charge/Shape_2" + input: "dipole_charge/strided_slice_15/stack" + input: "dipole_charge/strided_slice_15/stack_1" + input: "dipole_charge/strided_slice_15/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "dipole_charge/mul_13" + op: "Mul" + input: "dipole_charge/strided_slice_15" + input: "dipole_charge/strided_slice_16" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Reshape_14/shape" + op: "Pack" + input: "dipole_charge/mul_13" + input: "dipole_charge/Reshape_14/shape/1" + input: "dipole_charge/Reshape_14/shape/2" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "dipole_charge/Reshape_14" + op: "Reshape" + input: "dipole_charge/final_layer_type_1/add" + input: "dipole_charge/Reshape_14/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/MatMul" + op: "BatchMatMul" + input: "dipole_charge/Reshape_14" + input: "dipole_charge/Reshape_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_15_grad/Shape" + op: "Shape" + input: "dipole_charge/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_15_grad/Shape" + op: "Shape" + input: "dipole_charge/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Reshape_15_grad/Shape" + op: "Shape" + input: "dipole_charge/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Reshape_15" + op: "Reshape" + input: "dipole_charge/MatMul" + input: "dipole_charge/Reshape_15/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/concat_2_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/Reshape_15" + input: "dipole_charge/Reshape_21" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/concat_2_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_2/dipole_charge/concat_2_grad/mod" + input: "gradients_2/dipole_charge/concat_2_grad/ShapeN" + input: "gradients_2/dipole_charge/concat_2_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients_1/dipole_charge/concat_2_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/Reshape_15" + input: "dipole_charge/Reshape_21" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/concat_2_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_1/dipole_charge/concat_2_grad/mod" + input: "gradients_1/dipole_charge/concat_2_grad/ShapeN" + input: "gradients_1/dipole_charge/concat_2_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "gradients/dipole_charge/concat_2_grad/ShapeN" + op: "ShapeN" + input: "dipole_charge/Reshape_15" + input: "dipole_charge/Reshape_21" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/concat_2_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/dipole_charge/concat_2_grad/mod" + input: "gradients/dipole_charge/concat_2_grad/ShapeN" + input: "gradients/dipole_charge/concat_2_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "dipole_charge/concat_2" + op: "ConcatV2" + input: "dipole_charge/Reshape_15" + input: "dipole_charge/Reshape_21" + input: "dipole_charge/concat_2/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_24_grad/Shape" + op: "Shape" + input: "dipole_charge/concat_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_24_grad/Shape" + op: "Shape" + input: "dipole_charge/concat_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Reshape_24_grad/Shape" + op: "Shape" + input: "dipole_charge/concat_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/Reshape_24" + op: "Reshape" + input: "dipole_charge/concat_2" + input: "dipole_charge/Reshape_24/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/o_dipole" + op: "Identity" + input: "dipole_charge/Reshape_24" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/Reshape_2_grad/Shape" + op: "Shape" + input: "dipole_charge/o_dipole" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Reshape_2_grad/Shape" + op: "Shape" + input: "dipole_charge/o_dipole" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_2_grad/Shape" + op: "Shape" + input: "dipole_charge/o_dipole" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_2" + op: "Reshape" + input: "dipole_charge/o_dipole" + input: "Reshape_2/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Slice_1_grad/Shape_1" + op: "Shape" + input: "Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Slice_grad/Shape_1" + op: "Shape" + input: "Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_1_grad/Shape_1" + op: "Shape" + input: "Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_grad/Shape_1" + op: "Shape" + input: "Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/Shape_1" + op: "Shape" + input: "Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/Shape_1" + op: "Shape" + input: "Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_3" + op: "Shape" + input: "Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_9" + op: "StridedSlice" + input: "Shape_3" + input: "strided_slice_9/stack" + input: "strided_slice_9/stack_1" + input: "strided_slice_9/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "zeros_2/packed" + op: "Pack" + input: "strided_slice_9" + input: "mul_5" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "zeros_2" + op: "Fill" + input: "zeros_2/packed" + input: "zeros_2/Const" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "index_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_1" + op: "Slice" + input: "Reshape_2" + input: "Slice_1/begin" + input: "Slice_1/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/Slice_1_grad/Shape" + op: "Shape" + input: "Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Slice_1_grad/sub" + op: "Sub" + input: "gradients_2/Slice_1_grad/Shape_1" + input: "gradients_2/Slice_1_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Slice_1_grad/sub_1" + op: "Sub" + input: "gradients_2/Slice_1_grad/sub" + input: "Slice_1/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Slice_1_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/Slice_1_grad/sub_1" + input: "gradients_2/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Slice_1_grad/concat" + op: "ConcatV2" + input: "gradients_2/Slice_1_grad/Reshape" + input: "gradients_2/Slice_1_grad/Reshape_1" + input: "gradients_2/Slice_1_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_1_grad/Shape" + op: "Shape" + input: "Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_1_grad/sub" + op: "Sub" + input: "gradients_1/Slice_1_grad/Shape_1" + input: "gradients_1/Slice_1_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_1_grad/sub_1" + op: "Sub" + input: "gradients_1/Slice_1_grad/sub" + input: "Slice_1/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_1_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/Slice_1_grad/sub_1" + input: "gradients_1/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_1_grad/concat" + op: "ConcatV2" + input: "gradients_1/Slice_1_grad/Reshape" + input: "gradients_1/Slice_1_grad/Reshape_1" + input: "gradients_1/Slice_1_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/Shape" + op: "Shape" + input: "Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/sub" + op: "Sub" + input: "gradients/Slice_1_grad/Shape_1" + input: "gradients/Slice_1_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/sub_1" + op: "Sub" + input: "gradients/Slice_1_grad/sub" + input: "Slice_1/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/Slice_1_grad/sub_1" + input: "gradients/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/concat" + op: "ConcatV2" + input: "gradients/Slice_1_grad/Reshape" + input: "gradients/Slice_1_grad/Reshape_1" + input: "gradients/Slice_1_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_2" + op: "Shape" + input: "Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_5" + op: "StridedSlice" + input: "Shape_2" + input: "strided_slice_5/stack" + input: "strided_slice_5/stack_1" + input: "strided_slice_5/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "zeros_1/packed" + op: "Pack" + input: "strided_slice_5" + input: "mul_2" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "zeros_1" + op: "Fill" + input: "zeros_1/packed" + input: "zeros_1/Const" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "index_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice" + op: "Slice" + input: "Reshape_2" + input: "Slice/begin" + input: "Slice/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/Slice_grad/Shape" + op: "Shape" + input: "Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Slice_grad/sub" + op: "Sub" + input: "gradients_2/Slice_grad/Shape_1" + input: "gradients_2/Slice_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Slice_grad/sub_1" + op: "Sub" + input: "gradients_2/Slice_grad/sub" + input: "Slice/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Slice_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/Slice_grad/sub_1" + input: "gradients_2/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Slice_grad/concat" + op: "ConcatV2" + input: "gradients_2/Slice_grad/Reshape" + input: "gradients_2/Slice_grad/Reshape_1" + input: "gradients_2/Slice_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_grad/Shape" + op: "Shape" + input: "Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_grad/sub" + op: "Sub" + input: "gradients_1/Slice_grad/Shape_1" + input: "gradients_1/Slice_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_grad/sub_1" + op: "Sub" + input: "gradients_1/Slice_grad/sub" + input: "Slice/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/Slice_grad/sub_1" + input: "gradients_1/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_grad/concat" + op: "ConcatV2" + input: "gradients_1/Slice_grad/Reshape" + input: "gradients_1/Slice_grad/Reshape_1" + input: "gradients_1/Slice_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/Shape" + op: "Shape" + input: "Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/sub" + op: "Sub" + input: "gradients/Slice_grad/Shape_1" + input: "gradients/Slice_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/sub_1" + op: "Sub" + input: "gradients/Slice_grad/sub" + input: "Slice/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/Reshape_1" + op: "Reshape" + input: "gradients/Slice_grad/sub_1" + input: "gradients/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/concat" + op: "ConcatV2" + input: "gradients/Slice_grad/Reshape" + input: "gradients/Slice_grad/Reshape_1" + input: "gradients/Slice_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_1" + op: "Shape" + input: "Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_1" + op: "StridedSlice" + input: "Shape_1" + input: "strided_slice_1/stack" + input: "strided_slice_1/stack_1" + input: "strided_slice_1/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "zeros/packed" + op: "Pack" + input: "strided_slice_1" + input: "mul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "zeros" + op: "Fill" + input: "zeros/packed" + input: "zeros/Const" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "index_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/concat_grad/ShapeN" + op: "ShapeN" + input: "zeros" + input: "Slice" + input: "zeros_1" + input: "Slice_1" + input: "zeros_2" + attr { + key: "N" + value { + i: 5 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/concat_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_2/concat_grad/mod" + input: "gradients_2/concat_grad/ShapeN" + input: "gradients_2/concat_grad/ShapeN:1" + input: "gradients_2/concat_grad/ShapeN:2" + input: "gradients_2/concat_grad/ShapeN:3" + input: "gradients_2/concat_grad/ShapeN:4" + attr { + key: "N" + value { + i: 5 + } + } +} +node { + name: "gradients_1/concat_grad/ShapeN" + op: "ShapeN" + input: "zeros" + input: "Slice" + input: "zeros_1" + input: "Slice_1" + input: "zeros_2" + attr { + key: "N" + value { + i: 5 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/concat_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients_1/concat_grad/mod" + input: "gradients_1/concat_grad/ShapeN" + input: "gradients_1/concat_grad/ShapeN:1" + input: "gradients_1/concat_grad/ShapeN:2" + input: "gradients_1/concat_grad/ShapeN:3" + input: "gradients_1/concat_grad/ShapeN:4" + attr { + key: "N" + value { + i: 5 + } + } +} +node { + name: "gradients/concat_grad/ShapeN" + op: "ShapeN" + input: "zeros" + input: "Slice" + input: "zeros_1" + input: "Slice_1" + input: "zeros_2" + attr { + key: "N" + value { + i: 5 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/concat_grad/mod" + input: "gradients/concat_grad/ShapeN" + input: "gradients/concat_grad/ShapeN:1" + input: "gradients/concat_grad/ShapeN:2" + input: "gradients/concat_grad/ShapeN:3" + input: "gradients/concat_grad/ShapeN:4" + attr { + key: "N" + value { + i: 5 + } + } +} +node { + name: "concat" + op: "ConcatV2" + input: "zeros" + input: "Slice" + input: "zeros_1" + input: "Slice_1" + input: "zeros_2" + input: "concat/axis" + attr { + key: "N" + value { + i: 5 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Reshape_3_grad/Shape" + op: "Shape" + input: "concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Reshape_3_grad/Shape" + op: "Shape" + input: "concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_3_grad/Shape" + op: "Shape" + input: "concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_3" + op: "Reshape" + input: "concat" + input: "Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Slice_4_grad/Shape_1" + op: "Shape" + input: "Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_3_grad/Shape_1" + op: "Shape" + input: "Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/Shape_1" + op: "Shape" + input: "Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_4" + op: "Slice" + input: "Reshape_3" + input: "Slice_4/begin" + input: "Slice_4/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/Slice_4_grad/Shape" + op: "Shape" + input: "Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Slice_4_grad/sub" + op: "Sub" + input: "gradients_2/Slice_4_grad/Shape_1" + input: "gradients_2/Slice_4_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Slice_4_grad/sub_1" + op: "Sub" + input: "gradients_2/Slice_4_grad/sub" + input: "Slice_4/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Slice_4_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/Slice_4_grad/sub_1" + input: "gradients_2/Slice_4_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Slice_4_grad/concat" + op: "ConcatV2" + input: "gradients_2/Slice_4_grad/Reshape" + input: "gradients_2/Slice_4_grad/Reshape_1" + input: "gradients_2/Slice_4_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Reshape_4_grad/Shape" + op: "Shape" + input: "Slice_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_4" + op: "Reshape" + input: "Slice_4" + input: "Reshape_4/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Shape" + op: "Shape" + input: "Reshape_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Fill" + op: "Fill" + input: "gradients_2/Shape" + input: "gradients_2/grad_ys_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "index_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Reshape_4_grad/Reshape" + op: "Reshape" + input: "gradients_2/Fill" + input: "gradients_2/Reshape_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Slice_4_grad/Pad" + op: "Pad" + input: "gradients_2/Reshape_4_grad/Reshape" + input: "gradients_2/Slice_4_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/Reshape_3_grad/Reshape" + op: "Reshape" + input: "gradients_2/Slice_4_grad/Pad" + input: "gradients_2/Reshape_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/concat_grad/Slice_3" + op: "Slice" + input: "gradients_2/Reshape_3_grad/Reshape" + input: "gradients_2/concat_grad/ConcatOffset:3" + input: "gradients_2/concat_grad/ShapeN:3" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/Slice_1_grad/Pad" + op: "Pad" + input: "gradients_2/concat_grad/Slice_3" + input: "gradients_2/Slice_1_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/concat_grad/Slice_1" + op: "Slice" + input: "gradients_2/Reshape_3_grad/Reshape" + input: "gradients_2/concat_grad/ConcatOffset:1" + input: "gradients_2/concat_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/Slice_grad/Pad" + op: "Pad" + input: "gradients_2/concat_grad/Slice_1" + input: "gradients_2/Slice_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/AddN" + op: "AddN" + input: "gradients_2/Slice_grad/Pad" + input: "gradients_2/Slice_1_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/Slice_grad/Pad" + } + } + } +} +node { + name: "gradients_2/Reshape_2_grad/Reshape" + op: "Reshape" + input: "gradients_2/AddN" + input: "gradients_2/Reshape_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_24_grad/Reshape" + op: "Reshape" + input: "gradients_2/Reshape_2_grad/Reshape" + input: "gradients_2/dipole_charge/Reshape_24_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/concat_2_grad/Slice_1" + op: "Slice" + input: "gradients_2/dipole_charge/Reshape_24_grad/Reshape" + input: "gradients_2/dipole_charge/concat_2_grad/ConcatOffset:1" + input: "gradients_2/dipole_charge/concat_2_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_21_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/concat_2_grad/Slice_1" + input: "gradients_2/dipole_charge/Reshape_21_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/MatMul_1_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/Reshape_20" + input: "gradients_2/dipole_charge/Reshape_21_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_19_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/MatMul_1_grad/MatMul_1" + input: "gradients_2/dipole_charge/Reshape_19_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_7_grad/Pad" + op: "Pad" + input: "gradients_2/dipole_charge/Reshape_19_grad/Reshape" + input: "gradients_2/dipole_charge/Slice_7_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/MatMul_1_grad/MatMul" + op: "BatchMatMul" + input: "gradients_2/dipole_charge/Reshape_21_grad/Reshape" + input: "dipole_charge/Reshape_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_20_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/MatMul_1_grad/MatMul" + input: "gradients_2/dipole_charge/Reshape_20_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/final_layer_type_3/add_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/Reshape_20_grad/Reshape" + input: "gradients_2/dipole_charge/final_layer_type_3/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/final_layer_type_3/add_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/final_layer_type_3/add_grad/Sum" + input: "gradients_2/dipole_charge/final_layer_type_3/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/final_layer_type_3/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/final_layer_type_3/add_grad/Reshape" + input: "dipole_charge/final_layer_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/add_7_grad/Sum_1" + op: "Sum" + input: "gradients_2/dipole_charge/final_layer_type_3/MatMul_grad/MatMul" + input: "gradients_2/dipole_charge/add_7_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/add_7_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/add_7_grad/Sum_1" + input: "gradients_2/dipole_charge/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_3/mul_grad/Mul" + op: "Mul" + input: "gradients_2/dipole_charge/add_7_grad/Reshape_1" + input: "dipole_charge/layer_2_type_3/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_3/mul_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/layer_2_type_3/mul_grad/Mul" + input: "gradients_2/dipole_charge/layer_2_type_3/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_3/mul_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/layer_2_type_3/mul_grad/Sum" + input: "gradients_2/dipole_charge/layer_2_type_3/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_3/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/layer_2_type_3/mul_grad/Reshape" + input: "gradients_2/dipole_charge/layer_2_type_3/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_3/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/layer_2_type_3/Tanh" + input: "gradients_2/dipole_charge/layer_2_type_3/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_3/add_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/layer_2_type_3/Tanh_grad/TanhGrad" + input: "gradients_2/dipole_charge/layer_2_type_3/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_3/add_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/layer_2_type_3/add_grad/Sum" + input: "gradients_2/dipole_charge/layer_2_type_3/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_3/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/layer_2_type_3/add_grad/Reshape" + input: "dipole_charge/layer_2_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/add_7_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/final_layer_type_3/MatMul_grad/MatMul" + input: "gradients_2/dipole_charge/add_7_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/add_7_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/add_7_grad/Sum" + input: "gradients_2/dipole_charge/add_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/AddN_3" + op: "AddN" + input: "gradients_2/dipole_charge/add_7_grad/Reshape" + input: "gradients_2/dipole_charge/layer_2_type_3/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/add_7_grad/Reshape" + } + } + } +} +node { + name: "gradients_2/dipole_charge/add_6_grad/Sum_1" + op: "Sum" + input: "gradients_2/AddN_3" + input: "gradients_2/dipole_charge/add_6_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/add_6_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/add_6_grad/Sum_1" + input: "gradients_2/dipole_charge/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_3/mul_grad/Mul" + op: "Mul" + input: "gradients_2/dipole_charge/add_6_grad/Reshape_1" + input: "dipole_charge/layer_1_type_3/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_3/mul_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/layer_1_type_3/mul_grad/Mul" + input: "gradients_2/dipole_charge/layer_1_type_3/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_3/mul_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/layer_1_type_3/mul_grad/Sum" + input: "gradients_2/dipole_charge/layer_1_type_3/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_3/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/layer_1_type_3/mul_grad/Reshape" + input: "gradients_2/dipole_charge/layer_1_type_3/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_3/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/layer_1_type_3/Tanh" + input: "gradients_2/dipole_charge/layer_1_type_3/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_3/add_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/layer_1_type_3/Tanh_grad/TanhGrad" + input: "gradients_2/dipole_charge/layer_1_type_3/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_3/add_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/layer_1_type_3/add_grad/Sum" + input: "gradients_2/dipole_charge/layer_1_type_3/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_3/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/layer_1_type_3/add_grad/Reshape" + input: "dipole_charge/layer_1_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/add_6_grad/Sum" + op: "Sum" + input: "gradients_2/AddN_3" + input: "gradients_2/dipole_charge/add_6_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/add_6_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/add_6_grad/Sum" + input: "gradients_2/dipole_charge/add_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/AddN_5" + op: "AddN" + input: "gradients_2/dipole_charge/add_6_grad/Reshape" + input: "gradients_2/dipole_charge/layer_1_type_3/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/add_6_grad/Reshape" + } + } + } +} +node { + name: "gradients_2/dipole_charge/layer_0_type_3/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_2/AddN_5" + input: "gradients_2/dipole_charge/layer_0_type_3/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_0_type_3/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/layer_0_type_3/Tanh" + input: "gradients_2/dipole_charge/layer_0_type_3/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/layer_0_type_3/add_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/layer_0_type_3/Tanh_grad/TanhGrad" + input: "gradients_2/dipole_charge/layer_0_type_3/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/layer_0_type_3/add_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/layer_0_type_3/add_grad/Sum" + input: "gradients_2/dipole_charge/layer_0_type_3/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_0_type_3/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/layer_0_type_3/add_grad/Reshape" + input: "dipole_charge/layer_0_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_18_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/layer_0_type_3/MatMul_grad/MatMul" + input: "gradients_2/dipole_charge/Reshape_18_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_6_grad/Pad" + op: "Pad" + input: "gradients_2/dipole_charge/Reshape_18_grad/Reshape" + input: "gradients_2/dipole_charge/Slice_6_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/concat_2_grad/Slice" + op: "Slice" + input: "gradients_2/dipole_charge/Reshape_24_grad/Reshape" + input: "gradients_2/dipole_charge/concat_2_grad/ConcatOffset" + input: "gradients_2/dipole_charge/concat_2_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_15_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/concat_2_grad/Slice" + input: "gradients_2/dipole_charge/Reshape_15_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/MatMul_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/Reshape_14" + input: "gradients_2/dipole_charge/Reshape_15_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_13_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/MatMul_grad/MatMul_1" + input: "gradients_2/dipole_charge/Reshape_13_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_3_grad/Pad" + op: "Pad" + input: "gradients_2/dipole_charge/Reshape_13_grad/Reshape" + input: "gradients_2/dipole_charge/Slice_3_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/AddN_1" + op: "AddN" + input: "gradients_2/dipole_charge/Slice_3_grad/Pad" + input: "gradients_2/dipole_charge/Slice_7_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/Slice_3_grad/Pad" + } + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_9_grad/Reshape" + op: "Reshape" + input: "gradients_2/AddN_1" + input: "gradients_2/dipole_charge/Reshape_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_7_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/Reshape_9_grad/Reshape" + input: "gradients_2/dipole_charge/Reshape_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/transpose_grad/transpose" + op: "Transpose" + input: "gradients_2/dipole_charge/Reshape_7_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/transpose_grad/InvertPermutation" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tperm" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/Pad" + op: "Pad" + input: "gradients_2/dipole_charge/filter_type_all/transpose_grad/transpose" + input: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/MatMul_grad/MatMul" + op: "BatchMatMul" + input: "gradients_2/dipole_charge/Reshape_15_grad/Reshape" + input: "dipole_charge/Reshape_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_14_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/MatMul_grad/MatMul" + input: "gradients_2/dipole_charge/Reshape_14_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/final_layer_type_1/add_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/Reshape_14_grad/Reshape" + input: "gradients_2/dipole_charge/final_layer_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/final_layer_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/final_layer_type_1/add_grad/Sum" + input: "gradients_2/dipole_charge/final_layer_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/final_layer_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/final_layer_type_1/add_grad/Reshape" + input: "dipole_charge/final_layer_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/add_3_grad/Sum_1" + op: "Sum" + input: "gradients_2/dipole_charge/final_layer_type_1/MatMul_grad/MatMul" + input: "gradients_2/dipole_charge/add_3_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/add_3_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/add_3_grad/Sum_1" + input: "gradients_2/dipole_charge/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients_2/dipole_charge/add_3_grad/Reshape_1" + input: "dipole_charge/layer_2_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/layer_2_type_1/mul_grad/Mul" + input: "gradients_2/dipole_charge/layer_2_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/layer_2_type_1/mul_grad/Sum" + input: "gradients_2/dipole_charge/layer_2_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/layer_2_type_1/mul_grad/Reshape" + input: "gradients_2/dipole_charge/layer_2_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/layer_2_type_1/Tanh" + input: "gradients_2/dipole_charge/layer_2_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_1/add_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/layer_2_type_1/Tanh_grad/TanhGrad" + input: "gradients_2/dipole_charge/layer_2_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/layer_2_type_1/add_grad/Sum" + input: "gradients_2/dipole_charge/layer_2_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_2_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/layer_2_type_1/add_grad/Reshape" + input: "dipole_charge/layer_2_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/add_3_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/final_layer_type_1/MatMul_grad/MatMul" + input: "gradients_2/dipole_charge/add_3_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/add_3_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/add_3_grad/Sum" + input: "gradients_2/dipole_charge/add_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/AddN_2" + op: "AddN" + input: "gradients_2/dipole_charge/add_3_grad/Reshape" + input: "gradients_2/dipole_charge/layer_2_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/add_3_grad/Reshape" + } + } + } +} +node { + name: "gradients_2/dipole_charge/add_2_grad/Sum_1" + op: "Sum" + input: "gradients_2/AddN_2" + input: "gradients_2/dipole_charge/add_2_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/add_2_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/add_2_grad/Sum_1" + input: "gradients_2/dipole_charge/add_2_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients_2/dipole_charge/add_2_grad/Reshape_1" + input: "dipole_charge/layer_1_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/layer_1_type_1/mul_grad/Mul" + input: "gradients_2/dipole_charge/layer_1_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/layer_1_type_1/mul_grad/Sum" + input: "gradients_2/dipole_charge/layer_1_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/layer_1_type_1/mul_grad/Reshape" + input: "gradients_2/dipole_charge/layer_1_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/layer_1_type_1/Tanh" + input: "gradients_2/dipole_charge/layer_1_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_1/add_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/layer_1_type_1/Tanh_grad/TanhGrad" + input: "gradients_2/dipole_charge/layer_1_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/layer_1_type_1/add_grad/Sum" + input: "gradients_2/dipole_charge/layer_1_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_1_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/layer_1_type_1/add_grad/Reshape" + input: "dipole_charge/layer_1_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/add_2_grad/Sum" + op: "Sum" + input: "gradients_2/AddN_2" + input: "gradients_2/dipole_charge/add_2_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/add_2_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/add_2_grad/Sum" + input: "gradients_2/dipole_charge/add_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/AddN_4" + op: "AddN" + input: "gradients_2/dipole_charge/add_2_grad/Reshape" + input: "gradients_2/dipole_charge/layer_1_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/add_2_grad/Reshape" + } + } + } +} +node { + name: "gradients_2/dipole_charge/layer_0_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_2/AddN_4" + input: "gradients_2/dipole_charge/layer_0_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_0_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/layer_0_type_1/Tanh" + input: "gradients_2/dipole_charge/layer_0_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/layer_0_type_1/add_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/layer_0_type_1/Tanh_grad/TanhGrad" + input: "gradients_2/dipole_charge/layer_0_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/layer_0_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/layer_0_type_1/add_grad/Sum" + input: "gradients_2/dipole_charge/layer_0_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/layer_0_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/layer_0_type_1/add_grad/Reshape" + input: "dipole_charge/layer_0_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_12_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/layer_0_type_1/MatMul_grad/MatMul" + input: "gradients_2/dipole_charge/Reshape_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Slice_2_grad/Pad" + op: "Pad" + input: "gradients_2/dipole_charge/Reshape_12_grad/Reshape" + input: "gradients_2/dipole_charge/Slice_2_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/AddN_6" + op: "AddN" + input: "gradients_2/dipole_charge/Slice_2_grad/Pad" + input: "gradients_2/dipole_charge/Slice_6_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/Slice_2_grad/Pad" + } + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_8_grad/Reshape" + op: "Reshape" + input: "gradients_2/AddN_6" + input: "gradients_2/dipole_charge/Reshape_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_6_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/Reshape_8_grad/Reshape" + input: "gradients_2/dipole_charge/Reshape_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_35_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/Reshape_6_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_35_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_20_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/mul" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_35_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/Pad" + op: "Pad" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_20_grad/MatMul_1" + input: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_20_grad/MatMul" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Slice_10" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_35_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_2/AddN_7" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/Slice_11_grad/Pad" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_20_grad/MatMul" + input: "gradients_2/dipole_charge/filter_type_all/Slice_10_grad/Pad" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/Slice_11_grad/Pad" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/mul_grad/Mul" + op: "Mul" + input: "gradients_2/AddN_7" + input: "dipole_charge/filter_type_all/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/mul_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/mul_grad/Mul" + input: "gradients_2/dipole_charge/filter_type_all/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/mul_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/mul_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_33_grad/Sum_1" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/mul_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_33_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_33_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_33_grad/Sum_1" + input: "gradients_2/dipole_charge/filter_type_all/add_33_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_19_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_34" + input: "gradients_2/dipole_charge/filter_type_all/add_33_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_33_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_19_grad/MatMul_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_33_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_32_grad/Sum_1" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_33_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_32_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_32_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_32_grad/Sum_1" + input: "gradients_2/dipole_charge/filter_type_all/add_32_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_32_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_32_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_32_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Tanh_14_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_14" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_32_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_31_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Tanh_14_grad/TanhGrad" + input: "gradients_2/dipole_charge/filter_type_all/add_31_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_31_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_31_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_31_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_18_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/filter_type_all/add_31_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_3_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_32_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_33_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_32_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_32_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_32_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_32_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_14_grad/Slice_1" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_32_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_14_grad/ConcatOffset:1" + input: "gradients_2/dipole_charge/filter_type_all/concat_14_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_14_grad/Slice" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_32_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_14_grad/ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_14_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/AddN_8" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/concat_14_grad/Slice" + input: "gradients_2/dipole_charge/filter_type_all/concat_14_grad/Slice_1" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_18_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/concat_14_grad/Slice" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_30_grad/Sum_1" + op: "Sum" + input: "gradients_2/AddN_8" + input: "gradients_2/dipole_charge/filter_type_all/add_30_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_30_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_30_grad/Sum_1" + input: "gradients_2/dipole_charge/filter_type_all/add_30_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_31_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_30_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_31_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Tanh_13_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_13" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_31_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_29_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Tanh_13_grad/TanhGrad" + input: "gradients_2/dipole_charge/filter_type_all/add_29_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_29_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_29_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_29_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_17_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/filter_type_all/add_29_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_2_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_30_grad/Sum" + op: "Sum" + input: "gradients_2/AddN_8" + input: "gradients_2/dipole_charge/filter_type_all/add_30_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_30_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_30_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_30_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_13_grad/Slice_1" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_30_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_13_grad/ConcatOffset:1" + input: "gradients_2/dipole_charge/filter_type_all/concat_13_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_13_grad/Slice" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_30_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_13_grad/ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_13_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/AddN_13" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/concat_13_grad/Slice" + input: "gradients_2/dipole_charge/filter_type_all/concat_13_grad/Slice_1" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_17_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/concat_13_grad/Slice" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_28_grad/Sum_1" + op: "Sum" + input: "gradients_2/AddN_13" + input: "gradients_2/dipole_charge/filter_type_all/add_28_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_28_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_28_grad/Sum_1" + input: "gradients_2/dipole_charge/filter_type_all/add_28_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_30_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_28_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_30_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Tanh_12_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_12" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_30_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_27_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Tanh_12_grad/TanhGrad" + input: "gradients_2/dipole_charge/filter_type_all/add_27_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_27_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_27_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_27_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_16_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/filter_type_all/add_27_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_1_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_28_grad/Sum" + op: "Sum" + input: "gradients_2/AddN_13" + input: "gradients_2/dipole_charge/filter_type_all/add_28_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_28_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_28_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_28_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_12_grad/Slice_1" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_28_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_12_grad/ConcatOffset:1" + input: "gradients_2/dipole_charge/filter_type_all/concat_12_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_12_grad/Slice" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_28_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_12_grad/ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_12_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/AddN_18" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/concat_12_grad/Slice" + input: "gradients_2/dipole_charge/filter_type_all/concat_12_grad/Slice_1" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_16_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/concat_12_grad/Slice" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_29_grad/Reshape" + op: "Reshape" + input: "gradients_2/AddN_18" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_29_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/Pad" + op: "Pad" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_29_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_28_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_9_grad/Pad" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_28_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_19_grad/MatMul" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_33" + input: "gradients_2/dipole_charge/filter_type_all/add_33_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_34_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_19_grad/MatMul" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_34_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/AddN_23" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_34_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_28_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/Reshape_34_grad/Reshape" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/Pad" + op: "Pad" + input: "gradients_2/AddN_23" + input: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_33_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/mul_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_33_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_33_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_33_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_33_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_26_grad/Sum_1" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_33_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_26_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_26_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_26_grad/Sum_1" + input: "gradients_2/dipole_charge/filter_type_all/add_26_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_15_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_27" + input: "gradients_2/dipole_charge/filter_type_all/add_26_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_26_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_15_grad/MatMul_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_26_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_25_grad/Sum_1" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_26_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_25_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_25_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_25_grad/Sum_1" + input: "gradients_2/dipole_charge/filter_type_all/add_25_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_25_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_25_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_25_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Tanh_11_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_11" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_25_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_24_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Tanh_11_grad/TanhGrad" + input: "gradients_2/dipole_charge/filter_type_all/add_24_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_24_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_24_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_24_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_14_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/filter_type_all/add_24_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_3_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_25_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_26_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_25_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_25_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_25_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_25_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_11_grad/Slice_1" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_25_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_11_grad/ConcatOffset:1" + input: "gradients_2/dipole_charge/filter_type_all/concat_11_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_11_grad/Slice" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_25_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_11_grad/ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_11_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/AddN_9" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/concat_11_grad/Slice" + input: "gradients_2/dipole_charge/filter_type_all/concat_11_grad/Slice_1" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_14_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/concat_11_grad/Slice" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_23_grad/Sum_1" + op: "Sum" + input: "gradients_2/AddN_9" + input: "gradients_2/dipole_charge/filter_type_all/add_23_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_23_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_23_grad/Sum_1" + input: "gradients_2/dipole_charge/filter_type_all/add_23_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_24_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_23_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_24_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Tanh_10_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_10" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_24_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_22_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Tanh_10_grad/TanhGrad" + input: "gradients_2/dipole_charge/filter_type_all/add_22_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_22_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_22_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_22_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_13_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/filter_type_all/add_22_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_2_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_23_grad/Sum" + op: "Sum" + input: "gradients_2/AddN_9" + input: "gradients_2/dipole_charge/filter_type_all/add_23_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_23_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_23_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_23_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_10_grad/Slice_1" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_23_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_10_grad/ConcatOffset:1" + input: "gradients_2/dipole_charge/filter_type_all/concat_10_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_10_grad/Slice" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_23_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_10_grad/ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_10_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/AddN_14" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/concat_10_grad/Slice" + input: "gradients_2/dipole_charge/filter_type_all/concat_10_grad/Slice_1" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_13_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/concat_10_grad/Slice" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_21_grad/Sum_1" + op: "Sum" + input: "gradients_2/AddN_14" + input: "gradients_2/dipole_charge/filter_type_all/add_21_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_21_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_21_grad/Sum_1" + input: "gradients_2/dipole_charge/filter_type_all/add_21_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_23_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_21_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_23_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Tanh_9_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_9" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_23_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_20_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Tanh_9_grad/TanhGrad" + input: "gradients_2/dipole_charge/filter_type_all/add_20_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_20_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_20_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_20_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_12_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/filter_type_all/add_20_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_1_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_21_grad/Sum" + op: "Sum" + input: "gradients_2/AddN_14" + input: "gradients_2/dipole_charge/filter_type_all/add_21_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_21_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_21_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_21_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_9_grad/Slice_1" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_21_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_9_grad/ConcatOffset:1" + input: "gradients_2/dipole_charge/filter_type_all/concat_9_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_9_grad/Slice" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_21_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_9_grad/ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_9_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/AddN_19" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/concat_9_grad/Slice" + input: "gradients_2/dipole_charge/filter_type_all/concat_9_grad/Slice_1" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_12_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/concat_9_grad/Slice" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_22_grad/Reshape" + op: "Reshape" + input: "gradients_2/AddN_19" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_22_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/Pad" + op: "Pad" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_22_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_21_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_7_grad/Pad" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_21_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_15_grad/MatMul" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_26" + input: "gradients_2/dipole_charge/filter_type_all/add_26_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_27_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_15_grad/MatMul" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_27_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/AddN_24" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_27_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_21_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/Reshape_27_grad/Reshape" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/Pad" + op: "Pad" + input: "gradients_2/AddN_24" + input: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_26_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_33_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_26_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_26_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_26_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_26_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_19_grad/Sum_1" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_26_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_19_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_19_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_19_grad/Sum_1" + input: "gradients_2/dipole_charge/filter_type_all/add_19_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_11_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_20" + input: "gradients_2/dipole_charge/filter_type_all/add_19_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_19_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_11_grad/MatMul_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_19_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_18_grad/Sum_1" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_19_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_18_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_18_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_18_grad/Sum_1" + input: "gradients_2/dipole_charge/filter_type_all/add_18_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_18_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_18_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_18_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Tanh_8_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_8" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_18_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_17_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Tanh_8_grad/TanhGrad" + input: "gradients_2/dipole_charge/filter_type_all/add_17_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_17_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_17_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_17_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_10_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/filter_type_all/add_17_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_3_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_18_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_19_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_18_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_18_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_18_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_18_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_8_grad/Slice_1" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_18_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_8_grad/ConcatOffset:1" + input: "gradients_2/dipole_charge/filter_type_all/concat_8_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_8_grad/Slice" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_18_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_8_grad/ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_8_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/AddN_10" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/concat_8_grad/Slice" + input: "gradients_2/dipole_charge/filter_type_all/concat_8_grad/Slice_1" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_10_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/concat_8_grad/Slice" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_16_grad/Sum_1" + op: "Sum" + input: "gradients_2/AddN_10" + input: "gradients_2/dipole_charge/filter_type_all/add_16_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_16_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_16_grad/Sum_1" + input: "gradients_2/dipole_charge/filter_type_all/add_16_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_17_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_16_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_17_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Tanh_7_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_7" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_17_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_15_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Tanh_7_grad/TanhGrad" + input: "gradients_2/dipole_charge/filter_type_all/add_15_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_15_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_15_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_15_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_9_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/filter_type_all/add_15_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_2_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_16_grad/Sum" + op: "Sum" + input: "gradients_2/AddN_10" + input: "gradients_2/dipole_charge/filter_type_all/add_16_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_16_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_16_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_16_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_7_grad/Slice_1" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_16_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_7_grad/ConcatOffset:1" + input: "gradients_2/dipole_charge/filter_type_all/concat_7_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_7_grad/Slice" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_16_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_7_grad/ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_7_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/AddN_15" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/concat_7_grad/Slice" + input: "gradients_2/dipole_charge/filter_type_all/concat_7_grad/Slice_1" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_9_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/concat_7_grad/Slice" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_14_grad/Sum_1" + op: "Sum" + input: "gradients_2/AddN_15" + input: "gradients_2/dipole_charge/filter_type_all/add_14_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_14_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_14_grad/Sum_1" + input: "gradients_2/dipole_charge/filter_type_all/add_14_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_16_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_14_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_16_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Tanh_6_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_6" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_16_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_13_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Tanh_6_grad/TanhGrad" + input: "gradients_2/dipole_charge/filter_type_all/add_13_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_13_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_13_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_13_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_8_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/filter_type_all/add_13_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_1_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_14_grad/Sum" + op: "Sum" + input: "gradients_2/AddN_15" + input: "gradients_2/dipole_charge/filter_type_all/add_14_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_14_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_14_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_14_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_6_grad/Slice_1" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_14_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_6_grad/ConcatOffset:1" + input: "gradients_2/dipole_charge/filter_type_all/concat_6_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_6_grad/Slice" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_14_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_6_grad/ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_6_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/AddN_20" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/concat_6_grad/Slice" + input: "gradients_2/dipole_charge/filter_type_all/concat_6_grad/Slice_1" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_8_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/concat_6_grad/Slice" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_15_grad/Reshape" + op: "Reshape" + input: "gradients_2/AddN_20" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_15_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/Pad" + op: "Pad" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_15_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_14_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_5_grad/Pad" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_14_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_11_grad/MatMul" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_19" + input: "gradients_2/dipole_charge/filter_type_all/add_19_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_20_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_11_grad/MatMul" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_20_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/AddN_25" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_20_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_14_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/Reshape_20_grad/Reshape" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/Pad" + op: "Pad" + input: "gradients_2/AddN_25" + input: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_19_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_26_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_19_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_19_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_19_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_19_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_12_grad/Sum_1" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_19_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_12_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_12_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_12_grad/Sum_1" + input: "gradients_2/dipole_charge/filter_type_all/add_12_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_7_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_13" + input: "gradients_2/dipole_charge/filter_type_all/add_12_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_12_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_7_grad/MatMul_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_11_grad/Sum_1" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_12_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_11_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_11_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_11_grad/Sum_1" + input: "gradients_2/dipole_charge/filter_type_all/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_11_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_11_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Tanh_5_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_5" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_11_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_10_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Tanh_5_grad/TanhGrad" + input: "gradients_2/dipole_charge/filter_type_all/add_10_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_10_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_10_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_6_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/filter_type_all/add_10_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_11_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_12_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_11_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_11_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_11_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_5_grad/Slice_1" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_11_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_5_grad/ConcatOffset:1" + input: "gradients_2/dipole_charge/filter_type_all/concat_5_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_5_grad/Slice" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_11_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_5_grad/ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_5_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/AddN_12" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/concat_5_grad/Slice" + input: "gradients_2/dipole_charge/filter_type_all/concat_5_grad/Slice_1" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_6_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/concat_5_grad/Slice" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_9_grad/Sum_1" + op: "Sum" + input: "gradients_2/AddN_12" + input: "gradients_2/dipole_charge/filter_type_all/add_9_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_9_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_9_grad/Sum_1" + input: "gradients_2/dipole_charge/filter_type_all/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_10_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_9_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Tanh_4_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_4" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_10_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_8_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Tanh_4_grad/TanhGrad" + input: "gradients_2/dipole_charge/filter_type_all/add_8_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_8_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_8_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_5_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/filter_type_all/add_8_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_9_grad/Sum" + op: "Sum" + input: "gradients_2/AddN_12" + input: "gradients_2/dipole_charge/filter_type_all/add_9_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_9_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_9_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_4_grad/Slice_1" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_9_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_4_grad/ConcatOffset:1" + input: "gradients_2/dipole_charge/filter_type_all/concat_4_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_4_grad/Slice" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_9_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_4_grad/ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_4_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/AddN_17" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/concat_4_grad/Slice" + input: "gradients_2/dipole_charge/filter_type_all/concat_4_grad/Slice_1" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_5_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/concat_4_grad/Slice" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_7_grad/Sum_1" + op: "Sum" + input: "gradients_2/AddN_17" + input: "gradients_2/dipole_charge/filter_type_all/add_7_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_7_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_7_grad/Sum_1" + input: "gradients_2/dipole_charge/filter_type_all/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_9_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_7_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Tanh_3_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_3" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_9_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_6_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Tanh_3_grad/TanhGrad" + input: "gradients_2/dipole_charge/filter_type_all/add_6_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_6_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_6_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_4_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/filter_type_all/add_6_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_7_grad/Sum" + op: "Sum" + input: "gradients_2/AddN_17" + input: "gradients_2/dipole_charge/filter_type_all/add_7_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_7_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_7_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_3_grad/Slice_1" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_7_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_3_grad/ConcatOffset:1" + input: "gradients_2/dipole_charge/filter_type_all/concat_3_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_3_grad/Slice" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_7_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_3_grad/ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_3_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/AddN_22" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/concat_3_grad/Slice" + input: "gradients_2/dipole_charge/filter_type_all/concat_3_grad/Slice_1" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_4_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/concat_3_grad/Slice" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_8_grad/Reshape" + op: "Reshape" + input: "gradients_2/AddN_22" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/Pad" + op: "Pad" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_8_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_7_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_3_grad/Pad" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_7_grad/MatMul" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_12" + input: "gradients_2/dipole_charge/filter_type_all/add_12_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_13_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_7_grad/MatMul" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_13_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/AddN_27" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_13_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_7_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/Reshape_13_grad/Reshape" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/Pad" + op: "Pad" + input: "gradients_2/AddN_27" + input: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_12_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_19_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_12_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_12_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_12_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_3_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_6" + input: "gradients_2/dipole_charge/filter_type_all/add_12_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_5_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_3_grad/MatMul_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_5_grad/Sum_1" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_5_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_5_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_5_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_5_grad/Sum_1" + input: "gradients_2/dipole_charge/filter_type_all/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_4_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_5_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Tanh_2_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_2" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_4_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_4_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Tanh_2_grad/TanhGrad" + input: "gradients_2/dipole_charge/filter_type_all/add_4_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_4_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_4_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_2_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/filter_type_all/add_4_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_5_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_5_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_5_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_5_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_5_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_2_grad/Slice_1" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_5_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_2_grad/ConcatOffset:1" + input: "gradients_2/dipole_charge/filter_type_all/concat_2_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_2_grad/Slice" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_5_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_2_grad/ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_2_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/AddN_11" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/concat_2_grad/Slice" + input: "gradients_2/dipole_charge/filter_type_all/concat_2_grad/Slice_1" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_2_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/concat_2_grad/Slice" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_3_grad/Sum_1" + op: "Sum" + input: "gradients_2/AddN_11" + input: "gradients_2/dipole_charge/filter_type_all/add_3_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_3_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_3_grad/Sum_1" + input: "gradients_2/dipole_charge/filter_type_all/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_3_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_3_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Tanh_1_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_3_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_2_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Tanh_1_grad/TanhGrad" + input: "gradients_2/dipole_charge/filter_type_all/add_2_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_2_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_2_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_1_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/filter_type_all/add_2_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_3_grad/Sum" + op: "Sum" + input: "gradients_2/AddN_11" + input: "gradients_2/dipole_charge/filter_type_all/add_3_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_3_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_3_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_1_grad/Slice_1" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_3_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_1_grad/ConcatOffset:1" + input: "gradients_2/dipole_charge/filter_type_all/concat_1_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_1_grad/Slice" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_3_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_1_grad/ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_1_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/AddN_16" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/concat_1_grad/Slice" + input: "gradients_2/dipole_charge/filter_type_all/concat_1_grad/Slice_1" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_1_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/concat_1_grad/Slice" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_1_grad/Sum_1" + op: "Sum" + input: "gradients_2/AddN_16" + input: "gradients_2/dipole_charge/filter_type_all/add_1_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_1_grad/Reshape_1" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_1_grad/Sum_1" + input: "gradients_2/dipole_charge/filter_type_all/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_2_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_1_grad/Reshape_1" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_2_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_grad/Sum" + op: "Sum" + input: "gradients_2/dipole_charge/filter_type_all/Tanh_grad/TanhGrad" + input: "gradients_2/dipole_charge/filter_type_all/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_2/dipole_charge/filter_type_all/add_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_1_grad/Sum" + op: "Sum" + input: "gradients_2/AddN_16" + input: "gradients_2/dipole_charge/filter_type_all/add_1_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/add_1_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/add_1_grad/Sum" + input: "gradients_2/dipole_charge/filter_type_all/add_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_grad/Slice_1" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_1_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_grad/ConcatOffset:1" + input: "gradients_2/dipole_charge/filter_type_all/concat_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/concat_grad/Slice" + op: "Slice" + input: "gradients_2/dipole_charge/filter_type_all/add_1_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/concat_grad/ConcatOffset" + input: "gradients_2/dipole_charge/filter_type_all/concat_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_2/AddN_21" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/concat_grad/Slice" + input: "gradients_2/dipole_charge/filter_type_all/concat_grad/Slice_1" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/concat_grad/Slice" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_1_grad/Reshape" + op: "Reshape" + input: "gradients_2/AddN_21" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/Pad" + op: "Pad" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_1_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Slice_1_grad/Pad" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/MatMul_3_grad/MatMul" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_5" + input: "gradients_2/dipole_charge/filter_type_all/add_12_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Reshape_6_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/filter_type_all/MatMul_3_grad/MatMul" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/AddN_26" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_6_grad/Reshape" + input: "gradients_2/dipole_charge/filter_type_all/Reshape_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/Reshape_6_grad/Reshape" + } + } + } +} +node { + name: "gradients_2/dipole_charge/filter_type_all/Slice_grad/Pad" + op: "Pad" + input: "gradients_2/AddN_26" + input: "gradients_2/dipole_charge/filter_type_all/Slice_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/AddN_28" + op: "AddN" + input: "gradients_2/dipole_charge/filter_type_all/Slice_8_grad/Pad" + input: "gradients_2/dipole_charge/filter_type_all/Slice_6_grad/Pad" + input: "gradients_2/dipole_charge/filter_type_all/Slice_4_grad/Pad" + input: "gradients_2/dipole_charge/filter_type_all/Slice_grad/Pad" + input: "gradients_2/dipole_charge/filter_type_all/Slice_2_grad/Pad" + attr { + key: "N" + value { + i: 5 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_2/dipole_charge/filter_type_all/Slice_8_grad/Pad" + } + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_5_grad/Reshape" + op: "Reshape" + input: "gradients_2/AddN_28" + input: "gradients_2/dipole_charge/Reshape_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_2/dipole_charge/Reshape_4_grad/Reshape" + op: "Reshape" + input: "gradients_2/dipole_charge/Reshape_5_grad/Reshape" + input: "gradients_2/dipole_charge/Reshape_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_7" + op: "Reshape" + input: "gradients_2/dipole_charge/Reshape_4_grad/Reshape" + input: "Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_10" + op: "Slice" + input: "Reshape_7" + input: "Slice_10/begin" + input: "Slice_10/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Slice_9" + op: "Slice" + input: "Reshape_7" + input: "Slice_9/begin" + input: "Slice_9/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "concat_3" + op: "ConcatV2" + input: "Slice_9" + input: "Slice_10" + input: "concat_3/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_10" + op: "Reshape" + input: "concat_3" + input: "Reshape_10/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_3" + op: "Slice" + input: "Reshape_3" + input: "Slice_3/begin" + input: "Slice_3/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/Slice_3_grad/Shape" + op: "Shape" + input: "Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_3_grad/sub" + op: "Sub" + input: "gradients_1/Slice_3_grad/Shape_1" + input: "gradients_1/Slice_3_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_3_grad/sub_1" + op: "Sub" + input: "gradients_1/Slice_3_grad/sub" + input: "Slice_3/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_3_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/Slice_3_grad/sub_1" + input: "gradients_1/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_3_grad/concat" + op: "ConcatV2" + input: "gradients_1/Slice_3_grad/Reshape" + input: "gradients_1/Slice_3_grad/Reshape_1" + input: "gradients_1/Slice_3_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Shape" + op: "Shape" + input: "Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Fill" + op: "Fill" + input: "gradients_1/Shape" + input: "gradients_1/grad_ys_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "index_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Slice_3_grad/Pad" + op: "Pad" + input: "gradients_1/Fill" + input: "gradients_1/Slice_3_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/Reshape_3_grad/Reshape" + op: "Reshape" + input: "gradients_1/Slice_3_grad/Pad" + input: "gradients_1/Reshape_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/concat_grad/Slice_3" + op: "Slice" + input: "gradients_1/Reshape_3_grad/Reshape" + input: "gradients_1/concat_grad/ConcatOffset:3" + input: "gradients_1/concat_grad/ShapeN:3" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/Slice_1_grad/Pad" + op: "Pad" + input: "gradients_1/concat_grad/Slice_3" + input: "gradients_1/Slice_1_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/concat_grad/Slice_1" + op: "Slice" + input: "gradients_1/Reshape_3_grad/Reshape" + input: "gradients_1/concat_grad/ConcatOffset:1" + input: "gradients_1/concat_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/Slice_grad/Pad" + op: "Pad" + input: "gradients_1/concat_grad/Slice_1" + input: "gradients_1/Slice_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/AddN" + op: "AddN" + input: "gradients_1/Slice_grad/Pad" + input: "gradients_1/Slice_1_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/Slice_grad/Pad" + } + } + } +} +node { + name: "gradients_1/Reshape_2_grad/Reshape" + op: "Reshape" + input: "gradients_1/AddN" + input: "gradients_1/Reshape_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_24_grad/Reshape" + op: "Reshape" + input: "gradients_1/Reshape_2_grad/Reshape" + input: "gradients_1/dipole_charge/Reshape_24_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/concat_2_grad/Slice_1" + op: "Slice" + input: "gradients_1/dipole_charge/Reshape_24_grad/Reshape" + input: "gradients_1/dipole_charge/concat_2_grad/ConcatOffset:1" + input: "gradients_1/dipole_charge/concat_2_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_21_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/concat_2_grad/Slice_1" + input: "gradients_1/dipole_charge/Reshape_21_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/MatMul_1_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/Reshape_20" + input: "gradients_1/dipole_charge/Reshape_21_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_19_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/MatMul_1_grad/MatMul_1" + input: "gradients_1/dipole_charge/Reshape_19_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_7_grad/Pad" + op: "Pad" + input: "gradients_1/dipole_charge/Reshape_19_grad/Reshape" + input: "gradients_1/dipole_charge/Slice_7_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/MatMul_1_grad/MatMul" + op: "BatchMatMul" + input: "gradients_1/dipole_charge/Reshape_21_grad/Reshape" + input: "dipole_charge/Reshape_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_20_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/MatMul_1_grad/MatMul" + input: "gradients_1/dipole_charge/Reshape_20_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/final_layer_type_3/add_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/Reshape_20_grad/Reshape" + input: "gradients_1/dipole_charge/final_layer_type_3/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/final_layer_type_3/add_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/final_layer_type_3/add_grad/Sum" + input: "gradients_1/dipole_charge/final_layer_type_3/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/final_layer_type_3/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/final_layer_type_3/add_grad/Reshape" + input: "dipole_charge/final_layer_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/add_7_grad/Sum_1" + op: "Sum" + input: "gradients_1/dipole_charge/final_layer_type_3/MatMul_grad/MatMul" + input: "gradients_1/dipole_charge/add_7_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/add_7_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/add_7_grad/Sum_1" + input: "gradients_1/dipole_charge/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_3/mul_grad/Mul" + op: "Mul" + input: "gradients_1/dipole_charge/add_7_grad/Reshape_1" + input: "dipole_charge/layer_2_type_3/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_3/mul_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/layer_2_type_3/mul_grad/Mul" + input: "gradients_1/dipole_charge/layer_2_type_3/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_3/mul_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/layer_2_type_3/mul_grad/Sum" + input: "gradients_1/dipole_charge/layer_2_type_3/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_3/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/layer_2_type_3/mul_grad/Reshape" + input: "gradients_1/dipole_charge/layer_2_type_3/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_3/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/layer_2_type_3/Tanh" + input: "gradients_1/dipole_charge/layer_2_type_3/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_3/add_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/layer_2_type_3/Tanh_grad/TanhGrad" + input: "gradients_1/dipole_charge/layer_2_type_3/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_3/add_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/layer_2_type_3/add_grad/Sum" + input: "gradients_1/dipole_charge/layer_2_type_3/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_3/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/layer_2_type_3/add_grad/Reshape" + input: "dipole_charge/layer_2_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/add_7_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/final_layer_type_3/MatMul_grad/MatMul" + input: "gradients_1/dipole_charge/add_7_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/add_7_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/add_7_grad/Sum" + input: "gradients_1/dipole_charge/add_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/AddN_3" + op: "AddN" + input: "gradients_1/dipole_charge/add_7_grad/Reshape" + input: "gradients_1/dipole_charge/layer_2_type_3/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/add_7_grad/Reshape" + } + } + } +} +node { + name: "gradients_1/dipole_charge/add_6_grad/Sum_1" + op: "Sum" + input: "gradients_1/AddN_3" + input: "gradients_1/dipole_charge/add_6_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/add_6_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/add_6_grad/Sum_1" + input: "gradients_1/dipole_charge/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_3/mul_grad/Mul" + op: "Mul" + input: "gradients_1/dipole_charge/add_6_grad/Reshape_1" + input: "dipole_charge/layer_1_type_3/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_3/mul_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/layer_1_type_3/mul_grad/Mul" + input: "gradients_1/dipole_charge/layer_1_type_3/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_3/mul_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/layer_1_type_3/mul_grad/Sum" + input: "gradients_1/dipole_charge/layer_1_type_3/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_3/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/layer_1_type_3/mul_grad/Reshape" + input: "gradients_1/dipole_charge/layer_1_type_3/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_3/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/layer_1_type_3/Tanh" + input: "gradients_1/dipole_charge/layer_1_type_3/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_3/add_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/layer_1_type_3/Tanh_grad/TanhGrad" + input: "gradients_1/dipole_charge/layer_1_type_3/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_3/add_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/layer_1_type_3/add_grad/Sum" + input: "gradients_1/dipole_charge/layer_1_type_3/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_3/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/layer_1_type_3/add_grad/Reshape" + input: "dipole_charge/layer_1_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/add_6_grad/Sum" + op: "Sum" + input: "gradients_1/AddN_3" + input: "gradients_1/dipole_charge/add_6_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/add_6_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/add_6_grad/Sum" + input: "gradients_1/dipole_charge/add_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/AddN_5" + op: "AddN" + input: "gradients_1/dipole_charge/add_6_grad/Reshape" + input: "gradients_1/dipole_charge/layer_1_type_3/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/add_6_grad/Reshape" + } + } + } +} +node { + name: "gradients_1/dipole_charge/layer_0_type_3/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_1/AddN_5" + input: "gradients_1/dipole_charge/layer_0_type_3/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_0_type_3/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/layer_0_type_3/Tanh" + input: "gradients_1/dipole_charge/layer_0_type_3/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/layer_0_type_3/add_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/layer_0_type_3/Tanh_grad/TanhGrad" + input: "gradients_1/dipole_charge/layer_0_type_3/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/layer_0_type_3/add_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/layer_0_type_3/add_grad/Sum" + input: "gradients_1/dipole_charge/layer_0_type_3/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_0_type_3/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/layer_0_type_3/add_grad/Reshape" + input: "dipole_charge/layer_0_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_18_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/layer_0_type_3/MatMul_grad/MatMul" + input: "gradients_1/dipole_charge/Reshape_18_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_6_grad/Pad" + op: "Pad" + input: "gradients_1/dipole_charge/Reshape_18_grad/Reshape" + input: "gradients_1/dipole_charge/Slice_6_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/concat_2_grad/Slice" + op: "Slice" + input: "gradients_1/dipole_charge/Reshape_24_grad/Reshape" + input: "gradients_1/dipole_charge/concat_2_grad/ConcatOffset" + input: "gradients_1/dipole_charge/concat_2_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_15_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/concat_2_grad/Slice" + input: "gradients_1/dipole_charge/Reshape_15_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/MatMul_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/Reshape_14" + input: "gradients_1/dipole_charge/Reshape_15_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_13_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/MatMul_grad/MatMul_1" + input: "gradients_1/dipole_charge/Reshape_13_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_3_grad/Pad" + op: "Pad" + input: "gradients_1/dipole_charge/Reshape_13_grad/Reshape" + input: "gradients_1/dipole_charge/Slice_3_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/AddN_1" + op: "AddN" + input: "gradients_1/dipole_charge/Slice_3_grad/Pad" + input: "gradients_1/dipole_charge/Slice_7_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/Slice_3_grad/Pad" + } + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_9_grad/Reshape" + op: "Reshape" + input: "gradients_1/AddN_1" + input: "gradients_1/dipole_charge/Reshape_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_7_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/Reshape_9_grad/Reshape" + input: "gradients_1/dipole_charge/Reshape_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/transpose_grad/transpose" + op: "Transpose" + input: "gradients_1/dipole_charge/Reshape_7_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/transpose_grad/InvertPermutation" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tperm" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/Pad" + op: "Pad" + input: "gradients_1/dipole_charge/filter_type_all/transpose_grad/transpose" + input: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/MatMul_grad/MatMul" + op: "BatchMatMul" + input: "gradients_1/dipole_charge/Reshape_15_grad/Reshape" + input: "dipole_charge/Reshape_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_14_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/MatMul_grad/MatMul" + input: "gradients_1/dipole_charge/Reshape_14_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/final_layer_type_1/add_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/Reshape_14_grad/Reshape" + input: "gradients_1/dipole_charge/final_layer_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/final_layer_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/final_layer_type_1/add_grad/Sum" + input: "gradients_1/dipole_charge/final_layer_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/final_layer_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/final_layer_type_1/add_grad/Reshape" + input: "dipole_charge/final_layer_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/add_3_grad/Sum_1" + op: "Sum" + input: "gradients_1/dipole_charge/final_layer_type_1/MatMul_grad/MatMul" + input: "gradients_1/dipole_charge/add_3_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/add_3_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/add_3_grad/Sum_1" + input: "gradients_1/dipole_charge/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients_1/dipole_charge/add_3_grad/Reshape_1" + input: "dipole_charge/layer_2_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/layer_2_type_1/mul_grad/Mul" + input: "gradients_1/dipole_charge/layer_2_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/layer_2_type_1/mul_grad/Sum" + input: "gradients_1/dipole_charge/layer_2_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/layer_2_type_1/mul_grad/Reshape" + input: "gradients_1/dipole_charge/layer_2_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/layer_2_type_1/Tanh" + input: "gradients_1/dipole_charge/layer_2_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_1/add_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/layer_2_type_1/Tanh_grad/TanhGrad" + input: "gradients_1/dipole_charge/layer_2_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/layer_2_type_1/add_grad/Sum" + input: "gradients_1/dipole_charge/layer_2_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_2_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/layer_2_type_1/add_grad/Reshape" + input: "dipole_charge/layer_2_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/add_3_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/final_layer_type_1/MatMul_grad/MatMul" + input: "gradients_1/dipole_charge/add_3_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/add_3_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/add_3_grad/Sum" + input: "gradients_1/dipole_charge/add_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/AddN_2" + op: "AddN" + input: "gradients_1/dipole_charge/add_3_grad/Reshape" + input: "gradients_1/dipole_charge/layer_2_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/add_3_grad/Reshape" + } + } + } +} +node { + name: "gradients_1/dipole_charge/add_2_grad/Sum_1" + op: "Sum" + input: "gradients_1/AddN_2" + input: "gradients_1/dipole_charge/add_2_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/add_2_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/add_2_grad/Sum_1" + input: "gradients_1/dipole_charge/add_2_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients_1/dipole_charge/add_2_grad/Reshape_1" + input: "dipole_charge/layer_1_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/layer_1_type_1/mul_grad/Mul" + input: "gradients_1/dipole_charge/layer_1_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/layer_1_type_1/mul_grad/Sum" + input: "gradients_1/dipole_charge/layer_1_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/layer_1_type_1/mul_grad/Reshape" + input: "gradients_1/dipole_charge/layer_1_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/layer_1_type_1/Tanh" + input: "gradients_1/dipole_charge/layer_1_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_1/add_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/layer_1_type_1/Tanh_grad/TanhGrad" + input: "gradients_1/dipole_charge/layer_1_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/layer_1_type_1/add_grad/Sum" + input: "gradients_1/dipole_charge/layer_1_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_1_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/layer_1_type_1/add_grad/Reshape" + input: "dipole_charge/layer_1_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/add_2_grad/Sum" + op: "Sum" + input: "gradients_1/AddN_2" + input: "gradients_1/dipole_charge/add_2_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/add_2_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/add_2_grad/Sum" + input: "gradients_1/dipole_charge/add_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/AddN_4" + op: "AddN" + input: "gradients_1/dipole_charge/add_2_grad/Reshape" + input: "gradients_1/dipole_charge/layer_1_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/add_2_grad/Reshape" + } + } + } +} +node { + name: "gradients_1/dipole_charge/layer_0_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_1/AddN_4" + input: "gradients_1/dipole_charge/layer_0_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_0_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/layer_0_type_1/Tanh" + input: "gradients_1/dipole_charge/layer_0_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/layer_0_type_1/add_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/layer_0_type_1/Tanh_grad/TanhGrad" + input: "gradients_1/dipole_charge/layer_0_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/layer_0_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/layer_0_type_1/add_grad/Sum" + input: "gradients_1/dipole_charge/layer_0_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/layer_0_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/layer_0_type_1/add_grad/Reshape" + input: "dipole_charge/layer_0_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_12_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/layer_0_type_1/MatMul_grad/MatMul" + input: "gradients_1/dipole_charge/Reshape_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Slice_2_grad/Pad" + op: "Pad" + input: "gradients_1/dipole_charge/Reshape_12_grad/Reshape" + input: "gradients_1/dipole_charge/Slice_2_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/AddN_6" + op: "AddN" + input: "gradients_1/dipole_charge/Slice_2_grad/Pad" + input: "gradients_1/dipole_charge/Slice_6_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/Slice_2_grad/Pad" + } + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_8_grad/Reshape" + op: "Reshape" + input: "gradients_1/AddN_6" + input: "gradients_1/dipole_charge/Reshape_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_6_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/Reshape_8_grad/Reshape" + input: "gradients_1/dipole_charge/Reshape_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_35_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/Reshape_6_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_35_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_20_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/mul" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_35_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/Pad" + op: "Pad" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_20_grad/MatMul_1" + input: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_20_grad/MatMul" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Slice_10" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_35_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_1/AddN_7" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/Slice_11_grad/Pad" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_20_grad/MatMul" + input: "gradients_1/dipole_charge/filter_type_all/Slice_10_grad/Pad" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/Slice_11_grad/Pad" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/mul_grad/Mul" + op: "Mul" + input: "gradients_1/AddN_7" + input: "dipole_charge/filter_type_all/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/mul_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/mul_grad/Mul" + input: "gradients_1/dipole_charge/filter_type_all/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/mul_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/mul_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_33_grad/Sum_1" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/mul_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_33_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_33_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_33_grad/Sum_1" + input: "gradients_1/dipole_charge/filter_type_all/add_33_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_19_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_34" + input: "gradients_1/dipole_charge/filter_type_all/add_33_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_33_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_19_grad/MatMul_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_33_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_32_grad/Sum_1" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_33_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_32_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_32_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_32_grad/Sum_1" + input: "gradients_1/dipole_charge/filter_type_all/add_32_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_32_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_32_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_32_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Tanh_14_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_14" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_32_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_31_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Tanh_14_grad/TanhGrad" + input: "gradients_1/dipole_charge/filter_type_all/add_31_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_31_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_31_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_31_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_18_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/filter_type_all/add_31_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_3_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_32_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_33_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_32_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_32_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_32_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_32_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_14_grad/Slice_1" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_32_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_14_grad/ConcatOffset:1" + input: "gradients_1/dipole_charge/filter_type_all/concat_14_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_14_grad/Slice" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_32_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_14_grad/ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_14_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/AddN_8" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/concat_14_grad/Slice" + input: "gradients_1/dipole_charge/filter_type_all/concat_14_grad/Slice_1" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_18_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/concat_14_grad/Slice" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_30_grad/Sum_1" + op: "Sum" + input: "gradients_1/AddN_8" + input: "gradients_1/dipole_charge/filter_type_all/add_30_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_30_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_30_grad/Sum_1" + input: "gradients_1/dipole_charge/filter_type_all/add_30_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_31_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_30_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_31_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Tanh_13_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_13" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_31_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_29_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Tanh_13_grad/TanhGrad" + input: "gradients_1/dipole_charge/filter_type_all/add_29_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_29_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_29_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_29_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_17_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/filter_type_all/add_29_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_2_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_30_grad/Sum" + op: "Sum" + input: "gradients_1/AddN_8" + input: "gradients_1/dipole_charge/filter_type_all/add_30_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_30_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_30_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_30_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_13_grad/Slice_1" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_30_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_13_grad/ConcatOffset:1" + input: "gradients_1/dipole_charge/filter_type_all/concat_13_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_13_grad/Slice" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_30_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_13_grad/ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_13_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/AddN_13" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/concat_13_grad/Slice" + input: "gradients_1/dipole_charge/filter_type_all/concat_13_grad/Slice_1" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_17_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/concat_13_grad/Slice" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_28_grad/Sum_1" + op: "Sum" + input: "gradients_1/AddN_13" + input: "gradients_1/dipole_charge/filter_type_all/add_28_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_28_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_28_grad/Sum_1" + input: "gradients_1/dipole_charge/filter_type_all/add_28_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_30_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_28_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_30_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Tanh_12_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_12" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_30_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_27_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Tanh_12_grad/TanhGrad" + input: "gradients_1/dipole_charge/filter_type_all/add_27_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_27_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_27_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_27_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_16_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/filter_type_all/add_27_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_1_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_28_grad/Sum" + op: "Sum" + input: "gradients_1/AddN_13" + input: "gradients_1/dipole_charge/filter_type_all/add_28_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_28_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_28_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_28_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_12_grad/Slice_1" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_28_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_12_grad/ConcatOffset:1" + input: "gradients_1/dipole_charge/filter_type_all/concat_12_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_12_grad/Slice" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_28_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_12_grad/ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_12_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/AddN_18" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/concat_12_grad/Slice" + input: "gradients_1/dipole_charge/filter_type_all/concat_12_grad/Slice_1" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_16_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/concat_12_grad/Slice" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_29_grad/Reshape" + op: "Reshape" + input: "gradients_1/AddN_18" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_29_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/Pad" + op: "Pad" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_29_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_28_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_9_grad/Pad" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_28_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_19_grad/MatMul" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_33" + input: "gradients_1/dipole_charge/filter_type_all/add_33_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_34_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_19_grad/MatMul" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_34_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/AddN_23" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_34_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_28_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/Reshape_34_grad/Reshape" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/Pad" + op: "Pad" + input: "gradients_1/AddN_23" + input: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_33_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/mul_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_33_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_33_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_33_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_33_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_26_grad/Sum_1" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_33_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_26_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_26_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_26_grad/Sum_1" + input: "gradients_1/dipole_charge/filter_type_all/add_26_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_15_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_27" + input: "gradients_1/dipole_charge/filter_type_all/add_26_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_26_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_15_grad/MatMul_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_26_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_25_grad/Sum_1" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_26_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_25_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_25_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_25_grad/Sum_1" + input: "gradients_1/dipole_charge/filter_type_all/add_25_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_25_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_25_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_25_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Tanh_11_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_11" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_25_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_24_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Tanh_11_grad/TanhGrad" + input: "gradients_1/dipole_charge/filter_type_all/add_24_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_24_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_24_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_24_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_14_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/filter_type_all/add_24_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_3_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_25_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_26_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_25_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_25_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_25_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_25_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_11_grad/Slice_1" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_25_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_11_grad/ConcatOffset:1" + input: "gradients_1/dipole_charge/filter_type_all/concat_11_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_11_grad/Slice" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_25_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_11_grad/ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_11_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/AddN_9" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/concat_11_grad/Slice" + input: "gradients_1/dipole_charge/filter_type_all/concat_11_grad/Slice_1" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_14_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/concat_11_grad/Slice" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_23_grad/Sum_1" + op: "Sum" + input: "gradients_1/AddN_9" + input: "gradients_1/dipole_charge/filter_type_all/add_23_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_23_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_23_grad/Sum_1" + input: "gradients_1/dipole_charge/filter_type_all/add_23_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_24_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_23_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_24_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Tanh_10_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_10" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_24_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_22_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Tanh_10_grad/TanhGrad" + input: "gradients_1/dipole_charge/filter_type_all/add_22_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_22_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_22_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_22_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_13_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/filter_type_all/add_22_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_2_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_23_grad/Sum" + op: "Sum" + input: "gradients_1/AddN_9" + input: "gradients_1/dipole_charge/filter_type_all/add_23_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_23_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_23_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_23_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_10_grad/Slice_1" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_23_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_10_grad/ConcatOffset:1" + input: "gradients_1/dipole_charge/filter_type_all/concat_10_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_10_grad/Slice" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_23_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_10_grad/ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_10_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/AddN_14" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/concat_10_grad/Slice" + input: "gradients_1/dipole_charge/filter_type_all/concat_10_grad/Slice_1" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_13_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/concat_10_grad/Slice" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_21_grad/Sum_1" + op: "Sum" + input: "gradients_1/AddN_14" + input: "gradients_1/dipole_charge/filter_type_all/add_21_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_21_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_21_grad/Sum_1" + input: "gradients_1/dipole_charge/filter_type_all/add_21_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_23_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_21_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_23_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Tanh_9_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_9" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_23_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_20_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Tanh_9_grad/TanhGrad" + input: "gradients_1/dipole_charge/filter_type_all/add_20_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_20_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_20_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_20_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_12_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/filter_type_all/add_20_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_1_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_21_grad/Sum" + op: "Sum" + input: "gradients_1/AddN_14" + input: "gradients_1/dipole_charge/filter_type_all/add_21_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_21_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_21_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_21_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_9_grad/Slice_1" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_21_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_9_grad/ConcatOffset:1" + input: "gradients_1/dipole_charge/filter_type_all/concat_9_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_9_grad/Slice" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_21_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_9_grad/ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_9_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/AddN_19" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/concat_9_grad/Slice" + input: "gradients_1/dipole_charge/filter_type_all/concat_9_grad/Slice_1" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_12_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/concat_9_grad/Slice" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_22_grad/Reshape" + op: "Reshape" + input: "gradients_1/AddN_19" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_22_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/Pad" + op: "Pad" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_22_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_21_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_7_grad/Pad" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_21_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_15_grad/MatMul" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_26" + input: "gradients_1/dipole_charge/filter_type_all/add_26_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_27_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_15_grad/MatMul" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_27_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/AddN_24" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_27_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_21_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/Reshape_27_grad/Reshape" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/Pad" + op: "Pad" + input: "gradients_1/AddN_24" + input: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_26_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_33_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_26_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_26_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_26_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_26_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_19_grad/Sum_1" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_26_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_19_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_19_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_19_grad/Sum_1" + input: "gradients_1/dipole_charge/filter_type_all/add_19_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_11_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_20" + input: "gradients_1/dipole_charge/filter_type_all/add_19_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_19_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_11_grad/MatMul_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_19_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_18_grad/Sum_1" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_19_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_18_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_18_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_18_grad/Sum_1" + input: "gradients_1/dipole_charge/filter_type_all/add_18_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_18_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_18_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_18_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Tanh_8_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_8" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_18_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_17_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Tanh_8_grad/TanhGrad" + input: "gradients_1/dipole_charge/filter_type_all/add_17_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_17_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_17_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_17_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_10_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/filter_type_all/add_17_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_3_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_18_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_19_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_18_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_18_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_18_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_18_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_8_grad/Slice_1" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_18_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_8_grad/ConcatOffset:1" + input: "gradients_1/dipole_charge/filter_type_all/concat_8_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_8_grad/Slice" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_18_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_8_grad/ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_8_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/AddN_10" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/concat_8_grad/Slice" + input: "gradients_1/dipole_charge/filter_type_all/concat_8_grad/Slice_1" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_10_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/concat_8_grad/Slice" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_16_grad/Sum_1" + op: "Sum" + input: "gradients_1/AddN_10" + input: "gradients_1/dipole_charge/filter_type_all/add_16_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_16_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_16_grad/Sum_1" + input: "gradients_1/dipole_charge/filter_type_all/add_16_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_17_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_16_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_17_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Tanh_7_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_7" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_17_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_15_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Tanh_7_grad/TanhGrad" + input: "gradients_1/dipole_charge/filter_type_all/add_15_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_15_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_15_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_15_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_9_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/filter_type_all/add_15_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_2_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_16_grad/Sum" + op: "Sum" + input: "gradients_1/AddN_10" + input: "gradients_1/dipole_charge/filter_type_all/add_16_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_16_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_16_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_16_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_7_grad/Slice_1" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_16_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_7_grad/ConcatOffset:1" + input: "gradients_1/dipole_charge/filter_type_all/concat_7_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_7_grad/Slice" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_16_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_7_grad/ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_7_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/AddN_15" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/concat_7_grad/Slice" + input: "gradients_1/dipole_charge/filter_type_all/concat_7_grad/Slice_1" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_9_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/concat_7_grad/Slice" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_14_grad/Sum_1" + op: "Sum" + input: "gradients_1/AddN_15" + input: "gradients_1/dipole_charge/filter_type_all/add_14_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_14_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_14_grad/Sum_1" + input: "gradients_1/dipole_charge/filter_type_all/add_14_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_16_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_14_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_16_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Tanh_6_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_6" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_16_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_13_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Tanh_6_grad/TanhGrad" + input: "gradients_1/dipole_charge/filter_type_all/add_13_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_13_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_13_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_13_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_8_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/filter_type_all/add_13_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_1_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_14_grad/Sum" + op: "Sum" + input: "gradients_1/AddN_15" + input: "gradients_1/dipole_charge/filter_type_all/add_14_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_14_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_14_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_14_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_6_grad/Slice_1" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_14_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_6_grad/ConcatOffset:1" + input: "gradients_1/dipole_charge/filter_type_all/concat_6_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_6_grad/Slice" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_14_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_6_grad/ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_6_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/AddN_20" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/concat_6_grad/Slice" + input: "gradients_1/dipole_charge/filter_type_all/concat_6_grad/Slice_1" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_8_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/concat_6_grad/Slice" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_15_grad/Reshape" + op: "Reshape" + input: "gradients_1/AddN_20" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_15_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/Pad" + op: "Pad" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_15_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_14_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_5_grad/Pad" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_14_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_11_grad/MatMul" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_19" + input: "gradients_1/dipole_charge/filter_type_all/add_19_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_20_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_11_grad/MatMul" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_20_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/AddN_25" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_20_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_14_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/Reshape_20_grad/Reshape" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/Pad" + op: "Pad" + input: "gradients_1/AddN_25" + input: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_19_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_26_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_19_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_19_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_19_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_19_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_12_grad/Sum_1" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_19_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_12_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_12_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_12_grad/Sum_1" + input: "gradients_1/dipole_charge/filter_type_all/add_12_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_7_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_13" + input: "gradients_1/dipole_charge/filter_type_all/add_12_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_12_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_7_grad/MatMul_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_11_grad/Sum_1" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_12_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_11_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_11_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_11_grad/Sum_1" + input: "gradients_1/dipole_charge/filter_type_all/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_11_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_11_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Tanh_5_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_5" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_11_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_10_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Tanh_5_grad/TanhGrad" + input: "gradients_1/dipole_charge/filter_type_all/add_10_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_10_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_10_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_6_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/filter_type_all/add_10_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_11_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_12_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_11_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_11_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_11_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_5_grad/Slice_1" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_11_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_5_grad/ConcatOffset:1" + input: "gradients_1/dipole_charge/filter_type_all/concat_5_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_5_grad/Slice" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_11_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_5_grad/ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_5_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/AddN_12" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/concat_5_grad/Slice" + input: "gradients_1/dipole_charge/filter_type_all/concat_5_grad/Slice_1" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_6_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/concat_5_grad/Slice" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_9_grad/Sum_1" + op: "Sum" + input: "gradients_1/AddN_12" + input: "gradients_1/dipole_charge/filter_type_all/add_9_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_9_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_9_grad/Sum_1" + input: "gradients_1/dipole_charge/filter_type_all/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_10_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_9_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Tanh_4_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_4" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_10_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_8_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Tanh_4_grad/TanhGrad" + input: "gradients_1/dipole_charge/filter_type_all/add_8_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_8_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_8_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_5_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/filter_type_all/add_8_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_9_grad/Sum" + op: "Sum" + input: "gradients_1/AddN_12" + input: "gradients_1/dipole_charge/filter_type_all/add_9_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_9_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_9_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_4_grad/Slice_1" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_9_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_4_grad/ConcatOffset:1" + input: "gradients_1/dipole_charge/filter_type_all/concat_4_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_4_grad/Slice" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_9_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_4_grad/ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_4_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/AddN_17" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/concat_4_grad/Slice" + input: "gradients_1/dipole_charge/filter_type_all/concat_4_grad/Slice_1" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_5_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/concat_4_grad/Slice" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_7_grad/Sum_1" + op: "Sum" + input: "gradients_1/AddN_17" + input: "gradients_1/dipole_charge/filter_type_all/add_7_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_7_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_7_grad/Sum_1" + input: "gradients_1/dipole_charge/filter_type_all/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_9_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_7_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Tanh_3_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_3" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_9_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_6_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Tanh_3_grad/TanhGrad" + input: "gradients_1/dipole_charge/filter_type_all/add_6_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_6_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_6_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_4_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/filter_type_all/add_6_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_7_grad/Sum" + op: "Sum" + input: "gradients_1/AddN_17" + input: "gradients_1/dipole_charge/filter_type_all/add_7_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_7_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_7_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_3_grad/Slice_1" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_7_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_3_grad/ConcatOffset:1" + input: "gradients_1/dipole_charge/filter_type_all/concat_3_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_3_grad/Slice" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_7_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_3_grad/ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_3_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/AddN_22" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/concat_3_grad/Slice" + input: "gradients_1/dipole_charge/filter_type_all/concat_3_grad/Slice_1" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_4_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/concat_3_grad/Slice" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_8_grad/Reshape" + op: "Reshape" + input: "gradients_1/AddN_22" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/Pad" + op: "Pad" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_8_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_7_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_3_grad/Pad" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_7_grad/MatMul" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_12" + input: "gradients_1/dipole_charge/filter_type_all/add_12_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_13_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_7_grad/MatMul" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_13_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/AddN_27" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_13_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_7_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/Reshape_13_grad/Reshape" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/Pad" + op: "Pad" + input: "gradients_1/AddN_27" + input: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_12_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_19_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_12_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_12_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_12_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_3_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_6" + input: "gradients_1/dipole_charge/filter_type_all/add_12_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_5_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_3_grad/MatMul_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_5_grad/Sum_1" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_5_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_5_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_5_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_5_grad/Sum_1" + input: "gradients_1/dipole_charge/filter_type_all/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_4_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_5_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Tanh_2_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_2" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_4_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_4_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Tanh_2_grad/TanhGrad" + input: "gradients_1/dipole_charge/filter_type_all/add_4_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_4_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_4_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_2_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/filter_type_all/add_4_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_5_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_5_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_5_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_5_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_5_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_2_grad/Slice_1" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_5_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_2_grad/ConcatOffset:1" + input: "gradients_1/dipole_charge/filter_type_all/concat_2_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_2_grad/Slice" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_5_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_2_grad/ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_2_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/AddN_11" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/concat_2_grad/Slice" + input: "gradients_1/dipole_charge/filter_type_all/concat_2_grad/Slice_1" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_2_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/concat_2_grad/Slice" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_3_grad/Sum_1" + op: "Sum" + input: "gradients_1/AddN_11" + input: "gradients_1/dipole_charge/filter_type_all/add_3_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_3_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_3_grad/Sum_1" + input: "gradients_1/dipole_charge/filter_type_all/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_3_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_3_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Tanh_1_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_3_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_2_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Tanh_1_grad/TanhGrad" + input: "gradients_1/dipole_charge/filter_type_all/add_2_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_2_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_2_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_1_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/filter_type_all/add_2_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_3_grad/Sum" + op: "Sum" + input: "gradients_1/AddN_11" + input: "gradients_1/dipole_charge/filter_type_all/add_3_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_3_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_3_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_1_grad/Slice_1" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_3_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_1_grad/ConcatOffset:1" + input: "gradients_1/dipole_charge/filter_type_all/concat_1_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_1_grad/Slice" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_3_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_1_grad/ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_1_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/AddN_16" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/concat_1_grad/Slice" + input: "gradients_1/dipole_charge/filter_type_all/concat_1_grad/Slice_1" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_1_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/concat_1_grad/Slice" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_1_grad/Sum_1" + op: "Sum" + input: "gradients_1/AddN_16" + input: "gradients_1/dipole_charge/filter_type_all/add_1_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_1_grad/Reshape_1" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_1_grad/Sum_1" + input: "gradients_1/dipole_charge/filter_type_all/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_2_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_1_grad/Reshape_1" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_2_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_grad/Sum" + op: "Sum" + input: "gradients_1/dipole_charge/filter_type_all/Tanh_grad/TanhGrad" + input: "gradients_1/dipole_charge/filter_type_all/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients_1/dipole_charge/filter_type_all/add_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_1_grad/Sum" + op: "Sum" + input: "gradients_1/AddN_16" + input: "gradients_1/dipole_charge/filter_type_all/add_1_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/add_1_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/add_1_grad/Sum" + input: "gradients_1/dipole_charge/filter_type_all/add_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_grad/Slice_1" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_1_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_grad/ConcatOffset:1" + input: "gradients_1/dipole_charge/filter_type_all/concat_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/concat_grad/Slice" + op: "Slice" + input: "gradients_1/dipole_charge/filter_type_all/add_1_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/concat_grad/ConcatOffset" + input: "gradients_1/dipole_charge/filter_type_all/concat_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients_1/AddN_21" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/concat_grad/Slice" + input: "gradients_1/dipole_charge/filter_type_all/concat_grad/Slice_1" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/concat_grad/Slice" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_1_grad/Reshape" + op: "Reshape" + input: "gradients_1/AddN_21" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/Pad" + op: "Pad" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_1_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Slice_1_grad/Pad" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/MatMul_3_grad/MatMul" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_5" + input: "gradients_1/dipole_charge/filter_type_all/add_12_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Reshape_6_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/filter_type_all/MatMul_3_grad/MatMul" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/AddN_26" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_6_grad/Reshape" + input: "gradients_1/dipole_charge/filter_type_all/Reshape_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/Reshape_6_grad/Reshape" + } + } + } +} +node { + name: "gradients_1/dipole_charge/filter_type_all/Slice_grad/Pad" + op: "Pad" + input: "gradients_1/AddN_26" + input: "gradients_1/dipole_charge/filter_type_all/Slice_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/AddN_28" + op: "AddN" + input: "gradients_1/dipole_charge/filter_type_all/Slice_8_grad/Pad" + input: "gradients_1/dipole_charge/filter_type_all/Slice_6_grad/Pad" + input: "gradients_1/dipole_charge/filter_type_all/Slice_4_grad/Pad" + input: "gradients_1/dipole_charge/filter_type_all/Slice_grad/Pad" + input: "gradients_1/dipole_charge/filter_type_all/Slice_2_grad/Pad" + attr { + key: "N" + value { + i: 5 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients_1/dipole_charge/filter_type_all/Slice_8_grad/Pad" + } + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_5_grad/Reshape" + op: "Reshape" + input: "gradients_1/AddN_28" + input: "gradients_1/dipole_charge/Reshape_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients_1/dipole_charge/Reshape_4_grad/Reshape" + op: "Reshape" + input: "gradients_1/dipole_charge/Reshape_5_grad/Reshape" + input: "gradients_1/dipole_charge/Reshape_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_6" + op: "Reshape" + input: "gradients_1/dipole_charge/Reshape_4_grad/Reshape" + input: "Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_8" + op: "Slice" + input: "Reshape_6" + input: "Slice_8/begin" + input: "Slice_8/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Slice_7" + op: "Slice" + input: "Reshape_6" + input: "Slice_7/begin" + input: "Slice_7/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "concat_2" + op: "ConcatV2" + input: "Slice_7" + input: "Slice_8" + input: "concat_2/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_9" + op: "Reshape" + input: "concat_2" + input: "Reshape_9/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_2" + op: "Slice" + input: "Reshape_3" + input: "Slice_2/begin" + input: "Slice_2/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Slice_2_grad/Shape" + op: "Shape" + input: "Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/sub" + op: "Sub" + input: "gradients/Slice_2_grad/Shape_1" + input: "gradients/Slice_2_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/sub_1" + op: "Sub" + input: "gradients/Slice_2_grad/sub" + input: "Slice_2/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/Reshape_1" + op: "Reshape" + input: "gradients/Slice_2_grad/sub_1" + input: "gradients/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/concat" + op: "ConcatV2" + input: "gradients/Slice_2_grad/Reshape" + input: "gradients/Slice_2_grad/Reshape_1" + input: "gradients/Slice_2_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Shape" + op: "Shape" + input: "Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Fill" + op: "Fill" + input: "gradients/Shape" + input: "gradients/grad_ys_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "index_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/Pad" + op: "Pad" + input: "gradients/Fill" + input: "gradients/Slice_2_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_3_grad/Reshape" + op: "Reshape" + input: "gradients/Slice_2_grad/Pad" + input: "gradients/Reshape_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/Slice_3" + op: "Slice" + input: "gradients/Reshape_3_grad/Reshape" + input: "gradients/concat_grad/ConcatOffset:3" + input: "gradients/concat_grad/ShapeN:3" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Slice_1_grad/Pad" + op: "Pad" + input: "gradients/concat_grad/Slice_3" + input: "gradients/Slice_1_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/Slice_1" + op: "Slice" + input: "gradients/Reshape_3_grad/Reshape" + input: "gradients/concat_grad/ConcatOffset:1" + input: "gradients/concat_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Slice_grad/Pad" + op: "Pad" + input: "gradients/concat_grad/Slice_1" + input: "gradients/Slice_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN" + op: "AddN" + input: "gradients/Slice_grad/Pad" + input: "gradients/Slice_1_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/Slice_grad/Pad" + } + } + } +} +node { + name: "gradients/Reshape_2_grad/Reshape" + op: "Reshape" + input: "gradients/AddN" + input: "gradients/Reshape_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Reshape_24_grad/Reshape" + op: "Reshape" + input: "gradients/Reshape_2_grad/Reshape" + input: "gradients/dipole_charge/Reshape_24_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/concat_2_grad/Slice_1" + op: "Slice" + input: "gradients/dipole_charge/Reshape_24_grad/Reshape" + input: "gradients/dipole_charge/concat_2_grad/ConcatOffset:1" + input: "gradients/dipole_charge/concat_2_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/Reshape_21_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/concat_2_grad/Slice_1" + input: "gradients/dipole_charge/Reshape_21_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/MatMul_1_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/Reshape_20" + input: "gradients/dipole_charge/Reshape_21_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/Reshape_19_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/MatMul_1_grad/MatMul_1" + input: "gradients/dipole_charge/Reshape_19_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_7_grad/Pad" + op: "Pad" + input: "gradients/dipole_charge/Reshape_19_grad/Reshape" + input: "gradients/dipole_charge/Slice_7_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/MatMul_1_grad/MatMul" + op: "BatchMatMul" + input: "gradients/dipole_charge/Reshape_21_grad/Reshape" + input: "dipole_charge/Reshape_19" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/Reshape_20_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/MatMul_1_grad/MatMul" + input: "gradients/dipole_charge/Reshape_20_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/final_layer_type_3/add_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/Reshape_20_grad/Reshape" + input: "gradients/dipole_charge/final_layer_type_3/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/final_layer_type_3/add_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/final_layer_type_3/add_grad/Sum" + input: "gradients/dipole_charge/final_layer_type_3/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/final_layer_type_3/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/final_layer_type_3/add_grad/Reshape" + input: "dipole_charge/final_layer_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/add_7_grad/Sum_1" + op: "Sum" + input: "gradients/dipole_charge/final_layer_type_3/MatMul_grad/MatMul" + input: "gradients/dipole_charge/add_7_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/add_7_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/add_7_grad/Sum_1" + input: "gradients/dipole_charge/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_3/mul_grad/Mul" + op: "Mul" + input: "gradients/dipole_charge/add_7_grad/Reshape_1" + input: "dipole_charge/layer_2_type_3/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_3/mul_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/layer_2_type_3/mul_grad/Mul" + input: "gradients/dipole_charge/layer_2_type_3/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_3/mul_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/layer_2_type_3/mul_grad/Sum" + input: "gradients/dipole_charge/layer_2_type_3/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_3/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/layer_2_type_3/mul_grad/Reshape" + input: "gradients/dipole_charge/layer_2_type_3/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_3/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/layer_2_type_3/Tanh" + input: "gradients/dipole_charge/layer_2_type_3/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_3/add_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/layer_2_type_3/Tanh_grad/TanhGrad" + input: "gradients/dipole_charge/layer_2_type_3/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_3/add_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/layer_2_type_3/add_grad/Sum" + input: "gradients/dipole_charge/layer_2_type_3/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_3/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/layer_2_type_3/add_grad/Reshape" + input: "dipole_charge/layer_2_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/add_7_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/final_layer_type_3/MatMul_grad/MatMul" + input: "gradients/dipole_charge/add_7_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/add_7_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/add_7_grad/Sum" + input: "gradients/dipole_charge/add_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_3" + op: "AddN" + input: "gradients/dipole_charge/add_7_grad/Reshape" + input: "gradients/dipole_charge/layer_2_type_3/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/add_7_grad/Reshape" + } + } + } +} +node { + name: "gradients/dipole_charge/add_6_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_3" + input: "gradients/dipole_charge/add_6_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/add_6_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/add_6_grad/Sum_1" + input: "gradients/dipole_charge/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_3/mul_grad/Mul" + op: "Mul" + input: "gradients/dipole_charge/add_6_grad/Reshape_1" + input: "dipole_charge/layer_1_type_3/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_3/mul_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/layer_1_type_3/mul_grad/Mul" + input: "gradients/dipole_charge/layer_1_type_3/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_3/mul_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/layer_1_type_3/mul_grad/Sum" + input: "gradients/dipole_charge/layer_1_type_3/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_3/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/layer_1_type_3/mul_grad/Reshape" + input: "gradients/dipole_charge/layer_1_type_3/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_3/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/layer_1_type_3/Tanh" + input: "gradients/dipole_charge/layer_1_type_3/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_3/add_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/layer_1_type_3/Tanh_grad/TanhGrad" + input: "gradients/dipole_charge/layer_1_type_3/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_3/add_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/layer_1_type_3/add_grad/Sum" + input: "gradients/dipole_charge/layer_1_type_3/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_3/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/layer_1_type_3/add_grad/Reshape" + input: "dipole_charge/layer_1_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/add_6_grad/Sum" + op: "Sum" + input: "gradients/AddN_3" + input: "gradients/dipole_charge/add_6_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/add_6_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/add_6_grad/Sum" + input: "gradients/dipole_charge/add_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_5" + op: "AddN" + input: "gradients/dipole_charge/add_6_grad/Reshape" + input: "gradients/dipole_charge/layer_1_type_3/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/add_6_grad/Reshape" + } + } + } +} +node { + name: "gradients/dipole_charge/layer_0_type_3/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_5" + input: "gradients/dipole_charge/layer_0_type_3/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_0_type_3/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/layer_0_type_3/Tanh" + input: "gradients/dipole_charge/layer_0_type_3/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/layer_0_type_3/add_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/layer_0_type_3/Tanh_grad/TanhGrad" + input: "gradients/dipole_charge/layer_0_type_3/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/layer_0_type_3/add_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/layer_0_type_3/add_grad/Sum" + input: "gradients/dipole_charge/layer_0_type_3/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_0_type_3/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/layer_0_type_3/add_grad/Reshape" + input: "dipole_charge/layer_0_type_3/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/Reshape_18_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/layer_0_type_3/MatMul_grad/MatMul" + input: "gradients/dipole_charge/Reshape_18_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_6_grad/Pad" + op: "Pad" + input: "gradients/dipole_charge/Reshape_18_grad/Reshape" + input: "gradients/dipole_charge/Slice_6_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/concat_2_grad/Slice" + op: "Slice" + input: "gradients/dipole_charge/Reshape_24_grad/Reshape" + input: "gradients/dipole_charge/concat_2_grad/ConcatOffset" + input: "gradients/dipole_charge/concat_2_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/Reshape_15_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/concat_2_grad/Slice" + input: "gradients/dipole_charge/Reshape_15_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/MatMul_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/Reshape_14" + input: "gradients/dipole_charge/Reshape_15_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: true + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/Reshape_13_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/MatMul_grad/MatMul_1" + input: "gradients/dipole_charge/Reshape_13_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_3_grad/Pad" + op: "Pad" + input: "gradients/dipole_charge/Reshape_13_grad/Reshape" + input: "gradients/dipole_charge/Slice_3_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_1" + op: "AddN" + input: "gradients/dipole_charge/Slice_3_grad/Pad" + input: "gradients/dipole_charge/Slice_7_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/Slice_3_grad/Pad" + } + } + } +} +node { + name: "gradients/dipole_charge/Reshape_9_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_1" + input: "gradients/dipole_charge/Reshape_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Reshape_7_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/Reshape_9_grad/Reshape" + input: "gradients/dipole_charge/Reshape_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/transpose_grad/transpose" + op: "Transpose" + input: "gradients/dipole_charge/Reshape_7_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/transpose_grad/InvertPermutation" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tperm" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_11_grad/Pad" + op: "Pad" + input: "gradients/dipole_charge/filter_type_all/transpose_grad/transpose" + input: "gradients/dipole_charge/filter_type_all/Slice_11_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/MatMul_grad/MatMul" + op: "BatchMatMul" + input: "gradients/dipole_charge/Reshape_15_grad/Reshape" + input: "dipole_charge/Reshape_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/Reshape_14_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/MatMul_grad/MatMul" + input: "gradients/dipole_charge/Reshape_14_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/final_layer_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/Reshape_14_grad/Reshape" + input: "gradients/dipole_charge/final_layer_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/final_layer_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/final_layer_type_1/add_grad/Sum" + input: "gradients/dipole_charge/final_layer_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/final_layer_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/final_layer_type_1/add_grad/Reshape" + input: "dipole_charge/final_layer_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/add_3_grad/Sum_1" + op: "Sum" + input: "gradients/dipole_charge/final_layer_type_1/MatMul_grad/MatMul" + input: "gradients/dipole_charge/add_3_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/add_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/add_3_grad/Sum_1" + input: "gradients/dipole_charge/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients/dipole_charge/add_3_grad/Reshape_1" + input: "dipole_charge/layer_2_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/layer_2_type_1/mul_grad/Mul" + input: "gradients/dipole_charge/layer_2_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/layer_2_type_1/mul_grad/Sum" + input: "gradients/dipole_charge/layer_2_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/layer_2_type_1/mul_grad/Reshape" + input: "gradients/dipole_charge/layer_2_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/layer_2_type_1/Tanh" + input: "gradients/dipole_charge/layer_2_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/layer_2_type_1/Tanh_grad/TanhGrad" + input: "gradients/dipole_charge/layer_2_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/layer_2_type_1/add_grad/Sum" + input: "gradients/dipole_charge/layer_2_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_2_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/layer_2_type_1/add_grad/Reshape" + input: "dipole_charge/layer_2_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/add_3_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/final_layer_type_1/MatMul_grad/MatMul" + input: "gradients/dipole_charge/add_3_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/add_3_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/add_3_grad/Sum" + input: "gradients/dipole_charge/add_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_2" + op: "AddN" + input: "gradients/dipole_charge/add_3_grad/Reshape" + input: "gradients/dipole_charge/layer_2_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/add_3_grad/Reshape" + } + } + } +} +node { + name: "gradients/dipole_charge/add_2_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_2" + input: "gradients/dipole_charge/add_2_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/add_2_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/add_2_grad/Sum_1" + input: "gradients/dipole_charge/add_2_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients/dipole_charge/add_2_grad/Reshape_1" + input: "dipole_charge/layer_1_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/layer_1_type_1/mul_grad/Mul" + input: "gradients/dipole_charge/layer_1_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/layer_1_type_1/mul_grad/Sum" + input: "gradients/dipole_charge/layer_1_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/layer_1_type_1/mul_grad/Reshape" + input: "gradients/dipole_charge/layer_1_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/layer_1_type_1/Tanh" + input: "gradients/dipole_charge/layer_1_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/layer_1_type_1/Tanh_grad/TanhGrad" + input: "gradients/dipole_charge/layer_1_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/layer_1_type_1/add_grad/Sum" + input: "gradients/dipole_charge/layer_1_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_1_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/layer_1_type_1/add_grad/Reshape" + input: "dipole_charge/layer_1_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/add_2_grad/Sum" + op: "Sum" + input: "gradients/AddN_2" + input: "gradients/dipole_charge/add_2_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/add_2_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/add_2_grad/Sum" + input: "gradients/dipole_charge/add_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_4" + op: "AddN" + input: "gradients/dipole_charge/add_2_grad/Reshape" + input: "gradients/dipole_charge/layer_1_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/add_2_grad/Reshape" + } + } + } +} +node { + name: "gradients/dipole_charge/layer_0_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_4" + input: "gradients/dipole_charge/layer_0_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_0_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/layer_0_type_1/Tanh" + input: "gradients/dipole_charge/layer_0_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/layer_0_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/layer_0_type_1/Tanh_grad/TanhGrad" + input: "gradients/dipole_charge/layer_0_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/layer_0_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/layer_0_type_1/add_grad/Sum" + input: "gradients/dipole_charge/layer_0_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/layer_0_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/layer_0_type_1/add_grad/Reshape" + input: "dipole_charge/layer_0_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/Reshape_12_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/layer_0_type_1/MatMul_grad/MatMul" + input: "gradients/dipole_charge/Reshape_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Slice_2_grad/Pad" + op: "Pad" + input: "gradients/dipole_charge/Reshape_12_grad/Reshape" + input: "gradients/dipole_charge/Slice_2_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_6" + op: "AddN" + input: "gradients/dipole_charge/Slice_2_grad/Pad" + input: "gradients/dipole_charge/Slice_6_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/Slice_2_grad/Pad" + } + } + } +} +node { + name: "gradients/dipole_charge/Reshape_8_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_6" + input: "gradients/dipole_charge/Reshape_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Reshape_6_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/Reshape_8_grad/Reshape" + input: "gradients/dipole_charge/Reshape_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_35_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/Reshape_6_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Reshape_35_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_20_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/mul" + input: "gradients/dipole_charge/filter_type_all/Reshape_35_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_10_grad/Pad" + op: "Pad" + input: "gradients/dipole_charge/filter_type_all/MatMul_20_grad/MatMul_1" + input: "gradients/dipole_charge/filter_type_all/Slice_10_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_20_grad/MatMul" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Slice_10" + input: "gradients/dipole_charge/filter_type_all/Reshape_35_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/AddN_7" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/Slice_11_grad/Pad" + input: "gradients/dipole_charge/filter_type_all/MatMul_20_grad/MatMul" + input: "gradients/dipole_charge/filter_type_all/Slice_10_grad/Pad" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/Slice_11_grad/Pad" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/mul_grad/Mul" + op: "Mul" + input: "gradients/AddN_7" + input: "dipole_charge/filter_type_all/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/mul_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/mul_grad/Mul" + input: "gradients/dipole_charge/filter_type_all/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/mul_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/mul_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_33_grad/Sum_1" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/mul_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/add_33_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_33_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_33_grad/Sum_1" + input: "gradients/dipole_charge/filter_type_all/add_33_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_19_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_34" + input: "gradients/dipole_charge/filter_type_all/add_33_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_33_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/MatMul_19_grad/MatMul_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_33_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_32_grad/Sum_1" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Reshape_33_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/add_32_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_32_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_32_grad/Sum_1" + input: "gradients/dipole_charge/filter_type_all/add_32_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_32_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_32_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_32_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Tanh_14_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_14" + input: "gradients/dipole_charge/filter_type_all/Reshape_32_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_31_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Tanh_14_grad/TanhGrad" + input: "gradients/dipole_charge/filter_type_all/add_31_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_31_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_31_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_31_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_18_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/filter_type_all/add_31_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_3_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_32_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Reshape_33_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/add_32_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_32_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_32_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_32_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_14_grad/Slice_1" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_32_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_14_grad/ConcatOffset:1" + input: "gradients/dipole_charge/filter_type_all/concat_14_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_14_grad/Slice" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_32_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_14_grad/ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_14_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_8" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/concat_14_grad/Slice" + input: "gradients/dipole_charge/filter_type_all/concat_14_grad/Slice_1" + input: "gradients/dipole_charge/filter_type_all/MatMul_18_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/concat_14_grad/Slice" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_30_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_8" + input: "gradients/dipole_charge/filter_type_all/add_30_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_30_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_30_grad/Sum_1" + input: "gradients/dipole_charge/filter_type_all/add_30_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_31_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_30_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_31_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Tanh_13_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_13" + input: "gradients/dipole_charge/filter_type_all/Reshape_31_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_29_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Tanh_13_grad/TanhGrad" + input: "gradients/dipole_charge/filter_type_all/add_29_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_29_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_29_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_29_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_17_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/filter_type_all/add_29_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_2_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_30_grad/Sum" + op: "Sum" + input: "gradients/AddN_8" + input: "gradients/dipole_charge/filter_type_all/add_30_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_30_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_30_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_30_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_13_grad/Slice_1" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_30_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_13_grad/ConcatOffset:1" + input: "gradients/dipole_charge/filter_type_all/concat_13_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_13_grad/Slice" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_30_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_13_grad/ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_13_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_13" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/concat_13_grad/Slice" + input: "gradients/dipole_charge/filter_type_all/concat_13_grad/Slice_1" + input: "gradients/dipole_charge/filter_type_all/MatMul_17_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/concat_13_grad/Slice" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_28_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_13" + input: "gradients/dipole_charge/filter_type_all/add_28_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_28_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_28_grad/Sum_1" + input: "gradients/dipole_charge/filter_type_all/add_28_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_30_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_28_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_30_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Tanh_12_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_12" + input: "gradients/dipole_charge/filter_type_all/Reshape_30_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_27_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Tanh_12_grad/TanhGrad" + input: "gradients/dipole_charge/filter_type_all/add_27_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_27_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_27_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_27_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_16_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/filter_type_all/add_27_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_1_4/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_28_grad/Sum" + op: "Sum" + input: "gradients/AddN_13" + input: "gradients/dipole_charge/filter_type_all/add_28_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_28_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_28_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_28_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_12_grad/Slice_1" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_28_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_12_grad/ConcatOffset:1" + input: "gradients/dipole_charge/filter_type_all/concat_12_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_12_grad/Slice" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_28_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_12_grad/ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_12_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_18" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/concat_12_grad/Slice" + input: "gradients/dipole_charge/filter_type_all/concat_12_grad/Slice_1" + input: "gradients/dipole_charge/filter_type_all/MatMul_16_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/concat_12_grad/Slice" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_29_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_18" + input: "gradients/dipole_charge/filter_type_all/Reshape_29_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_9_grad/Pad" + op: "Pad" + input: "gradients/dipole_charge/filter_type_all/Reshape_29_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_9_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_28_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_9_grad/Pad" + input: "gradients/dipole_charge/filter_type_all/Reshape_28_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_19_grad/MatMul" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_33" + input: "gradients/dipole_charge/filter_type_all/add_33_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_34_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/MatMul_19_grad/MatMul" + input: "gradients/dipole_charge/filter_type_all/Reshape_34_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_23" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/Reshape_34_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Reshape_28_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/Reshape_34_grad/Reshape" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_8_grad/Pad" + op: "Pad" + input: "gradients/AddN_23" + input: "gradients/dipole_charge/filter_type_all/Slice_8_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_33_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/mul_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/add_33_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_33_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_33_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_33_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_26_grad/Sum_1" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/add_33_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/add_26_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_26_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_26_grad/Sum_1" + input: "gradients/dipole_charge/filter_type_all/add_26_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_15_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_27" + input: "gradients/dipole_charge/filter_type_all/add_26_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_26_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/MatMul_15_grad/MatMul_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_26_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_25_grad/Sum_1" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Reshape_26_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/add_25_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_25_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_25_grad/Sum_1" + input: "gradients/dipole_charge/filter_type_all/add_25_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_25_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_25_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_25_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Tanh_11_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_11" + input: "gradients/dipole_charge/filter_type_all/Reshape_25_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_24_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Tanh_11_grad/TanhGrad" + input: "gradients/dipole_charge/filter_type_all/add_24_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_24_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_24_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_24_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_14_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/filter_type_all/add_24_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_3_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_25_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Reshape_26_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/add_25_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_25_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_25_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_25_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_11_grad/Slice_1" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_25_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_11_grad/ConcatOffset:1" + input: "gradients/dipole_charge/filter_type_all/concat_11_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_11_grad/Slice" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_25_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_11_grad/ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_11_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_9" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/concat_11_grad/Slice" + input: "gradients/dipole_charge/filter_type_all/concat_11_grad/Slice_1" + input: "gradients/dipole_charge/filter_type_all/MatMul_14_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/concat_11_grad/Slice" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_23_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_9" + input: "gradients/dipole_charge/filter_type_all/add_23_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_23_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_23_grad/Sum_1" + input: "gradients/dipole_charge/filter_type_all/add_23_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_24_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_23_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_24_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Tanh_10_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_10" + input: "gradients/dipole_charge/filter_type_all/Reshape_24_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_22_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Tanh_10_grad/TanhGrad" + input: "gradients/dipole_charge/filter_type_all/add_22_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_22_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_22_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_22_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_13_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/filter_type_all/add_22_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_2_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_23_grad/Sum" + op: "Sum" + input: "gradients/AddN_9" + input: "gradients/dipole_charge/filter_type_all/add_23_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_23_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_23_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_23_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_10_grad/Slice_1" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_23_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_10_grad/ConcatOffset:1" + input: "gradients/dipole_charge/filter_type_all/concat_10_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_10_grad/Slice" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_23_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_10_grad/ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_10_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_14" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/concat_10_grad/Slice" + input: "gradients/dipole_charge/filter_type_all/concat_10_grad/Slice_1" + input: "gradients/dipole_charge/filter_type_all/MatMul_13_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/concat_10_grad/Slice" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_21_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_14" + input: "gradients/dipole_charge/filter_type_all/add_21_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_21_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_21_grad/Sum_1" + input: "gradients/dipole_charge/filter_type_all/add_21_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_23_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_21_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_23_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Tanh_9_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_9" + input: "gradients/dipole_charge/filter_type_all/Reshape_23_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_20_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Tanh_9_grad/TanhGrad" + input: "gradients/dipole_charge/filter_type_all/add_20_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_20_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_20_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_20_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_12_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/filter_type_all/add_20_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_1_3/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_21_grad/Sum" + op: "Sum" + input: "gradients/AddN_14" + input: "gradients/dipole_charge/filter_type_all/add_21_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_21_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_21_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_21_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_9_grad/Slice_1" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_21_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_9_grad/ConcatOffset:1" + input: "gradients/dipole_charge/filter_type_all/concat_9_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_9_grad/Slice" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_21_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_9_grad/ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_9_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_19" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/concat_9_grad/Slice" + input: "gradients/dipole_charge/filter_type_all/concat_9_grad/Slice_1" + input: "gradients/dipole_charge/filter_type_all/MatMul_12_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/concat_9_grad/Slice" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_22_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_19" + input: "gradients/dipole_charge/filter_type_all/Reshape_22_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_7_grad/Pad" + op: "Pad" + input: "gradients/dipole_charge/filter_type_all/Reshape_22_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_7_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_21_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_7_grad/Pad" + input: "gradients/dipole_charge/filter_type_all/Reshape_21_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_15_grad/MatMul" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_26" + input: "gradients/dipole_charge/filter_type_all/add_26_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_27_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/MatMul_15_grad/MatMul" + input: "gradients/dipole_charge/filter_type_all/Reshape_27_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_24" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/Reshape_27_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Reshape_21_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/Reshape_27_grad/Reshape" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_6_grad/Pad" + op: "Pad" + input: "gradients/AddN_24" + input: "gradients/dipole_charge/filter_type_all/Slice_6_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_26_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/add_33_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/add_26_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_26_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_26_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_26_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_19_grad/Sum_1" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/add_26_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/add_19_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_19_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_19_grad/Sum_1" + input: "gradients/dipole_charge/filter_type_all/add_19_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_11_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_20" + input: "gradients/dipole_charge/filter_type_all/add_19_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_19_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/MatMul_11_grad/MatMul_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_19_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_18_grad/Sum_1" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Reshape_19_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/add_18_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_18_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_18_grad/Sum_1" + input: "gradients/dipole_charge/filter_type_all/add_18_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_18_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_18_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_18_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Tanh_8_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_8" + input: "gradients/dipole_charge/filter_type_all/Reshape_18_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_17_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Tanh_8_grad/TanhGrad" + input: "gradients/dipole_charge/filter_type_all/add_17_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_17_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_17_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_17_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_10_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/filter_type_all/add_17_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_3_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_18_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Reshape_19_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/add_18_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_18_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_18_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_18_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_8_grad/Slice_1" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_18_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_8_grad/ConcatOffset:1" + input: "gradients/dipole_charge/filter_type_all/concat_8_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_8_grad/Slice" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_18_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_8_grad/ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_8_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_10" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/concat_8_grad/Slice" + input: "gradients/dipole_charge/filter_type_all/concat_8_grad/Slice_1" + input: "gradients/dipole_charge/filter_type_all/MatMul_10_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/concat_8_grad/Slice" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_16_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_10" + input: "gradients/dipole_charge/filter_type_all/add_16_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_16_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_16_grad/Sum_1" + input: "gradients/dipole_charge/filter_type_all/add_16_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_17_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_16_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_17_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Tanh_7_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_7" + input: "gradients/dipole_charge/filter_type_all/Reshape_17_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_15_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Tanh_7_grad/TanhGrad" + input: "gradients/dipole_charge/filter_type_all/add_15_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_15_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_15_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_15_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_9_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/filter_type_all/add_15_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_2_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_16_grad/Sum" + op: "Sum" + input: "gradients/AddN_10" + input: "gradients/dipole_charge/filter_type_all/add_16_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_16_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_16_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_16_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_7_grad/Slice_1" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_16_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_7_grad/ConcatOffset:1" + input: "gradients/dipole_charge/filter_type_all/concat_7_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_7_grad/Slice" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_16_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_7_grad/ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_7_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_15" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/concat_7_grad/Slice" + input: "gradients/dipole_charge/filter_type_all/concat_7_grad/Slice_1" + input: "gradients/dipole_charge/filter_type_all/MatMul_9_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/concat_7_grad/Slice" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_14_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_15" + input: "gradients/dipole_charge/filter_type_all/add_14_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_14_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_14_grad/Sum_1" + input: "gradients/dipole_charge/filter_type_all/add_14_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_16_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_14_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_16_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Tanh_6_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_6" + input: "gradients/dipole_charge/filter_type_all/Reshape_16_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_13_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Tanh_6_grad/TanhGrad" + input: "gradients/dipole_charge/filter_type_all/add_13_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_13_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_13_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_13_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_8_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/filter_type_all/add_13_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_1_2/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_14_grad/Sum" + op: "Sum" + input: "gradients/AddN_15" + input: "gradients/dipole_charge/filter_type_all/add_14_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_14_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_14_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_14_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_6_grad/Slice_1" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_14_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_6_grad/ConcatOffset:1" + input: "gradients/dipole_charge/filter_type_all/concat_6_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_6_grad/Slice" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_14_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_6_grad/ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_6_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_20" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/concat_6_grad/Slice" + input: "gradients/dipole_charge/filter_type_all/concat_6_grad/Slice_1" + input: "gradients/dipole_charge/filter_type_all/MatMul_8_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/concat_6_grad/Slice" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_15_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_20" + input: "gradients/dipole_charge/filter_type_all/Reshape_15_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_5_grad/Pad" + op: "Pad" + input: "gradients/dipole_charge/filter_type_all/Reshape_15_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_5_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_14_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_5_grad/Pad" + input: "gradients/dipole_charge/filter_type_all/Reshape_14_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_11_grad/MatMul" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_19" + input: "gradients/dipole_charge/filter_type_all/add_19_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_20_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/MatMul_11_grad/MatMul" + input: "gradients/dipole_charge/filter_type_all/Reshape_20_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_25" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/Reshape_20_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Reshape_14_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/Reshape_20_grad/Reshape" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_4_grad/Pad" + op: "Pad" + input: "gradients/AddN_25" + input: "gradients/dipole_charge/filter_type_all/Slice_4_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_19_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/add_26_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/add_19_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_19_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_19_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_19_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_12_grad/Sum_1" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/add_19_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/add_12_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_12_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_12_grad/Sum_1" + input: "gradients/dipole_charge/filter_type_all/add_12_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_7_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_13" + input: "gradients/dipole_charge/filter_type_all/add_12_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_12_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/MatMul_7_grad/MatMul_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_11_grad/Sum_1" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Reshape_12_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/add_11_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_11_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_11_grad/Sum_1" + input: "gradients/dipole_charge/filter_type_all/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_11_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_11_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Tanh_5_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_5" + input: "gradients/dipole_charge/filter_type_all/Reshape_11_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_10_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Tanh_5_grad/TanhGrad" + input: "gradients/dipole_charge/filter_type_all/add_10_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_10_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_10_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_6_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/filter_type_all/add_10_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_11_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Reshape_12_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/add_11_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_11_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_11_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_5_grad/Slice_1" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_11_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_5_grad/ConcatOffset:1" + input: "gradients/dipole_charge/filter_type_all/concat_5_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_5_grad/Slice" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_11_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_5_grad/ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_5_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_12" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/concat_5_grad/Slice" + input: "gradients/dipole_charge/filter_type_all/concat_5_grad/Slice_1" + input: "gradients/dipole_charge/filter_type_all/MatMul_6_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/concat_5_grad/Slice" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_9_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_12" + input: "gradients/dipole_charge/filter_type_all/add_9_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_9_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_9_grad/Sum_1" + input: "gradients/dipole_charge/filter_type_all/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_10_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_9_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Tanh_4_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_4" + input: "gradients/dipole_charge/filter_type_all/Reshape_10_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_8_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Tanh_4_grad/TanhGrad" + input: "gradients/dipole_charge/filter_type_all/add_8_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_8_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_8_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_5_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/filter_type_all/add_8_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_9_grad/Sum" + op: "Sum" + input: "gradients/AddN_12" + input: "gradients/dipole_charge/filter_type_all/add_9_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_9_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_9_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_4_grad/Slice_1" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_9_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_4_grad/ConcatOffset:1" + input: "gradients/dipole_charge/filter_type_all/concat_4_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_4_grad/Slice" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_9_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_4_grad/ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_4_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_17" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/concat_4_grad/Slice" + input: "gradients/dipole_charge/filter_type_all/concat_4_grad/Slice_1" + input: "gradients/dipole_charge/filter_type_all/MatMul_5_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/concat_4_grad/Slice" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_7_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_17" + input: "gradients/dipole_charge/filter_type_all/add_7_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_7_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_7_grad/Sum_1" + input: "gradients/dipole_charge/filter_type_all/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_9_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_7_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Tanh_3_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_3" + input: "gradients/dipole_charge/filter_type_all/Reshape_9_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_6_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Tanh_3_grad/TanhGrad" + input: "gradients/dipole_charge/filter_type_all/add_6_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_6_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_6_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_4_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/filter_type_all/add_6_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_7_grad/Sum" + op: "Sum" + input: "gradients/AddN_17" + input: "gradients/dipole_charge/filter_type_all/add_7_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_7_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_7_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_3_grad/Slice_1" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_7_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_3_grad/ConcatOffset:1" + input: "gradients/dipole_charge/filter_type_all/concat_3_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_3_grad/Slice" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_7_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_3_grad/ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_3_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_22" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/concat_3_grad/Slice" + input: "gradients/dipole_charge/filter_type_all/concat_3_grad/Slice_1" + input: "gradients/dipole_charge/filter_type_all/MatMul_4_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/concat_3_grad/Slice" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_8_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_22" + input: "gradients/dipole_charge/filter_type_all/Reshape_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_3_grad/Pad" + op: "Pad" + input: "gradients/dipole_charge/filter_type_all/Reshape_8_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_3_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_7_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_3_grad/Pad" + input: "gradients/dipole_charge/filter_type_all/Reshape_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_7_grad/MatMul" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_12" + input: "gradients/dipole_charge/filter_type_all/add_12_grad/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_13_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/MatMul_7_grad/MatMul" + input: "gradients/dipole_charge/filter_type_all/Reshape_13_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_27" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/Reshape_13_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Reshape_7_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/Reshape_13_grad/Reshape" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_2_grad/Pad" + op: "Pad" + input: "gradients/AddN_27" + input: "gradients/dipole_charge/filter_type_all/Slice_2_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_12_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/add_19_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/add_12_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_12_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_12_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_3_grad/MatMul_1" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_6" + input: "gradients/dipole_charge/filter_type_all/add_12_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_5_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/MatMul_3_grad/MatMul_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_5_grad/Sum_1" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Reshape_5_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/add_5_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_5_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_5_grad/Sum_1" + input: "gradients/dipole_charge/filter_type_all/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_4_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_5_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Tanh_2_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_2" + input: "gradients/dipole_charge/filter_type_all/Reshape_4_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_4_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Tanh_2_grad/TanhGrad" + input: "gradients/dipole_charge/filter_type_all/add_4_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_4_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_4_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_2_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/filter_type_all/add_4_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_5_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Reshape_5_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/add_5_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_5_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_5_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_2_grad/Slice_1" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_5_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_2_grad/ConcatOffset:1" + input: "gradients/dipole_charge/filter_type_all/concat_2_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_2_grad/Slice" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_5_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_2_grad/ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_2_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_11" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/concat_2_grad/Slice" + input: "gradients/dipole_charge/filter_type_all/concat_2_grad/Slice_1" + input: "gradients/dipole_charge/filter_type_all/MatMul_2_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/concat_2_grad/Slice" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_3_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_11" + input: "gradients/dipole_charge/filter_type_all/add_3_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_3_grad/Sum_1" + input: "gradients/dipole_charge/filter_type_all/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_3_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_3_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Tanh_1_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_3_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_2_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Tanh_1_grad/TanhGrad" + input: "gradients/dipole_charge/filter_type_all/add_2_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_2_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_2_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_1_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/filter_type_all/add_2_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_3_grad/Sum" + op: "Sum" + input: "gradients/AddN_11" + input: "gradients/dipole_charge/filter_type_all/add_3_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_3_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_3_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_1_grad/Slice_1" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_3_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_1_grad/ConcatOffset:1" + input: "gradients/dipole_charge/filter_type_all/concat_1_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_1_grad/Slice" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_3_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_1_grad/ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_1_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_16" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/concat_1_grad/Slice" + input: "gradients/dipole_charge/filter_type_all/concat_1_grad/Slice_1" + input: "gradients/dipole_charge/filter_type_all/MatMul_1_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/concat_1_grad/Slice" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_1_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_16" + input: "gradients/dipole_charge/filter_type_all/add_1_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_1_grad/Sum_1" + input: "gradients/dipole_charge/filter_type_all/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_2_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_1_grad/Reshape_1" + input: "gradients/dipole_charge/filter_type_all/Reshape_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "dipole_charge/filter_type_all/Tanh" + input: "gradients/dipole_charge/filter_type_all/Reshape_2_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_grad/Sum" + op: "Sum" + input: "gradients/dipole_charge/filter_type_all/Tanh_grad/TanhGrad" + input: "gradients/dipole_charge/filter_type_all/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/dipole_charge/filter_type_all/add_grad/Reshape" + input: "dipole_charge/filter_type_all/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_1_grad/Sum" + op: "Sum" + input: "gradients/AddN_16" + input: "gradients/dipole_charge/filter_type_all/add_1_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/add_1_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/add_1_grad/Sum" + input: "gradients/dipole_charge/filter_type_all/add_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_grad/Slice_1" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_1_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_grad/ConcatOffset:1" + input: "gradients/dipole_charge/filter_type_all/concat_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/concat_grad/Slice" + op: "Slice" + input: "gradients/dipole_charge/filter_type_all/add_1_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/concat_grad/ConcatOffset" + input: "gradients/dipole_charge/filter_type_all/concat_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_21" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/concat_grad/Slice" + input: "gradients/dipole_charge/filter_type_all/concat_grad/Slice_1" + input: "gradients/dipole_charge/filter_type_all/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/concat_grad/Slice" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_1_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_21" + input: "gradients/dipole_charge/filter_type_all/Reshape_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_1_grad/Pad" + op: "Pad" + input: "gradients/dipole_charge/filter_type_all/Reshape_1_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_1_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/Slice_1_grad/Pad" + input: "gradients/dipole_charge/filter_type_all/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/MatMul_3_grad/MatMul" + op: "BatchMatMul" + input: "dipole_charge/filter_type_all/Reshape_5" + input: "gradients/dipole_charge/filter_type_all/add_12_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: true + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Reshape_6_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/filter_type_all/MatMul_3_grad/MatMul" + input: "gradients/dipole_charge/filter_type_all/Reshape_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_26" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/Reshape_6_grad/Reshape" + input: "gradients/dipole_charge/filter_type_all/Reshape_grad/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/Reshape_6_grad/Reshape" + } + } + } +} +node { + name: "gradients/dipole_charge/filter_type_all/Slice_grad/Pad" + op: "Pad" + input: "gradients/AddN_26" + input: "gradients/dipole_charge/filter_type_all/Slice_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_28" + op: "AddN" + input: "gradients/dipole_charge/filter_type_all/Slice_8_grad/Pad" + input: "gradients/dipole_charge/filter_type_all/Slice_6_grad/Pad" + input: "gradients/dipole_charge/filter_type_all/Slice_4_grad/Pad" + input: "gradients/dipole_charge/filter_type_all/Slice_grad/Pad" + input: "gradients/dipole_charge/filter_type_all/Slice_2_grad/Pad" + attr { + key: "N" + value { + i: 5 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/dipole_charge/filter_type_all/Slice_8_grad/Pad" + } + } + } +} +node { + name: "gradients/dipole_charge/Reshape_5_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_28" + input: "gradients/dipole_charge/Reshape_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/dipole_charge/Reshape_4_grad/Reshape" + op: "Reshape" + input: "gradients/dipole_charge/Reshape_5_grad/Reshape" + input: "gradients/dipole_charge/Reshape_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_5" + op: "Reshape" + input: "gradients/dipole_charge/Reshape_4_grad/Reshape" + input: "Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_6" + op: "Slice" + input: "Reshape_5" + input: "Slice_6/begin" + input: "Slice_6/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Slice_5" + op: "Slice" + input: "Reshape_5" + input: "Slice_5/begin" + input: "Slice_5/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "concat_1" + op: "ConcatV2" + input: "Slice_5" + input: "Slice_6" + input: "concat_1/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_8" + op: "Reshape" + input: "concat_1" + input: "Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "concat_4" + op: "ConcatV2" + input: "Reshape_8" + input: "Reshape_9" + input: "Reshape_10" + input: "concat_4/axis" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_11" + op: "Reshape" + input: "concat_4" + input: "Reshape_11/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_12" + op: "Reshape" + input: "Reshape_11" + input: "Reshape_12/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "MatMul" + op: "BatchMatMul" + input: "Reshape_1" + input: "Reshape_12" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "adj_x" + value { + b: false + } + } + attr { + key: "adj_y" + value { + b: false + } + } +} +node { + name: "Reshape_13" + op: "Reshape" + input: "MatMul" + input: "Reshape_13/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_6" + op: "Shape" + input: "Reshape_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_43" + op: "StridedSlice" + input: "Shape_6" + input: "strided_slice_43/stack" + input: "strided_slice_43/stack_1" + input: "strided_slice_43/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "zeros_5/packed" + op: "Pack" + input: "strided_slice_43" + input: "mul_26" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "zeros_5" + op: "Fill" + input: "zeros_5/packed" + input: "zeros_5/Const" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "index_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_12" + op: "Slice" + input: "Reshape_13" + input: "Slice_12/begin" + input: "Slice_12/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Shape_5" + op: "Shape" + input: "Reshape_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_39" + op: "StridedSlice" + input: "Shape_5" + input: "strided_slice_39/stack" + input: "strided_slice_39/stack_1" + input: "strided_slice_39/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "zeros_4/packed" + op: "Pack" + input: "strided_slice_39" + input: "mul_23" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "zeros_4" + op: "Fill" + input: "zeros_4/packed" + input: "zeros_4/Const" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "index_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_11" + op: "Slice" + input: "Reshape_13" + input: "Slice_11/begin" + input: "Slice_11/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Shape_4" + op: "Shape" + input: "Reshape_13" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_35" + op: "StridedSlice" + input: "Shape_4" + input: "strided_slice_35/stack" + input: "strided_slice_35/stack_1" + input: "strided_slice_35/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "zeros_3/packed" + op: "Pack" + input: "strided_slice_35" + input: "mul_21" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "zeros_3" + op: "Fill" + input: "zeros_3/packed" + input: "zeros_3/Const" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "index_type" + value { + type: DT_INT32 + } + } +} +node { + name: "concat_5" + op: "ConcatV2" + input: "zeros_3" + input: "Slice_11" + input: "zeros_4" + input: "Slice_12" + input: "zeros_5" + input: "concat_5/axis" + attr { + key: "N" + value { + i: 5 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_14" + op: "Reshape" + input: "concat_5" + input: "Reshape_14/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Neg" + op: "Neg" + input: "Reshape_14" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/o_nlist" + op: "Identity" + input: "dipole_charge/ProdEnvMatA:3" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "dipole_charge/o_rij" + op: "Identity" + input: "dipole_charge/ProdEnvMatA:2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "dipole_charge/o_rmat_deriv" + op: "Identity" + input: "dipole_charge/ProdEnvMatA:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "ProdVirialSeA" + op: "ProdVirialSeA" + input: "Neg" + input: "dipole_charge/o_rmat_deriv" + input: "dipole_charge/o_rij" + input: "dipole_charge/o_nlist" + input: "dipole_charge/t_natoms" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "n_a_sel" + value { + i: 25 + } + } + attr { + key: "n_r_sel" + value { + i: 0 + } + } +} +node { + name: "o_dm_av" + op: "Identity" + input: "ProdVirialSeA:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "o_dm_virial" + op: "Identity" + input: "ProdVirialSeA" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "ProdForceSeA" + op: "ProdForceSeA" + input: "Neg" + input: "dipole_charge/o_rmat_deriv" + input: "dipole_charge/o_nlist" + input: "dipole_charge/t_natoms" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "n_a_sel" + value { + i: 25 + } + } + attr { + key: "n_r_sel" + value { + i: 0 + } + } +} +node { + name: "o_dm_force" + op: "Identity" + input: "ProdForceSeA" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +library { +} diff --git a/source/tests/test_dipolecharge.py b/source/tests/test_dipolecharge.py new file mode 100644 index 0000000000..94b94dffe2 --- /dev/null +++ b/source/tests/test_dipolecharge.py @@ -0,0 +1,112 @@ +import os,sys,platform,shutil,dpdata +import numpy as np +import unittest + +from infer.convert2pb import convert_pbtxt_to_pb +from deepmd.infer import DipoleChargeModifier +from common import tests_path + +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +if GLOBAL_NP_FLOAT_PRECISION == np.float32 : + default_places = 4 +else : + default_places = 10 + +class TestDipoleCharge(unittest.TestCase) : + def setUp(self): + convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","dipolecharge_d.pbtxt")), "dipolecharge_d.pb") + self.dp = DipoleChargeModifier( + "dipolecharge_d.pb", + [-1.0, -3.0], + [1.0, 1.0, 1.0, 1.0, 1.0], + 4.0, + 0.2 + ) + self.coords = np.array([ + 4.6067455554, 8.8719311819, 6.3886531197, + 4.0044515745, 4.2449530507, 7.7902855220, + 2.6453069446, 0.8772647726, 1.2804446790, + 1.1445332290, 0.0067366438, 1.8606485070, + 7.1002867706, 5.0325506787, 3.1805888348, + 4.5352891138, 7.7389683929, 9.4260970128, + 2.1833238914, 9.0916071034, 7.2299906064, + 4.1040157820, 1.0496745045, 5.4748315591, + ], dtype = np.float64) + # 1.1445332290, 0.0067366438, 1.8606485070, + # 2.1833238914, 9.0916071034, 7.2299906064, + # 4.0044515745, 4.2449530507, 7.7902855220, + # 7.1002867706, 5.0325506787, 3.1805888348, + self.atype = np.array([0,3,2,1,3,4,1,4], dtype=int) + self.box = np.array([10., 0., 0., 0., 10., 0., 0., 0., 10.]) + self.expected_e = np.array([ + 3.671081837126222158e+00 + ]) + self.expected_f = np.array([ + 8.786854427753210128e-01,-1.590752486903602159e-01,-2.709225006303785932e-01,-4.449513960033193438e-01,-1.564291540964127813e-01,2.139031741772115178e-02,1.219699614140521193e+00,-5.580358618499958734e-02,-3.878662478349682585e-01,-1.286685244990778854e+00,1.886475802950296488e-01,3.904450515493615437e-01,1.605017382138404849e-02,2.138016869742287995e-01,-2.617514921203008965e-02,2.877081057057793712e-01,-3.846449683844421763e-01,3.048855616906603894e-02,-9.075632811311897807e-01,-6.509653472431625731e-03,2.302010972126376787e-01,2.370565856822822726e-01,3.600133435593881881e-01,1.243887532859055609e-02 + ]) + self.expected_v = np.array([ + 3.714071471995848417e-01,6.957130186032146613e-01,-1.158289779017217302e+00,6.957130186032139951e-01,-1.400130091653774933e+01,-3.631620234653316626e-01,-1.158289779017217302e+00,-3.631620234653316626e-01,3.805077486043773050e+00 + ]) + self.natoms = self.atype.size + self.coords = self.coords.reshape([-1, self.natoms, 3]) + + def tearDown(self): + os.remove("dipolecharge_d.pb") + + def test_attrs(self): + self.assertEqual(self.dp.get_ntypes(), 5) + self.assertAlmostEqual(self.dp.get_rcut(), 4.0, places = default_places) + self.assertEqual(self.dp.get_type_map(), ['A', 'B', 'C', 'D', 'E']) + + def test_1frame(self): + ee, ff, vv = self.dp.eval(self.coords, self.box, self.atype, eval_fv = True +) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + self.assertEqual(self.expected_e.shape, (nframes,)) + self.assertEqual(self.expected_f.shape, (nframes*natoms*3,)) + self.assertEqual(self.expected_v.shape, (nframes*9,)) + # np.savetxt('ee.out', ee.reshape([1, -1]), delimiter=',') + # np.savetxt('ff.out', ff.reshape([1, -1]), delimiter=',') + # np.savetxt('vv.out', vv.reshape([1, -1]), delimiter=',') + ee = ee.reshape([-1]) + ff = ff.reshape([-1]) + vv = vv.reshape([-1]) + for ii in range(ee.size): + self.assertAlmostEqual(ee[ii], self.expected_e[ii]) + for ii in range(ff.size): + self.assertAlmostEqual(ff[ii], self.expected_f[ii]) + for ii in range(vv.size): + self.assertAlmostEqual(vv[ii], self.expected_v[ii]) + + def test_2frame(self): + nframes = 2 + self.coords = np.tile(self.coords, [nframes, 1, 1]) + self.box = np.tile(self.box, [nframes, 1]) + ee, ff, vv = self.dp.eval(self.coords, self.box, self.atype, eval_fv = True +) + # check shape of the returns + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + self.expected_e = np.tile(self.expected_e, [nframes]) + self.expected_f = np.tile(self.expected_f, [nframes]) + self.expected_v = np.tile(self.expected_v, [nframes]) + self.assertEqual(self.expected_e.shape, (nframes,)) + self.assertEqual(self.expected_f.shape, (nframes*natoms*3,)) + self.assertEqual(self.expected_v.shape, (nframes*9,)) + ee = ee.reshape([-1]) + ff = ff.reshape([-1]) + vv = vv.reshape([-1]) + for ii in range(ee.size): + self.assertAlmostEqual(ee[ii], self.expected_e[ii]) + for ii in range(ff.size): + self.assertAlmostEqual(ff[ii], self.expected_f[ii]) + for ii in range(vv.size): + self.assertAlmostEqual(vv[ii], self.expected_v[ii]) + From 96679a93f496be86a8d60836b6adf92a552cc902 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 10 Mar 2021 14:52:49 +0800 Subject: [PATCH 248/562] switched to new nlist interface. clean up c++ api. add unittests. --- source/api_cc/include/DataModifier.h | 10 +- source/api_cc/include/DeepTensor.h | 10 +- source/api_cc/include/NNPInter.h | 190 ++--- source/api_cc/include/common.h | 114 +-- source/api_cc/src/DataModifier.cc | 40 +- source/api_cc/src/DeepTensor.cc | 47 +- source/api_cc/src/NNPInter.cc | 904 +++++++++++------------ source/api_cc/src/common.cc | 737 +++++++++--------- source/api_cc/tests/CMakeLists.txt | 106 +++ source/api_cc/tests/test_deepdipole.cc | 106 +++ source/api_cc/tests/test_deeppolar.cc | 106 +++ source/api_cc/tests/test_deeppot.cc | 437 +++++++++++ source/api_cc/tests/test_dipolecharge.cc | 240 ++++++ source/api_cc/tests/test_utils.h | 50 ++ 14 files changed, 2070 insertions(+), 1027 deletions(-) create mode 100644 source/api_cc/tests/CMakeLists.txt create mode 100644 source/api_cc/tests/test_deepdipole.cc create mode 100644 source/api_cc/tests/test_deeppolar.cc create mode 100644 source/api_cc/tests/test_deeppot.cc create mode 100644 source/api_cc/tests/test_dipolecharge.cc create mode 100644 source/api_cc/tests/test_utils.h diff --git a/source/api_cc/include/DataModifier.h b/source/api_cc/include/DataModifier.h index 1bb3e26488..8d16d2ad6d 100644 --- a/source/api_cc/include/DataModifier.h +++ b/source/api_cc/include/DataModifier.h @@ -2,14 +2,14 @@ #include "NNPInter.h" -class DataModifier +class DipoleChargeModifier { public: - DataModifier(); - DataModifier(const std::string & model, + DipoleChargeModifier(); + DipoleChargeModifier(const std::string & model, const int & gpu_rank = 0, const std::string & name_scope = ""); - ~DataModifier () {}; + ~DipoleChargeModifier () {}; void init (const std::string & model, const int & gpu_rank = 0, const std::string & name_scope = ""); @@ -23,7 +23,7 @@ class DataModifier const std::vector> & pairs, const std::vector & delef_, const int nghost, - const LammpsNeighborList & lmp_list); + const InputNlist & lmp_list); VALUETYPE cutoff () const {assert(inited); return rcut;}; int numb_types () const {assert(inited); return ntypes;}; std::vector sel_types () const {assert(inited); return sel_type;}; diff --git a/source/api_cc/include/DeepTensor.h b/source/api_cc/include/DeepTensor.h index f73957137d..ec2c7de22b 100644 --- a/source/api_cc/include/DeepTensor.h +++ b/source/api_cc/include/DeepTensor.h @@ -17,14 +17,13 @@ class DeepTensor void compute (std::vector & value, const std::vector & coord, const std::vector & atype, - const std::vector & box, - const int nghost = 0); + const std::vector & box); void compute (std::vector & value, const std::vector & coord, const std::vector & atype, const std::vector & box, const int nghost, - const LammpsNeighborList & lmp_list); + const InputNlist & inlist); VALUETYPE cutoff () const {assert(inited); return rcut;}; int numb_types () const {assert(inited); return ntypes;}; int output_dim () const {assert(inited); return odim;}; @@ -51,13 +50,12 @@ class DeepTensor void compute_inner (std::vector & value, const std::vector & coord, const std::vector & atype, - const std::vector & box, - const int nghost = 0); + const std::vector & box); void compute_inner (std::vector & value, const std::vector & coord, const std::vector & atype, const std::vector & box, const int nghost, - const InternalNeighborList& lmp_list); + const InputNlist& inlist); }; diff --git a/source/api_cc/include/NNPInter.h b/source/api_cc/include/NNPInter.h index 11bfad9c27..da89cdc0cd 100644 --- a/source/api_cc/include/NNPInter.h +++ b/source/api_cc/include/NNPInter.h @@ -1,6 +1,7 @@ #pragma once #include "common.h" +#include "neighbor_list.h" typedef double compute_t; class NNPInter @@ -18,7 +19,6 @@ class NNPInter const std::vector & coord, const std::vector & atype, const std::vector & box, - const int nghost = 0, const std::vector& fparam = std::vector(), const std::vector& aparam = std::vector()); void compute (ENERGYTYPE & ener, @@ -28,7 +28,7 @@ class NNPInter const std::vector & atype, const std::vector & box, const int nghost, - const LammpsNeighborList & lmp_list, + const InputNlist & inlist, const int& ago, const std::vector& fparam = std::vector(), const std::vector& aparam = std::vector()); @@ -51,7 +51,7 @@ class NNPInter const std::vector & atype, const std::vector & box, const int nghost, - const LammpsNeighborList & lmp_list, + const InputNlist & lmp_list, const int& ago, const std::vector& fparam = std::vector(), const std::vector& aparam = std::vector()); @@ -91,7 +91,7 @@ class NNPInter bool init_nbor; std::vector sec_a; compute_t *array_double; - InternalNeighborList nlist; + NeighborListData nlist_data; NNPAtomMap nnpmap; int *ilist, *jrange, *jlist; int ilist_size, jrange_size, jlist_size; @@ -100,98 +100,98 @@ class NNPInter std::vector get_sel_a() const; }; -class NNPInterModelDevi -{ -public: - NNPInterModelDevi () ; - ~NNPInterModelDevi() ; - NNPInterModelDevi (const std::vector & models, const int & gpu_rank = 0, const std::vector & file_contents = std::vector()); - void init (const std::vector & models, const int & gpu_rank = 0, const std::vector & file_contents = std::vector()); -public: - void compute (ENERGYTYPE & ener, - std::vector & force, - std::vector & virial, - std::vector & model_devi, - const std::vector & coord, - const std::vector & atype, - const std::vector & box, - const std::vector & fparam = std::vector(), - const std::vector & aparam = std::vector()); - void compute (std::vector & all_ener, - std::vector > & all_force, - std::vector > & all_virial, - const std::vector & coord, - const std::vector & atype, - const std::vector & box, - const int nghost, - const LammpsNeighborList & lmp_list, - const int & ago, - const std::vector & fparam = std::vector(), - const std::vector & aparam = std::vector()); - void compute (std::vector & all_ener, - std::vector > & all_force, - std::vector > & all_virial, - std::vector > & all_atom_energy, - std::vector > & all_atom_virial, - const std::vector & coord, - const std::vector & atype, - const std::vector & box, - const int nghost, - const LammpsNeighborList & lmp_list, - const int & ago, - const std::vector & fparam = std::vector(), - const std::vector & aparam = std::vector()); - VALUETYPE cutoff () const {assert(inited); return rcut;}; - int numb_types () const {assert(inited); return ntypes;}; - int dim_fparam () const {assert(inited); return dfparam;}; - int dim_aparam () const {assert(inited); return daparam;}; -#ifndef HIGH_PREC - void compute_avg (ENERGYTYPE & dener, - const std::vector & all_energy); -#endif - void compute_avg (VALUETYPE & dener, - const std::vector & all_energy); - void compute_avg (std::vector & avg, - const std::vector > & xx); - void compute_std_e (std::vector & std, - const std::vector & avg, - const std::vector >& xx); - void compute_std_f (std::vector & std, - const std::vector & avg, - const std::vector >& xx); - void compute_relative_std_f (std::vector & std, - const std::vector & avg, - const VALUETYPE eps); -private: - unsigned numb_models; - std::vector sessions; - int num_intra_nthreads, num_inter_nthreads; - std::vector graph_defs; - bool inited; - template VT get_scalar(const std::string name) const; - // VALUETYPE get_rcut () const; - // int get_ntypes () const; - VALUETYPE rcut; - VALUETYPE cell_size; - int ntypes; - int dfparam; - int daparam; - void validate_fparam_aparam(const int & nloc, - const std::vector &fparam, - const std::vector &aparam)const ; +// class NNPInterModelDevi +// { +// public: +// NNPInterModelDevi () ; +// ~NNPInterModelDevi() ; +// NNPInterModelDevi (const std::vector & models, const int & gpu_rank = 0, const std::vector & file_contents = std::vector()); +// void init (const std::vector & models, const int & gpu_rank = 0, const std::vector & file_contents = std::vector()); +// public: +// void compute (ENERGYTYPE & ener, +// std::vector & force, +// std::vector & virial, +// std::vector & model_devi, +// const std::vector & coord, +// const std::vector & atype, +// const std::vector & box, +// const std::vector & fparam = std::vector(), +// const std::vector & aparam = std::vector()); +// void compute (std::vector & all_ener, +// std::vector > & all_force, +// std::vector > & all_virial, +// const std::vector & coord, +// const std::vector & atype, +// const std::vector & box, +// const int nghost, +// const LammpsNeighborList & lmp_list, +// const int & ago, +// const std::vector & fparam = std::vector(), +// const std::vector & aparam = std::vector()); +// void compute (std::vector & all_ener, +// std::vector > & all_force, +// std::vector > & all_virial, +// std::vector > & all_atom_energy, +// std::vector > & all_atom_virial, +// const std::vector & coord, +// const std::vector & atype, +// const std::vector & box, +// const int nghost, +// const LammpsNeighborList & lmp_list, +// const int & ago, +// const std::vector & fparam = std::vector(), +// const std::vector & aparam = std::vector()); +// VALUETYPE cutoff () const {assert(inited); return rcut;}; +// int numb_types () const {assert(inited); return ntypes;}; +// int dim_fparam () const {assert(inited); return dfparam;}; +// int dim_aparam () const {assert(inited); return daparam;}; +// #ifndef HIGH_PREC +// void compute_avg (ENERGYTYPE & dener, +// const std::vector & all_energy); +// #endif +// void compute_avg (VALUETYPE & dener, +// const std::vector & all_energy); +// void compute_avg (std::vector & avg, +// const std::vector > & xx); +// void compute_std_e (std::vector & std, +// const std::vector & avg, +// const std::vector >& xx); +// void compute_std_f (std::vector & std, +// const std::vector & avg, +// const std::vector >& xx); +// void compute_relative_std_f (std::vector & std, +// const std::vector & avg, +// const VALUETYPE eps); +// private: +// unsigned numb_models; +// std::vector sessions; +// int num_intra_nthreads, num_inter_nthreads; +// std::vector graph_defs; +// bool inited; +// template VT get_scalar(const std::string name) const; +// // VALUETYPE get_rcut () const; +// // int get_ntypes () const; +// VALUETYPE rcut; +// VALUETYPE cell_size; +// int ntypes; +// int dfparam; +// int daparam; +// void validate_fparam_aparam(const int & nloc, +// const std::vector &fparam, +// const std::vector &aparam)const ; - // copy neighbor list info from host - bool init_nbor; - compute_t *array_double; - std::vector > sec; - InternalNeighborList nlist; - NNPAtomMap nnpmap; - int *ilist, *jrange, *jlist; - int ilist_size, jrange_size, jlist_size; +// // copy neighbor list info from host +// bool init_nbor; +// compute_t *array_double; +// std::vector > sec; +// InternalNeighborList nlist; +// NNPAtomMap nnpmap; +// int *ilist, *jrange, *jlist; +// int ilist_size, jrange_size, jlist_size; - // function used for nborlist copy - std::vector > get_sel() const; - void cum_sum(const std::vector > n_sel); -}; +// // function used for nborlist copy +// std::vector > get_sel() const; +// void cum_sum(const std::vector > n_sel); +// }; diff --git a/source/api_cc/include/common.h b/source/api_cc/include/common.h index 4014b643b8..9e2110b03b 100644 --- a/source/api_cc/include/common.h +++ b/source/api_cc/include/common.h @@ -4,6 +4,7 @@ #include #include #include "version.h" +#include "neighbor_list.h" #include "NNPAtomMap.h" #include "tensorflow/core/platform/env.h" @@ -27,52 +28,20 @@ typedef float VALUETYPE; typedef double ENERGYTYPE; #endif -struct LammpsNeighborList +struct NeighborListData { - int inum; - const int * ilist; - const int * numneigh; - const int *const* firstneigh; - LammpsNeighborList (int inum_, - const int * ilist_, - const int * numneigh_, - const int *const* firstneigh_) - : inum(inum_), ilist(ilist_), numneigh(numneigh_), firstneigh(firstneigh_) - { - } -}; - -struct InternalNeighborList -{ - int * pilist; - int * pjrange; - int * pjlist; std::vector ilist; - std::vector jrange; - std::vector jlist; - void clear () {ilist.clear(); jrange.clear(); jlist.clear();} - void make_ptrs () { - pilist = &ilist[0]; pjrange = &jrange[0]; pjlist = &jlist[0]; - } + std::vector > jlist; + std::vector numneigh; + std::vector firstneigh; +public: + void copy_from_nlist(const InputNlist & inlist); + void shuffle(const std::vector & fwd_map); + void shuffle(const NNPAtomMap & map); + void shuffle_exclude_empty(const std::vector & fwd_map); + void make_inlist(InputNlist & inlist); }; -void -convert_nlist_lmp_internal (InternalNeighborList & list, - const LammpsNeighborList & lmp_list); - -void -shuffle_nlist (InternalNeighborList & list, - const std::vector & fwd_map); - -void -shuffle_nlist (InternalNeighborList & list, - const NNPAtomMap & map); - -void -shuffle_nlist_exclude_empty (InternalNeighborList & list, - const std::vector & fwd_map); - - void select_by_type(std::vector & fwd_map, std::vector & bkw_map, @@ -125,8 +94,7 @@ session_input_tensors (std::vector> & input_tenso const std::vector & fparam_, const std::vector & aparam_, const NNPAtomMap& nnpmap, - const int nghost = 0, - const std::string scope = ""); + const std::string scope = ""); int session_input_tensors (std::vector> & input_tensors, @@ -134,40 +102,40 @@ session_input_tensors (std::vector> & input_tenso const int & ntypes, const std::vector & datype_, const std::vector & dbox, - InternalNeighborList & dlist, + InputNlist & dlist, const std::vector & fparam_, const std::vector & aparam_, const NNPAtomMap& nnpmap, const int nghost, const int ago, - const std::string scope = ""); - -int -session_input_tensors (std::vector> & input_tensors, - const std::vector & dcoord_, - const int & ntypes, - const std::vector & datype_, - const std::vector & dbox, - InternalNeighborList & dlist, - const std::vector & fparam_, - const std::vector & aparam_, - const NNPAtomMap& nnpmap, - const int nghost, - const std::string scope = ""); - -int -session_input_tensors (std::vector>& input_tensors, - const std::vector & dcoord_, - const int & ntypes, - const std::vector & atype_, - const std::vector & dbox, - const int * ilist, - const int * jrange, - const int * jlist, - const std::vector & fparam_, - const std::vector & aparam_, - const NNPAtomMap & nnpmap, - const int & nghost); + const std::string scope = ""); + +// int +// session_input_tensors (std::vector> & input_tensors, +// const std::vector & dcoord_, +// const int & ntypes, +// const std::vector & datype_, +// const std::vector & dbox, +// InputNlist & dlist, +// const std::vector & fparam_, +// const std::vector & aparam_, +// const NNPAtomMap& nnpmap, +// const int nghost, +// const std::string scope = ""); + +// int +// session_input_tensors (std::vector>& input_tensors, +// const std::vector & dcoord_, +// const int & ntypes, +// const std::vector & atype_, +// const std::vector & dbox, +// const int * ilist, +// const int * jrange, +// const int * jlist, +// const std::vector & fparam_, +// const std::vector & aparam_, +// const NNPAtomMap & nnpmap, +// const int & nghost); template diff --git a/source/api_cc/src/DataModifier.cc b/source/api_cc/src/DataModifier.cc index 8144451841..45ded50346 100644 --- a/source/api_cc/src/DataModifier.cc +++ b/source/api_cc/src/DataModifier.cc @@ -1,30 +1,33 @@ #include "DataModifier.h" -DataModifier:: -DataModifier() +DipoleChargeModifier:: +DipoleChargeModifier() : inited (false) { } -DataModifier:: -DataModifier(const std::string & model, +DipoleChargeModifier:: +DipoleChargeModifier(const std::string & model, const int & gpu_rank, const std::string &name_scope_) : inited (false), name_scope(name_scope_) { - get_env_nthreads(num_intra_nthreads, num_inter_nthreads); init(model, gpu_rank); } void -DataModifier:: +DipoleChargeModifier:: init (const std::string & model, const int & gpu_rank, const std::string &name_scope_) { - assert (!inited); + if (inited){ + std::cerr << "WARNING: deepmd-kit should not be initialized twice, do nothing at the second call of initializer" << std::endl; + return ; + } name_scope = name_scope_; SessionOptions options; + get_env_nthreads(num_intra_nthreads, num_inter_nthreads); options.config.set_inter_op_parallelism_threads(num_inter_nthreads); options.config.set_intra_op_parallelism_threads(num_intra_nthreads); checkStatus(NewSession(options, &session)); @@ -45,7 +48,7 @@ init (const std::string & model, template VT -DataModifier:: +DipoleChargeModifier:: get_scalar (const std::string & name) const { return session_get_scalar(session, name, name_scope); @@ -53,14 +56,14 @@ get_scalar (const std::string & name) const template void -DataModifier:: +DipoleChargeModifier:: get_vector (std::vector & vec, const std::string & name) const { session_get_vector(vec, session, name, name_scope); } void -DataModifier:: +DipoleChargeModifier:: run_model (std::vector & dforce, std::vector & dvirial, Session * session, @@ -113,7 +116,7 @@ run_model (std::vector & dforce, void -DataModifier:: +DipoleChargeModifier:: compute (std::vector & dfcorr_, std::vector & dvcorr_, const std::vector & dcoord_, @@ -122,7 +125,7 @@ compute (std::vector & dfcorr_, const std::vector>& pairs, const std::vector & delef_, const int nghost, - const LammpsNeighborList & lmp_list) + const InputNlist & nlist) { // firstly do selection int nall = datype_.size(); @@ -151,20 +154,21 @@ compute (std::vector & dfcorr_, select_map(delef_real, delef_, real_fwd_map, 3); select_map(datype_real, datype_, real_fwd_map, 1); // internal nlist - InternalNeighborList nlist_; - convert_nlist_lmp_internal(nlist_, lmp_list); - shuffle_nlist_exclude_empty(nlist_, real_fwd_map); + NeighborListData nlist_data; + nlist_data.copy_from_nlist(nlist); + nlist_data.shuffle_exclude_empty(real_fwd_map); // sort atoms NNPAtomMap nnpmap (datype_real.begin(), datype_real.begin() + nloc_real); assert (nloc_real == nnpmap.get_type().size()); const std::vector & sort_fwd_map(nnpmap.get_fwd_map()); const std::vector & sort_bkw_map(nnpmap.get_bkw_map()); // shuffle nlist - InternalNeighborList nlist(nlist_); - shuffle_nlist (nlist, nnpmap); + nlist_data.shuffle(nnpmap); + InputNlist inlist; + nlist_data.make_inlist(inlist); // make input tensors std::vector> input_tensors; - int ret = session_input_tensors (input_tensors, dcoord_real, ntypes, datype_real, dbox, nlist, std::vector(), std::vector(), nnpmap, nghost_real, name_scope); + int ret = session_input_tensors (input_tensors, dcoord_real, ntypes, datype_real, dbox, inlist, std::vector(), std::vector(), nnpmap, nghost_real, 0, name_scope); assert (nloc_real == ret); // make bond idx map std::vector bd_idx(nall, -1); diff --git a/source/api_cc/src/DeepTensor.cc b/source/api_cc/src/DeepTensor.cc index 311cd1051d..a26729d8ef 100644 --- a/source/api_cc/src/DeepTensor.cc +++ b/source/api_cc/src/DeepTensor.cc @@ -12,7 +12,6 @@ DeepTensor(const std::string & model, const std::string &name_scope_) : inited (false), name_scope(name_scope_) { - get_env_nthreads(num_intra_nthreads, num_inter_nthreads); init(model, gpu_rank); } @@ -22,9 +21,13 @@ init (const std::string & model, const int & gpu_rank, const std::string &name_scope_) { - assert (!inited); + if (inited){ + std::cerr << "WARNING: deepmd-kit should not be initialized twice, do nothing at the second call of initializer" << std::endl; + return ; + } name_scope = name_scope_; SessionOptions options; + get_env_nthreads(num_intra_nthreads, num_inter_nthreads); options.config.set_inter_op_parallelism_threads(num_inter_nthreads); options.config.set_intra_op_parallelism_threads(num_intra_nthreads); checkStatus (NewSession(options, &session)); @@ -96,20 +99,20 @@ DeepTensor:: compute (std::vector & dtensor_, const std::vector & dcoord_, const std::vector & datype_, - const std::vector & dbox, - const int nghost) + const std::vector & dbox) { std::vector dcoord; std::vector datype, fwd_map, bkw_map; int nghost_real; - select_real_atoms(fwd_map, bkw_map, nghost_real, dcoord_, datype_, nghost, ntypes); + select_real_atoms(fwd_map, bkw_map, nghost_real, dcoord_, datype_, 0, ntypes); + assert(nghost_real == 0); // resize to nall_real dcoord.resize(bkw_map.size() * 3); datype.resize(bkw_map.size()); // fwd map select_map(dcoord, dcoord_, fwd_map, 3); select_map(datype, datype_, fwd_map, 1); - compute_inner(dtensor_, dcoord, datype, dbox, nghost_real); + compute_inner(dtensor_, dcoord, datype, dbox); } void @@ -119,7 +122,7 @@ compute (std::vector & dtensor_, const std::vector & datype_, const std::vector & dbox, const int nghost, - const LammpsNeighborList & lmp_list) + const InputNlist & nlist) { std::vector dcoord; std::vector datype, fwd_map, bkw_map; @@ -132,10 +135,12 @@ compute (std::vector & dtensor_, select_map(dcoord, dcoord_, fwd_map, 3); select_map(datype, datype_, fwd_map, 1); // internal nlist - InternalNeighborList nlist; - convert_nlist_lmp_internal(nlist, lmp_list); - shuffle_nlist_exclude_empty(nlist, fwd_map); - compute_inner(dtensor_, dcoord, datype, dbox, nghost_real, nlist); + NeighborListData nlist_data; + nlist_data.copy_from_nlist(nlist); + nlist_data.shuffle_exclude_empty(fwd_map); + InputNlist inlist; + nlist_data.make_inlist(inlist); + compute_inner(dtensor_, dcoord, datype, dbox, nghost_real, inlist); } @@ -144,19 +149,18 @@ DeepTensor:: compute_inner (std::vector & dtensor_, const std::vector & dcoord_, const std::vector & datype_, - const std::vector & dbox, - const int nghost) + const std::vector & dbox) { int nall = dcoord_.size() / 3; - int nloc = nall - nghost; + int nloc = nall; NNPAtomMap nnpmap (datype_.begin(), datype_.begin() + nloc); assert (nloc == nnpmap.get_type().size()); std::vector> input_tensors; - int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, std::vector(), std::vector(), nnpmap, nghost, name_scope); + int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, std::vector(), std::vector(), nnpmap, name_scope); assert (ret == nloc); - run_model (dtensor_, session, input_tensors, nnpmap, nghost); + run_model (dtensor_, session, input_tensors, nnpmap); } void @@ -166,18 +170,21 @@ compute_inner (std::vector & dtensor_, const std::vector & datype_, const std::vector & dbox, const int nghost, - const InternalNeighborList & nlist_) + const InputNlist & nlist) { int nall = dcoord_.size() / 3; int nloc = nall - nghost; NNPAtomMap nnpmap (datype_.begin(), datype_.begin() + nloc); assert (nloc == nnpmap.get_type().size()); - InternalNeighborList nlist(nlist_); - shuffle_nlist (nlist, nnpmap); + NeighborListData nlist_data; + nlist_data.copy_from_nlist(nlist); + nlist_data.shuffle(nnpmap); + InputNlist inlist; + nlist_data.make_inlist(inlist); std::vector> input_tensors; - int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, std::vector(), std::vector(), nnpmap, nghost, name_scope); + int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, inlist, std::vector(), std::vector(), nnpmap, nghost, 0, name_scope); assert (nloc == ret); run_model (dtensor_, session, input_tensors, nnpmap, nghost); diff --git a/source/api_cc/src/NNPInter.cc b/source/api_cc/src/NNPInter.cc index 4ac454a324..cfb17a314c 100644 --- a/source/api_cc/src/NNPInter.cc +++ b/source/api_cc/src/NNPInter.cc @@ -173,14 +173,12 @@ NNPInter:: NNPInter () : inited (false), init_nbor (false) { - get_env_nthreads(num_intra_nthreads, num_inter_nthreads); } NNPInter:: NNPInter (const std::string & model, const int & gpu_rank, const std::string & file_content) : inited (false), init_nbor (false) { - get_env_nthreads(num_intra_nthreads, num_inter_nthreads); init(model, gpu_rank, file_content); } @@ -195,6 +193,7 @@ init (const std::string & model, const int & gpu_rank, const std::string & file_ return ; } SessionOptions options; + get_env_nthreads(num_intra_nthreads, num_inter_nthreads); options.config.set_inter_op_parallelism_threads(num_inter_nthreads); options.config.set_intra_op_parallelism_threads(num_intra_nthreads); @@ -322,21 +321,20 @@ compute (ENERGYTYPE & dener, const std::vector & dcoord_, const std::vector & datype_, const std::vector & dbox, - const int nghost, const std::vector & fparam, const std::vector & aparam) { int nall = dcoord_.size() / 3; - int nloc = nall - nghost; + int nloc = nall; nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); assert (nloc == nnpmap.get_type().size()); validate_fparam_aparam(nloc, fparam, aparam); std::vector> input_tensors; - int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, fparam, aparam, nnpmap, nghost); + int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, fparam, aparam, nnpmap); assert (ret == nloc); - run_model (dener, dforce_, dvirial, session, input_tensors, nnpmap, nghost); + run_model (dener, dforce_, dvirial, session, input_tensors, nnpmap); } void @@ -348,7 +346,7 @@ compute (ENERGYTYPE & dener, const std::vector & datype_, const std::vector & dbox, const int nghost, - const LammpsNeighborList & lmp_list, + const InputNlist & inlist, const int& ago, const std::vector & fparam, const std::vector & aparam_) @@ -370,11 +368,12 @@ compute (ENERGYTYPE & dener, } // internal nlist if (ago == 0){ - convert_nlist_lmp_internal(nlist, lmp_list); - shuffle_nlist_exclude_empty(nlist, fwd_map); + nlist_data.copy_from_nlist(inlist); + nlist_data.shuffle_exclude_empty(fwd_map); } compute_inner(dener, dforce, dvirial, dcoord, datype, dbox, nghost_real, ago, fparam, aparam); // bkw map + dforce_.resize(fwd_map.size() * 3); select_map(dforce_, dforce, bkw_map, 3); } @@ -399,13 +398,13 @@ compute_inner (ENERGYTYPE & dener, // agp == 0 means that the LAMMPS nbor list has been updated if (ago == 0) { - nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); - assert (nloc == nnpmap.get_type().size()); - - shuffle_nlist (nlist, nnpmap); + nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); + assert (nloc == nnpmap.get_type().size()); + nlist_data.shuffle(nnpmap); } - - int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, nnpmap, nghost, ago); + InputNlist inlist; + nlist_data.make_inlist(inlist); + int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, inlist, fparam, aparam, nnpmap, nghost, ago); assert (nloc == ret); run_model (dener, dforce_, dvirial, session, input_tensors, nnpmap, nghost); } @@ -446,7 +445,7 @@ compute (ENERGYTYPE & dener, const std::vector & datype_, const std::vector & dbox, const int nghost, - const LammpsNeighborList & lmp_list, + const InputNlist & nlist, const int & ago, const std::vector & fparam, const std::vector & aparam) @@ -459,13 +458,14 @@ compute (ENERGYTYPE & dener, if (ago == 0) { nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); assert (nloc == nnpmap.get_type().size()); - - // InternalNeighborList nlist; - convert_nlist_lmp_internal (nlist, lmp_list); - shuffle_nlist (nlist, nnpmap); + // make internal nlist data + nlist_data.copy_from_nlist(nlist); + nlist_data.shuffle(nnpmap); } - int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, nnpmap, nghost, ago); + InputNlist inlist; + nlist_data.make_inlist(inlist); + int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, inlist, fparam, aparam, nnpmap, nghost, ago); assert (nloc == ret); run_model (dener, dforce_, dvirial, datom_energy_, datom_virial_, session, input_tensors, nnpmap, nghost); } @@ -478,448 +478,448 @@ get_type_map(std::string & type_map){ -NNPInterModelDevi:: -NNPInterModelDevi () - : inited (false), - init_nbor (false), - numb_models (0) -{ - get_env_nthreads(num_intra_nthreads, num_inter_nthreads); -} - -NNPInterModelDevi:: -NNPInterModelDevi (const std::vector & models, const int & gpu_rank, const std::vector & file_contents) - : inited (false), - init_nbor(false), - numb_models (0) -{ - get_env_nthreads(num_intra_nthreads, num_inter_nthreads); - init(models, gpu_rank, file_contents); -} - -NNPInterModelDevi::~NNPInterModelDevi() {} - -void -NNPInterModelDevi:: -init (const std::vector & models, const int & gpu_rank, const std::vector & file_contents) -{ - if (inited){ - std::cerr << "WARNING: deepmd-kit should not be initialized twice, do nothing at the second call of initializer" << std::endl; - return ; - } - numb_models = models.size(); - sessions.resize(numb_models); - graph_defs.resize(numb_models); +// // NNPInterModelDevi:: +// // NNPInterModelDevi () +// // : inited (false), +// // init_nbor (false), +// // numb_models (0) +// // { +// // get_env_nthreads(num_intra_nthreads, num_inter_nthreads); +// // } + +// // NNPInterModelDevi:: +// // NNPInterModelDevi (const std::vector & models, const int & gpu_rank, const std::vector & file_contents) +// // : inited (false), +// // init_nbor(false), +// // numb_models (0) +// // { +// // get_env_nthreads(num_intra_nthreads, num_inter_nthreads); +// // init(models, gpu_rank, file_contents); +// // } + +// // NNPInterModelDevi::~NNPInterModelDevi() {} + +// // void +// // NNPInterModelDevi:: +// // init (const std::vector & models, const int & gpu_rank, const std::vector & file_contents) +// // { +// // if (inited){ +// // std::cerr << "WARNING: deepmd-kit should not be initialized twice, do nothing at the second call of initializer" << std::endl; +// // return ; +// // } +// // numb_models = models.size(); +// // sessions.resize(numb_models); +// // graph_defs.resize(numb_models); - int gpu_num = -1; - #if GOOGLE_CUDA - cudaGetDeviceCount(&gpu_num); - #endif // GOOGLE_CUDA - - SessionOptions options; - options.config.set_inter_op_parallelism_threads(num_inter_nthreads); - options.config.set_intra_op_parallelism_threads(num_intra_nthreads); - for (unsigned ii = 0; ii < numb_models; ++ii){ - if (file_contents.size() == 0) - checkStatus (ReadBinaryProto(Env::Default(), models[ii], &graph_defs[ii])); - else - graph_defs[ii].ParseFromString(file_contents[ii]); - } - #if GOOGLE_CUDA - if (gpu_num > 0) { - options.config.set_allow_soft_placement(true); - options.config.mutable_gpu_options()->set_per_process_gpu_memory_fraction(0.9); - options.config.mutable_gpu_options()->set_allow_growth(true); - cudaErrcheck(cudaSetDevice(gpu_rank % gpu_num)); - } - #endif // GOOGLE_CUDA - - for (unsigned ii = 0; ii < numb_models; ++ii) { - if (gpu_num > 0) { - std::string str = "/gpu:"; - str += std::to_string(gpu_rank % gpu_num); - graph::SetDefaultDevice(str, &graph_defs[ii]); - } - checkStatus (NewSession(options, &(sessions[ii]))); - checkStatus (sessions[ii]->Create(graph_defs[ii])); - } - rcut = get_scalar("descrpt_attr/rcut"); - cell_size = rcut; - ntypes = get_scalar("descrpt_attr/ntypes"); - dfparam = get_scalar("fitting_attr/dfparam"); - daparam = get_scalar("fitting_attr/daparam"); - if (dfparam < 0) dfparam = 0; - if (daparam < 0) daparam = 0; - // rcut = get_rcut(); - // cell_size = rcut; - // ntypes = get_ntypes(); - inited = true; +// // int gpu_num = -1; +// // #if GOOGLE_CUDA +// // cudaGetDeviceCount(&gpu_num); +// // #endif // GOOGLE_CUDA + +// // SessionOptions options; +// // options.config.set_inter_op_parallelism_threads(num_inter_nthreads); +// // options.config.set_intra_op_parallelism_threads(num_intra_nthreads); +// // for (unsigned ii = 0; ii < numb_models; ++ii){ +// // if (file_contents.size() == 0) +// // checkStatus (ReadBinaryProto(Env::Default(), models[ii], &graph_defs[ii])); +// // else +// // graph_defs[ii].ParseFromString(file_contents[ii]); +// // } +// // #if GOOGLE_CUDA +// // if (gpu_num > 0) { +// // options.config.set_allow_soft_placement(true); +// // options.config.mutable_gpu_options()->set_per_process_gpu_memory_fraction(0.9); +// // options.config.mutable_gpu_options()->set_allow_growth(true); +// // cudaErrcheck(cudaSetDevice(gpu_rank % gpu_num)); +// // } +// // #endif // GOOGLE_CUDA + +// // for (unsigned ii = 0; ii < numb_models; ++ii) { +// // if (gpu_num > 0) { +// // std::string str = "/gpu:"; +// // str += std::to_string(gpu_rank % gpu_num); +// // graph::SetDefaultDevice(str, &graph_defs[ii]); +// // } +// // checkStatus (NewSession(options, &(sessions[ii]))); +// // checkStatus (sessions[ii]->Create(graph_defs[ii])); +// // } +// // rcut = get_scalar("descrpt_attr/rcut"); +// // cell_size = rcut; +// // ntypes = get_scalar("descrpt_attr/ntypes"); +// // dfparam = get_scalar("fitting_attr/dfparam"); +// // daparam = get_scalar("fitting_attr/daparam"); +// // if (dfparam < 0) dfparam = 0; +// // if (daparam < 0) daparam = 0; +// // // rcut = get_rcut(); +// // // cell_size = rcut; +// // // ntypes = get_ntypes(); +// // inited = true; - init_nbor = false; - ilist = NULL; jrange = NULL; jlist = NULL; - ilist_size = 0; jrange_size = 0; jlist_size = 0; -} - -template -VT -NNPInterModelDevi:: -get_scalar(const std::string name) const -{ - VT myrcut = 0; - for (unsigned ii = 0; ii < numb_models; ++ii){ - VT ret = session_get_scalar(sessions[ii], name); - if (ii == 0){ - myrcut = ret; - } - else { - assert (myrcut == ret); - } - } - return myrcut; -} - -// init the tmp array data -std::vector > -NNPInterModelDevi:: -get_sel () const -{ - std::vector > sec; - for (int ii = 0; ii < numb_models; ii++) { - std::vector sel; - std::istringstream is(graph_info(graph_defs[ii])); - std::string line = ""; - while(is >> line) { - if (line.find("sel") != line.npos) { - while (std::getline(is, line) && line != "}") { - if (line.find("i:") != line.npos) { - sel.push_back(atoi((line.substr(line.find("i:") + 2)).c_str())); - } - } break; - } - if (line.find("sel_a") != line.npos) { - while (std::getline(is, line) && line != "}") { - if (line.find("i:") != line.npos) { - sel.push_back(atoi((line.substr(line.find("i:") + 2)).c_str())); - } - } break; - } - } - sec.push_back(sel); - } - return sec; -} - -void -NNPInterModelDevi:: -cum_sum (const std::vector > n_sel) -{ - for (int ii = 0; ii < numb_models; ++ii) { - std::vector _sec; - _sec.resize (n_sel[ii].size() + 1); - _sec[0] = 0; - for (int jj = 1; jj < _sec.size(); ++jj) { - _sec[jj] = _sec[jj-1] + n_sel[ii][jj-1]; - } - sec.push_back(_sec); - } -} - -void -NNPInterModelDevi:: -validate_fparam_aparam(const int & nloc, - const std::vector &fparam, - const std::vector &aparam)const -{ - if (fparam.size() != dfparam) { - throw std::runtime_error("the dim of frame parameter provided is not consistent with what the model uses"); - } - if (aparam.size() != daparam * nloc) { - throw std::runtime_error("the dim of atom parameter provided is not consistent with what the model uses"); - } -} - -void -NNPInterModelDevi:: -compute (ENERGYTYPE & dener, - std::vector & dforce_, - std::vector & dvirial, - std::vector & model_devi, - const std::vector & dcoord_, - const std::vector & datype_, - const std::vector & dbox, - const std::vector & fparam, - const std::vector & aparam) -{ - if (numb_models == 0) return; - - nnpmap = NNPAtomMap (datype_.begin(), datype_.end()); - validate_fparam_aparam(nnpmap.get_type().size(), fparam, aparam); - - std::vector> input_tensors; - int nloc = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, fparam, aparam, nnpmap); - - std::vector all_energy (numb_models); - std::vector > all_force (numb_models); - std::vector > all_virial (numb_models); - - for (unsigned ii = 0; ii < numb_models; ++ii){ - run_model (all_energy[ii], all_force[ii], all_virial[ii], sessions[ii], input_tensors, nnpmap); - } - - dener = 0; - for (unsigned ii = 0; ii < numb_models; ++ii){ - dener += all_energy[ii]; - } - dener /= VALUETYPE(numb_models); - compute_avg (dvirial, all_virial); - compute_avg (dforce_, all_force); +// // init_nbor = false; +// // ilist = NULL; jrange = NULL; jlist = NULL; +// // ilist_size = 0; jrange_size = 0; jlist_size = 0; +// // } + +// // template +// // VT +// // NNPInterModelDevi:: +// // get_scalar(const std::string name) const +// // { +// // VT myrcut = 0; +// // for (unsigned ii = 0; ii < numb_models; ++ii){ +// // VT ret = session_get_scalar(sessions[ii], name); +// // if (ii == 0){ +// // myrcut = ret; +// // } +// // else { +// // assert (myrcut == ret); +// // } +// // } +// // return myrcut; +// // } + +// // // init the tmp array data +// // std::vector > +// // NNPInterModelDevi:: +// // get_sel () const +// // { +// // std::vector > sec; +// // for (int ii = 0; ii < numb_models; ii++) { +// // std::vector sel; +// // std::istringstream is(graph_info(graph_defs[ii])); +// // std::string line = ""; +// // while(is >> line) { +// // if (line.find("sel") != line.npos) { +// // while (std::getline(is, line) && line != "}") { +// // if (line.find("i:") != line.npos) { +// // sel.push_back(atoi((line.substr(line.find("i:") + 2)).c_str())); +// // } +// // } break; +// // } +// // if (line.find("sel_a") != line.npos) { +// // while (std::getline(is, line) && line != "}") { +// // if (line.find("i:") != line.npos) { +// // sel.push_back(atoi((line.substr(line.find("i:") + 2)).c_str())); +// // } +// // } break; +// // } +// // } +// // sec.push_back(sel); +// // } +// // return sec; +// // } + +// // void +// // NNPInterModelDevi:: +// // cum_sum (const std::vector > n_sel) +// // { +// // for (int ii = 0; ii < numb_models; ++ii) { +// // std::vector _sec; +// // _sec.resize (n_sel[ii].size() + 1); +// // _sec[0] = 0; +// // for (int jj = 1; jj < _sec.size(); ++jj) { +// // _sec[jj] = _sec[jj-1] + n_sel[ii][jj-1]; +// // } +// // sec.push_back(_sec); +// // } +// // } + +// // void +// // NNPInterModelDevi:: +// // validate_fparam_aparam(const int & nloc, +// // const std::vector &fparam, +// // const std::vector &aparam)const +// // { +// // if (fparam.size() != dfparam) { +// // throw std::runtime_error("the dim of frame parameter provided is not consistent with what the model uses"); +// // } +// // if (aparam.size() != daparam * nloc) { +// // throw std::runtime_error("the dim of atom parameter provided is not consistent with what the model uses"); +// // } +// // } + +// // void +// // NNPInterModelDevi:: +// // compute (ENERGYTYPE & dener, +// // std::vector & dforce_, +// // std::vector & dvirial, +// // std::vector & model_devi, +// // const std::vector & dcoord_, +// // const std::vector & datype_, +// // const std::vector & dbox, +// // const std::vector & fparam, +// // const std::vector & aparam) +// // { +// // if (numb_models == 0) return; + +// // nnpmap = NNPAtomMap (datype_.begin(), datype_.end()); +// // validate_fparam_aparam(nnpmap.get_type().size(), fparam, aparam); + +// // std::vector> input_tensors; +// // int nloc = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, fparam, aparam, nnpmap); + +// // std::vector all_energy (numb_models); +// // std::vector > all_force (numb_models); +// // std::vector > all_virial (numb_models); + +// // for (unsigned ii = 0; ii < numb_models; ++ii){ +// // run_model (all_energy[ii], all_force[ii], all_virial[ii], sessions[ii], input_tensors, nnpmap); +// // } + +// // dener = 0; +// // for (unsigned ii = 0; ii < numb_models; ++ii){ +// // dener += all_energy[ii]; +// // } +// // dener /= VALUETYPE(numb_models); +// // compute_avg (dvirial, all_virial); +// // compute_avg (dforce_, all_force); - compute_std_f (model_devi, dforce_, all_force); +// // compute_std_f (model_devi, dforce_, all_force); - // for (unsigned ii = 0; ii < numb_models; ++ii){ - // cout << all_force[ii][573] << " " << all_force[ii][574] << " " << all_force[ii][575] << endl; - // } - // cout << dforce_[573] << " " - // << dforce_[574] << " " - // << dforce_[575] << " " - // << model_devi[191] << endl; -} - -void -NNPInterModelDevi:: -compute (std::vector & all_energy, - std::vector> & all_force, - std::vector> & all_virial, - const std::vector & dcoord_, - const std::vector & datype_, - const std::vector & dbox, - const int nghost, - const LammpsNeighborList & lmp_list, - const int & ago, - const std::vector & fparam, - const std::vector & aparam) -{ - if (numb_models == 0) return; - int nall = dcoord_.size() / 3; - int nloc = nall - nghost; - validate_fparam_aparam(nloc, fparam, aparam); - std::vector> input_tensors; - - // agp == 0 means that the LAMMPS nbor list has been updated - if (ago == 0) { - nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); - assert (nloc == nnpmap.get_type().size()); - - // InternalNeighborList nlist; - convert_nlist_lmp_internal (nlist, lmp_list); - shuffle_nlist (nlist, nnpmap); - } - int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, nnpmap, nghost, ago); - - all_energy.resize (numb_models); - all_force.resize (numb_models); - all_virial.resize (numb_models); - assert (nloc == ret); - for (unsigned ii = 0; ii < numb_models; ++ii) { - run_model (all_energy[ii], all_force[ii], all_virial[ii], sessions[ii], input_tensors, nnpmap, nghost); - } -} - -void -NNPInterModelDevi:: -compute (std::vector & all_energy, - std::vector> & all_force, - std::vector> & all_virial, - std::vector> & all_atom_energy, - std::vector> & all_atom_virial, - const std::vector & dcoord_, - const std::vector & datype_, - const std::vector & dbox, - const int nghost, - const LammpsNeighborList & lmp_list, - const int & ago, - const std::vector & fparam, - const std::vector & aparam) -{ - if (numb_models == 0) return; - int nall = dcoord_.size() / 3; - int nloc = nall - nghost; - validate_fparam_aparam(nloc, fparam, aparam); - std::vector> input_tensors; - - // agp == 0 means that the LAMMPS nbor list has been updated - if (ago == 0) { - nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); - assert (nloc == nnpmap.get_type().size()); - - // InternalNeighborList nlist; - convert_nlist_lmp_internal (nlist, lmp_list); - shuffle_nlist (nlist, nnpmap); - } - int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, nnpmap, nghost, ago); - - all_energy.resize (numb_models); - all_force .resize (numb_models); - all_virial.resize (numb_models); - all_atom_energy.resize (numb_models); - all_atom_virial.resize (numb_models); - assert (nloc == ret); - for (unsigned ii = 0; ii < numb_models; ++ii) { - run_model (all_energy[ii], all_force[ii], all_virial[ii], all_atom_energy[ii], all_atom_virial[ii], sessions[ii], input_tensors, nnpmap, nghost); - } -} - -void -NNPInterModelDevi:: -compute_avg (VALUETYPE & dener, - const std::vector & all_energy) -{ - assert (all_energy.size() == numb_models); - if (numb_models == 0) return; - - dener = 0; - for (unsigned ii = 0; ii < numb_models; ++ii){ - dener += all_energy[ii]; - } - dener /= (VALUETYPE)(numb_models); -} - -#ifndef HIGH_PREC -void -NNPInterModelDevi:: -compute_avg (ENERGYTYPE & dener, - const std::vector& all_energy) -{ - assert (all_energy.size() == numb_models); - if (numb_models == 0) return; - - dener = 0; - for (unsigned ii = 0; ii < numb_models; ++ii){ - dener += all_energy[ii]; - } - dener /= (ENERGYTYPE)(numb_models); -} -#endif - -void -NNPInterModelDevi:: -compute_avg (std::vector & avg, - const std::vector > & xx) -{ - assert (xx.size() == numb_models); - if (numb_models == 0) return; +// // // for (unsigned ii = 0; ii < numb_models; ++ii){ +// // // cout << all_force[ii][573] << " " << all_force[ii][574] << " " << all_force[ii][575] << endl; +// // // } +// // // cout << dforce_[573] << " " +// // // << dforce_[574] << " " +// // // << dforce_[575] << " " +// // // << model_devi[191] << endl; +// // } + +// // void +// // NNPInterModelDevi:: +// // compute (std::vector & all_energy, +// // std::vector> & all_force, +// // std::vector> & all_virial, +// // const std::vector & dcoord_, +// // const std::vector & datype_, +// // const std::vector & dbox, +// // const int nghost, +// // const LammpsNeighborList & lmp_list, +// // const int & ago, +// // const std::vector & fparam, +// // const std::vector & aparam) +// // { +// // if (numb_models == 0) return; +// // int nall = dcoord_.size() / 3; +// // int nloc = nall - nghost; +// // validate_fparam_aparam(nloc, fparam, aparam); +// // std::vector> input_tensors; + +// // // agp == 0 means that the LAMMPS nbor list has been updated +// // if (ago == 0) { +// // nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); +// // assert (nloc == nnpmap.get_type().size()); + +// // // InternalNeighborList nlist; +// // convert_nlist_lmp_internal (nlist, lmp_list); +// // shuffle_nlist (nlist, nnpmap); +// // } +// // int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, nnpmap, nghost, ago); + +// // all_energy.resize (numb_models); +// // all_force.resize (numb_models); +// // all_virial.resize (numb_models); +// // assert (nloc == ret); +// // for (unsigned ii = 0; ii < numb_models; ++ii) { +// // run_model (all_energy[ii], all_force[ii], all_virial[ii], sessions[ii], input_tensors, nnpmap, nghost); +// // } +// // } + +// // void +// // NNPInterModelDevi:: +// // compute (std::vector & all_energy, +// // std::vector> & all_force, +// // std::vector> & all_virial, +// // std::vector> & all_atom_energy, +// // std::vector> & all_atom_virial, +// // const std::vector & dcoord_, +// // const std::vector & datype_, +// // const std::vector & dbox, +// // const int nghost, +// // const LammpsNeighborList & lmp_list, +// // const int & ago, +// // const std::vector & fparam, +// // const std::vector & aparam) +// // { +// // if (numb_models == 0) return; +// // int nall = dcoord_.size() / 3; +// // int nloc = nall - nghost; +// // validate_fparam_aparam(nloc, fparam, aparam); +// // std::vector> input_tensors; + +// // // agp == 0 means that the LAMMPS nbor list has been updated +// // if (ago == 0) { +// // nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); +// // assert (nloc == nnpmap.get_type().size()); + +// // // InternalNeighborList nlist; +// // convert_nlist_lmp_internal (nlist, lmp_list); +// // shuffle_nlist (nlist, nnpmap); +// // } +// // int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, nnpmap, nghost, ago); + +// // all_energy.resize (numb_models); +// // all_force .resize (numb_models); +// // all_virial.resize (numb_models); +// // all_atom_energy.resize (numb_models); +// // all_atom_virial.resize (numb_models); +// // assert (nloc == ret); +// // for (unsigned ii = 0; ii < numb_models; ++ii) { +// // run_model (all_energy[ii], all_force[ii], all_virial[ii], all_atom_energy[ii], all_atom_virial[ii], sessions[ii], input_tensors, nnpmap, nghost); +// // } +// // } + +// // void +// // NNPInterModelDevi:: +// // compute_avg (VALUETYPE & dener, +// // const std::vector & all_energy) +// // { +// // assert (all_energy.size() == numb_models); +// // if (numb_models == 0) return; + +// // dener = 0; +// // for (unsigned ii = 0; ii < numb_models; ++ii){ +// // dener += all_energy[ii]; +// // } +// // dener /= (VALUETYPE)(numb_models); +// // } + +// // #ifndef HIGH_PREC +// // void +// // NNPInterModelDevi:: +// // compute_avg (ENERGYTYPE & dener, +// // const std::vector& all_energy) +// // { +// // assert (all_energy.size() == numb_models); +// // if (numb_models == 0) return; + +// // dener = 0; +// // for (unsigned ii = 0; ii < numb_models; ++ii){ +// // dener += all_energy[ii]; +// // } +// // dener /= (ENERGYTYPE)(numb_models); +// // } +// // #endif + +// // void +// // NNPInterModelDevi:: +// // compute_avg (std::vector & avg, +// // const std::vector > & xx) +// // { +// // assert (xx.size() == numb_models); +// // if (numb_models == 0) return; - avg.resize(xx[0].size()); - fill (avg.begin(), avg.end(), VALUETYPE(0.)); +// // avg.resize(xx[0].size()); +// // fill (avg.begin(), avg.end(), VALUETYPE(0.)); - for (unsigned ii = 0; ii < numb_models; ++ii){ - for (unsigned jj = 0; jj < avg.size(); ++jj){ - avg[jj] += xx[ii][jj]; - } - } - - for (unsigned jj = 0; jj < avg.size(); ++jj){ - avg[jj] /= VALUETYPE(numb_models); - } -} +// // for (unsigned ii = 0; ii < numb_models; ++ii){ +// // for (unsigned jj = 0; jj < avg.size(); ++jj){ +// // avg[jj] += xx[ii][jj]; +// // } +// // } + +// // for (unsigned jj = 0; jj < avg.size(); ++jj){ +// // avg[jj] /= VALUETYPE(numb_models); +// // } +// // } + + +// // // void +// // // NNPInterModelDevi:: +// // // compute_std (VALUETYPE & std, +// // // const VALUETYPE & avg, +// // // const vector& xx) +// // // { +// // // std = 0; +// // // assert(xx.size() == numb_models); +// // // for (unsigned jj = 0; jj < xx.size(); ++jj){ +// // // std += (xx[jj] - avg) * (xx[jj] - avg); +// // // } +// // // std = sqrt(std / VALUETYPE(numb_models)); +// // // // std = sqrt(std / VALUETYPE(numb_models-)); +// // // } + +// // void +// // NNPInterModelDevi:: +// // compute_std_e (std::vector & std, +// // const std::vector & avg, +// // const std::vector >&xx) +// // { +// // assert (xx.size() == numb_models); +// // if (numb_models == 0) return; + +// // unsigned ndof = avg.size(); +// // unsigned nloc = ndof; +// // assert (nloc == ndof); + +// // std.resize(nloc); +// // fill (std.begin(), std.end(), VALUETYPE(0.)); + +// // for (unsigned ii = 0; ii < numb_models; ++ii) { +// // for (unsigned jj = 0 ; jj < nloc; ++jj){ +// // const VALUETYPE * tmp_f = &(xx[ii][jj]); +// // const VALUETYPE * tmp_avg = &(avg[jj]); +// // VALUETYPE vdiff = xx[ii][jj] - avg[jj]; +// // std[jj] += vdiff * vdiff; +// // } +// // } + +// // for (unsigned jj = 0; jj < nloc; ++jj){ +// // std[jj] = sqrt(std[jj] / VALUETYPE(numb_models)); +// // // std[jj] = sqrt(std[jj] / VALUETYPE(numb_models-1)); +// // } +// // } + +// // void +// // NNPInterModelDevi:: +// // compute_std_f (std::vector & std, +// // const std::vector & avg, +// // const std::vector >&xx) +// // { +// // assert (xx.size() == numb_models); +// // if (numb_models == 0) return; + +// // unsigned ndof = avg.size(); +// // unsigned nloc = ndof / 3; +// // assert (nloc * 3 == ndof); + +// // std.resize(nloc); +// // fill (std.begin(), std.end(), VALUETYPE(0.)); + +// // for (unsigned ii = 0; ii < numb_models; ++ii) { +// for (unsigned jj = 0 ; jj < nloc; ++jj){ +// const VALUETYPE * tmp_f = &(xx[ii][jj*3]); +// const VALUETYPE * tmp_avg = &(avg[jj*3]); +// VALUETYPE vdiff[3]; +// vdiff[0] = tmp_f[0] - tmp_avg[0]; +// vdiff[1] = tmp_f[1] - tmp_avg[1]; +// vdiff[2] = tmp_f[2] - tmp_avg[2]; +// std[jj] += dot3(vdiff, vdiff); +// } +// } +// for (unsigned jj = 0; jj < nloc; ++jj){ +// std[jj] = sqrt(std[jj] / VALUETYPE(numb_models)); +// // std[jj] = sqrt(std[jj] / VALUETYPE(numb_models-1)); +// } +// } // void // NNPInterModelDevi:: -// compute_std (VALUETYPE & std, -// const VALUETYPE & avg, -// const vector& xx) +// compute_relative_std_f (std::vector &std, +// const std::vector &avg, +// const VALUETYPE eps) // { -// std = 0; -// assert(xx.size() == numb_models); -// for (unsigned jj = 0; jj < xx.size(); ++jj){ -// std += (xx[jj] - avg) * (xx[jj] - avg); +// unsigned nloc = std.size(); +// for (unsigned ii = 0; ii < nloc; ++ii){ +// const VALUETYPE * tmp_avg = &(avg[ii*3]); +// VALUETYPE vdiff[3]; +// vdiff[0] = tmp_avg[0]; +// vdiff[1] = tmp_avg[1]; +// vdiff[2] = tmp_avg[2]; +// VALUETYPE f_norm = sqrt(dot3(vdiff, vdiff)); +// // relative std = std/(abs(f)+eps) +// std[ii] /= f_norm + eps; // } -// std = sqrt(std / VALUETYPE(numb_models)); -// // std = sqrt(std / VALUETYPE(numb_models-)); // } -void -NNPInterModelDevi:: -compute_std_e (std::vector & std, - const std::vector & avg, - const std::vector >&xx) -{ - assert (xx.size() == numb_models); - if (numb_models == 0) return; - - unsigned ndof = avg.size(); - unsigned nloc = ndof; - assert (nloc == ndof); - - std.resize(nloc); - fill (std.begin(), std.end(), VALUETYPE(0.)); - - for (unsigned ii = 0; ii < numb_models; ++ii) { - for (unsigned jj = 0 ; jj < nloc; ++jj){ - const VALUETYPE * tmp_f = &(xx[ii][jj]); - const VALUETYPE * tmp_avg = &(avg[jj]); - VALUETYPE vdiff = xx[ii][jj] - avg[jj]; - std[jj] += vdiff * vdiff; - } - } - - for (unsigned jj = 0; jj < nloc; ++jj){ - std[jj] = sqrt(std[jj] / VALUETYPE(numb_models)); - // std[jj] = sqrt(std[jj] / VALUETYPE(numb_models-1)); - } -} - -void -NNPInterModelDevi:: -compute_std_f (std::vector & std, - const std::vector & avg, - const std::vector >&xx) -{ - assert (xx.size() == numb_models); - if (numb_models == 0) return; - - unsigned ndof = avg.size(); - unsigned nloc = ndof / 3; - assert (nloc * 3 == ndof); - - std.resize(nloc); - fill (std.begin(), std.end(), VALUETYPE(0.)); - - for (unsigned ii = 0; ii < numb_models; ++ii) { - for (unsigned jj = 0 ; jj < nloc; ++jj){ - const VALUETYPE * tmp_f = &(xx[ii][jj*3]); - const VALUETYPE * tmp_avg = &(avg[jj*3]); - VALUETYPE vdiff[3]; - vdiff[0] = tmp_f[0] - tmp_avg[0]; - vdiff[1] = tmp_f[1] - tmp_avg[1]; - vdiff[2] = tmp_f[2] - tmp_avg[2]; - std[jj] += dot3(vdiff, vdiff); - } - } - - for (unsigned jj = 0; jj < nloc; ++jj){ - std[jj] = sqrt(std[jj] / VALUETYPE(numb_models)); - // std[jj] = sqrt(std[jj] / VALUETYPE(numb_models-1)); - } -} - -void -NNPInterModelDevi:: -compute_relative_std_f (std::vector &std, - const std::vector &avg, - const VALUETYPE eps) -{ - unsigned nloc = std.size(); - for (unsigned ii = 0; ii < nloc; ++ii){ - const VALUETYPE * tmp_avg = &(avg[ii*3]); - VALUETYPE vdiff[3]; - vdiff[0] = tmp_avg[0]; - vdiff[1] = tmp_avg[1]; - vdiff[2] = tmp_avg[2]; - VALUETYPE f_norm = sqrt(dot3(vdiff, vdiff)); - // relative std = std/(abs(f)+eps) - std[ii] /= f_norm + eps; - } -} - diff --git a/source/api_cc/src/common.cc b/source/api_cc/src/common.cc index 31981658ee..0bbce93120 100644 --- a/source/api_cc/src/common.cc +++ b/source/api_cc/src/common.cc @@ -60,92 +60,136 @@ select_real_atoms(std::vector & fwd_map, select_by_type(fwd_map, bkw_map, nghost_real, dcoord_, datype_, nghost, sel_type); } + void -convert_nlist_lmp_internal (InternalNeighborList & list, - const LammpsNeighborList & lmp_list) +NeighborListData:: +copy_from_nlist(const InputNlist & inlist) { - list.clear(); - int total_num_nei = 0; - int inum = lmp_list.inum; - for (int ii = 0; ii < inum; ++ii){ - total_num_nei += lmp_list.numneigh[ii]; - } - list.ilist.resize(inum); - list.jrange.resize(inum+1); - list.jlist.resize(total_num_nei); - memcpy(&list.ilist[0], lmp_list.ilist, inum*sizeof(int)); - list.jrange[0] = 0; - for (int ii = 0; ii < inum; ++ii){ - int jnum = lmp_list.numneigh[ii]; - list.jrange[ii+1] = list.jrange[ii] + jnum; - const int * jlist = lmp_list.firstneigh[ii]; - memcpy(&(list.jlist[list.jrange[ii]]), jlist, jnum*sizeof(int)); + int inum = inlist.inum; + ilist.resize(inum); + jlist.resize(inum); + memcpy(&ilist[0], inlist.ilist, inum*sizeof(int)); + for(int ii = 0; ii < inum; ++ii){ + int jnum = inlist.numneigh[ii]; + jlist[ii].resize(jnum); + memcpy(&jlist[ii][0], inlist.firstneigh[ii], jnum*sizeof(int)); } } + void -shuffle_nlist (InternalNeighborList & list, - const NNPAtomMap & map) +NeighborListData:: +shuffle(const NNPAtomMap & map) { const std::vector & fwd_map = map.get_fwd_map(); - shuffle_nlist(list, fwd_map); + shuffle(fwd_map); } void -shuffle_nlist (InternalNeighborList & list, - const std::vector & fwd_map) +NeighborListData:: +shuffle(const std::vector & fwd_map) { int nloc = fwd_map.size(); - for (unsigned ii = 0; ii < list.ilist.size(); ++ii){ - if (list.ilist[ii] < nloc) { - list.ilist[ii] = fwd_map[list.ilist[ii]]; + for(unsigned ii = 0; ii < ilist.size(); ++ii){ + if(ilist[ii] < nloc){ + ilist[ii] = fwd_map[ilist[ii]]; } } - for (unsigned ii = 0; ii < list.jlist.size(); ++ii){ - if (list.jlist[ii] < nloc) { - list.jlist[ii] = fwd_map[list.jlist[ii]]; + for(unsigned ii = 0; ii < jlist.size(); ++ii){ + for(unsigned jj = 0; jj < jlist[ii].size(); ++jj){ + if(jlist[ii][jj] < nloc){ + jlist[ii][jj] = fwd_map[jlist[ii][jj]]; + } } } } void -shuffle_nlist_exclude_empty (InternalNeighborList & list, - const std::vector & fwd_map) +NeighborListData:: +shuffle_exclude_empty (const std::vector & fwd_map) { - int old_nloc = fwd_map.size(); - shuffle_nlist(list, fwd_map); - std::vector new_ilist, new_jrange, new_jlist, new_icount; - new_ilist.reserve(list.ilist.size()); - new_icount.reserve(list.ilist.size()); - new_jrange.reserve(list.jrange.size()); - new_jlist.reserve(list.jlist.size()); - for(int ii = 0; ii < list.ilist.size(); ++ii){ - if(list.ilist[ii] >= 0){ - new_ilist.push_back(list.ilist[ii]); + shuffle(fwd_map); + std::vector new_ilist; + std::vector > new_jlist; + new_ilist.reserve(ilist.size()); + new_jlist.reserve(jlist.size()); + for(int ii = 0; ii < ilist.size(); ++ii){ + if(ilist[ii] >= 0){ + new_ilist.push_back(ilist[ii]); } } - new_jrange.resize(new_ilist.size()+1); - new_jrange[0] = 0; - int ci = 0; - for(int ii = 0; ii < list.ilist.size(); ++ii){ - if (list.ilist[ii] < 0) continue; - int js = list.jrange[ii]; - int je = list.jrange[ii+1]; - int cc = 0; - for (int jj = js; jj < je; ++jj){ - if (list.jlist[jj] >= 0) { - new_jlist.push_back(list.jlist[jj]); - cc++; - } + int new_inum = new_ilist.size(); + for(int ii = 0; ii < jlist.size(); ++ii){ + if(ilist[ii] >= 0){ + std::vector tmp_jlist; + tmp_jlist.reserve(jlist[ii].size()); + for(int jj = 0; jj < jlist[ii].size(); ++jj){ + if(jlist[ii][jj] >= 0){ + tmp_jlist.push_back(jlist[ii][jj]); + } + } + new_jlist.push_back(tmp_jlist); } - new_jrange[ci+1] = new_jrange[ci] + cc; - ci ++; } - list.ilist = new_ilist; - list.jrange = new_jrange; - list.jlist = new_jlist; + ilist = new_ilist; + jlist = new_jlist; +} + +void +NeighborListData:: +make_inlist(InputNlist & inlist) +{ + int nloc = ilist.size(); + numneigh.resize(nloc); + firstneigh.resize(nloc); + for(int ii = 0; ii < nloc; ++ii){ + numneigh[ii] = jlist[ii].size(); + firstneigh[ii] = &jlist[ii][0]; + } + inlist.inum = nloc; + inlist.ilist = &ilist[0]; + inlist.numneigh = &numneigh[0]; + inlist.firstneigh = &firstneigh[0]; } +// void +// shuffle_nlist_exclude_empty (InternalNeighborList & list, +// const std::vector & fwd_map) +// { +// int old_nloc = fwd_map.size(); +// shuffle_nlist(list, fwd_map); +// std::vector new_ilist, new_jrange, new_jlist, new_icount; +// new_ilist.reserve(list.ilist.size()); +// new_icount.reserve(list.ilist.size()); +// new_jrange.reserve(list.jrange.size()); +// new_jlist.reserve(list.jlist.size()); +// for(int ii = 0; ii < list.ilist.size(); ++ii){ +// if(list.ilist[ii] >= 0){ +// new_ilist.push_back(list.ilist[ii]); +// } +// } +// new_jrange.resize(new_ilist.size()+1); +// new_jrange[0] = 0; +// int ci = 0; +// for(int ii = 0; ii < list.ilist.size(); ++ii){ +// if (list.ilist[ii] < 0) continue; +// int js = list.jrange[ii]; +// int je = list.jrange[ii+1]; +// int cc = 0; +// for (int jj = js; jj < je; ++jj){ +// if (list.jlist[jj] >= 0) { +// new_jlist.push_back(list.jlist[jj]); +// cc++; +// } +// } +// new_jrange[ci+1] = new_jrange[ci] + cc; +// ci ++; +// } +// list.ilist = new_ilist; +// list.jrange = new_jrange; +// list.jlist = new_jlist; +// } + void checkStatus(const tensorflow::Status& status) { if (!status.ok()) { @@ -196,16 +240,13 @@ session_input_tensors (std::vector> & input_tenso const std::vector & fparam_, const std::vector & aparam_, const NNPAtomMap& nnpmap, - const int nghost, - const std::string scope) + const std::string scope) { - bool b_ghost = (nghost != 0); - - assert (dbox.size() == 9); + bool b_pbc = (dbox.size() == 9); int nframes = 1; int nall = dcoord_.size() / 3; - int nloc = nall - nghost; + int nloc = nall; assert (nall == datype_.size()); std::vector datype = nnpmap.get_type(); @@ -215,26 +256,6 @@ session_input_tensors (std::vector> & input_tenso } datype.insert (datype.end(), datype_.begin() + nloc, datype_.end()); - SimulationRegion region; - std::vector dbox_(9); - for (int dd = 0; dd < 9; ++dd) dbox_[dd] = dbox[dd]; - region.reinitBox (&dbox_[0]); - double box_l[3]; - region.toFaceDistance (box_l); - - std::vector ncell (3, 2); - for (int dd = 0; dd < 3; ++dd){ - ncell[dd] = box_l[dd] / cell_size; - if (ncell[dd] < 2) ncell[dd] = 2; - } - std::vector next(3, 0); - for (int dd = 0; dd < 3; ++dd){ - double cellh = box_l[dd] / ncell[dd]; - next[dd] = cellh / cell_size; - if (next[dd] * cellh < cell_size) next[dd]++; - assert (next[dd] * cellh >= cell_size); - } - TensorShape coord_shape ; coord_shape.AddDim (nframes); coord_shape.AddDim (nall * 3); @@ -245,11 +266,11 @@ session_input_tensors (std::vector> & input_tenso box_shape.AddDim (nframes); box_shape.AddDim (9); TensorShape mesh_shape ; - if (!b_ghost){ - mesh_shape.AddDim (6); + if (b_pbc){ + mesh_shape.AddDim(6); } else { - mesh_shape.AddDim (12); + mesh_shape.AddDim(0); } TensorShape natoms_shape ; natoms_shape.AddDim (2 + ntypes); @@ -290,8 +311,15 @@ session_input_tensors (std::vector> & input_tenso for (int jj = 0; jj < nall * 3; ++jj){ coord(ii, jj) = dcoord[jj]; } - for (int jj = 0; jj < 9; ++jj){ - box(ii, jj) = dbox[jj]; + if(b_pbc){ + for (int jj = 0; jj < 9; ++jj){ + box(ii, jj) = dbox[jj]; + } + } + else{ + for (int jj = 0; jj < 9; ++jj){ + box(ii, jj) = 0.; + } } for (int jj = 0; jj < nall; ++jj){ type(ii, jj) = datype[jj]; @@ -303,19 +331,13 @@ session_input_tensors (std::vector> & input_tenso aparam(ii, jj) = aparam_[jj]; } } - mesh (1-1) = 0; - mesh (2-1) = 0; - mesh (3-1) = 0; - mesh (4-1) = ncell[0]; - mesh (5-1) = ncell[1]; - mesh (6-1) = ncell[2]; - if (b_ghost){ - mesh(7-1) = -next[0]; - mesh(8-1) = -next[1]; - mesh(9-1) = -next[2]; - mesh(10-1) = ncell[0] + next[0]; - mesh(11-1) = ncell[1] + next[1]; - mesh(12-1) = ncell[2] + next[2]; + if (b_pbc){ + mesh (1-1) = 0; + mesh (2-1) = 0; + mesh (3-1) = 0; + mesh (4-1) = 0; + mesh (5-1) = 0; + mesh (6-1) = 0; } natoms (0) = nloc; natoms (1) = nall; @@ -347,7 +369,7 @@ session_input_tensors (std::vector> & input_tenso const int & ntypes, const std::vector & datype_, const std::vector & dbox, - InternalNeighborList & dlist, + InputNlist & dlist, const std::vector & fparam_, const std::vector & aparam_, const NNPAtomMap& nnpmap, @@ -439,13 +461,12 @@ session_input_tensors (std::vector> & input_tenso assert (stride * sizeof(int) == sizeof(int *)); assert (stride <= 4); mesh (0) = ago; - mesh (1) = dlist.ilist.size(); - mesh (2) = dlist.jrange.size(); - mesh (3) = dlist.jlist.size(); - dlist.make_ptrs(); - memcpy (&mesh(4), &(dlist.pilist), sizeof(int *)); - memcpy (&mesh(8), &(dlist.pjrange), sizeof(int *)); - memcpy (&mesh(12), &(dlist.pjlist), sizeof(int *)); + mesh (1) = dlist.inum; + mesh (2) = 0; + mesh (3) = 0; + memcpy (&mesh(4), &(dlist.ilist), sizeof(int *)); + memcpy (&mesh(8), &(dlist.numneigh), sizeof(int *)); + memcpy (&mesh(12), &(dlist.firstneigh), sizeof(int **)); natoms (0) = nloc; natoms (1) = nall; @@ -471,257 +492,257 @@ session_input_tensors (std::vector> & input_tenso return nloc; } -int -session_input_tensors (std::vector> & input_tensors, - const std::vector & dcoord_, - const int & ntypes, - const std::vector & datype_, - const std::vector & dbox, - InternalNeighborList & dlist, - const std::vector & fparam_, - const std::vector & aparam_, - const NNPAtomMap& nnpmap, - const int nghost, - const std::string scope) -{ - assert (dbox.size() == 9); - - int nframes = 1; - int nall = dcoord_.size() / 3; - int nloc = nall - nghost; - assert (nall == datype_.size()); - - std::vector datype = nnpmap.get_type(); - std::vector type_count (ntypes, 0); - for (unsigned ii = 0; ii < datype.size(); ++ii){ - type_count[datype[ii]] ++; - } - datype.insert (datype.end(), datype_.begin() + nloc, datype_.end()); - - TensorShape coord_shape ; - coord_shape.AddDim (nframes); - coord_shape.AddDim (nall * 3); - TensorShape type_shape ; - type_shape.AddDim (nframes); - type_shape.AddDim (nall); - TensorShape box_shape ; - box_shape.AddDim (nframes); - box_shape.AddDim (9); - TensorShape mesh_shape ; - mesh_shape.AddDim (16); - TensorShape natoms_shape ; - natoms_shape.AddDim (2 + ntypes); - TensorShape fparam_shape ; - fparam_shape.AddDim (nframes); - fparam_shape.AddDim (fparam_.size()); - TensorShape aparam_shape ; - aparam_shape.AddDim (nframes); - aparam_shape.AddDim (aparam_.size()); +// int +// session_input_tensors (std::vector> & input_tensors, +// const std::vector & dcoord_, +// const int & ntypes, +// const std::vector & datype_, +// const std::vector & dbox, +// InternalNeighborList & dlist, +// const std::vector & fparam_, +// const std::vector & aparam_, +// const NNPAtomMap& nnpmap, +// const int nghost, +// const std::string scope) +// { +// assert (dbox.size() == 9); + +// int nframes = 1; +// int nall = dcoord_.size() / 3; +// int nloc = nall - nghost; +// assert (nall == datype_.size()); + +// std::vector datype = nnpmap.get_type(); +// std::vector type_count (ntypes, 0); +// for (unsigned ii = 0; ii < datype.size(); ++ii){ +// type_count[datype[ii]] ++; +// } +// datype.insert (datype.end(), datype_.begin() + nloc, datype_.end()); + +// TensorShape coord_shape ; +// coord_shape.AddDim (nframes); +// coord_shape.AddDim (nall * 3); +// TensorShape type_shape ; +// type_shape.AddDim (nframes); +// type_shape.AddDim (nall); +// TensorShape box_shape ; +// box_shape.AddDim (nframes); +// box_shape.AddDim (9); +// TensorShape mesh_shape ; +// mesh_shape.AddDim (16); +// TensorShape natoms_shape ; +// natoms_shape.AddDim (2 + ntypes); +// TensorShape fparam_shape ; +// fparam_shape.AddDim (nframes); +// fparam_shape.AddDim (fparam_.size()); +// TensorShape aparam_shape ; +// aparam_shape.AddDim (nframes); +// aparam_shape.AddDim (aparam_.size()); -#ifdef HIGH_PREC - Tensor coord_tensor (DT_DOUBLE, coord_shape); - Tensor box_tensor (DT_DOUBLE, box_shape); - Tensor fparam_tensor (DT_DOUBLE, fparam_shape); - Tensor aparam_tensor (DT_DOUBLE, aparam_shape); -#else - Tensor coord_tensor (DT_FLOAT, coord_shape); - Tensor box_tensor (DT_FLOAT, box_shape); - Tensor fparam_tensor (DT_FLOAT, fparam_shape); - Tensor aparam_tensor (DT_FLOAT, aparam_shape); -#endif - Tensor type_tensor (DT_INT32, type_shape); - Tensor mesh_tensor (DT_INT32, mesh_shape); - Tensor natoms_tensor (DT_INT32, natoms_shape); - - auto coord = coord_tensor.matrix (); - auto type = type_tensor.matrix (); - auto box = box_tensor.matrix (); - auto mesh = mesh_tensor.flat (); - auto natoms = natoms_tensor.flat (); - auto fparam = fparam_tensor.matrix (); - auto aparam = aparam_tensor.matrix (); - - std::vector dcoord (dcoord_); - nnpmap.forward (dcoord.begin(), dcoord_.begin(), 3); +// #ifdef HIGH_PREC +// Tensor coord_tensor (DT_DOUBLE, coord_shape); +// Tensor box_tensor (DT_DOUBLE, box_shape); +// Tensor fparam_tensor (DT_DOUBLE, fparam_shape); +// Tensor aparam_tensor (DT_DOUBLE, aparam_shape); +// #else +// Tensor coord_tensor (DT_FLOAT, coord_shape); +// Tensor box_tensor (DT_FLOAT, box_shape); +// Tensor fparam_tensor (DT_FLOAT, fparam_shape); +// Tensor aparam_tensor (DT_FLOAT, aparam_shape); +// #endif +// Tensor type_tensor (DT_INT32, type_shape); +// Tensor mesh_tensor (DT_INT32, mesh_shape); +// Tensor natoms_tensor (DT_INT32, natoms_shape); + +// auto coord = coord_tensor.matrix (); +// auto type = type_tensor.matrix (); +// auto box = box_tensor.matrix (); +// auto mesh = mesh_tensor.flat (); +// auto natoms = natoms_tensor.flat (); +// auto fparam = fparam_tensor.matrix (); +// auto aparam = aparam_tensor.matrix (); + +// std::vector dcoord (dcoord_); +// nnpmap.forward (dcoord.begin(), dcoord_.begin(), 3); - for (int ii = 0; ii < nframes; ++ii){ - for (int jj = 0; jj < nall * 3; ++jj){ - coord(ii, jj) = dcoord[jj]; - } - for (int jj = 0; jj < 9; ++jj){ - box(ii, jj) = dbox[jj]; - } - for (int jj = 0; jj < nall; ++jj){ - type(ii, jj) = datype[jj]; - } - for (int jj = 0; jj < fparam_.size(); ++jj){ - fparam(ii, jj) = fparam_[jj]; - } - for (int jj = 0; jj < aparam_.size(); ++jj){ - aparam(ii, jj) = aparam_[jj]; - } - } +// for (int ii = 0; ii < nframes; ++ii){ +// for (int jj = 0; jj < nall * 3; ++jj){ +// coord(ii, jj) = dcoord[jj]; +// } +// for (int jj = 0; jj < 9; ++jj){ +// box(ii, jj) = dbox[jj]; +// } +// for (int jj = 0; jj < nall; ++jj){ +// type(ii, jj) = datype[jj]; +// } +// for (int jj = 0; jj < fparam_.size(); ++jj){ +// fparam(ii, jj) = fparam_[jj]; +// } +// for (int jj = 0; jj < aparam_.size(); ++jj){ +// aparam(ii, jj) = aparam_[jj]; +// } +// } - for (int ii = 0; ii < 16; ++ii) mesh(ii) = 0; +// for (int ii = 0; ii < 16; ++ii) mesh(ii) = 0; - mesh (0) = sizeof(int *) / sizeof(int); - assert (mesh(0) * sizeof(int) == sizeof(int *)); - const int & stride = mesh(0); - mesh (1) = dlist.ilist.size(); - assert (mesh(1) == nloc); - assert (stride <= 4); - dlist.make_ptrs(); - memcpy (&mesh(4), &(dlist.pilist), sizeof(int *)); - memcpy (&mesh(8), &(dlist.pjrange), sizeof(int *)); - memcpy (&mesh(12), &(dlist.pjlist), sizeof(int *)); - - natoms (0) = nloc; - natoms (1) = nall; - for (int ii = 0; ii < ntypes; ++ii) natoms(ii+2) = type_count[ii]; - - std::string prefix = ""; - if (scope != ""){ - prefix = scope + "/"; - } - input_tensors = { - {prefix+"t_coord", coord_tensor}, - {prefix+"t_type", type_tensor}, - {prefix+"t_box", box_tensor}, - {prefix+"t_mesh", mesh_tensor}, - {prefix+"t_natoms",natoms_tensor}, - }; - if (fparam_.size() > 0) { - input_tensors.push_back({prefix+"t_fparam", fparam_tensor}); - } - if (aparam_.size() > 0) { - input_tensors.push_back({prefix+"t_aparam", aparam_tensor}); - } - - return nloc; -} - -int -session_input_tensors ( - std::vector> & input_tensors, - const std::vector & dcoord_, - const int & ntypes, - const std::vector & datype_, - const std::vector & dbox, - const int * ilist, - const int * jrange, - const int * jlist, - const std::vector & fparam_, - const std::vector & aparam_, - const NNPAtomMap & nnpmap, - const int & nghost) -{ - assert (dbox.size() == 9); - - int nframes = 1; - int nall = dcoord_.size() / 3; - int nloc = nall - nghost; - assert (nall == datype_.size()); - - std::vector datype = nnpmap.get_type(); - std::vector type_count (ntypes, 0); - for (unsigned ii = 0; ii < datype.size(); ++ii) { - type_count[datype[ii]] ++; - } - datype.insert (datype.end(), datype_.begin() + nloc, datype_.end()); - - TensorShape coord_shape ; - coord_shape.AddDim (nframes); - coord_shape.AddDim (nall * 3); - TensorShape type_shape ; - type_shape.AddDim (nframes); - type_shape.AddDim (nall); - TensorShape box_shape ; - box_shape.AddDim (nframes); - box_shape.AddDim (9); - TensorShape mesh_shape; - mesh_shape.AddDim (16); - TensorShape natoms_shape; - natoms_shape.AddDim (2 + ntypes); - TensorShape fparam_shape; - fparam_shape.AddDim (nframes); - fparam_shape.AddDim (fparam_.size()); - TensorShape aparam_shape ; - aparam_shape.AddDim (nframes); - aparam_shape.AddDim (aparam_.size()); - - #ifdef HIGH_PREC - Tensor coord_tensor (DT_DOUBLE, coord_shape); - Tensor box_tensor (DT_DOUBLE, box_shape); - Tensor fparam_tensor(DT_DOUBLE, fparam_shape); - Tensor aparam_tensor(DT_DOUBLE, fparam_shape); - #else - Tensor coord_tensor (DT_FLOAT, coord_shape); - Tensor box_tensor (DT_FLOAT, box_shape); - Tensor fparam_tensor(DT_FLOAT, fparam_shape); - Tensor aparam_tensor(DT_FLOAT, fparam_shape); - #endif - Tensor type_tensor (DT_INT32, type_shape); - Tensor mesh_tensor (DT_INT32, mesh_shape); - Tensor natoms_tensor(DT_INT32, natoms_shape); - - auto coord = coord_tensor.matrix (); - auto type = type_tensor.matrix (); - auto box = box_tensor.matrix (); - auto mesh = mesh_tensor.flat (); - auto natoms = natoms_tensor.flat (); - auto fparam = fparam_tensor.matrix (); - auto aparam = aparam_tensor.matrix (); - - std::vector dcoord (dcoord_); - nnpmap.forward (dcoord.begin(), dcoord_.begin(), 3); - - for (int ii = 0; ii < nframes; ++ii) { - for (int jj = 0; jj < nall * 3; ++jj) { - coord(ii, jj) = dcoord[jj]; - } - for (int jj = 0; jj < 9; ++jj) { - box(ii, jj) = dbox[jj]; - } - for (int jj = 0; jj < nall; ++jj) { - type(ii, jj) = datype[jj]; - } - for (int jj = 0; jj < fparam_.size(); ++jj) { - fparam(ii, jj) = fparam_[jj]; - } - for (int jj = 0; jj < aparam_.size(); ++jj) { - aparam(ii, jj) = aparam_[jj]; - } - } +// mesh (0) = sizeof(int *) / sizeof(int); +// assert (mesh(0) * sizeof(int) == sizeof(int *)); +// const int & stride = mesh(0); +// mesh (1) = dlist.ilist.size(); +// assert (mesh(1) == nloc); +// assert (stride <= 4); +// dlist.make_ptrs(); +// memcpy (&mesh(4), &(dlist.pilist), sizeof(int *)); +// memcpy (&mesh(8), &(dlist.pjrange), sizeof(int *)); +// memcpy (&mesh(12), &(dlist.pjlist), sizeof(int *)); + +// natoms (0) = nloc; +// natoms (1) = nall; +// for (int ii = 0; ii < ntypes; ++ii) natoms(ii+2) = type_count[ii]; + +// std::string prefix = ""; +// if (scope != ""){ +// prefix = scope + "/"; +// } +// input_tensors = { +// {prefix+"t_coord", coord_tensor}, +// {prefix+"t_type", type_tensor}, +// {prefix+"t_box", box_tensor}, +// {prefix+"t_mesh", mesh_tensor}, +// {prefix+"t_natoms",natoms_tensor}, +// }; +// if (fparam_.size() > 0) { +// input_tensors.push_back({prefix+"t_fparam", fparam_tensor}); +// } +// if (aparam_.size() > 0) { +// input_tensors.push_back({prefix+"t_aparam", aparam_tensor}); +// } + +// return nloc; +// } + +// int +// session_input_tensors ( +// std::vector> & input_tensors, +// const std::vector & dcoord_, +// const int & ntypes, +// const std::vector & datype_, +// const std::vector & dbox, +// const int * ilist, +// const int * jrange, +// const int * jlist, +// const std::vector & fparam_, +// const std::vector & aparam_, +// const NNPAtomMap & nnpmap, +// const int & nghost) +// { +// assert (dbox.size() == 9); + +// int nframes = 1; +// int nall = dcoord_.size() / 3; +// int nloc = nall - nghost; +// assert (nall == datype_.size()); + +// std::vector datype = nnpmap.get_type(); +// std::vector type_count (ntypes, 0); +// for (unsigned ii = 0; ii < datype.size(); ++ii) { +// type_count[datype[ii]] ++; +// } +// datype.insert (datype.end(), datype_.begin() + nloc, datype_.end()); + +// TensorShape coord_shape ; +// coord_shape.AddDim (nframes); +// coord_shape.AddDim (nall * 3); +// TensorShape type_shape ; +// type_shape.AddDim (nframes); +// type_shape.AddDim (nall); +// TensorShape box_shape ; +// box_shape.AddDim (nframes); +// box_shape.AddDim (9); +// TensorShape mesh_shape; +// mesh_shape.AddDim (16); +// TensorShape natoms_shape; +// natoms_shape.AddDim (2 + ntypes); +// TensorShape fparam_shape; +// fparam_shape.AddDim (nframes); +// fparam_shape.AddDim (fparam_.size()); +// TensorShape aparam_shape ; +// aparam_shape.AddDim (nframes); +// aparam_shape.AddDim (aparam_.size()); + +// #ifdef HIGH_PREC +// Tensor coord_tensor (DT_DOUBLE, coord_shape); +// Tensor box_tensor (DT_DOUBLE, box_shape); +// Tensor fparam_tensor(DT_DOUBLE, fparam_shape); +// Tensor aparam_tensor(DT_DOUBLE, fparam_shape); +// #else +// Tensor coord_tensor (DT_FLOAT, coord_shape); +// Tensor box_tensor (DT_FLOAT, box_shape); +// Tensor fparam_tensor(DT_FLOAT, fparam_shape); +// Tensor aparam_tensor(DT_FLOAT, fparam_shape); +// #endif +// Tensor type_tensor (DT_INT32, type_shape); +// Tensor mesh_tensor (DT_INT32, mesh_shape); +// Tensor natoms_tensor(DT_INT32, natoms_shape); + +// auto coord = coord_tensor.matrix (); +// auto type = type_tensor.matrix (); +// auto box = box_tensor.matrix (); +// auto mesh = mesh_tensor.flat (); +// auto natoms = natoms_tensor.flat (); +// auto fparam = fparam_tensor.matrix (); +// auto aparam = aparam_tensor.matrix (); + +// std::vector dcoord (dcoord_); +// nnpmap.forward (dcoord.begin(), dcoord_.begin(), 3); + +// for (int ii = 0; ii < nframes; ++ii) { +// for (int jj = 0; jj < nall * 3; ++jj) { +// coord(ii, jj) = dcoord[jj]; +// } +// for (int jj = 0; jj < 9; ++jj) { +// box(ii, jj) = dbox[jj]; +// } +// for (int jj = 0; jj < nall; ++jj) { +// type(ii, jj) = datype[jj]; +// } +// for (int jj = 0; jj < fparam_.size(); ++jj) { +// fparam(ii, jj) = fparam_[jj]; +// } +// for (int jj = 0; jj < aparam_.size(); ++jj) { +// aparam(ii, jj) = aparam_[jj]; +// } +// } - for (int ii = 0; ii < 16; ++ii) mesh(ii) = 0; +// for (int ii = 0; ii < 16; ++ii) mesh(ii) = 0; - mesh (0) = sizeof(int *) / sizeof(int); - assert (mesh(0) * sizeof(int) == sizeof(int *)); - const int & stride = mesh(0); - // mesh (1) = dlist.ilist.size(); - mesh (1) = nloc; - assert (mesh(1) == nloc); - assert (stride <= 4); - memcpy (&mesh(4), &(ilist), sizeof(int *)); - memcpy (&mesh(8), &(jrange), sizeof(int *)); - memcpy (&mesh(12), &(jlist), sizeof(int *)); - - natoms (0) = nloc; - natoms (1) = nall; - for (int ii = 0; ii < ntypes; ++ii) natoms(ii+2) = type_count[ii]; +// mesh (0) = sizeof(int *) / sizeof(int); +// assert (mesh(0) * sizeof(int) == sizeof(int *)); +// const int & stride = mesh(0); +// // mesh (1) = dlist.ilist.size(); +// mesh (1) = nloc; +// assert (mesh(1) == nloc); +// assert (stride <= 4); +// memcpy (&mesh(4), &(ilist), sizeof(int *)); +// memcpy (&mesh(8), &(jrange), sizeof(int *)); +// memcpy (&mesh(12), &(jlist), sizeof(int *)); + +// natoms (0) = nloc; +// natoms (1) = nall; +// for (int ii = 0; ii < ntypes; ++ii) natoms(ii+2) = type_count[ii]; - input_tensors = { - {"t_coord", coord_tensor}, - {"t_type", type_tensor}, - {"t_box", box_tensor}, - {"t_mesh", mesh_tensor}, - {"t_natoms", natoms_tensor}, - }; - if (fparam_.size() > 0) { - input_tensors.push_back({"t_fparam", fparam_tensor}); - } - if (aparam_.size() > 0) { - input_tensors.push_back({"t_aparam", aparam_tensor}); - } - return nloc; -} \ No newline at end of file +// input_tensors = { +// {"t_coord", coord_tensor}, +// {"t_type", type_tensor}, +// {"t_box", box_tensor}, +// {"t_mesh", mesh_tensor}, +// {"t_natoms", natoms_tensor}, +// }; +// if (fparam_.size() > 0) { +// input_tensors.push_back({"t_fparam", fparam_tensor}); +// } +// if (aparam_.size() > 0) { +// input_tensors.push_back({"t_aparam", aparam_tensor}); +// } +// return nloc; +// } diff --git a/source/api_cc/tests/CMakeLists.txt b/source/api_cc/tests/CMakeLists.txt new file mode 100644 index 0000000000..4ffa71de3d --- /dev/null +++ b/source/api_cc/tests/CMakeLists.txt @@ -0,0 +1,106 @@ +cmake_minimum_required(VERSION 3.9) +project(deepmd_api_test) +set(CMAKE_LINK_WHAT_YOU_USE TRUE) + +if (NOT DEFINED BUILD_CPP_IF) + set(BUILD_CPP_IF TRUE) +endif (NOT DEFINED BUILD_CPP_IF) +add_definitions ("-DHIGH_PREC") + +enable_testing() + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + +message(${PROJECT_SOURCE_DIR}) +message(${CMAKE_SOURCE_DIR}) + +set(libname "deepmd") +set(LIB_BASE_DIR ${CMAKE_SOURCE_DIR}/../../lib) +include_directories(${LIB_BASE_DIR}/include) +file(GLOB LIB_SRC ${LIB_BASE_DIR}/src/*.cc ${LIB_BASE_DIR}/src/*.cpp) +add_library(${libname} SHARED ${LIB_SRC}) + +set(apiname "deepmd_api") +set(API_BASE_DIR ${CMAKE_SOURCE_DIR}/../) +include_directories(${API_BASE_DIR}/include) +include_directories(${CMAKE_SOURCE_DIR}) +file(GLOB API_SRC ${API_BASE_DIR}/src/*.cc ${API_BASE_DIR}/src/*.cpp) +add_library(${apiname} SHARED ${API_SRC}) +configure_file( + ${API_BASE_DIR}/include/version.h.in + version.h + @ONLY +) + +set(opname "deepmd_op") +set(OP_BASE_DIR ${CMAKE_SOURCE_DIR}/../../op) +# file(GLOB OP_SRC ${OP_BASE_DIR}/*.cc) +file(GLOB OP_SRC ${OP_BASE_DIR}/prod_force.cc ${OP_BASE_DIR}/prod_virial.cc ${OP_BASE_DIR}/descrpt.cc ${OP_BASE_DIR}/descrpt_se_a.cc ${OP_BASE_DIR}/descrpt_se_a_ef.cc ${OP_BASE_DIR}/descrpt_se_a_ef.cc ${OP_BASE_DIR}/descrpt_se_a_ef_para.cc ${OP_BASE_DIR}/descrpt_se_a_ef_vert.cc ${OP_BASE_DIR}/descrpt_se_r.cc ${OP_BASE_DIR}/pair_tab.cc ${OP_BASE_DIR}/prod_force_se_a.cc ${OP_BASE_DIR}/prod_virial_se_a.cc ${OP_BASE_DIR}/prod_force_se_r.cc ${OP_BASE_DIR}/prod_virial_se_r.cc ${OP_BASE_DIR}/soft_min.cc ${OP_BASE_DIR}/soft_min_force.cc ${OP_BASE_DIR}/soft_min_virial.cc ${OP_BASE_DIR}/ewald_recp.cc ${OP_BASE_DIR}/gelu_multi_device.cc ${OP_BASE_DIR}/map_aparam.cc ${OP_BASE_DIR}/neighbor_stat.cc ${OP_BASE_DIR}/unaggregated_grad.cc ${OP_BASE_DIR}/tabulate_multi_device.cc ${OP_BASE_DIR}/prod_env_mat_multi_device.cc) +add_library(${opname} SHARED ${OP_SRC}) + +list (APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/../../cmake/) +find_package(tensorflow REQUIRED) +include_directories(${TensorFlow_INCLUDE_DIRS}) + +find_package(Threads) +# find openmp +find_package(OpenMP) +if (OPENMP_FOUND) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") +endif() + +# define USE_CUDA_TOOLKIT +if (DEFINED USE_CUDA_TOOLKIT) + if (USE_CUDA_TOOLKIT) + find_package(CUDA REQUIRED) + else() + message(STATUS "Will not build nv GPU support") + endif() +else() + find_package(CUDA QUIET) + if (CUDA_FOUND) + set(USE_CUDA_TOOLKIT TRUE) + message(STATUS "Found CUDA in ${CUDA_TOOLKIT_ROOT_DIR}, build nv GPU support") + else() + set(USE_CUDA_TOOLKIT FALSE) + message(STATUS "No cuda support found, will not build nv GPU support") + endif() +endif() + +if (USE_CUDA_TOOLKIT) + add_definitions("-D GOOGLE_CUDA") + include_directories(${CUDA_INCLUDE_DIRS}) + add_subdirectory(${LIB_BASE_DIR}/src/cuda cuda_binary_dir) +endif() + +file(GLOB TEST_SRC test_*.cc) +add_executable( runUnitTests ${TEST_SRC} ) + +if (USE_CUDA_TOOLKIT) + target_link_libraries(runUnitTests gtest gtest_main ${libname} pthread deepmd_op_cuda) +else() + target_link_libraries(runUnitTests gtest gtest_main ${libname} ${apiname} ${opname} pthread ${TensorFlow_LIBRARY}) +endif() +add_test( runUnitTests runUnitTests ) + +find_package(GTest) +if(NOT GTEST_LIBRARY) + configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt) + execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) + if(result) + message(FATAL_ERROR "CMake step for googletest failed: ${result}") + endif() + execute_process(COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) + if(result) + message(FATAL_ERROR "Build step for googletest failed: ${result}") + endif() + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src ${CMAKE_CURRENT_BINARY_DIR}/googletest-build EXCLUDE_FROM_ALL) +else () + include_directories(${GTEST_INCLUDE_DIRS}) +endif () diff --git a/source/api_cc/tests/test_deepdipole.cc b/source/api_cc/tests/test_deepdipole.cc new file mode 100644 index 0000000000..1c69e72cc6 --- /dev/null +++ b/source/api_cc/tests/test_deepdipole.cc @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +#include "DeepTensor.h" +#include "SimulationRegion.h" +#include "neighbor_list.h" +#include "test_utils.h" + +#include "google/protobuf/text_format.h" +#include "google/protobuf/io/zero_copy_stream_impl.h" +#include +#include +#include + +class TestInferDeepDipole : public ::testing::Test +{ +protected: + std::vector coord = { + 12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = { + 0, 1, 1, 0, 1, 1 + }; + std::vector box = { + 13., 0., 0., 0., 13., 0., 0., 0., 13. + }; + std::vector expected_d = { + -9.274180565967479195e-01,2.698028341272042496e+00,2.521268387140979117e-01,2.927260638453461628e+00,-8.571926301526779923e-01,1.667785136187720063e+00 + }; + int natoms; + + DeepTensor dp; + + void SetUp() override { + std::string file_name = "../../tests/infer/deepdipole.pbtxt"; + int fd = open(file_name.c_str(), O_RDONLY); + protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); + GraphDef graph_def; + protobuf::TextFormat::Parse(input, &graph_def); + delete input; + std::fstream output("deepdipole.pb", std::ios::out | std::ios::trunc | std::ios::binary); + graph_def.SerializeToOstream(&output); + // check the string by the following commands + // string txt; + // protobuf::TextFormat::PrintToString(graph_def, &txt); + + dp.init("deepdipole.pb"); + + natoms = expected_d.size(); + }; + + void TearDown() override { + remove( "deepdipole.pb" ) ; + }; +}; + + +TEST_F(TestInferDeepDipole, cpu_build_nlist) +{ + EXPECT_EQ(dp.cutoff(), 4.); + EXPECT_EQ(dp.numb_types(), 2); + EXPECT_EQ(dp.output_dim(), 3); + std::vector sel_types = dp.sel_types(); + EXPECT_EQ(sel_types.size(), 1); + EXPECT_EQ(sel_types[0], 0); + + std::vector value; + dp.compute(value, coord, atype, box); + + EXPECT_EQ(value.size(), expected_d.size()); + for(int ii = 0; ii < expected_d.size(); ++ii){ + EXPECT_LT(fabs(value[ii] - expected_d[ii]), 1e-10); + } +} + +TEST_F(TestInferDeepDipole, cpu_lmp_nlist) +{ + float rc = dp.cutoff(); + int nloc = coord.size() / 3; + std::vector coord_cpy; + std::vector atype_cpy, mapping; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + std::vector > nlist_data; + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, + coord, atype, box, rc); + int nall = coord_cpy.size() / 3; + convert_nlist(inlist, nlist_data); + + std::vector value; + dp.compute(value, coord_cpy, atype_cpy, box, nall-nloc, inlist); + + EXPECT_EQ(value.size(), expected_d.size()); + for(int ii = 0; ii < expected_d.size(); ++ii){ + EXPECT_LT(fabs(value[ii] - expected_d[ii]), 1e-10); + } +} + diff --git a/source/api_cc/tests/test_deeppolar.cc b/source/api_cc/tests/test_deeppolar.cc new file mode 100644 index 0000000000..1d02ac5879 --- /dev/null +++ b/source/api_cc/tests/test_deeppolar.cc @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +#include "DeepTensor.h" +#include "SimulationRegion.h" +#include "neighbor_list.h" +#include "test_utils.h" + +#include "google/protobuf/text_format.h" +#include "google/protobuf/io/zero_copy_stream_impl.h" +#include +#include +#include + +class TestInferDeepPolar : public ::testing::Test +{ +protected: + std::vector coord = { + 12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = { + 0, 1, 1, 0, 1, 1 + }; + std::vector box = { + 13., 0., 0., 0., 13., 0., 0., 0., 13. + }; + std::vector expected_d = { + 1.061407927405987051e-01,-3.569013342133873778e-01,-2.862108976089940138e-02,-3.569013342133875444e-01,1.304367268874677244e+00,1.037647501453442256e-01,-2.862108976089940138e-02,1.037647501453441284e-01,8.100521520762453409e-03,1.236797829492216616e+00,-3.717307430531632262e-01,7.371515676976750919e-01,-3.717307430531630041e-01,1.127222682121889058e-01,-2.239181552775717510e-01,7.371515676976746478e-01,-2.239181552775717787e-01,4.448255365635306879e-01 + }; + int natoms; + + DeepTensor dp; + + void SetUp() override { + std::string file_name = "../../tests/infer/deeppolar.pbtxt"; + int fd = open(file_name.c_str(), O_RDONLY); + protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); + GraphDef graph_def; + protobuf::TextFormat::Parse(input, &graph_def); + delete input; + std::fstream output("deeppolar.pb", std::ios::out | std::ios::trunc | std::ios::binary); + graph_def.SerializeToOstream(&output); + // check the string by the following commands + // string txt; + // protobuf::TextFormat::PrintToString(graph_def, &txt); + + dp.init("deeppolar.pb"); + + natoms = expected_d.size(); + }; + + void TearDown() override { + remove( "deeppolar.pb" ) ; + }; +}; + + +TEST_F(TestInferDeepPolar, cpu_build_nlist) +{ + EXPECT_EQ(dp.cutoff(), 6.); + EXPECT_EQ(dp.numb_types(), 2); + EXPECT_EQ(dp.output_dim(), 9); + std::vector sel_types = dp.sel_types(); + EXPECT_EQ(sel_types.size(), 1); + EXPECT_EQ(sel_types[0], 0); + + std::vector value; + dp.compute(value, coord, atype, box); + + EXPECT_EQ(value.size(), expected_d.size()); + for(int ii = 0; ii < expected_d.size(); ++ii){ + EXPECT_LT(fabs(value[ii] - expected_d[ii]), 1e-10); + } +} + +TEST_F(TestInferDeepPolar, cpu_lmp_nlist) +{ + float rc = dp.cutoff(); + int nloc = coord.size() / 3; + std::vector coord_cpy; + std::vector atype_cpy, mapping; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + std::vector > nlist_data; + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, + coord, atype, box, rc); + int nall = coord_cpy.size() / 3; + convert_nlist(inlist, nlist_data); + + std::vector value; + dp.compute(value, coord_cpy, atype_cpy, box, nall-nloc, inlist); + + EXPECT_EQ(value.size(), expected_d.size()); + for(int ii = 0; ii < expected_d.size(); ++ii){ + EXPECT_LT(fabs(value[ii] - expected_d[ii]), 1e-10); + } +} + diff --git a/source/api_cc/tests/test_deeppot.cc b/source/api_cc/tests/test_deeppot.cc new file mode 100644 index 0000000000..e59677dd66 --- /dev/null +++ b/source/api_cc/tests/test_deeppot.cc @@ -0,0 +1,437 @@ +#include +#include +#include +#include +#include +#include "NNPInter.h" +#include "SimulationRegion.h" +#include "neighbor_list.h" +#include "test_utils.h" + +#include "google/protobuf/text_format.h" +#include "google/protobuf/io/zero_copy_stream_impl.h" +#include +#include +#include + +class TestInferDeepPot : public ::testing::Test +{ +protected: + std::vector coord = { + 12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = { + 0, 1, 1, 0, 1, 1 + }; + std::vector box = { + 13., 0., 0., 0., 13., 0., 0., 0., 13. + }; + std::vector expected_e = { + -9.275780747115504710e+01,-1.863501786584258468e+02,-1.863392472863538103e+02,-9.279281325486221021e+01,-1.863671545232153903e+02,-1.863619822847602165e+02 + }; + std::vector expected_f = { + -3.034045420701179663e-01,8.405844663871177014e-01,7.696947487118485642e-02,7.662001266663505117e-01,-1.880601391333554251e-01,-6.183333871091722944e-01,-5.036172391059643427e-01,-6.529525836149027151e-01,5.432962643022043459e-01,6.382357912332115024e-01,-1.748518296794561167e-01,3.457363524891907125e-01,1.286482986991941552e-03,3.757251165286925043e-01,-5.972588700887541124e-01,-5.987006197104716154e-01,-2.004450304880958100e-01,2.495901655353461868e-01 + }; + std::vector expected_v = { + -2.912234126853306959e-01,-3.800610846612756388e-02,2.776624987489437202e-01,-5.053761003913598976e-02,-3.152373041953385746e-01,1.060894290092162379e-01,2.826389131596073745e-01,1.039129970665329250e-01,-2.584378792325942586e-01,-3.121722367954994914e-01,8.483275876786681990e-02,2.524662342344257682e-01,4.142176771106586414e-02,-3.820285230785245428e-02,-2.727311173065460545e-02,2.668859789777112135e-01,-6.448243569420382404e-02,-2.121731470426218846e-01,-8.624335220278558922e-02,-1.809695356746038597e-01,1.529875294531883312e-01,-1.283658185172031341e-01,-1.992682279795223999e-01,1.409924999632362341e-01,1.398322735274434292e-01,1.804318474574856390e-01,-1.470309318999652726e-01,-2.593983661598450730e-01,-4.236536279233147489e-02,3.386387920184946720e-02,-4.174017537818433543e-02,-1.003500282164128260e-01,1.525690815194478966e-01,3.398976109910181037e-02,1.522253908435125536e-01,-2.349125581341701963e-01,9.515545977581392825e-04,-1.643218849228543846e-02,1.993234765412972564e-02,6.027265332209678569e-04,-9.563256398907417355e-02,1.510815124001868293e-01,-7.738094816888557714e-03,1.502832772532304295e-01,-2.380965783745832010e-01,-2.309456719810296654e-01,-6.666961081213038098e-02,7.955566551234216632e-02,-8.099093777937517447e-02,-3.386641099800401927e-02,4.447884755740908608e-02,1.008593228579038742e-01,4.556718179228393811e-02,-6.078081273849572641e-02 + }; + int natoms; + double expected_tot_e; + std::vectorexpected_tot_v; + + NNPInter dp; + + void SetUp() override { + std::string file_name = "../../tests/infer/deeppot.pbtxt"; + int fd = open(file_name.c_str(), O_RDONLY); + protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); + GraphDef graph_def; + protobuf::TextFormat::Parse(input, &graph_def); + delete input; + std::fstream output("deeppot.pb", std::ios::out | std::ios::trunc | std::ios::binary); + graph_def.SerializeToOstream(&output); + // check the string by the following commands + // string txt; + // protobuf::TextFormat::PrintToString(graph_def, &txt); + + dp.init("deeppot.pb"); + + natoms = expected_e.size(); + EXPECT_EQ(natoms * 3, expected_f.size()); + EXPECT_EQ(natoms * 9, expected_v.size()); + expected_tot_e = 0.; + expected_tot_v.resize(9); + std::fill(expected_tot_v.begin(), expected_tot_v.end(), 0.); + for(int ii = 0; ii < natoms; ++ii){ + expected_tot_e += expected_e[ii]; + } + for(int ii = 0; ii < natoms; ++ii){ + for(int dd = 0; dd < 9; ++dd){ + expected_tot_v[dd] += expected_v[ii*9+dd]; + } + } + }; + + void TearDown() override { + remove( "deeppot.pb" ) ; + }; +}; + + +TEST_F(TestInferDeepPot, cpu_build_nlist) +{ + double ener; + std::vector force, virial; + dp.compute(ener, force, virial, coord, atype, box); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } +} + +TEST_F(TestInferDeepPot, cpu_build_nlist_atomic) +{ + double ener; + std::vector force, virial, atom_ener, atom_vir; + dp.compute(ener, force, virial, atom_ener, atom_vir, coord, atype, box); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + EXPECT_EQ(atom_ener.size(), natoms); + EXPECT_EQ(atom_vir.size(), natoms*9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } + for(int ii = 0; ii < natoms; ++ii){ + EXPECT_LT(fabs(atom_ener[ii] - expected_e[ii]), 1e-10); + } + for(int ii = 0; ii < natoms*9; ++ii){ + EXPECT_LT(fabs(atom_vir[ii] - expected_v[ii]), 1e-10); + } +} + + +TEST_F(TestInferDeepPot, cpu_lmp_nlist) +{ + float rc = dp.cutoff(); + int nloc = coord.size() / 3; + std::vector coord_cpy; + std::vector atype_cpy, mapping; + std::vector > nlist_data; + _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, + coord, atype, box, rc); + int nall = coord_cpy.size() / 3; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_data); + + double ener; + std::vector force_, virial; + dp.compute(ener, force_, virial, coord_cpy, atype_cpy, box, nall-nloc, inlist, 0); + std::vector force; + _fold_back(force, force_, mapping, nloc, nall, 3); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } + + ener = 0.; + std::fill(force_.begin(), force_.end(), 0.0); + std::fill(virial.begin(), virial.end(), 0.0); + dp.compute(ener, force_, virial, coord_cpy, atype_cpy, box, nall-nloc, inlist, 1); + _fold_back(force, force_, mapping, nloc, nall, 3); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } +} + + +TEST_F(TestInferDeepPot, cpu_lmp_nlist_atomic) +{ + float rc = dp.cutoff(); + int nloc = coord.size() / 3; + std::vector coord_cpy; + std::vector atype_cpy, mapping; + std::vector > nlist_data; + _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, + coord, atype, box, rc); + int nall = coord_cpy.size() / 3; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_data); + + double ener; + std::vector force_, atom_ener_, atom_vir_, virial; + std::vector force, atom_ener, atom_vir; + dp.compute(ener, force_, virial, atom_ener_, atom_vir_, coord_cpy, atype_cpy, box, nall-nloc, inlist, 0); + _fold_back(force, force_, mapping, nloc, nall, 3); + _fold_back(atom_ener, atom_ener_, mapping, nloc, nall, 1); + _fold_back(atom_vir, atom_vir_, mapping, nloc, nall, 9); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + EXPECT_EQ(atom_ener.size(), natoms); + EXPECT_EQ(atom_vir.size(), natoms*9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } + for(int ii = 0; ii < natoms; ++ii){ + EXPECT_LT(fabs(atom_ener[ii] - expected_e[ii]), 1e-10); + } + for(int ii = 0; ii < natoms*9; ++ii){ + EXPECT_LT(fabs(atom_vir[ii] - expected_v[ii]), 1e-10); + } + + ener = 0.; + std::fill(force_.begin(), force_.end(), 0.0); + std::fill(virial.begin(), virial.end(), 0.0); + std::fill(atom_ener_.begin(), atom_ener_.end(), 0.0); + std::fill(atom_vir_.begin(), atom_vir_.end(), 0.0); + dp.compute(ener, force_, virial, atom_ener_, atom_vir_, coord_cpy, atype_cpy, box, nall-nloc, inlist, 1); + _fold_back(force, force_, mapping, nloc, nall, 3); + _fold_back(atom_ener, atom_ener_, mapping, nloc, nall, 1); + _fold_back(atom_vir, atom_vir_, mapping, nloc, nall, 9); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + EXPECT_EQ(atom_ener.size(), natoms); + EXPECT_EQ(atom_vir.size(), natoms*9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } + for(int ii = 0; ii < natoms; ++ii){ + EXPECT_LT(fabs(atom_ener[ii] - expected_e[ii]), 1e-10); + } + for(int ii = 0; ii < natoms*9; ++ii){ + EXPECT_LT(fabs(atom_vir[ii] - expected_v[ii]), 1e-10); + } +} + + +TEST_F(TestInferDeepPot, cpu_lmp_nlist_2rc) +{ + float rc = dp.cutoff(); + int nloc = coord.size() / 3; + std::vector coord_cpy; + std::vector atype_cpy, mapping; + std::vector > nlist_data; + _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, + coord, atype, box, rc*2); + int nall = coord_cpy.size() / 3; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_data); + + double ener; + std::vector force_(nall*3, 0.0), virial(9, 0.0); + dp.compute(ener, force_, virial, coord_cpy, atype_cpy, box, nall-nloc, inlist, 0); + std::vector force; + _fold_back(force, force_, mapping, nloc, nall, 3); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } + + ener = 0.; + std::fill(force_.begin(), force_.end(), 0.0); + std::fill(virial.begin(), virial.end(), 0.0); + dp.compute(ener, force_, virial, coord_cpy, atype_cpy, box, nall-nloc, inlist, 1); + _fold_back(force, force_, mapping, nloc, nall, 3); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } +} + + +TEST_F(TestInferDeepPot, cpu_lmp_nlist_type_sel) +{ + float rc = dp.cutoff(); + + // add vir atoms + int nvir = 2; + std::vector coord_vir(nvir*3); + std::vector atype_vir(nvir, 2); + for(int ii = 0; ii < nvir; ++ii){ + coord_vir[ii] = coord[ii]; + } + coord.insert(coord.begin(), coord_vir.begin(), coord_vir.end()); + atype.insert(atype.begin(), atype_vir.begin(), atype_vir.end()); + natoms += nvir; + std::vector expected_f_vir(nvir*3, 0.0); + expected_f.insert(expected_f.begin(), expected_f_vir.begin(), expected_f_vir.end()); + + // build nlist + int nloc = coord.size() / 3; + std::vector coord_cpy; + std::vector atype_cpy, mapping; + std::vector > nlist_data; + _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, + coord, atype, box, rc); + int nall = coord_cpy.size() / 3; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_data); + + // dp compute + double ener; + std::vector force_(nall*3, 0.0), virial(9, 0.0); + dp.compute(ener, force_, virial, coord_cpy, atype_cpy, box, nall-nloc, inlist, 0); + // fold back + std::vector force; + _fold_back(force, force_, mapping, nloc, nall, 3); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } +} + + + +class TestInferDeepPotNoPbc : public ::testing::Test +{ +protected: + std::vector coord = { + 12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = { + 0, 1, 1, 0, 1, 1 + }; + std::vector box = {}; + std::vector expected_e = { + -9.255934839310273787e+01,-1.863253376736990106e+02,-1.857237299341402945e+02,-9.279308539717486326e+01,-1.863708105823244239e+02,-1.863635196514972563e+02 + }; + std::vector expected_f = { + -2.161037360255332107e+00,9.052994347015581589e-01,1.635379623977007979e+00,2.161037360255332107e+00,-9.052994347015581589e-01,-1.635379623977007979e+00,-1.167128117249453811e-02,1.371975700096064992e-03,-1.575265180249604477e-03,6.226508593971802341e-01,-1.816734122009256991e-01,3.561766019664774907e-01,-1.406075393906316626e-02,3.789140061530929526e-01,-6.018777878642909140e-01,-5.969188242856223736e-01,-1.986125696522633155e-01,2.472764510780630642e-01 + }; + std::vector expected_v = { + -7.042445481792056761e-01,2.950213647777754078e-01,5.329418202437231633e-01,2.950213647777752968e-01,-1.235900311906896754e-01,-2.232594111831812944e-01,5.329418202437232743e-01,-2.232594111831813499e-01,-4.033073234276823849e-01,-8.949230984097404917e-01,3.749002169013777030e-01,6.772391014992630298e-01,3.749002169013777586e-01,-1.570527935667933583e-01,-2.837082722496912512e-01,6.772391014992631408e-01,-2.837082722496912512e-01,-5.125052659994422388e-01,4.858210330291591605e-02,-6.902596153269104431e-03,6.682612642430500391e-03,-5.612247004554610057e-03,9.767795567660207592e-04,-9.773758942738038254e-04,5.638322117219018645e-03,-9.483806049779926932e-04,8.493873281881353637e-04,-2.941738570564985666e-01,-4.482529909499673171e-02,4.091569840186781021e-02,-4.509020615859140463e-02,-1.013919988807244071e-01,1.551440772665269030e-01,4.181857726606644232e-02,1.547200233064863484e-01,-2.398213304685777592e-01,-3.218625798524068354e-02,-1.012438450438508421e-02,1.271639330380921855e-02,3.072814938490859779e-03,-9.556241797915024372e-02,1.512251983492413077e-01,-8.277872384009607454e-03,1.505412040827929787e-01,-2.386150620881526407e-01,-2.312295470054945568e-01,-6.631490213524345034e-02,7.932427266386249398e-02,-8.053754366323923053e-02,-3.294595881137418747e-02,4.342495071150231922e-02,1.004599500126941436e-01,4.450400364869536163e-02,-5.951077548033092968e-02 + }; + int natoms; + double expected_tot_e; + std::vectorexpected_tot_v; + + NNPInter dp; + + void SetUp() override { + std::string file_name = "../../tests/infer/deeppot.pbtxt"; + int fd = open(file_name.c_str(), O_RDONLY); + protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); + GraphDef graph_def; + protobuf::TextFormat::Parse(input, &graph_def); + delete input; + std::fstream output("deeppot.pb", std::ios::out | std::ios::trunc | std::ios::binary); + graph_def.SerializeToOstream(&output); + + dp.init("deeppot.pb"); + + natoms = expected_e.size(); + EXPECT_EQ(natoms * 3, expected_f.size()); + EXPECT_EQ(natoms * 9, expected_v.size()); + expected_tot_e = 0.; + expected_tot_v.resize(9); + std::fill(expected_tot_v.begin(), expected_tot_v.end(), 0.); + for(int ii = 0; ii < natoms; ++ii){ + expected_tot_e += expected_e[ii]; + } + for(int ii = 0; ii < natoms; ++ii){ + for(int dd = 0; dd < 9; ++dd){ + expected_tot_v[dd] += expected_v[ii*9+dd]; + } + } + }; + + void TearDown() override { + remove( "deeppot.pb" ) ; + }; +}; + +TEST_F(TestInferDeepPotNoPbc, cpu_build_nlist) +{ + double ener; + std::vector force, virial; + dp.compute(ener, force, virial, coord, atype, box); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } +} diff --git a/source/api_cc/tests/test_dipolecharge.cc b/source/api_cc/tests/test_dipolecharge.cc new file mode 100644 index 0000000000..8c517057f3 --- /dev/null +++ b/source/api_cc/tests/test_dipolecharge.cc @@ -0,0 +1,240 @@ +#include +#include +#include +#include +#include +#include "DeepTensor.h" +#include "DataModifier.h" +#include "SimulationRegion.h" +#include "Ewald.h" +#include "neighbor_list.h" +#include "test_utils.h" + +#include "google/protobuf/text_format.h" +#include "google/protobuf/io/zero_copy_stream_impl.h" +#include +#include +#include + +class TestDipoleCharge : public ::testing::Test +{ +protected: + std::vector coord = { + 4.6067455554, 8.8719311819, 6.3886531197, + 4.0044515745, 4.2449530507, 7.7902855220, + 2.6453069446, 0.8772647726, 1.2804446790, + 1.1445332290, 0.0067366438, 1.8606485070, + 7.1002867706, 5.0325506787, 3.1805888348, + 4.5352891138, 7.7389683929, 9.4260970128, + 2.1833238914, 9.0916071034, 7.2299906064, + 4.1040157820, 1.0496745045, 5.4748315591, + }; + std::vector atype = { + 0,3,2,1,3,4,1,4 + }; + std::vector box = { + 10., 0., 0., 0., 10., 0., 0., 0., 10. + }; + std::vector expected_e = { + 3.671081837126222158e+00 + }; + std::vector expected_f = { + 8.786854427753210128e-01,-1.590752486903602159e-01,-2.709225006303785932e-01,-4.449513960033193438e-01,-1.564291540964127813e-01,2.139031741772115178e-02,1.219699614140521193e+00,-5.580358618499958734e-02,-3.878662478349682585e-01,-1.286685244990778854e+00,1.886475802950296488e-01,3.904450515493615437e-01,1.605017382138404849e-02,2.138016869742287995e-01,-2.617514921203008965e-02,2.877081057057793712e-01,-3.846449683844421763e-01,3.048855616906603894e-02,-9.075632811311897807e-01,-6.509653472431625731e-03,2.302010972126376787e-01,2.370565856822822726e-01,3.600133435593881881e-01,1.243887532859055609e-02 + }; + std::vector expected_v = { + 3.714071471995848417e-01,6.957130186032146613e-01,-1.158289779017217302e+00,6.957130186032139951e-01,-1.400130091653774933e+01,-3.631620234653316626e-01,-1.158289779017217302e+00,-3.631620234653316626e-01,3.805077486043773050e+00 + }; + std::vector charge_map = { + 1., 1., 1., 1., 1., -1., -3. + }; + int natoms; + int ntypes; + std::vector type_asso; + double expected_tot_e; + std::vectorexpected_tot_v; + + DeepTensor dp; + DipoleChargeModifier dm; + + void SetUp() override { + std::string file_name = "../../tests/infer/dipolecharge_e.pbtxt"; + int fd = open(file_name.c_str(), O_RDONLY); + protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); + GraphDef graph_def; + protobuf::TextFormat::Parse(input, &graph_def); + delete input; + string model = "dipolecharge_e.pb"; + std::fstream output(model.c_str(), std::ios::out | std::ios::trunc | std::ios::binary); + graph_def.SerializeToOstream(&output); + // check the string by the following commands + // string txt; + // protobuf::TextFormat::PrintToString(graph_def, &txt); + + // dp.init("dipolecharge_d.pb"); + // dm.init("dipolecharge_d.pb"); + dp.init(model, 0, "dipole_charge"); + dm.init(model, 0, "dipole_charge"); + + natoms = atype.size(); + ntypes = 5; + type_asso.resize(ntypes, -1); + type_asso[1] = 5; + type_asso[3] = 6; + + EXPECT_EQ(natoms * 3, expected_f.size()); + EXPECT_EQ(9, expected_v.size()); + }; + + void TearDown() override { + remove( "dipolecharge_e.pb" ) ; + }; +}; + +static bool +_in_vec(const int & value, + const std::vector & vec) +{ + // naive impl. + for(int ii = 0; ii < vec.size(); ++ii){ + if(value == vec[ii]) return true; + } + return false; +} + +TEST_F(TestDipoleCharge, cpu_lmp_nlist) +{ + // build nlist + // float rc = dp.cutoff(); + float rc = 4.0; + int nloc = coord.size() / 3; + std::vector coord_cpy; + std::vector atype_cpy, mapping; + std::vector > nlist_data; + _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, + coord, atype, box, rc); + int nall = coord_cpy.size() / 3; + int nghost = nall - nloc; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_data); + + // evaluate dipole + std::vector dipole, dipole_recd(nloc*3, 0.0); + dp.compute(dipole, coord_cpy, atype_cpy, box, nall-nloc, inlist); + + // add virtual atoms to the system + // // a lot of mappings + std::vector sel_types = dp.sel_types(); + std::vector sel_fwd, sel_bwd; + int sel_nghost; + select_by_type(sel_fwd, sel_bwd, sel_nghost, coord_cpy, atype_cpy, nghost, sel_types); + int sel_nall = sel_bwd.size(); + int sel_nloc = sel_nall - sel_nghost; + std::vector sel_atype(sel_bwd.size()); + select_map(sel_atype, atype, sel_fwd, 1); + NNPAtomMap nnp_map(sel_atype.begin(), sel_atype.begin() + sel_nloc); + const std::vector & sort_fwd_map(nnp_map.get_fwd_map()); + + // // add coords + std::vector add_coord; + std::vector add_atype; + std::vector> pairs; + for(int ii = 0; ii < nloc; ++ii){ + if(_in_vec(atype[ii], sel_types)){ + int res_idx = sort_fwd_map[sel_fwd[ii]]; + std::vector tmp_coord(3); + for(int dd = 0; dd < 3; ++dd){ + tmp_coord[dd] = coord[ii*3+dd] + dipole[res_idx*3+dd]; + dipole_recd[ii*3+dd] = dipole[res_idx*3+dd]; + } + pairs.push_back(std::pair(ii, add_atype.size()+atype.size())); + // std::cout << ii << " " + // << atype[ii] << " " + // << res_idx << " " + // << type_asso[atype[ii]] << " " + // << " pair " + // << pairs.back().first << " " << pairs.back().second << " " + // << std::endl; + add_coord.insert(add_coord.end(), tmp_coord.begin(), tmp_coord.end()); + add_atype.push_back(type_asso[atype[ii]]); + } + } + coord.insert(coord.end(), add_coord.begin(), add_coord.end()); + atype.insert(atype.end(), add_atype.begin(), add_atype.end()); + nloc = atype.size(); + EXPECT_EQ(atype.size()*3, coord.size()); + + // get charge value + std::vector charge(nloc); + for(int ii = 0; ii < nloc; ++ii){ + charge[ii] = charge_map[atype[ii]]; + } + + // compute the recp part of the ele interaction + double eener; + std::vector eforce, evirial; + SimulationRegion region; + region.reinitBox(&box[0]); + EwaldParameters eparam; + eparam.beta = 0.2; + eparam.spacing = 4; + EwaldReciprocal(eener, eforce, evirial, coord, charge, region, eparam); + + EXPECT_LT(fabs(eener - expected_e[0]), 1e-6); + EXPECT_EQ(eforce.size(), coord.size()); + EXPECT_EQ(evirial.size(), 9); + + // extend the system with virtual atoms, and build nlist + _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, + coord, atype, box, rc); + nall = coord_cpy.size() / 3; + nghost = nall - nloc; + ilist.resize(nloc); + numneigh.resize(nloc); + firstneigh.resize(nloc); + inlist.inum = nloc; + inlist.ilist = &ilist[0]; + inlist.numneigh = &numneigh[0]; + inlist.firstneigh = &firstneigh[0]; + convert_nlist(inlist, nlist_data); + + // compute force and virial + std::vector force_, force, virial; + dm.compute(force_, virial, coord_cpy, atype_cpy, box, pairs, eforce, nghost, inlist); + // for(int ii = 0; ii < force_.size(); ++ii){ + // std::cout << force_[ii] << " " ; + // } + // std::cout << std::endl; + _fold_back(force, force_, mapping, nloc, nall, 3); + + // compare force + EXPECT_EQ(force.size(), nloc*3); + // note nloc > expected_f.size(), because nloc contains virtual atoms. + for(int ii = 0; ii < expected_f.size(); ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-6); + } + + // add recp virial and viral corr to virial + // virial = virial_recp + virial_dipolecharge + virial_corr + for (int dd0 = 0; dd0 < 3; ++dd0){ + for (int dd1 = 0; dd1 < 3; ++dd1){ + virial[dd0*3+dd1] += evirial[dd0*3+dd1]; + } + } + for(int ii = 0; ii < pairs.size(); ++ii){ + int idx0 = pairs[ii].first; + int idx1 = pairs[ii].second; + for (int dd0 = 0; dd0 < 3; ++dd0){ + for (int dd1 = 0; dd1 < 3; ++dd1){ + virial[dd0*3+dd1] -= eforce[idx1*3+dd0] * dipole_recd[idx0*3+dd1]; + } + } + } + // compare virial + EXPECT_EQ(virial.size(), 3*3); + for(int ii = 0; ii < expected_v.size(); ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_v[ii]), 1e-5); + } +} + diff --git a/source/api_cc/tests/test_utils.h b/source/api_cc/tests/test_utils.h new file mode 100644 index 0000000000..4135f46498 --- /dev/null +++ b/source/api_cc/tests/test_utils.h @@ -0,0 +1,50 @@ +#pragma once + +inline void +_fold_back( + std::vector &out, + const std::vector &in, + const std::vector &mapping, + const int nloc, + const int nall, + const int ndim) +{ + out.resize(nloc*ndim); + std::copy(in.begin(), in.begin() + nloc*ndim, out.begin()); + for(int ii = nloc; ii < nall; ++ii){ + int in_idx = ii; + int out_idx = mapping[in_idx]; + for(int dd = 0; dd < ndim; ++dd){ + out[out_idx * ndim + dd] += in[in_idx * ndim + dd]; + } + } +} + +inline void +_build_nlist( + std::vector> &nlist_data, + std::vector & coord_cpy, + std::vector & atype_cpy, + std::vector & mapping, + const std::vector & coord, + const std::vector & atype, + const std::vector & box, + const float & rc) +{ + SimulationRegion region; + region.reinitBox(&box[0]); + std::vector ncell, ngcell; + copy_coord(coord_cpy, atype_cpy, mapping, ncell, ngcell, coord, atype, rc, region); + std::vector nat_stt, ext_stt, ext_end; + nat_stt.resize(3); + ext_stt.resize(3); + ext_end.resize(3); + for (int dd = 0; dd < 3; ++dd){ + ext_stt[dd] = -ngcell[dd]; + ext_end[dd] = ncell[dd] + ngcell[dd]; + } + int nloc = coord.size() / 3; + int nall = coord_cpy.size() / 3; + std::vector> nlist_r_cpy; + build_nlist(nlist_data, nlist_r_cpy, coord_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); +} From 1623569f784feb63f90ae6ac51909b4186cf92db Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 10 Mar 2021 14:54:37 +0800 Subject: [PATCH 249/562] add destructor for InputNlist --- source/lib/include/neighbor_list.h | 1 + 1 file changed, 1 insertion(+) diff --git a/source/lib/include/neighbor_list.h b/source/lib/include/neighbor_list.h index 58d5f150ed..174fad1a9f 100644 --- a/source/lib/include/neighbor_list.h +++ b/source/lib/include/neighbor_list.h @@ -27,6 +27,7 @@ struct InputNlist ) : inum(inum_), ilist(ilist_), numneigh(numneigh_), firstneigh(firstneigh_) {}; + ~InputNlist(){}; }; void convert_nlist( From 03016888891e84fcc92005ac92889d6397437c1c Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 10 Mar 2021 14:55:49 +0800 Subject: [PATCH 250/562] freeze output_dim in tensor models --- deepmd/entrypoints/freeze.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deepmd/entrypoints/freeze.py b/deepmd/entrypoints/freeze.py index c42ae2f968..d47dffaf87 100755 --- a/deepmd/entrypoints/freeze.py +++ b/deepmd/entrypoints/freeze.py @@ -76,11 +76,13 @@ def _make_node_names(model_type: str, modifier_type: Optional[str] = None) -> Li nodes += [ "o_polar", "model_attr/sel_type", + "model_attr/output_dim", ] elif model_type == "global_polar": nodes += [ "o_global_polar", "model_attr/sel_type", + "model_attr/output_dim", ] else: raise RuntimeError(f"unknow model type {model_type}") From 10116bfdba429d5d252b77af90eaab7887e1017d Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 10 Mar 2021 14:56:18 +0800 Subject: [PATCH 251/562] DipoleChargeModifier determine number of atoms by input vector of atom types --- deepmd/infer/data_modifier.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/deepmd/infer/data_modifier.py b/deepmd/infer/data_modifier.py index 1cf4446f7d..0db33c2b02 100644 --- a/deepmd/infer/data_modifier.py +++ b/deepmd/infer/data_modifier.py @@ -235,8 +235,10 @@ def eval(self, tot_v The virial modification """ + atype = np.array(atype, dtype=int) coord, atype, imap = self.sort_input(coord, atype) - natoms = coord.shape[1] // 3 + # natoms = coord.shape[1] // 3 + natoms = atype.size nframes = coord.shape[0] box = np.reshape(box, [nframes, 9]) atype = np.reshape(atype, [natoms]) From ad2f64d58f61eedf340a950e8504d4b3375e56df Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 10 Mar 2021 15:07:42 +0800 Subject: [PATCH 252/562] clean up outdated commented code --- source/api_cc/src/common.cc | 292 ------------------------------------ 1 file changed, 292 deletions(-) diff --git a/source/api_cc/src/common.cc b/source/api_cc/src/common.cc index 0bbce93120..4603c82492 100644 --- a/source/api_cc/src/common.cc +++ b/source/api_cc/src/common.cc @@ -152,44 +152,6 @@ make_inlist(InputNlist & inlist) inlist.firstneigh = &firstneigh[0]; } -// void -// shuffle_nlist_exclude_empty (InternalNeighborList & list, -// const std::vector & fwd_map) -// { -// int old_nloc = fwd_map.size(); -// shuffle_nlist(list, fwd_map); -// std::vector new_ilist, new_jrange, new_jlist, new_icount; -// new_ilist.reserve(list.ilist.size()); -// new_icount.reserve(list.ilist.size()); -// new_jrange.reserve(list.jrange.size()); -// new_jlist.reserve(list.jlist.size()); -// for(int ii = 0; ii < list.ilist.size(); ++ii){ -// if(list.ilist[ii] >= 0){ -// new_ilist.push_back(list.ilist[ii]); -// } -// } -// new_jrange.resize(new_ilist.size()+1); -// new_jrange[0] = 0; -// int ci = 0; -// for(int ii = 0; ii < list.ilist.size(); ++ii){ -// if (list.ilist[ii] < 0) continue; -// int js = list.jrange[ii]; -// int je = list.jrange[ii+1]; -// int cc = 0; -// for (int jj = js; jj < je; ++jj){ -// if (list.jlist[jj] >= 0) { -// new_jlist.push_back(list.jlist[jj]); -// cc++; -// } -// } -// new_jrange[ci+1] = new_jrange[ci] + cc; -// ci ++; -// } -// list.ilist = new_ilist; -// list.jrange = new_jrange; -// list.jlist = new_jlist; -// } - void checkStatus(const tensorflow::Status& status) { if (!status.ok()) { @@ -492,257 +454,3 @@ session_input_tensors (std::vector> & input_tenso return nloc; } -// int -// session_input_tensors (std::vector> & input_tensors, -// const std::vector & dcoord_, -// const int & ntypes, -// const std::vector & datype_, -// const std::vector & dbox, -// InternalNeighborList & dlist, -// const std::vector & fparam_, -// const std::vector & aparam_, -// const NNPAtomMap& nnpmap, -// const int nghost, -// const std::string scope) -// { -// assert (dbox.size() == 9); - -// int nframes = 1; -// int nall = dcoord_.size() / 3; -// int nloc = nall - nghost; -// assert (nall == datype_.size()); - -// std::vector datype = nnpmap.get_type(); -// std::vector type_count (ntypes, 0); -// for (unsigned ii = 0; ii < datype.size(); ++ii){ -// type_count[datype[ii]] ++; -// } -// datype.insert (datype.end(), datype_.begin() + nloc, datype_.end()); - -// TensorShape coord_shape ; -// coord_shape.AddDim (nframes); -// coord_shape.AddDim (nall * 3); -// TensorShape type_shape ; -// type_shape.AddDim (nframes); -// type_shape.AddDim (nall); -// TensorShape box_shape ; -// box_shape.AddDim (nframes); -// box_shape.AddDim (9); -// TensorShape mesh_shape ; -// mesh_shape.AddDim (16); -// TensorShape natoms_shape ; -// natoms_shape.AddDim (2 + ntypes); -// TensorShape fparam_shape ; -// fparam_shape.AddDim (nframes); -// fparam_shape.AddDim (fparam_.size()); -// TensorShape aparam_shape ; -// aparam_shape.AddDim (nframes); -// aparam_shape.AddDim (aparam_.size()); - -// #ifdef HIGH_PREC -// Tensor coord_tensor (DT_DOUBLE, coord_shape); -// Tensor box_tensor (DT_DOUBLE, box_shape); -// Tensor fparam_tensor (DT_DOUBLE, fparam_shape); -// Tensor aparam_tensor (DT_DOUBLE, aparam_shape); -// #else -// Tensor coord_tensor (DT_FLOAT, coord_shape); -// Tensor box_tensor (DT_FLOAT, box_shape); -// Tensor fparam_tensor (DT_FLOAT, fparam_shape); -// Tensor aparam_tensor (DT_FLOAT, aparam_shape); -// #endif -// Tensor type_tensor (DT_INT32, type_shape); -// Tensor mesh_tensor (DT_INT32, mesh_shape); -// Tensor natoms_tensor (DT_INT32, natoms_shape); - -// auto coord = coord_tensor.matrix (); -// auto type = type_tensor.matrix (); -// auto box = box_tensor.matrix (); -// auto mesh = mesh_tensor.flat (); -// auto natoms = natoms_tensor.flat (); -// auto fparam = fparam_tensor.matrix (); -// auto aparam = aparam_tensor.matrix (); - -// std::vector dcoord (dcoord_); -// nnpmap.forward (dcoord.begin(), dcoord_.begin(), 3); - -// for (int ii = 0; ii < nframes; ++ii){ -// for (int jj = 0; jj < nall * 3; ++jj){ -// coord(ii, jj) = dcoord[jj]; -// } -// for (int jj = 0; jj < 9; ++jj){ -// box(ii, jj) = dbox[jj]; -// } -// for (int jj = 0; jj < nall; ++jj){ -// type(ii, jj) = datype[jj]; -// } -// for (int jj = 0; jj < fparam_.size(); ++jj){ -// fparam(ii, jj) = fparam_[jj]; -// } -// for (int jj = 0; jj < aparam_.size(); ++jj){ -// aparam(ii, jj) = aparam_[jj]; -// } -// } - -// for (int ii = 0; ii < 16; ++ii) mesh(ii) = 0; - -// mesh (0) = sizeof(int *) / sizeof(int); -// assert (mesh(0) * sizeof(int) == sizeof(int *)); -// const int & stride = mesh(0); -// mesh (1) = dlist.ilist.size(); -// assert (mesh(1) == nloc); -// assert (stride <= 4); -// dlist.make_ptrs(); -// memcpy (&mesh(4), &(dlist.pilist), sizeof(int *)); -// memcpy (&mesh(8), &(dlist.pjrange), sizeof(int *)); -// memcpy (&mesh(12), &(dlist.pjlist), sizeof(int *)); - -// natoms (0) = nloc; -// natoms (1) = nall; -// for (int ii = 0; ii < ntypes; ++ii) natoms(ii+2) = type_count[ii]; - -// std::string prefix = ""; -// if (scope != ""){ -// prefix = scope + "/"; -// } -// input_tensors = { -// {prefix+"t_coord", coord_tensor}, -// {prefix+"t_type", type_tensor}, -// {prefix+"t_box", box_tensor}, -// {prefix+"t_mesh", mesh_tensor}, -// {prefix+"t_natoms",natoms_tensor}, -// }; -// if (fparam_.size() > 0) { -// input_tensors.push_back({prefix+"t_fparam", fparam_tensor}); -// } -// if (aparam_.size() > 0) { -// input_tensors.push_back({prefix+"t_aparam", aparam_tensor}); -// } - -// return nloc; -// } - -// int -// session_input_tensors ( -// std::vector> & input_tensors, -// const std::vector & dcoord_, -// const int & ntypes, -// const std::vector & datype_, -// const std::vector & dbox, -// const int * ilist, -// const int * jrange, -// const int * jlist, -// const std::vector & fparam_, -// const std::vector & aparam_, -// const NNPAtomMap & nnpmap, -// const int & nghost) -// { -// assert (dbox.size() == 9); - -// int nframes = 1; -// int nall = dcoord_.size() / 3; -// int nloc = nall - nghost; -// assert (nall == datype_.size()); - -// std::vector datype = nnpmap.get_type(); -// std::vector type_count (ntypes, 0); -// for (unsigned ii = 0; ii < datype.size(); ++ii) { -// type_count[datype[ii]] ++; -// } -// datype.insert (datype.end(), datype_.begin() + nloc, datype_.end()); - -// TensorShape coord_shape ; -// coord_shape.AddDim (nframes); -// coord_shape.AddDim (nall * 3); -// TensorShape type_shape ; -// type_shape.AddDim (nframes); -// type_shape.AddDim (nall); -// TensorShape box_shape ; -// box_shape.AddDim (nframes); -// box_shape.AddDim (9); -// TensorShape mesh_shape; -// mesh_shape.AddDim (16); -// TensorShape natoms_shape; -// natoms_shape.AddDim (2 + ntypes); -// TensorShape fparam_shape; -// fparam_shape.AddDim (nframes); -// fparam_shape.AddDim (fparam_.size()); -// TensorShape aparam_shape ; -// aparam_shape.AddDim (nframes); -// aparam_shape.AddDim (aparam_.size()); - -// #ifdef HIGH_PREC -// Tensor coord_tensor (DT_DOUBLE, coord_shape); -// Tensor box_tensor (DT_DOUBLE, box_shape); -// Tensor fparam_tensor(DT_DOUBLE, fparam_shape); -// Tensor aparam_tensor(DT_DOUBLE, fparam_shape); -// #else -// Tensor coord_tensor (DT_FLOAT, coord_shape); -// Tensor box_tensor (DT_FLOAT, box_shape); -// Tensor fparam_tensor(DT_FLOAT, fparam_shape); -// Tensor aparam_tensor(DT_FLOAT, fparam_shape); -// #endif -// Tensor type_tensor (DT_INT32, type_shape); -// Tensor mesh_tensor (DT_INT32, mesh_shape); -// Tensor natoms_tensor(DT_INT32, natoms_shape); - -// auto coord = coord_tensor.matrix (); -// auto type = type_tensor.matrix (); -// auto box = box_tensor.matrix (); -// auto mesh = mesh_tensor.flat (); -// auto natoms = natoms_tensor.flat (); -// auto fparam = fparam_tensor.matrix (); -// auto aparam = aparam_tensor.matrix (); - -// std::vector dcoord (dcoord_); -// nnpmap.forward (dcoord.begin(), dcoord_.begin(), 3); - -// for (int ii = 0; ii < nframes; ++ii) { -// for (int jj = 0; jj < nall * 3; ++jj) { -// coord(ii, jj) = dcoord[jj]; -// } -// for (int jj = 0; jj < 9; ++jj) { -// box(ii, jj) = dbox[jj]; -// } -// for (int jj = 0; jj < nall; ++jj) { -// type(ii, jj) = datype[jj]; -// } -// for (int jj = 0; jj < fparam_.size(); ++jj) { -// fparam(ii, jj) = fparam_[jj]; -// } -// for (int jj = 0; jj < aparam_.size(); ++jj) { -// aparam(ii, jj) = aparam_[jj]; -// } -// } - -// for (int ii = 0; ii < 16; ++ii) mesh(ii) = 0; - -// mesh (0) = sizeof(int *) / sizeof(int); -// assert (mesh(0) * sizeof(int) == sizeof(int *)); -// const int & stride = mesh(0); -// // mesh (1) = dlist.ilist.size(); -// mesh (1) = nloc; -// assert (mesh(1) == nloc); -// assert (stride <= 4); -// memcpy (&mesh(4), &(ilist), sizeof(int *)); -// memcpy (&mesh(8), &(jrange), sizeof(int *)); -// memcpy (&mesh(12), &(jlist), sizeof(int *)); - -// natoms (0) = nloc; -// natoms (1) = nall; -// for (int ii = 0; ii < ntypes; ++ii) natoms(ii+2) = type_count[ii]; - -// input_tensors = { -// {"t_coord", coord_tensor}, -// {"t_type", type_tensor}, -// {"t_box", box_tensor}, -// {"t_mesh", mesh_tensor}, -// {"t_natoms", natoms_tensor}, -// }; -// if (fparam_.size() > 0) { -// input_tensors.push_back({"t_fparam", fparam_tensor}); -// } -// if (aparam_.size() > 0) { -// input_tensors.push_back({"t_aparam", aparam_tensor}); -// } -// return nloc; -// } From 41a05014812b50a0b029d7cf089fc558244e818b Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 10 Mar 2021 02:41:20 -0500 Subject: [PATCH 253/562] add test CI for api_cc --- source/api_cc/tests/CMakeLists.txt | 2 +- .../CMakeLists.txt.in => cmake/googletest.cmake.in} | 0 source/install/test_cc.sh | 12 ++++++++++++ source/lib/tests/CMakeLists.txt | 2 +- 4 files changed, 14 insertions(+), 2 deletions(-) rename source/{lib/tests/CMakeLists.txt.in => cmake/googletest.cmake.in} (100%) diff --git a/source/api_cc/tests/CMakeLists.txt b/source/api_cc/tests/CMakeLists.txt index 4ffa71de3d..6015c00166 100644 --- a/source/api_cc/tests/CMakeLists.txt +++ b/source/api_cc/tests/CMakeLists.txt @@ -86,7 +86,7 @@ add_test( runUnitTests runUnitTests ) find_package(GTest) if(NOT GTEST_LIBRARY) - configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt) + configure_file(../../cmake/googletest.cmake.in googletest-download/CMakeLists.txt) execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . RESULT_VARIABLE result WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) diff --git a/source/lib/tests/CMakeLists.txt.in b/source/cmake/googletest.cmake.in similarity index 100% rename from source/lib/tests/CMakeLists.txt.in rename to source/cmake/googletest.cmake.in diff --git a/source/install/test_cc.sh b/source/install/test_cc.sh index 6464a9a904..ecab79ab24 100755 --- a/source/install/test_cc.sh +++ b/source/install/test_cc.sh @@ -16,3 +16,15 @@ make -j${NPROC} #------------------ ${BUILD_TMP_DIR}/runUnitTests + +#------------------ + +BUILD_TMP_DIR=${SCRIPT_PATH}/../build_cc_tests +mkdir -p ${BUILD_TMP_DIR} +cd ${BUILD_TMP_DIR} +cmake ../api_cc/tests +make -j${NPROC} + +#------------------ +${BUILD_TMP_DIR}/runUnitTests + diff --git a/source/lib/tests/CMakeLists.txt b/source/lib/tests/CMakeLists.txt index c3b54f2a09..874f9768a2 100644 --- a/source/lib/tests/CMakeLists.txt +++ b/source/lib/tests/CMakeLists.txt @@ -59,7 +59,7 @@ add_test( runUnitTests runUnitTests ) find_package(GTest) if(NOT GTEST_LIBRARY) - configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt) + configure_file(../../cmake/googletest.cmake.in googletest-download/CMakeLists.txt) execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . RESULT_VARIABLE result WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) From 94480b62311c87531a1addd05c133fb30ec47931 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 10 Mar 2021 02:58:36 -0500 Subject: [PATCH 254/562] install tensorflow --- source/install/test_cc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/install/test_cc.sh b/source/install/test_cc.sh index ecab79ab24..23426e4b4e 100755 --- a/source/install/test_cc.sh +++ b/source/install/test_cc.sh @@ -22,7 +22,7 @@ ${BUILD_TMP_DIR}/runUnitTests BUILD_TMP_DIR=${SCRIPT_PATH}/../build_cc_tests mkdir -p ${BUILD_TMP_DIR} cd ${BUILD_TMP_DIR} -cmake ../api_cc/tests +cmake -DINSTALL_TENSORFLOW=TRUE ../api_cc/tests make -j${NPROC} #------------------ From 296cafe5cbf6bca820d4e7dd2425d6f26e0e1373 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 10 Mar 2021 03:11:29 -0500 Subject: [PATCH 255/562] set INSTALL_PREFIX --- source/install/test_cc.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/install/test_cc.sh b/source/install/test_cc.sh index 23426e4b4e..0c5333f41c 100755 --- a/source/install/test_cc.sh +++ b/source/install/test_cc.sh @@ -20,9 +20,11 @@ ${BUILD_TMP_DIR}/runUnitTests #------------------ BUILD_TMP_DIR=${SCRIPT_PATH}/../build_cc_tests +INSTALL_PREFIX=${SCRIPT_PATH}/../../dp mkdir -p ${BUILD_TMP_DIR} +mkdir -p ${INSTALL_PREFIX} cd ${BUILD_TMP_DIR} -cmake -DINSTALL_TENSORFLOW=TRUE ../api_cc/tests +cmake -DINSTALL_TENSORFLOW=TRUE -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} ../api_cc/tests make -j${NPROC} #------------------ From 1e0f71db172b9a525b4330bae7675fccc0a157e9 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 10 Mar 2021 06:04:46 -0500 Subject: [PATCH 256/562] change the directory of version.h --- source/api_cc/tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/api_cc/tests/CMakeLists.txt b/source/api_cc/tests/CMakeLists.txt index 6015c00166..aedb5b0f20 100644 --- a/source/api_cc/tests/CMakeLists.txt +++ b/source/api_cc/tests/CMakeLists.txt @@ -28,7 +28,7 @@ file(GLOB API_SRC ${API_BASE_DIR}/src/*.cc ${API_BASE_DIR}/src/*.cpp) add_library(${apiname} SHARED ${API_SRC}) configure_file( ${API_BASE_DIR}/include/version.h.in - version.h + ${CMAKE_SOURCE_DIR}/version.h @ONLY ) From e2f92c11eff368f17e315ebeede3b7dbefd2c077 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 10 Mar 2021 22:45:11 +0800 Subject: [PATCH 257/562] clean up model devi, add unittests --- source/api_cc/include/NNPInter.h | 175 ++-- source/api_cc/src/NNPInter.cc | 884 +++++++++--------- .../api_cc/tests/test_deeppot_model_devi.cc | 160 ++++ source/lmp/fix_dplr.cpp | 4 +- source/lmp/fix_dplr.h | 2 +- source/lmp/pair_nnp.cpp | 6 +- source/tests/infer/deeppot-1.pbtxt | 12 +- 7 files changed, 694 insertions(+), 549 deletions(-) create mode 100644 source/api_cc/tests/test_deeppot_model_devi.cc diff --git a/source/api_cc/include/NNPInter.h b/source/api_cc/include/NNPInter.h index da89cdc0cd..2586bfd89e 100644 --- a/source/api_cc/include/NNPInter.h +++ b/source/api_cc/include/NNPInter.h @@ -92,106 +92,95 @@ class NNPInter std::vector sec_a; compute_t *array_double; NeighborListData nlist_data; + InputNlist nlist; NNPAtomMap nnpmap; - int *ilist, *jrange, *jlist; - int ilist_size, jrange_size, jlist_size; // function used for neighbor list copy std::vector get_sel_a() const; }; -// class NNPInterModelDevi -// { -// public: -// NNPInterModelDevi () ; -// ~NNPInterModelDevi() ; -// NNPInterModelDevi (const std::vector & models, const int & gpu_rank = 0, const std::vector & file_contents = std::vector()); -// void init (const std::vector & models, const int & gpu_rank = 0, const std::vector & file_contents = std::vector()); -// public: -// void compute (ENERGYTYPE & ener, -// std::vector & force, -// std::vector & virial, -// std::vector & model_devi, -// const std::vector & coord, -// const std::vector & atype, -// const std::vector & box, -// const std::vector & fparam = std::vector(), -// const std::vector & aparam = std::vector()); -// void compute (std::vector & all_ener, -// std::vector > & all_force, -// std::vector > & all_virial, -// const std::vector & coord, -// const std::vector & atype, -// const std::vector & box, -// const int nghost, -// const LammpsNeighborList & lmp_list, -// const int & ago, -// const std::vector & fparam = std::vector(), -// const std::vector & aparam = std::vector()); -// void compute (std::vector & all_ener, -// std::vector > & all_force, -// std::vector > & all_virial, -// std::vector > & all_atom_energy, -// std::vector > & all_atom_virial, -// const std::vector & coord, -// const std::vector & atype, -// const std::vector & box, -// const int nghost, -// const LammpsNeighborList & lmp_list, -// const int & ago, -// const std::vector & fparam = std::vector(), -// const std::vector & aparam = std::vector()); -// VALUETYPE cutoff () const {assert(inited); return rcut;}; -// int numb_types () const {assert(inited); return ntypes;}; -// int dim_fparam () const {assert(inited); return dfparam;}; -// int dim_aparam () const {assert(inited); return daparam;}; -// #ifndef HIGH_PREC -// void compute_avg (ENERGYTYPE & dener, -// const std::vector & all_energy); -// #endif -// void compute_avg (VALUETYPE & dener, -// const std::vector & all_energy); -// void compute_avg (std::vector & avg, -// const std::vector > & xx); -// void compute_std_e (std::vector & std, -// const std::vector & avg, -// const std::vector >& xx); -// void compute_std_f (std::vector & std, -// const std::vector & avg, -// const std::vector >& xx); -// void compute_relative_std_f (std::vector & std, -// const std::vector & avg, -// const VALUETYPE eps); -// private: -// unsigned numb_models; -// std::vector sessions; -// int num_intra_nthreads, num_inter_nthreads; -// std::vector graph_defs; -// bool inited; -// template VT get_scalar(const std::string name) const; -// // VALUETYPE get_rcut () const; -// // int get_ntypes () const; -// VALUETYPE rcut; -// VALUETYPE cell_size; -// int ntypes; -// int dfparam; -// int daparam; -// void validate_fparam_aparam(const int & nloc, -// const std::vector &fparam, -// const std::vector &aparam)const ; +class NNPInterModelDevi +{ +public: + NNPInterModelDevi () ; + ~NNPInterModelDevi() ; + NNPInterModelDevi (const std::vector & models, const int & gpu_rank = 0, const std::vector & file_contents = std::vector()); + void init (const std::vector & models, const int & gpu_rank = 0, const std::vector & file_contents = std::vector()); +public: + void compute (std::vector & all_ener, + std::vector > & all_force, + std::vector > & all_virial, + const std::vector & coord, + const std::vector & atype, + const std::vector & box, + const int nghost, + const InputNlist & lmp_list, + const int & ago, + const std::vector & fparam = std::vector(), + const std::vector & aparam = std::vector()); + void compute (std::vector & all_ener, + std::vector > & all_force, + std::vector > & all_virial, + std::vector > & all_atom_energy, + std::vector > & all_atom_virial, + const std::vector & coord, + const std::vector & atype, + const std::vector & box, + const int nghost, + const InputNlist & lmp_list, + const int & ago, + const std::vector & fparam = std::vector(), + const std::vector & aparam = std::vector()); + VALUETYPE cutoff () const {assert(inited); return rcut;}; + int numb_types () const {assert(inited); return ntypes;}; + int dim_fparam () const {assert(inited); return dfparam;}; + int dim_aparam () const {assert(inited); return daparam;}; +#ifndef HIGH_PREC + void compute_avg (ENERGYTYPE & dener, + const std::vector & all_energy); +#endif + void compute_avg (VALUETYPE & dener, + const std::vector & all_energy); + void compute_avg (std::vector & avg, + const std::vector > & xx); + void compute_std_e (std::vector & std, + const std::vector & avg, + const std::vector >& xx); + void compute_std_f (std::vector & std, + const std::vector & avg, + const std::vector >& xx); + void compute_relative_std_f (std::vector & std, + const std::vector & avg, + const VALUETYPE eps); +private: + unsigned numb_models; + std::vector sessions; + int num_intra_nthreads, num_inter_nthreads; + std::vector graph_defs; + bool inited; + template VT get_scalar(const std::string name) const; + // VALUETYPE get_rcut () const; + // int get_ntypes () const; + VALUETYPE rcut; + VALUETYPE cell_size; + int ntypes; + int dfparam; + int daparam; + void validate_fparam_aparam(const int & nloc, + const std::vector &fparam, + const std::vector &aparam)const ; -// // copy neighbor list info from host -// bool init_nbor; -// compute_t *array_double; -// std::vector > sec; -// InternalNeighborList nlist; -// NNPAtomMap nnpmap; -// int *ilist, *jrange, *jlist; -// int ilist_size, jrange_size, jlist_size; + // copy neighbor list info from host + bool init_nbor; + compute_t *array_double; + std::vector > sec; + NNPAtomMap nnpmap; + NeighborListData nlist_data; + InputNlist nlist; -// // function used for nborlist copy -// std::vector > get_sel() const; -// void cum_sum(const std::vector > n_sel); -// }; + // function used for nborlist copy + std::vector > get_sel() const; + void cum_sum(const std::vector > n_sel); +}; diff --git a/source/api_cc/src/NNPInter.cc b/source/api_cc/src/NNPInter.cc index cfb17a314c..55686bde81 100644 --- a/source/api_cc/src/NNPInter.cc +++ b/source/api_cc/src/NNPInter.cc @@ -173,12 +173,14 @@ NNPInter:: NNPInter () : inited (false), init_nbor (false) { + get_env_nthreads(num_intra_nthreads, num_inter_nthreads); } NNPInter:: NNPInter (const std::string & model, const int & gpu_rank, const std::string & file_content) : inited (false), init_nbor (false) { + get_env_nthreads(num_intra_nthreads, num_inter_nthreads); init(model, gpu_rank, file_content); } @@ -226,8 +228,6 @@ init (const std::string & model, const int & gpu_rank, const std::string & file_ inited = true; init_nbor = false; - ilist = NULL; jrange = NULL; jlist = NULL; - ilist_size = 0; jrange_size = 0; jlist_size = 0; } void @@ -346,7 +346,7 @@ compute (ENERGYTYPE & dener, const std::vector & datype_, const std::vector & dbox, const int nghost, - const InputNlist & inlist, + const InputNlist & lmp_list, const int& ago, const std::vector & fparam, const std::vector & aparam_) @@ -368,7 +368,7 @@ compute (ENERGYTYPE & dener, } // internal nlist if (ago == 0){ - nlist_data.copy_from_nlist(inlist); + nlist_data.copy_from_nlist(lmp_list); nlist_data.shuffle_exclude_empty(fwd_map); } compute_inner(dener, dforce, dvirial, dcoord, datype, dbox, nghost_real, ago, fparam, aparam); @@ -401,10 +401,9 @@ compute_inner (ENERGYTYPE & dener, nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); assert (nloc == nnpmap.get_type().size()); nlist_data.shuffle(nnpmap); + nlist_data.make_inlist(nlist); } - InputNlist inlist; - nlist_data.make_inlist(inlist); - int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, inlist, fparam, aparam, nnpmap, nghost, ago); + int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, nnpmap, nghost, ago); assert (nloc == ret); run_model (dener, dforce_, dvirial, session, input_tensors, nnpmap, nghost); } @@ -445,7 +444,7 @@ compute (ENERGYTYPE & dener, const std::vector & datype_, const std::vector & dbox, const int nghost, - const InputNlist & nlist, + const InputNlist & lmp_list, const int & ago, const std::vector & fparam, const std::vector & aparam) @@ -458,14 +457,13 @@ compute (ENERGYTYPE & dener, if (ago == 0) { nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); assert (nloc == nnpmap.get_type().size()); - // make internal nlist data - nlist_data.copy_from_nlist(nlist); + + nlist_data.copy_from_nlist(lmp_list); nlist_data.shuffle(nnpmap); + nlist_data.make_inlist(nlist); } - InputNlist inlist; - nlist_data.make_inlist(inlist); - int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, inlist, fparam, aparam, nnpmap, nghost, ago); + int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, nnpmap, nghost, ago); assert (nloc == ret); run_model (dener, dforce_, dvirial, datom_energy_, datom_virial_, session, input_tensors, nnpmap, nghost); } @@ -478,448 +476,446 @@ get_type_map(std::string & type_map){ -// // NNPInterModelDevi:: -// // NNPInterModelDevi () -// // : inited (false), -// // init_nbor (false), -// // numb_models (0) -// // { -// // get_env_nthreads(num_intra_nthreads, num_inter_nthreads); -// // } - -// // NNPInterModelDevi:: -// // NNPInterModelDevi (const std::vector & models, const int & gpu_rank, const std::vector & file_contents) -// // : inited (false), -// // init_nbor(false), -// // numb_models (0) -// // { -// // get_env_nthreads(num_intra_nthreads, num_inter_nthreads); -// // init(models, gpu_rank, file_contents); -// // } - -// // NNPInterModelDevi::~NNPInterModelDevi() {} - -// // void -// // NNPInterModelDevi:: -// // init (const std::vector & models, const int & gpu_rank, const std::vector & file_contents) -// // { -// // if (inited){ -// // std::cerr << "WARNING: deepmd-kit should not be initialized twice, do nothing at the second call of initializer" << std::endl; -// // return ; -// // } -// // numb_models = models.size(); -// // sessions.resize(numb_models); -// // graph_defs.resize(numb_models); - -// // int gpu_num = -1; -// // #if GOOGLE_CUDA -// // cudaGetDeviceCount(&gpu_num); -// // #endif // GOOGLE_CUDA - -// // SessionOptions options; -// // options.config.set_inter_op_parallelism_threads(num_inter_nthreads); -// // options.config.set_intra_op_parallelism_threads(num_intra_nthreads); -// // for (unsigned ii = 0; ii < numb_models; ++ii){ -// // if (file_contents.size() == 0) -// // checkStatus (ReadBinaryProto(Env::Default(), models[ii], &graph_defs[ii])); -// // else -// // graph_defs[ii].ParseFromString(file_contents[ii]); -// // } -// // #if GOOGLE_CUDA -// // if (gpu_num > 0) { -// // options.config.set_allow_soft_placement(true); -// // options.config.mutable_gpu_options()->set_per_process_gpu_memory_fraction(0.9); -// // options.config.mutable_gpu_options()->set_allow_growth(true); -// // cudaErrcheck(cudaSetDevice(gpu_rank % gpu_num)); -// // } -// // #endif // GOOGLE_CUDA - -// // for (unsigned ii = 0; ii < numb_models; ++ii) { -// // if (gpu_num > 0) { -// // std::string str = "/gpu:"; -// // str += std::to_string(gpu_rank % gpu_num); -// // graph::SetDefaultDevice(str, &graph_defs[ii]); -// // } -// // checkStatus (NewSession(options, &(sessions[ii]))); -// // checkStatus (sessions[ii]->Create(graph_defs[ii])); -// // } -// // rcut = get_scalar("descrpt_attr/rcut"); -// // cell_size = rcut; -// // ntypes = get_scalar("descrpt_attr/ntypes"); -// // dfparam = get_scalar("fitting_attr/dfparam"); -// // daparam = get_scalar("fitting_attr/daparam"); -// // if (dfparam < 0) dfparam = 0; -// // if (daparam < 0) daparam = 0; -// // // rcut = get_rcut(); -// // // cell_size = rcut; -// // // ntypes = get_ntypes(); -// // inited = true; - -// // init_nbor = false; -// // ilist = NULL; jrange = NULL; jlist = NULL; -// // ilist_size = 0; jrange_size = 0; jlist_size = 0; -// // } - -// // template -// // VT -// // NNPInterModelDevi:: -// // get_scalar(const std::string name) const -// // { -// // VT myrcut = 0; -// // for (unsigned ii = 0; ii < numb_models; ++ii){ -// // VT ret = session_get_scalar(sessions[ii], name); -// // if (ii == 0){ -// // myrcut = ret; -// // } -// // else { -// // assert (myrcut == ret); -// // } -// // } -// // return myrcut; -// // } - -// // // init the tmp array data -// // std::vector > -// // NNPInterModelDevi:: -// // get_sel () const -// // { -// // std::vector > sec; -// // for (int ii = 0; ii < numb_models; ii++) { -// // std::vector sel; -// // std::istringstream is(graph_info(graph_defs[ii])); -// // std::string line = ""; -// // while(is >> line) { -// // if (line.find("sel") != line.npos) { -// // while (std::getline(is, line) && line != "}") { -// // if (line.find("i:") != line.npos) { -// // sel.push_back(atoi((line.substr(line.find("i:") + 2)).c_str())); -// // } -// // } break; -// // } -// // if (line.find("sel_a") != line.npos) { -// // while (std::getline(is, line) && line != "}") { -// // if (line.find("i:") != line.npos) { -// // sel.push_back(atoi((line.substr(line.find("i:") + 2)).c_str())); -// // } -// // } break; -// // } -// // } -// // sec.push_back(sel); -// // } -// // return sec; -// // } - -// // void -// // NNPInterModelDevi:: -// // cum_sum (const std::vector > n_sel) -// // { -// // for (int ii = 0; ii < numb_models; ++ii) { -// // std::vector _sec; -// // _sec.resize (n_sel[ii].size() + 1); -// // _sec[0] = 0; -// // for (int jj = 1; jj < _sec.size(); ++jj) { -// // _sec[jj] = _sec[jj-1] + n_sel[ii][jj-1]; -// // } -// // sec.push_back(_sec); -// // } -// // } - -// // void -// // NNPInterModelDevi:: -// // validate_fparam_aparam(const int & nloc, -// // const std::vector &fparam, -// // const std::vector &aparam)const -// // { -// // if (fparam.size() != dfparam) { -// // throw std::runtime_error("the dim of frame parameter provided is not consistent with what the model uses"); -// // } -// // if (aparam.size() != daparam * nloc) { -// // throw std::runtime_error("the dim of atom parameter provided is not consistent with what the model uses"); -// // } -// // } - -// // void -// // NNPInterModelDevi:: -// // compute (ENERGYTYPE & dener, -// // std::vector & dforce_, -// // std::vector & dvirial, -// // std::vector & model_devi, -// // const std::vector & dcoord_, -// // const std::vector & datype_, -// // const std::vector & dbox, -// // const std::vector & fparam, -// // const std::vector & aparam) -// // { -// // if (numb_models == 0) return; - -// // nnpmap = NNPAtomMap (datype_.begin(), datype_.end()); -// // validate_fparam_aparam(nnpmap.get_type().size(), fparam, aparam); - -// // std::vector> input_tensors; -// // int nloc = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, fparam, aparam, nnpmap); - -// // std::vector all_energy (numb_models); -// // std::vector > all_force (numb_models); -// // std::vector > all_virial (numb_models); - -// // for (unsigned ii = 0; ii < numb_models; ++ii){ -// // run_model (all_energy[ii], all_force[ii], all_virial[ii], sessions[ii], input_tensors, nnpmap); -// // } - -// // dener = 0; -// // for (unsigned ii = 0; ii < numb_models; ++ii){ -// // dener += all_energy[ii]; -// // } -// // dener /= VALUETYPE(numb_models); -// // compute_avg (dvirial, all_virial); -// // compute_avg (dforce_, all_force); - -// // compute_std_f (model_devi, dforce_, all_force); - -// // // for (unsigned ii = 0; ii < numb_models; ++ii){ -// // // cout << all_force[ii][573] << " " << all_force[ii][574] << " " << all_force[ii][575] << endl; -// // // } -// // // cout << dforce_[573] << " " -// // // << dforce_[574] << " " -// // // << dforce_[575] << " " -// // // << model_devi[191] << endl; -// // } - -// // void -// // NNPInterModelDevi:: -// // compute (std::vector & all_energy, -// // std::vector> & all_force, -// // std::vector> & all_virial, -// // const std::vector & dcoord_, -// // const std::vector & datype_, -// // const std::vector & dbox, -// // const int nghost, -// // const LammpsNeighborList & lmp_list, -// // const int & ago, -// // const std::vector & fparam, -// // const std::vector & aparam) -// // { -// // if (numb_models == 0) return; -// // int nall = dcoord_.size() / 3; -// // int nloc = nall - nghost; -// // validate_fparam_aparam(nloc, fparam, aparam); -// // std::vector> input_tensors; - -// // // agp == 0 means that the LAMMPS nbor list has been updated -// // if (ago == 0) { -// // nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); -// // assert (nloc == nnpmap.get_type().size()); - -// // // InternalNeighborList nlist; -// // convert_nlist_lmp_internal (nlist, lmp_list); -// // shuffle_nlist (nlist, nnpmap); -// // } -// // int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, nnpmap, nghost, ago); - -// // all_energy.resize (numb_models); -// // all_force.resize (numb_models); -// // all_virial.resize (numb_models); -// // assert (nloc == ret); -// // for (unsigned ii = 0; ii < numb_models; ++ii) { -// // run_model (all_energy[ii], all_force[ii], all_virial[ii], sessions[ii], input_tensors, nnpmap, nghost); -// // } -// // } - -// // void -// // NNPInterModelDevi:: -// // compute (std::vector & all_energy, -// // std::vector> & all_force, -// // std::vector> & all_virial, -// // std::vector> & all_atom_energy, -// // std::vector> & all_atom_virial, -// // const std::vector & dcoord_, -// // const std::vector & datype_, -// // const std::vector & dbox, -// // const int nghost, -// // const LammpsNeighborList & lmp_list, -// // const int & ago, -// // const std::vector & fparam, -// // const std::vector & aparam) -// // { -// // if (numb_models == 0) return; -// // int nall = dcoord_.size() / 3; -// // int nloc = nall - nghost; -// // validate_fparam_aparam(nloc, fparam, aparam); -// // std::vector> input_tensors; - -// // // agp == 0 means that the LAMMPS nbor list has been updated -// // if (ago == 0) { -// // nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); -// // assert (nloc == nnpmap.get_type().size()); - -// // // InternalNeighborList nlist; -// // convert_nlist_lmp_internal (nlist, lmp_list); -// // shuffle_nlist (nlist, nnpmap); -// // } -// // int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, nnpmap, nghost, ago); - -// // all_energy.resize (numb_models); -// // all_force .resize (numb_models); -// // all_virial.resize (numb_models); -// // all_atom_energy.resize (numb_models); -// // all_atom_virial.resize (numb_models); -// // assert (nloc == ret); -// // for (unsigned ii = 0; ii < numb_models; ++ii) { -// // run_model (all_energy[ii], all_force[ii], all_virial[ii], all_atom_energy[ii], all_atom_virial[ii], sessions[ii], input_tensors, nnpmap, nghost); -// // } -// // } - -// // void -// // NNPInterModelDevi:: -// // compute_avg (VALUETYPE & dener, -// // const std::vector & all_energy) -// // { -// // assert (all_energy.size() == numb_models); -// // if (numb_models == 0) return; - -// // dener = 0; -// // for (unsigned ii = 0; ii < numb_models; ++ii){ -// // dener += all_energy[ii]; -// // } -// // dener /= (VALUETYPE)(numb_models); -// // } - -// // #ifndef HIGH_PREC -// // void -// // NNPInterModelDevi:: -// // compute_avg (ENERGYTYPE & dener, -// // const std::vector& all_energy) -// // { -// // assert (all_energy.size() == numb_models); -// // if (numb_models == 0) return; - -// // dener = 0; -// // for (unsigned ii = 0; ii < numb_models; ++ii){ -// // dener += all_energy[ii]; -// // } -// // dener /= (ENERGYTYPE)(numb_models); -// // } -// // #endif - -// // void -// // NNPInterModelDevi:: -// // compute_avg (std::vector & avg, -// // const std::vector > & xx) -// // { -// // assert (xx.size() == numb_models); -// // if (numb_models == 0) return; +NNPInterModelDevi:: +NNPInterModelDevi () + : inited (false), + init_nbor (false), + numb_models (0) +{ + get_env_nthreads(num_intra_nthreads, num_inter_nthreads); +} + +NNPInterModelDevi:: +NNPInterModelDevi (const std::vector & models, const int & gpu_rank, const std::vector & file_contents) + : inited (false), + init_nbor(false), + numb_models (0) +{ + get_env_nthreads(num_intra_nthreads, num_inter_nthreads); + init(models, gpu_rank, file_contents); +} + +NNPInterModelDevi::~NNPInterModelDevi() {} + +void +NNPInterModelDevi:: +init (const std::vector & models, const int & gpu_rank, const std::vector & file_contents) +{ + if (inited){ + std::cerr << "WARNING: deepmd-kit should not be initialized twice, do nothing at the second call of initializer" << std::endl; + return ; + } + numb_models = models.size(); + sessions.resize(numb_models); + graph_defs.resize(numb_models); -// // avg.resize(xx[0].size()); -// // fill (avg.begin(), avg.end(), VALUETYPE(0.)); + int gpu_num = -1; + #if GOOGLE_CUDA + cudaGetDeviceCount(&gpu_num); + #endif // GOOGLE_CUDA + + SessionOptions options; + options.config.set_inter_op_parallelism_threads(num_inter_nthreads); + options.config.set_intra_op_parallelism_threads(num_intra_nthreads); + for (unsigned ii = 0; ii < numb_models; ++ii){ + if (file_contents.size() == 0) + checkStatus (ReadBinaryProto(Env::Default(), models[ii], &graph_defs[ii])); + else + graph_defs[ii].ParseFromString(file_contents[ii]); + } + #if GOOGLE_CUDA + if (gpu_num > 0) { + options.config.set_allow_soft_placement(true); + options.config.mutable_gpu_options()->set_per_process_gpu_memory_fraction(0.9); + options.config.mutable_gpu_options()->set_allow_growth(true); + cudaErrcheck(cudaSetDevice(gpu_rank % gpu_num)); + } + #endif // GOOGLE_CUDA + + for (unsigned ii = 0; ii < numb_models; ++ii) { + if (gpu_num > 0) { + std::string str = "/gpu:"; + str += std::to_string(gpu_rank % gpu_num); + graph::SetDefaultDevice(str, &graph_defs[ii]); + } + checkStatus (NewSession(options, &(sessions[ii]))); + checkStatus (sessions[ii]->Create(graph_defs[ii])); + } + rcut = get_scalar("descrpt_attr/rcut"); + cell_size = rcut; + ntypes = get_scalar("descrpt_attr/ntypes"); + dfparam = get_scalar("fitting_attr/dfparam"); + daparam = get_scalar("fitting_attr/daparam"); + if (dfparam < 0) dfparam = 0; + if (daparam < 0) daparam = 0; + // rcut = get_rcut(); + // cell_size = rcut; + // ntypes = get_ntypes(); + inited = true; -// // for (unsigned ii = 0; ii < numb_models; ++ii){ -// // for (unsigned jj = 0; jj < avg.size(); ++jj){ -// // avg[jj] += xx[ii][jj]; -// // } -// // } - -// // for (unsigned jj = 0; jj < avg.size(); ++jj){ -// // avg[jj] /= VALUETYPE(numb_models); -// // } -// // } - - -// // // void -// // // NNPInterModelDevi:: -// // // compute_std (VALUETYPE & std, -// // // const VALUETYPE & avg, -// // // const vector& xx) -// // // { -// // // std = 0; -// // // assert(xx.size() == numb_models); -// // // for (unsigned jj = 0; jj < xx.size(); ++jj){ -// // // std += (xx[jj] - avg) * (xx[jj] - avg); -// // // } -// // // std = sqrt(std / VALUETYPE(numb_models)); -// // // // std = sqrt(std / VALUETYPE(numb_models-)); -// // // } - -// // void -// // NNPInterModelDevi:: -// // compute_std_e (std::vector & std, -// // const std::vector & avg, -// // const std::vector >&xx) -// // { -// // assert (xx.size() == numb_models); -// // if (numb_models == 0) return; - -// // unsigned ndof = avg.size(); -// // unsigned nloc = ndof; -// // assert (nloc == ndof); + init_nbor = false; +} + +template +VT +NNPInterModelDevi:: +get_scalar(const std::string name) const +{ + VT myrcut = 0; + for (unsigned ii = 0; ii < numb_models; ++ii){ + VT ret = session_get_scalar(sessions[ii], name); + if (ii == 0){ + myrcut = ret; + } + else { + assert (myrcut == ret); + } + } + return myrcut; +} + +// init the tmp array data +std::vector > +NNPInterModelDevi:: +get_sel () const +{ + std::vector > sec; + for (int ii = 0; ii < numb_models; ii++) { + std::vector sel; + std::istringstream is(graph_info(graph_defs[ii])); + std::string line = ""; + while(is >> line) { + if (line.find("sel") != line.npos) { + while (std::getline(is, line) && line != "}") { + if (line.find("i:") != line.npos) { + sel.push_back(atoi((line.substr(line.find("i:") + 2)).c_str())); + } + } break; + } + if (line.find("sel_a") != line.npos) { + while (std::getline(is, line) && line != "}") { + if (line.find("i:") != line.npos) { + sel.push_back(atoi((line.substr(line.find("i:") + 2)).c_str())); + } + } break; + } + } + sec.push_back(sel); + } + return sec; +} + +void +NNPInterModelDevi:: +cum_sum (const std::vector > n_sel) +{ + for (int ii = 0; ii < numb_models; ++ii) { + std::vector _sec; + _sec.resize (n_sel[ii].size() + 1); + _sec[0] = 0; + for (int jj = 1; jj < _sec.size(); ++jj) { + _sec[jj] = _sec[jj-1] + n_sel[ii][jj-1]; + } + sec.push_back(_sec); + } +} + +void +NNPInterModelDevi:: +validate_fparam_aparam(const int & nloc, + const std::vector &fparam, + const std::vector &aparam)const +{ + if (fparam.size() != dfparam) { + throw std::runtime_error("the dim of frame parameter provided is not consistent with what the model uses"); + } + if (aparam.size() != daparam * nloc) { + throw std::runtime_error("the dim of atom parameter provided is not consistent with what the model uses"); + } +} + +// void +// NNPInterModelDevi:: +// compute (ENERGYTYPE & dener, +// std::vector & dforce_, +// std::vector & dvirial, +// std::vector & model_devi, +// const std::vector & dcoord_, +// const std::vector & datype_, +// const std::vector & dbox, +// const std::vector & fparam, +// const std::vector & aparam) +// { +// if (numb_models == 0) return; + +// nnpmap = NNPAtomMap (datype_.begin(), datype_.end()); +// validate_fparam_aparam(nnpmap.get_type().size(), fparam, aparam); + +// std::vector> input_tensors; +// int nloc = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, fparam, aparam, nnpmap); + +// std::vector all_energy (numb_models); +// std::vector > all_force (numb_models); +// std::vector > all_virial (numb_models); + +// for (unsigned ii = 0; ii < numb_models; ++ii){ +// run_model (all_energy[ii], all_force[ii], all_virial[ii], sessions[ii], input_tensors, nnpmap); +// } + +// dener = 0; +// for (unsigned ii = 0; ii < numb_models; ++ii){ +// dener += all_energy[ii]; +// } +// dener /= VALUETYPE(numb_models); +// compute_avg (dvirial, all_virial); +// compute_avg (dforce_, all_force); -// // std.resize(nloc); -// // fill (std.begin(), std.end(), VALUETYPE(0.)); +// compute_std_f (model_devi, dforce_, all_force); -// // for (unsigned ii = 0; ii < numb_models; ++ii) { -// // for (unsigned jj = 0 ; jj < nloc; ++jj){ -// // const VALUETYPE * tmp_f = &(xx[ii][jj]); -// // const VALUETYPE * tmp_avg = &(avg[jj]); -// // VALUETYPE vdiff = xx[ii][jj] - avg[jj]; -// // std[jj] += vdiff * vdiff; -// // } -// // } - -// // for (unsigned jj = 0; jj < nloc; ++jj){ -// // std[jj] = sqrt(std[jj] / VALUETYPE(numb_models)); -// // // std[jj] = sqrt(std[jj] / VALUETYPE(numb_models-1)); -// // } -// // } - -// // void -// // NNPInterModelDevi:: -// // compute_std_f (std::vector & std, -// // const std::vector & avg, -// // const std::vector >&xx) -// // { -// // assert (xx.size() == numb_models); -// // if (numb_models == 0) return; - -// // unsigned ndof = avg.size(); -// // unsigned nloc = ndof / 3; -// // assert (nloc * 3 == ndof); +// // for (unsigned ii = 0; ii < numb_models; ++ii){ +// // cout << all_force[ii][573] << " " << all_force[ii][574] << " " << all_force[ii][575] << endl; +// // } +// // cout << dforce_[573] << " " +// // << dforce_[574] << " " +// // << dforce_[575] << " " +// // << model_devi[191] << endl; +// } + +void +NNPInterModelDevi:: +compute (std::vector & all_energy, + std::vector> & all_force, + std::vector> & all_virial, + const std::vector & dcoord_, + const std::vector & datype_, + const std::vector & dbox, + const int nghost, + const InputNlist & lmp_list, + const int & ago, + const std::vector & fparam, + const std::vector & aparam) +{ + if (numb_models == 0) return; + int nall = dcoord_.size() / 3; + int nloc = nall - nghost; + validate_fparam_aparam(nloc, fparam, aparam); + std::vector> input_tensors; + + // agp == 0 means that the LAMMPS nbor list has been updated + if (ago == 0) { + nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); + assert (nloc == nnpmap.get_type().size()); + + nlist_data.copy_from_nlist(lmp_list); + nlist_data.shuffle(nnpmap); + nlist_data.make_inlist(nlist); + } + int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, nnpmap, nghost, ago); + + all_energy.resize (numb_models); + all_force.resize (numb_models); + all_virial.resize (numb_models); + assert (nloc == ret); + for (unsigned ii = 0; ii < numb_models; ++ii) { + run_model (all_energy[ii], all_force[ii], all_virial[ii], sessions[ii], input_tensors, nnpmap, nghost); + } +} + +void +NNPInterModelDevi:: +compute (std::vector & all_energy, + std::vector> & all_force, + std::vector> & all_virial, + std::vector> & all_atom_energy, + std::vector> & all_atom_virial, + const std::vector & dcoord_, + const std::vector & datype_, + const std::vector & dbox, + const int nghost, + const InputNlist & lmp_list, + const int & ago, + const std::vector & fparam, + const std::vector & aparam) +{ + if (numb_models == 0) return; + int nall = dcoord_.size() / 3; + int nloc = nall - nghost; + validate_fparam_aparam(nloc, fparam, aparam); + std::vector> input_tensors; + + // agp == 0 means that the LAMMPS nbor list has been updated + if (ago == 0) { + nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); + assert (nloc == nnpmap.get_type().size()); + + nlist_data.copy_from_nlist(lmp_list); + nlist_data.shuffle(nnpmap); + nlist_data.make_inlist(nlist); + } + int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, nnpmap, nghost, ago); + + all_energy.resize (numb_models); + all_force .resize (numb_models); + all_virial.resize (numb_models); + all_atom_energy.resize (numb_models); + all_atom_virial.resize (numb_models); + assert (nloc == ret); + for (unsigned ii = 0; ii < numb_models; ++ii) { + run_model (all_energy[ii], all_force[ii], all_virial[ii], all_atom_energy[ii], all_atom_virial[ii], sessions[ii], input_tensors, nnpmap, nghost); + } +} + +void +NNPInterModelDevi:: +compute_avg (VALUETYPE & dener, + const std::vector & all_energy) +{ + assert (all_energy.size() == numb_models); + if (numb_models == 0) return; + + dener = 0; + for (unsigned ii = 0; ii < numb_models; ++ii){ + dener += all_energy[ii]; + } + dener /= (VALUETYPE)(numb_models); +} + +#ifndef HIGH_PREC +void +NNPInterModelDevi:: +compute_avg (ENERGYTYPE & dener, + const std::vector& all_energy) +{ + assert (all_energy.size() == numb_models); + if (numb_models == 0) return; + + dener = 0; + for (unsigned ii = 0; ii < numb_models; ++ii){ + dener += all_energy[ii]; + } + dener /= (ENERGYTYPE)(numb_models); +} +#endif + +void +NNPInterModelDevi:: +compute_avg (std::vector & avg, + const std::vector > & xx) +{ + assert (xx.size() == numb_models); + if (numb_models == 0) return; -// // std.resize(nloc); -// // fill (std.begin(), std.end(), VALUETYPE(0.)); + avg.resize(xx[0].size()); + fill (avg.begin(), avg.end(), VALUETYPE(0.)); -// // for (unsigned ii = 0; ii < numb_models; ++ii) { -// for (unsigned jj = 0 ; jj < nloc; ++jj){ -// const VALUETYPE * tmp_f = &(xx[ii][jj*3]); -// const VALUETYPE * tmp_avg = &(avg[jj*3]); -// VALUETYPE vdiff[3]; -// vdiff[0] = tmp_f[0] - tmp_avg[0]; -// vdiff[1] = tmp_f[1] - tmp_avg[1]; -// vdiff[2] = tmp_f[2] - tmp_avg[2]; -// std[jj] += dot3(vdiff, vdiff); -// } -// } + for (unsigned ii = 0; ii < numb_models; ++ii){ + for (unsigned jj = 0; jj < avg.size(); ++jj){ + avg[jj] += xx[ii][jj]; + } + } + + for (unsigned jj = 0; jj < avg.size(); ++jj){ + avg[jj] /= VALUETYPE(numb_models); + } +} -// for (unsigned jj = 0; jj < nloc; ++jj){ -// std[jj] = sqrt(std[jj] / VALUETYPE(numb_models)); -// // std[jj] = sqrt(std[jj] / VALUETYPE(numb_models-1)); -// } -// } // void // NNPInterModelDevi:: -// compute_relative_std_f (std::vector &std, -// const std::vector &avg, -// const VALUETYPE eps) +// compute_std (VALUETYPE & std, +// const VALUETYPE & avg, +// const vector& xx) // { -// unsigned nloc = std.size(); -// for (unsigned ii = 0; ii < nloc; ++ii){ -// const VALUETYPE * tmp_avg = &(avg[ii*3]); -// VALUETYPE vdiff[3]; -// vdiff[0] = tmp_avg[0]; -// vdiff[1] = tmp_avg[1]; -// vdiff[2] = tmp_avg[2]; -// VALUETYPE f_norm = sqrt(dot3(vdiff, vdiff)); -// // relative std = std/(abs(f)+eps) -// std[ii] /= f_norm + eps; +// std = 0; +// assert(xx.size() == numb_models); +// for (unsigned jj = 0; jj < xx.size(); ++jj){ +// std += (xx[jj] - avg) * (xx[jj] - avg); // } +// std = sqrt(std / VALUETYPE(numb_models)); +// // std = sqrt(std / VALUETYPE(numb_models-)); // } +void +NNPInterModelDevi:: +compute_std_e (std::vector & std, + const std::vector & avg, + const std::vector >&xx) +{ + assert (xx.size() == numb_models); + if (numb_models == 0) return; + + unsigned ndof = avg.size(); + unsigned nloc = ndof; + assert (nloc == ndof); + + std.resize(nloc); + fill (std.begin(), std.end(), VALUETYPE(0.)); + + for (unsigned ii = 0; ii < numb_models; ++ii) { + for (unsigned jj = 0 ; jj < nloc; ++jj){ + const VALUETYPE * tmp_f = &(xx[ii][jj]); + const VALUETYPE * tmp_avg = &(avg[jj]); + VALUETYPE vdiff = xx[ii][jj] - avg[jj]; + std[jj] += vdiff * vdiff; + } + } + + for (unsigned jj = 0; jj < nloc; ++jj){ + std[jj] = sqrt(std[jj] / VALUETYPE(numb_models)); + // std[jj] = sqrt(std[jj] / VALUETYPE(numb_models-1)); + } +} + +void +NNPInterModelDevi:: +compute_std_f (std::vector & std, + const std::vector & avg, + const std::vector >&xx) +{ + assert (xx.size() == numb_models); + if (numb_models == 0) return; + + unsigned ndof = avg.size(); + unsigned nloc = ndof / 3; + assert (nloc * 3 == ndof); + + std.resize(nloc); + fill (std.begin(), std.end(), VALUETYPE(0.)); + + for (unsigned ii = 0; ii < numb_models; ++ii) { + for (unsigned jj = 0 ; jj < nloc; ++jj){ + const VALUETYPE * tmp_f = &(xx[ii][jj*3]); + const VALUETYPE * tmp_avg = &(avg[jj*3]); + VALUETYPE vdiff[3]; + vdiff[0] = tmp_f[0] - tmp_avg[0]; + vdiff[1] = tmp_f[1] - tmp_avg[1]; + vdiff[2] = tmp_f[2] - tmp_avg[2]; + std[jj] += dot3(vdiff, vdiff); + } + } + + for (unsigned jj = 0; jj < nloc; ++jj){ + std[jj] = sqrt(std[jj] / VALUETYPE(numb_models)); + // std[jj] = sqrt(std[jj] / VALUETYPE(numb_models-1)); + } +} + +void +NNPInterModelDevi:: +compute_relative_std_f (std::vector &std, + const std::vector &avg, + const VALUETYPE eps) +{ + unsigned nloc = std.size(); + for (unsigned ii = 0; ii < nloc; ++ii){ + const VALUETYPE * tmp_avg = &(avg[ii*3]); + VALUETYPE vdiff[3]; + vdiff[0] = tmp_avg[0]; + vdiff[1] = tmp_avg[1]; + vdiff[2] = tmp_avg[2]; + VALUETYPE f_norm = sqrt(dot3(vdiff, vdiff)); + // relative std = std/(abs(f)+eps) + std[ii] /= f_norm + eps; + } +} + diff --git a/source/api_cc/tests/test_deeppot_model_devi.cc b/source/api_cc/tests/test_deeppot_model_devi.cc new file mode 100644 index 0000000000..a911bcd4d8 --- /dev/null +++ b/source/api_cc/tests/test_deeppot_model_devi.cc @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include +#include "NNPInter.h" +#include "SimulationRegion.h" +#include "neighbor_list.h" +#include "test_utils.h" + +#include "google/protobuf/text_format.h" +#include "google/protobuf/io/zero_copy_stream_impl.h" +#include +#include +#include + +class TestInferDeepPotModeDevi : public ::testing::Test +{ +protected: + std::vector coord = { + 12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = { + 0, 1, 1, 0, 1, 1 + }; + std::vector box = { + 13., 0., 0., 0., 13., 0., 0., 0., 13. + }; + int natoms; + + NNPInter dp0; + NNPInter dp1; + NNPInterModelDevi dp_md; + + void SetUp() override { + { + std::string file_name = "../../tests/infer/deeppot.pbtxt"; + int fd = open(file_name.c_str(), O_RDONLY); + protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); + GraphDef graph_def; + protobuf::TextFormat::Parse(input, &graph_def); + delete input; + std::fstream output("deeppot.pb", std::ios::out | std::ios::trunc | std::ios::binary); + graph_def.SerializeToOstream(&output); + dp0.init("deeppot.pb"); + } + { + std::string file_name = "../../tests/infer/deeppot-1.pbtxt"; + int fd = open(file_name.c_str(), O_RDONLY); + protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); + GraphDef graph_def; + protobuf::TextFormat::Parse(input, &graph_def); + delete input; + std::fstream output("deeppot-1.pb", std::ios::out | std::ios::trunc | std::ios::binary); + graph_def.SerializeToOstream(&output); + dp1.init("deeppot-1.pb"); + } + dp_md.init(std::vector({"deeppot.pb", "deeppot-1.pb"})); + }; + + void TearDown() override { + remove( "deeppot.pb" ) ; + //remove( "deeppot-1.pb" ) ; + }; +}; + +TEST_F(TestInferDeepPotModeDevi, attrs) +{ + EXPECT_EQ(dp0.cutoff(), dp_md.cutoff()); + EXPECT_EQ(dp0.numb_types(), dp_md.numb_types()); + EXPECT_EQ(dp0.dim_fparam(), dp_md.dim_fparam()); + EXPECT_EQ(dp0.dim_aparam(), dp_md.dim_aparam()); + EXPECT_EQ(dp1.cutoff(), dp_md.cutoff()); + EXPECT_EQ(dp1.numb_types(), dp_md.numb_types()); + EXPECT_EQ(dp1.dim_fparam(), dp_md.dim_fparam()); + EXPECT_EQ(dp1.dim_aparam(), dp_md.dim_aparam()); +} + + +TEST_F(TestInferDeepPotModeDevi, cpu_lmp_list) +{ + float rc = dp_md.cutoff(); + int nloc = coord.size() / 3; + std::vector coord_cpy; + std::vector atype_cpy, mapping; + std::vector > nlist_data; + _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, + coord, atype, box, rc); + int nall = coord_cpy.size() / 3; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_data); + + int nmodel = 2; + std::vector edir(nmodel), emd; + std::vector > fdir_(nmodel), fdir(nmodel), vdir(nmodel), fmd_, fmd(nmodel), vmd; + dp0.compute(edir[0], fdir_[0], vdir[0], coord_cpy, atype_cpy, box, nall-nloc, inlist, 0); + dp1.compute(edir[1], fdir_[1], vdir[1], coord_cpy, atype_cpy, box, nall-nloc, inlist, 0); + dp_md.compute(emd, fmd_, vmd, coord_cpy, atype_cpy, box, nall-nloc, inlist, 0); + for(int kk = 0; kk < nmodel; ++kk){ + _fold_back(fdir[kk], fdir_[kk], mapping, nloc, nall, 3); + _fold_back(fmd[kk], fmd_[kk], mapping, nloc, nall, 3); + } + + + EXPECT_EQ(edir.size(), emd.size()); + EXPECT_EQ(fdir.size(), fmd.size()); + EXPECT_EQ(vdir.size(), vmd.size()); + for(int kk = 0; kk < nmodel; ++kk){ + EXPECT_EQ(fdir[kk].size(), fmd[kk].size()); + EXPECT_EQ(vdir[kk].size(), vmd[kk].size()); + } + for(int kk = 0; kk < nmodel; ++kk){ + EXPECT_LT(fabs(edir[kk] - emd[kk]), 1e-10); + for(int ii = 0; ii < fdir[0].size(); ++ii){ + EXPECT_LT(fabs(fdir[kk][ii] - fmd[kk][ii]), 1e-10); + } + for(int ii = 0; ii < vdir[0].size(); ++ii){ + EXPECT_LT(fabs(vdir[kk][ii] - vmd[kk][ii]), 1e-10); + } + } + + std::vector avg_f, std_f; + dp_md.compute_avg(avg_f, fmd); + dp_md.compute_std_f(std_f, avg_f, fmd); + + // manual compute std f + std::vector manual_std_f(nloc); + EXPECT_EQ(fmd[0].size(), nloc * 3); + for(int ii = 0; ii < nloc; ++ii){ + std::vector avg_f(3, 0.0); + for(int dd = 0; dd < 3; ++dd){ + for(int kk = 0; kk < nmodel; ++kk){ + avg_f[dd] += fmd[kk][ii*3+dd]; + } + avg_f[dd] /= (nmodel) * 1.0; + } + double std = 0.; + for(int kk = 0; kk < nmodel; ++kk){ + for(int dd = 0; dd < 3; ++dd){ + double tmp = fmd[kk][ii*3+dd] - avg_f[dd]; + std += tmp * tmp; + } + } + std /= nmodel * 1.0; + manual_std_f[ii] = sqrt(std); + } + + EXPECT_EQ(manual_std_f.size(), std_f.size()); + for(int ii = 0; ii < std_f.size(); ++ii){ + EXPECT_LT(fabs(manual_std_f[ii] - std_f[ii]), 1e-10); + } +} + diff --git a/source/lmp/fix_dplr.cpp b/source/lmp/fix_dplr.cpp index 03fef55420..637f36bda9 100644 --- a/source/lmp/fix_dplr.cpp +++ b/source/lmp/fix_dplr.cpp @@ -263,7 +263,7 @@ void FixDPLR::pre_force(int vflag) } // get lammps nlist NeighList * list = pair_nnp->list; - LammpsNeighborList lmp_list (list->inum, list->ilist, list->numneigh, list->firstneigh); + InputNlist lmp_list (list->inum, list->ilist, list->numneigh, list->firstneigh); // declear output vector tensor; // compute @@ -417,7 +417,7 @@ void FixDPLR::post_force(int vflag) } // lmp nlist NeighList * list = pair_nnp->list; - LammpsNeighborList lmp_list (list->inum, list->ilist, list->numneigh, list->firstneigh); + InputNlist lmp_list (list->inum, list->ilist, list->numneigh, list->firstneigh); // bonded pairs vector > valid_pairs; get_valid_pairs(valid_pairs); diff --git a/source/lmp/fix_dplr.h b/source/lmp/fix_dplr.h index e52215151c..a1bb7e1d60 100644 --- a/source/lmp/fix_dplr.h +++ b/source/lmp/fix_dplr.h @@ -37,7 +37,7 @@ namespace LAMMPS_NS { private: PairNNP * pair_nnp; DeepTensor dpt; - DataModifier dtm; + DipoleChargeModifier dtm; std::string model; int ntypes; std::vector sel_type; diff --git a/source/lmp/pair_nnp.cpp b/source/lmp/pair_nnp.cpp index fd2adb2729..401506df9f 100644 --- a/source/lmp/pair_nnp.cpp +++ b/source/lmp/pair_nnp.cpp @@ -360,7 +360,7 @@ void PairNNP::compute(int eflag, int vflag) multi_models_no_mod_devi = (numb_models > 1 && (out_freq == 0 || update->ntimestep % out_freq != 0)); multi_models_mod_devi = (numb_models > 1 && (out_freq > 0 && update->ntimestep % out_freq == 0)); if (do_ghost) { - LammpsNeighborList lmp_list (list->inum, list->ilist, list->numneigh, list->firstneigh); + InputNlist lmp_list (list->inum, list->ilist, list->numneigh, list->firstneigh); if (single_model || multi_models_no_mod_devi) { if ( ! (eflag_atom || vflag_atom) ) { #ifdef HIGH_PREC @@ -583,7 +583,7 @@ void PairNNP::compute(int eflag, int vflag) else { if (numb_models == 1) { #ifdef HIGH_PREC - nnp_inter.compute (dener, dforce, dvirial, dcoord, dtype, dbox, nghost); + nnp_inter.compute (dener, dforce, dvirial, dcoord, dtype, dbox); #else vector dcoord_(dcoord.size()); vector dbox_(dbox.size()); @@ -592,7 +592,7 @@ void PairNNP::compute(int eflag, int vflag) vector dforce_(dforce.size(), 0); vector dvirial_(dvirial.size(), 0); double dener_ = 0; - nnp_inter.compute (dener_, dforce_, dvirial_, dcoord_, dtype, dbox_, nghost); + nnp_inter.compute (dener_, dforce_, dvirial_, dcoord_, dtype, dbox_); for (unsigned dd = 0; dd < dforce.size(); ++dd) dforce[dd] = dforce_[dd]; for (unsigned dd = 0; dd < dvirial.size(); ++dd) dvirial[dd] = dvirial_[dd]; dener = dener_; diff --git a/source/tests/infer/deeppot-1.pbtxt b/source/tests/infer/deeppot-1.pbtxt index 4ad2deb6ff..3f8034de55 100644 --- a/source/tests/infer/deeppot-1.pbtxt +++ b/source/tests/infer/deeppot-1.pbtxt @@ -10515,8 +10515,8 @@ node { } } node { - name: "DescrptSeA" - op: "DescrptSeA" + name: "ProdEnvMatA" + op: "ProdEnvMatA" input: "Reshape_2" input: "Reshape_4" input: "t_natoms" @@ -10570,7 +10570,7 @@ node { node { name: "o_nlist" op: "Identity" - input: "DescrptSeA:3" + input: "ProdEnvMatA:3" attr { key: "T" value { @@ -10581,7 +10581,7 @@ node { node { name: "o_rij" op: "Identity" - input: "DescrptSeA:2" + input: "ProdEnvMatA:2" attr { key: "T" value { @@ -10592,7 +10592,7 @@ node { node { name: "o_rmat_deriv" op: "Identity" - input: "DescrptSeA:1" + input: "ProdEnvMatA:1" attr { key: "T" value { @@ -10603,7 +10603,7 @@ node { node { name: "Reshape_5" op: "Reshape" - input: "DescrptSeA" + input: "ProdEnvMatA" input: "Reshape_5/shape" attr { key: "T" From c3e950e80eb2a6e60fc78af846e1f1a4f0f1af9f Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 10 Mar 2021 22:50:39 +0800 Subject: [PATCH 258/562] add UT for model devi in the atomic case --- .../api_cc/tests/test_deeppot_model_devi.cc | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/source/api_cc/tests/test_deeppot_model_devi.cc b/source/api_cc/tests/test_deeppot_model_devi.cc index a911bcd4d8..0c3d3103fe 100644 --- a/source/api_cc/tests/test_deeppot_model_devi.cc +++ b/source/api_cc/tests/test_deeppot_model_devi.cc @@ -158,3 +158,60 @@ TEST_F(TestInferDeepPotModeDevi, cpu_lmp_list) } } + +TEST_F(TestInferDeepPotModeDevi, cpu_lmp_list_atomic) +{ + float rc = dp_md.cutoff(); + int nloc = coord.size() / 3; + std::vector coord_cpy; + std::vector atype_cpy, mapping; + std::vector > nlist_data; + _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, + coord, atype, box, rc); + int nall = coord_cpy.size() / 3; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_data); + + int nmodel = 2; + std::vector edir(nmodel), emd; + std::vector > fdir_(nmodel), fdir(nmodel), vdir(nmodel), fmd_, fmd(nmodel), vmd, aedir(nmodel), aemd, avdir(nmodel), avdir_(nmodel), avmd(nmodel), avmd_; + dp0.compute(edir[0], fdir_[0], vdir[0], aedir[0], avdir_[0], coord_cpy, atype_cpy, box, nall-nloc, inlist, 0); + dp1.compute(edir[1], fdir_[1], vdir[1], aedir[1], avdir_[1], coord_cpy, atype_cpy, box, nall-nloc, inlist, 0); + dp_md.compute(emd, fmd_, vmd, aemd, avmd_, coord_cpy, atype_cpy, box, nall-nloc, inlist, 0); + for(int kk = 0; kk < nmodel; ++kk){ + _fold_back(fdir[kk], fdir_[kk], mapping, nloc, nall, 3); + _fold_back(fmd[kk], fmd_[kk], mapping, nloc, nall, 3); + _fold_back(avdir[kk], avdir_[kk], mapping, nloc, nall, 9); + _fold_back(avmd[kk], avmd_[kk], mapping, nloc, nall, 9); + } + + EXPECT_EQ(edir.size(), emd.size()); + EXPECT_EQ(fdir.size(), fmd.size()); + EXPECT_EQ(vdir.size(), vmd.size()); + EXPECT_EQ(aedir.size(), aemd.size()); + EXPECT_EQ(avdir.size(), avmd.size()); + for(int kk = 0; kk < nmodel; ++kk){ + EXPECT_EQ(fdir[kk].size(), fmd[kk].size()); + EXPECT_EQ(vdir[kk].size(), vmd[kk].size()); + EXPECT_EQ(aedir[kk].size(), aemd[kk].size()); + EXPECT_EQ(avdir[kk].size(), avmd[kk].size()); + } + for(int kk = 0; kk < nmodel; ++kk){ + EXPECT_LT(fabs(edir[kk] - emd[kk]), 1e-10); + for(int ii = 0; ii < fdir[0].size(); ++ii){ + EXPECT_LT(fabs(fdir[kk][ii] - fmd[kk][ii]), 1e-10); + } + for(int ii = 0; ii < vdir[0].size(); ++ii){ + EXPECT_LT(fabs(vdir[kk][ii] - vmd[kk][ii]), 1e-10); + } + for(int ii = 0; ii < aedir[0].size(); ++ii){ + EXPECT_LT(fabs(aedir[kk][ii] - aemd[kk][ii]), 1e-10); + } + for(int ii = 0; ii < avdir[0].size(); ++ii){ + EXPECT_LT(fabs(avdir[kk][ii] - avmd[kk][ii]), 1e-10); + } + } +} + From 0fa68a163c977186405ba575156d8d68946f8973 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 10 Mar 2021 22:59:45 +0800 Subject: [PATCH 259/562] fall back to some old name convention --- source/api_cc/src/DataModifier.cc | 10 +++++----- source/api_cc/src/DeepTensor.cc | 20 +++++++++---------- .../api_cc/tests/test_deeppot_model_devi.cc | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/source/api_cc/src/DataModifier.cc b/source/api_cc/src/DataModifier.cc index 45ded50346..49e62be76c 100644 --- a/source/api_cc/src/DataModifier.cc +++ b/source/api_cc/src/DataModifier.cc @@ -125,7 +125,7 @@ compute (std::vector & dfcorr_, const std::vector>& pairs, const std::vector & delef_, const int nghost, - const InputNlist & nlist) + const InputNlist & lmp_list) { // firstly do selection int nall = datype_.size(); @@ -155,7 +155,7 @@ compute (std::vector & dfcorr_, select_map(datype_real, datype_, real_fwd_map, 1); // internal nlist NeighborListData nlist_data; - nlist_data.copy_from_nlist(nlist); + nlist_data.copy_from_nlist(lmp_list); nlist_data.shuffle_exclude_empty(real_fwd_map); // sort atoms NNPAtomMap nnpmap (datype_real.begin(), datype_real.begin() + nloc_real); @@ -164,11 +164,11 @@ compute (std::vector & dfcorr_, const std::vector & sort_bkw_map(nnpmap.get_bkw_map()); // shuffle nlist nlist_data.shuffle(nnpmap); - InputNlist inlist; - nlist_data.make_inlist(inlist); + InputNlist nlist; + nlist_data.make_inlist(nlist); // make input tensors std::vector> input_tensors; - int ret = session_input_tensors (input_tensors, dcoord_real, ntypes, datype_real, dbox, inlist, std::vector(), std::vector(), nnpmap, nghost_real, 0, name_scope); + int ret = session_input_tensors (input_tensors, dcoord_real, ntypes, datype_real, dbox, nlist, std::vector(), std::vector(), nnpmap, nghost_real, 0, name_scope); assert (nloc_real == ret); // make bond idx map std::vector bd_idx(nall, -1); diff --git a/source/api_cc/src/DeepTensor.cc b/source/api_cc/src/DeepTensor.cc index a26729d8ef..5a26b85a68 100644 --- a/source/api_cc/src/DeepTensor.cc +++ b/source/api_cc/src/DeepTensor.cc @@ -122,7 +122,7 @@ compute (std::vector & dtensor_, const std::vector & datype_, const std::vector & dbox, const int nghost, - const InputNlist & nlist) + const InputNlist & lmp_list) { std::vector dcoord; std::vector datype, fwd_map, bkw_map; @@ -136,11 +136,11 @@ compute (std::vector & dtensor_, select_map(datype, datype_, fwd_map, 1); // internal nlist NeighborListData nlist_data; - nlist_data.copy_from_nlist(nlist); + nlist_data.copy_from_nlist(lmp_list); nlist_data.shuffle_exclude_empty(fwd_map); - InputNlist inlist; - nlist_data.make_inlist(inlist); - compute_inner(dtensor_, dcoord, datype, dbox, nghost_real, inlist); + InputNlist nlist; + nlist_data.make_inlist(nlist); + compute_inner(dtensor_, dcoord, datype, dbox, nghost_real, nlist); } @@ -170,7 +170,7 @@ compute_inner (std::vector & dtensor_, const std::vector & datype_, const std::vector & dbox, const int nghost, - const InputNlist & nlist) + const InputNlist & nlist_) { int nall = dcoord_.size() / 3; int nloc = nall - nghost; @@ -178,13 +178,13 @@ compute_inner (std::vector & dtensor_, assert (nloc == nnpmap.get_type().size()); NeighborListData nlist_data; - nlist_data.copy_from_nlist(nlist); + nlist_data.copy_from_nlist(nlist_); nlist_data.shuffle(nnpmap); - InputNlist inlist; - nlist_data.make_inlist(inlist); + InputNlist nlist; + nlist_data.make_inlist(nlist); std::vector> input_tensors; - int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, inlist, std::vector(), std::vector(), nnpmap, nghost, 0, name_scope); + int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, std::vector(), std::vector(), nnpmap, nghost, 0, name_scope); assert (nloc == ret); run_model (dtensor_, session, input_tensors, nnpmap, nghost); diff --git a/source/api_cc/tests/test_deeppot_model_devi.cc b/source/api_cc/tests/test_deeppot_model_devi.cc index 0c3d3103fe..fced03d4eb 100644 --- a/source/api_cc/tests/test_deeppot_model_devi.cc +++ b/source/api_cc/tests/test_deeppot_model_devi.cc @@ -65,7 +65,7 @@ class TestInferDeepPotModeDevi : public ::testing::Test void TearDown() override { remove( "deeppot.pb" ) ; - //remove( "deeppot-1.pb" ) ; + remove( "deeppot-1.pb" ) ; }; }; From e30c7e5bc54f62f7fa2fbfcf4efcdfc0261f2106 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 10 Mar 2021 14:04:38 -0500 Subject: [PATCH 260/562] cd api_cc/tests --- source/install/test_cc.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/source/install/test_cc.sh b/source/install/test_cc.sh index 0c5333f41c..f28bff9e7b 100755 --- a/source/install/test_cc.sh +++ b/source/install/test_cc.sh @@ -28,5 +28,6 @@ cmake -DINSTALL_TENSORFLOW=TRUE -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} ../api_ make -j${NPROC} #------------------ +cd ${SCRIPT_PATH}/../api_cc/tests ${BUILD_TMP_DIR}/runUnitTests From 0d3f35833060774eb4cf980c870953abc494289b Mon Sep 17 00:00:00 2001 From: Han Wang Date: Thu, 11 Mar 2021 15:07:46 +0800 Subject: [PATCH 261/562] implement prod_env_mat_r on cpu, add unittests --- source/api_cc/tests/.gitignore | 5 + .../{test_deeppot.cc => test_deeppot_a.cc} | 18 +- source/api_cc/tests/test_deeppot_r.cc | 437 + source/op/prod_env_mat_multi_device.cc | 202 +- source/tests/infer/deeppot-r.pbtxt | 22458 ++++++++++++++++ .../{test_deeppot.py => test_deeppot_a.py} | 6 +- source/tests/test_deeppot_r.py | 290 + 7 files changed, 23360 insertions(+), 56 deletions(-) create mode 100644 source/api_cc/tests/.gitignore rename source/api_cc/tests/{test_deeppot.cc => test_deeppot_a.cc} (97%) create mode 100644 source/api_cc/tests/test_deeppot_r.cc create mode 100644 source/tests/infer/deeppot-r.pbtxt rename source/tests/{test_deeppot.py => test_deeppot_a.py} (99%) create mode 100644 source/tests/test_deeppot_r.py diff --git a/source/api_cc/tests/.gitignore b/source/api_cc/tests/.gitignore new file mode 100644 index 0000000000..2c32bfb8cf --- /dev/null +++ b/source/api_cc/tests/.gitignore @@ -0,0 +1,5 @@ +CTestTestfile.cmake +Makefile +cmake_install.cmake +runUnitTests +version.h diff --git a/source/api_cc/tests/test_deeppot.cc b/source/api_cc/tests/test_deeppot_a.cc similarity index 97% rename from source/api_cc/tests/test_deeppot.cc rename to source/api_cc/tests/test_deeppot_a.cc index e59677dd66..0a736a7b88 100644 --- a/source/api_cc/tests/test_deeppot.cc +++ b/source/api_cc/tests/test_deeppot_a.cc @@ -14,7 +14,7 @@ #include #include -class TestInferDeepPot : public ::testing::Test +class TestInferDeepPotA : public ::testing::Test { protected: std::vector coord = { @@ -83,7 +83,7 @@ class TestInferDeepPot : public ::testing::Test }; -TEST_F(TestInferDeepPot, cpu_build_nlist) +TEST_F(TestInferDeepPotA, cpu_build_nlist) { double ener; std::vector force, virial; @@ -101,7 +101,7 @@ TEST_F(TestInferDeepPot, cpu_build_nlist) } } -TEST_F(TestInferDeepPot, cpu_build_nlist_atomic) +TEST_F(TestInferDeepPotA, cpu_build_nlist_atomic) { double ener; std::vector force, virial, atom_ener, atom_vir; @@ -128,7 +128,7 @@ TEST_F(TestInferDeepPot, cpu_build_nlist_atomic) } -TEST_F(TestInferDeepPot, cpu_lmp_nlist) +TEST_F(TestInferDeepPotA, cpu_lmp_nlist) { float rc = dp.cutoff(); int nloc = coord.size() / 3; @@ -179,7 +179,7 @@ TEST_F(TestInferDeepPot, cpu_lmp_nlist) } -TEST_F(TestInferDeepPot, cpu_lmp_nlist_atomic) +TEST_F(TestInferDeepPotA, cpu_lmp_nlist_atomic) { float rc = dp.cutoff(); int nloc = coord.size() / 3; @@ -252,7 +252,7 @@ TEST_F(TestInferDeepPot, cpu_lmp_nlist_atomic) } -TEST_F(TestInferDeepPot, cpu_lmp_nlist_2rc) +TEST_F(TestInferDeepPotA, cpu_lmp_nlist_2rc) { float rc = dp.cutoff(); int nloc = coord.size() / 3; @@ -303,7 +303,7 @@ TEST_F(TestInferDeepPot, cpu_lmp_nlist_2rc) } -TEST_F(TestInferDeepPot, cpu_lmp_nlist_type_sel) +TEST_F(TestInferDeepPotA, cpu_lmp_nlist_type_sel) { float rc = dp.cutoff(); @@ -355,7 +355,7 @@ TEST_F(TestInferDeepPot, cpu_lmp_nlist_type_sel) -class TestInferDeepPotNoPbc : public ::testing::Test +class TestInferDeepPotANoPbc : public ::testing::Test { protected: std::vector coord = { @@ -418,7 +418,7 @@ class TestInferDeepPotNoPbc : public ::testing::Test }; }; -TEST_F(TestInferDeepPotNoPbc, cpu_build_nlist) +TEST_F(TestInferDeepPotANoPbc, cpu_build_nlist) { double ener; std::vector force, virial; diff --git a/source/api_cc/tests/test_deeppot_r.cc b/source/api_cc/tests/test_deeppot_r.cc new file mode 100644 index 0000000000..ca0511c810 --- /dev/null +++ b/source/api_cc/tests/test_deeppot_r.cc @@ -0,0 +1,437 @@ +#include +#include +#include +#include +#include +#include "NNPInter.h" +#include "SimulationRegion.h" +#include "neighbor_list.h" +#include "test_utils.h" + +#include "google/protobuf/text_format.h" +#include "google/protobuf/io/zero_copy_stream_impl.h" +#include +#include +#include + +class TestInferDeepPotR : public ::testing::Test +{ +protected: + std::vector coord = { + 12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = { + 0, 1, 1, 0, 1, 1 + }; + std::vector box = { + 13., 0., 0., 0., 13., 0., 0., 0., 13. + }; + std::vector expected_e = { + -9.320909762801588272e+01,-1.868020345400987878e+02,-1.868011172371355997e+02,-9.320868430396934912e+01,-1.868010398844378415e+02,-1.868016706555875999e+02 + }; + std::vector expected_f = { + 6.385312846474267391e-04,-6.460452911141417731e-03,-5.652405655332678417e-04,-7.516468794343579736e-03,1.128804614240160216e-03,5.531937784564192051e-03,1.914138124904981664e-03,5.601819906021693503e-03,-5.131359585752605541e-03,-4.847104424804288617e-03,1.992071550328819614e-03,-4.028159855157302516e-03,1.236340684486603517e-03,-5.373955841338794344e-03,8.312829460571366513e-03,8.574563125108854156e-03,3.111712681889538742e-03,-4.120007238692381148e-03 + }; + std::vector expected_v = { + 5.844056241889131371e-03,4.663973497239899614e-04,-2.268382127762904633e-03,4.663973497239897988e-04,2.349338784202595950e-03,-6.908546513234039253e-04,-2.268382127762904633e-03,-6.908546513234039253e-04,2.040499248150800561e-03,4.238130266437327605e-03,-1.539867187443782223e-04,-2.393101333240631613e-03,-1.539867187443782223e-04,4.410341945447907377e-04,9.544239698119633068e-06,-2.393101333240631613e-03,9.544239698119578858e-06,1.877785959095269654e-03,5.798992562057291543e-03,6.943392552230453693e-04,-1.180376879311998773e-03,6.943392552230453693e-04,1.686725132156275536e-03,-1.461632060145726542e-03,-1.180376879311998556e-03,-1.461632060145726325e-03,1.749543733794208444e-03,7.173915604192910439e-03,3.903218041111061569e-04,-5.747400467123527524e-04,3.903218041111061569e-04,1.208289706621179949e-03,-1.826828914132010932e-03,-5.747400467123527524e-04,-1.826828914132011148e-03,2.856960586657185906e-03,4.067553030177322240e-03,-3.267469855253819430e-05,-6.980667859103454904e-05,-3.267469855253830272e-05,1.387653029234650918e-03,-2.096820720698671855e-03,-6.980667859103444062e-05,-2.096820720698671855e-03,3.218305506720191278e-03,4.753992590355240674e-03,1.224911338353675992e-03,-1.683421934571502484e-03,1.224911338353676209e-03,7.332113564901583539e-04,-1.025577052190138451e-03,-1.683421934571502484e-03,-1.025577052190138234e-03,1.456681925652047018e-03 + }; + int natoms; + double expected_tot_e; + std::vectorexpected_tot_v; + + NNPInter dp; + + void SetUp() override { + std::string file_name = "../../tests/infer/deeppot-r.pbtxt"; + int fd = open(file_name.c_str(), O_RDONLY); + protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); + GraphDef graph_def; + protobuf::TextFormat::Parse(input, &graph_def); + delete input; + std::fstream output("deeppot.pb", std::ios::out | std::ios::trunc | std::ios::binary); + graph_def.SerializeToOstream(&output); + // check the string by the following commands + // string txt; + // protobuf::TextFormat::PrintToString(graph_def, &txt); + + dp.init("deeppot.pb"); + + natoms = expected_e.size(); + EXPECT_EQ(natoms * 3, expected_f.size()); + EXPECT_EQ(natoms * 9, expected_v.size()); + expected_tot_e = 0.; + expected_tot_v.resize(9); + std::fill(expected_tot_v.begin(), expected_tot_v.end(), 0.); + for(int ii = 0; ii < natoms; ++ii){ + expected_tot_e += expected_e[ii]; + } + for(int ii = 0; ii < natoms; ++ii){ + for(int dd = 0; dd < 9; ++dd){ + expected_tot_v[dd] += expected_v[ii*9+dd]; + } + } + }; + + void TearDown() override { + remove( "deeppot.pb" ) ; + }; +}; + + +TEST_F(TestInferDeepPotR, cpu_build_nlist) +{ + double ener; + std::vector force, virial; + dp.compute(ener, force, virial, coord, atype, box); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } +} + +TEST_F(TestInferDeepPotR, cpu_build_nlist_atomic) +{ + double ener; + std::vector force, virial, atom_ener, atom_vir; + dp.compute(ener, force, virial, atom_ener, atom_vir, coord, atype, box); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + EXPECT_EQ(atom_ener.size(), natoms); + EXPECT_EQ(atom_vir.size(), natoms*9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } + for(int ii = 0; ii < natoms; ++ii){ + EXPECT_LT(fabs(atom_ener[ii] - expected_e[ii]), 1e-10); + } + for(int ii = 0; ii < natoms*9; ++ii){ + EXPECT_LT(fabs(atom_vir[ii] - expected_v[ii]), 1e-10); + } +} + + +TEST_F(TestInferDeepPotR, cpu_lmp_nlist) +{ + float rc = dp.cutoff(); + int nloc = coord.size() / 3; + std::vector coord_cpy; + std::vector atype_cpy, mapping; + std::vector > nlist_data; + _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, + coord, atype, box, rc); + int nall = coord_cpy.size() / 3; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_data); + + double ener; + std::vector force_, virial; + dp.compute(ener, force_, virial, coord_cpy, atype_cpy, box, nall-nloc, inlist, 0); + std::vector force; + _fold_back(force, force_, mapping, nloc, nall, 3); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } + + ener = 0.; + std::fill(force_.begin(), force_.end(), 0.0); + std::fill(virial.begin(), virial.end(), 0.0); + dp.compute(ener, force_, virial, coord_cpy, atype_cpy, box, nall-nloc, inlist, 1); + _fold_back(force, force_, mapping, nloc, nall, 3); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } +} + + +TEST_F(TestInferDeepPotR, cpu_lmp_nlist_atomic) +{ + float rc = dp.cutoff(); + int nloc = coord.size() / 3; + std::vector coord_cpy; + std::vector atype_cpy, mapping; + std::vector > nlist_data; + _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, + coord, atype, box, rc); + int nall = coord_cpy.size() / 3; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_data); + + double ener; + std::vector force_, atom_ener_, atom_vir_, virial; + std::vector force, atom_ener, atom_vir; + dp.compute(ener, force_, virial, atom_ener_, atom_vir_, coord_cpy, atype_cpy, box, nall-nloc, inlist, 0); + _fold_back(force, force_, mapping, nloc, nall, 3); + _fold_back(atom_ener, atom_ener_, mapping, nloc, nall, 1); + _fold_back(atom_vir, atom_vir_, mapping, nloc, nall, 9); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + EXPECT_EQ(atom_ener.size(), natoms); + EXPECT_EQ(atom_vir.size(), natoms*9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } + for(int ii = 0; ii < natoms; ++ii){ + EXPECT_LT(fabs(atom_ener[ii] - expected_e[ii]), 1e-10); + } + for(int ii = 0; ii < natoms*9; ++ii){ + EXPECT_LT(fabs(atom_vir[ii] - expected_v[ii]), 1e-10); + } + + ener = 0.; + std::fill(force_.begin(), force_.end(), 0.0); + std::fill(virial.begin(), virial.end(), 0.0); + std::fill(atom_ener_.begin(), atom_ener_.end(), 0.0); + std::fill(atom_vir_.begin(), atom_vir_.end(), 0.0); + dp.compute(ener, force_, virial, atom_ener_, atom_vir_, coord_cpy, atype_cpy, box, nall-nloc, inlist, 1); + _fold_back(force, force_, mapping, nloc, nall, 3); + _fold_back(atom_ener, atom_ener_, mapping, nloc, nall, 1); + _fold_back(atom_vir, atom_vir_, mapping, nloc, nall, 9); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + EXPECT_EQ(atom_ener.size(), natoms); + EXPECT_EQ(atom_vir.size(), natoms*9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } + for(int ii = 0; ii < natoms; ++ii){ + EXPECT_LT(fabs(atom_ener[ii] - expected_e[ii]), 1e-10); + } + for(int ii = 0; ii < natoms*9; ++ii){ + EXPECT_LT(fabs(atom_vir[ii] - expected_v[ii]), 1e-10); + } +} + + +TEST_F(TestInferDeepPotR, cpu_lmp_nlist_2rc) +{ + float rc = dp.cutoff(); + int nloc = coord.size() / 3; + std::vector coord_cpy; + std::vector atype_cpy, mapping; + std::vector > nlist_data; + _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, + coord, atype, box, rc*2); + int nall = coord_cpy.size() / 3; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_data); + + double ener; + std::vector force_(nall*3, 0.0), virial(9, 0.0); + dp.compute(ener, force_, virial, coord_cpy, atype_cpy, box, nall-nloc, inlist, 0); + std::vector force; + _fold_back(force, force_, mapping, nloc, nall, 3); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } + + ener = 0.; + std::fill(force_.begin(), force_.end(), 0.0); + std::fill(virial.begin(), virial.end(), 0.0); + dp.compute(ener, force_, virial, coord_cpy, atype_cpy, box, nall-nloc, inlist, 1); + _fold_back(force, force_, mapping, nloc, nall, 3); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } +} + + +TEST_F(TestInferDeepPotR, cpu_lmp_nlist_type_sel) +{ + float rc = dp.cutoff(); + + // add vir atoms + int nvir = 2; + std::vector coord_vir(nvir*3); + std::vector atype_vir(nvir, 2); + for(int ii = 0; ii < nvir; ++ii){ + coord_vir[ii] = coord[ii]; + } + coord.insert(coord.begin(), coord_vir.begin(), coord_vir.end()); + atype.insert(atype.begin(), atype_vir.begin(), atype_vir.end()); + natoms += nvir; + std::vector expected_f_vir(nvir*3, 0.0); + expected_f.insert(expected_f.begin(), expected_f_vir.begin(), expected_f_vir.end()); + + // build nlist + int nloc = coord.size() / 3; + std::vector coord_cpy; + std::vector atype_cpy, mapping; + std::vector > nlist_data; + _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, + coord, atype, box, rc); + int nall = coord_cpy.size() / 3; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_data); + + // dp compute + double ener; + std::vector force_(nall*3, 0.0), virial(9, 0.0); + dp.compute(ener, force_, virial, coord_cpy, atype_cpy, box, nall-nloc, inlist, 0); + // fold back + std::vector force; + _fold_back(force, force_, mapping, nloc, nall, 3); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } +} + + + +class TestInferDeepPotRNoPbc : public ::testing::Test +{ +protected: + std::vector coord = { + 12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = { + 0, 1, 1, 0, 1, 1 + }; + std::vector box = {}; + std::vector expected_e = { + -9.321213823508108476e+01,-1.868044102481340758e+02,-1.868067983858651075e+02,-9.320899631301440991e+01,-1.868014559732615112e+02,-1.868017660713088617e+02 + }; + std::vector expected_f = { + 4.578151103701261042e-03,-1.917874111009987628e-03,-3.464546781179331930e-03,-4.578151103701261042e-03,1.917874111009987628e-03,3.464546781179331930e-03,-2.624402581721222913e-03,3.566275128489623933e-04,-2.859315986763691776e-04,-5.767787273464367384e-03,1.907053583551196647e-03,-3.889064429673861831e-03,1.786820066350549132e-04,-5.327197473636275694e-03,8.236236182834734409e-03,8.213507848550535492e-03,3.063516377236116545e-03,-4.061240154484504865e-03 + }; + std::vector expected_v = { + 1.984979026299632174e-03,-8.315452677741701822e-04,-1.502146290172694243e-03,-8.315452677741700738e-04,3.483500446080982317e-04,6.292774999372096039e-04,-1.502146290172694243e-03,6.292774999372097123e-04,1.136759354725281907e-03,1.402852790439301908e-03,-5.876815743732210226e-04,-1.061618327900012114e-03,-5.876815743732211311e-04,2.461909298049979960e-04,4.447320022283834766e-04,-1.061618327900012331e-03,4.447320022283834766e-04,8.033868427351443728e-04,4.143606961846296385e-03,-5.511382161123719835e-04,4.465413399437045397e-04,-5.511382161123719835e-04,1.082271054025323839e-04,-1.097918001262628728e-04,4.465413399437046481e-04,-1.097918001262628728e-04,1.220966982358671871e-04,5.263952004497593831e-03,2.395243710938091842e-04,-2.830378939414603329e-04,2.395243710938094010e-04,1.189969706598244898e-03,-1.805627331015851201e-03,-2.830378939414602245e-04,-1.805627331015851635e-03,2.801996513751836820e-03,2.208413501170402270e-03,5.331756287635716889e-05,-1.664423506603235218e-04,5.331756287635695205e-05,1.379626072862918072e-03,-2.094132943741625064e-03,-1.664423506603234133e-04,-2.094132943741625064e-03,3.199787996743366607e-03,4.047014004814953811e-03,1.137904999421357000e-03,-1.568106936614101698e-03,1.137904999421357217e-03,7.205982843216952307e-04,-1.011174600268313238e-03,-1.568106936614101698e-03,-1.011174600268313238e-03,1.435226522157425754e-03 + }; + int natoms; + double expected_tot_e; + std::vectorexpected_tot_v; + + NNPInter dp; + + void SetUp() override { + std::string file_name = "../../tests/infer/deeppot-r.pbtxt"; + int fd = open(file_name.c_str(), O_RDONLY); + protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); + GraphDef graph_def; + protobuf::TextFormat::Parse(input, &graph_def); + delete input; + std::fstream output("deeppot.pb", std::ios::out | std::ios::trunc | std::ios::binary); + graph_def.SerializeToOstream(&output); + + dp.init("deeppot.pb"); + + natoms = expected_e.size(); + EXPECT_EQ(natoms * 3, expected_f.size()); + EXPECT_EQ(natoms * 9, expected_v.size()); + expected_tot_e = 0.; + expected_tot_v.resize(9); + std::fill(expected_tot_v.begin(), expected_tot_v.end(), 0.); + for(int ii = 0; ii < natoms; ++ii){ + expected_tot_e += expected_e[ii]; + } + for(int ii = 0; ii < natoms; ++ii){ + for(int dd = 0; dd < 9; ++dd){ + expected_tot_v[dd] += expected_v[ii*9+dd]; + } + } + }; + + void TearDown() override { + remove( "deeppot.pb" ) ; + }; +}; + +TEST_F(TestInferDeepPotRNoPbc, cpu_build_nlist) +{ + double ener; + std::vector force, virial; + dp.compute(ener, force, virial, coord, atype, box); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } +} diff --git a/source/op/prod_env_mat_multi_device.cc b/source/op/prod_env_mat_multi_device.cc index 42310ed30b..09d365869a 100644 --- a/source/op/prod_env_mat_multi_device.cc +++ b/source/op/prod_env_mat_multi_device.cc @@ -80,6 +80,33 @@ _map_nlist_cpu( const int & nloc, const int & nnei); +template +static void +_prepare_coord_nlist_cpu( + OpKernelContext* context, + FPTYPE const ** coord, + std::vector & coord_cpy, + int const** type, + std::vector & type_cpy, + std::vector & idx_mapping, + InputNlist & inlist, + std::vector & ilist, + std::vector & numneigh, + std::vector & firstneigh, + std::vector> & jlist, + int & new_nall, + int & mem_cpy, + int & mem_nnei, + int & max_nbor_size, + const FPTYPE * box, + const int * mesh_tensor_data, + const int & nloc, + const int & nei_mode, + const float & rcut_r, + const int & max_cpy_trial, + const int & max_nnei_trial); + + template class ProdEnvMatAOp : public OpKernel { @@ -228,7 +255,6 @@ class ProdEnvMatAOp : public OpKernel { const FPTYPE * coord = p_coord + ff*nall*3; const FPTYPE * box = p_box + ff*9; const int * type = p_type + ff*nall; - std::vector idx_mapping; if(device == "GPU") { #if GOOGLE_CUDA @@ -254,46 +280,24 @@ class ProdEnvMatAOp : public OpKernel { #endif //GOOGLE_CUDA } else if (device == "CPU") { - int new_nall = nall; InputNlist inlist; - inlist.inum = nloc; - // some buffers, be free after prod_env_mat_a_cpu + // some buffers, be freed after the evaluation of this frame + std::vector idx_mapping; std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); std::vector> jlist(nloc); std::vector coord_cpy; std::vector type_cpy; - if(nei_mode != 3){ - // build nlist by myself - // normalize and copy coord - if(nei_mode == 1){ - int copy_ok = _norm_copy_coord_cpu( - coord_cpy, type_cpy, idx_mapping, new_nall, mem_cpy, - coord, box, type, nloc, max_cpy_trial, rcut_r); - OP_REQUIRES (context, copy_ok, errors::Aborted("cannot allocate mem for copied coords")); - coord = &coord_cpy[0]; - type = &type_cpy[0]; - } - // build nlist - int build_ok = _build_nlist_cpu( - ilist, numneigh, firstneigh, jlist, max_nbor_size, mem_nnei, - coord, nloc, new_nall, max_nnei_trial, rcut_r); - OP_REQUIRES (context, build_ok, errors::Aborted("cannot allocate mem for nlist")); - inlist.ilist = &ilist[0]; - inlist.numneigh = &numneigh[0]; - inlist.firstneigh = &firstneigh[0]; - } - else{ - // copy pointers to nlist data - memcpy(&inlist.ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy(&inlist.numneigh, 8 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy(&inlist.firstneigh, 12 + mesh_tensor.flat().data(), sizeof(int **)); - max_nbor_size = max_numneigh(inlist); - } + // prepare coord and nlist + _prepare_coord_nlist_cpu( + context, &coord, coord_cpy, &type, type_cpy, idx_mapping, + inlist, ilist, numneigh, firstneigh, jlist, + nall, mem_cpy, mem_nnei, max_nbor_size, + box, mesh_tensor.flat().data(), nloc, nei_mode, rcut_r, max_cpy_trial, max_nnei_trial); // launch the cpu compute function prod_env_mat_a_cpu( em, em_deriv, rij, nlist, - coord, type, inlist, max_nbor_size, avg, std, nloc, new_nall, rcut_r, rcut_r_smth, sec_a); + coord, type, inlist, max_nbor_size, avg, std, nloc, nall, rcut_r, rcut_r_smth, sec_a); // do nlist mapping if coords were copied if(b_nlist_map) _map_nlist_cpu(nlist, &idx_mapping[0], nloc, nnei); } @@ -334,6 +338,10 @@ class ProdEnvMatROp : public OpKernel { ndescrpt = sec.back() * 1; nnei = sec.back(); max_nbor_size = 1024; + max_cpy_trial = 100; + mem_cpy = 256; + max_nnei_trial = 100; + mem_nnei = 256; } void Compute(OpKernelContext* context) override { @@ -376,6 +384,28 @@ class ProdEnvMatROp : public OpKernel { OP_REQUIRES (context, (9 == box_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of box should be 9")); OP_REQUIRES (context, (ndescrpt == avg_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of avg should be ndescrpt")); OP_REQUIRES (context, (ndescrpt == std_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of std should be ndescrpt")); + + int nei_mode = 0; + bool b_nlist_map = false; + if (mesh_tensor.shape().dim_size(0) == 16) { + // lammps neighbor list + nei_mode = 3; + } + else if (mesh_tensor.shape().dim_size(0) == 6) { + // manual copied pbc + assert (nloc == nall); + nei_mode = 1; + b_nlist_map = true; + } + else if (mesh_tensor.shape().dim_size(0) == 0) { + // no pbc + assert (nloc == nall); + nei_mode = -1; + } + else { + throw std::runtime_error("invalid mesh tensor"); + } + // Create an output tensor TensorShape descrpt_shape ; descrpt_shape.AddDim (nsamples); @@ -412,14 +442,25 @@ class ProdEnvMatROp : public OpKernel { nlist_shape, &nlist_tensor)); - FPTYPE * em = descrpt_tensor->flat().data(); - FPTYPE * em_deriv = descrpt_deriv_tensor->flat().data(); - FPTYPE * rij = rij_tensor->flat().data(); - int * nlist = nlist_tensor->flat().data(); - const FPTYPE * coord = coord_tensor.flat().data(); + FPTYPE * p_em = descrpt_tensor->flat().data(); + FPTYPE * p_em_deriv = descrpt_deriv_tensor->flat().data(); + FPTYPE * p_rij = rij_tensor->flat().data(); + int * p_nlist = nlist_tensor->flat().data(); + const FPTYPE * p_coord = coord_tensor.flat().data(); + const FPTYPE * p_box = box_tensor.flat().data(); const FPTYPE * avg = avg_tensor.flat().data(); const FPTYPE * std = std_tensor.flat().data(); - const int * type = type_tensor.flat().data(); + const int * p_type = type_tensor.flat().data(); + + // loop over samples + for(int ff = 0; ff < nsamples; ++ff){ + FPTYPE * em = p_em + ff*nloc*ndescrpt; + FPTYPE * em_deriv = p_em_deriv + ff*nloc*ndescrpt*3; + FPTYPE * rij = p_rij + ff*nloc*nnei*3; + int * nlist = p_nlist + ff*nloc*nnei; + const FPTYPE * coord = p_coord + ff*nall*3; + const FPTYPE * box = p_box + ff*9; + const int * type = p_type + ff*nall; if(device == "GPU") { #if GOOGLE_CUDA @@ -445,13 +486,26 @@ class ProdEnvMatROp : public OpKernel { #endif //GOOGLE_CUDA } else if (device == "CPU") { - memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy (&jrange, 8 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy (&jlist, 12 + mesh_tensor.flat().data(), sizeof(int *)); + InputNlist inlist; + // some buffers, be freed after the evaluation of this frame + std::vector idx_mapping; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + std::vector> jlist(nloc); + std::vector coord_cpy; + std::vector type_cpy; + // prepare coord and nlist + _prepare_coord_nlist_cpu( + context, &coord, coord_cpy, &type, type_cpy, idx_mapping, + inlist, ilist, numneigh, firstneigh, jlist, + nall, mem_cpy, mem_nnei, max_nbor_size, + box, mesh_tensor.flat().data(), nloc, nei_mode, rcut, max_cpy_trial, max_nnei_trial); // launch the cpu compute function - // prod_env_mat_r_cpu( - // em, em_deriv, rij, nlist, - // coord, type, ilist, jrange, jlist, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); + prod_env_mat_r_cpu( + em, em_deriv, rij, nlist, + coord, type, inlist, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); + if(b_nlist_map) _map_nlist_cpu(nlist, &idx_mapping[0], nloc, nnei); + } } } @@ -465,6 +519,8 @@ class ProdEnvMatROp : public OpKernel { std::vector sec; std::vector sec_null; int nnei, ndescrpt, nloc, nall, max_nbor_size; + int mem_cpy, max_cpy_trial; + int mem_nnei, max_nnei_trial; std::string device; int * array_int = NULL; unsigned long long * array_longlong = NULL; @@ -473,6 +529,9 @@ class ProdEnvMatROp : public OpKernel { int ilist_size = 0, jrange_size = 0, jlist_size = 0; }; + + + template static int _norm_copy_coord_cpu( @@ -563,6 +622,61 @@ _map_nlist_cpu( } } +template +static void +_prepare_coord_nlist_cpu( + OpKernelContext* context, + FPTYPE const ** coord, + std::vector & coord_cpy, + int const** type, + std::vector & type_cpy, + std::vector & idx_mapping, + InputNlist & inlist, + std::vector & ilist, + std::vector & numneigh, + std::vector & firstneigh, + std::vector> & jlist, + int & new_nall, + int & mem_cpy, + int & mem_nnei, + int & max_nbor_size, + const FPTYPE * box, + const int * mesh_tensor_data, + const int & nloc, + const int & nei_mode, + const float & rcut_r, + const int & max_cpy_trial, + const int & max_nnei_trial) +{ + inlist.inum = nloc; + if(nei_mode != 3){ + // build nlist by myself + // normalize and copy coord + if(nei_mode == 1){ + int copy_ok = _norm_copy_coord_cpu( + coord_cpy, type_cpy, idx_mapping, new_nall, mem_cpy, + *coord, box, *type, nloc, max_cpy_trial, rcut_r); + OP_REQUIRES (context, copy_ok, errors::Aborted("cannot allocate mem for copied coords")); + *coord = &coord_cpy[0]; + *type = &type_cpy[0]; + } + // build nlist + int build_ok = _build_nlist_cpu( + ilist, numneigh, firstneigh, jlist, max_nbor_size, mem_nnei, + *coord, nloc, new_nall, max_nnei_trial, rcut_r); + OP_REQUIRES (context, build_ok, errors::Aborted("cannot allocate mem for nlist")); + inlist.ilist = &ilist[0]; + inlist.numneigh = &numneigh[0]; + inlist.firstneigh = &firstneigh[0]; + } + else{ + // copy pointers to nlist data + memcpy(&inlist.ilist, 4 + mesh_tensor_data, sizeof(int *)); + memcpy(&inlist.numneigh, 8 + mesh_tensor_data, sizeof(int *)); + memcpy(&inlist.firstneigh, 12 + mesh_tensor_data, sizeof(int **)); + max_nbor_size = max_numneigh(inlist); + } +} // Register the CPU kernels. diff --git a/source/tests/infer/deeppot-r.pbtxt b/source/tests/infer/deeppot-r.pbtxt new file mode 100644 index 0000000000..3ddd2effe4 --- /dev/null +++ b/source/tests/infer/deeppot-r.pbtxt @@ -0,0 +1,22458 @@ +node { + name: "o_atom_virial/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_14/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 9 + } + } + } +} +node { + name: "strided_slice_25/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_25/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_25/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "o_virial/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\t\000\000\000" + } + } + } +} +node { + name: "o_force/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_13/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_24/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_24/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_24/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "Reshape_17/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_12/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 138 + } + } + } +} +node { + name: "strided_slice_23/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_23/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_23/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "gradients/Slice_1_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_1_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_1_grad/stack" + op: "Pack" + input: "gradients/Slice_1_grad/Rank" + input: "gradients/Slice_1_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/Slice_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_grad/stack" + op: "Pack" + input: "gradients/Slice_grad/Rank" + input: "gradients/Slice_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/stack" + op: "Pack" + input: "gradients/filter_type_1/Slice_1_grad/Rank" + input: "gradients/filter_type_1/Slice_1_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/stack" + op: "Pack" + input: "gradients/filter_type_1/Slice_grad/Rank" + input: "gradients/filter_type_1/Slice_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/stack" + op: "Pack" + input: "gradients/filter_type_0/Slice_1_grad/Rank" + input: "gradients/filter_type_0/Slice_1_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/stack" + op: "Pack" + input: "gradients/filter_type_0/Slice_grad/Rank" + input: "gradients/filter_type_0/Slice_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_6_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_6_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Maximum_1/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Const_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Const" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Maximum/y" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Fill/value" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/range/delta" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/range/start" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Shape_1" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + } + } + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Fill" + op: "Fill" + input: "gradients/filter_type_1/Mean_grad/Shape_1" + input: "gradients/filter_type_1/Mean_grad/Fill/value" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } + attr { + key: "index_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Size" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/range" + op: "Range" + input: "gradients/filter_type_1/Mean_grad/range/start" + input: "gradients/filter_type_1/Mean_grad/Size" + input: "gradients/filter_type_1/Mean_grad/range/delta" + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Maximum_1/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Const_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Const" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Maximum/y" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Fill/value" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/range/delta" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/range/start" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Shape_1" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + } + } + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Fill" + op: "Fill" + input: "gradients/filter_type_0/Mean_grad/Shape_1" + input: "gradients/filter_type_0/Mean_grad/Fill/value" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } + attr { + key: "index_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Size" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/range" + op: "Range" + input: "gradients/filter_type_0/Mean_grad/range/start" + input: "gradients/filter_type_0/Mean_grad/Size" + input: "gradients/filter_type_0/Mean_grad/range/delta" + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + } + } + } + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + } + } + } + } + } +} +node { + name: "gradients/concat_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_3_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_3_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_3_grad/stack" + op: "Pack" + input: "gradients/Slice_3_grad/Rank" + input: "gradients/Slice_3_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/Slice_2_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_2_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_2_grad/stack" + op: "Pack" + input: "gradients/Slice_2_grad/Rank" + input: "gradients/Slice_2_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "gradients/concat_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/grad_ys_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 1.0 + } + } + } +} +node { + name: "o_energy/reduction_indices" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "o_atom_energy/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "strided_slice_22/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_22/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_22/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_16/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: -1 + } + } + } +} +node { + name: "concat_1/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/concat_1_grad/mod" + op: "FloorMod" + input: "concat_1/axis" + input: "gradients/concat_1_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_21/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_21/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_21/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_20/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_20/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_20/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "final_layer_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + } + double_val: -186.95558874781707 + } + } + } +} +node { + name: "final_layer_type_1/bias/read" + op: "Identity" + input: "final_layer_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_1/bias" + } + } + } +} +node { + name: "final_layer_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 1 + } + } + tensor_content: "\\\013\372#\355n\277?\360\225\365o&\236\274\277\241\265`:\214\217\324\277\203\0024J.\334\301\277" + } + } + } +} +node { + name: "final_layer_type_1/matrix/read" + op: "Identity" + input: "final_layer_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_1/matrix" + } + } + } +} +node { + name: "layer_2_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "layer_2_type_1/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\256\246\233X\377,\302?m\\\355\314\231W\263?\325\367\205&p\277\247?@q\352r\312q\303?" + } + } + } +} +node { + name: "layer_2_type_1/idt/read" + op: "Identity" + input: "layer_2_type_1/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_1/idt" + } + } + } +} +node { + name: "layer_2_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\232\021\347\311\307=\310?\201\260\026G\3248\323\277*\273\034\265i\030\351\277\264\316\177\345\022^\310\277" + } + } + } +} +node { + name: "layer_2_type_1/bias/read" + op: "Identity" + input: "layer_2_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_1/bias" + } + } + } +} +node { + name: "layer_2_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 4 + } + } + tensor_content: "\336\373)\232`f\270?\004\302\271(\200\033\301\277\014\252\232\010\207\202\323\277kn\371\233\207\233\270\277\0371\315\320\246\027\347?\211\232\302:\332F\306\277D\2546\031\340\260\265?\306\260V\342\351\345\344\277\313I+\337\365;\322?\235\322f\336kg\324\277\257\342\260\230\364\325x?\270\272\360\334!L\332\277\234\233\007\301\345\244i\277\022\014\367\214U\036\323?8\213j}\226\336\277\277" + } + } + } +} +node { + name: "layer_2_type_1/matrix/read" + op: "Identity" + input: "layer_2_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_1/matrix" + } + } + } +} +node { + name: "layer_1_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "layer_1_type_1/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\322O\226^\237y\300?\034j\254wY\303\260?\322.\304\376\314\303\247?T\354\031\034\177S\303?" + } + } + } +} +node { + name: "layer_1_type_1/idt/read" + op: "Identity" + input: "layer_1_type_1/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_1/idt" + } + } + } +} +node { + name: "layer_1_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\200\344\343~\274;\310?\250\0331o+C\323\277\337Vm\270\235\030\351\277\373f \253\177]\310\277" + } + } + } +} +node { + name: "layer_1_type_1/bias/read" + op: "Identity" + input: "layer_1_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_1/bias" + } + } + } +} +node { + name: "layer_1_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 4 + } + } + tensor_content: "\310\034R\242>\317\267?`\3732\331b\310\300\277W\255J\243S]\323\277\257\034\345Bp\t\270\277(\376\255\177\020\014\347?\303\313\355\315\261\365\305\277\240\341GJ\221\013\266?Q5\363A\275\327\344\277\331\316\246\211\r=\322?)\254Mmu]\324\277\2745\021\356\022\306x?_\005\036vcL\332\2774]~I\354\255e\277\210\233\367\243\253\037\342?\211o\302\213\221\031\323?\342Eq\307]\362\277\277" + } + } + } +} +node { + name: "layer_1_type_1/matrix/read" + op: "Identity" + input: "layer_1_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_1/matrix" + } + } + } +} +node { + name: "layer_0_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "layer_0_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\\\007\303\2406C\310?p\274k:IA\323\277\002>\035{\307\023\351\277d\237\250-\256^\310\277" + } + } + } +} +node { + name: "layer_0_type_1/bias/read" + op: "Identity" + input: "layer_0_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_1/bias" + } + } + } +} +node { + name: "layer_0_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + dim { + size: 4 + } + } + tensor_content: "a\267\230\311F\336\216?\017\210\244\324\207\265\250\277E\331\263u\353\360\307\277\036\202\030\3502\272\217\277A\201(\312tM\343?x\346\207\333\r/\304\277\366p!\351\215\361\252?<\017@u\203\204\341\277s\253\227\363\233\232\316?z\375\036 \332\031\321\277\217\200\324\022\\\336]\2777\017\304\0074\357\325\277HC\275\274+b\250?y\334T4\316\214\332?\2712\272\223\240\334\310?f\214\021~Fx\303\277\222\313\342-\032\334\326\277L\257\213)\2659\350?\220\000T6\344D\247\277\343G6f*\303\311?\004\367\202\347\276\316\317? x\005\227\355Z\277?Bz_bL\376\210?\017\002n\201\023\327\303\277\014)\340\311=I\267\277l\246\262\201\036\005\234?\334\370B\325f\313\223\277\255 \327\277\213b\344\277+\202\327\337q\277\320\277\365\257\206\267r[\311\277\371\350\010e\225T\322\277\376\222\2732\304\246\311\277" + } + } + } +} +node { + name: "layer_0_type_1/matrix/read" + op: "Identity" + input: "layer_0_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_1/matrix" + } + } + } +} +node { + name: "Reshape_14/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "Slice_3/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_3/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_11/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "strided_slice_18/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_18/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_18/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "mul_10/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "strided_slice_17/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_17/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_17/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_16/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_16/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_16/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "final_layer_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + } + double_val: -93.38284094403838 + } + } + } +} +node { + name: "final_layer_type_0/bias/read" + op: "Identity" + input: "final_layer_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_0/bias" + } + } + } +} +node { + name: "final_layer_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 1 + } + } + tensor_content: " q\003\376\035F\273?\305 \264\236\225T\300\277\267\330Oj\211\217\324\277\311)\372\n\236r\301\277" + } + } + } +} +node { + name: "final_layer_type_0/matrix/read" + op: "Identity" + input: "final_layer_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_0/matrix" + } + } + } +} +node { + name: "layer_2_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "layer_2_type_0/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "-s\2148P\213\300?\t\\5\207:\343\261?\354\253\344\255]\273\247?\nN\273\007\317p\303?" + } + } + } +} +node { + name: "layer_2_type_0/idt/read" + op: "Identity" + input: "layer_2_type_0/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_0/idt" + } + } + } +} +node { + name: "layer_2_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\350\2536U\2378\310?F^d\232\037<\323\277<\333\316\263\334\030\351\277n)\2739\323\\\310\277" + } + } + } +} +node { + name: "layer_2_type_0/bias/read" + op: "Identity" + input: "layer_2_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_0/bias" + } + } + } +} +node { + name: "layer_2_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 4 + } + } + tensor_content: "1I\331x\365y\264?\236=\021\3015\"\276\277t\241\024q}\202\322\277\'X\375\243R\311\264\277\357\272\306\234B\224\346?\202\277\326\035\265B\304\277\265\203\203<\256\202\271?\364\360\345Q\310d\344\277~\202\205\340D>\322?\272\265^s\372c\324\277\247\020\361``\021y?Ce\213d\257L\332\277\2315@\003\323yQ?\223\226E\313\350\005\342?\332$\220\331!\334\322?\236\302 \262bb\300\277" + } + } + } +} +node { + name: "layer_2_type_0/matrix/read" + op: "Identity" + input: "layer_2_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_0/matrix" + } + } + } +} +node { + name: "layer_1_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "layer_1_type_0/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\270\377\233v\233%\300?\252\343\016~\2346\257?|\021\005zw\277\247?\212\336\002}\237%\303?" + } + } + } +} +node { + name: "layer_1_type_0/idt/read" + op: "Identity" + input: "layer_1_type_0/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_0/idt" + } + } + } +} +node { + name: "layer_1_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\327\255v@\2378\310?\337\264\020&`D\323\277n\013!*\374\030\351\277]\314(\251C\\\310\277" + } + } + } +} +node { + name: "layer_1_type_0/bias/read" + op: "Identity" + input: "layer_1_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_0/bias" + } + } + } +} +node { + name: "layer_1_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 4 + } + } + tensor_content: "\3771>\326\251\362\263?X\350\356\3338\211\275\277C\031q\0010`\322\277\216JkA @\264\277m\027i\350l\217\346?K6{\321\232\"\304\277An\035\322\356\226\271?\231!4\253;`\344\277v\317IWE>\322?4\370\307\273?\\\324\277\007\022\303\'\275\371x?\365_+\247\343L\332\277\315\315\026B?\020_?\216\277Kw\014\376\341?\342BV\321u\320\322?\0166\\\244\372{\300\277" + } + } + } +} +node { + name: "layer_1_type_0/matrix/read" + op: "Identity" + input: "layer_1_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_0/matrix" + } + } + } +} +node { + name: "layer_0_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "layer_0_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\021\356`\3544C\310?T\232\255\216\313=\323\277h\320\n\257\230\023\351\277\373\351\330\"\020^\310\277" + } + } + } +} +node { + name: "layer_0_type_0/bias/read" + op: "Identity" + input: "layer_0_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_0/bias" + } + } + } +} +node { + name: "layer_0_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + dim { + size: 4 + } + } + tensor_content: "1Xa\274\006\271\215?\226y\267\363\026\\\250\277\231\261k`U\334\307\277A\221{ \254\216\216\277\234J\353\371\352\252\342?\361#\362\2134\250\301\277\n\332\024\273\360\177\262?\313&V\231U\340\340\277!\017\256\256\372>\314?#\275\371\256\017\321\317\277\264N\026\273\221\205\220?\232Xd\245\253\270\324\277\220\352^\201\031\305\244?\322\336\240#\356\336\332?\002\313\260\036\005\245\311?{\340Z\020\320\254\302\277\303#D\002:\344\326\277\037\342X\214G>\350?\037\315\330\224<\004\247\277\002\303\252\214\306\322\311?\327\351sx{i\315?\266\332\315\313\321\031\302?\242\224#\27226\237?\224\274\036\250\323a\301\277\003:I\253\203G\270\277\201\r\262Y\351\370\236?[\355xx\212\035\220\277\016\353\364\225~D\344\277W+\013\314c\365\321\277\273\332\205\350\234\373\306\2774b\341\345\343\"\321\277\343|\213\016t7\307\277" + } + } + } +} +node { + name: "layer_0_type_0/matrix/read" + op: "Identity" + input: "layer_0_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_0/matrix" + } + } + } +} +node { + name: "add_2/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "strided_slice_15/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_15/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_15/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "Reshape_12/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "Slice_2/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_2/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/Slice_2_grad/Reshape" + op: "Reshape" + input: "Slice_2/begin" + input: "gradients/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_9/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "strided_slice_14/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_14/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_14/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "Reshape_11/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_8/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "strided_slice_13/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_13/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_13/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "fitting_attr/daparam" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "fitting_attr/dfparam" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/concat_grad/mod" + op: "FloorMod" + input: "concat/axis" + input: "gradients/concat_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_7/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "strided_slice_11/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_11/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_11/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_10/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_10/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_10/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "filter_type_1/mul/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.2 + } + } + } +} +node { + name: "filter_type_1/Mean/reduction_indices" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/add" + op: "Add" + input: "filter_type_1/Mean/reduction_indices" + input: "gradients/filter_type_1/Mean_grad/Size" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/mod" + op: "FloorMod" + input: "gradients/filter_type_1/Mean_grad/add" + input: "gradients/filter_type_1/Mean_grad/Size" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } +} +node { + name: "filter_type_1/concat_6/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_6_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_6/axis" + input: "gradients/filter_type_1/concat_6_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_9/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\\\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/concat_5/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_5/axis" + input: "gradients/filter_type_1/concat_5_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_8/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\313~\206\227\026]\310?\251\260eSc\000\332\277\001\024\000\365\264v\354\277)N\024=\273\226\310\277\215L?a0f\377?@J:!\263\373\332\277\257\201\376\t\225\241\323?\344\017\230?6L\374\277" + } + } + } +} +node { + name: "filter_type_1/bias_3_1/read" + op: "Identity" + input: "filter_type_1/bias_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_3_1" + } + } + } +} +node { + name: "filter_type_1/matrix_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "C\365\223\350\217v\230?\017t\200\254R\t\303\277\241\326V*\320\244\310\277\226\242\013\321J\307\271\277\232\022$\232\300\367\337?A\220\3636\353\347\302\277\026.!\333\257U\303?\'\021dQsb\334\277\033\261M?q\354\316?o(\300\340X\r\305\277>\253\306!}\266\271?\251\317\327\006N\375\325\2773\254\370\371\276\375\236\277\316\376Y\367\321g\337?\310\216\2443?y\321?\006\220\\\232;\365\262\277\016\240HJv\004\320\277#\253\033N:6\350?Y\224\366M\375\314\247\277\231w\277a\265\247\270?\360\236\322=u\252\302?\226\302Ze\373f\313?Vp\004\323\212y\275?\r\203}\227\345\206\252\277\351u\360\231Gz\261\277\273\001\2232\\P\271?H\351\361\232\247T\260?gL\354\224K\021\345\277|LZ\2058`\327\277\254\32788\017O\273\277\031\234\000>\270Y\307\277\347%\304w\'\265\270\277" + } + } + } +} +node { + name: "filter_type_1/matrix_3_1/read" + op: "Identity" + input: "filter_type_1/matrix_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_3_1" + } + } + } +} +node { + name: "filter_type_1/concat_4/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_4/axis" + input: "gradients/filter_type_1/concat_4_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_7/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "{\343v8\035\361\322?f\342*J\013\000\332\277ew\317\t\246y\354\277X\257x\247\222\357\321\277" + } + } + } +} +node { + name: "filter_type_1/bias_2_1/read" + op: "Identity" + input: "filter_type_1/bias_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_2_1" + } + } + } +} +node { + name: "filter_type_1/matrix_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "/\344KnK\\\257?\337j\314\211\266\334\302\277\376uT\340\"y\327\277\033\213\371\316M\002\256\2776RV\376WJ\347?\245\337*\265\323\374\270\277\251u\204\352\302\232\311?\354\262\303*\035\354\344\277" + } + } + } +} +node { + name: "filter_type_1/matrix_2_1/read" + op: "Identity" + input: "filter_type_1/matrix_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_2_1" + } + } + } +} +node { + name: "filter_type_1/concat_3/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_3/axis" + input: "gradients/filter_type_1/concat_3_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_6/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "^\342\206\234\0047\310?Km\034Np\000\332\277" + } + } + } +} +node { + name: "filter_type_1/bias_1_1/read" + op: "Identity" + input: "filter_type_1/bias_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_1_1" + } + } + } +} +node { + name: "filter_type_1/matrix_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\021\037\265\250\211\276\267?_\250\232\361\264w\303\277" + } + } + } +} +node { + name: "filter_type_1/matrix_1_1/read" + op: "Identity" + input: "filter_type_1/matrix_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_1_1" + } + } + } +} +node { + name: "filter_type_1/Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_1/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\\\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_1/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000.\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Reshape" + op: "Reshape" + input: "filter_type_1/Slice_1/begin" + input: "gradients/filter_type_1/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_4/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_2/axis" + input: "gradients/filter_type_1/concat_2_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "JBu\357\245t\310?\036\025\0032P\010\332\277\327\320\2728\027w\354\277\216\275\"u\253\216\310\277\244\003\033L\207g\377?\326\2659\304\023\242\331\277\367\213\250\261N\244\323?\314\003{\2474M\374\277" + } + } + } +} +node { + name: "filter_type_1/bias_3_0/read" + op: "Identity" + input: "filter_type_1/bias_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_3_0" + } + } + } +} +node { + name: "filter_type_1/matrix_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\000\321\243\226\211X\250?i\307\361\315\364\213\302\277F\230+\376+/\310\277$J\"\242\210d\262\277\343\257\367\275#\353\337?Ny\376\002\320\212\271\277\255\302v@Gq\304?2\331\216\270mT\334\27738\027\2603\002\317?92\254N\305\005\305\277\001\360o*\272\305\271?j\215\207}\355\366\325\277\316Y2\020\304`\237\277*\250\211\027d\246\337?\203\325\030j\225\200\321?\2464;\373\003\341\262\277j\253\006X\354\265\317\277\262\257\271\313\213\330\347?\346\326]^.\232\247\277\3551\265yi\360\270?\334\264K\311\002\234\302?\301\373\017\rgC\315?\302\226w\003F\263\275?\324\347z60T\252\277\030&d\222\360 \261\277i\214\236\212\014M\274?\216\345\030\220Pa\260?5\234pM\036\014\345\277\301\241\363\241\215e\327\2772z\252\207vq\267\277\234_\204J\221?\307\277\201\243\271\247\321\243\270\277" + } + } + } +} +node { + name: "filter_type_1/matrix_3_0/read" + op: "Identity" + input: "filter_type_1/matrix_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_3_0" + } + } + } +} +node { + name: "filter_type_1/concat_1/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_1/axis" + input: "gradients/filter_type_1/concat_1_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_2/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\341\243\243(k\356\322?\030\3010\365m\377\331\277^\312\255\217\250y\354\277\233\333\316\037\266\032\322\277" + } + } + } +} +node { + name: "filter_type_1/bias_2_0/read" + op: "Identity" + input: "filter_type_1/bias_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_2_0" + } + } + } +} +node { + name: "filter_type_1/matrix_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\221}\350\203\261\221\263?|\024\373m\r\306\300\277\004\347\366D\327U\327\277\326\rH^\236\374\277\277!\316\2655\023J\347?\375\275\322\035\014\317\270\277\273\266|+\215\243\311?\2033\362\240-\027\345\277" + } + } + } +} +node { + name: "filter_type_1/matrix_2_0/read" + op: "Identity" + input: "filter_type_1/matrix_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_2_0" + } + } + } +} +node { + name: "filter_type_1/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat/axis" + input: "gradients/filter_type_1/concat_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_1/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\304E\347rg6\310?9\327\337\346\n\000\332\277" + } + } + } +} +node { + name: "filter_type_1/bias_1_0/read" + op: "Identity" + input: "filter_type_1/bias_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_1_0" + } + } + } +} +node { + name: "filter_type_1/matrix_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\202\022\302\306e\025\267?8\371\017Z|\366\302\277" + } + } + } +} +node { + name: "filter_type_1/matrix_1_0/read" + op: "Identity" + input: "filter_type_1/matrix_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_1_0" + } + } + } +} +node { + name: "filter_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377.\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Reshape" + op: "Reshape" + input: "filter_type_1/Slice/begin" + input: "gradients/filter_type_1/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_9/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\212\000\000\000" + } + } + } +} +node { + name: "Slice_1/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_1/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_6/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 138 + } + } + } +} +node { + name: "strided_slice_9/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_9/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_9/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "mul_5/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 138 + } + } + } +} +node { + name: "add/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "strided_slice_8/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_8/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_8/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "mul_4/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "strided_slice_7/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_7/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_7/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_6/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_6/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_6/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "filter_type_0/mul/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.2 + } + } + } +} +node { + name: "filter_type_0/Mean/reduction_indices" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/add" + op: "Add" + input: "filter_type_0/Mean/reduction_indices" + input: "gradients/filter_type_0/Mean_grad/Size" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/mod" + op: "FloorMod" + input: "gradients/filter_type_0/Mean_grad/add" + input: "gradients/filter_type_0/Mean_grad/Size" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } +} +node { + name: "filter_type_0/concat_6/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_6_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat_6/axis" + input: "gradients/filter_type_0/concat_6_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_9/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\\\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/concat_5/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat_5/axis" + input: "gradients/filter_type_0/concat_5_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_8/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\331!K\213\207w\310?\010\276\335\237L\010\332\277\271\205\272$\311w\354\277Q\0052.u\201\310\277\321\032\222\333Yg\377?\230j\003mLQ\327\277&ij\220g\243\323?L\332\2225\320M\374\277" + } + } + } +} +node { + name: "filter_type_0/bias_3_1/read" + op: "Identity" + input: "filter_type_0/bias_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_3_1" + } + } + } +} +node { + name: "filter_type_0/matrix_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\031(\002l\311n\247?\372\331\201\317\033\374\300\277\223\270\2718n*\310\277\372\213\362N\273\330\262\277P:@\327x\352\337?\367Q\325\036\321m\274\277\302tk\351\"m\304?\214\204\222\021\317P\334\277\327b\260\312!b\315?\375\244\031\260^\346\304\277p\225i\347X\315\271?2\230\270\014+\375\325\277\352\226\246\213\027X\237\277\240\332\"\263\rV\335?\370\326\271%\361~\321?\2168\276$\202\330\262\277\225\327=\222w\343\317\277)/\234\304\254=\350?\340\305\225h\017\210\247\277\200\257\343\237\227\325\270?\345]L~\271\234\302?\233(\"\007\304\364\310?\242|;\205\177\256\275?`y\2462\263@\252\277\255\313n\242\\\347\265\277\226t}\336j\241\274?\215N\270?\221p\260?\232\367&J\213\020\345\277\204\244\274Z\245e\327\277k\370\222.i\314\277\277\227\346\307\204\235E\307\277\251\337\243\263\333\227\270\277" + } + } + } +} +node { + name: "filter_type_0/matrix_3_1/read" + op: "Identity" + input: "filter_type_0/matrix_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_3_1" + } + } + } +} +node { + name: "filter_type_0/concat_4/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat_4/axis" + input: "gradients/filter_type_0/concat_4_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_7/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\272\021\240\274\314\356\322?\377K\0227\240\001\332\277\324\214\334\352\333z\354\277,\251\000W\316\326\320\277" + } + } + } +} +node { + name: "filter_type_0/bias_2_1/read" + op: "Identity" + input: "filter_type_0/bias_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_2_1" + } + } + } +} +node { + name: "filter_type_0/matrix_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "Z\215\207r2\266\272?\355D(\234\t\200\302\277\236h\0166A\002\331\277O\'\212\206\311^\301\277\0363n\251,J\347?*0FS\247\263\270\277\223\023\341\324\203\252\311?\261\227\362\242F\224\345\277" + } + } + } +} +node { + name: "filter_type_0/matrix_2_1/read" + op: "Identity" + input: "filter_type_0/matrix_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_2_1" + } + } + } +} +node { + name: "filter_type_0/concat_3/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat_3/axis" + input: "gradients/filter_type_0/concat_3_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_6/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "N\362\000\re\020\311?\346\352\361\031\330\004\332\277" + } + } + } +} +node { + name: "filter_type_0/bias_1_1/read" + op: "Identity" + input: "filter_type_0/bias_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_1_1" + } + } + } +} +node { + name: "filter_type_0/matrix_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: ",\000\346\016\227\300\266?\237\251v2\353\354\302\277" + } + } + } +} +node { + name: "filter_type_0/matrix_1_1/read" + op: "Identity" + input: "filter_type_0/matrix_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_1_1" + } + } + } +} +node { + name: "filter_type_0/Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_1/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\\\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_1/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000.\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Reshape" + op: "Reshape" + input: "filter_type_0/Slice_1/begin" + input: "gradients/filter_type_0/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_4/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat_2/axis" + input: "gradients/filter_type_0/concat_2_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\2456\257\225LZ\310?\211\031\320\021F\006\332\277\375S\200\237Gy\354\277\336\372\334\325\232\204\310\277\242I\246\033\344j\377?\366K\362 \rx\330\277\260+\257\316\022\241\323?\316\034\304\274\356P\374\277" + } + } + } +} +node { + name: "filter_type_0/bias_3_0/read" + op: "Identity" + input: "filter_type_0/bias_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_3_0" + } + } + } +} +node { + name: "filter_type_0/matrix_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\013\262Z\331\305B\254?,!\262\347\203\024\304\277\360\307\256f\227\365\307\277Ee\315x\276\257\235\277\255>\324F.\311\337?\276\315nN\202\315\276\277(\014*3\203\323\303?\255\223\020e\3012\334\277,\265\310\340\275\366\316?bX\212\200\312\n\305\277u\363\3364\376\343\271?1\375\032t\024\377\325\277\300\215\271\234\225;\240\277\222\350X\344\000\356\334?\330/%A\262|\321?\314\267d\301\373\225\262\277\354\375\371\227\027\000\320\277\000\031S.\345\353\347?\020\355\222\3570=\247\277\244\031\255\320tp\271?\265f1\356\202r\302?\252Ez\340\262\311\307?\r\373\376\273\350\221\275?\373-34/\242\251\277J8wBuP\261\277U\256\205\036\032A\274?\363\0004\357Ip\260?3\337\203\366#\025\345\277qv\021\365\327v\327\277-\237\010\277I\027\301\277g\333,\201\264T\307\277W\024\036\255\'Y\270\277" + } + } + } +} +node { + name: "filter_type_0/matrix_3_0/read" + op: "Identity" + input: "filter_type_0/matrix_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_3_0" + } + } + } +} +node { + name: "filter_type_0/concat_1/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat_1/axis" + input: "gradients/filter_type_0/concat_1_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_2/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\2062H4X\352\322?F\366\221\034\217\002\332\277F/\267\203\307z\354\277\352\315\302\242n\274\320\277" + } + } + } +} +node { + name: "filter_type_0/bias_2_0/read" + op: "Identity" + input: "filter_type_0/bias_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_2_0" + } + } + } +} +node { + name: "filter_type_0/matrix_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\'\213\223\334\232\243\260?\246\005\017\254\372\254\304\277\203\327\374{\335\235\330\277\242i\216\263L\251\274\2774ra\267\021A\347?\004\375\3451L\342\270\277\025S\005\347_\244\311?\252\255\353\274\\\324\345\277" + } + } + } +} +node { + name: "filter_type_0/matrix_2_0/read" + op: "Identity" + input: "filter_type_0/matrix_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_2_0" + } + } + } +} +node { + name: "filter_type_0/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat/axis" + input: "gradients/filter_type_0/concat_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_1/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "ZAK\341x\260\310?\227K9\034\032\013\332\277" + } + } + } +} +node { + name: "filter_type_0/bias_1_0/read" + op: "Identity" + input: "filter_type_0/bias_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_1_0" + } + } + } +} +node { + name: "filter_type_0/matrix_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\004\316\275t\373\350\265?&\033\243\370\214!\310\277" + } + } + } +} +node { + name: "filter_type_0/matrix_1_0/read" + op: "Identity" + input: "filter_type_0/matrix_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_1_0" + } + } + } +} +node { + name: "filter_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377.\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Reshape" + op: "Reshape" + input: "filter_type_0/Slice/begin" + input: "gradients/filter_type_0/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_7/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\212\000\000\000" + } + } + } +} +node { + name: "Slice/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/Slice_grad/Reshape" + op: "Reshape" + input: "Slice/begin" + input: "gradients/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_3/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 138 + } + } + } +} +node { + name: "strided_slice_5/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_5/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_5/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "Reshape_6/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_2/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 138 + } + } + } +} +node { + name: "strided_slice_4/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_4/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_4/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\212\000\000\000" + } + } + } +} +node { + name: "Reshape_4/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "strided_slice_3/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_3/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_3/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\t\000\000\000" + } + } + } +} +node { + name: "Reshape_2/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_1/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_2/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_2/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_2/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "descrpt_attr/t_std" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 138 + } + } + tensor_content: "\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?" + } + } + } +} +node { + name: "descrpt_attr/t_std/read" + op: "Identity" + input: "descrpt_attr/t_std" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@descrpt_attr/t_std" + } + } + } +} +node { + name: "descrpt_attr/t_avg" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 138 + } + } + tensor_content: "\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?" + } + } + } +} +node { + name: "descrpt_attr/t_avg/read" + op: "Identity" + input: "descrpt_attr/t_avg" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@descrpt_attr/t_avg" + } + } + } +} +node { + name: "descrpt_attr/ntypes" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "descrpt_attr/rcut" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 6.0 + } + } + } +} +node { + name: "model_attr/model_type" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "ener" + } + } + } +} +node { + name: "model_attr/tmap" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "O H" + } + } + } +} +node { + name: "t_mesh" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "t_natoms" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: 4 + } + } + } + } +} +node { + name: "strided_slice_25" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_25/stack" + input: "strided_slice_25/stack_1" + input: "strided_slice_25/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_14" + op: "Mul" + input: "mul_14/x" + input: "strided_slice_25" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "o_atom_virial/shape" + op: "Pack" + input: "o_atom_virial/shape/0" + input: "mul_14" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_24" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_24/stack" + input: "strided_slice_24/stack_1" + input: "strided_slice_24/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_13" + op: "Mul" + input: "mul_13/x" + input: "strided_slice_24" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "o_force/shape" + op: "Pack" + input: "o_force/shape/0" + input: "mul_13" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_23" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_23/stack" + input: "strided_slice_23/stack_1" + input: "strided_slice_23/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_12" + op: "Mul" + input: "strided_slice_23" + input: "mul_12/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_17/shape" + op: "Pack" + input: "Reshape_17/shape/0" + input: "mul_12" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_22" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_22/stack" + input: "strided_slice_22/stack_1" + input: "strided_slice_22/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "o_atom_energy/shape" + op: "Pack" + input: "o_atom_energy/shape/0" + input: "strided_slice_22" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_21" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_21/stack" + input: "strided_slice_21/stack_1" + input: "strided_slice_21/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_18" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_18/stack" + input: "strided_slice_18/stack_1" + input: "strided_slice_18/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_11" + op: "Mul" + input: "strided_slice_18" + input: "mul_11/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_3/size" + op: "Pack" + input: "Slice_3/size/0" + input: "mul_11" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_17" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_17/stack" + input: "strided_slice_17/stack_1" + input: "strided_slice_17/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_15" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_15/stack" + input: "strided_slice_15/stack_1" + input: "strided_slice_15/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "add_2" + op: "Add" + input: "add_2/x" + input: "strided_slice_15" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_10" + op: "Mul" + input: "add_2" + input: "mul_10/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_3/begin" + op: "Pack" + input: "Slice_3/begin/0" + input: "mul_10" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/Slice_3_grad/Reshape" + op: "Reshape" + input: "Slice_3/begin" + input: "gradients/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_14" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_14/stack" + input: "strided_slice_14/stack_1" + input: "strided_slice_14/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_9" + op: "Mul" + input: "strided_slice_14" + input: "mul_9/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_2/size" + op: "Pack" + input: "Slice_2/size/0" + input: "mul_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_13" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_13/stack" + input: "strided_slice_13/stack_1" + input: "strided_slice_13/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_8" + op: "Mul" + input: "mul_8/x" + input: "strided_slice_13" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_11/shape" + op: "Pack" + input: "Reshape_11/shape/0" + input: "mul_8" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_11" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_11/stack" + input: "strided_slice_11/stack_1" + input: "strided_slice_11/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_7" + op: "Mul" + input: "strided_slice_11" + input: "mul_7/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_9" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_9/stack" + input: "strided_slice_9/stack_1" + input: "strided_slice_9/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_6" + op: "Mul" + input: "strided_slice_9" + input: "mul_6/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_1/size" + op: "Pack" + input: "Slice_1/size/0" + input: "mul_6" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_8" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_8/stack" + input: "strided_slice_8/stack_1" + input: "strided_slice_8/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "add" + op: "Add" + input: "add/x" + input: "strided_slice_8" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_5" + op: "Mul" + input: "add" + input: "mul_5/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_1/begin" + op: "Pack" + input: "Slice_1/begin/0" + input: "mul_5" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/Slice_1_grad/Reshape" + op: "Reshape" + input: "Slice_1/begin" + input: "gradients/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_7" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_7/stack" + input: "strided_slice_7/stack_1" + input: "strided_slice_7/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_4" + op: "Mul" + input: "strided_slice_7" + input: "mul_4/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_5" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_5/stack" + input: "strided_slice_5/stack_1" + input: "strided_slice_5/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_3" + op: "Mul" + input: "strided_slice_5" + input: "mul_3/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice/size" + op: "Pack" + input: "Slice/size/0" + input: "mul_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_4" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_4/stack" + input: "strided_slice_4/stack_1" + input: "strided_slice_4/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_2" + op: "Mul" + input: "mul_2/x" + input: "strided_slice_4" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_6/shape" + op: "Pack" + input: "Reshape_6/shape/0" + input: "mul_2" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_3" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_3/stack" + input: "strided_slice_3/stack_1" + input: "strided_slice_3/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_4/shape" + op: "Pack" + input: "Reshape_4/shape/0" + input: "strided_slice_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_2" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_2/stack" + input: "strided_slice_2/stack_1" + input: "strided_slice_2/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_1" + op: "Mul" + input: "strided_slice_2" + input: "mul_1/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_2/shape" + op: "Pack" + input: "Reshape_2/shape/0" + input: "mul_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "t_type" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_4" + op: "Reshape" + input: "t_type" + input: "Reshape_4/shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "t_coord" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_2" + op: "Reshape" + input: "t_coord" + input: "Reshape_2/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "t_box" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_3" + op: "Reshape" + input: "t_box" + input: "Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "ProdEnvMatR" + op: "ProdEnvMatR" + input: "Reshape_2" + input: "Reshape_4" + input: "t_natoms" + input: "Reshape_3" + input: "t_mesh" + input: "descrpt_attr/t_avg/read" + input: "descrpt_attr/t_std/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "rcut" + value { + f: 6.0 + } + } + attr { + key: "rcut_smth" + value { + f: 1.0 + } + } + attr { + key: "sel" + value { + list { + i: 46 + i: 92 + } + } + } +} +node { + name: "o_nlist" + op: "Identity" + input: "ProdEnvMatR:3" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "o_rij" + op: "Identity" + input: "ProdEnvMatR:2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "o_rmat_deriv" + op: "Identity" + input: "ProdEnvMatR:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_5" + op: "Reshape" + input: "ProdEnvMatR" + input: "Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_rmat" + op: "Identity" + input: "Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_6_grad/Shape" + op: "Shape" + input: "o_rmat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_6" + op: "Reshape" + input: "o_rmat" + input: "Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/Shape_1" + op: "Shape" + input: "Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/Shape_1" + op: "Shape" + input: "Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_1" + op: "Shape" + input: "Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_10" + op: "StridedSlice" + input: "Shape_1" + input: "strided_slice_10/stack" + input: "strided_slice_10/stack_1" + input: "strided_slice_10/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_10/shape" + op: "Pack" + input: "strided_slice_10" + input: "mul_7" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_1" + op: "Slice" + input: "Reshape_6" + input: "Slice_1/begin" + input: "Slice_1/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Slice_1_grad/Shape" + op: "Shape" + input: "Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/sub" + op: "Sub" + input: "gradients/Slice_1_grad/Shape_1" + input: "gradients/Slice_1_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/sub_1" + op: "Sub" + input: "gradients/Slice_1_grad/sub" + input: "Slice_1/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/Slice_1_grad/sub_1" + input: "gradients/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/concat" + op: "ConcatV2" + input: "gradients/Slice_1_grad/Reshape" + input: "gradients/Slice_1_grad/Reshape_1" + input: "gradients/Slice_1_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_9_grad/Shape" + op: "Shape" + input: "Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_9" + op: "Reshape" + input: "Slice_1" + input: "Reshape_9/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Shape_1" + op: "Shape" + input: "Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Shape_1" + op: "Shape" + input: "Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Slice_1" + op: "Slice" + input: "Reshape_9" + input: "filter_type_1/Slice_1/begin" + input: "filter_type_1/Slice_1/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/sub" + op: "Sub" + input: "gradients/filter_type_1/Slice_1_grad/Shape_1" + input: "gradients/filter_type_1/Slice_1_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_1/Slice_1_grad/sub" + input: "filter_type_1/Slice_1/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/Slice_1_grad/sub_1" + input: "gradients/filter_type_1/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_1/Slice_1_grad/Reshape" + input: "gradients/filter_type_1/Slice_1_grad/Reshape_1" + input: "gradients/filter_type_1/Slice_1_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_5_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_5" + op: "Reshape" + input: "filter_type_1/Slice_1" + input: "filter_type_1/Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/Reshape_5" + input: "filter_type_1/Reshape_5" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_3_grad/mod" + input: "gradients/filter_type_1/concat_3_grad/ShapeN" + input: "gradients/filter_type_1/concat_3_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_3" + op: "ConcatV2" + input: "filter_type_1/Reshape_5" + input: "filter_type_1/Reshape_5" + input: "filter_type_1/concat_3/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_3" + op: "MatMul" + input: "filter_type_1/Reshape_5" + input: "filter_type_1/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_6_grad/Shape" + input: "gradients/filter_type_1/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_6" + op: "Add" + input: "filter_type_1/MatMul_3" + input: "filter_type_1/bias_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_3" + op: "Tanh" + input: "filter_type_1/add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_6_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_6" + op: "Reshape" + input: "filter_type_1/Tanh_3" + input: "filter_type_1/Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_7_grad/Shape" + input: "gradients/filter_type_1/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_7" + op: "Add" + input: "filter_type_1/concat_3" + input: "filter_type_1/Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/add_7" + input: "filter_type_1/add_7" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_4_grad/mod" + input: "gradients/filter_type_1/concat_4_grad/ShapeN" + input: "gradients/filter_type_1/concat_4_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_4" + op: "ConcatV2" + input: "filter_type_1/add_7" + input: "filter_type_1/add_7" + input: "filter_type_1/concat_4/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_4" + op: "MatMul" + input: "filter_type_1/add_7" + input: "filter_type_1/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_8_grad/Shape" + input: "gradients/filter_type_1/add_8_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_8" + op: "Add" + input: "filter_type_1/MatMul_4" + input: "filter_type_1/bias_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_4" + op: "Tanh" + input: "filter_type_1/add_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_7_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_7" + op: "Reshape" + input: "filter_type_1/Tanh_4" + input: "filter_type_1/Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_9_grad/Shape" + input: "gradients/filter_type_1/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_9" + op: "Add" + input: "filter_type_1/concat_4" + input: "filter_type_1/Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/add_9" + input: "filter_type_1/add_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_5_grad/mod" + input: "gradients/filter_type_1/concat_5_grad/ShapeN" + input: "gradients/filter_type_1/concat_5_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_5" + op: "ConcatV2" + input: "filter_type_1/add_9" + input: "filter_type_1/add_9" + input: "filter_type_1/concat_5/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_5" + op: "MatMul" + input: "filter_type_1/add_9" + input: "filter_type_1/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_10_grad/Shape" + input: "gradients/filter_type_1/add_10_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_10" + op: "Add" + input: "filter_type_1/MatMul_5" + input: "filter_type_1/bias_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_5" + op: "Tanh" + input: "filter_type_1/add_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_8_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_8" + op: "Reshape" + input: "filter_type_1/Tanh_5" + input: "filter_type_1/Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_11_grad/Shape" + input: "gradients/filter_type_1/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_11" + op: "Add" + input: "filter_type_1/concat_5" + input: "filter_type_1/Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_9_grad/Shape" + op: "Shape" + input: "filter_type_1/add_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_9" + op: "Reshape" + input: "filter_type_1/add_11" + input: "filter_type_1/Reshape_9/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Slice" + op: "Slice" + input: "Reshape_9" + input: "filter_type_1/Slice/begin" + input: "filter_type_1/Slice/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/sub" + op: "Sub" + input: "gradients/filter_type_1/Slice_grad/Shape_1" + input: "gradients/filter_type_1/Slice_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_1/Slice_grad/sub" + input: "filter_type_1/Slice/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/Slice_grad/sub_1" + input: "gradients/filter_type_1/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_1/Slice_grad/Reshape" + input: "gradients/filter_type_1/Slice_grad/Reshape_1" + input: "gradients/filter_type_1/Slice_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape" + op: "Reshape" + input: "filter_type_1/Slice" + input: "filter_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/Reshape" + input: "filter_type_1/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_grad/mod" + input: "gradients/filter_type_1/concat_grad/ShapeN" + input: "gradients/filter_type_1/concat_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat" + op: "ConcatV2" + input: "filter_type_1/Reshape" + input: "filter_type_1/Reshape" + input: "filter_type_1/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Shape" + op: "Shape" + input: "filter_type_1/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul" + op: "MatMul" + input: "filter_type_1/Reshape" + input: "filter_type_1/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_grad/Shape" + input: "gradients/filter_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add" + op: "Add" + input: "filter_type_1/MatMul" + input: "filter_type_1/bias_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh" + op: "Tanh" + input: "filter_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_1_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_1" + op: "Reshape" + input: "filter_type_1/Tanh" + input: "filter_type_1/Reshape_1/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_1_grad/Shape" + input: "gradients/filter_type_1/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_1" + op: "Add" + input: "filter_type_1/concat" + input: "filter_type_1/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/add_1" + input: "filter_type_1/add_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_1_grad/mod" + input: "gradients/filter_type_1/concat_1_grad/ShapeN" + input: "gradients/filter_type_1/concat_1_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_1" + op: "ConcatV2" + input: "filter_type_1/add_1" + input: "filter_type_1/add_1" + input: "filter_type_1/concat_1/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_1" + op: "MatMul" + input: "filter_type_1/add_1" + input: "filter_type_1/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_2_grad/Shape" + input: "gradients/filter_type_1/add_2_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_2" + op: "Add" + input: "filter_type_1/MatMul_1" + input: "filter_type_1/bias_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_1" + op: "Tanh" + input: "filter_type_1/add_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_2_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_2" + op: "Reshape" + input: "filter_type_1/Tanh_1" + input: "filter_type_1/Reshape_2/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_3_grad/Shape" + input: "gradients/filter_type_1/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_3" + op: "Add" + input: "filter_type_1/concat_1" + input: "filter_type_1/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/add_3" + input: "filter_type_1/add_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_2_grad/mod" + input: "gradients/filter_type_1/concat_2_grad/ShapeN" + input: "gradients/filter_type_1/concat_2_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_2" + op: "ConcatV2" + input: "filter_type_1/add_3" + input: "filter_type_1/add_3" + input: "filter_type_1/concat_2/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_2" + op: "MatMul" + input: "filter_type_1/add_3" + input: "filter_type_1/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_4_grad/Shape" + input: "gradients/filter_type_1/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_4" + op: "Add" + input: "filter_type_1/MatMul_2" + input: "filter_type_1/bias_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_2" + op: "Tanh" + input: "filter_type_1/add_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_3_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_3" + op: "Reshape" + input: "filter_type_1/Tanh_2" + input: "filter_type_1/Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_5_grad/Shape" + input: "gradients/filter_type_1/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_5" + op: "Add" + input: "filter_type_1/concat_2" + input: "filter_type_1/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_4_grad/Shape" + op: "Shape" + input: "filter_type_1/add_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_4" + op: "Reshape" + input: "filter_type_1/add_5" + input: "filter_type_1/Reshape_4/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_6_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/Reshape_4" + input: "filter_type_1/Reshape_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_6_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_6_grad/mod" + input: "gradients/filter_type_1/concat_6_grad/ShapeN" + input: "gradients/filter_type_1/concat_6_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_6" + op: "ConcatV2" + input: "filter_type_1/Reshape_4" + input: "filter_type_1/Reshape_9" + input: "filter_type_1/concat_6/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Shape_2" + op: "Shape" + input: "filter_type_1/concat_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Prod" + op: "Prod" + input: "gradients/filter_type_1/Mean_grad/Shape_2" + input: "gradients/filter_type_1/Mean_grad/Const" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/DynamicStitch" + op: "DynamicStitch" + input: "gradients/filter_type_1/Mean_grad/range" + input: "gradients/filter_type_1/Mean_grad/mod" + input: "gradients/filter_type_1/Mean_grad/Shape" + input: "gradients/filter_type_1/Mean_grad/Fill" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Maximum" + op: "Maximum" + input: "gradients/filter_type_1/Mean_grad/DynamicStitch" + input: "gradients/filter_type_1/Mean_grad/Maximum/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/floordiv" + op: "FloorDiv" + input: "gradients/filter_type_1/Mean_grad/Shape" + input: "gradients/filter_type_1/Mean_grad/Maximum" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } +} +node { + name: "filter_type_1/Mean" + op: "Mean" + input: "filter_type_1/concat_6" + input: "filter_type_1/Mean/reduction_indices" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Shape_3" + op: "Shape" + input: "filter_type_1/Mean" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Prod_1" + op: "Prod" + input: "gradients/filter_type_1/Mean_grad/Shape_3" + input: "gradients/filter_type_1/Mean_grad/Const_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Maximum_1" + op: "Maximum" + input: "gradients/filter_type_1/Mean_grad/Prod_1" + input: "gradients/filter_type_1/Mean_grad/Maximum_1/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/floordiv_1" + op: "FloorDiv" + input: "gradients/filter_type_1/Mean_grad/Prod" + input: "gradients/filter_type_1/Mean_grad/Maximum_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Cast" + op: "Cast" + input: "gradients/filter_type_1/Mean_grad/floordiv_1" + attr { + key: "DstT" + value { + type: DT_DOUBLE + } + } + attr { + key: "SrcT" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Shape" + op: "Shape" + input: "filter_type_1/Mean" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/mul_grad/Shape" + input: "gradients/filter_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/mul" + op: "Mul" + input: "filter_type_1/Mean" + input: "filter_type_1/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_10_grad/Shape" + op: "Shape" + input: "filter_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_10" + op: "Reshape" + input: "filter_type_1/mul" + input: "Reshape_10/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape" + op: "Shape" + input: "Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_6" + op: "StridedSlice" + input: "Shape" + input: "strided_slice_6/stack" + input: "strided_slice_6/stack_1" + input: "strided_slice_6/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_8/shape" + op: "Pack" + input: "strided_slice_6" + input: "mul_4" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice" + op: "Slice" + input: "Reshape_6" + input: "Slice/begin" + input: "Slice/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Slice_grad/Shape" + op: "Shape" + input: "Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/sub" + op: "Sub" + input: "gradients/Slice_grad/Shape_1" + input: "gradients/Slice_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/sub_1" + op: "Sub" + input: "gradients/Slice_grad/sub" + input: "Slice/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/Reshape_1" + op: "Reshape" + input: "gradients/Slice_grad/sub_1" + input: "gradients/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/concat" + op: "ConcatV2" + input: "gradients/Slice_grad/Reshape" + input: "gradients/Slice_grad/Reshape_1" + input: "gradients/Slice_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_7_grad/Shape" + op: "Shape" + input: "Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_7" + op: "Reshape" + input: "Slice" + input: "Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Shape_1" + op: "Shape" + input: "Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Shape_1" + op: "Shape" + input: "Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Slice_1" + op: "Slice" + input: "Reshape_7" + input: "filter_type_0/Slice_1/begin" + input: "filter_type_0/Slice_1/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/sub" + op: "Sub" + input: "gradients/filter_type_0/Slice_1_grad/Shape_1" + input: "gradients/filter_type_0/Slice_1_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_0/Slice_1_grad/sub" + input: "filter_type_0/Slice_1/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/Slice_1_grad/sub_1" + input: "gradients/filter_type_0/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_0/Slice_1_grad/Reshape" + input: "gradients/filter_type_0/Slice_1_grad/Reshape_1" + input: "gradients/filter_type_0/Slice_1_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_5_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_5" + op: "Reshape" + input: "filter_type_0/Slice_1" + input: "filter_type_0/Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/Reshape_5" + input: "filter_type_0/Reshape_5" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_3_grad/mod" + input: "gradients/filter_type_0/concat_3_grad/ShapeN" + input: "gradients/filter_type_0/concat_3_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_3" + op: "ConcatV2" + input: "filter_type_0/Reshape_5" + input: "filter_type_0/Reshape_5" + input: "filter_type_0/concat_3/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_3" + op: "MatMul" + input: "filter_type_0/Reshape_5" + input: "filter_type_0/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_6_grad/Shape" + input: "gradients/filter_type_0/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_6" + op: "Add" + input: "filter_type_0/MatMul_3" + input: "filter_type_0/bias_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_3" + op: "Tanh" + input: "filter_type_0/add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_6_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_6" + op: "Reshape" + input: "filter_type_0/Tanh_3" + input: "filter_type_0/Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_7_grad/Shape" + input: "gradients/filter_type_0/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_7" + op: "Add" + input: "filter_type_0/concat_3" + input: "filter_type_0/Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/add_7" + input: "filter_type_0/add_7" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_4_grad/mod" + input: "gradients/filter_type_0/concat_4_grad/ShapeN" + input: "gradients/filter_type_0/concat_4_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_4" + op: "ConcatV2" + input: "filter_type_0/add_7" + input: "filter_type_0/add_7" + input: "filter_type_0/concat_4/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_4" + op: "MatMul" + input: "filter_type_0/add_7" + input: "filter_type_0/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_8_grad/Shape" + input: "gradients/filter_type_0/add_8_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_8" + op: "Add" + input: "filter_type_0/MatMul_4" + input: "filter_type_0/bias_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_4" + op: "Tanh" + input: "filter_type_0/add_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_7_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_7" + op: "Reshape" + input: "filter_type_0/Tanh_4" + input: "filter_type_0/Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_9_grad/Shape" + input: "gradients/filter_type_0/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_9" + op: "Add" + input: "filter_type_0/concat_4" + input: "filter_type_0/Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/add_9" + input: "filter_type_0/add_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_5_grad/mod" + input: "gradients/filter_type_0/concat_5_grad/ShapeN" + input: "gradients/filter_type_0/concat_5_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_5" + op: "ConcatV2" + input: "filter_type_0/add_9" + input: "filter_type_0/add_9" + input: "filter_type_0/concat_5/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_5" + op: "MatMul" + input: "filter_type_0/add_9" + input: "filter_type_0/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_10_grad/Shape" + input: "gradients/filter_type_0/add_10_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_10" + op: "Add" + input: "filter_type_0/MatMul_5" + input: "filter_type_0/bias_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_5" + op: "Tanh" + input: "filter_type_0/add_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_8_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_8" + op: "Reshape" + input: "filter_type_0/Tanh_5" + input: "filter_type_0/Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_11_grad/Shape" + input: "gradients/filter_type_0/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_11" + op: "Add" + input: "filter_type_0/concat_5" + input: "filter_type_0/Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_9_grad/Shape" + op: "Shape" + input: "filter_type_0/add_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_9" + op: "Reshape" + input: "filter_type_0/add_11" + input: "filter_type_0/Reshape_9/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Slice" + op: "Slice" + input: "Reshape_7" + input: "filter_type_0/Slice/begin" + input: "filter_type_0/Slice/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/sub" + op: "Sub" + input: "gradients/filter_type_0/Slice_grad/Shape_1" + input: "gradients/filter_type_0/Slice_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_0/Slice_grad/sub" + input: "filter_type_0/Slice/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/Slice_grad/sub_1" + input: "gradients/filter_type_0/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_0/Slice_grad/Reshape" + input: "gradients/filter_type_0/Slice_grad/Reshape_1" + input: "gradients/filter_type_0/Slice_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape" + op: "Reshape" + input: "filter_type_0/Slice" + input: "filter_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/Reshape" + input: "filter_type_0/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_grad/mod" + input: "gradients/filter_type_0/concat_grad/ShapeN" + input: "gradients/filter_type_0/concat_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat" + op: "ConcatV2" + input: "filter_type_0/Reshape" + input: "filter_type_0/Reshape" + input: "filter_type_0/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Shape" + op: "Shape" + input: "filter_type_0/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul" + op: "MatMul" + input: "filter_type_0/Reshape" + input: "filter_type_0/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_grad/Shape" + input: "gradients/filter_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add" + op: "Add" + input: "filter_type_0/MatMul" + input: "filter_type_0/bias_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh" + op: "Tanh" + input: "filter_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_1_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_1" + op: "Reshape" + input: "filter_type_0/Tanh" + input: "filter_type_0/Reshape_1/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_1_grad/Shape" + input: "gradients/filter_type_0/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_1" + op: "Add" + input: "filter_type_0/concat" + input: "filter_type_0/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/add_1" + input: "filter_type_0/add_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_1_grad/mod" + input: "gradients/filter_type_0/concat_1_grad/ShapeN" + input: "gradients/filter_type_0/concat_1_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_1" + op: "ConcatV2" + input: "filter_type_0/add_1" + input: "filter_type_0/add_1" + input: "filter_type_0/concat_1/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_1" + op: "MatMul" + input: "filter_type_0/add_1" + input: "filter_type_0/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_2_grad/Shape" + input: "gradients/filter_type_0/add_2_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_2" + op: "Add" + input: "filter_type_0/MatMul_1" + input: "filter_type_0/bias_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_1" + op: "Tanh" + input: "filter_type_0/add_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_2_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_2" + op: "Reshape" + input: "filter_type_0/Tanh_1" + input: "filter_type_0/Reshape_2/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_3_grad/Shape" + input: "gradients/filter_type_0/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_3" + op: "Add" + input: "filter_type_0/concat_1" + input: "filter_type_0/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/add_3" + input: "filter_type_0/add_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_2_grad/mod" + input: "gradients/filter_type_0/concat_2_grad/ShapeN" + input: "gradients/filter_type_0/concat_2_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_2" + op: "ConcatV2" + input: "filter_type_0/add_3" + input: "filter_type_0/add_3" + input: "filter_type_0/concat_2/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_2" + op: "MatMul" + input: "filter_type_0/add_3" + input: "filter_type_0/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_4_grad/Shape" + input: "gradients/filter_type_0/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_4" + op: "Add" + input: "filter_type_0/MatMul_2" + input: "filter_type_0/bias_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_2" + op: "Tanh" + input: "filter_type_0/add_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_3_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_3" + op: "Reshape" + input: "filter_type_0/Tanh_2" + input: "filter_type_0/Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_5_grad/Shape" + input: "gradients/filter_type_0/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_5" + op: "Add" + input: "filter_type_0/concat_2" + input: "filter_type_0/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_4_grad/Shape" + op: "Shape" + input: "filter_type_0/add_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_4" + op: "Reshape" + input: "filter_type_0/add_5" + input: "filter_type_0/Reshape_4/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_6_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/Reshape_4" + input: "filter_type_0/Reshape_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_6_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_6_grad/mod" + input: "gradients/filter_type_0/concat_6_grad/ShapeN" + input: "gradients/filter_type_0/concat_6_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_6" + op: "ConcatV2" + input: "filter_type_0/Reshape_4" + input: "filter_type_0/Reshape_9" + input: "filter_type_0/concat_6/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Shape_2" + op: "Shape" + input: "filter_type_0/concat_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Prod" + op: "Prod" + input: "gradients/filter_type_0/Mean_grad/Shape_2" + input: "gradients/filter_type_0/Mean_grad/Const" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/DynamicStitch" + op: "DynamicStitch" + input: "gradients/filter_type_0/Mean_grad/range" + input: "gradients/filter_type_0/Mean_grad/mod" + input: "gradients/filter_type_0/Mean_grad/Shape" + input: "gradients/filter_type_0/Mean_grad/Fill" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Maximum" + op: "Maximum" + input: "gradients/filter_type_0/Mean_grad/DynamicStitch" + input: "gradients/filter_type_0/Mean_grad/Maximum/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/floordiv" + op: "FloorDiv" + input: "gradients/filter_type_0/Mean_grad/Shape" + input: "gradients/filter_type_0/Mean_grad/Maximum" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } +} +node { + name: "filter_type_0/Mean" + op: "Mean" + input: "filter_type_0/concat_6" + input: "filter_type_0/Mean/reduction_indices" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Shape_3" + op: "Shape" + input: "filter_type_0/Mean" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Prod_1" + op: "Prod" + input: "gradients/filter_type_0/Mean_grad/Shape_3" + input: "gradients/filter_type_0/Mean_grad/Const_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Maximum_1" + op: "Maximum" + input: "gradients/filter_type_0/Mean_grad/Prod_1" + input: "gradients/filter_type_0/Mean_grad/Maximum_1/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/floordiv_1" + op: "FloorDiv" + input: "gradients/filter_type_0/Mean_grad/Prod" + input: "gradients/filter_type_0/Mean_grad/Maximum_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Cast" + op: "Cast" + input: "gradients/filter_type_0/Mean_grad/floordiv_1" + attr { + key: "DstT" + value { + type: DT_DOUBLE + } + } + attr { + key: "SrcT" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Shape" + op: "Shape" + input: "filter_type_0/Mean" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/mul_grad/Shape" + input: "gradients/filter_type_0/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/mul" + op: "Mul" + input: "filter_type_0/Mean" + input: "filter_type_0/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_8_grad/Shape" + op: "Shape" + input: "filter_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_8" + op: "Reshape" + input: "filter_type_0/mul" + input: "Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/ShapeN" + op: "ShapeN" + input: "Reshape_8" + input: "Reshape_10" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/concat_grad/mod" + input: "gradients/concat_grad/ShapeN" + input: "gradients/concat_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "concat" + op: "ConcatV2" + input: "Reshape_8" + input: "Reshape_10" + input: "concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "o_descriptor" + op: "Identity" + input: "concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_11_grad/Shape" + op: "Shape" + input: "o_descriptor" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_11" + op: "Reshape" + input: "o_descriptor" + input: "Reshape_11/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/Shape_1" + op: "Shape" + input: "Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/Shape_1" + op: "Shape" + input: "Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_3" + op: "Shape" + input: "Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_20" + op: "StridedSlice" + input: "Shape_3" + input: "strided_slice_20/stack" + input: "strided_slice_20/stack_1" + input: "strided_slice_20/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_15/shape" + op: "Pack" + input: "strided_slice_20" + input: "strided_slice_21" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_3" + op: "Slice" + input: "Reshape_11" + input: "Slice_3/begin" + input: "Slice_3/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Slice_3_grad/Shape" + op: "Shape" + input: "Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/sub" + op: "Sub" + input: "gradients/Slice_3_grad/Shape_1" + input: "gradients/Slice_3_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/sub_1" + op: "Sub" + input: "gradients/Slice_3_grad/sub" + input: "Slice_3/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/Slice_3_grad/sub_1" + input: "gradients/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/concat" + op: "ConcatV2" + input: "gradients/Slice_3_grad/Reshape" + input: "gradients/Slice_3_grad/Reshape_1" + input: "gradients/Slice_3_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_14_grad/Shape" + op: "Shape" + input: "Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_14" + op: "Reshape" + input: "Slice_3" + input: "Reshape_14/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_1/MatMul" + op: "MatMul" + input: "Reshape_14" + input: "layer_0_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/Shape" + op: "Shape" + input: "layer_0_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_0_type_1/add_grad/Shape" + input: "gradients/layer_0_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_1/add" + op: "Add" + input: "layer_0_type_1/MatMul" + input: "layer_0_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_0_type_1/Tanh" + op: "Tanh" + input: "layer_0_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_0_type_1/Reshape_grad/Shape" + op: "Shape" + input: "layer_0_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_1/Reshape" + op: "Reshape" + input: "layer_0_type_1/Tanh" + input: "layer_0_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_6_grad/Shape" + op: "Shape" + input: "layer_0_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/MatMul" + op: "MatMul" + input: "layer_0_type_1/Reshape" + input: "layer_1_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/Shape" + op: "Shape" + input: "layer_1_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_1_type_1/add_grad/Shape" + input: "gradients/layer_1_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/add" + op: "Add" + input: "layer_1_type_1/MatMul" + input: "layer_1_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_1_type_1/Tanh" + op: "Tanh" + input: "layer_1_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_1/Reshape_grad/Shape" + op: "Shape" + input: "layer_1_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/Reshape" + op: "Reshape" + input: "layer_1_type_1/Tanh" + input: "layer_1_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Shape" + op: "Shape" + input: "layer_1_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_1_type_1/mul_grad/Shape" + input: "gradients/layer_1_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/mul" + op: "Mul" + input: "layer_1_type_1/Reshape" + input: "layer_1_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_6_grad/Shape_1" + op: "Shape" + input: "layer_1_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_6_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/add_6_grad/Shape" + input: "gradients/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_6" + op: "Add" + input: "layer_0_type_1/Reshape" + input: "layer_1_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_7_grad/Shape" + op: "Shape" + input: "add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/MatMul" + op: "MatMul" + input: "add_6" + input: "layer_2_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/Shape" + op: "Shape" + input: "layer_2_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_2_type_1/add_grad/Shape" + input: "gradients/layer_2_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/add" + op: "Add" + input: "layer_2_type_1/MatMul" + input: "layer_2_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_1/Tanh" + op: "Tanh" + input: "layer_2_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_1/Reshape_grad/Shape" + op: "Shape" + input: "layer_2_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/Reshape" + op: "Reshape" + input: "layer_2_type_1/Tanh" + input: "layer_2_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Shape" + op: "Shape" + input: "layer_2_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_2_type_1/mul_grad/Shape" + input: "gradients/layer_2_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/mul" + op: "Mul" + input: "layer_2_type_1/Reshape" + input: "layer_2_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_7_grad/Shape_1" + op: "Shape" + input: "layer_2_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_7_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/add_7_grad/Shape" + input: "gradients/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_7" + op: "Add" + input: "add_6" + input: "layer_2_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "final_layer_type_1/MatMul" + op: "MatMul" + input: "add_7" + input: "final_layer_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/Shape" + op: "Shape" + input: "final_layer_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/final_layer_type_1/add_grad/Shape" + input: "gradients/final_layer_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "final_layer_type_1/add" + op: "Add" + input: "final_layer_type_1/MatMul" + input: "final_layer_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_15_grad/Shape" + op: "Shape" + input: "final_layer_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_15" + op: "Reshape" + input: "final_layer_type_1/add" + input: "Reshape_15/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_2" + op: "Shape" + input: "Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_16" + op: "StridedSlice" + input: "Shape_2" + input: "strided_slice_16/stack" + input: "strided_slice_16/stack_1" + input: "strided_slice_16/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_13/shape" + op: "Pack" + input: "strided_slice_16" + input: "strided_slice_17" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_2" + op: "Slice" + input: "Reshape_11" + input: "Slice_2/begin" + input: "Slice_2/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Slice_2_grad/Shape" + op: "Shape" + input: "Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/sub" + op: "Sub" + input: "gradients/Slice_2_grad/Shape_1" + input: "gradients/Slice_2_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/sub_1" + op: "Sub" + input: "gradients/Slice_2_grad/sub" + input: "Slice_2/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/Reshape_1" + op: "Reshape" + input: "gradients/Slice_2_grad/sub_1" + input: "gradients/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/concat" + op: "ConcatV2" + input: "gradients/Slice_2_grad/Reshape" + input: "gradients/Slice_2_grad/Reshape_1" + input: "gradients/Slice_2_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_12_grad/Shape" + op: "Shape" + input: "Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_12" + op: "Reshape" + input: "Slice_2" + input: "Reshape_12/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_0/MatMul" + op: "MatMul" + input: "Reshape_12" + input: "layer_0_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/Shape" + op: "Shape" + input: "layer_0_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_0_type_0/add_grad/Shape" + input: "gradients/layer_0_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_0/add" + op: "Add" + input: "layer_0_type_0/MatMul" + input: "layer_0_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_0_type_0/Tanh" + op: "Tanh" + input: "layer_0_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_0_type_0/Reshape_grad/Shape" + op: "Shape" + input: "layer_0_type_0/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_0/Reshape" + op: "Reshape" + input: "layer_0_type_0/Tanh" + input: "layer_0_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_3_grad/Shape" + op: "Shape" + input: "layer_0_type_0/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/MatMul" + op: "MatMul" + input: "layer_0_type_0/Reshape" + input: "layer_1_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/Shape" + op: "Shape" + input: "layer_1_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_1_type_0/add_grad/Shape" + input: "gradients/layer_1_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/add" + op: "Add" + input: "layer_1_type_0/MatMul" + input: "layer_1_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_1_type_0/Tanh" + op: "Tanh" + input: "layer_1_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_0/Reshape_grad/Shape" + op: "Shape" + input: "layer_1_type_0/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/Reshape" + op: "Reshape" + input: "layer_1_type_0/Tanh" + input: "layer_1_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Shape" + op: "Shape" + input: "layer_1_type_0/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_1_type_0/mul_grad/Shape" + input: "gradients/layer_1_type_0/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/mul" + op: "Mul" + input: "layer_1_type_0/Reshape" + input: "layer_1_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_3_grad/Shape_1" + op: "Shape" + input: "layer_1_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_3_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/add_3_grad/Shape" + input: "gradients/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_3" + op: "Add" + input: "layer_0_type_0/Reshape" + input: "layer_1_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_4_grad/Shape" + op: "Shape" + input: "add_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/MatMul" + op: "MatMul" + input: "add_3" + input: "layer_2_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/Shape" + op: "Shape" + input: "layer_2_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_2_type_0/add_grad/Shape" + input: "gradients/layer_2_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/add" + op: "Add" + input: "layer_2_type_0/MatMul" + input: "layer_2_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_0/Tanh" + op: "Tanh" + input: "layer_2_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_0/Reshape_grad/Shape" + op: "Shape" + input: "layer_2_type_0/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/Reshape" + op: "Reshape" + input: "layer_2_type_0/Tanh" + input: "layer_2_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Shape" + op: "Shape" + input: "layer_2_type_0/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_2_type_0/mul_grad/Shape" + input: "gradients/layer_2_type_0/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/mul" + op: "Mul" + input: "layer_2_type_0/Reshape" + input: "layer_2_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_4_grad/Shape_1" + op: "Shape" + input: "layer_2_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_4_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/add_4_grad/Shape" + input: "gradients/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_4" + op: "Add" + input: "add_3" + input: "layer_2_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "final_layer_type_0/MatMul" + op: "MatMul" + input: "add_4" + input: "final_layer_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/Shape" + op: "Shape" + input: "final_layer_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/final_layer_type_0/add_grad/Shape" + input: "gradients/final_layer_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "final_layer_type_0/add" + op: "Add" + input: "final_layer_type_0/MatMul" + input: "final_layer_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_13_grad/Shape" + op: "Shape" + input: "final_layer_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_13" + op: "Reshape" + input: "final_layer_type_0/add" + input: "Reshape_13/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_1_grad/ShapeN" + op: "ShapeN" + input: "Reshape_13" + input: "Reshape_15" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_1_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/concat_1_grad/mod" + input: "gradients/concat_1_grad/ShapeN" + input: "gradients/concat_1_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "concat_1" + op: "ConcatV2" + input: "Reshape_13" + input: "Reshape_15" + input: "concat_1/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_16_grad/Shape" + op: "Shape" + input: "concat_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_16" + op: "Reshape" + input: "concat_1" + input: "Reshape_16/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Shape" + op: "Shape" + input: "Reshape_16" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Fill" + op: "Fill" + input: "gradients/Shape" + input: "gradients/grad_ys_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "index_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_16_grad/Reshape" + op: "Reshape" + input: "gradients/Fill" + input: "gradients/Reshape_16_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_1_grad/Slice_1" + op: "Slice" + input: "gradients/Reshape_16_grad/Reshape" + input: "gradients/concat_1_grad/ConcatOffset:1" + input: "gradients/concat_1_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_15_grad/Reshape" + op: "Reshape" + input: "gradients/concat_1_grad/Slice_1" + input: "gradients/Reshape_15_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/Reshape_15_grad/Reshape" + input: "gradients/final_layer_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/final_layer_type_1/add_grad/Sum" + input: "gradients/final_layer_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/final_layer_type_1/add_grad/Reshape" + input: "final_layer_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_7_grad/Sum_1" + op: "Sum" + input: "gradients/final_layer_type_1/MatMul_grad/MatMul" + input: "gradients/add_7_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_7_grad/Reshape_1" + op: "Reshape" + input: "gradients/add_7_grad/Sum_1" + input: "gradients/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients/add_7_grad/Reshape_1" + input: "layer_2_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients/layer_2_type_1/mul_grad/Mul" + input: "gradients/layer_2_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_1/mul_grad/Sum" + input: "gradients/layer_2_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_1/mul_grad/Reshape" + input: "gradients/layer_2_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_2_type_1/Tanh" + input: "gradients/layer_2_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/layer_2_type_1/Tanh_grad/TanhGrad" + input: "gradients/layer_2_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_1/add_grad/Sum" + input: "gradients/layer_2_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_2_type_1/add_grad/Reshape" + input: "layer_2_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_7_grad/Sum" + op: "Sum" + input: "gradients/final_layer_type_1/MatMul_grad/MatMul" + input: "gradients/add_7_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_7_grad/Reshape" + op: "Reshape" + input: "gradients/add_7_grad/Sum" + input: "gradients/add_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_1" + op: "AddN" + input: "gradients/add_7_grad/Reshape" + input: "gradients/layer_2_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/add_7_grad/Reshape" + } + } + } +} +node { + name: "gradients/add_6_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_1" + input: "gradients/add_6_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_6_grad/Reshape_1" + op: "Reshape" + input: "gradients/add_6_grad/Sum_1" + input: "gradients/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients/add_6_grad/Reshape_1" + input: "layer_1_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients/layer_1_type_1/mul_grad/Mul" + input: "gradients/layer_1_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_1/mul_grad/Sum" + input: "gradients/layer_1_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_1/mul_grad/Reshape" + input: "gradients/layer_1_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_1_type_1/Tanh" + input: "gradients/layer_1_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/layer_1_type_1/Tanh_grad/TanhGrad" + input: "gradients/layer_1_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_1/add_grad/Sum" + input: "gradients/layer_1_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_1_type_1/add_grad/Reshape" + input: "layer_1_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_6_grad/Sum" + op: "Sum" + input: "gradients/AddN_1" + input: "gradients/add_6_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_6_grad/Reshape" + op: "Reshape" + input: "gradients/add_6_grad/Sum" + input: "gradients/add_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_3" + op: "AddN" + input: "gradients/add_6_grad/Reshape" + input: "gradients/layer_1_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/add_6_grad/Reshape" + } + } + } +} +node { + name: "gradients/layer_0_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_3" + input: "gradients/layer_0_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_0_type_1/Tanh" + input: "gradients/layer_0_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/layer_0_type_1/Tanh_grad/TanhGrad" + input: "gradients/layer_0_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_0_type_1/add_grad/Sum" + input: "gradients/layer_0_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_0_type_1/add_grad/Reshape" + input: "layer_0_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/Reshape_14_grad/Reshape" + op: "Reshape" + input: "gradients/layer_0_type_1/MatMul_grad/MatMul" + input: "gradients/Reshape_14_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/Pad" + op: "Pad" + input: "gradients/Reshape_14_grad/Reshape" + input: "gradients/Slice_3_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_1_grad/Slice" + op: "Slice" + input: "gradients/Reshape_16_grad/Reshape" + input: "gradients/concat_1_grad/ConcatOffset" + input: "gradients/concat_1_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_13_grad/Reshape" + op: "Reshape" + input: "gradients/concat_1_grad/Slice" + input: "gradients/Reshape_13_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/Reshape_13_grad/Reshape" + input: "gradients/final_layer_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/final_layer_type_0/add_grad/Sum" + input: "gradients/final_layer_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/final_layer_type_0/add_grad/Reshape" + input: "final_layer_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_4_grad/Sum_1" + op: "Sum" + input: "gradients/final_layer_type_0/MatMul_grad/MatMul" + input: "gradients/add_4_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_4_grad/Reshape_1" + op: "Reshape" + input: "gradients/add_4_grad/Sum_1" + input: "gradients/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Mul" + op: "Mul" + input: "gradients/add_4_grad/Reshape_1" + input: "layer_2_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Sum" + op: "Sum" + input: "gradients/layer_2_type_0/mul_grad/Mul" + input: "gradients/layer_2_type_0/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_0/mul_grad/Sum" + input: "gradients/layer_2_type_0/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_0/mul_grad/Reshape" + input: "gradients/layer_2_type_0/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_2_type_0/Tanh" + input: "gradients/layer_2_type_0/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/layer_2_type_0/Tanh_grad/TanhGrad" + input: "gradients/layer_2_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_0/add_grad/Sum" + input: "gradients/layer_2_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_2_type_0/add_grad/Reshape" + input: "layer_2_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_4_grad/Sum" + op: "Sum" + input: "gradients/final_layer_type_0/MatMul_grad/MatMul" + input: "gradients/add_4_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_4_grad/Reshape" + op: "Reshape" + input: "gradients/add_4_grad/Sum" + input: "gradients/add_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN" + op: "AddN" + input: "gradients/add_4_grad/Reshape" + input: "gradients/layer_2_type_0/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/add_4_grad/Reshape" + } + } + } +} +node { + name: "gradients/add_3_grad/Sum_1" + op: "Sum" + input: "gradients/AddN" + input: "gradients/add_3_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/add_3_grad/Sum_1" + input: "gradients/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Mul" + op: "Mul" + input: "gradients/add_3_grad/Reshape_1" + input: "layer_1_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Sum" + op: "Sum" + input: "gradients/layer_1_type_0/mul_grad/Mul" + input: "gradients/layer_1_type_0/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_0/mul_grad/Sum" + input: "gradients/layer_1_type_0/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_0/mul_grad/Reshape" + input: "gradients/layer_1_type_0/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_1_type_0/Tanh" + input: "gradients/layer_1_type_0/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/layer_1_type_0/Tanh_grad/TanhGrad" + input: "gradients/layer_1_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_0/add_grad/Sum" + input: "gradients/layer_1_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_1_type_0/add_grad/Reshape" + input: "layer_1_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_3_grad/Sum" + op: "Sum" + input: "gradients/AddN" + input: "gradients/add_3_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_3_grad/Reshape" + op: "Reshape" + input: "gradients/add_3_grad/Sum" + input: "gradients/add_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_2" + op: "AddN" + input: "gradients/add_3_grad/Reshape" + input: "gradients/layer_1_type_0/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/add_3_grad/Reshape" + } + } + } +} +node { + name: "gradients/layer_0_type_0/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_2" + input: "gradients/layer_0_type_0/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_0/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_0_type_0/Tanh" + input: "gradients/layer_0_type_0/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/layer_0_type_0/Tanh_grad/TanhGrad" + input: "gradients/layer_0_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_0_type_0/add_grad/Sum" + input: "gradients/layer_0_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_0_type_0/add_grad/Reshape" + input: "layer_0_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/Reshape_12_grad/Reshape" + op: "Reshape" + input: "gradients/layer_0_type_0/MatMul_grad/MatMul" + input: "gradients/Reshape_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/Pad" + op: "Pad" + input: "gradients/Reshape_12_grad/Reshape" + input: "gradients/Slice_2_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_4" + op: "AddN" + input: "gradients/Slice_2_grad/Pad" + input: "gradients/Slice_3_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/Slice_2_grad/Pad" + } + } + } +} +node { + name: "gradients/Reshape_11_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_4" + input: "gradients/Reshape_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/Slice_1" + op: "Slice" + input: "gradients/Reshape_11_grad/Reshape" + input: "gradients/concat_grad/ConcatOffset:1" + input: "gradients/concat_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_10_grad/Reshape" + op: "Reshape" + input: "gradients/concat_grad/Slice_1" + input: "gradients/Reshape_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients/Reshape_10_grad/Reshape" + input: "filter_type_1/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/mul_grad/Mul" + input: "gradients/filter_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/mul_grad/Sum" + input: "gradients/filter_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/mul_grad/Reshape" + input: "gradients/filter_type_1/Mean_grad/DynamicStitch" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Tile" + op: "Tile" + input: "gradients/filter_type_1/Mean_grad/Reshape" + input: "gradients/filter_type_1/Mean_grad/floordiv" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tmultiples" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/truediv" + op: "RealDiv" + input: "gradients/filter_type_1/Mean_grad/Tile" + input: "gradients/filter_type_1/Mean_grad/Cast" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_6_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/Mean_grad/truediv" + input: "gradients/filter_type_1/concat_6_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_6_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_9_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/concat_6_grad/Slice_1" + input: "gradients/filter_type_1/Reshape_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_1/Reshape_9_grad/Reshape" + input: "gradients/filter_type_1/add_11_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_11_grad/Sum_1" + input: "gradients/filter_type_1/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_8_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_11_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_5_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_5" + input: "gradients/filter_type_1/Reshape_8_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_5_grad/TanhGrad" + input: "gradients/filter_type_1/add_10_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_10_grad/Sum" + input: "gradients/filter_type_1/add_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_5_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_10_grad/Reshape" + input: "filter_type_1/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Reshape_9_grad/Reshape" + input: "gradients/filter_type_1/add_11_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_11_grad/Sum" + input: "gradients/filter_type_1/add_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_11_grad/Reshape" + input: "gradients/filter_type_1/concat_5_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_5_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_11_grad/Reshape" + input: "gradients/filter_type_1/concat_5_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_5_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_8" + op: "AddN" + input: "gradients/filter_type_1/concat_5_grad/Slice" + input: "gradients/filter_type_1/concat_5_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_5_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_5_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_8" + input: "gradients/filter_type_1/add_9_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_9_grad/Sum_1" + input: "gradients/filter_type_1/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_7_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_9_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_4_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_4" + input: "gradients/filter_type_1/Reshape_7_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_4_grad/TanhGrad" + input: "gradients/filter_type_1/add_8_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_8_grad/Sum" + input: "gradients/filter_type_1/add_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_4_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_8_grad/Reshape" + input: "filter_type_1/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Sum" + op: "Sum" + input: "gradients/AddN_8" + input: "gradients/filter_type_1/add_9_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_9_grad/Sum" + input: "gradients/filter_type_1/add_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_9_grad/Reshape" + input: "gradients/filter_type_1/concat_4_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_4_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_9_grad/Reshape" + input: "gradients/filter_type_1/concat_4_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_4_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_12" + op: "AddN" + input: "gradients/filter_type_1/concat_4_grad/Slice" + input: "gradients/filter_type_1/concat_4_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_4_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_4_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_12" + input: "gradients/filter_type_1/add_7_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_7_grad/Sum_1" + input: "gradients/filter_type_1/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_6_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_7_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_3_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_3" + input: "gradients/filter_type_1/Reshape_6_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_3_grad/TanhGrad" + input: "gradients/filter_type_1/add_6_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_6_grad/Sum" + input: "gradients/filter_type_1/add_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_3_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_6_grad/Reshape" + input: "filter_type_1/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Sum" + op: "Sum" + input: "gradients/AddN_12" + input: "gradients/filter_type_1/add_7_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_7_grad/Sum" + input: "gradients/filter_type_1/add_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_7_grad/Reshape" + input: "gradients/filter_type_1/concat_3_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_3_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_7_grad/Reshape" + input: "gradients/filter_type_1/concat_3_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_3_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_16" + op: "AddN" + input: "gradients/filter_type_1/concat_3_grad/Slice" + input: "gradients/filter_type_1/concat_3_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_3_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_3_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/Reshape_5_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_16" + input: "gradients/filter_type_1/Reshape_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Pad" + op: "Pad" + input: "gradients/filter_type_1/Reshape_5_grad/Reshape" + input: "gradients/filter_type_1/Slice_1_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_6_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/Mean_grad/truediv" + input: "gradients/filter_type_1/concat_6_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_6_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_4_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/concat_6_grad/Slice" + input: "gradients/filter_type_1/Reshape_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_1/Reshape_4_grad/Reshape" + input: "gradients/filter_type_1/add_5_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_5_grad/Sum_1" + input: "gradients/filter_type_1/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_3_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_5_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_2_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_2" + input: "gradients/filter_type_1/Reshape_3_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_2_grad/TanhGrad" + input: "gradients/filter_type_1/add_4_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_4_grad/Sum" + input: "gradients/filter_type_1/add_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_2_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_4_grad/Reshape" + input: "filter_type_1/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Reshape_4_grad/Reshape" + input: "gradients/filter_type_1/add_5_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_5_grad/Sum" + input: "gradients/filter_type_1/add_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_5_grad/Reshape" + input: "gradients/filter_type_1/concat_2_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_2_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_5_grad/Reshape" + input: "gradients/filter_type_1/concat_2_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_2_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_7" + op: "AddN" + input: "gradients/filter_type_1/concat_2_grad/Slice" + input: "gradients/filter_type_1/concat_2_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_2_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_2_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_7" + input: "gradients/filter_type_1/add_3_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_3_grad/Sum_1" + input: "gradients/filter_type_1/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_2_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_3_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_1_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_1" + input: "gradients/filter_type_1/Reshape_2_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_1_grad/TanhGrad" + input: "gradients/filter_type_1/add_2_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_2_grad/Sum" + input: "gradients/filter_type_1/add_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_1_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_2_grad/Reshape" + input: "filter_type_1/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Sum" + op: "Sum" + input: "gradients/AddN_7" + input: "gradients/filter_type_1/add_3_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_3_grad/Sum" + input: "gradients/filter_type_1/add_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_3_grad/Reshape" + input: "gradients/filter_type_1/concat_1_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_1_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_3_grad/Reshape" + input: "gradients/filter_type_1/concat_1_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_1_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_11" + op: "AddN" + input: "gradients/filter_type_1/concat_1_grad/Slice" + input: "gradients/filter_type_1/concat_1_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_1_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_1_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_11" + input: "gradients/filter_type_1/add_1_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_1_grad/Sum_1" + input: "gradients/filter_type_1/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_1_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_1_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh" + input: "gradients/filter_type_1/Reshape_1_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_grad/TanhGrad" + input: "gradients/filter_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_grad/Sum" + input: "gradients/filter_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_grad/Reshape" + input: "filter_type_1/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Sum" + op: "Sum" + input: "gradients/AddN_11" + input: "gradients/filter_type_1/add_1_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_1_grad/Sum" + input: "gradients/filter_type_1/add_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_1_grad/Reshape" + input: "gradients/filter_type_1/concat_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_1_grad/Reshape" + input: "gradients/filter_type_1/concat_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_15" + op: "AddN" + input: "gradients/filter_type_1/concat_grad/Slice" + input: "gradients/filter_type_1/concat_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_15" + input: "gradients/filter_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Pad" + op: "Pad" + input: "gradients/filter_type_1/Reshape_grad/Reshape" + input: "gradients/filter_type_1/Slice_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_18" + op: "AddN" + input: "gradients/filter_type_1/Slice_grad/Pad" + input: "gradients/filter_type_1/Slice_1_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Slice_grad/Pad" + } + } + } +} +node { + name: "gradients/Reshape_9_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_18" + input: "gradients/Reshape_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/Pad" + op: "Pad" + input: "gradients/Reshape_9_grad/Reshape" + input: "gradients/Slice_1_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/Slice" + op: "Slice" + input: "gradients/Reshape_11_grad/Reshape" + input: "gradients/concat_grad/ConcatOffset" + input: "gradients/concat_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_8_grad/Reshape" + op: "Reshape" + input: "gradients/concat_grad/Slice" + input: "gradients/Reshape_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Mul" + op: "Mul" + input: "gradients/Reshape_8_grad/Reshape" + input: "filter_type_0/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/mul_grad/Mul" + input: "gradients/filter_type_0/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/mul_grad/Sum" + input: "gradients/filter_type_0/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/mul_grad/Reshape" + input: "gradients/filter_type_0/Mean_grad/DynamicStitch" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Tile" + op: "Tile" + input: "gradients/filter_type_0/Mean_grad/Reshape" + input: "gradients/filter_type_0/Mean_grad/floordiv" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tmultiples" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/truediv" + op: "RealDiv" + input: "gradients/filter_type_0/Mean_grad/Tile" + input: "gradients/filter_type_0/Mean_grad/Cast" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_6_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/Mean_grad/truediv" + input: "gradients/filter_type_0/concat_6_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_6_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_9_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/concat_6_grad/Slice_1" + input: "gradients/filter_type_0/Reshape_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_0/Reshape_9_grad/Reshape" + input: "gradients/filter_type_0/add_11_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_11_grad/Sum_1" + input: "gradients/filter_type_0/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_8_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_11_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_5_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_5" + input: "gradients/filter_type_0/Reshape_8_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_5_grad/TanhGrad" + input: "gradients/filter_type_0/add_10_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_10_grad/Sum" + input: "gradients/filter_type_0/add_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_5_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_10_grad/Reshape" + input: "filter_type_0/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Reshape_9_grad/Reshape" + input: "gradients/filter_type_0/add_11_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_11_grad/Sum" + input: "gradients/filter_type_0/add_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_11_grad/Reshape" + input: "gradients/filter_type_0/concat_5_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_5_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_11_grad/Reshape" + input: "gradients/filter_type_0/concat_5_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_5_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_6" + op: "AddN" + input: "gradients/filter_type_0/concat_5_grad/Slice" + input: "gradients/filter_type_0/concat_5_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_5_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_5_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_6" + input: "gradients/filter_type_0/add_9_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_9_grad/Sum_1" + input: "gradients/filter_type_0/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_7_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_9_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_4_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_4" + input: "gradients/filter_type_0/Reshape_7_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_4_grad/TanhGrad" + input: "gradients/filter_type_0/add_8_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_8_grad/Sum" + input: "gradients/filter_type_0/add_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_4_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_8_grad/Reshape" + input: "filter_type_0/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Sum" + op: "Sum" + input: "gradients/AddN_6" + input: "gradients/filter_type_0/add_9_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_9_grad/Sum" + input: "gradients/filter_type_0/add_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_9_grad/Reshape" + input: "gradients/filter_type_0/concat_4_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_4_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_9_grad/Reshape" + input: "gradients/filter_type_0/concat_4_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_4_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_10" + op: "AddN" + input: "gradients/filter_type_0/concat_4_grad/Slice" + input: "gradients/filter_type_0/concat_4_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_4_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_4_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_10" + input: "gradients/filter_type_0/add_7_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_7_grad/Sum_1" + input: "gradients/filter_type_0/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_6_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_7_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_3_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_3" + input: "gradients/filter_type_0/Reshape_6_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_3_grad/TanhGrad" + input: "gradients/filter_type_0/add_6_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_6_grad/Sum" + input: "gradients/filter_type_0/add_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_3_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_6_grad/Reshape" + input: "filter_type_0/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Sum" + op: "Sum" + input: "gradients/AddN_10" + input: "gradients/filter_type_0/add_7_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_7_grad/Sum" + input: "gradients/filter_type_0/add_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_7_grad/Reshape" + input: "gradients/filter_type_0/concat_3_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_3_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_7_grad/Reshape" + input: "gradients/filter_type_0/concat_3_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_3_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_14" + op: "AddN" + input: "gradients/filter_type_0/concat_3_grad/Slice" + input: "gradients/filter_type_0/concat_3_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_3_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_3_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/Reshape_5_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_14" + input: "gradients/filter_type_0/Reshape_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Pad" + op: "Pad" + input: "gradients/filter_type_0/Reshape_5_grad/Reshape" + input: "gradients/filter_type_0/Slice_1_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_6_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/Mean_grad/truediv" + input: "gradients/filter_type_0/concat_6_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_6_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_4_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/concat_6_grad/Slice" + input: "gradients/filter_type_0/Reshape_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_0/Reshape_4_grad/Reshape" + input: "gradients/filter_type_0/add_5_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_5_grad/Sum_1" + input: "gradients/filter_type_0/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_3_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_5_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_2_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_2" + input: "gradients/filter_type_0/Reshape_3_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_2_grad/TanhGrad" + input: "gradients/filter_type_0/add_4_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_4_grad/Sum" + input: "gradients/filter_type_0/add_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_2_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_4_grad/Reshape" + input: "filter_type_0/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Reshape_4_grad/Reshape" + input: "gradients/filter_type_0/add_5_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_5_grad/Sum" + input: "gradients/filter_type_0/add_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_5_grad/Reshape" + input: "gradients/filter_type_0/concat_2_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_2_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_5_grad/Reshape" + input: "gradients/filter_type_0/concat_2_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_2_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_5" + op: "AddN" + input: "gradients/filter_type_0/concat_2_grad/Slice" + input: "gradients/filter_type_0/concat_2_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_2_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_2_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_5" + input: "gradients/filter_type_0/add_3_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_3_grad/Sum_1" + input: "gradients/filter_type_0/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_2_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_3_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_1_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_1" + input: "gradients/filter_type_0/Reshape_2_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_1_grad/TanhGrad" + input: "gradients/filter_type_0/add_2_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_2_grad/Sum" + input: "gradients/filter_type_0/add_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_1_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_2_grad/Reshape" + input: "filter_type_0/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Sum" + op: "Sum" + input: "gradients/AddN_5" + input: "gradients/filter_type_0/add_3_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_3_grad/Sum" + input: "gradients/filter_type_0/add_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_3_grad/Reshape" + input: "gradients/filter_type_0/concat_1_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_1_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_3_grad/Reshape" + input: "gradients/filter_type_0/concat_1_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_1_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_9" + op: "AddN" + input: "gradients/filter_type_0/concat_1_grad/Slice" + input: "gradients/filter_type_0/concat_1_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_1_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_1_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_9" + input: "gradients/filter_type_0/add_1_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_1_grad/Sum_1" + input: "gradients/filter_type_0/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_1_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_1_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh" + input: "gradients/filter_type_0/Reshape_1_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_grad/TanhGrad" + input: "gradients/filter_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_grad/Sum" + input: "gradients/filter_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_grad/Reshape" + input: "filter_type_0/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Sum" + op: "Sum" + input: "gradients/AddN_9" + input: "gradients/filter_type_0/add_1_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_1_grad/Sum" + input: "gradients/filter_type_0/add_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_1_grad/Reshape" + input: "gradients/filter_type_0/concat_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_1_grad/Reshape" + input: "gradients/filter_type_0/concat_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_13" + op: "AddN" + input: "gradients/filter_type_0/concat_grad/Slice" + input: "gradients/filter_type_0/concat_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_13" + input: "gradients/filter_type_0/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Pad" + op: "Pad" + input: "gradients/filter_type_0/Reshape_grad/Reshape" + input: "gradients/filter_type_0/Slice_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_17" + op: "AddN" + input: "gradients/filter_type_0/Slice_grad/Pad" + input: "gradients/filter_type_0/Slice_1_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Slice_grad/Pad" + } + } + } +} +node { + name: "gradients/Reshape_7_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_17" + input: "gradients/Reshape_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/Pad" + op: "Pad" + input: "gradients/Reshape_7_grad/Reshape" + input: "gradients/Slice_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_19" + op: "AddN" + input: "gradients/Slice_grad/Pad" + input: "gradients/Slice_1_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/Slice_grad/Pad" + } + } + } +} +node { + name: "gradients/Reshape_6_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_19" + input: "gradients/Reshape_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_17" + op: "Reshape" + input: "gradients/Reshape_6_grad/Reshape" + input: "Reshape_17/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "ProdVirialSeR" + op: "ProdVirialSeR" + input: "Reshape_17" + input: "o_rmat_deriv" + input: "o_rij" + input: "o_nlist" + input: "t_natoms" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "o_atom_virial" + op: "Reshape" + input: "ProdVirialSeR:1" + input: "o_atom_virial/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_virial" + op: "Reshape" + input: "ProdVirialSeR" + input: "o_virial/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "ProdForceSeR" + op: "ProdForceSeR" + input: "Reshape_17" + input: "o_rmat_deriv" + input: "o_nlist" + input: "t_natoms" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "o_force" + op: "Reshape" + input: "ProdForceSeR" + input: "o_force/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_atom_energy" + op: "Reshape" + input: "Reshape_16" + input: "o_atom_energy/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_energy" + op: "Sum" + input: "o_atom_energy" + input: "o_energy/reduction_indices" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +library { +} diff --git a/source/tests/test_deeppot.py b/source/tests/test_deeppot_a.py similarity index 99% rename from source/tests/test_deeppot.py rename to source/tests/test_deeppot_a.py index a513ad492d..8dee81df75 100644 --- a/source/tests/test_deeppot.py +++ b/source/tests/test_deeppot_a.py @@ -12,7 +12,7 @@ else : default_places = 10 -class TestDeepPotPBC(unittest.TestCase) : +class TestDeepPotAPBC(unittest.TestCase) : def setUp(self): convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot.pbtxt")), "deeppot.pb") self.dp = DeepPot("deeppot.pb") @@ -111,7 +111,7 @@ def test_2frame_atm(self): self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) -class TestDeepPotNoPBC(unittest.TestCase) : +class TestDeepPotANoPBC(unittest.TestCase) : def setUp(self): convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot.pbtxt")), "deeppot.pb") self.dp = DeepPot("deeppot.pb") @@ -202,7 +202,7 @@ def test_2frame_atm(self): self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) -class TestDeepPotLargeBoxNoPBC(unittest.TestCase) : +class TestDeepPotALargeBoxNoPBC(unittest.TestCase) : def setUp(self): convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot.pbtxt")), "deeppot.pb") self.dp = DeepPot("deeppot.pb") diff --git a/source/tests/test_deeppot_r.py b/source/tests/test_deeppot_r.py new file mode 100644 index 0000000000..7f9a97ce66 --- /dev/null +++ b/source/tests/test_deeppot_r.py @@ -0,0 +1,290 @@ +import os,sys,platform,shutil,dpdata +import numpy as np +import unittest + +from infer.convert2pb import convert_pbtxt_to_pb +from deepmd.infer import DeepPot +from common import tests_path + +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +if GLOBAL_NP_FLOAT_PRECISION == np.float32 : + default_places = 4 +else : + default_places = 10 + +class TestDeepPotRPBC(unittest.TestCase) : + def setUp(self): + convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot-r.pbtxt")), "deeppot.pb") + self.dp = DeepPot("deeppot.pb") + self.coords = np.array([12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56]) + self.atype = [0, 1, 1, 0, 1, 1] + self.box = np.array([13., 0., 0., 0., 13., 0., 0., 0., 13.]) + self.expected_e = np.array([ + -9.320909762801588272e+01,-1.868020345400987878e+02,-1.868011172371355997e+02,-9.320868430396934912e+01,-1.868010398844378415e+02,-1.868016706555875999e+02 + ]) + self.expected_f = np.array([ + 6.385312846474267391e-04,-6.460452911141417731e-03,-5.652405655332678417e-04,-7.516468794343579736e-03,1.128804614240160216e-03,5.531937784564192051e-03,1.914138124904981664e-03,5.601819906021693503e-03,-5.131359585752605541e-03,-4.847104424804288617e-03,1.992071550328819614e-03,-4.028159855157302516e-03,1.236340684486603517e-03,-5.373955841338794344e-03,8.312829460571366513e-03,8.574563125108854156e-03,3.111712681889538742e-03,-4.120007238692381148e-03 + ]) + self.expected_v = np.array([ + 5.844056241889131371e-03,4.663973497239899614e-04,-2.268382127762904633e-03,4.663973497239897988e-04,2.349338784202595950e-03,-6.908546513234039253e-04,-2.268382127762904633e-03,-6.908546513234039253e-04,2.040499248150800561e-03,4.238130266437327605e-03,-1.539867187443782223e-04,-2.393101333240631613e-03,-1.539867187443782223e-04,4.410341945447907377e-04,9.544239698119633068e-06,-2.393101333240631613e-03,9.544239698119578858e-06,1.877785959095269654e-03,5.798992562057291543e-03,6.943392552230453693e-04,-1.180376879311998773e-03,6.943392552230453693e-04,1.686725132156275536e-03,-1.461632060145726542e-03,-1.180376879311998556e-03,-1.461632060145726325e-03,1.749543733794208444e-03,7.173915604192910439e-03,3.903218041111061569e-04,-5.747400467123527524e-04,3.903218041111061569e-04,1.208289706621179949e-03,-1.826828914132010932e-03,-5.747400467123527524e-04,-1.826828914132011148e-03,2.856960586657185906e-03,4.067553030177322240e-03,-3.267469855253819430e-05,-6.980667859103454904e-05,-3.267469855253830272e-05,1.387653029234650918e-03,-2.096820720698671855e-03,-6.980667859103444062e-05,-2.096820720698671855e-03,3.218305506720191278e-03,4.753992590355240674e-03,1.224911338353675992e-03,-1.683421934571502484e-03,1.224911338353676209e-03,7.332113564901583539e-04,-1.025577052190138451e-03,-1.683421934571502484e-03,-1.025577052190138234e-03,1.456681925652047018e-03 + ]) + + def tearDown(self): + os.remove("deeppot.pb") + + def test_attrs(self): + self.assertEqual(self.dp.get_ntypes(), 2) + self.assertAlmostEqual(self.dp.get_rcut(), 6.0, places = default_places) + self.assertEqual(self.dp.get_type_map(), ['O', 'H']) + self.assertEqual(self.dp.get_dim_fparam(), 0) + self.assertEqual(self.dp.get_dim_aparam(), 0) + + # def test_1frame(self): + # ee, ff, vv, ae, av = self.dp.eval(self.coords, self.box, self.atype, atomic = True) + # np.savetxt('ee.out', ae.reshape([1, -1]), delimiter=',') + # np.savetxt('ff.out', ff.reshape([1, -1]), delimiter=',') + # np.savetxt('vv.out', av.reshape([1, -1]), delimiter=',') + + def test_1frame(self): + ee, ff, vv = self.dp.eval(self.coords, self.box, self.atype, atomic = False) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + def test_1frame_atm(self): + ee, ff, vv, ae, av = self.dp.eval(self.coords, self.box, self.atype, atomic = True) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + self.assertEqual(ae.shape, (nframes,natoms,1)) + self.assertEqual(av.shape, (nframes,natoms,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + for ii in range(ae.size): + self.assertAlmostEqual(ae.reshape([-1])[ii], self.expected_e.reshape([-1])[ii], places = default_places) + for ii in range(av.size): + self.assertAlmostEqual(av.reshape([-1])[ii], self.expected_v.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + + def test_2frame_atm(self): + coords2 = np.concatenate((self.coords, self.coords)) + box2 = np.concatenate((self.box, self.box)) + ee, ff, vv, ae, av = self.dp.eval(coords2, box2, self.atype, atomic = True) + # check shape of the returns + nframes = 2 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + self.assertEqual(ae.shape, (nframes,natoms,1)) + self.assertEqual(av.shape, (nframes,natoms,9)) + # check values + expected_f = np.concatenate((self.expected_f, self.expected_f), axis = 0) + expected_e = np.concatenate((self.expected_e, self.expected_e), axis = 0) + expected_v = np.concatenate((self.expected_v, self.expected_v), axis = 0) + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], expected_f.reshape([-1])[ii], places = default_places) + for ii in range(ae.size): + self.assertAlmostEqual(ae.reshape([-1])[ii], expected_e.reshape([-1])[ii], places = default_places) + for ii in range(av.size): + self.assertAlmostEqual(av.reshape([-1])[ii], expected_v.reshape([-1])[ii], places = default_places) + expected_se = np.sum(expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + +class TestDeepPotRNoPBC(unittest.TestCase) : + def setUp(self): + convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot-r.pbtxt")), "deeppot.pb") + self.dp = DeepPot("deeppot.pb") + self.coords = np.array([12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56]) + self.atype = [0, 1, 1, 0, 1, 1] + self.box = None + self.expected_e = np.array([ + -9.321213823508108476e+01,-1.868044102481340758e+02,-1.868067983858651075e+02,-9.320899631301440991e+01,-1.868014559732615112e+02,-1.868017660713088617e+02 + ]) + self.expected_f = np.array([ + 4.578151103701261042e-03,-1.917874111009987628e-03,-3.464546781179331930e-03,-4.578151103701261042e-03,1.917874111009987628e-03,3.464546781179331930e-03,-2.624402581721222913e-03,3.566275128489623933e-04,-2.859315986763691776e-04,-5.767787273464367384e-03,1.907053583551196647e-03,-3.889064429673861831e-03,1.786820066350549132e-04,-5.327197473636275694e-03,8.236236182834734409e-03,8.213507848550535492e-03,3.063516377236116545e-03,-4.061240154484504865e-03 + ]) + self.expected_v = np.array([ + 1.984979026299632174e-03,-8.315452677741701822e-04,-1.502146290172694243e-03,-8.315452677741700738e-04,3.483500446080982317e-04,6.292774999372096039e-04,-1.502146290172694243e-03,6.292774999372097123e-04,1.136759354725281907e-03,1.402852790439301908e-03,-5.876815743732210226e-04,-1.061618327900012114e-03,-5.876815743732211311e-04,2.461909298049979960e-04,4.447320022283834766e-04,-1.061618327900012331e-03,4.447320022283834766e-04,8.033868427351443728e-04,4.143606961846296385e-03,-5.511382161123719835e-04,4.465413399437045397e-04,-5.511382161123719835e-04,1.082271054025323839e-04,-1.097918001262628728e-04,4.465413399437046481e-04,-1.097918001262628728e-04,1.220966982358671871e-04,5.263952004497593831e-03,2.395243710938091842e-04,-2.830378939414603329e-04,2.395243710938094010e-04,1.189969706598244898e-03,-1.805627331015851201e-03,-2.830378939414602245e-04,-1.805627331015851635e-03,2.801996513751836820e-03,2.208413501170402270e-03,5.331756287635716889e-05,-1.664423506603235218e-04,5.331756287635695205e-05,1.379626072862918072e-03,-2.094132943741625064e-03,-1.664423506603234133e-04,-2.094132943741625064e-03,3.199787996743366607e-03,4.047014004814953811e-03,1.137904999421357000e-03,-1.568106936614101698e-03,1.137904999421357217e-03,7.205982843216952307e-04,-1.011174600268313238e-03,-1.568106936614101698e-03,-1.011174600268313238e-03,1.435226522157425754e-03 + ]) + + def tearDown(self): + os.remove("deeppot.pb") + + def test_1frame(self): + ee, ff, vv = self.dp.eval(self.coords, self.box, self.atype, atomic = False) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + def test_1frame_atm(self): + ee, ff, vv, ae, av = self.dp.eval(self.coords, self.box, self.atype, atomic = True) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + self.assertEqual(ae.shape, (nframes,natoms,1)) + self.assertEqual(av.shape, (nframes,natoms,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + for ii in range(ae.size): + self.assertAlmostEqual(ae.reshape([-1])[ii], self.expected_e.reshape([-1])[ii], places = default_places) + for ii in range(av.size): + self.assertAlmostEqual(av.reshape([-1])[ii], self.expected_v.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + + def test_2frame_atm(self): + coords2 = np.concatenate((self.coords, self.coords)) + ee, ff, vv, ae, av = self.dp.eval(coords2, self.box, self.atype, atomic = True) + # check shape of the returns + nframes = 2 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + self.assertEqual(ae.shape, (nframes,natoms,1)) + self.assertEqual(av.shape, (nframes,natoms,9)) + # check values + expected_f = np.concatenate((self.expected_f, self.expected_f), axis = 0) + expected_e = np.concatenate((self.expected_e, self.expected_e), axis = 0) + expected_v = np.concatenate((self.expected_v, self.expected_v), axis = 0) + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], expected_f.reshape([-1])[ii], places = default_places) + for ii in range(ae.size): + self.assertAlmostEqual(ae.reshape([-1])[ii], expected_e.reshape([-1])[ii], places = default_places) + for ii in range(av.size): + self.assertAlmostEqual(av.reshape([-1])[ii], expected_v.reshape([-1])[ii], places = default_places) + expected_se = np.sum(expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + +class TestDeepPotRLargeBoxNoPBC(unittest.TestCase) : + def setUp(self): + convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot-r.pbtxt")), "deeppot.pb") + self.dp = DeepPot("deeppot.pb") + self.coords = np.array([12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56]) + self.atype = [0, 1, 1, 0, 1, 1] + self.box = np.array([19., 0., 0., 0., 13., 0., 0., 0., 13.]) + self.expected_e = np.array([ + -9.321213823508108476e+01,-1.868044102481340758e+02,-1.868067983858651075e+02,-9.320899631301440991e+01,-1.868014559732615112e+02,-1.868017660713088617e+02 + ]) + self.expected_f = np.array([ + 4.578151103701261042e-03,-1.917874111009987628e-03,-3.464546781179331930e-03,-4.578151103701261042e-03,1.917874111009987628e-03,3.464546781179331930e-03,-2.624402581721222913e-03,3.566275128489623933e-04,-2.859315986763691776e-04,-5.767787273464367384e-03,1.907053583551196647e-03,-3.889064429673861831e-03,1.786820066350549132e-04,-5.327197473636275694e-03,8.236236182834734409e-03,8.213507848550535492e-03,3.063516377236116545e-03,-4.061240154484504865e-03 + ]) + self.expected_v = np.array([ + 1.984979026299632174e-03,-8.315452677741701822e-04,-1.502146290172694243e-03,-8.315452677741700738e-04,3.483500446080982317e-04,6.292774999372096039e-04,-1.502146290172694243e-03,6.292774999372097123e-04,1.136759354725281907e-03,1.402852790439301908e-03,-5.876815743732210226e-04,-1.061618327900012114e-03,-5.876815743732211311e-04,2.461909298049979960e-04,4.447320022283834766e-04,-1.061618327900012331e-03,4.447320022283834766e-04,8.033868427351443728e-04,4.143606961846296385e-03,-5.511382161123719835e-04,4.465413399437045397e-04,-5.511382161123719835e-04,1.082271054025323839e-04,-1.097918001262628728e-04,4.465413399437046481e-04,-1.097918001262628728e-04,1.220966982358671871e-04,5.263952004497593831e-03,2.395243710938091842e-04,-2.830378939414603329e-04,2.395243710938094010e-04,1.189969706598244898e-03,-1.805627331015851201e-03,-2.830378939414602245e-04,-1.805627331015851635e-03,2.801996513751836820e-03,2.208413501170402270e-03,5.331756287635716889e-05,-1.664423506603235218e-04,5.331756287635695205e-05,1.379626072862918072e-03,-2.094132943741625064e-03,-1.664423506603234133e-04,-2.094132943741625064e-03,3.199787996743366607e-03,4.047014004814953811e-03,1.137904999421357000e-03,-1.568106936614101698e-03,1.137904999421357217e-03,7.205982843216952307e-04,-1.011174600268313238e-03,-1.568106936614101698e-03,-1.011174600268313238e-03,1.435226522157425754e-03 + ]) + + def tearDown(self): + os.remove("deeppot.pb") + + def test_1frame(self): + ee, ff, vv = self.dp.eval(self.coords, self.box, self.atype, atomic = False) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + def test_1frame_atm(self): + ee, ff, vv, ae, av = self.dp.eval(self.coords, self.box, self.atype, atomic = True) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + self.assertEqual(ae.shape, (nframes,natoms,1)) + self.assertEqual(av.shape, (nframes,natoms,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + for ii in range(ae.size): + self.assertAlmostEqual(ae.reshape([-1])[ii], self.expected_e.reshape([-1])[ii], places = default_places) + for ii in range(av.size): + self.assertAlmostEqual(av.reshape([-1])[ii], self.expected_v.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + From 4a96b1150677adce5a9a18eac06d4831abea3b05 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Thu, 11 Mar 2021 20:36:43 +0800 Subject: [PATCH 262/562] fix bug in prod_env_mat. python infer evaluate a batch rather than frame by frame --- deepmd/infer/deep_eval.py | 13 ++++--- deepmd/infer/deep_pot.py | 47 ++++++++++++-------------- source/op/prod_env_mat_multi_device.cc | 10 +++--- 3 files changed, 33 insertions(+), 37 deletions(-) diff --git a/deepmd/infer/deep_eval.py b/deepmd/infer/deep_eval.py index 4add62c151..2c52644eb1 100644 --- a/deepmd/infer/deep_eval.py +++ b/deepmd/infer/deep_eval.py @@ -245,14 +245,13 @@ def eval( tensor = [] feed_dict_test = {} feed_dict_test[self.t_natoms] = natoms_vec - feed_dict_test[self.t_type ] = atom_types + feed_dict_test[self.t_type ] = np.tile(atom_types, [nframes,1]).reshape([-1]) t_out = [self.t_tensor] - for ii in range(nframes) : - feed_dict_test[self.t_coord] = np.reshape(coords[ii:ii+1, :], [-1]) - feed_dict_test[self.t_box ] = np.reshape(cells [ii:ii+1, :], [-1]) - feed_dict_test[self.t_mesh ] = make_default_mesh(cells[ii:ii+1, :]) - v_out = self.sess.run (t_out, feed_dict = feed_dict_test) - tensor.append(v_out[0]) + feed_dict_test[self.t_coord] = np.reshape(coords, [-1]) + feed_dict_test[self.t_box ] = np.reshape(cells , [-1]) + feed_dict_test[self.t_mesh ] = make_default_mesh(cells) + v_out = self.sess.run (t_out, feed_dict = feed_dict_test) + tensor = v_out[0] # reverse map of the outputs if atomic: diff --git a/deepmd/infer/deep_pot.py b/deepmd/infer/deep_pot.py index 80157642ee..8fefe843d5 100644 --- a/deepmd/infer/deep_pot.py +++ b/deepmd/infer/deep_pot.py @@ -259,40 +259,35 @@ def _eval_inner( assert(natoms_vec[0] == natoms) # evaluate - energy = [] - force = [] - virial = [] - ae = [] - av = [] feed_dict_test = {} feed_dict_test[self.t_natoms] = natoms_vec - feed_dict_test[self.t_type ] = atom_types + feed_dict_test[self.t_type ] = np.tile(atom_types, [nframes, 1]).reshape([-1]) t_out = [self.t_energy, self.t_force, self.t_virial] if atomic : t_out += [self.t_ae, self.t_av] - for ii in range(nframes) : - feed_dict_test[self.t_coord] = np.reshape(coords[ii:ii+1, :], [-1]) - feed_dict_test[self.t_box ] = np.reshape(cells [ii:ii+1, :], [-1]) - if self.has_efield: - feed_dict_test[self.t_efield]= np.reshape(efield[ii:ii+1, :], [-1]) - if pbc: - feed_dict_test[self.t_mesh ] = make_default_mesh(cells[ii:ii+1, :]) - else: - feed_dict_test[self.t_mesh ] = np.array([], dtype = np.int32) - if self.has_fparam: - feed_dict_test[self.t_fparam] = np.reshape(fparam[ii:ii+1, :], [-1]) - if self.has_aparam: - feed_dict_test[self.t_aparam] = np.reshape(aparam[ii:ii+1, :], [-1]) - v_out = self.sess.run (t_out, feed_dict = feed_dict_test) - energy.append(v_out[0]) - force .append(v_out[1]) - virial.append(v_out[2]) - if atomic: - ae.append(v_out[3]) - av.append(v_out[4]) + + feed_dict_test[self.t_coord] = np.reshape(coords, [-1]) + feed_dict_test[self.t_box ] = np.reshape(cells , [-1]) + if self.has_efield: + feed_dict_test[self.t_efield]= np.reshape(efield, [-1]) + if pbc: + feed_dict_test[self.t_mesh ] = make_default_mesh(cells) + else: + feed_dict_test[self.t_mesh ] = np.array([], dtype = np.int32) + if self.has_fparam: + feed_dict_test[self.t_fparam] = np.reshape(fparam, [-1]) + if self.has_aparam: + feed_dict_test[self.t_aparam] = np.reshape(aparam, [-1]) + v_out = self.sess.run (t_out, feed_dict = feed_dict_test) + energy = v_out[0] + force = v_out[1] + virial = v_out[2] + if atomic: + ae = v_out[3] + av = v_out[4] # reverse map of the outputs force = self.reverse_map(np.reshape(force, [nframes,-1,3]), imap) diff --git a/source/op/prod_env_mat_multi_device.cc b/source/op/prod_env_mat_multi_device.cc index 09d365869a..bc0cc5e0f3 100644 --- a/source/op/prod_env_mat_multi_device.cc +++ b/source/op/prod_env_mat_multi_device.cc @@ -288,16 +288,17 @@ class ProdEnvMatAOp : public OpKernel { std::vector> jlist(nloc); std::vector coord_cpy; std::vector type_cpy; + int frame_nall = nall; // prepare coord and nlist _prepare_coord_nlist_cpu( context, &coord, coord_cpy, &type, type_cpy, idx_mapping, inlist, ilist, numneigh, firstneigh, jlist, - nall, mem_cpy, mem_nnei, max_nbor_size, + frame_nall, mem_cpy, mem_nnei, max_nbor_size, box, mesh_tensor.flat().data(), nloc, nei_mode, rcut_r, max_cpy_trial, max_nnei_trial); // launch the cpu compute function prod_env_mat_a_cpu( em, em_deriv, rij, nlist, - coord, type, inlist, max_nbor_size, avg, std, nloc, nall, rcut_r, rcut_r_smth, sec_a); + coord, type, inlist, max_nbor_size, avg, std, nloc, frame_nall, rcut_r, rcut_r_smth, sec_a); // do nlist mapping if coords were copied if(b_nlist_map) _map_nlist_cpu(nlist, &idx_mapping[0], nloc, nnei); } @@ -494,16 +495,17 @@ class ProdEnvMatROp : public OpKernel { std::vector> jlist(nloc); std::vector coord_cpy; std::vector type_cpy; + int frame_nall = nall; // prepare coord and nlist _prepare_coord_nlist_cpu( context, &coord, coord_cpy, &type, type_cpy, idx_mapping, inlist, ilist, numneigh, firstneigh, jlist, - nall, mem_cpy, mem_nnei, max_nbor_size, + frame_nall, mem_cpy, mem_nnei, max_nbor_size, box, mesh_tensor.flat().data(), nloc, nei_mode, rcut, max_cpy_trial, max_nnei_trial); // launch the cpu compute function prod_env_mat_r_cpu( em, em_deriv, rij, nlist, - coord, type, inlist, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); + coord, type, inlist, max_nbor_size, avg, std, nloc, frame_nall, rcut, rcut_smth, sec); if(b_nlist_map) _map_nlist_cpu(nlist, &idx_mapping[0], nloc, nnei); } } From 4cad46fff0dd2f65a68b056e6371e8e06ccf4ec5 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Fri, 12 Mar 2021 01:34:03 +0800 Subject: [PATCH 263/562] add lammps nbor_list support for gpu inference --- source/lib/include/gpu_cuda.h | 15 ++++- source/lib/include/neighbor_list.h | 10 ++++ source/lib/include/prod_env_mat.h | 18 ++---- source/lib/src/cuda/prod_env_mat.cu | 62 +++++++++----------- source/lib/src/neighbor_list.cc | 33 +++++++++++ source/lib/src/prod_env_mat.cc | 79 +++++++++++++------------- source/lib/tests/test_env_mat_a.cc | 79 ++++++++++---------------- source/lib/tests/test_env_mat_r.cc | 60 +++++++------------ source/op/prod_env_mat_multi_device.cc | 57 ++++++++++++------- 9 files changed, 210 insertions(+), 203 deletions(-) diff --git a/source/lib/include/gpu_cuda.h b/source/lib/include/gpu_cuda.h index 2f5c3c5957..845e0b9d9f 100644 --- a/source/lib/include/gpu_cuda.h +++ b/source/lib/include/gpu_cuda.h @@ -21,6 +21,15 @@ void memcpy_host_to_device( cudaErrcheck(cudaMemcpy(device, &host[0], sizeof(FPTYPE) * host.size(), cudaMemcpyHostToDevice)); } +template +void memcpy_host_to_device( + FPTYPE * device, + FPTYPE * host, + const int size) +{ + cudaErrcheck(cudaMemcpy(device, host, sizeof(FPTYPE) * size, cudaMemcpyHostToDevice)); +} + template void memcpy_device_to_host( FPTYPE * device, @@ -56,7 +65,9 @@ void malloc_device_memory_sync( template void delete_device_memory( - FPTYPE * device) + FPTYPE * &device) { - cudaErrcheck(cudaFree(device)); + if (device != NULL) { + cudaErrcheck(cudaFree(device)); + } } \ No newline at end of file diff --git a/source/lib/include/neighbor_list.h b/source/lib/include/neighbor_list.h index 174fad1a9f..ef4013c7d7 100644 --- a/source/lib/include/neighbor_list.h +++ b/source/lib/include/neighbor_list.h @@ -121,3 +121,13 @@ copy_coord (std::vector & out_c, const std::vector & in_t, const double & rc, const SimulationRegion & region); + +#if GOOGLE_CUDA +void convert_nlist_gpu_cuda( + InputNlist & gpu_nlist, + InputNlist & cpu_nlist, + int* & gpu_memory, + const int & max_nbor_size); + +void free_nlist_gpu_cuda(InputNlist & gpu_nlist); +#endif // GOOGLE_CUDA diff --git a/source/lib/include/prod_env_mat.h b/source/lib/include/prod_env_mat.h index ff12ba1710..6b866c5590 100644 --- a/source/lib/include/prod_env_mat.h +++ b/source/lib/include/prod_env_mat.h @@ -48,9 +48,7 @@ void prod_env_mat_a_gpu_cuda( int * nlist, const FPTYPE * coord, const int * type, - const int * ilist, - const int * jrange, - const int * jlist, + const InputNlist & gpu_inlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, @@ -70,9 +68,7 @@ void prod_env_mat_r_gpu_cuda( int * nlist, const FPTYPE * coord, const int * type, - const int * ilist, - const int * jrange, - const int * jlist, + const InputNlist & gpu_inlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, @@ -85,14 +81,10 @@ void prod_env_mat_r_gpu_cuda( const std::vector sec); void env_mat_nbor_update( - bool &init, - int * &ilist, - int * &jrange, - int * &jlist, - int &ilist_size, - int &jrange_size, - int &jlist_size, + InputNlist &inlist, + InputNlist &gpu_inlist, int &max_nbor_size, + int* &nbor_list_dev, const int * mesh, const int size); #endif // GOOGLE_CUDA diff --git a/source/lib/src/cuda/prod_env_mat.cu b/source/lib/src/cuda/prod_env_mat.cu index 0205a92d0a..d26e089efa 100644 --- a/source/lib/src/cuda/prod_env_mat.cu +++ b/source/lib/src/cuda/prod_env_mat.cu @@ -89,8 +89,8 @@ __global__ void format_nlist_fill_a( int_64 * key, const FPTYPE * coord, const int * type, - const int * jrange, - const int * jlist, + const int * numneigh, + int ** firstneigh, const float rcut, int * i_idx, const int MAX_NBOR_SIZE) @@ -99,11 +99,12 @@ __global__ void format_nlist_fill_a( const unsigned int idx = blockIdx.x; const unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y; - const int nsize = jrange[i_idx[idx] + 1] - jrange[i_idx[idx]]; + const int nsize = numneigh[i_idx[idx]]; if (idy >= nsize) { return; } - const int * nei_idx = jlist + jrange[i_idx[idx]]; + + const int * nei_idx = firstneigh[i_idx[idx]]; // dev_copy(nei_idx, &jlist[jrange[i_idx]], nsize); int_64 * key_in = key + idx * MAX_NBOR_SIZE; FPTYPE diff[3]; @@ -122,8 +123,6 @@ __global__ void format_nlist_fill_b( int * nlist, const int nlist_size, const int nloc, - const int * jrange, - const int * jlist, FPTYPE * key, const int * sec, const int sec_size, @@ -155,8 +154,7 @@ void format_nbor_list_1024 ( int_64 * key, const FPTYPE* coord, const int* type, - const int* jrange, - const int* jlist, + const InputNlist & gpu_inlist, const int& nloc, const float& rcut, int * i_idx) @@ -168,7 +166,7 @@ void format_nbor_list_1024 ( dim3 thread_grid(1, LEN); format_nlist_fill_a<<>> ( key, - coord, type, jrange, jlist, rcut, i_idx, MAX_NBOR_SIZE); + coord, type, gpu_inlist.numneigh, gpu_inlist.firstneigh, rcut, i_idx, MAX_NBOR_SIZE); const int ITEMS_PER_THREAD = 8; const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; // BlockSortKernel<<>> ( @@ -182,8 +180,7 @@ void format_nbor_list_2048 ( int_64 * key, const FPTYPE* coord, const int* type, - const int* jrange, - const int* jlist, + const InputNlist & gpu_inlist, const int& nloc, const float& rcut, int * i_idx) @@ -195,7 +192,7 @@ void format_nbor_list_2048 ( dim3 thread_grid(1, LEN); format_nlist_fill_a<<>> ( key, - coord, type, jrange, jlist, rcut, i_idx, MAX_NBOR_SIZE); + coord, type, gpu_inlist.numneigh, gpu_inlist.firstneigh, rcut, i_idx, MAX_NBOR_SIZE); const int ITEMS_PER_THREAD = 8; const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; // BlockSortKernel<<>> ( @@ -209,8 +206,7 @@ void format_nbor_list_4096 ( int_64 * key, const FPTYPE* coord, const int* type, - const int* jrange, - const int* jlist, + const InputNlist & gpu_inlist, const int& nloc, const float& rcut, int * i_idx) @@ -222,7 +218,7 @@ void format_nbor_list_4096 ( dim3 thread_grid(1, LEN); format_nlist_fill_a<<>> ( key, - coord, type, jrange, jlist, rcut, i_idx, MAX_NBOR_SIZE); + coord, type, gpu_inlist.numneigh, gpu_inlist.firstneigh, rcut, i_idx, MAX_NBOR_SIZE); const int ITEMS_PER_THREAD = 16; const int BLOCK_THREADS = MAX_NBOR_SIZE / ITEMS_PER_THREAD; // BlockSortKernel<<>> ( @@ -236,10 +232,8 @@ void format_nbor_list( int * nlist, const FPTYPE * coord, const int * type, - const int * ilist, - const int * jrange, - const int * jlist, - int * array_int, + const InputNlist & gpu_inlist, + int * array_int, int_64 * array_longlong, const int max_nbor_size, const int nloc, @@ -261,27 +255,27 @@ void format_nbor_list( get_i_idx<<>>( i_idx, - nloc, ilist); + nloc, gpu_inlist.ilist); if (max_nbor_size == 1024) { format_nbor_list_1024 ( key, - coord, type, jrange, jlist, nloc, rcut, i_idx); + coord, type, gpu_inlist, nloc, rcut, i_idx); } else if (max_nbor_size == 2048) { format_nbor_list_2048 ( key, - coord, type, jrange, jlist, nloc, rcut, i_idx); + coord, type, gpu_inlist, nloc, rcut, i_idx); } else if (max_nbor_size == 4096) { format_nbor_list_4096 ( key, - coord, type, jrange, jlist, nloc, rcut, i_idx); + coord, type, gpu_inlist, nloc, rcut, i_idx); } format_nlist_fill_b<<>> ( nlist, - nnei, nloc, jrange, jlist, key, sec_dev, sec.size(), nei_iter, max_nbor_size); + nnei, nloc, key, sec_dev, sec.size(), nei_iter, max_nbor_size); } template< @@ -445,9 +439,7 @@ void prod_env_mat_a_gpu_cuda( int * nlist, const FPTYPE * coord, const int * type, - const int * ilist, - const int * jrange, - const int * jlist, + const InputNlist & gpu_inlist, int * array_int, int_64 * array_longlong, const int max_nbor_size, @@ -466,7 +458,7 @@ void prod_env_mat_a_gpu_cuda( format_nbor_list( nlist, - coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, nloc, nall, rcut, sec); + coord, type, gpu_inlist, array_int, array_longlong, max_nbor_size, nloc, nall, rcut, sec); compute_env_mat_a <<>> ( em, em_deriv, rij, @@ -481,9 +473,7 @@ void prod_env_mat_r_gpu_cuda( int * nlist, const FPTYPE * coord, const int * type, - const int * ilist, - const int * jrange, - const int * jlist, + const InputNlist & gpu_inlist, int * array_int, int_64 * array_longlong, const int max_nbor_size, @@ -502,14 +492,14 @@ void prod_env_mat_r_gpu_cuda( format_nbor_list( nlist, - coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, nloc, nall, rcut, sec); + coord, type, gpu_inlist, array_int, array_longlong, max_nbor_size, nloc, nall, rcut, sec); compute_env_mat_r <<>> ( em, em_deriv, rij, coord, avg, std, type, nlist, nnei, rcut_smth, rcut); } -template void prod_env_mat_a_gpu_cuda(float * em, float * em_deriv, float * rij, int * nlist, const float * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const float * avg, const float * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); -template void prod_env_mat_a_gpu_cuda(double * em, double * em_deriv, double * rij, int * nlist, const double * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const double * avg, const double * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); -template void prod_env_mat_r_gpu_cuda(float * em, float * em_deriv, float * rij, int * nlist, const float * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const float * avg, const float * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); -template void prod_env_mat_r_gpu_cuda(double * em, double * em_deriv, double * rij, int * nlist, const double * coord, const int * type, const int * ilist, const int * jrange, const int * jlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const double * avg, const double * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); +template void prod_env_mat_a_gpu_cuda(float * em, float * em_deriv, float * rij, int * nlist, const float * coord, const int * type, const InputNlist & gpu_inlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const float * avg, const float * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); +template void prod_env_mat_a_gpu_cuda(double * em, double * em_deriv, double * rij, int * nlist, const double * coord, const int * type, const InputNlist & gpu_inlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const double * avg, const double * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); +template void prod_env_mat_r_gpu_cuda(float * em, float * em_deriv, float * rij, int * nlist, const float * coord, const int * type, const InputNlist & gpu_inlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const float * avg, const float * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); +template void prod_env_mat_r_gpu_cuda(double * em, double * em_deriv, double * rij, int * nlist, const double * coord, const int * type, const InputNlist & gpu_inlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const double * avg, const double * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); diff --git a/source/lib/src/neighbor_list.cc b/source/lib/src/neighbor_list.cc index 6a603dc94e..4223b50fe6 100644 --- a/source/lib/src/neighbor_list.cc +++ b/source/lib/src/neighbor_list.cc @@ -1,4 +1,5 @@ #include "neighbor_list.h" +#include "device.h" #include // #include @@ -836,3 +837,35 @@ build_nlist_cpu( const int & mem_size, const float & rcut); +#if GOOGLE_CUDA +void convert_nlist_gpu_cuda( + InputNlist & gpu_nlist, + InputNlist & cpu_nlist, + int* & gpu_memory, + const int & max_nbor_size) +{ + const int inum = cpu_nlist.inum; + gpu_nlist.inum = inum; + malloc_device_memory(gpu_nlist.ilist, inum); + malloc_device_memory(gpu_nlist.numneigh, inum); + malloc_device_memory(gpu_nlist.firstneigh, inum); + memcpy_host_to_device(gpu_nlist.ilist, cpu_nlist.ilist, inum); + memcpy_host_to_device(gpu_nlist.numneigh, cpu_nlist.numneigh, inum); + int ** _firstneigh = NULL; + _firstneigh = (int**)malloc(sizeof(int*) * inum); + for (int ii = 0; ii < inum; ii++) { + memcpy_host_to_device(gpu_memory + ii * max_nbor_size, cpu_nlist.firstneigh[ii], cpu_nlist.numneigh[ii]); + _firstneigh[ii] = gpu_memory + ii * max_nbor_size; + } + memcpy_host_to_device(gpu_nlist.firstneigh, _firstneigh, inum); + free(_firstneigh); +} + +void free_nlist_gpu_cuda( + InputNlist & gpu_nlist) +{ + delete_device_memory(gpu_nlist.ilist); + delete_device_memory(gpu_nlist.numneigh); + delete_device_memory(gpu_nlist.firstneigh); +} +#endif // GOOGLE_CUDA \ No newline at end of file diff --git a/source/lib/src/prod_env_mat.cc b/source/lib/src/prod_env_mat.cc index df8dcb6273..23d367e10e 100644 --- a/source/lib/src/prod_env_mat.cc +++ b/source/lib/src/prod_env_mat.cc @@ -244,59 +244,56 @@ void prod_env_mat_r_cpu( #if GOOGLE_CUDA void env_mat_nbor_update( - bool &init, - int * &ilist, - int * &jrange, - int * &jlist, - int &ilist_size, - int &jrange_size, - int &jlist_size, + InputNlist &inlist, + InputNlist &gpu_inlist, int &max_nbor_size, + int* &nbor_list_dev, const int * mesh, const int size) { - int *mesh_host = new int[size], *ilist_host = NULL, *jrange_host = NULL, *jlist_host = NULL; + int *mesh_host = new int[size]; cudaErrcheck(cudaMemcpy(mesh_host, mesh, sizeof(int) * size, cudaMemcpyDeviceToHost)); - memcpy (&ilist_host, 4 + mesh_host, sizeof(int *)); - memcpy (&jrange_host, 8 + mesh_host, sizeof(int *)); - memcpy (&jlist_host, 12 + mesh_host, sizeof(int *)); - int const ago = mesh_host[0]; - if (!init || ago == 0) { - if (ilist_size < mesh_host[1]) { - ilist_size = (int)(mesh_host[1] * 1.2); - if (ilist != NULL) {cudaErrcheck(cudaFree(ilist));} - cudaErrcheck(cudaMalloc((void **)&ilist, sizeof(int) * ilist_size)); + memcpy(&inlist.ilist, 4 + mesh_host, sizeof(int *)); + memcpy(&inlist.numneigh, 8 + mesh_host, sizeof(int *)); + memcpy(&inlist.firstneigh, 12 + mesh_host, sizeof(int **)); + const int ago = mesh_host[0]; + if (ago == 0) { + const int inum = inlist.inum; + if (gpu_inlist.inum < inum) { + delete_device_memory(gpu_inlist.ilist); + delete_device_memory(gpu_inlist.numneigh); + delete_device_memory(gpu_inlist.firstneigh); + malloc_device_memory(gpu_inlist.ilist, inum); + malloc_device_memory(gpu_inlist.numneigh, inum); + malloc_device_memory(gpu_inlist.firstneigh, inum); } - if (jrange_size < mesh_host[2]) { - jrange_size = (int)(mesh_host[2] * 1.2); - if (jrange != NULL) {cudaErrcheck(cudaFree(jrange));} - cudaErrcheck(cudaMalloc((void **)&jrange,sizeof(int) * jrange_size)); + gpu_inlist.inum = inum; + memcpy_host_to_device(gpu_inlist.ilist, inlist.ilist, inum); + memcpy_host_to_device(gpu_inlist.numneigh, inlist.numneigh, inum); + int _max_nbor_size = max_numneigh(inlist); + if (_max_nbor_size <= 1024) { + _max_nbor_size = 1024; } - if (jlist_size < mesh_host[3]) { - jlist_size = (int)(mesh_host[3] * 1.2); - if (jlist != NULL) {cudaErrcheck(cudaFree(jlist));} - cudaErrcheck(cudaMalloc((void **)&jlist, sizeof(int) * jlist_size)); + else if (_max_nbor_size <= 2048) { + _max_nbor_size = 2048; } - cudaErrcheck(cudaMemcpy(ilist, ilist_host, sizeof(int) * mesh_host[1], cudaMemcpyHostToDevice)); - cudaErrcheck(cudaMemcpy(jrange, jrange_host, sizeof(int) * mesh_host[2], cudaMemcpyHostToDevice)); - cudaErrcheck(cudaMemcpy(jlist, jlist_host, sizeof(int) * mesh_host[3], cudaMemcpyHostToDevice)); - - max_nbor_size = 0; - for(int ii = 0; ii < mesh_host[2]; ii++) { - max_nbor_size = (jrange_host[ii + 1] - jrange_host[ii]) > max_nbor_size ? (jrange_host[ii + 1] - jrange_host[ii]) : max_nbor_size; - } - assert(max_nbor_size <= GPU_MAX_NBOR_SIZE); - if (max_nbor_size <= 1024) { - max_nbor_size = 1024; + else { + _max_nbor_size = 4096; } - else if (max_nbor_size <= 2048) { - max_nbor_size = 2048; + if (_max_nbor_size > max_nbor_size || nbor_list_dev == NULL) { + delete_device_memory(nbor_list_dev); + malloc_device_memory(nbor_list_dev, inum * max_nbor_size); } - else { - max_nbor_size = 4096; + max_nbor_size = _max_nbor_size; + int ** _firstneigh = NULL; + _firstneigh = (int**)malloc(sizeof(int*) * inum); + for (int ii = 0; ii < inum; ii++) { + memcpy_host_to_device(nbor_list_dev + ii * max_nbor_size, inlist.firstneigh[ii], inlist.numneigh[ii]); + _firstneigh[ii] = nbor_list_dev + ii * max_nbor_size; } + memcpy_host_to_device(gpu_inlist.firstneigh, _firstneigh, inum); + free(_firstneigh); } - init = true; delete [] mesh_host; } #endif // GOOGLE_CUDA diff --git a/source/lib/tests/test_env_mat_a.cc b/source/lib/tests/test_env_mat_a.cc index 1e630ecd7d..25fab3e59d 100644 --- a/source/lib/tests/test_env_mat_a.cc +++ b/source/lib/tests/test_env_mat_a.cc @@ -533,15 +533,10 @@ TEST_F(TestEnvMatA, prod_gpu_cuda) else { max_nbor_size = 4096; } - std::vector ilist(nloc), jlist(tot_nnei), jrange(nloc+1, 0); - for (int ii = 0; ii < nloc; ++ii){ - ilist[ii] = ii; - jrange[ii+1] = jrange[ii] + nlist_a_cpy[ii].size(); - int jj, cc; - for (jj = jrange[ii], cc = 0; jj < jrange[ii+1]; ++jj, ++cc){ - jlist[jj] = nlist_a_cpy[ii][cc]; - } - } + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]), gpu_inlist; + convert_nlist(inlist, nlist_a_cpy); std::vector em(nloc * ndescrpt, 0.0), em_deriv(nloc * ndescrpt * 3, 0.0), rij(nloc * nnei * 3, 0.0); std::vector nlist(nloc * nnei, 0); std::vector avg(ntypes * ndescrpt, 0); @@ -549,7 +544,7 @@ TEST_F(TestEnvMatA, prod_gpu_cuda) double * em_dev = NULL, * em_deriv_dev = NULL, * rij_dev = NULL; double * posi_cpy_dev = NULL, * avg_dev = NULL, * std_dev = NULL; - int * atype_cpy_dev = NULL, * nlist_dev = NULL, * ilist_dev = NULL, * jrange_dev = NULL, * jlist_dev = NULL, * array_int_dev = NULL; + int * atype_cpy_dev = NULL, * nlist_dev = NULL, * array_int_dev = NULL, * memory_dev = NULL; int_64 * array_longlong_dev = NULL; malloc_device_memory_sync(em_dev, em); malloc_device_memory_sync(em_deriv_dev, em_deriv); @@ -557,15 +552,12 @@ TEST_F(TestEnvMatA, prod_gpu_cuda) malloc_device_memory_sync(posi_cpy_dev, posi_cpy); malloc_device_memory_sync(avg_dev, avg); malloc_device_memory_sync(std_dev, std); - malloc_device_memory_sync(atype_cpy_dev, atype_cpy); malloc_device_memory_sync(nlist_dev, nlist); - malloc_device_memory_sync(ilist_dev, ilist); - malloc_device_memory_sync(jrange_dev, jrange); - malloc_device_memory_sync(jlist_dev, jlist); - malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); + malloc_device_memory(memory_dev, nloc * max_nbor_size); + convert_nlist_gpu_cuda(gpu_inlist, inlist, memory_dev, max_nbor_size); prod_env_mat_a_gpu_cuda( em_dev, @@ -574,9 +566,7 @@ TEST_F(TestEnvMatA, prod_gpu_cuda) nlist_dev, posi_cpy_dev, atype_cpy_dev, - ilist_dev, - jrange_dev, - jlist_dev, + gpu_inlist, array_int_dev, array_longlong_dev, max_nbor_size, @@ -593,13 +583,12 @@ TEST_F(TestEnvMatA, prod_gpu_cuda) delete_device_memory(nlist_dev); delete_device_memory(posi_cpy_dev); delete_device_memory(atype_cpy_dev); - delete_device_memory(ilist_dev); - delete_device_memory(jrange_dev); - delete_device_memory(jlist_dev); delete_device_memory(array_int_dev); delete_device_memory(array_longlong_dev); delete_device_memory(avg_dev); delete_device_memory(std_dev); + delete_device_memory(memory_dev); + free_nlist_gpu_cuda(gpu_inlist); for(int ii = 0; ii < nloc; ++ii){ for (int jj = 0; jj < nnei; ++jj){ @@ -634,15 +623,10 @@ TEST_F(TestEnvMatA, prod_gpu_cuda_equal_cpu) else { max_nbor_size = 4096; } - std::vector ilist(nloc), jlist(tot_nnei), jrange(nloc+1, 0); - for (int ii = 0; ii < nloc; ++ii){ - ilist[ii] = ii; - jrange[ii+1] = jrange[ii] + nlist_a_cpy[ii].size(); - int jj, cc; - for (jj = jrange[ii], cc = 0; jj < jrange[ii+1]; ++jj, ++cc){ - jlist[jj] = nlist_a_cpy[ii][cc]; - } - } + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]), gpu_inlist; + convert_nlist(inlist, nlist_a_cpy); std::vector em(nloc * ndescrpt, 0.0), em_deriv(nloc * ndescrpt * 3, 0.0), rij(nloc * nnei * 3, 0.0); std::vector nlist(nloc * nnei, 0); std::vector avg(ntypes * ndescrpt, 0); @@ -650,7 +634,7 @@ TEST_F(TestEnvMatA, prod_gpu_cuda_equal_cpu) double * em_dev = NULL, * em_deriv_dev = NULL, * rij_dev = NULL; double * posi_cpy_dev = NULL, * avg_dev = NULL, * std_dev = NULL; - int * atype_cpy_dev = NULL, * nlist_dev = NULL, * ilist_dev = NULL, * jrange_dev = NULL, * jlist_dev = NULL, * array_int_dev = NULL; + int * atype_cpy_dev = NULL, * nlist_dev = NULL, * array_int_dev = NULL, * memory_dev = NULL; int_64 * array_longlong_dev = NULL; malloc_device_memory_sync(em_dev, em); malloc_device_memory_sync(em_deriv_dev, em_deriv); @@ -661,12 +645,10 @@ TEST_F(TestEnvMatA, prod_gpu_cuda_equal_cpu) malloc_device_memory_sync(atype_cpy_dev, atype_cpy); malloc_device_memory_sync(nlist_dev, nlist); - malloc_device_memory_sync(ilist_dev, ilist); - malloc_device_memory_sync(jrange_dev, jrange); - malloc_device_memory_sync(jlist_dev, jlist); - malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); + malloc_device_memory(memory_dev, nloc * max_nbor_size); + convert_nlist_gpu_cuda(gpu_inlist, inlist, memory_dev, max_nbor_size); prod_env_mat_a_gpu_cuda( em_dev, @@ -675,9 +657,7 @@ TEST_F(TestEnvMatA, prod_gpu_cuda_equal_cpu) nlist_dev, posi_cpy_dev, atype_cpy_dev, - ilist_dev, - jrange_dev, - jlist_dev, + gpu_inlist, array_int_dev, array_longlong_dev, max_nbor_size, @@ -697,13 +677,12 @@ TEST_F(TestEnvMatA, prod_gpu_cuda_equal_cpu) delete_device_memory(nlist_dev); delete_device_memory(posi_cpy_dev); delete_device_memory(atype_cpy_dev); - delete_device_memory(ilist_dev); - delete_device_memory(jrange_dev); - delete_device_memory(jlist_dev); delete_device_memory(array_int_dev); delete_device_memory(array_longlong_dev); delete_device_memory(avg_dev); delete_device_memory(std_dev); + delete_device_memory(memory_dev); + free_nlist_gpu_cuda(gpu_inlist); std::vector fmt_nlist_a_1, fmt_nlist_r_1; std::vector env_1, env_deriv_1, rij_a_1; @@ -733,14 +712,14 @@ TEST_F(TestEnvMatA, prod_gpu_cuda_equal_cpu) } } - // for(int ii = 0; ii < nloc; ++ii){ - // for (int jj = 0; jj < nnei; ++jj){ - // for (int dd = 0; dd < 4; ++dd){ - // EXPECT_LT(fabs(em[ii*nnei*4 + jj*4 + dd] - - // expected_env[ii*nnei*4 + jj*4 + dd]) , - // 1e-5); - // } - // } - // } + for(int ii = 0; ii < nloc; ++ii){ + for (int jj = 0; jj < nnei; ++jj){ + for (int dd = 0; dd < 4; ++dd){ + EXPECT_LT(fabs(em[ii*nnei*4 + jj*4 + dd] - + expected_env[ii*nnei*4 + jj*4 + dd]) , + 1e-5); + } + } + } } #endif //GOOGLE_CUDA diff --git a/source/lib/tests/test_env_mat_r.cc b/source/lib/tests/test_env_mat_r.cc index 153c10d582..4dfd369c1a 100644 --- a/source/lib/tests/test_env_mat_r.cc +++ b/source/lib/tests/test_env_mat_r.cc @@ -375,15 +375,10 @@ TEST_F(TestEnvMatR, prod_gpu_cuda) else { max_nbor_size = 4096; } - std::vector ilist(nloc), jlist(tot_nnei), jrange(nloc+1, 0); - for (int ii = 0; ii < nloc; ++ii){ - ilist[ii] = ii; - jrange[ii+1] = jrange[ii] + nlist_a_cpy[ii].size(); - int jj, cc; - for (jj = jrange[ii], cc = 0; jj < jrange[ii+1]; ++jj, ++cc){ - jlist[jj] = nlist_a_cpy[ii][cc]; - } - } + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]), gpu_inlist; + convert_nlist(inlist, nlist_a_cpy); std::vector em(nloc * ndescrpt, 0.0), em_deriv(nloc * ndescrpt * 3, 0.0), rij(nloc * nnei * 3, 0.0); std::vector nlist(nloc * nnei, 0); std::vector avg(ntypes * ndescrpt, 0); @@ -391,7 +386,7 @@ TEST_F(TestEnvMatR, prod_gpu_cuda) double * em_dev = NULL, * em_deriv_dev = NULL, * rij_dev = NULL; double * posi_cpy_dev = NULL, * avg_dev = NULL, * std_dev = NULL; - int * atype_cpy_dev = NULL, * nlist_dev = NULL, * ilist_dev = NULL, * jrange_dev = NULL, * jlist_dev = NULL, * array_int_dev = NULL; + int * atype_cpy_dev = NULL, * nlist_dev = NULL, * array_int_dev = NULL, * memory_dev = NULL; int_64 * array_longlong_dev = NULL; malloc_device_memory_sync(em_dev, em); malloc_device_memory_sync(em_deriv_dev, em_deriv); @@ -402,12 +397,10 @@ TEST_F(TestEnvMatR, prod_gpu_cuda) malloc_device_memory_sync(atype_cpy_dev, atype_cpy); malloc_device_memory_sync(nlist_dev, nlist); - malloc_device_memory_sync(ilist_dev, ilist); - malloc_device_memory_sync(jrange_dev, jrange); - malloc_device_memory_sync(jlist_dev, jlist); - malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); + malloc_device_memory(memory_dev, nloc * max_nbor_size); + convert_nlist_gpu_cuda(gpu_inlist, inlist, memory_dev, max_nbor_size); prod_env_mat_r_gpu_cuda( em_dev, @@ -416,9 +409,7 @@ TEST_F(TestEnvMatR, prod_gpu_cuda) nlist_dev, posi_cpy_dev, atype_cpy_dev, - ilist_dev, - jrange_dev, - jlist_dev, + gpu_inlist, array_int_dev, array_longlong_dev, max_nbor_size, @@ -435,13 +426,12 @@ TEST_F(TestEnvMatR, prod_gpu_cuda) delete_device_memory(nlist_dev); delete_device_memory(posi_cpy_dev); delete_device_memory(atype_cpy_dev); - delete_device_memory(ilist_dev); - delete_device_memory(jrange_dev); - delete_device_memory(jlist_dev); delete_device_memory(array_int_dev); delete_device_memory(array_longlong_dev); delete_device_memory(avg_dev); delete_device_memory(std_dev); + delete_device_memory(memory_dev); + free_nlist_gpu_cuda(gpu_inlist); for(int ii = 0; ii < nloc; ++ii){ for (int jj = 0; jj < nnei; ++jj){ @@ -475,15 +465,10 @@ TEST_F(TestEnvMatR, prod_gpu_cuda_equal_cpu) else { max_nbor_size = 4096; } - std::vector ilist(nloc), jlist(tot_nnei), jrange(nloc+1, 0); - for (int ii = 0; ii < nloc; ++ii){ - ilist[ii] = ii; - jrange[ii+1] = jrange[ii] + nlist_a_cpy[ii].size(); - int jj, cc; - for (jj = jrange[ii], cc = 0; jj < jrange[ii+1]; ++jj, ++cc){ - jlist[jj] = nlist_a_cpy[ii][cc]; - } - } + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]), gpu_inlist; + convert_nlist(inlist, nlist_a_cpy); std::vector em(nloc * ndescrpt, 0.0), em_deriv(nloc * ndescrpt * 3, 0.0), rij(nloc * nnei * 3, 0.0); std::vector nlist(nloc * nnei, 0); std::vector avg(ntypes * ndescrpt, 0); @@ -491,7 +476,7 @@ TEST_F(TestEnvMatR, prod_gpu_cuda_equal_cpu) double * em_dev = NULL, * em_deriv_dev = NULL, * rij_dev = NULL; double * posi_cpy_dev = NULL, * avg_dev = NULL, * std_dev = NULL; - int * atype_cpy_dev = NULL, * nlist_dev = NULL, * ilist_dev = NULL, * jrange_dev = NULL, * jlist_dev = NULL, * array_int_dev = NULL; + int * atype_cpy_dev = NULL, * nlist_dev = NULL, * array_int_dev = NULL, * memory_dev = NULL; int_64 * array_longlong_dev = NULL; malloc_device_memory_sync(em_dev, em); malloc_device_memory_sync(em_deriv_dev, em_deriv); @@ -502,12 +487,10 @@ TEST_F(TestEnvMatR, prod_gpu_cuda_equal_cpu) malloc_device_memory_sync(atype_cpy_dev, atype_cpy); malloc_device_memory_sync(nlist_dev, nlist); - malloc_device_memory_sync(ilist_dev, ilist); - malloc_device_memory_sync(jrange_dev, jrange); - malloc_device_memory_sync(jlist_dev, jlist); - malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); + malloc_device_memory(memory_dev, nloc * max_nbor_size); + convert_nlist_gpu_cuda(gpu_inlist, inlist, memory_dev, max_nbor_size); prod_env_mat_r_gpu_cuda( em_dev, @@ -516,9 +499,7 @@ TEST_F(TestEnvMatR, prod_gpu_cuda_equal_cpu) nlist_dev, posi_cpy_dev, atype_cpy_dev, - ilist_dev, - jrange_dev, - jlist_dev, + gpu_inlist, array_int_dev, array_longlong_dev, max_nbor_size, @@ -538,13 +519,12 @@ TEST_F(TestEnvMatR, prod_gpu_cuda_equal_cpu) delete_device_memory(nlist_dev); delete_device_memory(posi_cpy_dev); delete_device_memory(atype_cpy_dev); - delete_device_memory(ilist_dev); - delete_device_memory(jrange_dev); - delete_device_memory(jlist_dev); delete_device_memory(array_int_dev); delete_device_memory(array_longlong_dev); delete_device_memory(avg_dev); delete_device_memory(std_dev); + delete_device_memory(memory_dev); + free_nlist_gpu_cuda(gpu_inlist); std::vector fmt_nlist_a_1, fmt_nlist_r_1; std::vector env_1, env_deriv_1, rij_a_1; diff --git a/source/op/prod_env_mat_multi_device.cc b/source/op/prod_env_mat_multi_device.cc index 42310ed30b..b50b7d80b8 100644 --- a/source/op/prod_env_mat_multi_device.cc +++ b/source/op/prod_env_mat_multi_device.cc @@ -243,14 +243,18 @@ class ProdEnvMatAOp : public OpKernel { OP_REQUIRES_OK(context, context->allocate_temp(DT_UINT64, uint64_shape, &uint64_temp)); array_int = int_temp.flat().data(); array_longlong = uint64_temp.flat().data(); + + // update nbor list + InputNlist inlist; + inlist.inum = nloc; env_mat_nbor_update( - init, ilist, jrange, jlist, ilist_size, jrange_size, jlist_size, max_nbor_size, + inlist, gpu_inlist, max_nbor_size, nbor_list_dev, mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); - OP_REQUIRES (context, (max_nbor_size <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than " + std::to_string(GPU_MAX_NBOR_SIZE) + ", which currently is not supported by deepmd-kit.")); + OP_REQUIRES (context, (max_numneigh(inlist) <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_numneigh(inlist)) + " is larger than " + std::to_string(GPU_MAX_NBOR_SIZE) + ", which currently is not supported by deepmd-kit.")); // launch the gpu(nv) compute function prod_env_mat_a_gpu_cuda( em, em_deriv, rij, nlist, - coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, rcut_r, rcut_r_smth, sec_a); + coord, type, gpu_inlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, rcut_r, rcut_r_smth, sec_a); #endif //GOOGLE_CUDA } else if (device == "CPU") { @@ -316,9 +320,8 @@ class ProdEnvMatAOp : public OpKernel { std::string device; int * array_int = NULL; unsigned long long * array_longlong = NULL; - bool init = false; - int * ilist = NULL, * jrange = NULL, * jlist = NULL; - int ilist_size = 0, jrange_size = 0, jlist_size = 0; + InputNlist gpu_inlist; + int * nbor_list_dev = NULL; }; template @@ -434,24 +437,37 @@ class ProdEnvMatROp : public OpKernel { OP_REQUIRES_OK(context, context->allocate_temp(DT_UINT64, uint64_shape, &uint64_temp)); array_int = int_temp.flat().data(); array_longlong = uint64_temp.flat().data(); + + // update nbor list + InputNlist inlist; + inlist.inum = nloc; env_mat_nbor_update( - init, ilist, jrange, jlist, ilist_size, jrange_size, jlist_size, max_nbor_size, + inlist, gpu_inlist, max_nbor_size, nbor_list_dev, mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); - OP_REQUIRES (context, (max_nbor_size <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_nbor_size) + " is larger than " + std::to_string(GPU_MAX_NBOR_SIZE) + ", which currently is not supported by deepmd-kit.")); + OP_REQUIRES (context, (max_numneigh(inlist) <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_numneigh(inlist)) + " is larger than " + std::to_string(GPU_MAX_NBOR_SIZE) + ", which currently is not supported by deepmd-kit.")); // launch the gpu(nv) compute function prod_env_mat_r_gpu_cuda( em, em_deriv, rij, nlist, - coord, type, ilist, jrange, jlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); + coord, type, gpu_inlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); #endif //GOOGLE_CUDA } else if (device == "CPU") { - memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy (&jrange, 8 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy (&jlist, 12 + mesh_tensor.flat().data(), sizeof(int *)); + // memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); + // memcpy (&jrange, 8 + mesh_tensor.flat().data(), sizeof(int *)); + // memcpy (&jlist, 12 + mesh_tensor.flat().data(), sizeof(int *)); // launch the cpu compute function // prod_env_mat_r_cpu( // em, em_deriv, rij, nlist, // coord, type, ilist, jrange, jlist, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); + InputNlist inlist; + inlist.inum = nloc; + memcpy(&inlist.ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); + memcpy(&inlist.numneigh, 8 + mesh_tensor.flat().data(), sizeof(int *)); + memcpy(&inlist.firstneigh, 12 + mesh_tensor.flat().data(), sizeof(int **)); + max_nbor_size = max_numneigh(inlist); + prod_env_mat_r_cpu( + em, em_deriv, rij, nlist, + coord, type, inlist, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); } } @@ -468,9 +484,8 @@ class ProdEnvMatROp : public OpKernel { std::string device; int * array_int = NULL; unsigned long long * array_longlong = NULL; - bool init = false; - int * ilist = NULL, * jrange = NULL, * jlist = NULL; - int ilist_size = 0, jrange_size = 0, jlist_size = 0; + InputNlist gpu_inlist; + int * nbor_list_dev = NULL; }; template @@ -568,10 +583,10 @@ _map_nlist_cpu( // Register the CPU kernels. #define REGISTER_CPU(T) \ REGISTER_KERNEL_BUILDER( \ - Name("ProdEnvMatA").Device(DEVICE_CPU).TypeConstraint("T"), \ - ProdEnvMatAOp); \ + Name("ProdEnvMatA").Device(DEVICE_CPU).TypeConstraint("T"), \ + ProdEnvMatAOp); \ REGISTER_KERNEL_BUILDER( \ - Name("ProdEnvMatR").Device(DEVICE_CPU).TypeConstraint("T"), \ + Name("ProdEnvMatR").Device(DEVICE_CPU).TypeConstraint("T"), \ ProdEnvMatROp); REGISTER_CPU(float); REGISTER_CPU(double); @@ -580,10 +595,10 @@ REGISTER_CPU(double); #if GOOGLE_CUDA #define REGISTER_GPU(T) \ REGISTER_KERNEL_BUILDER( \ - Name("ProdEnvMatA").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ - ProdEnvMatAOp); \ + Name("ProdEnvMatA").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ + ProdEnvMatAOp); \ REGISTER_KERNEL_BUILDER( \ - Name("ProdEnvMatR").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ + Name("ProdEnvMatR").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ ProdEnvMatROp); REGISTER_GPU(float); REGISTER_GPU(double); From bee9078e71750b075e7673f70ee362ef7baf7457 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Fri, 12 Mar 2021 02:13:26 +0800 Subject: [PATCH 264/562] fix conflicts --- deepmd/infer/deep_eval.py | 13 +- deepmd/infer/deep_pot.py | 47 +- source/api_cc/tests/.gitignore | 5 + .../{test_deeppot.cc => test_deeppot_a.cc} | 18 +- source/api_cc/tests/test_deeppot_r.cc | 437 + source/op/prod_env_mat_multi_device.cc | 209 +- source/tests/infer/deeppot-r.pbtxt | 22458 ++++++++++++++++ .../{test_deeppot.py => test_deeppot_a.py} | 6 +- source/tests/test_deeppot_r.py | 290 + 9 files changed, 23387 insertions(+), 96 deletions(-) create mode 100644 source/api_cc/tests/.gitignore rename source/api_cc/tests/{test_deeppot.cc => test_deeppot_a.cc} (97%) create mode 100644 source/api_cc/tests/test_deeppot_r.cc create mode 100644 source/tests/infer/deeppot-r.pbtxt rename source/tests/{test_deeppot.py => test_deeppot_a.py} (99%) create mode 100644 source/tests/test_deeppot_r.py diff --git a/deepmd/infer/deep_eval.py b/deepmd/infer/deep_eval.py index 4add62c151..2c52644eb1 100644 --- a/deepmd/infer/deep_eval.py +++ b/deepmd/infer/deep_eval.py @@ -245,14 +245,13 @@ def eval( tensor = [] feed_dict_test = {} feed_dict_test[self.t_natoms] = natoms_vec - feed_dict_test[self.t_type ] = atom_types + feed_dict_test[self.t_type ] = np.tile(atom_types, [nframes,1]).reshape([-1]) t_out = [self.t_tensor] - for ii in range(nframes) : - feed_dict_test[self.t_coord] = np.reshape(coords[ii:ii+1, :], [-1]) - feed_dict_test[self.t_box ] = np.reshape(cells [ii:ii+1, :], [-1]) - feed_dict_test[self.t_mesh ] = make_default_mesh(cells[ii:ii+1, :]) - v_out = self.sess.run (t_out, feed_dict = feed_dict_test) - tensor.append(v_out[0]) + feed_dict_test[self.t_coord] = np.reshape(coords, [-1]) + feed_dict_test[self.t_box ] = np.reshape(cells , [-1]) + feed_dict_test[self.t_mesh ] = make_default_mesh(cells) + v_out = self.sess.run (t_out, feed_dict = feed_dict_test) + tensor = v_out[0] # reverse map of the outputs if atomic: diff --git a/deepmd/infer/deep_pot.py b/deepmd/infer/deep_pot.py index 80157642ee..8fefe843d5 100644 --- a/deepmd/infer/deep_pot.py +++ b/deepmd/infer/deep_pot.py @@ -259,40 +259,35 @@ def _eval_inner( assert(natoms_vec[0] == natoms) # evaluate - energy = [] - force = [] - virial = [] - ae = [] - av = [] feed_dict_test = {} feed_dict_test[self.t_natoms] = natoms_vec - feed_dict_test[self.t_type ] = atom_types + feed_dict_test[self.t_type ] = np.tile(atom_types, [nframes, 1]).reshape([-1]) t_out = [self.t_energy, self.t_force, self.t_virial] if atomic : t_out += [self.t_ae, self.t_av] - for ii in range(nframes) : - feed_dict_test[self.t_coord] = np.reshape(coords[ii:ii+1, :], [-1]) - feed_dict_test[self.t_box ] = np.reshape(cells [ii:ii+1, :], [-1]) - if self.has_efield: - feed_dict_test[self.t_efield]= np.reshape(efield[ii:ii+1, :], [-1]) - if pbc: - feed_dict_test[self.t_mesh ] = make_default_mesh(cells[ii:ii+1, :]) - else: - feed_dict_test[self.t_mesh ] = np.array([], dtype = np.int32) - if self.has_fparam: - feed_dict_test[self.t_fparam] = np.reshape(fparam[ii:ii+1, :], [-1]) - if self.has_aparam: - feed_dict_test[self.t_aparam] = np.reshape(aparam[ii:ii+1, :], [-1]) - v_out = self.sess.run (t_out, feed_dict = feed_dict_test) - energy.append(v_out[0]) - force .append(v_out[1]) - virial.append(v_out[2]) - if atomic: - ae.append(v_out[3]) - av.append(v_out[4]) + + feed_dict_test[self.t_coord] = np.reshape(coords, [-1]) + feed_dict_test[self.t_box ] = np.reshape(cells , [-1]) + if self.has_efield: + feed_dict_test[self.t_efield]= np.reshape(efield, [-1]) + if pbc: + feed_dict_test[self.t_mesh ] = make_default_mesh(cells) + else: + feed_dict_test[self.t_mesh ] = np.array([], dtype = np.int32) + if self.has_fparam: + feed_dict_test[self.t_fparam] = np.reshape(fparam, [-1]) + if self.has_aparam: + feed_dict_test[self.t_aparam] = np.reshape(aparam, [-1]) + v_out = self.sess.run (t_out, feed_dict = feed_dict_test) + energy = v_out[0] + force = v_out[1] + virial = v_out[2] + if atomic: + ae = v_out[3] + av = v_out[4] # reverse map of the outputs force = self.reverse_map(np.reshape(force, [nframes,-1,3]), imap) diff --git a/source/api_cc/tests/.gitignore b/source/api_cc/tests/.gitignore new file mode 100644 index 0000000000..2c32bfb8cf --- /dev/null +++ b/source/api_cc/tests/.gitignore @@ -0,0 +1,5 @@ +CTestTestfile.cmake +Makefile +cmake_install.cmake +runUnitTests +version.h diff --git a/source/api_cc/tests/test_deeppot.cc b/source/api_cc/tests/test_deeppot_a.cc similarity index 97% rename from source/api_cc/tests/test_deeppot.cc rename to source/api_cc/tests/test_deeppot_a.cc index e59677dd66..0a736a7b88 100644 --- a/source/api_cc/tests/test_deeppot.cc +++ b/source/api_cc/tests/test_deeppot_a.cc @@ -14,7 +14,7 @@ #include #include -class TestInferDeepPot : public ::testing::Test +class TestInferDeepPotA : public ::testing::Test { protected: std::vector coord = { @@ -83,7 +83,7 @@ class TestInferDeepPot : public ::testing::Test }; -TEST_F(TestInferDeepPot, cpu_build_nlist) +TEST_F(TestInferDeepPotA, cpu_build_nlist) { double ener; std::vector force, virial; @@ -101,7 +101,7 @@ TEST_F(TestInferDeepPot, cpu_build_nlist) } } -TEST_F(TestInferDeepPot, cpu_build_nlist_atomic) +TEST_F(TestInferDeepPotA, cpu_build_nlist_atomic) { double ener; std::vector force, virial, atom_ener, atom_vir; @@ -128,7 +128,7 @@ TEST_F(TestInferDeepPot, cpu_build_nlist_atomic) } -TEST_F(TestInferDeepPot, cpu_lmp_nlist) +TEST_F(TestInferDeepPotA, cpu_lmp_nlist) { float rc = dp.cutoff(); int nloc = coord.size() / 3; @@ -179,7 +179,7 @@ TEST_F(TestInferDeepPot, cpu_lmp_nlist) } -TEST_F(TestInferDeepPot, cpu_lmp_nlist_atomic) +TEST_F(TestInferDeepPotA, cpu_lmp_nlist_atomic) { float rc = dp.cutoff(); int nloc = coord.size() / 3; @@ -252,7 +252,7 @@ TEST_F(TestInferDeepPot, cpu_lmp_nlist_atomic) } -TEST_F(TestInferDeepPot, cpu_lmp_nlist_2rc) +TEST_F(TestInferDeepPotA, cpu_lmp_nlist_2rc) { float rc = dp.cutoff(); int nloc = coord.size() / 3; @@ -303,7 +303,7 @@ TEST_F(TestInferDeepPot, cpu_lmp_nlist_2rc) } -TEST_F(TestInferDeepPot, cpu_lmp_nlist_type_sel) +TEST_F(TestInferDeepPotA, cpu_lmp_nlist_type_sel) { float rc = dp.cutoff(); @@ -355,7 +355,7 @@ TEST_F(TestInferDeepPot, cpu_lmp_nlist_type_sel) -class TestInferDeepPotNoPbc : public ::testing::Test +class TestInferDeepPotANoPbc : public ::testing::Test { protected: std::vector coord = { @@ -418,7 +418,7 @@ class TestInferDeepPotNoPbc : public ::testing::Test }; }; -TEST_F(TestInferDeepPotNoPbc, cpu_build_nlist) +TEST_F(TestInferDeepPotANoPbc, cpu_build_nlist) { double ener; std::vector force, virial; diff --git a/source/api_cc/tests/test_deeppot_r.cc b/source/api_cc/tests/test_deeppot_r.cc new file mode 100644 index 0000000000..ca0511c810 --- /dev/null +++ b/source/api_cc/tests/test_deeppot_r.cc @@ -0,0 +1,437 @@ +#include +#include +#include +#include +#include +#include "NNPInter.h" +#include "SimulationRegion.h" +#include "neighbor_list.h" +#include "test_utils.h" + +#include "google/protobuf/text_format.h" +#include "google/protobuf/io/zero_copy_stream_impl.h" +#include +#include +#include + +class TestInferDeepPotR : public ::testing::Test +{ +protected: + std::vector coord = { + 12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = { + 0, 1, 1, 0, 1, 1 + }; + std::vector box = { + 13., 0., 0., 0., 13., 0., 0., 0., 13. + }; + std::vector expected_e = { + -9.320909762801588272e+01,-1.868020345400987878e+02,-1.868011172371355997e+02,-9.320868430396934912e+01,-1.868010398844378415e+02,-1.868016706555875999e+02 + }; + std::vector expected_f = { + 6.385312846474267391e-04,-6.460452911141417731e-03,-5.652405655332678417e-04,-7.516468794343579736e-03,1.128804614240160216e-03,5.531937784564192051e-03,1.914138124904981664e-03,5.601819906021693503e-03,-5.131359585752605541e-03,-4.847104424804288617e-03,1.992071550328819614e-03,-4.028159855157302516e-03,1.236340684486603517e-03,-5.373955841338794344e-03,8.312829460571366513e-03,8.574563125108854156e-03,3.111712681889538742e-03,-4.120007238692381148e-03 + }; + std::vector expected_v = { + 5.844056241889131371e-03,4.663973497239899614e-04,-2.268382127762904633e-03,4.663973497239897988e-04,2.349338784202595950e-03,-6.908546513234039253e-04,-2.268382127762904633e-03,-6.908546513234039253e-04,2.040499248150800561e-03,4.238130266437327605e-03,-1.539867187443782223e-04,-2.393101333240631613e-03,-1.539867187443782223e-04,4.410341945447907377e-04,9.544239698119633068e-06,-2.393101333240631613e-03,9.544239698119578858e-06,1.877785959095269654e-03,5.798992562057291543e-03,6.943392552230453693e-04,-1.180376879311998773e-03,6.943392552230453693e-04,1.686725132156275536e-03,-1.461632060145726542e-03,-1.180376879311998556e-03,-1.461632060145726325e-03,1.749543733794208444e-03,7.173915604192910439e-03,3.903218041111061569e-04,-5.747400467123527524e-04,3.903218041111061569e-04,1.208289706621179949e-03,-1.826828914132010932e-03,-5.747400467123527524e-04,-1.826828914132011148e-03,2.856960586657185906e-03,4.067553030177322240e-03,-3.267469855253819430e-05,-6.980667859103454904e-05,-3.267469855253830272e-05,1.387653029234650918e-03,-2.096820720698671855e-03,-6.980667859103444062e-05,-2.096820720698671855e-03,3.218305506720191278e-03,4.753992590355240674e-03,1.224911338353675992e-03,-1.683421934571502484e-03,1.224911338353676209e-03,7.332113564901583539e-04,-1.025577052190138451e-03,-1.683421934571502484e-03,-1.025577052190138234e-03,1.456681925652047018e-03 + }; + int natoms; + double expected_tot_e; + std::vectorexpected_tot_v; + + NNPInter dp; + + void SetUp() override { + std::string file_name = "../../tests/infer/deeppot-r.pbtxt"; + int fd = open(file_name.c_str(), O_RDONLY); + protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); + GraphDef graph_def; + protobuf::TextFormat::Parse(input, &graph_def); + delete input; + std::fstream output("deeppot.pb", std::ios::out | std::ios::trunc | std::ios::binary); + graph_def.SerializeToOstream(&output); + // check the string by the following commands + // string txt; + // protobuf::TextFormat::PrintToString(graph_def, &txt); + + dp.init("deeppot.pb"); + + natoms = expected_e.size(); + EXPECT_EQ(natoms * 3, expected_f.size()); + EXPECT_EQ(natoms * 9, expected_v.size()); + expected_tot_e = 0.; + expected_tot_v.resize(9); + std::fill(expected_tot_v.begin(), expected_tot_v.end(), 0.); + for(int ii = 0; ii < natoms; ++ii){ + expected_tot_e += expected_e[ii]; + } + for(int ii = 0; ii < natoms; ++ii){ + for(int dd = 0; dd < 9; ++dd){ + expected_tot_v[dd] += expected_v[ii*9+dd]; + } + } + }; + + void TearDown() override { + remove( "deeppot.pb" ) ; + }; +}; + + +TEST_F(TestInferDeepPotR, cpu_build_nlist) +{ + double ener; + std::vector force, virial; + dp.compute(ener, force, virial, coord, atype, box); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } +} + +TEST_F(TestInferDeepPotR, cpu_build_nlist_atomic) +{ + double ener; + std::vector force, virial, atom_ener, atom_vir; + dp.compute(ener, force, virial, atom_ener, atom_vir, coord, atype, box); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + EXPECT_EQ(atom_ener.size(), natoms); + EXPECT_EQ(atom_vir.size(), natoms*9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } + for(int ii = 0; ii < natoms; ++ii){ + EXPECT_LT(fabs(atom_ener[ii] - expected_e[ii]), 1e-10); + } + for(int ii = 0; ii < natoms*9; ++ii){ + EXPECT_LT(fabs(atom_vir[ii] - expected_v[ii]), 1e-10); + } +} + + +TEST_F(TestInferDeepPotR, cpu_lmp_nlist) +{ + float rc = dp.cutoff(); + int nloc = coord.size() / 3; + std::vector coord_cpy; + std::vector atype_cpy, mapping; + std::vector > nlist_data; + _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, + coord, atype, box, rc); + int nall = coord_cpy.size() / 3; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_data); + + double ener; + std::vector force_, virial; + dp.compute(ener, force_, virial, coord_cpy, atype_cpy, box, nall-nloc, inlist, 0); + std::vector force; + _fold_back(force, force_, mapping, nloc, nall, 3); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } + + ener = 0.; + std::fill(force_.begin(), force_.end(), 0.0); + std::fill(virial.begin(), virial.end(), 0.0); + dp.compute(ener, force_, virial, coord_cpy, atype_cpy, box, nall-nloc, inlist, 1); + _fold_back(force, force_, mapping, nloc, nall, 3); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } +} + + +TEST_F(TestInferDeepPotR, cpu_lmp_nlist_atomic) +{ + float rc = dp.cutoff(); + int nloc = coord.size() / 3; + std::vector coord_cpy; + std::vector atype_cpy, mapping; + std::vector > nlist_data; + _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, + coord, atype, box, rc); + int nall = coord_cpy.size() / 3; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_data); + + double ener; + std::vector force_, atom_ener_, atom_vir_, virial; + std::vector force, atom_ener, atom_vir; + dp.compute(ener, force_, virial, atom_ener_, atom_vir_, coord_cpy, atype_cpy, box, nall-nloc, inlist, 0); + _fold_back(force, force_, mapping, nloc, nall, 3); + _fold_back(atom_ener, atom_ener_, mapping, nloc, nall, 1); + _fold_back(atom_vir, atom_vir_, mapping, nloc, nall, 9); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + EXPECT_EQ(atom_ener.size(), natoms); + EXPECT_EQ(atom_vir.size(), natoms*9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } + for(int ii = 0; ii < natoms; ++ii){ + EXPECT_LT(fabs(atom_ener[ii] - expected_e[ii]), 1e-10); + } + for(int ii = 0; ii < natoms*9; ++ii){ + EXPECT_LT(fabs(atom_vir[ii] - expected_v[ii]), 1e-10); + } + + ener = 0.; + std::fill(force_.begin(), force_.end(), 0.0); + std::fill(virial.begin(), virial.end(), 0.0); + std::fill(atom_ener_.begin(), atom_ener_.end(), 0.0); + std::fill(atom_vir_.begin(), atom_vir_.end(), 0.0); + dp.compute(ener, force_, virial, atom_ener_, atom_vir_, coord_cpy, atype_cpy, box, nall-nloc, inlist, 1); + _fold_back(force, force_, mapping, nloc, nall, 3); + _fold_back(atom_ener, atom_ener_, mapping, nloc, nall, 1); + _fold_back(atom_vir, atom_vir_, mapping, nloc, nall, 9); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + EXPECT_EQ(atom_ener.size(), natoms); + EXPECT_EQ(atom_vir.size(), natoms*9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } + for(int ii = 0; ii < natoms; ++ii){ + EXPECT_LT(fabs(atom_ener[ii] - expected_e[ii]), 1e-10); + } + for(int ii = 0; ii < natoms*9; ++ii){ + EXPECT_LT(fabs(atom_vir[ii] - expected_v[ii]), 1e-10); + } +} + + +TEST_F(TestInferDeepPotR, cpu_lmp_nlist_2rc) +{ + float rc = dp.cutoff(); + int nloc = coord.size() / 3; + std::vector coord_cpy; + std::vector atype_cpy, mapping; + std::vector > nlist_data; + _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, + coord, atype, box, rc*2); + int nall = coord_cpy.size() / 3; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_data); + + double ener; + std::vector force_(nall*3, 0.0), virial(9, 0.0); + dp.compute(ener, force_, virial, coord_cpy, atype_cpy, box, nall-nloc, inlist, 0); + std::vector force; + _fold_back(force, force_, mapping, nloc, nall, 3); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } + + ener = 0.; + std::fill(force_.begin(), force_.end(), 0.0); + std::fill(virial.begin(), virial.end(), 0.0); + dp.compute(ener, force_, virial, coord_cpy, atype_cpy, box, nall-nloc, inlist, 1); + _fold_back(force, force_, mapping, nloc, nall, 3); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } +} + + +TEST_F(TestInferDeepPotR, cpu_lmp_nlist_type_sel) +{ + float rc = dp.cutoff(); + + // add vir atoms + int nvir = 2; + std::vector coord_vir(nvir*3); + std::vector atype_vir(nvir, 2); + for(int ii = 0; ii < nvir; ++ii){ + coord_vir[ii] = coord[ii]; + } + coord.insert(coord.begin(), coord_vir.begin(), coord_vir.end()); + atype.insert(atype.begin(), atype_vir.begin(), atype_vir.end()); + natoms += nvir; + std::vector expected_f_vir(nvir*3, 0.0); + expected_f.insert(expected_f.begin(), expected_f_vir.begin(), expected_f_vir.end()); + + // build nlist + int nloc = coord.size() / 3; + std::vector coord_cpy; + std::vector atype_cpy, mapping; + std::vector > nlist_data; + _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, + coord, atype, box, rc); + int nall = coord_cpy.size() / 3; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + convert_nlist(inlist, nlist_data); + + // dp compute + double ener; + std::vector force_(nall*3, 0.0), virial(9, 0.0); + dp.compute(ener, force_, virial, coord_cpy, atype_cpy, box, nall-nloc, inlist, 0); + // fold back + std::vector force; + _fold_back(force, force_, mapping, nloc, nall, 3); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } +} + + + +class TestInferDeepPotRNoPbc : public ::testing::Test +{ +protected: + std::vector coord = { + 12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector atype = { + 0, 1, 1, 0, 1, 1 + }; + std::vector box = {}; + std::vector expected_e = { + -9.321213823508108476e+01,-1.868044102481340758e+02,-1.868067983858651075e+02,-9.320899631301440991e+01,-1.868014559732615112e+02,-1.868017660713088617e+02 + }; + std::vector expected_f = { + 4.578151103701261042e-03,-1.917874111009987628e-03,-3.464546781179331930e-03,-4.578151103701261042e-03,1.917874111009987628e-03,3.464546781179331930e-03,-2.624402581721222913e-03,3.566275128489623933e-04,-2.859315986763691776e-04,-5.767787273464367384e-03,1.907053583551196647e-03,-3.889064429673861831e-03,1.786820066350549132e-04,-5.327197473636275694e-03,8.236236182834734409e-03,8.213507848550535492e-03,3.063516377236116545e-03,-4.061240154484504865e-03 + }; + std::vector expected_v = { + 1.984979026299632174e-03,-8.315452677741701822e-04,-1.502146290172694243e-03,-8.315452677741700738e-04,3.483500446080982317e-04,6.292774999372096039e-04,-1.502146290172694243e-03,6.292774999372097123e-04,1.136759354725281907e-03,1.402852790439301908e-03,-5.876815743732210226e-04,-1.061618327900012114e-03,-5.876815743732211311e-04,2.461909298049979960e-04,4.447320022283834766e-04,-1.061618327900012331e-03,4.447320022283834766e-04,8.033868427351443728e-04,4.143606961846296385e-03,-5.511382161123719835e-04,4.465413399437045397e-04,-5.511382161123719835e-04,1.082271054025323839e-04,-1.097918001262628728e-04,4.465413399437046481e-04,-1.097918001262628728e-04,1.220966982358671871e-04,5.263952004497593831e-03,2.395243710938091842e-04,-2.830378939414603329e-04,2.395243710938094010e-04,1.189969706598244898e-03,-1.805627331015851201e-03,-2.830378939414602245e-04,-1.805627331015851635e-03,2.801996513751836820e-03,2.208413501170402270e-03,5.331756287635716889e-05,-1.664423506603235218e-04,5.331756287635695205e-05,1.379626072862918072e-03,-2.094132943741625064e-03,-1.664423506603234133e-04,-2.094132943741625064e-03,3.199787996743366607e-03,4.047014004814953811e-03,1.137904999421357000e-03,-1.568106936614101698e-03,1.137904999421357217e-03,7.205982843216952307e-04,-1.011174600268313238e-03,-1.568106936614101698e-03,-1.011174600268313238e-03,1.435226522157425754e-03 + }; + int natoms; + double expected_tot_e; + std::vectorexpected_tot_v; + + NNPInter dp; + + void SetUp() override { + std::string file_name = "../../tests/infer/deeppot-r.pbtxt"; + int fd = open(file_name.c_str(), O_RDONLY); + protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); + GraphDef graph_def; + protobuf::TextFormat::Parse(input, &graph_def); + delete input; + std::fstream output("deeppot.pb", std::ios::out | std::ios::trunc | std::ios::binary); + graph_def.SerializeToOstream(&output); + + dp.init("deeppot.pb"); + + natoms = expected_e.size(); + EXPECT_EQ(natoms * 3, expected_f.size()); + EXPECT_EQ(natoms * 9, expected_v.size()); + expected_tot_e = 0.; + expected_tot_v.resize(9); + std::fill(expected_tot_v.begin(), expected_tot_v.end(), 0.); + for(int ii = 0; ii < natoms; ++ii){ + expected_tot_e += expected_e[ii]; + } + for(int ii = 0; ii < natoms; ++ii){ + for(int dd = 0; dd < 9; ++dd){ + expected_tot_v[dd] += expected_v[ii*9+dd]; + } + } + }; + + void TearDown() override { + remove( "deeppot.pb" ) ; + }; +}; + +TEST_F(TestInferDeepPotRNoPbc, cpu_build_nlist) +{ + double ener; + std::vector force, virial; + dp.compute(ener, force, virial, coord, atype, box); + + EXPECT_EQ(force.size(), natoms*3); + EXPECT_EQ(virial.size(), 9); + + EXPECT_LT(fabs(ener - expected_tot_e), 1e-10); + for(int ii = 0; ii < natoms*3; ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < 3*3; ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_tot_v[ii]), 1e-10); + } +} diff --git a/source/op/prod_env_mat_multi_device.cc b/source/op/prod_env_mat_multi_device.cc index b50b7d80b8..e12fa73017 100644 --- a/source/op/prod_env_mat_multi_device.cc +++ b/source/op/prod_env_mat_multi_device.cc @@ -80,6 +80,33 @@ _map_nlist_cpu( const int & nloc, const int & nnei); +template +static void +_prepare_coord_nlist_cpu( + OpKernelContext* context, + FPTYPE const ** coord, + std::vector & coord_cpy, + int const** type, + std::vector & type_cpy, + std::vector & idx_mapping, + InputNlist & inlist, + std::vector & ilist, + std::vector & numneigh, + std::vector & firstneigh, + std::vector> & jlist, + int & new_nall, + int & mem_cpy, + int & mem_nnei, + int & max_nbor_size, + const FPTYPE * box, + const int * mesh_tensor_data, + const int & nloc, + const int & nei_mode, + const float & rcut_r, + const int & max_cpy_trial, + const int & max_nnei_trial); + + template class ProdEnvMatAOp : public OpKernel { @@ -228,7 +255,6 @@ class ProdEnvMatAOp : public OpKernel { const FPTYPE * coord = p_coord + ff*nall*3; const FPTYPE * box = p_box + ff*9; const int * type = p_type + ff*nall; - std::vector idx_mapping; if(device == "GPU") { #if GOOGLE_CUDA @@ -258,46 +284,25 @@ class ProdEnvMatAOp : public OpKernel { #endif //GOOGLE_CUDA } else if (device == "CPU") { - int new_nall = nall; InputNlist inlist; - inlist.inum = nloc; - // some buffers, be free after prod_env_mat_a_cpu + // some buffers, be freed after the evaluation of this frame + std::vector idx_mapping; std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); std::vector> jlist(nloc); std::vector coord_cpy; std::vector type_cpy; - if(nei_mode != 3){ - // build nlist by myself - // normalize and copy coord - if(nei_mode == 1){ - int copy_ok = _norm_copy_coord_cpu( - coord_cpy, type_cpy, idx_mapping, new_nall, mem_cpy, - coord, box, type, nloc, max_cpy_trial, rcut_r); - OP_REQUIRES (context, copy_ok, errors::Aborted("cannot allocate mem for copied coords")); - coord = &coord_cpy[0]; - type = &type_cpy[0]; - } - // build nlist - int build_ok = _build_nlist_cpu( - ilist, numneigh, firstneigh, jlist, max_nbor_size, mem_nnei, - coord, nloc, new_nall, max_nnei_trial, rcut_r); - OP_REQUIRES (context, build_ok, errors::Aborted("cannot allocate mem for nlist")); - inlist.ilist = &ilist[0]; - inlist.numneigh = &numneigh[0]; - inlist.firstneigh = &firstneigh[0]; - } - else{ - // copy pointers to nlist data - memcpy(&inlist.ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy(&inlist.numneigh, 8 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy(&inlist.firstneigh, 12 + mesh_tensor.flat().data(), sizeof(int **)); - max_nbor_size = max_numneigh(inlist); - } + int frame_nall = nall; + // prepare coord and nlist + _prepare_coord_nlist_cpu( + context, &coord, coord_cpy, &type, type_cpy, idx_mapping, + inlist, ilist, numneigh, firstneigh, jlist, + frame_nall, mem_cpy, mem_nnei, max_nbor_size, + box, mesh_tensor.flat().data(), nloc, nei_mode, rcut_r, max_cpy_trial, max_nnei_trial); // launch the cpu compute function prod_env_mat_a_cpu( em, em_deriv, rij, nlist, - coord, type, inlist, max_nbor_size, avg, std, nloc, new_nall, rcut_r, rcut_r_smth, sec_a); + coord, type, inlist, max_nbor_size, avg, std, nloc, frame_nall, rcut_r, rcut_r_smth, sec_a); // do nlist mapping if coords were copied if(b_nlist_map) _map_nlist_cpu(nlist, &idx_mapping[0], nloc, nnei); } @@ -337,6 +342,10 @@ class ProdEnvMatROp : public OpKernel { ndescrpt = sec.back() * 1; nnei = sec.back(); max_nbor_size = 1024; + max_cpy_trial = 100; + mem_cpy = 256; + max_nnei_trial = 100; + mem_nnei = 256; } void Compute(OpKernelContext* context) override { @@ -379,6 +388,28 @@ class ProdEnvMatROp : public OpKernel { OP_REQUIRES (context, (9 == box_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of box should be 9")); OP_REQUIRES (context, (ndescrpt == avg_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of avg should be ndescrpt")); OP_REQUIRES (context, (ndescrpt == std_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of std should be ndescrpt")); + + int nei_mode = 0; + bool b_nlist_map = false; + if (mesh_tensor.shape().dim_size(0) == 16) { + // lammps neighbor list + nei_mode = 3; + } + else if (mesh_tensor.shape().dim_size(0) == 6) { + // manual copied pbc + assert (nloc == nall); + nei_mode = 1; + b_nlist_map = true; + } + else if (mesh_tensor.shape().dim_size(0) == 0) { + // no pbc + assert (nloc == nall); + nei_mode = -1; + } + else { + throw std::runtime_error("invalid mesh tensor"); + } + // Create an output tensor TensorShape descrpt_shape ; descrpt_shape.AddDim (nsamples); @@ -415,14 +446,25 @@ class ProdEnvMatROp : public OpKernel { nlist_shape, &nlist_tensor)); - FPTYPE * em = descrpt_tensor->flat().data(); - FPTYPE * em_deriv = descrpt_deriv_tensor->flat().data(); - FPTYPE * rij = rij_tensor->flat().data(); - int * nlist = nlist_tensor->flat().data(); - const FPTYPE * coord = coord_tensor.flat().data(); + FPTYPE * p_em = descrpt_tensor->flat().data(); + FPTYPE * p_em_deriv = descrpt_deriv_tensor->flat().data(); + FPTYPE * p_rij = rij_tensor->flat().data(); + int * p_nlist = nlist_tensor->flat().data(); + const FPTYPE * p_coord = coord_tensor.flat().data(); + const FPTYPE * p_box = box_tensor.flat().data(); const FPTYPE * avg = avg_tensor.flat().data(); const FPTYPE * std = std_tensor.flat().data(); - const int * type = type_tensor.flat().data(); + const int * p_type = type_tensor.flat().data(); + + // loop over samples + for(int ff = 0; ff < nsamples; ++ff){ + FPTYPE * em = p_em + ff*nloc*ndescrpt; + FPTYPE * em_deriv = p_em_deriv + ff*nloc*ndescrpt*3; + FPTYPE * rij = p_rij + ff*nloc*nnei*3; + int * nlist = p_nlist + ff*nloc*nnei; + const FPTYPE * coord = p_coord + ff*nall*3; + const FPTYPE * box = p_box + ff*9; + const int * type = p_type + ff*nall; if(device == "GPU") { #if GOOGLE_CUDA @@ -452,22 +494,27 @@ class ProdEnvMatROp : public OpKernel { #endif //GOOGLE_CUDA } else if (device == "CPU") { - // memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); - // memcpy (&jrange, 8 + mesh_tensor.flat().data(), sizeof(int *)); - // memcpy (&jlist, 12 + mesh_tensor.flat().data(), sizeof(int *)); - // launch the cpu compute function - // prod_env_mat_r_cpu( - // em, em_deriv, rij, nlist, - // coord, type, ilist, jrange, jlist, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); InputNlist inlist; - inlist.inum = nloc; - memcpy(&inlist.ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy(&inlist.numneigh, 8 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy(&inlist.firstneigh, 12 + mesh_tensor.flat().data(), sizeof(int **)); - max_nbor_size = max_numneigh(inlist); + // some buffers, be freed after the evaluation of this frame + std::vector idx_mapping; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + std::vector> jlist(nloc); + std::vector coord_cpy; + std::vector type_cpy; + int frame_nall = nall; + // prepare coord and nlist + _prepare_coord_nlist_cpu( + context, &coord, coord_cpy, &type, type_cpy, idx_mapping, + inlist, ilist, numneigh, firstneigh, jlist, + frame_nall, mem_cpy, mem_nnei, max_nbor_size, + box, mesh_tensor.flat().data(), nloc, nei_mode, rcut, max_cpy_trial, max_nnei_trial); + // launch the cpu compute function prod_env_mat_r_cpu( em, em_deriv, rij, nlist, - coord, type, inlist, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); + coord, type, inlist, max_nbor_size, avg, std, nloc, frame_nall, rcut, rcut_smth, sec); + if(b_nlist_map) _map_nlist_cpu(nlist, &idx_mapping[0], nloc, nnei); + } } } @@ -481,6 +528,8 @@ class ProdEnvMatROp : public OpKernel { std::vector sec; std::vector sec_null; int nnei, ndescrpt, nloc, nall, max_nbor_size; + int mem_cpy, max_cpy_trial; + int mem_nnei, max_nnei_trial; std::string device; int * array_int = NULL; unsigned long long * array_longlong = NULL; @@ -488,6 +537,9 @@ class ProdEnvMatROp : public OpKernel { int * nbor_list_dev = NULL; }; + + + template static int _norm_copy_coord_cpu( @@ -578,6 +630,61 @@ _map_nlist_cpu( } } +template +static void +_prepare_coord_nlist_cpu( + OpKernelContext* context, + FPTYPE const ** coord, + std::vector & coord_cpy, + int const** type, + std::vector & type_cpy, + std::vector & idx_mapping, + InputNlist & inlist, + std::vector & ilist, + std::vector & numneigh, + std::vector & firstneigh, + std::vector> & jlist, + int & new_nall, + int & mem_cpy, + int & mem_nnei, + int & max_nbor_size, + const FPTYPE * box, + const int * mesh_tensor_data, + const int & nloc, + const int & nei_mode, + const float & rcut_r, + const int & max_cpy_trial, + const int & max_nnei_trial) +{ + inlist.inum = nloc; + if(nei_mode != 3){ + // build nlist by myself + // normalize and copy coord + if(nei_mode == 1){ + int copy_ok = _norm_copy_coord_cpu( + coord_cpy, type_cpy, idx_mapping, new_nall, mem_cpy, + *coord, box, *type, nloc, max_cpy_trial, rcut_r); + OP_REQUIRES (context, copy_ok, errors::Aborted("cannot allocate mem for copied coords")); + *coord = &coord_cpy[0]; + *type = &type_cpy[0]; + } + // build nlist + int build_ok = _build_nlist_cpu( + ilist, numneigh, firstneigh, jlist, max_nbor_size, mem_nnei, + *coord, nloc, new_nall, max_nnei_trial, rcut_r); + OP_REQUIRES (context, build_ok, errors::Aborted("cannot allocate mem for nlist")); + inlist.ilist = &ilist[0]; + inlist.numneigh = &numneigh[0]; + inlist.firstneigh = &firstneigh[0]; + } + else{ + // copy pointers to nlist data + memcpy(&inlist.ilist, 4 + mesh_tensor_data, sizeof(int *)); + memcpy(&inlist.numneigh, 8 + mesh_tensor_data, sizeof(int *)); + memcpy(&inlist.firstneigh, 12 + mesh_tensor_data, sizeof(int **)); + max_nbor_size = max_numneigh(inlist); + } +} // Register the CPU kernels. diff --git a/source/tests/infer/deeppot-r.pbtxt b/source/tests/infer/deeppot-r.pbtxt new file mode 100644 index 0000000000..3ddd2effe4 --- /dev/null +++ b/source/tests/infer/deeppot-r.pbtxt @@ -0,0 +1,22458 @@ +node { + name: "o_atom_virial/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_14/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 9 + } + } + } +} +node { + name: "strided_slice_25/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_25/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_25/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "o_virial/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\t\000\000\000" + } + } + } +} +node { + name: "o_force/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_13/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_24/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_24/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_24/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "Reshape_17/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_12/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 138 + } + } + } +} +node { + name: "strided_slice_23/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_23/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_23/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "gradients/Slice_1_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_1_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_1_grad/stack" + op: "Pack" + input: "gradients/Slice_1_grad/Rank" + input: "gradients/Slice_1_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/Slice_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_grad/stack" + op: "Pack" + input: "gradients/Slice_grad/Rank" + input: "gradients/Slice_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/stack" + op: "Pack" + input: "gradients/filter_type_1/Slice_1_grad/Rank" + input: "gradients/filter_type_1/Slice_1_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/stack" + op: "Pack" + input: "gradients/filter_type_1/Slice_grad/Rank" + input: "gradients/filter_type_1/Slice_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/stack" + op: "Pack" + input: "gradients/filter_type_0/Slice_1_grad/Rank" + input: "gradients/filter_type_0/Slice_1_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/stack" + op: "Pack" + input: "gradients/filter_type_0/Slice_grad/Rank" + input: "gradients/filter_type_0/Slice_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\002\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\004\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\001\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_6_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_6_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Maximum_1/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Const_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Const" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Maximum/y" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Fill/value" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/range/delta" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/range/start" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Shape_1" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + } + } + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Fill" + op: "Fill" + input: "gradients/filter_type_1/Mean_grad/Shape_1" + input: "gradients/filter_type_1/Mean_grad/Fill/value" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } + attr { + key: "index_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Size" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/range" + op: "Range" + input: "gradients/filter_type_1/Mean_grad/range/start" + input: "gradients/filter_type_1/Mean_grad/Size" + input: "gradients/filter_type_1/Mean_grad/range/delta" + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Maximum_1/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Const_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Const" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Maximum/y" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Fill/value" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/range/delta" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/range/start" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Shape_1" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + } + } + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Fill" + op: "Fill" + input: "gradients/filter_type_0/Mean_grad/Shape_1" + input: "gradients/filter_type_0/Mean_grad/Fill/value" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } + attr { + key: "index_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Size" + op: "Const" + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/range" + op: "Range" + input: "gradients/filter_type_0/Mean_grad/range/start" + input: "gradients/filter_type_0/Mean_grad/Size" + input: "gradients/filter_type_0/Mean_grad/range/delta" + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + } + } + } + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + } + } + } + } + } +} +node { + name: "gradients/concat_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_3_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_3_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_3_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_3_grad/stack" + op: "Pack" + input: "gradients/Slice_3_grad/Rank" + input: "gradients/Slice_3_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/Slice_2_grad/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_2_grad/stack/1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/Slice_2_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/Slice_2_grad/stack" + op: "Pack" + input: "gradients/Slice_2_grad/Rank" + input: "gradients/Slice_2_grad/stack/1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/Shape_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "gradients/concat_1_grad/Rank" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "gradients/grad_ys_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 1.0 + } + } + } +} +node { + name: "o_energy/reduction_indices" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "o_atom_energy/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "strided_slice_22/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_22/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_22/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_16/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: -1 + } + } + } +} +node { + name: "concat_1/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/concat_1_grad/mod" + op: "FloorMod" + input: "concat_1/axis" + input: "gradients/concat_1_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_21/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_21/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_21/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_20/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_20/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_20/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "final_layer_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + } + double_val: -186.95558874781707 + } + } + } +} +node { + name: "final_layer_type_1/bias/read" + op: "Identity" + input: "final_layer_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_1/bias" + } + } + } +} +node { + name: "final_layer_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 1 + } + } + tensor_content: "\\\013\372#\355n\277?\360\225\365o&\236\274\277\241\265`:\214\217\324\277\203\0024J.\334\301\277" + } + } + } +} +node { + name: "final_layer_type_1/matrix/read" + op: "Identity" + input: "final_layer_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_1/matrix" + } + } + } +} +node { + name: "layer_2_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "layer_2_type_1/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\256\246\233X\377,\302?m\\\355\314\231W\263?\325\367\205&p\277\247?@q\352r\312q\303?" + } + } + } +} +node { + name: "layer_2_type_1/idt/read" + op: "Identity" + input: "layer_2_type_1/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_1/idt" + } + } + } +} +node { + name: "layer_2_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\232\021\347\311\307=\310?\201\260\026G\3248\323\277*\273\034\265i\030\351\277\264\316\177\345\022^\310\277" + } + } + } +} +node { + name: "layer_2_type_1/bias/read" + op: "Identity" + input: "layer_2_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_1/bias" + } + } + } +} +node { + name: "layer_2_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 4 + } + } + tensor_content: "\336\373)\232`f\270?\004\302\271(\200\033\301\277\014\252\232\010\207\202\323\277kn\371\233\207\233\270\277\0371\315\320\246\027\347?\211\232\302:\332F\306\277D\2546\031\340\260\265?\306\260V\342\351\345\344\277\313I+\337\365;\322?\235\322f\336kg\324\277\257\342\260\230\364\325x?\270\272\360\334!L\332\277\234\233\007\301\345\244i\277\022\014\367\214U\036\323?8\213j}\226\336\277\277" + } + } + } +} +node { + name: "layer_2_type_1/matrix/read" + op: "Identity" + input: "layer_2_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_1/matrix" + } + } + } +} +node { + name: "layer_1_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "layer_1_type_1/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\322O\226^\237y\300?\034j\254wY\303\260?\322.\304\376\314\303\247?T\354\031\034\177S\303?" + } + } + } +} +node { + name: "layer_1_type_1/idt/read" + op: "Identity" + input: "layer_1_type_1/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_1/idt" + } + } + } +} +node { + name: "layer_1_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\200\344\343~\274;\310?\250\0331o+C\323\277\337Vm\270\235\030\351\277\373f \253\177]\310\277" + } + } + } +} +node { + name: "layer_1_type_1/bias/read" + op: "Identity" + input: "layer_1_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_1/bias" + } + } + } +} +node { + name: "layer_1_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 4 + } + } + tensor_content: "\310\034R\242>\317\267?`\3732\331b\310\300\277W\255J\243S]\323\277\257\034\345Bp\t\270\277(\376\255\177\020\014\347?\303\313\355\315\261\365\305\277\240\341GJ\221\013\266?Q5\363A\275\327\344\277\331\316\246\211\r=\322?)\254Mmu]\324\277\2745\021\356\022\306x?_\005\036vcL\332\2774]~I\354\255e\277\210\233\367\243\253\037\342?\211o\302\213\221\031\323?\342Eq\307]\362\277\277" + } + } + } +} +node { + name: "layer_1_type_1/matrix/read" + op: "Identity" + input: "layer_1_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_1/matrix" + } + } + } +} +node { + name: "layer_0_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "layer_0_type_1/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\\\007\303\2406C\310?p\274k:IA\323\277\002>\035{\307\023\351\277d\237\250-\256^\310\277" + } + } + } +} +node { + name: "layer_0_type_1/bias/read" + op: "Identity" + input: "layer_0_type_1/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_1/bias" + } + } + } +} +node { + name: "layer_0_type_1/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + dim { + size: 4 + } + } + tensor_content: "a\267\230\311F\336\216?\017\210\244\324\207\265\250\277E\331\263u\353\360\307\277\036\202\030\3502\272\217\277A\201(\312tM\343?x\346\207\333\r/\304\277\366p!\351\215\361\252?<\017@u\203\204\341\277s\253\227\363\233\232\316?z\375\036 \332\031\321\277\217\200\324\022\\\336]\2777\017\304\0074\357\325\277HC\275\274+b\250?y\334T4\316\214\332?\2712\272\223\240\334\310?f\214\021~Fx\303\277\222\313\342-\032\334\326\277L\257\213)\2659\350?\220\000T6\344D\247\277\343G6f*\303\311?\004\367\202\347\276\316\317? x\005\227\355Z\277?Bz_bL\376\210?\017\002n\201\023\327\303\277\014)\340\311=I\267\277l\246\262\201\036\005\234?\334\370B\325f\313\223\277\255 \327\277\213b\344\277+\202\327\337q\277\320\277\365\257\206\267r[\311\277\371\350\010e\225T\322\277\376\222\2732\304\246\311\277" + } + } + } +} +node { + name: "layer_0_type_1/matrix/read" + op: "Identity" + input: "layer_0_type_1/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_1/matrix" + } + } + } +} +node { + name: "Reshape_14/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "Slice_3/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_3/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_11/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "strided_slice_18/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_18/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_18/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "mul_10/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "strided_slice_17/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_17/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_17/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_16/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_16/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_16/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "final_layer_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + } + double_val: -93.38284094403838 + } + } + } +} +node { + name: "final_layer_type_0/bias/read" + op: "Identity" + input: "final_layer_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_0/bias" + } + } + } +} +node { + name: "final_layer_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 1 + } + } + tensor_content: " q\003\376\035F\273?\305 \264\236\225T\300\277\267\330Oj\211\217\324\277\311)\372\n\236r\301\277" + } + } + } +} +node { + name: "final_layer_type_0/matrix/read" + op: "Identity" + input: "final_layer_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@final_layer_type_0/matrix" + } + } + } +} +node { + name: "layer_2_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "layer_2_type_0/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "-s\2148P\213\300?\t\\5\207:\343\261?\354\253\344\255]\273\247?\nN\273\007\317p\303?" + } + } + } +} +node { + name: "layer_2_type_0/idt/read" + op: "Identity" + input: "layer_2_type_0/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_0/idt" + } + } + } +} +node { + name: "layer_2_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\350\2536U\2378\310?F^d\232\037<\323\277<\333\316\263\334\030\351\277n)\2739\323\\\310\277" + } + } + } +} +node { + name: "layer_2_type_0/bias/read" + op: "Identity" + input: "layer_2_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_0/bias" + } + } + } +} +node { + name: "layer_2_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 4 + } + } + tensor_content: "1I\331x\365y\264?\236=\021\3015\"\276\277t\241\024q}\202\322\277\'X\375\243R\311\264\277\357\272\306\234B\224\346?\202\277\326\035\265B\304\277\265\203\203<\256\202\271?\364\360\345Q\310d\344\277~\202\205\340D>\322?\272\265^s\372c\324\277\247\020\361``\021y?Ce\213d\257L\332\277\2315@\003\323yQ?\223\226E\313\350\005\342?\332$\220\331!\334\322?\236\302 \262bb\300\277" + } + } + } +} +node { + name: "layer_2_type_0/matrix/read" + op: "Identity" + input: "layer_2_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_2_type_0/matrix" + } + } + } +} +node { + name: "layer_1_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "layer_1_type_0/idt" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\270\377\233v\233%\300?\252\343\016~\2346\257?|\021\005zw\277\247?\212\336\002}\237%\303?" + } + } + } +} +node { + name: "layer_1_type_0/idt/read" + op: "Identity" + input: "layer_1_type_0/idt" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_0/idt" + } + } + } +} +node { + name: "layer_1_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\327\255v@\2378\310?\337\264\020&`D\323\277n\013!*\374\030\351\277]\314(\251C\\\310\277" + } + } + } +} +node { + name: "layer_1_type_0/bias/read" + op: "Identity" + input: "layer_1_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_0/bias" + } + } + } +} +node { + name: "layer_1_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 4 + } + } + tensor_content: "\3771>\326\251\362\263?X\350\356\3338\211\275\277C\031q\0010`\322\277\216JkA @\264\277m\027i\350l\217\346?K6{\321\232\"\304\277An\035\322\356\226\271?\231!4\253;`\344\277v\317IWE>\322?4\370\307\273?\\\324\277\007\022\303\'\275\371x?\365_+\247\343L\332\277\315\315\026B?\020_?\216\277Kw\014\376\341?\342BV\321u\320\322?\0166\\\244\372{\300\277" + } + } + } +} +node { + name: "layer_1_type_0/matrix/read" + op: "Identity" + input: "layer_1_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_1_type_0/matrix" + } + } + } +} +node { + name: "layer_0_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "layer_0_type_0/bias" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + } + tensor_content: "\021\356`\3544C\310?T\232\255\216\313=\323\277h\320\n\257\230\023\351\277\373\351\330\"\020^\310\277" + } + } + } +} +node { + name: "layer_0_type_0/bias/read" + op: "Identity" + input: "layer_0_type_0/bias" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_0/bias" + } + } + } +} +node { + name: "layer_0_type_0/matrix" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 8 + } + dim { + size: 4 + } + } + tensor_content: "1Xa\274\006\271\215?\226y\267\363\026\\\250\277\231\261k`U\334\307\277A\221{ \254\216\216\277\234J\353\371\352\252\342?\361#\362\2134\250\301\277\n\332\024\273\360\177\262?\313&V\231U\340\340\277!\017\256\256\372>\314?#\275\371\256\017\321\317\277\264N\026\273\221\205\220?\232Xd\245\253\270\324\277\220\352^\201\031\305\244?\322\336\240#\356\336\332?\002\313\260\036\005\245\311?{\340Z\020\320\254\302\277\303#D\002:\344\326\277\037\342X\214G>\350?\037\315\330\224<\004\247\277\002\303\252\214\306\322\311?\327\351sx{i\315?\266\332\315\313\321\031\302?\242\224#\27226\237?\224\274\036\250\323a\301\277\003:I\253\203G\270\277\201\r\262Y\351\370\236?[\355xx\212\035\220\277\016\353\364\225~D\344\277W+\013\314c\365\321\277\273\332\205\350\234\373\306\2774b\341\345\343\"\321\277\343|\213\016t7\307\277" + } + } + } +} +node { + name: "layer_0_type_0/matrix/read" + op: "Identity" + input: "layer_0_type_0/matrix" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@layer_0_type_0/matrix" + } + } + } +} +node { + name: "add_2/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "strided_slice_15/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_15/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_15/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "Reshape_12/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "Slice_2/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_2/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/Slice_2_grad/Reshape" + op: "Reshape" + input: "Slice_2/begin" + input: "gradients/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_9/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "strided_slice_14/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_14/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_14/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "Reshape_11/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_8/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "strided_slice_13/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_13/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_13/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "fitting_attr/daparam" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "fitting_attr/dfparam" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/concat_grad/mod" + op: "FloorMod" + input: "concat/axis" + input: "gradients/concat_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_7/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "strided_slice_11/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_11/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_11/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_10/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_10/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_10/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "filter_type_1/mul/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.2 + } + } + } +} +node { + name: "filter_type_1/Mean/reduction_indices" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/add" + op: "Add" + input: "filter_type_1/Mean/reduction_indices" + input: "gradients/filter_type_1/Mean_grad/Size" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/mod" + op: "FloorMod" + input: "gradients/filter_type_1/Mean_grad/add" + input: "gradients/filter_type_1/Mean_grad/Size" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } +} +node { + name: "filter_type_1/concat_6/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_6_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_6/axis" + input: "gradients/filter_type_1/concat_6_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_9/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\\\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/concat_5/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_5/axis" + input: "gradients/filter_type_1/concat_5_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_8/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\313~\206\227\026]\310?\251\260eSc\000\332\277\001\024\000\365\264v\354\277)N\024=\273\226\310\277\215L?a0f\377?@J:!\263\373\332\277\257\201\376\t\225\241\323?\344\017\230?6L\374\277" + } + } + } +} +node { + name: "filter_type_1/bias_3_1/read" + op: "Identity" + input: "filter_type_1/bias_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_3_1" + } + } + } +} +node { + name: "filter_type_1/matrix_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "C\365\223\350\217v\230?\017t\200\254R\t\303\277\241\326V*\320\244\310\277\226\242\013\321J\307\271\277\232\022$\232\300\367\337?A\220\3636\353\347\302\277\026.!\333\257U\303?\'\021dQsb\334\277\033\261M?q\354\316?o(\300\340X\r\305\277>\253\306!}\266\271?\251\317\327\006N\375\325\2773\254\370\371\276\375\236\277\316\376Y\367\321g\337?\310\216\2443?y\321?\006\220\\\232;\365\262\277\016\240HJv\004\320\277#\253\033N:6\350?Y\224\366M\375\314\247\277\231w\277a\265\247\270?\360\236\322=u\252\302?\226\302Ze\373f\313?Vp\004\323\212y\275?\r\203}\227\345\206\252\277\351u\360\231Gz\261\277\273\001\2232\\P\271?H\351\361\232\247T\260?gL\354\224K\021\345\277|LZ\2058`\327\277\254\32788\017O\273\277\031\234\000>\270Y\307\277\347%\304w\'\265\270\277" + } + } + } +} +node { + name: "filter_type_1/matrix_3_1/read" + op: "Identity" + input: "filter_type_1/matrix_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_3_1" + } + } + } +} +node { + name: "filter_type_1/concat_4/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_4/axis" + input: "gradients/filter_type_1/concat_4_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_7/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "{\343v8\035\361\322?f\342*J\013\000\332\277ew\317\t\246y\354\277X\257x\247\222\357\321\277" + } + } + } +} +node { + name: "filter_type_1/bias_2_1/read" + op: "Identity" + input: "filter_type_1/bias_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_2_1" + } + } + } +} +node { + name: "filter_type_1/matrix_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "/\344KnK\\\257?\337j\314\211\266\334\302\277\376uT\340\"y\327\277\033\213\371\316M\002\256\2776RV\376WJ\347?\245\337*\265\323\374\270\277\251u\204\352\302\232\311?\354\262\303*\035\354\344\277" + } + } + } +} +node { + name: "filter_type_1/matrix_2_1/read" + op: "Identity" + input: "filter_type_1/matrix_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_2_1" + } + } + } +} +node { + name: "filter_type_1/concat_3/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_3/axis" + input: "gradients/filter_type_1/concat_3_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_6/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "^\342\206\234\0047\310?Km\034Np\000\332\277" + } + } + } +} +node { + name: "filter_type_1/bias_1_1/read" + op: "Identity" + input: "filter_type_1/bias_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_1_1" + } + } + } +} +node { + name: "filter_type_1/matrix_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\021\037\265\250\211\276\267?_\250\232\361\264w\303\277" + } + } + } +} +node { + name: "filter_type_1/matrix_1_1/read" + op: "Identity" + input: "filter_type_1/matrix_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_1_1" + } + } + } +} +node { + name: "filter_type_1/Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_1/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\\\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice_1/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000.\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Reshape" + op: "Reshape" + input: "filter_type_1/Slice_1/begin" + input: "gradients/filter_type_1/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_4/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_2/axis" + input: "gradients/filter_type_1/concat_2_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "JBu\357\245t\310?\036\025\0032P\010\332\277\327\320\2728\027w\354\277\216\275\"u\253\216\310\277\244\003\033L\207g\377?\326\2659\304\023\242\331\277\367\213\250\261N\244\323?\314\003{\2474M\374\277" + } + } + } +} +node { + name: "filter_type_1/bias_3_0/read" + op: "Identity" + input: "filter_type_1/bias_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_3_0" + } + } + } +} +node { + name: "filter_type_1/matrix_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\000\321\243\226\211X\250?i\307\361\315\364\213\302\277F\230+\376+/\310\277$J\"\242\210d\262\277\343\257\367\275#\353\337?Ny\376\002\320\212\271\277\255\302v@Gq\304?2\331\216\270mT\334\27738\027\2603\002\317?92\254N\305\005\305\277\001\360o*\272\305\271?j\215\207}\355\366\325\277\316Y2\020\304`\237\277*\250\211\027d\246\337?\203\325\030j\225\200\321?\2464;\373\003\341\262\277j\253\006X\354\265\317\277\262\257\271\313\213\330\347?\346\326]^.\232\247\277\3551\265yi\360\270?\334\264K\311\002\234\302?\301\373\017\rgC\315?\302\226w\003F\263\275?\324\347z60T\252\277\030&d\222\360 \261\277i\214\236\212\014M\274?\216\345\030\220Pa\260?5\234pM\036\014\345\277\301\241\363\241\215e\327\2772z\252\207vq\267\277\234_\204J\221?\307\277\201\243\271\247\321\243\270\277" + } + } + } +} +node { + name: "filter_type_1/matrix_3_0/read" + op: "Identity" + input: "filter_type_1/matrix_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_3_0" + } + } + } +} +node { + name: "filter_type_1/concat_1/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat_1/axis" + input: "gradients/filter_type_1/concat_1_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_2/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\341\243\243(k\356\322?\030\3010\365m\377\331\277^\312\255\217\250y\354\277\233\333\316\037\266\032\322\277" + } + } + } +} +node { + name: "filter_type_1/bias_2_0/read" + op: "Identity" + input: "filter_type_1/bias_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_2_0" + } + } + } +} +node { + name: "filter_type_1/matrix_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\221}\350\203\261\221\263?|\024\373m\r\306\300\277\004\347\366D\327U\327\277\326\rH^\236\374\277\277!\316\2655\023J\347?\375\275\322\035\014\317\270\277\273\266|+\215\243\311?\2033\362\240-\027\345\277" + } + } + } +} +node { + name: "filter_type_1/matrix_2_0/read" + op: "Identity" + input: "filter_type_1/matrix_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_2_0" + } + } + } +} +node { + name: "filter_type_1/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/mod" + op: "FloorMod" + input: "filter_type_1/concat/axis" + input: "gradients/filter_type_1/concat_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_1/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_1/bias_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\304E\347rg6\310?9\327\337\346\n\000\332\277" + } + } + } +} +node { + name: "filter_type_1/bias_1_0/read" + op: "Identity" + input: "filter_type_1/bias_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/bias_1_0" + } + } + } +} +node { + name: "filter_type_1/matrix_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\202\022\302\306e\025\267?8\371\017Z|\366\302\277" + } + } + } +} +node { + name: "filter_type_1/matrix_1_0/read" + op: "Identity" + input: "filter_type_1/matrix_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_1/matrix_1_0" + } + } + } +} +node { + name: "filter_type_1/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377.\000\000\000" + } + } + } +} +node { + name: "filter_type_1/Slice/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Reshape" + op: "Reshape" + input: "filter_type_1/Slice/begin" + input: "gradients/filter_type_1/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_9/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\212\000\000\000" + } + } + } +} +node { + name: "Slice_1/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice_1/begin/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "mul_6/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 138 + } + } + } +} +node { + name: "strided_slice_9/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_9/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 4 + } + } + } +} +node { + name: "strided_slice_9/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "mul_5/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 138 + } + } + } +} +node { + name: "add/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 0 + } + } + } +} +node { + name: "strided_slice_8/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_8/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_8/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "mul_4/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 8 + } + } + } +} +node { + name: "strided_slice_7/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_7/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_7/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_6/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_6/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_6/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "filter_type_0/mul/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 0.2 + } + } + } +} +node { + name: "filter_type_0/Mean/reduction_indices" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/add" + op: "Add" + input: "filter_type_0/Mean/reduction_indices" + input: "gradients/filter_type_0/Mean_grad/Size" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/mod" + op: "FloorMod" + input: "gradients/filter_type_0/Mean_grad/add" + input: "gradients/filter_type_0/Mean_grad/Size" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } +} +node { + name: "filter_type_0/concat_6/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_6_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat_6/axis" + input: "gradients/filter_type_0/concat_6_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_9/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377\\\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/concat_5/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat_5/axis" + input: "gradients/filter_type_0/concat_5_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_8/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\331!K\213\207w\310?\010\276\335\237L\010\332\277\271\205\272$\311w\354\277Q\0052.u\201\310\277\321\032\222\333Yg\377?\230j\003mLQ\327\277&ij\220g\243\323?L\332\2225\320M\374\277" + } + } + } +} +node { + name: "filter_type_0/bias_3_1/read" + op: "Identity" + input: "filter_type_0/bias_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_3_1" + } + } + } +} +node { + name: "filter_type_0/matrix_3_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\031(\002l\311n\247?\372\331\201\317\033\374\300\277\223\270\2718n*\310\277\372\213\362N\273\330\262\277P:@\327x\352\337?\367Q\325\036\321m\274\277\302tk\351\"m\304?\214\204\222\021\317P\334\277\327b\260\312!b\315?\375\244\031\260^\346\304\277p\225i\347X\315\271?2\230\270\014+\375\325\277\352\226\246\213\027X\237\277\240\332\"\263\rV\335?\370\326\271%\361~\321?\2168\276$\202\330\262\277\225\327=\222w\343\317\277)/\234\304\254=\350?\340\305\225h\017\210\247\277\200\257\343\237\227\325\270?\345]L~\271\234\302?\233(\"\007\304\364\310?\242|;\205\177\256\275?`y\2462\263@\252\277\255\313n\242\\\347\265\277\226t}\336j\241\274?\215N\270?\221p\260?\232\367&J\213\020\345\277\204\244\274Z\245e\327\277k\370\222.i\314\277\277\227\346\307\204\235E\307\277\251\337\243\263\333\227\270\277" + } + } + } +} +node { + name: "filter_type_0/matrix_3_1/read" + op: "Identity" + input: "filter_type_0/matrix_3_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_3_1" + } + } + } +} +node { + name: "filter_type_0/concat_4/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat_4/axis" + input: "gradients/filter_type_0/concat_4_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_7/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\272\021\240\274\314\356\322?\377K\0227\240\001\332\277\324\214\334\352\333z\354\277,\251\000W\316\326\320\277" + } + } + } +} +node { + name: "filter_type_0/bias_2_1/read" + op: "Identity" + input: "filter_type_0/bias_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_2_1" + } + } + } +} +node { + name: "filter_type_0/matrix_2_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "Z\215\207r2\266\272?\355D(\234\t\200\302\277\236h\0166A\002\331\277O\'\212\206\311^\301\277\0363n\251,J\347?*0FS\247\263\270\277\223\023\341\324\203\252\311?\261\227\362\242F\224\345\277" + } + } + } +} +node { + name: "filter_type_0/matrix_2_1/read" + op: "Identity" + input: "filter_type_0/matrix_2_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_2_1" + } + } + } +} +node { + name: "filter_type_0/concat_3/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat_3/axis" + input: "gradients/filter_type_0/concat_3_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_6/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "N\362\000\re\020\311?\346\352\361\031\330\004\332\277" + } + } + } +} +node { + name: "filter_type_0/bias_1_1/read" + op: "Identity" + input: "filter_type_0/bias_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_1_1" + } + } + } +} +node { + name: "filter_type_0/matrix_1_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: ",\000\346\016\227\300\266?\237\251v2\353\354\302\277" + } + } + } +} +node { + name: "filter_type_0/matrix_1_1/read" + op: "Identity" + input: "filter_type_0/matrix_1_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_1_1" + } + } + } +} +node { + name: "filter_type_0/Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_1/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\\\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice_1/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000.\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Reshape" + op: "Reshape" + input: "filter_type_0/Slice_1/begin" + input: "gradients/filter_type_0/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_4/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 3 + } + } + tensor_content: "\377\377\377\377.\000\000\000\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/concat_2/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat_2/axis" + input: "gradients/filter_type_0/concat_2_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\010\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 8 + } + } + tensor_content: "\2456\257\225LZ\310?\211\031\320\021F\006\332\277\375S\200\237Gy\354\277\336\372\334\325\232\204\310\277\242I\246\033\344j\377?\366K\362 \rx\330\277\260+\257\316\022\241\323?\316\034\304\274\356P\374\277" + } + } + } +} +node { + name: "filter_type_0/bias_3_0/read" + op: "Identity" + input: "filter_type_0/bias_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_3_0" + } + } + } +} +node { + name: "filter_type_0/matrix_3_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 4 + } + dim { + size: 8 + } + } + tensor_content: "\013\262Z\331\305B\254?,!\262\347\203\024\304\277\360\307\256f\227\365\307\277Ee\315x\276\257\235\277\255>\324F.\311\337?\276\315nN\202\315\276\277(\014*3\203\323\303?\255\223\020e\3012\334\277,\265\310\340\275\366\316?bX\212\200\312\n\305\277u\363\3364\376\343\271?1\375\032t\024\377\325\277\300\215\271\234\225;\240\277\222\350X\344\000\356\334?\330/%A\262|\321?\314\267d\301\373\225\262\277\354\375\371\227\027\000\320\277\000\031S.\345\353\347?\020\355\222\3570=\247\277\244\031\255\320tp\271?\265f1\356\202r\302?\252Ez\340\262\311\307?\r\373\376\273\350\221\275?\373-34/\242\251\277J8wBuP\261\277U\256\205\036\032A\274?\363\0004\357Ip\260?3\337\203\366#\025\345\277qv\021\365\327v\327\277-\237\010\277I\027\301\277g\333,\201\264T\307\277W\024\036\255\'Y\270\277" + } + } + } +} +node { + name: "filter_type_0/matrix_3_0/read" + op: "Identity" + input: "filter_type_0/matrix_3_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_3_0" + } + } + } +} +node { + name: "filter_type_0/concat_1/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat_1/axis" + input: "gradients/filter_type_0/concat_1_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_2/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\004\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 4 + } + } + tensor_content: "\2062H4X\352\322?F\366\221\034\217\002\332\277F/\267\203\307z\354\277\352\315\302\242n\274\320\277" + } + } + } +} +node { + name: "filter_type_0/bias_2_0/read" + op: "Identity" + input: "filter_type_0/bias_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_2_0" + } + } + } +} +node { + name: "filter_type_0/matrix_2_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 4 + } + } + tensor_content: "\'\213\223\334\232\243\260?\246\005\017\254\372\254\304\277\203\327\374{\335\235\330\277\242i\216\263L\251\274\2774ra\267\021A\347?\004\375\3451L\342\270\277\025S\005\347_\244\311?\252\255\353\274\\\324\345\277" + } + } + } +} +node { + name: "filter_type_0/matrix_2_0/read" + op: "Identity" + input: "filter_type_0/matrix_2_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_2_0" + } + } + } +} +node { + name: "filter_type_0/concat/axis" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 1 + } + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/mod" + op: "FloorMod" + input: "filter_type_0/concat/axis" + input: "gradients/filter_type_0/concat_grad/Rank" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_1/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\002\000\000\000" + } + } + } +} +node { + name: "filter_type_0/bias_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "ZAK\341x\260\310?\227K9\034\032\013\332\277" + } + } + } +} +node { + name: "filter_type_0/bias_1_0/read" + op: "Identity" + input: "filter_type_0/bias_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/bias_1_0" + } + } + } +} +node { + name: "filter_type_0/matrix_1_0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 1 + } + dim { + size: 2 + } + } + tensor_content: "\004\316\275t\373\350\265?&\033\243\370\214!\310\277" + } + } + } +} +node { + name: "filter_type_0/matrix_1_0/read" + op: "Identity" + input: "filter_type_0/matrix_1_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@filter_type_0/matrix_1_0" + } + } + } +} +node { + name: "filter_type_0/Reshape/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\001\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice/size" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377.\000\000\000" + } + } + } +} +node { + name: "filter_type_0/Slice/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Reshape" + op: "Reshape" + input: "filter_type_0/Slice/begin" + input: "gradients/filter_type_0/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_7/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\212\000\000\000" + } + } + } +} +node { + name: "Slice/size/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "Slice/begin" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\000\000\000\000\000\000\000\000" + } + } + } +} +node { + name: "gradients/Slice_grad/Reshape" + op: "Reshape" + input: "Slice/begin" + input: "gradients/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_3/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 138 + } + } + } +} +node { + name: "strided_slice_5/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_5/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_5/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "Reshape_6/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_2/x" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 138 + } + } + } +} +node { + name: "strided_slice_4/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_4/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_4/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 0 + } + } + } +} +node { + name: "Reshape_5/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\212\000\000\000" + } + } + } +} +node { + name: "Reshape_4/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "strided_slice_3/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_3/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_3/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "Reshape_3/shape" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 2 + } + } + tensor_content: "\377\377\377\377\t\000\000\000" + } + } + } +} +node { + name: "Reshape_2/shape/0" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: -1 + } + } + } +} +node { + name: "mul_1/y" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 3 + } + } + } +} +node { + name: "strided_slice_2/stack_2" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "strided_slice_2/stack_1" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 2 + } + } + } +} +node { + name: "strided_slice_2/stack" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + dim { + size: 1 + } + } + int_val: 1 + } + } + } +} +node { + name: "descrpt_attr/t_std" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 138 + } + } + tensor_content: "\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\024\314\2718\254\216\302?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?\031\025\322j\032\270\300?" + } + } + } +} +node { + name: "descrpt_attr/t_std/read" + op: "Identity" + input: "descrpt_attr/t_std" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@descrpt_attr/t_std" + } + } + } +} +node { + name: "descrpt_attr/t_avg" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + dim { + size: 2 + } + dim { + size: 138 + } + } + tensor_content: "\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\024[\204\335\351\375\254?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?\331\272\014\265\n\355\253?" + } + } + } +} +node { + name: "descrpt_attr/t_avg/read" + op: "Identity" + input: "descrpt_attr/t_avg" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@descrpt_attr/t_avg" + } + } + } +} +node { + name: "descrpt_attr/ntypes" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + int_val: 2 + } + } + } +} +node { + name: "descrpt_attr/rcut" + op: "Const" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_DOUBLE + tensor_shape { + } + double_val: 6.0 + } + } + } +} +node { + name: "model_attr/model_type" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "ener" + } + } + } +} +node { + name: "model_attr/tmap" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "O H" + } + } + } +} +node { + name: "t_mesh" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "t_natoms" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: 4 + } + } + } + } +} +node { + name: "strided_slice_25" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_25/stack" + input: "strided_slice_25/stack_1" + input: "strided_slice_25/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_14" + op: "Mul" + input: "mul_14/x" + input: "strided_slice_25" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "o_atom_virial/shape" + op: "Pack" + input: "o_atom_virial/shape/0" + input: "mul_14" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_24" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_24/stack" + input: "strided_slice_24/stack_1" + input: "strided_slice_24/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_13" + op: "Mul" + input: "mul_13/x" + input: "strided_slice_24" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "o_force/shape" + op: "Pack" + input: "o_force/shape/0" + input: "mul_13" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_23" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_23/stack" + input: "strided_slice_23/stack_1" + input: "strided_slice_23/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_12" + op: "Mul" + input: "strided_slice_23" + input: "mul_12/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_17/shape" + op: "Pack" + input: "Reshape_17/shape/0" + input: "mul_12" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_22" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_22/stack" + input: "strided_slice_22/stack_1" + input: "strided_slice_22/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "o_atom_energy/shape" + op: "Pack" + input: "o_atom_energy/shape/0" + input: "strided_slice_22" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_21" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_21/stack" + input: "strided_slice_21/stack_1" + input: "strided_slice_21/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_18" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_18/stack" + input: "strided_slice_18/stack_1" + input: "strided_slice_18/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_11" + op: "Mul" + input: "strided_slice_18" + input: "mul_11/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_3/size" + op: "Pack" + input: "Slice_3/size/0" + input: "mul_11" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_17" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_17/stack" + input: "strided_slice_17/stack_1" + input: "strided_slice_17/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "strided_slice_15" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_15/stack" + input: "strided_slice_15/stack_1" + input: "strided_slice_15/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "add_2" + op: "Add" + input: "add_2/x" + input: "strided_slice_15" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_10" + op: "Mul" + input: "add_2" + input: "mul_10/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_3/begin" + op: "Pack" + input: "Slice_3/begin/0" + input: "mul_10" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/Slice_3_grad/Reshape" + op: "Reshape" + input: "Slice_3/begin" + input: "gradients/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_14" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_14/stack" + input: "strided_slice_14/stack_1" + input: "strided_slice_14/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_9" + op: "Mul" + input: "strided_slice_14" + input: "mul_9/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_2/size" + op: "Pack" + input: "Slice_2/size/0" + input: "mul_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_13" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_13/stack" + input: "strided_slice_13/stack_1" + input: "strided_slice_13/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_8" + op: "Mul" + input: "mul_8/x" + input: "strided_slice_13" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_11/shape" + op: "Pack" + input: "Reshape_11/shape/0" + input: "mul_8" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_11" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_11/stack" + input: "strided_slice_11/stack_1" + input: "strided_slice_11/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_7" + op: "Mul" + input: "strided_slice_11" + input: "mul_7/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_9" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_9/stack" + input: "strided_slice_9/stack_1" + input: "strided_slice_9/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_6" + op: "Mul" + input: "strided_slice_9" + input: "mul_6/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_1/size" + op: "Pack" + input: "Slice_1/size/0" + input: "mul_6" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_8" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_8/stack" + input: "strided_slice_8/stack_1" + input: "strided_slice_8/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "add" + op: "Add" + input: "add/x" + input: "strided_slice_8" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "mul_5" + op: "Mul" + input: "add" + input: "mul_5/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice_1/begin" + op: "Pack" + input: "Slice_1/begin/0" + input: "mul_5" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "gradients/Slice_1_grad/Reshape" + op: "Reshape" + input: "Slice_1/begin" + input: "gradients/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_7" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_7/stack" + input: "strided_slice_7/stack_1" + input: "strided_slice_7/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_4" + op: "Mul" + input: "strided_slice_7" + input: "mul_4/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_5" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_5/stack" + input: "strided_slice_5/stack_1" + input: "strided_slice_5/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_3" + op: "Mul" + input: "strided_slice_5" + input: "mul_3/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Slice/size" + op: "Pack" + input: "Slice/size/0" + input: "mul_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_4" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_4/stack" + input: "strided_slice_4/stack_1" + input: "strided_slice_4/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_2" + op: "Mul" + input: "mul_2/x" + input: "strided_slice_4" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_6/shape" + op: "Pack" + input: "Reshape_6/shape/0" + input: "mul_2" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_3" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_3/stack" + input: "strided_slice_3/stack_1" + input: "strided_slice_3/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_4/shape" + op: "Pack" + input: "Reshape_4/shape/0" + input: "strided_slice_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "strided_slice_2" + op: "StridedSlice" + input: "t_natoms" + input: "strided_slice_2/stack" + input: "strided_slice_2/stack_1" + input: "strided_slice_2/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "mul_1" + op: "Mul" + input: "strided_slice_2" + input: "mul_1/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_2/shape" + op: "Pack" + input: "Reshape_2/shape/0" + input: "mul_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "t_type" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_4" + op: "Reshape" + input: "t_type" + input: "Reshape_4/shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "t_coord" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_2" + op: "Reshape" + input: "t_coord" + input: "Reshape_2/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "t_box" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_DOUBLE + } + } + attr { + key: "shape" + value { + shape { + dim { + size: -1 + } + } + } + } +} +node { + name: "Reshape_3" + op: "Reshape" + input: "t_box" + input: "Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "ProdEnvMatR" + op: "ProdEnvMatR" + input: "Reshape_2" + input: "Reshape_4" + input: "t_natoms" + input: "Reshape_3" + input: "t_mesh" + input: "descrpt_attr/t_avg/read" + input: "descrpt_attr/t_std/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "rcut" + value { + f: 6.0 + } + } + attr { + key: "rcut_smth" + value { + f: 1.0 + } + } + attr { + key: "sel" + value { + list { + i: 46 + i: 92 + } + } + } +} +node { + name: "o_nlist" + op: "Identity" + input: "ProdEnvMatR:3" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "o_rij" + op: "Identity" + input: "ProdEnvMatR:2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "o_rmat_deriv" + op: "Identity" + input: "ProdEnvMatR:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "Reshape_5" + op: "Reshape" + input: "ProdEnvMatR" + input: "Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_rmat" + op: "Identity" + input: "Reshape_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_6_grad/Shape" + op: "Shape" + input: "o_rmat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_6" + op: "Reshape" + input: "o_rmat" + input: "Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/Shape_1" + op: "Shape" + input: "Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/Shape_1" + op: "Shape" + input: "Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_1" + op: "Shape" + input: "Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_10" + op: "StridedSlice" + input: "Shape_1" + input: "strided_slice_10/stack" + input: "strided_slice_10/stack_1" + input: "strided_slice_10/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_10/shape" + op: "Pack" + input: "strided_slice_10" + input: "mul_7" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_1" + op: "Slice" + input: "Reshape_6" + input: "Slice_1/begin" + input: "Slice_1/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Slice_1_grad/Shape" + op: "Shape" + input: "Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/sub" + op: "Sub" + input: "gradients/Slice_1_grad/Shape_1" + input: "gradients/Slice_1_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/sub_1" + op: "Sub" + input: "gradients/Slice_1_grad/sub" + input: "Slice_1/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/Slice_1_grad/sub_1" + input: "gradients/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/concat" + op: "ConcatV2" + input: "gradients/Slice_1_grad/Reshape" + input: "gradients/Slice_1_grad/Reshape_1" + input: "gradients/Slice_1_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_9_grad/Shape" + op: "Shape" + input: "Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_9" + op: "Reshape" + input: "Slice_1" + input: "Reshape_9/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Shape_1" + op: "Shape" + input: "Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Shape_1" + op: "Shape" + input: "Reshape_9" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Slice_1" + op: "Slice" + input: "Reshape_9" + input: "filter_type_1/Slice_1/begin" + input: "filter_type_1/Slice_1/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/sub" + op: "Sub" + input: "gradients/filter_type_1/Slice_1_grad/Shape_1" + input: "gradients/filter_type_1/Slice_1_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_1/Slice_1_grad/sub" + input: "filter_type_1/Slice_1/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/Slice_1_grad/sub_1" + input: "gradients/filter_type_1/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_1/Slice_1_grad/Reshape" + input: "gradients/filter_type_1/Slice_1_grad/Reshape_1" + input: "gradients/filter_type_1/Slice_1_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_5_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_5" + op: "Reshape" + input: "filter_type_1/Slice_1" + input: "filter_type_1/Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/Reshape_5" + input: "filter_type_1/Reshape_5" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_3_grad/mod" + input: "gradients/filter_type_1/concat_3_grad/ShapeN" + input: "gradients/filter_type_1/concat_3_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_3" + op: "ConcatV2" + input: "filter_type_1/Reshape_5" + input: "filter_type_1/Reshape_5" + input: "filter_type_1/concat_3/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_3" + op: "MatMul" + input: "filter_type_1/Reshape_5" + input: "filter_type_1/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_6_grad/Shape" + input: "gradients/filter_type_1/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_6" + op: "Add" + input: "filter_type_1/MatMul_3" + input: "filter_type_1/bias_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_3" + op: "Tanh" + input: "filter_type_1/add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_6_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_6" + op: "Reshape" + input: "filter_type_1/Tanh_3" + input: "filter_type_1/Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_7_grad/Shape" + input: "gradients/filter_type_1/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_7" + op: "Add" + input: "filter_type_1/concat_3" + input: "filter_type_1/Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/add_7" + input: "filter_type_1/add_7" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_4_grad/mod" + input: "gradients/filter_type_1/concat_4_grad/ShapeN" + input: "gradients/filter_type_1/concat_4_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_4" + op: "ConcatV2" + input: "filter_type_1/add_7" + input: "filter_type_1/add_7" + input: "filter_type_1/concat_4/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_4" + op: "MatMul" + input: "filter_type_1/add_7" + input: "filter_type_1/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_8_grad/Shape" + input: "gradients/filter_type_1/add_8_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_8" + op: "Add" + input: "filter_type_1/MatMul_4" + input: "filter_type_1/bias_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_4" + op: "Tanh" + input: "filter_type_1/add_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_7_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_7" + op: "Reshape" + input: "filter_type_1/Tanh_4" + input: "filter_type_1/Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_9_grad/Shape" + input: "gradients/filter_type_1/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_9" + op: "Add" + input: "filter_type_1/concat_4" + input: "filter_type_1/Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/add_9" + input: "filter_type_1/add_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_5_grad/mod" + input: "gradients/filter_type_1/concat_5_grad/ShapeN" + input: "gradients/filter_type_1/concat_5_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_5" + op: "ConcatV2" + input: "filter_type_1/add_9" + input: "filter_type_1/add_9" + input: "filter_type_1/concat_5/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_5" + op: "MatMul" + input: "filter_type_1/add_9" + input: "filter_type_1/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_10_grad/Shape" + input: "gradients/filter_type_1/add_10_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_10" + op: "Add" + input: "filter_type_1/MatMul_5" + input: "filter_type_1/bias_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_5" + op: "Tanh" + input: "filter_type_1/add_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_8_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_8" + op: "Reshape" + input: "filter_type_1/Tanh_5" + input: "filter_type_1/Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_11_grad/Shape" + input: "gradients/filter_type_1/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_11" + op: "Add" + input: "filter_type_1/concat_5" + input: "filter_type_1/Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_9_grad/Shape" + op: "Shape" + input: "filter_type_1/add_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_9" + op: "Reshape" + input: "filter_type_1/add_11" + input: "filter_type_1/Reshape_9/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Slice" + op: "Slice" + input: "Reshape_9" + input: "filter_type_1/Slice/begin" + input: "filter_type_1/Slice/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/sub" + op: "Sub" + input: "gradients/filter_type_1/Slice_grad/Shape_1" + input: "gradients/filter_type_1/Slice_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_1/Slice_grad/sub" + input: "filter_type_1/Slice/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/Slice_grad/sub_1" + input: "gradients/filter_type_1/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_1/Slice_grad/Reshape" + input: "gradients/filter_type_1/Slice_grad/Reshape_1" + input: "gradients/filter_type_1/Slice_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_grad/Shape" + op: "Shape" + input: "filter_type_1/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape" + op: "Reshape" + input: "filter_type_1/Slice" + input: "filter_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/Reshape" + input: "filter_type_1/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_grad/mod" + input: "gradients/filter_type_1/concat_grad/ShapeN" + input: "gradients/filter_type_1/concat_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat" + op: "ConcatV2" + input: "filter_type_1/Reshape" + input: "filter_type_1/Reshape" + input: "filter_type_1/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Shape" + op: "Shape" + input: "filter_type_1/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul" + op: "MatMul" + input: "filter_type_1/Reshape" + input: "filter_type_1/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_grad/Shape" + input: "gradients/filter_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add" + op: "Add" + input: "filter_type_1/MatMul" + input: "filter_type_1/bias_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh" + op: "Tanh" + input: "filter_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_1_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_1" + op: "Reshape" + input: "filter_type_1/Tanh" + input: "filter_type_1/Reshape_1/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_1_grad/Shape" + input: "gradients/filter_type_1/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_1" + op: "Add" + input: "filter_type_1/concat" + input: "filter_type_1/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/add_1" + input: "filter_type_1/add_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_1_grad/mod" + input: "gradients/filter_type_1/concat_1_grad/ShapeN" + input: "gradients/filter_type_1/concat_1_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_1" + op: "ConcatV2" + input: "filter_type_1/add_1" + input: "filter_type_1/add_1" + input: "filter_type_1/concat_1/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_1" + op: "MatMul" + input: "filter_type_1/add_1" + input: "filter_type_1/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_2_grad/Shape" + input: "gradients/filter_type_1/add_2_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_2" + op: "Add" + input: "filter_type_1/MatMul_1" + input: "filter_type_1/bias_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_1" + op: "Tanh" + input: "filter_type_1/add_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_2_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_2" + op: "Reshape" + input: "filter_type_1/Tanh_1" + input: "filter_type_1/Reshape_2/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_3_grad/Shape" + input: "gradients/filter_type_1/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_3" + op: "Add" + input: "filter_type_1/concat_1" + input: "filter_type_1/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/add_3" + input: "filter_type_1/add_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_2_grad/mod" + input: "gradients/filter_type_1/concat_2_grad/ShapeN" + input: "gradients/filter_type_1/concat_2_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_2" + op: "ConcatV2" + input: "filter_type_1/add_3" + input: "filter_type_1/add_3" + input: "filter_type_1/concat_2/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/MatMul_2" + op: "MatMul" + input: "filter_type_1/add_3" + input: "filter_type_1/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/Shape" + op: "Shape" + input: "filter_type_1/MatMul_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_4_grad/Shape" + input: "gradients/filter_type_1/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_4" + op: "Add" + input: "filter_type_1/MatMul_2" + input: "filter_type_1/bias_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_1/Tanh_2" + op: "Tanh" + input: "filter_type_1/add_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_3_grad/Shape" + op: "Shape" + input: "filter_type_1/Tanh_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_3" + op: "Reshape" + input: "filter_type_1/Tanh_2" + input: "filter_type_1/Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Shape_1" + op: "Shape" + input: "filter_type_1/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/add_5_grad/Shape" + input: "gradients/filter_type_1/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/add_5" + op: "Add" + input: "filter_type_1/concat_2" + input: "filter_type_1/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_4_grad/Shape" + op: "Shape" + input: "filter_type_1/add_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/Reshape_4" + op: "Reshape" + input: "filter_type_1/add_5" + input: "filter_type_1/Reshape_4/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_6_grad/ShapeN" + op: "ShapeN" + input: "filter_type_1/Reshape_4" + input: "filter_type_1/Reshape_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_6_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_1/concat_6_grad/mod" + input: "gradients/filter_type_1/concat_6_grad/ShapeN" + input: "gradients/filter_type_1/concat_6_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_1/concat_6" + op: "ConcatV2" + input: "filter_type_1/Reshape_4" + input: "filter_type_1/Reshape_9" + input: "filter_type_1/concat_6/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Shape_2" + op: "Shape" + input: "filter_type_1/concat_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Prod" + op: "Prod" + input: "gradients/filter_type_1/Mean_grad/Shape_2" + input: "gradients/filter_type_1/Mean_grad/Const" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Shape" + op: "Shape" + input: "filter_type_1/concat_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/DynamicStitch" + op: "DynamicStitch" + input: "gradients/filter_type_1/Mean_grad/range" + input: "gradients/filter_type_1/Mean_grad/mod" + input: "gradients/filter_type_1/Mean_grad/Shape" + input: "gradients/filter_type_1/Mean_grad/Fill" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Maximum" + op: "Maximum" + input: "gradients/filter_type_1/Mean_grad/DynamicStitch" + input: "gradients/filter_type_1/Mean_grad/Maximum/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/floordiv" + op: "FloorDiv" + input: "gradients/filter_type_1/Mean_grad/Shape" + input: "gradients/filter_type_1/Mean_grad/Maximum" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Mean_grad/Shape" + } + } + } +} +node { + name: "filter_type_1/Mean" + op: "Mean" + input: "filter_type_1/concat_6" + input: "filter_type_1/Mean/reduction_indices" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Shape_3" + op: "Shape" + input: "filter_type_1/Mean" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Prod_1" + op: "Prod" + input: "gradients/filter_type_1/Mean_grad/Shape_3" + input: "gradients/filter_type_1/Mean_grad/Const_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Maximum_1" + op: "Maximum" + input: "gradients/filter_type_1/Mean_grad/Prod_1" + input: "gradients/filter_type_1/Mean_grad/Maximum_1/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/floordiv_1" + op: "FloorDiv" + input: "gradients/filter_type_1/Mean_grad/Prod" + input: "gradients/filter_type_1/Mean_grad/Maximum_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Cast" + op: "Cast" + input: "gradients/filter_type_1/Mean_grad/floordiv_1" + attr { + key: "DstT" + value { + type: DT_DOUBLE + } + } + attr { + key: "SrcT" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Shape" + op: "Shape" + input: "filter_type_1/Mean" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_1/mul_grad/Shape" + input: "gradients/filter_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_1/mul" + op: "Mul" + input: "filter_type_1/Mean" + input: "filter_type_1/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_10_grad/Shape" + op: "Shape" + input: "filter_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_10" + op: "Reshape" + input: "filter_type_1/mul" + input: "Reshape_10/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape" + op: "Shape" + input: "Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_6" + op: "StridedSlice" + input: "Shape" + input: "strided_slice_6/stack" + input: "strided_slice_6/stack_1" + input: "strided_slice_6/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_8/shape" + op: "Pack" + input: "strided_slice_6" + input: "mul_4" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice" + op: "Slice" + input: "Reshape_6" + input: "Slice/begin" + input: "Slice/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Slice_grad/Shape" + op: "Shape" + input: "Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/sub" + op: "Sub" + input: "gradients/Slice_grad/Shape_1" + input: "gradients/Slice_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/sub_1" + op: "Sub" + input: "gradients/Slice_grad/sub" + input: "Slice/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/Reshape_1" + op: "Reshape" + input: "gradients/Slice_grad/sub_1" + input: "gradients/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/concat" + op: "ConcatV2" + input: "gradients/Slice_grad/Reshape" + input: "gradients/Slice_grad/Reshape_1" + input: "gradients/Slice_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_7_grad/Shape" + op: "Shape" + input: "Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_7" + op: "Reshape" + input: "Slice" + input: "Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Shape_1" + op: "Shape" + input: "Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Shape_1" + op: "Shape" + input: "Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Slice_1" + op: "Slice" + input: "Reshape_7" + input: "filter_type_0/Slice_1/begin" + input: "filter_type_0/Slice_1/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/sub" + op: "Sub" + input: "gradients/filter_type_0/Slice_1_grad/Shape_1" + input: "gradients/filter_type_0/Slice_1_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_0/Slice_1_grad/sub" + input: "filter_type_0/Slice_1/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/Slice_1_grad/sub_1" + input: "gradients/filter_type_0/Slice_1_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_0/Slice_1_grad/Reshape" + input: "gradients/filter_type_0/Slice_1_grad/Reshape_1" + input: "gradients/filter_type_0/Slice_1_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_5_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_5" + op: "Reshape" + input: "filter_type_0/Slice_1" + input: "filter_type_0/Reshape_5/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/Reshape_5" + input: "filter_type_0/Reshape_5" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_3_grad/mod" + input: "gradients/filter_type_0/concat_3_grad/ShapeN" + input: "gradients/filter_type_0/concat_3_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_3" + op: "ConcatV2" + input: "filter_type_0/Reshape_5" + input: "filter_type_0/Reshape_5" + input: "filter_type_0/concat_3/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_3" + op: "MatMul" + input: "filter_type_0/Reshape_5" + input: "filter_type_0/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_6_grad/Shape" + input: "gradients/filter_type_0/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_6" + op: "Add" + input: "filter_type_0/MatMul_3" + input: "filter_type_0/bias_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_3" + op: "Tanh" + input: "filter_type_0/add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_6_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_6" + op: "Reshape" + input: "filter_type_0/Tanh_3" + input: "filter_type_0/Reshape_6/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_7_grad/Shape" + input: "gradients/filter_type_0/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_7" + op: "Add" + input: "filter_type_0/concat_3" + input: "filter_type_0/Reshape_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/add_7" + input: "filter_type_0/add_7" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_4_grad/mod" + input: "gradients/filter_type_0/concat_4_grad/ShapeN" + input: "gradients/filter_type_0/concat_4_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_4" + op: "ConcatV2" + input: "filter_type_0/add_7" + input: "filter_type_0/add_7" + input: "filter_type_0/concat_4/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_4" + op: "MatMul" + input: "filter_type_0/add_7" + input: "filter_type_0/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_8_grad/Shape" + input: "gradients/filter_type_0/add_8_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_8" + op: "Add" + input: "filter_type_0/MatMul_4" + input: "filter_type_0/bias_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_4" + op: "Tanh" + input: "filter_type_0/add_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_7_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_7" + op: "Reshape" + input: "filter_type_0/Tanh_4" + input: "filter_type_0/Reshape_7/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_9_grad/Shape" + input: "gradients/filter_type_0/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_9" + op: "Add" + input: "filter_type_0/concat_4" + input: "filter_type_0/Reshape_7" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/add_9" + input: "filter_type_0/add_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_5_grad/mod" + input: "gradients/filter_type_0/concat_5_grad/ShapeN" + input: "gradients/filter_type_0/concat_5_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_5" + op: "ConcatV2" + input: "filter_type_0/add_9" + input: "filter_type_0/add_9" + input: "filter_type_0/concat_5/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_5" + op: "MatMul" + input: "filter_type_0/add_9" + input: "filter_type_0/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_10_grad/Shape" + input: "gradients/filter_type_0/add_10_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_10" + op: "Add" + input: "filter_type_0/MatMul_5" + input: "filter_type_0/bias_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_5" + op: "Tanh" + input: "filter_type_0/add_10" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_8_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_8" + op: "Reshape" + input: "filter_type_0/Tanh_5" + input: "filter_type_0/Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_11_grad/Shape" + input: "gradients/filter_type_0/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_11" + op: "Add" + input: "filter_type_0/concat_5" + input: "filter_type_0/Reshape_8" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_9_grad/Shape" + op: "Shape" + input: "filter_type_0/add_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_9" + op: "Reshape" + input: "filter_type_0/add_11" + input: "filter_type_0/Reshape_9/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Slice" + op: "Slice" + input: "Reshape_7" + input: "filter_type_0/Slice/begin" + input: "filter_type_0/Slice/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/sub" + op: "Sub" + input: "gradients/filter_type_0/Slice_grad/Shape_1" + input: "gradients/filter_type_0/Slice_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/sub_1" + op: "Sub" + input: "gradients/filter_type_0/Slice_grad/sub" + input: "filter_type_0/Slice/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/Slice_grad/sub_1" + input: "gradients/filter_type_0/Slice_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/concat" + op: "ConcatV2" + input: "gradients/filter_type_0/Slice_grad/Reshape" + input: "gradients/filter_type_0/Slice_grad/Reshape_1" + input: "gradients/filter_type_0/Slice_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_grad/Shape" + op: "Shape" + input: "filter_type_0/Slice" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape" + op: "Reshape" + input: "filter_type_0/Slice" + input: "filter_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/Reshape" + input: "filter_type_0/Reshape" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_grad/mod" + input: "gradients/filter_type_0/concat_grad/ShapeN" + input: "gradients/filter_type_0/concat_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat" + op: "ConcatV2" + input: "filter_type_0/Reshape" + input: "filter_type_0/Reshape" + input: "filter_type_0/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Shape" + op: "Shape" + input: "filter_type_0/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul" + op: "MatMul" + input: "filter_type_0/Reshape" + input: "filter_type_0/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_grad/Shape" + input: "gradients/filter_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add" + op: "Add" + input: "filter_type_0/MatMul" + input: "filter_type_0/bias_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh" + op: "Tanh" + input: "filter_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_1_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_1" + op: "Reshape" + input: "filter_type_0/Tanh" + input: "filter_type_0/Reshape_1/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_1_grad/Shape" + input: "gradients/filter_type_0/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_1" + op: "Add" + input: "filter_type_0/concat" + input: "filter_type_0/Reshape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/add_1" + input: "filter_type_0/add_1" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_1_grad/mod" + input: "gradients/filter_type_0/concat_1_grad/ShapeN" + input: "gradients/filter_type_0/concat_1_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_1" + op: "ConcatV2" + input: "filter_type_0/add_1" + input: "filter_type_0/add_1" + input: "filter_type_0/concat_1/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_1" + op: "MatMul" + input: "filter_type_0/add_1" + input: "filter_type_0/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_2_grad/Shape" + input: "gradients/filter_type_0/add_2_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_2" + op: "Add" + input: "filter_type_0/MatMul_1" + input: "filter_type_0/bias_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_1" + op: "Tanh" + input: "filter_type_0/add_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_2_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_2" + op: "Reshape" + input: "filter_type_0/Tanh_1" + input: "filter_type_0/Reshape_2/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_3_grad/Shape" + input: "gradients/filter_type_0/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_3" + op: "Add" + input: "filter_type_0/concat_1" + input: "filter_type_0/Reshape_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/add_3" + input: "filter_type_0/add_3" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_2_grad/mod" + input: "gradients/filter_type_0/concat_2_grad/ShapeN" + input: "gradients/filter_type_0/concat_2_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_2" + op: "ConcatV2" + input: "filter_type_0/add_3" + input: "filter_type_0/add_3" + input: "filter_type_0/concat_2/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/MatMul_2" + op: "MatMul" + input: "filter_type_0/add_3" + input: "filter_type_0/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/Shape" + op: "Shape" + input: "filter_type_0/MatMul_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_4_grad/Shape" + input: "gradients/filter_type_0/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_4" + op: "Add" + input: "filter_type_0/MatMul_2" + input: "filter_type_0/bias_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "filter_type_0/Tanh_2" + op: "Tanh" + input: "filter_type_0/add_4" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_3_grad/Shape" + op: "Shape" + input: "filter_type_0/Tanh_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_3" + op: "Reshape" + input: "filter_type_0/Tanh_2" + input: "filter_type_0/Reshape_3/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Shape_1" + op: "Shape" + input: "filter_type_0/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/add_5_grad/Shape" + input: "gradients/filter_type_0/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/add_5" + op: "Add" + input: "filter_type_0/concat_2" + input: "filter_type_0/Reshape_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_4_grad/Shape" + op: "Shape" + input: "filter_type_0/add_5" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/Reshape_4" + op: "Reshape" + input: "filter_type_0/add_5" + input: "filter_type_0/Reshape_4/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_6_grad/ShapeN" + op: "ShapeN" + input: "filter_type_0/Reshape_4" + input: "filter_type_0/Reshape_9" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_6_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/filter_type_0/concat_6_grad/mod" + input: "gradients/filter_type_0/concat_6_grad/ShapeN" + input: "gradients/filter_type_0/concat_6_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "filter_type_0/concat_6" + op: "ConcatV2" + input: "filter_type_0/Reshape_4" + input: "filter_type_0/Reshape_9" + input: "filter_type_0/concat_6/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Shape_2" + op: "Shape" + input: "filter_type_0/concat_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Prod" + op: "Prod" + input: "gradients/filter_type_0/Mean_grad/Shape_2" + input: "gradients/filter_type_0/Mean_grad/Const" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Shape" + op: "Shape" + input: "filter_type_0/concat_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/DynamicStitch" + op: "DynamicStitch" + input: "gradients/filter_type_0/Mean_grad/range" + input: "gradients/filter_type_0/Mean_grad/mod" + input: "gradients/filter_type_0/Mean_grad/Shape" + input: "gradients/filter_type_0/Mean_grad/Fill" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Maximum" + op: "Maximum" + input: "gradients/filter_type_0/Mean_grad/DynamicStitch" + input: "gradients/filter_type_0/Mean_grad/Maximum/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/floordiv" + op: "FloorDiv" + input: "gradients/filter_type_0/Mean_grad/Shape" + input: "gradients/filter_type_0/Mean_grad/Maximum" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Mean_grad/Shape" + } + } + } +} +node { + name: "filter_type_0/Mean" + op: "Mean" + input: "filter_type_0/concat_6" + input: "filter_type_0/Mean/reduction_indices" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Shape_3" + op: "Shape" + input: "filter_type_0/Mean" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Prod_1" + op: "Prod" + input: "gradients/filter_type_0/Mean_grad/Shape_3" + input: "gradients/filter_type_0/Mean_grad/Const_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Maximum_1" + op: "Maximum" + input: "gradients/filter_type_0/Mean_grad/Prod_1" + input: "gradients/filter_type_0/Mean_grad/Maximum_1/y" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/floordiv_1" + op: "FloorDiv" + input: "gradients/filter_type_0/Mean_grad/Prod" + input: "gradients/filter_type_0/Mean_grad/Maximum_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Cast" + op: "Cast" + input: "gradients/filter_type_0/Mean_grad/floordiv_1" + attr { + key: "DstT" + value { + type: DT_DOUBLE + } + } + attr { + key: "SrcT" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Shape" + op: "Shape" + input: "filter_type_0/Mean" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/filter_type_0/mul_grad/Shape" + input: "gradients/filter_type_0/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "filter_type_0/mul" + op: "Mul" + input: "filter_type_0/Mean" + input: "filter_type_0/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_8_grad/Shape" + op: "Shape" + input: "filter_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_8" + op: "Reshape" + input: "filter_type_0/mul" + input: "Reshape_8/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/ShapeN" + op: "ShapeN" + input: "Reshape_8" + input: "Reshape_10" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/concat_grad/mod" + input: "gradients/concat_grad/ShapeN" + input: "gradients/concat_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "concat" + op: "ConcatV2" + input: "Reshape_8" + input: "Reshape_10" + input: "concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "o_descriptor" + op: "Identity" + input: "concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_11_grad/Shape" + op: "Shape" + input: "o_descriptor" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_11" + op: "Reshape" + input: "o_descriptor" + input: "Reshape_11/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/Shape_1" + op: "Shape" + input: "Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/Shape_1" + op: "Shape" + input: "Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_3" + op: "Shape" + input: "Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_20" + op: "StridedSlice" + input: "Shape_3" + input: "strided_slice_20/stack" + input: "strided_slice_20/stack_1" + input: "strided_slice_20/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_15/shape" + op: "Pack" + input: "strided_slice_20" + input: "strided_slice_21" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_3" + op: "Slice" + input: "Reshape_11" + input: "Slice_3/begin" + input: "Slice_3/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Slice_3_grad/Shape" + op: "Shape" + input: "Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/sub" + op: "Sub" + input: "gradients/Slice_3_grad/Shape_1" + input: "gradients/Slice_3_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/sub_1" + op: "Sub" + input: "gradients/Slice_3_grad/sub" + input: "Slice_3/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/Slice_3_grad/sub_1" + input: "gradients/Slice_3_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/concat" + op: "ConcatV2" + input: "gradients/Slice_3_grad/Reshape" + input: "gradients/Slice_3_grad/Reshape_1" + input: "gradients/Slice_3_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_14_grad/Shape" + op: "Shape" + input: "Slice_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_14" + op: "Reshape" + input: "Slice_3" + input: "Reshape_14/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_1/MatMul" + op: "MatMul" + input: "Reshape_14" + input: "layer_0_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/Shape" + op: "Shape" + input: "layer_0_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_0_type_1/add_grad/Shape" + input: "gradients/layer_0_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_1/add" + op: "Add" + input: "layer_0_type_1/MatMul" + input: "layer_0_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_0_type_1/Tanh" + op: "Tanh" + input: "layer_0_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_0_type_1/Reshape_grad/Shape" + op: "Shape" + input: "layer_0_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_1/Reshape" + op: "Reshape" + input: "layer_0_type_1/Tanh" + input: "layer_0_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_6_grad/Shape" + op: "Shape" + input: "layer_0_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/MatMul" + op: "MatMul" + input: "layer_0_type_1/Reshape" + input: "layer_1_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/Shape" + op: "Shape" + input: "layer_1_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_1_type_1/add_grad/Shape" + input: "gradients/layer_1_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/add" + op: "Add" + input: "layer_1_type_1/MatMul" + input: "layer_1_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_1_type_1/Tanh" + op: "Tanh" + input: "layer_1_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_1/Reshape_grad/Shape" + op: "Shape" + input: "layer_1_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/Reshape" + op: "Reshape" + input: "layer_1_type_1/Tanh" + input: "layer_1_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Shape" + op: "Shape" + input: "layer_1_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_1_type_1/mul_grad/Shape" + input: "gradients/layer_1_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_1/mul" + op: "Mul" + input: "layer_1_type_1/Reshape" + input: "layer_1_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_6_grad/Shape_1" + op: "Shape" + input: "layer_1_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_6_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/add_6_grad/Shape" + input: "gradients/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_6" + op: "Add" + input: "layer_0_type_1/Reshape" + input: "layer_1_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_7_grad/Shape" + op: "Shape" + input: "add_6" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/MatMul" + op: "MatMul" + input: "add_6" + input: "layer_2_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/Shape" + op: "Shape" + input: "layer_2_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_2_type_1/add_grad/Shape" + input: "gradients/layer_2_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/add" + op: "Add" + input: "layer_2_type_1/MatMul" + input: "layer_2_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_1/Tanh" + op: "Tanh" + input: "layer_2_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_1/Reshape_grad/Shape" + op: "Shape" + input: "layer_2_type_1/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/Reshape" + op: "Reshape" + input: "layer_2_type_1/Tanh" + input: "layer_2_type_1/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Shape" + op: "Shape" + input: "layer_2_type_1/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_2_type_1/mul_grad/Shape" + input: "gradients/layer_2_type_1/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_1/mul" + op: "Mul" + input: "layer_2_type_1/Reshape" + input: "layer_2_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_7_grad/Shape_1" + op: "Shape" + input: "layer_2_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_7_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/add_7_grad/Shape" + input: "gradients/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_7" + op: "Add" + input: "add_6" + input: "layer_2_type_1/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "final_layer_type_1/MatMul" + op: "MatMul" + input: "add_7" + input: "final_layer_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/Shape" + op: "Shape" + input: "final_layer_type_1/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/final_layer_type_1/add_grad/Shape" + input: "gradients/final_layer_type_1/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "final_layer_type_1/add" + op: "Add" + input: "final_layer_type_1/MatMul" + input: "final_layer_type_1/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_15_grad/Shape" + op: "Shape" + input: "final_layer_type_1/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_15" + op: "Reshape" + input: "final_layer_type_1/add" + input: "Reshape_15/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Shape_2" + op: "Shape" + input: "Reshape_11" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "strided_slice_16" + op: "StridedSlice" + input: "Shape_2" + input: "strided_slice_16/stack" + input: "strided_slice_16/stack_1" + input: "strided_slice_16/stack_2" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "begin_mask" + value { + i: 0 + } + } + attr { + key: "ellipsis_mask" + value { + i: 0 + } + } + attr { + key: "end_mask" + value { + i: 0 + } + } + attr { + key: "new_axis_mask" + value { + i: 0 + } + } + attr { + key: "shrink_axis_mask" + value { + i: 1 + } + } +} +node { + name: "Reshape_13/shape" + op: "Pack" + input: "strided_slice_16" + input: "strided_slice_17" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "axis" + value { + i: 0 + } + } +} +node { + name: "Slice_2" + op: "Slice" + input: "Reshape_11" + input: "Slice_2/begin" + input: "Slice_2/size" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Slice_2_grad/Shape" + op: "Shape" + input: "Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/sub" + op: "Sub" + input: "gradients/Slice_2_grad/Shape_1" + input: "gradients/Slice_2_grad/Shape" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/sub_1" + op: "Sub" + input: "gradients/Slice_2_grad/sub" + input: "Slice_2/begin" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/Reshape_1" + op: "Reshape" + input: "gradients/Slice_2_grad/sub_1" + input: "gradients/Slice_2_grad/stack" + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/concat" + op: "ConcatV2" + input: "gradients/Slice_2_grad/Reshape" + input: "gradients/Slice_2_grad/Reshape_1" + input: "gradients/Slice_2_grad/concat/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_INT32 + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_12_grad/Shape" + op: "Shape" + input: "Slice_2" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_12" + op: "Reshape" + input: "Slice_2" + input: "Reshape_12/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_0/MatMul" + op: "MatMul" + input: "Reshape_12" + input: "layer_0_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/Shape" + op: "Shape" + input: "layer_0_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_0_type_0/add_grad/Shape" + input: "gradients/layer_0_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_0/add" + op: "Add" + input: "layer_0_type_0/MatMul" + input: "layer_0_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_0_type_0/Tanh" + op: "Tanh" + input: "layer_0_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_0_type_0/Reshape_grad/Shape" + op: "Shape" + input: "layer_0_type_0/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_0_type_0/Reshape" + op: "Reshape" + input: "layer_0_type_0/Tanh" + input: "layer_0_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_3_grad/Shape" + op: "Shape" + input: "layer_0_type_0/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/MatMul" + op: "MatMul" + input: "layer_0_type_0/Reshape" + input: "layer_1_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/Shape" + op: "Shape" + input: "layer_1_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_1_type_0/add_grad/Shape" + input: "gradients/layer_1_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/add" + op: "Add" + input: "layer_1_type_0/MatMul" + input: "layer_1_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_1_type_0/Tanh" + op: "Tanh" + input: "layer_1_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_0/Reshape_grad/Shape" + op: "Shape" + input: "layer_1_type_0/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/Reshape" + op: "Reshape" + input: "layer_1_type_0/Tanh" + input: "layer_1_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Shape" + op: "Shape" + input: "layer_1_type_0/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_1_type_0/mul_grad/Shape" + input: "gradients/layer_1_type_0/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_1_type_0/mul" + op: "Mul" + input: "layer_1_type_0/Reshape" + input: "layer_1_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_3_grad/Shape_1" + op: "Shape" + input: "layer_1_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_3_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/add_3_grad/Shape" + input: "gradients/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_3" + op: "Add" + input: "layer_0_type_0/Reshape" + input: "layer_1_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_4_grad/Shape" + op: "Shape" + input: "add_3" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/MatMul" + op: "MatMul" + input: "add_3" + input: "layer_2_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/Shape" + op: "Shape" + input: "layer_2_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_2_type_0/add_grad/Shape" + input: "gradients/layer_2_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/add" + op: "Add" + input: "layer_2_type_0/MatMul" + input: "layer_2_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "layer_2_type_0/Tanh" + op: "Tanh" + input: "layer_2_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_0/Reshape_grad/Shape" + op: "Shape" + input: "layer_2_type_0/Tanh" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/Reshape" + op: "Reshape" + input: "layer_2_type_0/Tanh" + input: "layer_2_type_0/Reshape/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Shape" + op: "Shape" + input: "layer_2_type_0/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/layer_2_type_0/mul_grad/Shape" + input: "gradients/layer_2_type_0/mul_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "layer_2_type_0/mul" + op: "Mul" + input: "layer_2_type_0/Reshape" + input: "layer_2_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/add_4_grad/Shape_1" + op: "Shape" + input: "layer_2_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/add_4_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/add_4_grad/Shape" + input: "gradients/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "add_4" + op: "Add" + input: "add_3" + input: "layer_2_type_0/mul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "final_layer_type_0/MatMul" + op: "MatMul" + input: "add_4" + input: "final_layer_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: false + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/Shape" + op: "Shape" + input: "final_layer_type_0/MatMul" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/BroadcastGradientArgs" + op: "BroadcastGradientArgs" + input: "gradients/final_layer_type_0/add_grad/Shape" + input: "gradients/final_layer_type_0/add_grad/Shape_1" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} +node { + name: "final_layer_type_0/add" + op: "Add" + input: "final_layer_type_0/MatMul" + input: "final_layer_type_0/bias/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_13_grad/Shape" + op: "Shape" + input: "final_layer_type_0/add" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_13" + op: "Reshape" + input: "final_layer_type_0/add" + input: "Reshape_13/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_1_grad/ShapeN" + op: "ShapeN" + input: "Reshape_13" + input: "Reshape_15" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_1_grad/ConcatOffset" + op: "ConcatOffset" + input: "gradients/concat_1_grad/mod" + input: "gradients/concat_1_grad/ShapeN" + input: "gradients/concat_1_grad/ShapeN:1" + attr { + key: "N" + value { + i: 2 + } + } +} +node { + name: "concat_1" + op: "ConcatV2" + input: "Reshape_13" + input: "Reshape_15" + input: "concat_1/axis" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_16_grad/Shape" + op: "Shape" + input: "concat_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_16" + op: "Reshape" + input: "concat_1" + input: "Reshape_16/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Shape" + op: "Shape" + input: "Reshape_16" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "out_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Fill" + op: "Fill" + input: "gradients/Shape" + input: "gradients/grad_ys_0" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "index_type" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Reshape_16_grad/Reshape" + op: "Reshape" + input: "gradients/Fill" + input: "gradients/Reshape_16_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_1_grad/Slice_1" + op: "Slice" + input: "gradients/Reshape_16_grad/Reshape" + input: "gradients/concat_1_grad/ConcatOffset:1" + input: "gradients/concat_1_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_15_grad/Reshape" + op: "Reshape" + input: "gradients/concat_1_grad/Slice_1" + input: "gradients/Reshape_15_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/Reshape_15_grad/Reshape" + input: "gradients/final_layer_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/final_layer_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/final_layer_type_1/add_grad/Sum" + input: "gradients/final_layer_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/final_layer_type_1/add_grad/Reshape" + input: "final_layer_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_7_grad/Sum_1" + op: "Sum" + input: "gradients/final_layer_type_1/MatMul_grad/MatMul" + input: "gradients/add_7_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_7_grad/Reshape_1" + op: "Reshape" + input: "gradients/add_7_grad/Sum_1" + input: "gradients/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients/add_7_grad/Reshape_1" + input: "layer_2_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients/layer_2_type_1/mul_grad/Mul" + input: "gradients/layer_2_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_1/mul_grad/Sum" + input: "gradients/layer_2_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_1/mul_grad/Reshape" + input: "gradients/layer_2_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_2_type_1/Tanh" + input: "gradients/layer_2_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/layer_2_type_1/Tanh_grad/TanhGrad" + input: "gradients/layer_2_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_1/add_grad/Sum" + input: "gradients/layer_2_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_2_type_1/add_grad/Reshape" + input: "layer_2_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_7_grad/Sum" + op: "Sum" + input: "gradients/final_layer_type_1/MatMul_grad/MatMul" + input: "gradients/add_7_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_7_grad/Reshape" + op: "Reshape" + input: "gradients/add_7_grad/Sum" + input: "gradients/add_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_1" + op: "AddN" + input: "gradients/add_7_grad/Reshape" + input: "gradients/layer_2_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/add_7_grad/Reshape" + } + } + } +} +node { + name: "gradients/add_6_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_1" + input: "gradients/add_6_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_6_grad/Reshape_1" + op: "Reshape" + input: "gradients/add_6_grad/Sum_1" + input: "gradients/add_6_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients/add_6_grad/Reshape_1" + input: "layer_1_type_1/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients/layer_1_type_1/mul_grad/Mul" + input: "gradients/layer_1_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_1/mul_grad/Sum" + input: "gradients/layer_1_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_1/mul_grad/Reshape" + input: "gradients/layer_1_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_1_type_1/Tanh" + input: "gradients/layer_1_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/layer_1_type_1/Tanh_grad/TanhGrad" + input: "gradients/layer_1_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_1/add_grad/Sum" + input: "gradients/layer_1_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_1_type_1/add_grad/Reshape" + input: "layer_1_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_6_grad/Sum" + op: "Sum" + input: "gradients/AddN_1" + input: "gradients/add_6_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_6_grad/Reshape" + op: "Reshape" + input: "gradients/add_6_grad/Sum" + input: "gradients/add_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_3" + op: "AddN" + input: "gradients/add_6_grad/Reshape" + input: "gradients/layer_1_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/add_6_grad/Reshape" + } + } + } +} +node { + name: "gradients/layer_0_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_3" + input: "gradients/layer_0_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_0_type_1/Tanh" + input: "gradients/layer_0_type_1/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/layer_0_type_1/Tanh_grad/TanhGrad" + input: "gradients/layer_0_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_0_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_0_type_1/add_grad/Sum" + input: "gradients/layer_0_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_0_type_1/add_grad/Reshape" + input: "layer_0_type_1/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/Reshape_14_grad/Reshape" + op: "Reshape" + input: "gradients/layer_0_type_1/MatMul_grad/MatMul" + input: "gradients/Reshape_14_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_3_grad/Pad" + op: "Pad" + input: "gradients/Reshape_14_grad/Reshape" + input: "gradients/Slice_3_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_1_grad/Slice" + op: "Slice" + input: "gradients/Reshape_16_grad/Reshape" + input: "gradients/concat_1_grad/ConcatOffset" + input: "gradients/concat_1_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_13_grad/Reshape" + op: "Reshape" + input: "gradients/concat_1_grad/Slice" + input: "gradients/Reshape_13_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/Reshape_13_grad/Reshape" + input: "gradients/final_layer_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/final_layer_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/final_layer_type_0/add_grad/Sum" + input: "gradients/final_layer_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/final_layer_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/final_layer_type_0/add_grad/Reshape" + input: "final_layer_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_4_grad/Sum_1" + op: "Sum" + input: "gradients/final_layer_type_0/MatMul_grad/MatMul" + input: "gradients/add_4_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_4_grad/Reshape_1" + op: "Reshape" + input: "gradients/add_4_grad/Sum_1" + input: "gradients/add_4_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Mul" + op: "Mul" + input: "gradients/add_4_grad/Reshape_1" + input: "layer_2_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Sum" + op: "Sum" + input: "gradients/layer_2_type_0/mul_grad/Mul" + input: "gradients/layer_2_type_0/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_0/mul_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_0/mul_grad/Sum" + input: "gradients/layer_2_type_0/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_0/mul_grad/Reshape" + input: "gradients/layer_2_type_0/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_2_type_0/Tanh" + input: "gradients/layer_2_type_0/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/layer_2_type_0/Tanh_grad/TanhGrad" + input: "gradients/layer_2_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_2_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_2_type_0/add_grad/Sum" + input: "gradients/layer_2_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_2_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_2_type_0/add_grad/Reshape" + input: "layer_2_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_4_grad/Sum" + op: "Sum" + input: "gradients/final_layer_type_0/MatMul_grad/MatMul" + input: "gradients/add_4_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_4_grad/Reshape" + op: "Reshape" + input: "gradients/add_4_grad/Sum" + input: "gradients/add_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN" + op: "AddN" + input: "gradients/add_4_grad/Reshape" + input: "gradients/layer_2_type_0/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/add_4_grad/Reshape" + } + } + } +} +node { + name: "gradients/add_3_grad/Sum_1" + op: "Sum" + input: "gradients/AddN" + input: "gradients/add_3_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/add_3_grad/Sum_1" + input: "gradients/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Mul" + op: "Mul" + input: "gradients/add_3_grad/Reshape_1" + input: "layer_1_type_0/idt/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Sum" + op: "Sum" + input: "gradients/layer_1_type_0/mul_grad/Mul" + input: "gradients/layer_1_type_0/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_0/mul_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_0/mul_grad/Sum" + input: "gradients/layer_1_type_0/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_0/mul_grad/Reshape" + input: "gradients/layer_1_type_0/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_1_type_0/Tanh" + input: "gradients/layer_1_type_0/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/layer_1_type_0/Tanh_grad/TanhGrad" + input: "gradients/layer_1_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_1_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_1_type_0/add_grad/Sum" + input: "gradients/layer_1_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_1_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_1_type_0/add_grad/Reshape" + input: "layer_1_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/add_3_grad/Sum" + op: "Sum" + input: "gradients/AddN" + input: "gradients/add_3_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/add_3_grad/Reshape" + op: "Reshape" + input: "gradients/add_3_grad/Sum" + input: "gradients/add_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_2" + op: "AddN" + input: "gradients/add_3_grad/Reshape" + input: "gradients/layer_1_type_0/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/add_3_grad/Reshape" + } + } + } +} +node { + name: "gradients/layer_0_type_0/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_2" + input: "gradients/layer_0_type_0/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_0/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "layer_0_type_0/Tanh" + input: "gradients/layer_0_type_0/Reshape_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/layer_0_type_0/Tanh_grad/TanhGrad" + input: "gradients/layer_0_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/layer_0_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/layer_0_type_0/add_grad/Sum" + input: "gradients/layer_0_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/layer_0_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/layer_0_type_0/add_grad/Reshape" + input: "layer_0_type_0/matrix/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/Reshape_12_grad/Reshape" + op: "Reshape" + input: "gradients/layer_0_type_0/MatMul_grad/MatMul" + input: "gradients/Reshape_12_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_2_grad/Pad" + op: "Pad" + input: "gradients/Reshape_12_grad/Reshape" + input: "gradients/Slice_2_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_4" + op: "AddN" + input: "gradients/Slice_2_grad/Pad" + input: "gradients/Slice_3_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/Slice_2_grad/Pad" + } + } + } +} +node { + name: "gradients/Reshape_11_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_4" + input: "gradients/Reshape_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/Slice_1" + op: "Slice" + input: "gradients/Reshape_11_grad/Reshape" + input: "gradients/concat_grad/ConcatOffset:1" + input: "gradients/concat_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_10_grad/Reshape" + op: "Reshape" + input: "gradients/concat_grad/Slice_1" + input: "gradients/Reshape_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Mul" + op: "Mul" + input: "gradients/Reshape_10_grad/Reshape" + input: "filter_type_1/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/mul_grad/Mul" + input: "gradients/filter_type_1/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/mul_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/mul_grad/Sum" + input: "gradients/filter_type_1/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/mul_grad/Reshape" + input: "gradients/filter_type_1/Mean_grad/DynamicStitch" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/Tile" + op: "Tile" + input: "gradients/filter_type_1/Mean_grad/Reshape" + input: "gradients/filter_type_1/Mean_grad/floordiv" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tmultiples" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Mean_grad/truediv" + op: "RealDiv" + input: "gradients/filter_type_1/Mean_grad/Tile" + input: "gradients/filter_type_1/Mean_grad/Cast" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_6_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/Mean_grad/truediv" + input: "gradients/filter_type_1/concat_6_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_6_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_9_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/concat_6_grad/Slice_1" + input: "gradients/filter_type_1/Reshape_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_1/Reshape_9_grad/Reshape" + input: "gradients/filter_type_1/add_11_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_11_grad/Sum_1" + input: "gradients/filter_type_1/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_8_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_11_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_5_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_5" + input: "gradients/filter_type_1/Reshape_8_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_5_grad/TanhGrad" + input: "gradients/filter_type_1/add_10_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_10_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_10_grad/Sum" + input: "gradients/filter_type_1/add_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_5_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_10_grad/Reshape" + input: "filter_type_1/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Reshape_9_grad/Reshape" + input: "gradients/filter_type_1/add_11_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_11_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_11_grad/Sum" + input: "gradients/filter_type_1/add_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_11_grad/Reshape" + input: "gradients/filter_type_1/concat_5_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_5_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_5_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_11_grad/Reshape" + input: "gradients/filter_type_1/concat_5_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_5_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_8" + op: "AddN" + input: "gradients/filter_type_1/concat_5_grad/Slice" + input: "gradients/filter_type_1/concat_5_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_5_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_5_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_8" + input: "gradients/filter_type_1/add_9_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_9_grad/Sum_1" + input: "gradients/filter_type_1/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_7_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_9_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_4_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_4" + input: "gradients/filter_type_1/Reshape_7_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_4_grad/TanhGrad" + input: "gradients/filter_type_1/add_8_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_8_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_8_grad/Sum" + input: "gradients/filter_type_1/add_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_4_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_8_grad/Reshape" + input: "filter_type_1/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Sum" + op: "Sum" + input: "gradients/AddN_8" + input: "gradients/filter_type_1/add_9_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_9_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_9_grad/Sum" + input: "gradients/filter_type_1/add_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_9_grad/Reshape" + input: "gradients/filter_type_1/concat_4_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_4_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_4_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_9_grad/Reshape" + input: "gradients/filter_type_1/concat_4_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_4_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_12" + op: "AddN" + input: "gradients/filter_type_1/concat_4_grad/Slice" + input: "gradients/filter_type_1/concat_4_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_4_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_4_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_12" + input: "gradients/filter_type_1/add_7_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_7_grad/Sum_1" + input: "gradients/filter_type_1/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_6_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_7_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_3_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_3" + input: "gradients/filter_type_1/Reshape_6_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_3_grad/TanhGrad" + input: "gradients/filter_type_1/add_6_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_6_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_6_grad/Sum" + input: "gradients/filter_type_1/add_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_3_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_6_grad/Reshape" + input: "filter_type_1/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Sum" + op: "Sum" + input: "gradients/AddN_12" + input: "gradients/filter_type_1/add_7_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_7_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_7_grad/Sum" + input: "gradients/filter_type_1/add_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_7_grad/Reshape" + input: "gradients/filter_type_1/concat_3_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_3_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_3_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_7_grad/Reshape" + input: "gradients/filter_type_1/concat_3_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_3_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_16" + op: "AddN" + input: "gradients/filter_type_1/concat_3_grad/Slice" + input: "gradients/filter_type_1/concat_3_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_3_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_3_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/Reshape_5_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_16" + input: "gradients/filter_type_1/Reshape_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_1_grad/Pad" + op: "Pad" + input: "gradients/filter_type_1/Reshape_5_grad/Reshape" + input: "gradients/filter_type_1/Slice_1_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_6_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/Mean_grad/truediv" + input: "gradients/filter_type_1/concat_6_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_6_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/Reshape_4_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/concat_6_grad/Slice" + input: "gradients/filter_type_1/Reshape_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_1/Reshape_4_grad/Reshape" + input: "gradients/filter_type_1/add_5_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_5_grad/Sum_1" + input: "gradients/filter_type_1/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_3_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_5_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_2_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_2" + input: "gradients/filter_type_1/Reshape_3_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_2_grad/TanhGrad" + input: "gradients/filter_type_1/add_4_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_4_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_4_grad/Sum" + input: "gradients/filter_type_1/add_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_2_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_4_grad/Reshape" + input: "filter_type_1/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Reshape_4_grad/Reshape" + input: "gradients/filter_type_1/add_5_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_5_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_5_grad/Sum" + input: "gradients/filter_type_1/add_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_5_grad/Reshape" + input: "gradients/filter_type_1/concat_2_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_2_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_2_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_5_grad/Reshape" + input: "gradients/filter_type_1/concat_2_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_2_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_7" + op: "AddN" + input: "gradients/filter_type_1/concat_2_grad/Slice" + input: "gradients/filter_type_1/concat_2_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_2_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_2_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_7" + input: "gradients/filter_type_1/add_3_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_3_grad/Sum_1" + input: "gradients/filter_type_1/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_2_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_3_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_1_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh_1" + input: "gradients/filter_type_1/Reshape_2_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_1_grad/TanhGrad" + input: "gradients/filter_type_1/add_2_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_2_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_2_grad/Sum" + input: "gradients/filter_type_1/add_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_1_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_2_grad/Reshape" + input: "filter_type_1/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Sum" + op: "Sum" + input: "gradients/AddN_7" + input: "gradients/filter_type_1/add_3_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_3_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_3_grad/Sum" + input: "gradients/filter_type_1/add_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_3_grad/Reshape" + input: "gradients/filter_type_1/concat_1_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_1_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_1_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_3_grad/Reshape" + input: "gradients/filter_type_1/concat_1_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_1_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_11" + op: "AddN" + input: "gradients/filter_type_1/concat_1_grad/Slice" + input: "gradients/filter_type_1/concat_1_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_1_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_1_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_11" + input: "gradients/filter_type_1/add_1_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_1/add_1_grad/Sum_1" + input: "gradients/filter_type_1/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Reshape_1_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_1_grad/Reshape_1" + input: "gradients/filter_type_1/Reshape_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_1/Tanh" + input: "gradients/filter_type_1/Reshape_1_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/add_grad/Sum" + op: "Sum" + input: "gradients/filter_type_1/Tanh_grad/TanhGrad" + input: "gradients/filter_type_1/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_grad/Sum" + input: "gradients/filter_type_1/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_1/add_grad/Reshape" + input: "filter_type_1/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Sum" + op: "Sum" + input: "gradients/AddN_11" + input: "gradients/filter_type_1/add_1_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_1/add_1_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_1/add_1_grad/Sum" + input: "gradients/filter_type_1/add_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_1/add_1_grad/Reshape" + input: "gradients/filter_type_1/concat_grad/ConcatOffset:1" + input: "gradients/filter_type_1/concat_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_1/concat_grad/Slice" + op: "Slice" + input: "gradients/filter_type_1/add_1_grad/Reshape" + input: "gradients/filter_type_1/concat_grad/ConcatOffset" + input: "gradients/filter_type_1/concat_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_15" + op: "AddN" + input: "gradients/filter_type_1/concat_grad/Slice" + input: "gradients/filter_type_1/concat_grad/Slice_1" + input: "gradients/filter_type_1/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/concat_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_1/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_15" + input: "gradients/filter_type_1/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_1/Slice_grad/Pad" + op: "Pad" + input: "gradients/filter_type_1/Reshape_grad/Reshape" + input: "gradients/filter_type_1/Slice_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_18" + op: "AddN" + input: "gradients/filter_type_1/Slice_grad/Pad" + input: "gradients/filter_type_1/Slice_1_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_1/Slice_grad/Pad" + } + } + } +} +node { + name: "gradients/Reshape_9_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_18" + input: "gradients/Reshape_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_1_grad/Pad" + op: "Pad" + input: "gradients/Reshape_9_grad/Reshape" + input: "gradients/Slice_1_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/concat_grad/Slice" + op: "Slice" + input: "gradients/Reshape_11_grad/Reshape" + input: "gradients/concat_grad/ConcatOffset" + input: "gradients/concat_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/Reshape_8_grad/Reshape" + op: "Reshape" + input: "gradients/concat_grad/Slice" + input: "gradients/Reshape_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Mul" + op: "Mul" + input: "gradients/Reshape_8_grad/Reshape" + input: "filter_type_0/mul/y" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/mul_grad/Mul" + input: "gradients/filter_type_0/mul_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/mul_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/mul_grad/Sum" + input: "gradients/filter_type_0/mul_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/mul_grad/Reshape" + input: "gradients/filter_type_0/Mean_grad/DynamicStitch" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/Tile" + op: "Tile" + input: "gradients/filter_type_0/Mean_grad/Reshape" + input: "gradients/filter_type_0/Mean_grad/floordiv" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tmultiples" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Mean_grad/truediv" + op: "RealDiv" + input: "gradients/filter_type_0/Mean_grad/Tile" + input: "gradients/filter_type_0/Mean_grad/Cast" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_6_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/Mean_grad/truediv" + input: "gradients/filter_type_0/concat_6_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_6_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_9_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/concat_6_grad/Slice_1" + input: "gradients/filter_type_0/Reshape_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_0/Reshape_9_grad/Reshape" + input: "gradients/filter_type_0/add_11_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_11_grad/Sum_1" + input: "gradients/filter_type_0/add_11_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_8_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_11_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_5_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_5" + input: "gradients/filter_type_0/Reshape_8_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_5_grad/TanhGrad" + input: "gradients/filter_type_0/add_10_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_10_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_10_grad/Sum" + input: "gradients/filter_type_0/add_10_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_5_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_10_grad/Reshape" + input: "filter_type_0/matrix_3_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Reshape_9_grad/Reshape" + input: "gradients/filter_type_0/add_11_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_11_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_11_grad/Sum" + input: "gradients/filter_type_0/add_11_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_11_grad/Reshape" + input: "gradients/filter_type_0/concat_5_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_5_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_5_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_11_grad/Reshape" + input: "gradients/filter_type_0/concat_5_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_5_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_6" + op: "AddN" + input: "gradients/filter_type_0/concat_5_grad/Slice" + input: "gradients/filter_type_0/concat_5_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_5_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_5_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_6" + input: "gradients/filter_type_0/add_9_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_9_grad/Sum_1" + input: "gradients/filter_type_0/add_9_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_7_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_9_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_4_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_4" + input: "gradients/filter_type_0/Reshape_7_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_4_grad/TanhGrad" + input: "gradients/filter_type_0/add_8_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_8_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_8_grad/Sum" + input: "gradients/filter_type_0/add_8_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_4_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_8_grad/Reshape" + input: "filter_type_0/matrix_2_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Sum" + op: "Sum" + input: "gradients/AddN_6" + input: "gradients/filter_type_0/add_9_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_9_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_9_grad/Sum" + input: "gradients/filter_type_0/add_9_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_9_grad/Reshape" + input: "gradients/filter_type_0/concat_4_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_4_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_4_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_9_grad/Reshape" + input: "gradients/filter_type_0/concat_4_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_4_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_10" + op: "AddN" + input: "gradients/filter_type_0/concat_4_grad/Slice" + input: "gradients/filter_type_0/concat_4_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_4_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_4_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_10" + input: "gradients/filter_type_0/add_7_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_7_grad/Sum_1" + input: "gradients/filter_type_0/add_7_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_6_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_7_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_3_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_3" + input: "gradients/filter_type_0/Reshape_6_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_3_grad/TanhGrad" + input: "gradients/filter_type_0/add_6_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_6_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_6_grad/Sum" + input: "gradients/filter_type_0/add_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_3_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_6_grad/Reshape" + input: "filter_type_0/matrix_1_1/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Sum" + op: "Sum" + input: "gradients/AddN_10" + input: "gradients/filter_type_0/add_7_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_7_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_7_grad/Sum" + input: "gradients/filter_type_0/add_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_7_grad/Reshape" + input: "gradients/filter_type_0/concat_3_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_3_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_3_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_7_grad/Reshape" + input: "gradients/filter_type_0/concat_3_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_3_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_14" + op: "AddN" + input: "gradients/filter_type_0/concat_3_grad/Slice" + input: "gradients/filter_type_0/concat_3_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_3_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_3_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/Reshape_5_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_14" + input: "gradients/filter_type_0/Reshape_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_1_grad/Pad" + op: "Pad" + input: "gradients/filter_type_0/Reshape_5_grad/Reshape" + input: "gradients/filter_type_0/Slice_1_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_6_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/Mean_grad/truediv" + input: "gradients/filter_type_0/concat_6_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_6_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/Reshape_4_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/concat_6_grad/Slice" + input: "gradients/filter_type_0/Reshape_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Sum_1" + op: "Sum" + input: "gradients/filter_type_0/Reshape_4_grad/Reshape" + input: "gradients/filter_type_0/add_5_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_5_grad/Sum_1" + input: "gradients/filter_type_0/add_5_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_3_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_5_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_2_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_2" + input: "gradients/filter_type_0/Reshape_3_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_2_grad/TanhGrad" + input: "gradients/filter_type_0/add_4_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_4_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_4_grad/Sum" + input: "gradients/filter_type_0/add_4_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_2_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_4_grad/Reshape" + input: "filter_type_0/matrix_3_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Reshape_4_grad/Reshape" + input: "gradients/filter_type_0/add_5_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_5_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_5_grad/Sum" + input: "gradients/filter_type_0/add_5_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_5_grad/Reshape" + input: "gradients/filter_type_0/concat_2_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_2_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_2_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_5_grad/Reshape" + input: "gradients/filter_type_0/concat_2_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_2_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_5" + op: "AddN" + input: "gradients/filter_type_0/concat_2_grad/Slice" + input: "gradients/filter_type_0/concat_2_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_2_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_2_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_5" + input: "gradients/filter_type_0/add_3_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_3_grad/Sum_1" + input: "gradients/filter_type_0/add_3_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_2_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_3_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_1_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh_1" + input: "gradients/filter_type_0/Reshape_2_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_1_grad/TanhGrad" + input: "gradients/filter_type_0/add_2_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_2_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_2_grad/Sum" + input: "gradients/filter_type_0/add_2_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_1_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_2_grad/Reshape" + input: "filter_type_0/matrix_2_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Sum" + op: "Sum" + input: "gradients/AddN_5" + input: "gradients/filter_type_0/add_3_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_3_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_3_grad/Sum" + input: "gradients/filter_type_0/add_3_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_3_grad/Reshape" + input: "gradients/filter_type_0/concat_1_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_1_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_1_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_3_grad/Reshape" + input: "gradients/filter_type_0/concat_1_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_1_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_9" + op: "AddN" + input: "gradients/filter_type_0/concat_1_grad/Slice" + input: "gradients/filter_type_0/concat_1_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_1_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_1_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Sum_1" + op: "Sum" + input: "gradients/AddN_9" + input: "gradients/filter_type_0/add_1_grad/BroadcastGradientArgs:1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Reshape_1" + op: "Reshape" + input: "gradients/filter_type_0/add_1_grad/Sum_1" + input: "gradients/filter_type_0/add_1_grad/Shape_1" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Reshape_1_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_1_grad/Reshape_1" + input: "gradients/filter_type_0/Reshape_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Tanh_grad/TanhGrad" + op: "TanhGrad" + input: "filter_type_0/Tanh" + input: "gradients/filter_type_0/Reshape_1_grad/Reshape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/add_grad/Sum" + op: "Sum" + input: "gradients/filter_type_0/Tanh_grad/TanhGrad" + input: "gradients/filter_type_0/add_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_grad/Sum" + input: "gradients/filter_type_0/add_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/MatMul_grad/MatMul" + op: "MatMul" + input: "gradients/filter_type_0/add_grad/Reshape" + input: "filter_type_0/matrix_1_0/read" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "transpose_a" + value { + b: false + } + } + attr { + key: "transpose_b" + value { + b: true + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Sum" + op: "Sum" + input: "gradients/AddN_9" + input: "gradients/filter_type_0/add_1_grad/BroadcastGradientArgs" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +node { + name: "gradients/filter_type_0/add_1_grad/Reshape" + op: "Reshape" + input: "gradients/filter_type_0/add_1_grad/Sum" + input: "gradients/filter_type_0/add_1_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/Slice_1" + op: "Slice" + input: "gradients/filter_type_0/add_1_grad/Reshape" + input: "gradients/filter_type_0/concat_grad/ConcatOffset:1" + input: "gradients/filter_type_0/concat_grad/ShapeN:1" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/filter_type_0/concat_grad/Slice" + op: "Slice" + input: "gradients/filter_type_0/add_1_grad/Reshape" + input: "gradients/filter_type_0/concat_grad/ConcatOffset" + input: "gradients/filter_type_0/concat_grad/ShapeN" + attr { + key: "Index" + value { + type: DT_INT32 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "gradients/AddN_13" + op: "AddN" + input: "gradients/filter_type_0/concat_grad/Slice" + input: "gradients/filter_type_0/concat_grad/Slice_1" + input: "gradients/filter_type_0/MatMul_grad/MatMul" + attr { + key: "N" + value { + i: 3 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/concat_grad/Slice" + } + } + } +} +node { + name: "gradients/filter_type_0/Reshape_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_13" + input: "gradients/filter_type_0/Reshape_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/filter_type_0/Slice_grad/Pad" + op: "Pad" + input: "gradients/filter_type_0/Reshape_grad/Reshape" + input: "gradients/filter_type_0/Slice_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_17" + op: "AddN" + input: "gradients/filter_type_0/Slice_grad/Pad" + input: "gradients/filter_type_0/Slice_1_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/filter_type_0/Slice_grad/Pad" + } + } + } +} +node { + name: "gradients/Reshape_7_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_17" + input: "gradients/Reshape_7_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/Slice_grad/Pad" + op: "Pad" + input: "gradients/Reshape_7_grad/Reshape" + input: "gradients/Slice_grad/concat" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tpaddings" + value { + type: DT_INT32 + } + } +} +node { + name: "gradients/AddN_19" + op: "AddN" + input: "gradients/Slice_grad/Pad" + input: "gradients/Slice_1_grad/Pad" + attr { + key: "N" + value { + i: 2 + } + } + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "_class" + value { + list { + s: "loc:@gradients/Slice_grad/Pad" + } + } + } +} +node { + name: "gradients/Reshape_6_grad/Reshape" + op: "Reshape" + input: "gradients/AddN_19" + input: "gradients/Reshape_6_grad/Shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "Reshape_17" + op: "Reshape" + input: "gradients/Reshape_6_grad/Reshape" + input: "Reshape_17/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "ProdVirialSeR" + op: "ProdVirialSeR" + input: "Reshape_17" + input: "o_rmat_deriv" + input: "o_rij" + input: "o_nlist" + input: "t_natoms" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "o_atom_virial" + op: "Reshape" + input: "ProdVirialSeR:1" + input: "o_atom_virial/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_virial" + op: "Reshape" + input: "ProdVirialSeR" + input: "o_virial/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "ProdForceSeR" + op: "ProdForceSeR" + input: "Reshape_17" + input: "o_rmat_deriv" + input: "o_nlist" + input: "t_natoms" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } +} +node { + name: "o_force" + op: "Reshape" + input: "ProdForceSeR" + input: "o_force/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_atom_energy" + op: "Reshape" + input: "Reshape_16" + input: "o_atom_energy/shape" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tshape" + value { + type: DT_INT32 + } + } +} +node { + name: "o_energy" + op: "Sum" + input: "o_atom_energy" + input: "o_energy/reduction_indices" + attr { + key: "T" + value { + type: DT_DOUBLE + } + } + attr { + key: "Tidx" + value { + type: DT_INT32 + } + } + attr { + key: "keep_dims" + value { + b: false + } + } +} +library { +} diff --git a/source/tests/test_deeppot.py b/source/tests/test_deeppot_a.py similarity index 99% rename from source/tests/test_deeppot.py rename to source/tests/test_deeppot_a.py index a513ad492d..8dee81df75 100644 --- a/source/tests/test_deeppot.py +++ b/source/tests/test_deeppot_a.py @@ -12,7 +12,7 @@ else : default_places = 10 -class TestDeepPotPBC(unittest.TestCase) : +class TestDeepPotAPBC(unittest.TestCase) : def setUp(self): convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot.pbtxt")), "deeppot.pb") self.dp = DeepPot("deeppot.pb") @@ -111,7 +111,7 @@ def test_2frame_atm(self): self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) -class TestDeepPotNoPBC(unittest.TestCase) : +class TestDeepPotANoPBC(unittest.TestCase) : def setUp(self): convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot.pbtxt")), "deeppot.pb") self.dp = DeepPot("deeppot.pb") @@ -202,7 +202,7 @@ def test_2frame_atm(self): self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) -class TestDeepPotLargeBoxNoPBC(unittest.TestCase) : +class TestDeepPotALargeBoxNoPBC(unittest.TestCase) : def setUp(self): convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot.pbtxt")), "deeppot.pb") self.dp = DeepPot("deeppot.pb") diff --git a/source/tests/test_deeppot_r.py b/source/tests/test_deeppot_r.py new file mode 100644 index 0000000000..7f9a97ce66 --- /dev/null +++ b/source/tests/test_deeppot_r.py @@ -0,0 +1,290 @@ +import os,sys,platform,shutil,dpdata +import numpy as np +import unittest + +from infer.convert2pb import convert_pbtxt_to_pb +from deepmd.infer import DeepPot +from common import tests_path + +from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +if GLOBAL_NP_FLOAT_PRECISION == np.float32 : + default_places = 4 +else : + default_places = 10 + +class TestDeepPotRPBC(unittest.TestCase) : + def setUp(self): + convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot-r.pbtxt")), "deeppot.pb") + self.dp = DeepPot("deeppot.pb") + self.coords = np.array([12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56]) + self.atype = [0, 1, 1, 0, 1, 1] + self.box = np.array([13., 0., 0., 0., 13., 0., 0., 0., 13.]) + self.expected_e = np.array([ + -9.320909762801588272e+01,-1.868020345400987878e+02,-1.868011172371355997e+02,-9.320868430396934912e+01,-1.868010398844378415e+02,-1.868016706555875999e+02 + ]) + self.expected_f = np.array([ + 6.385312846474267391e-04,-6.460452911141417731e-03,-5.652405655332678417e-04,-7.516468794343579736e-03,1.128804614240160216e-03,5.531937784564192051e-03,1.914138124904981664e-03,5.601819906021693503e-03,-5.131359585752605541e-03,-4.847104424804288617e-03,1.992071550328819614e-03,-4.028159855157302516e-03,1.236340684486603517e-03,-5.373955841338794344e-03,8.312829460571366513e-03,8.574563125108854156e-03,3.111712681889538742e-03,-4.120007238692381148e-03 + ]) + self.expected_v = np.array([ + 5.844056241889131371e-03,4.663973497239899614e-04,-2.268382127762904633e-03,4.663973497239897988e-04,2.349338784202595950e-03,-6.908546513234039253e-04,-2.268382127762904633e-03,-6.908546513234039253e-04,2.040499248150800561e-03,4.238130266437327605e-03,-1.539867187443782223e-04,-2.393101333240631613e-03,-1.539867187443782223e-04,4.410341945447907377e-04,9.544239698119633068e-06,-2.393101333240631613e-03,9.544239698119578858e-06,1.877785959095269654e-03,5.798992562057291543e-03,6.943392552230453693e-04,-1.180376879311998773e-03,6.943392552230453693e-04,1.686725132156275536e-03,-1.461632060145726542e-03,-1.180376879311998556e-03,-1.461632060145726325e-03,1.749543733794208444e-03,7.173915604192910439e-03,3.903218041111061569e-04,-5.747400467123527524e-04,3.903218041111061569e-04,1.208289706621179949e-03,-1.826828914132010932e-03,-5.747400467123527524e-04,-1.826828914132011148e-03,2.856960586657185906e-03,4.067553030177322240e-03,-3.267469855253819430e-05,-6.980667859103454904e-05,-3.267469855253830272e-05,1.387653029234650918e-03,-2.096820720698671855e-03,-6.980667859103444062e-05,-2.096820720698671855e-03,3.218305506720191278e-03,4.753992590355240674e-03,1.224911338353675992e-03,-1.683421934571502484e-03,1.224911338353676209e-03,7.332113564901583539e-04,-1.025577052190138451e-03,-1.683421934571502484e-03,-1.025577052190138234e-03,1.456681925652047018e-03 + ]) + + def tearDown(self): + os.remove("deeppot.pb") + + def test_attrs(self): + self.assertEqual(self.dp.get_ntypes(), 2) + self.assertAlmostEqual(self.dp.get_rcut(), 6.0, places = default_places) + self.assertEqual(self.dp.get_type_map(), ['O', 'H']) + self.assertEqual(self.dp.get_dim_fparam(), 0) + self.assertEqual(self.dp.get_dim_aparam(), 0) + + # def test_1frame(self): + # ee, ff, vv, ae, av = self.dp.eval(self.coords, self.box, self.atype, atomic = True) + # np.savetxt('ee.out', ae.reshape([1, -1]), delimiter=',') + # np.savetxt('ff.out', ff.reshape([1, -1]), delimiter=',') + # np.savetxt('vv.out', av.reshape([1, -1]), delimiter=',') + + def test_1frame(self): + ee, ff, vv = self.dp.eval(self.coords, self.box, self.atype, atomic = False) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + def test_1frame_atm(self): + ee, ff, vv, ae, av = self.dp.eval(self.coords, self.box, self.atype, atomic = True) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + self.assertEqual(ae.shape, (nframes,natoms,1)) + self.assertEqual(av.shape, (nframes,natoms,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + for ii in range(ae.size): + self.assertAlmostEqual(ae.reshape([-1])[ii], self.expected_e.reshape([-1])[ii], places = default_places) + for ii in range(av.size): + self.assertAlmostEqual(av.reshape([-1])[ii], self.expected_v.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + + def test_2frame_atm(self): + coords2 = np.concatenate((self.coords, self.coords)) + box2 = np.concatenate((self.box, self.box)) + ee, ff, vv, ae, av = self.dp.eval(coords2, box2, self.atype, atomic = True) + # check shape of the returns + nframes = 2 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + self.assertEqual(ae.shape, (nframes,natoms,1)) + self.assertEqual(av.shape, (nframes,natoms,9)) + # check values + expected_f = np.concatenate((self.expected_f, self.expected_f), axis = 0) + expected_e = np.concatenate((self.expected_e, self.expected_e), axis = 0) + expected_v = np.concatenate((self.expected_v, self.expected_v), axis = 0) + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], expected_f.reshape([-1])[ii], places = default_places) + for ii in range(ae.size): + self.assertAlmostEqual(ae.reshape([-1])[ii], expected_e.reshape([-1])[ii], places = default_places) + for ii in range(av.size): + self.assertAlmostEqual(av.reshape([-1])[ii], expected_v.reshape([-1])[ii], places = default_places) + expected_se = np.sum(expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + +class TestDeepPotRNoPBC(unittest.TestCase) : + def setUp(self): + convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot-r.pbtxt")), "deeppot.pb") + self.dp = DeepPot("deeppot.pb") + self.coords = np.array([12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56]) + self.atype = [0, 1, 1, 0, 1, 1] + self.box = None + self.expected_e = np.array([ + -9.321213823508108476e+01,-1.868044102481340758e+02,-1.868067983858651075e+02,-9.320899631301440991e+01,-1.868014559732615112e+02,-1.868017660713088617e+02 + ]) + self.expected_f = np.array([ + 4.578151103701261042e-03,-1.917874111009987628e-03,-3.464546781179331930e-03,-4.578151103701261042e-03,1.917874111009987628e-03,3.464546781179331930e-03,-2.624402581721222913e-03,3.566275128489623933e-04,-2.859315986763691776e-04,-5.767787273464367384e-03,1.907053583551196647e-03,-3.889064429673861831e-03,1.786820066350549132e-04,-5.327197473636275694e-03,8.236236182834734409e-03,8.213507848550535492e-03,3.063516377236116545e-03,-4.061240154484504865e-03 + ]) + self.expected_v = np.array([ + 1.984979026299632174e-03,-8.315452677741701822e-04,-1.502146290172694243e-03,-8.315452677741700738e-04,3.483500446080982317e-04,6.292774999372096039e-04,-1.502146290172694243e-03,6.292774999372097123e-04,1.136759354725281907e-03,1.402852790439301908e-03,-5.876815743732210226e-04,-1.061618327900012114e-03,-5.876815743732211311e-04,2.461909298049979960e-04,4.447320022283834766e-04,-1.061618327900012331e-03,4.447320022283834766e-04,8.033868427351443728e-04,4.143606961846296385e-03,-5.511382161123719835e-04,4.465413399437045397e-04,-5.511382161123719835e-04,1.082271054025323839e-04,-1.097918001262628728e-04,4.465413399437046481e-04,-1.097918001262628728e-04,1.220966982358671871e-04,5.263952004497593831e-03,2.395243710938091842e-04,-2.830378939414603329e-04,2.395243710938094010e-04,1.189969706598244898e-03,-1.805627331015851201e-03,-2.830378939414602245e-04,-1.805627331015851635e-03,2.801996513751836820e-03,2.208413501170402270e-03,5.331756287635716889e-05,-1.664423506603235218e-04,5.331756287635695205e-05,1.379626072862918072e-03,-2.094132943741625064e-03,-1.664423506603234133e-04,-2.094132943741625064e-03,3.199787996743366607e-03,4.047014004814953811e-03,1.137904999421357000e-03,-1.568106936614101698e-03,1.137904999421357217e-03,7.205982843216952307e-04,-1.011174600268313238e-03,-1.568106936614101698e-03,-1.011174600268313238e-03,1.435226522157425754e-03 + ]) + + def tearDown(self): + os.remove("deeppot.pb") + + def test_1frame(self): + ee, ff, vv = self.dp.eval(self.coords, self.box, self.atype, atomic = False) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + def test_1frame_atm(self): + ee, ff, vv, ae, av = self.dp.eval(self.coords, self.box, self.atype, atomic = True) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + self.assertEqual(ae.shape, (nframes,natoms,1)) + self.assertEqual(av.shape, (nframes,natoms,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + for ii in range(ae.size): + self.assertAlmostEqual(ae.reshape([-1])[ii], self.expected_e.reshape([-1])[ii], places = default_places) + for ii in range(av.size): + self.assertAlmostEqual(av.reshape([-1])[ii], self.expected_v.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + + def test_2frame_atm(self): + coords2 = np.concatenate((self.coords, self.coords)) + ee, ff, vv, ae, av = self.dp.eval(coords2, self.box, self.atype, atomic = True) + # check shape of the returns + nframes = 2 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + self.assertEqual(ae.shape, (nframes,natoms,1)) + self.assertEqual(av.shape, (nframes,natoms,9)) + # check values + expected_f = np.concatenate((self.expected_f, self.expected_f), axis = 0) + expected_e = np.concatenate((self.expected_e, self.expected_e), axis = 0) + expected_v = np.concatenate((self.expected_v, self.expected_v), axis = 0) + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], expected_f.reshape([-1])[ii], places = default_places) + for ii in range(ae.size): + self.assertAlmostEqual(ae.reshape([-1])[ii], expected_e.reshape([-1])[ii], places = default_places) + for ii in range(av.size): + self.assertAlmostEqual(av.reshape([-1])[ii], expected_v.reshape([-1])[ii], places = default_places) + expected_se = np.sum(expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + +class TestDeepPotRLargeBoxNoPBC(unittest.TestCase) : + def setUp(self): + convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot-r.pbtxt")), "deeppot.pb") + self.dp = DeepPot("deeppot.pb") + self.coords = np.array([12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56]) + self.atype = [0, 1, 1, 0, 1, 1] + self.box = np.array([19., 0., 0., 0., 13., 0., 0., 0., 13.]) + self.expected_e = np.array([ + -9.321213823508108476e+01,-1.868044102481340758e+02,-1.868067983858651075e+02,-9.320899631301440991e+01,-1.868014559732615112e+02,-1.868017660713088617e+02 + ]) + self.expected_f = np.array([ + 4.578151103701261042e-03,-1.917874111009987628e-03,-3.464546781179331930e-03,-4.578151103701261042e-03,1.917874111009987628e-03,3.464546781179331930e-03,-2.624402581721222913e-03,3.566275128489623933e-04,-2.859315986763691776e-04,-5.767787273464367384e-03,1.907053583551196647e-03,-3.889064429673861831e-03,1.786820066350549132e-04,-5.327197473636275694e-03,8.236236182834734409e-03,8.213507848550535492e-03,3.063516377236116545e-03,-4.061240154484504865e-03 + ]) + self.expected_v = np.array([ + 1.984979026299632174e-03,-8.315452677741701822e-04,-1.502146290172694243e-03,-8.315452677741700738e-04,3.483500446080982317e-04,6.292774999372096039e-04,-1.502146290172694243e-03,6.292774999372097123e-04,1.136759354725281907e-03,1.402852790439301908e-03,-5.876815743732210226e-04,-1.061618327900012114e-03,-5.876815743732211311e-04,2.461909298049979960e-04,4.447320022283834766e-04,-1.061618327900012331e-03,4.447320022283834766e-04,8.033868427351443728e-04,4.143606961846296385e-03,-5.511382161123719835e-04,4.465413399437045397e-04,-5.511382161123719835e-04,1.082271054025323839e-04,-1.097918001262628728e-04,4.465413399437046481e-04,-1.097918001262628728e-04,1.220966982358671871e-04,5.263952004497593831e-03,2.395243710938091842e-04,-2.830378939414603329e-04,2.395243710938094010e-04,1.189969706598244898e-03,-1.805627331015851201e-03,-2.830378939414602245e-04,-1.805627331015851635e-03,2.801996513751836820e-03,2.208413501170402270e-03,5.331756287635716889e-05,-1.664423506603235218e-04,5.331756287635695205e-05,1.379626072862918072e-03,-2.094132943741625064e-03,-1.664423506603234133e-04,-2.094132943741625064e-03,3.199787996743366607e-03,4.047014004814953811e-03,1.137904999421357000e-03,-1.568106936614101698e-03,1.137904999421357217e-03,7.205982843216952307e-04,-1.011174600268313238e-03,-1.568106936614101698e-03,-1.011174600268313238e-03,1.435226522157425754e-03 + ]) + + def tearDown(self): + os.remove("deeppot.pb") + + def test_1frame(self): + ee, ff, vv = self.dp.eval(self.coords, self.box, self.atype, atomic = False) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + def test_1frame_atm(self): + ee, ff, vv, ae, av = self.dp.eval(self.coords, self.box, self.atype, atomic = True) + # check shape of the returns + nframes = 1 + natoms = len(self.atype) + self.assertEqual(ee.shape, (nframes,1)) + self.assertEqual(ff.shape, (nframes,natoms,3)) + self.assertEqual(vv.shape, (nframes,9)) + self.assertEqual(ae.shape, (nframes,natoms,1)) + self.assertEqual(av.shape, (nframes,natoms,9)) + # check values + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + for ii in range(ae.size): + self.assertAlmostEqual(ae.reshape([-1])[ii], self.expected_e.reshape([-1])[ii], places = default_places) + for ii in range(av.size): + self.assertAlmostEqual(av.reshape([-1])[ii], self.expected_v.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) + expected_sv = np.sum(self.expected_v.reshape([nframes, -1, 9]), axis = 1) + for ii in range(nframes, 9): + self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + + From 2cc3cc354cf72d43603f9399093d3d1b8b62458c Mon Sep 17 00:00:00 2001 From: denghuilu Date: Fri, 12 Mar 2021 02:19:03 +0800 Subject: [PATCH 265/562] fix conflicts --- source/op/prod_env_mat_multi_device.cc | 209 +++++++++++++++++++------ 1 file changed, 158 insertions(+), 51 deletions(-) diff --git a/source/op/prod_env_mat_multi_device.cc b/source/op/prod_env_mat_multi_device.cc index b50b7d80b8..e12fa73017 100644 --- a/source/op/prod_env_mat_multi_device.cc +++ b/source/op/prod_env_mat_multi_device.cc @@ -80,6 +80,33 @@ _map_nlist_cpu( const int & nloc, const int & nnei); +template +static void +_prepare_coord_nlist_cpu( + OpKernelContext* context, + FPTYPE const ** coord, + std::vector & coord_cpy, + int const** type, + std::vector & type_cpy, + std::vector & idx_mapping, + InputNlist & inlist, + std::vector & ilist, + std::vector & numneigh, + std::vector & firstneigh, + std::vector> & jlist, + int & new_nall, + int & mem_cpy, + int & mem_nnei, + int & max_nbor_size, + const FPTYPE * box, + const int * mesh_tensor_data, + const int & nloc, + const int & nei_mode, + const float & rcut_r, + const int & max_cpy_trial, + const int & max_nnei_trial); + + template class ProdEnvMatAOp : public OpKernel { @@ -228,7 +255,6 @@ class ProdEnvMatAOp : public OpKernel { const FPTYPE * coord = p_coord + ff*nall*3; const FPTYPE * box = p_box + ff*9; const int * type = p_type + ff*nall; - std::vector idx_mapping; if(device == "GPU") { #if GOOGLE_CUDA @@ -258,46 +284,25 @@ class ProdEnvMatAOp : public OpKernel { #endif //GOOGLE_CUDA } else if (device == "CPU") { - int new_nall = nall; InputNlist inlist; - inlist.inum = nloc; - // some buffers, be free after prod_env_mat_a_cpu + // some buffers, be freed after the evaluation of this frame + std::vector idx_mapping; std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); std::vector> jlist(nloc); std::vector coord_cpy; std::vector type_cpy; - if(nei_mode != 3){ - // build nlist by myself - // normalize and copy coord - if(nei_mode == 1){ - int copy_ok = _norm_copy_coord_cpu( - coord_cpy, type_cpy, idx_mapping, new_nall, mem_cpy, - coord, box, type, nloc, max_cpy_trial, rcut_r); - OP_REQUIRES (context, copy_ok, errors::Aborted("cannot allocate mem for copied coords")); - coord = &coord_cpy[0]; - type = &type_cpy[0]; - } - // build nlist - int build_ok = _build_nlist_cpu( - ilist, numneigh, firstneigh, jlist, max_nbor_size, mem_nnei, - coord, nloc, new_nall, max_nnei_trial, rcut_r); - OP_REQUIRES (context, build_ok, errors::Aborted("cannot allocate mem for nlist")); - inlist.ilist = &ilist[0]; - inlist.numneigh = &numneigh[0]; - inlist.firstneigh = &firstneigh[0]; - } - else{ - // copy pointers to nlist data - memcpy(&inlist.ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy(&inlist.numneigh, 8 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy(&inlist.firstneigh, 12 + mesh_tensor.flat().data(), sizeof(int **)); - max_nbor_size = max_numneigh(inlist); - } + int frame_nall = nall; + // prepare coord and nlist + _prepare_coord_nlist_cpu( + context, &coord, coord_cpy, &type, type_cpy, idx_mapping, + inlist, ilist, numneigh, firstneigh, jlist, + frame_nall, mem_cpy, mem_nnei, max_nbor_size, + box, mesh_tensor.flat().data(), nloc, nei_mode, rcut_r, max_cpy_trial, max_nnei_trial); // launch the cpu compute function prod_env_mat_a_cpu( em, em_deriv, rij, nlist, - coord, type, inlist, max_nbor_size, avg, std, nloc, new_nall, rcut_r, rcut_r_smth, sec_a); + coord, type, inlist, max_nbor_size, avg, std, nloc, frame_nall, rcut_r, rcut_r_smth, sec_a); // do nlist mapping if coords were copied if(b_nlist_map) _map_nlist_cpu(nlist, &idx_mapping[0], nloc, nnei); } @@ -337,6 +342,10 @@ class ProdEnvMatROp : public OpKernel { ndescrpt = sec.back() * 1; nnei = sec.back(); max_nbor_size = 1024; + max_cpy_trial = 100; + mem_cpy = 256; + max_nnei_trial = 100; + mem_nnei = 256; } void Compute(OpKernelContext* context) override { @@ -379,6 +388,28 @@ class ProdEnvMatROp : public OpKernel { OP_REQUIRES (context, (9 == box_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of box should be 9")); OP_REQUIRES (context, (ndescrpt == avg_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of avg should be ndescrpt")); OP_REQUIRES (context, (ndescrpt == std_tensor.shape().dim_size(1)), errors::InvalidArgument ("number of std should be ndescrpt")); + + int nei_mode = 0; + bool b_nlist_map = false; + if (mesh_tensor.shape().dim_size(0) == 16) { + // lammps neighbor list + nei_mode = 3; + } + else if (mesh_tensor.shape().dim_size(0) == 6) { + // manual copied pbc + assert (nloc == nall); + nei_mode = 1; + b_nlist_map = true; + } + else if (mesh_tensor.shape().dim_size(0) == 0) { + // no pbc + assert (nloc == nall); + nei_mode = -1; + } + else { + throw std::runtime_error("invalid mesh tensor"); + } + // Create an output tensor TensorShape descrpt_shape ; descrpt_shape.AddDim (nsamples); @@ -415,14 +446,25 @@ class ProdEnvMatROp : public OpKernel { nlist_shape, &nlist_tensor)); - FPTYPE * em = descrpt_tensor->flat().data(); - FPTYPE * em_deriv = descrpt_deriv_tensor->flat().data(); - FPTYPE * rij = rij_tensor->flat().data(); - int * nlist = nlist_tensor->flat().data(); - const FPTYPE * coord = coord_tensor.flat().data(); + FPTYPE * p_em = descrpt_tensor->flat().data(); + FPTYPE * p_em_deriv = descrpt_deriv_tensor->flat().data(); + FPTYPE * p_rij = rij_tensor->flat().data(); + int * p_nlist = nlist_tensor->flat().data(); + const FPTYPE * p_coord = coord_tensor.flat().data(); + const FPTYPE * p_box = box_tensor.flat().data(); const FPTYPE * avg = avg_tensor.flat().data(); const FPTYPE * std = std_tensor.flat().data(); - const int * type = type_tensor.flat().data(); + const int * p_type = type_tensor.flat().data(); + + // loop over samples + for(int ff = 0; ff < nsamples; ++ff){ + FPTYPE * em = p_em + ff*nloc*ndescrpt; + FPTYPE * em_deriv = p_em_deriv + ff*nloc*ndescrpt*3; + FPTYPE * rij = p_rij + ff*nloc*nnei*3; + int * nlist = p_nlist + ff*nloc*nnei; + const FPTYPE * coord = p_coord + ff*nall*3; + const FPTYPE * box = p_box + ff*9; + const int * type = p_type + ff*nall; if(device == "GPU") { #if GOOGLE_CUDA @@ -452,22 +494,27 @@ class ProdEnvMatROp : public OpKernel { #endif //GOOGLE_CUDA } else if (device == "CPU") { - // memcpy (&ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); - // memcpy (&jrange, 8 + mesh_tensor.flat().data(), sizeof(int *)); - // memcpy (&jlist, 12 + mesh_tensor.flat().data(), sizeof(int *)); - // launch the cpu compute function - // prod_env_mat_r_cpu( - // em, em_deriv, rij, nlist, - // coord, type, ilist, jrange, jlist, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); InputNlist inlist; - inlist.inum = nloc; - memcpy(&inlist.ilist, 4 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy(&inlist.numneigh, 8 + mesh_tensor.flat().data(), sizeof(int *)); - memcpy(&inlist.firstneigh, 12 + mesh_tensor.flat().data(), sizeof(int **)); - max_nbor_size = max_numneigh(inlist); + // some buffers, be freed after the evaluation of this frame + std::vector idx_mapping; + std::vector ilist(nloc), numneigh(nloc); + std::vector firstneigh(nloc); + std::vector> jlist(nloc); + std::vector coord_cpy; + std::vector type_cpy; + int frame_nall = nall; + // prepare coord and nlist + _prepare_coord_nlist_cpu( + context, &coord, coord_cpy, &type, type_cpy, idx_mapping, + inlist, ilist, numneigh, firstneigh, jlist, + frame_nall, mem_cpy, mem_nnei, max_nbor_size, + box, mesh_tensor.flat().data(), nloc, nei_mode, rcut, max_cpy_trial, max_nnei_trial); + // launch the cpu compute function prod_env_mat_r_cpu( em, em_deriv, rij, nlist, - coord, type, inlist, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); + coord, type, inlist, max_nbor_size, avg, std, nloc, frame_nall, rcut, rcut_smth, sec); + if(b_nlist_map) _map_nlist_cpu(nlist, &idx_mapping[0], nloc, nnei); + } } } @@ -481,6 +528,8 @@ class ProdEnvMatROp : public OpKernel { std::vector sec; std::vector sec_null; int nnei, ndescrpt, nloc, nall, max_nbor_size; + int mem_cpy, max_cpy_trial; + int mem_nnei, max_nnei_trial; std::string device; int * array_int = NULL; unsigned long long * array_longlong = NULL; @@ -488,6 +537,9 @@ class ProdEnvMatROp : public OpKernel { int * nbor_list_dev = NULL; }; + + + template static int _norm_copy_coord_cpu( @@ -578,6 +630,61 @@ _map_nlist_cpu( } } +template +static void +_prepare_coord_nlist_cpu( + OpKernelContext* context, + FPTYPE const ** coord, + std::vector & coord_cpy, + int const** type, + std::vector & type_cpy, + std::vector & idx_mapping, + InputNlist & inlist, + std::vector & ilist, + std::vector & numneigh, + std::vector & firstneigh, + std::vector> & jlist, + int & new_nall, + int & mem_cpy, + int & mem_nnei, + int & max_nbor_size, + const FPTYPE * box, + const int * mesh_tensor_data, + const int & nloc, + const int & nei_mode, + const float & rcut_r, + const int & max_cpy_trial, + const int & max_nnei_trial) +{ + inlist.inum = nloc; + if(nei_mode != 3){ + // build nlist by myself + // normalize and copy coord + if(nei_mode == 1){ + int copy_ok = _norm_copy_coord_cpu( + coord_cpy, type_cpy, idx_mapping, new_nall, mem_cpy, + *coord, box, *type, nloc, max_cpy_trial, rcut_r); + OP_REQUIRES (context, copy_ok, errors::Aborted("cannot allocate mem for copied coords")); + *coord = &coord_cpy[0]; + *type = &type_cpy[0]; + } + // build nlist + int build_ok = _build_nlist_cpu( + ilist, numneigh, firstneigh, jlist, max_nbor_size, mem_nnei, + *coord, nloc, new_nall, max_nnei_trial, rcut_r); + OP_REQUIRES (context, build_ok, errors::Aborted("cannot allocate mem for nlist")); + inlist.ilist = &ilist[0]; + inlist.numneigh = &numneigh[0]; + inlist.firstneigh = &firstneigh[0]; + } + else{ + // copy pointers to nlist data + memcpy(&inlist.ilist, 4 + mesh_tensor_data, sizeof(int *)); + memcpy(&inlist.numneigh, 8 + mesh_tensor_data, sizeof(int *)); + memcpy(&inlist.firstneigh, 12 + mesh_tensor_data, sizeof(int **)); + max_nbor_size = max_numneigh(inlist); + } +} // Register the CPU kernels. From f8d3bfba9ac480b87fea2abf4cf8d3548f3733d7 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 12 Mar 2021 11:30:58 +0800 Subject: [PATCH 266/562] update names of the c++ api --- .../include/{NNPAtomMap.h => AtomMap.h} | 6 +- source/api_cc/include/DataModifier.h | 4 +- .../api_cc/include/{NNPInter.h => DeepPot.h} | 20 +-- source/api_cc/include/DeepTensor.h | 4 +- source/api_cc/include/common.h | 12 +- .../api_cc/src/{NNPAtomMap.cc => AtomMap.cc} | 18 +- source/api_cc/src/DataModifier.cc | 22 +-- source/api_cc/src/{NNPInter.cc => DeepPot.cc} | 156 +++++++++--------- source/api_cc/src/DeepTensor.cc | 22 +-- source/api_cc/src/common.cc | 16 +- source/api_cc/tests/test_deeppot_a.cc | 6 +- .../api_cc/tests/test_deeppot_model_devi.cc | 8 +- source/api_cc/tests/test_deeppot_r.cc | 6 +- source/api_cc/tests/test_dipolecharge.cc | 2 +- source/cmake/cmake_lammps.cmake.in | 2 +- source/ipi/driver.cc | 4 +- source/lmp/CMakeLists.txt | 2 +- source/lmp/fix_dplr.cpp | 12 +- source/lmp/fix_dplr.h | 4 +- source/lmp/{pair_nnp.cpp => pair_deepmd.cpp} | 126 +++++++------- .../lmp/{pair_nnp.h.in => pair_deepmd.h.in} | 14 +- 21 files changed, 233 insertions(+), 233 deletions(-) rename source/api_cc/include/{NNPAtomMap.h => AtomMap.h} (88%) rename source/api_cc/include/{NNPInter.h => DeepPot.h} (93%) rename source/api_cc/src/{NNPAtomMap.cc => AtomMap.cc} (85%) rename source/api_cc/src/{NNPInter.cc => DeepPot.cc} (89%) rename source/lmp/{pair_nnp.cpp => pair_deepmd.cpp} (86%) rename source/lmp/{pair_nnp.h.in => pair_deepmd.h.in} (93%) diff --git a/source/api_cc/include/NNPAtomMap.h b/source/api_cc/include/AtomMap.h similarity index 88% rename from source/api_cc/include/NNPAtomMap.h rename to source/api_cc/include/AtomMap.h index 6d537fd99b..32c4ed7c99 100644 --- a/source/api_cc/include/NNPAtomMap.h +++ b/source/api_cc/include/AtomMap.h @@ -5,11 +5,11 @@ // using namespace std; template -class NNPAtomMap +class AtomMap { public: - NNPAtomMap(); - NNPAtomMap(const std::vector::const_iterator in_begin, + AtomMap(); + AtomMap(const std::vector::const_iterator in_begin, const std::vector::const_iterator in_end); void forward (typename std::vector::iterator out, const typename std::vector::const_iterator in, diff --git a/source/api_cc/include/DataModifier.h b/source/api_cc/include/DataModifier.h index 8d16d2ad6d..822812621b 100644 --- a/source/api_cc/include/DataModifier.h +++ b/source/api_cc/include/DataModifier.h @@ -1,6 +1,6 @@ #pragma once -#include "NNPInter.h" +#include "DeepPot.h" class DipoleChargeModifier { @@ -44,7 +44,7 @@ class DipoleChargeModifier std::vector & dvirial, Session * session, const std::vector> & input_tensors, - const NNPAtomMap & nnpmap, + const AtomMap & atommap, const int nghost); }; diff --git a/source/api_cc/include/NNPInter.h b/source/api_cc/include/DeepPot.h similarity index 93% rename from source/api_cc/include/NNPInter.h rename to source/api_cc/include/DeepPot.h index 2586bfd89e..ba6162a62b 100644 --- a/source/api_cc/include/NNPInter.h +++ b/source/api_cc/include/DeepPot.h @@ -4,12 +4,12 @@ #include "neighbor_list.h" typedef double compute_t; -class NNPInter +class DeepPot { public: - NNPInter () ; - ~NNPInter() ; - NNPInter (const std::string & model, const int & gpu_rank = 0, const std::string & file_content = ""); + DeepPot () ; + ~DeepPot() ; + DeepPot (const std::string & model, const int & gpu_rank = 0, const std::string & file_content = ""); void init (const std::string & model, const int & gpu_rank = 0, const std::string & file_content = ""); void print_summary(const std::string &pre) const; public: @@ -93,18 +93,18 @@ class NNPInter compute_t *array_double; NeighborListData nlist_data; InputNlist nlist; - NNPAtomMap nnpmap; + AtomMap atommap; // function used for neighbor list copy std::vector get_sel_a() const; }; -class NNPInterModelDevi +class DeepPotModelDevi { public: - NNPInterModelDevi () ; - ~NNPInterModelDevi() ; - NNPInterModelDevi (const std::vector & models, const int & gpu_rank = 0, const std::vector & file_contents = std::vector()); + DeepPotModelDevi () ; + ~DeepPotModelDevi() ; + DeepPotModelDevi (const std::vector & models, const int & gpu_rank = 0, const std::vector & file_contents = std::vector()); void init (const std::vector & models, const int & gpu_rank = 0, const std::vector & file_contents = std::vector()); public: void compute (std::vector & all_ener, @@ -174,7 +174,7 @@ class NNPInterModelDevi bool init_nbor; compute_t *array_double; std::vector > sec; - NNPAtomMap nnpmap; + AtomMap atommap; NeighborListData nlist_data; InputNlist nlist; diff --git a/source/api_cc/include/DeepTensor.h b/source/api_cc/include/DeepTensor.h index ec2c7de22b..786908f295 100644 --- a/source/api_cc/include/DeepTensor.h +++ b/source/api_cc/include/DeepTensor.h @@ -1,6 +1,6 @@ #pragma once -#include "NNPInter.h" +#include "DeepPot.h" class DeepTensor { @@ -45,7 +45,7 @@ class DeepTensor void run_model (std::vector & d_tensor_, Session * session, const std::vector> & input_tensors, - const NNPAtomMap & nnpmap, + const AtomMap & atommap, const int nghost = 0); void compute_inner (std::vector & value, const std::vector & coord, diff --git a/source/api_cc/include/common.h b/source/api_cc/include/common.h index 9e2110b03b..698ebe04ed 100644 --- a/source/api_cc/include/common.h +++ b/source/api_cc/include/common.h @@ -5,7 +5,7 @@ #include #include "version.h" #include "neighbor_list.h" -#include "NNPAtomMap.h" +#include "AtomMap.h" #include "tensorflow/core/platform/env.h" #include "tensorflow/core/public/session.h" @@ -37,7 +37,7 @@ struct NeighborListData public: void copy_from_nlist(const InputNlist & inlist); void shuffle(const std::vector & fwd_map); - void shuffle(const NNPAtomMap & map); + void shuffle(const AtomMap & map); void shuffle_exclude_empty(const std::vector & fwd_map); void make_inlist(InputNlist & inlist); }; @@ -93,7 +93,7 @@ session_input_tensors (std::vector> & input_tenso const VALUETYPE & cell_size, const std::vector & fparam_, const std::vector & aparam_, - const NNPAtomMap& nnpmap, + const AtomMap& atommap, const std::string scope = ""); int @@ -105,7 +105,7 @@ session_input_tensors (std::vector> & input_tenso InputNlist & dlist, const std::vector & fparam_, const std::vector & aparam_, - const NNPAtomMap& nnpmap, + const AtomMap& atommap, const int nghost, const int ago, const std::string scope = ""); @@ -119,7 +119,7 @@ session_input_tensors (std::vector> & input_tenso // InputNlist & dlist, // const std::vector & fparam_, // const std::vector & aparam_, -// const NNPAtomMap& nnpmap, +// const AtomMap& atommap, // const int nghost, // const std::string scope = ""); @@ -134,7 +134,7 @@ session_input_tensors (std::vector> & input_tenso // const int * jlist, // const std::vector & fparam_, // const std::vector & aparam_, -// const NNPAtomMap & nnpmap, +// const AtomMap & atommap, // const int & nghost); diff --git a/source/api_cc/src/NNPAtomMap.cc b/source/api_cc/src/AtomMap.cc similarity index 85% rename from source/api_cc/src/NNPAtomMap.cc rename to source/api_cc/src/AtomMap.cc index 5529bbc0ac..dc37669fa6 100644 --- a/source/api_cc/src/NNPAtomMap.cc +++ b/source/api_cc/src/AtomMap.cc @@ -1,15 +1,15 @@ -#include "NNPAtomMap.h" +#include "AtomMap.h" #include #include template -NNPAtomMap:: -NNPAtomMap() {} +AtomMap:: +AtomMap() {} template -NNPAtomMap:: -NNPAtomMap(const std::vector::const_iterator in_begin, +AtomMap:: +AtomMap(const std::vector::const_iterator in_begin, const std::vector::const_iterator in_end) { int natoms = in_end - in_begin; @@ -31,7 +31,7 @@ NNPAtomMap(const std::vector::const_iterator in_begin, template void -NNPAtomMap:: +AtomMap:: forward (typename std::vector::iterator out, const typename std::vector::const_iterator in, const int stride) const @@ -48,7 +48,7 @@ forward (typename std::vector::iterator out, template void -NNPAtomMap:: +AtomMap:: backward (typename std::vector::iterator out, const typename std::vector::const_iterator in, const int stride) const @@ -63,6 +63,6 @@ backward (typename std::vector::iterator out, } } -template class NNPAtomMap; -template class NNPAtomMap; +template class AtomMap; +template class AtomMap; diff --git a/source/api_cc/src/DataModifier.cc b/source/api_cc/src/DataModifier.cc index 49e62be76c..94ebadf724 100644 --- a/source/api_cc/src/DataModifier.cc +++ b/source/api_cc/src/DataModifier.cc @@ -68,10 +68,10 @@ run_model (std::vector & dforce, std::vector & dvirial, Session * session, const std::vector> & input_tensors, - const NNPAtomMap & nnpmap, + const AtomMap & atommap, const int nghost) { - unsigned nloc = nnpmap.get_type().size(); + unsigned nloc = atommap.get_type().size(); unsigned nall = nloc + nghost; if (nloc == 0) { dforce.clear(); @@ -158,17 +158,17 @@ compute (std::vector & dfcorr_, nlist_data.copy_from_nlist(lmp_list); nlist_data.shuffle_exclude_empty(real_fwd_map); // sort atoms - NNPAtomMap nnpmap (datype_real.begin(), datype_real.begin() + nloc_real); - assert (nloc_real == nnpmap.get_type().size()); - const std::vector & sort_fwd_map(nnpmap.get_fwd_map()); - const std::vector & sort_bkw_map(nnpmap.get_bkw_map()); + AtomMap atommap (datype_real.begin(), datype_real.begin() + nloc_real); + assert (nloc_real == atommap.get_type().size()); + const std::vector & sort_fwd_map(atommap.get_fwd_map()); + const std::vector & sort_bkw_map(atommap.get_bkw_map()); // shuffle nlist - nlist_data.shuffle(nnpmap); + nlist_data.shuffle(atommap); InputNlist nlist; nlist_data.make_inlist(nlist); // make input tensors std::vector> input_tensors; - int ret = session_input_tensors (input_tensors, dcoord_real, ntypes, datype_real, dbox, nlist, std::vector(), std::vector(), nnpmap, nghost_real, 0, name_scope); + int ret = session_input_tensors (input_tensors, dcoord_real, ntypes, datype_real, dbox, nlist, std::vector(), std::vector(), atommap, nghost_real, 0, name_scope); assert (nloc_real == ret); // make bond idx map std::vector bd_idx(nall, -1); @@ -176,7 +176,7 @@ compute (std::vector & dfcorr_, bd_idx[pairs[ii].first] = pairs[ii].second; } // make extf by bond idx map - std::vector dtype_sort_loc = nnpmap.get_type(); + std::vector dtype_sort_loc = atommap.get_type(); std::vector dextf; for(int ii = 0; ii < dtype_sort_loc.size(); ++ii){ if (binary_search(sel_type.begin(), sel_type.end(), dtype_sort_loc[ii])){ @@ -211,11 +211,11 @@ compute (std::vector & dfcorr_, input_tensors.push_back({"t_ef", extf_tensor}); // run model std::vector dfcorr, dvcorr; - run_model (dfcorr, dvcorr, session, input_tensors, nnpmap, nghost_real); + run_model (dfcorr, dvcorr, session, input_tensors, atommap, nghost_real); assert(dfcorr.size() == nall_real * 3); // back map force std::vector dfcorr_1 = dfcorr; - nnpmap.backward (dfcorr_1.begin(), dfcorr.begin(), 3); + atommap.backward (dfcorr_1.begin(), dfcorr.begin(), 3); assert(dfcorr_1.size() == nall_real * 3); // resize to all and clear std::vector dfcorr_2(nall*3); diff --git a/source/api_cc/src/NNPInter.cc b/source/api_cc/src/DeepPot.cc similarity index 89% rename from source/api_cc/src/NNPInter.cc rename to source/api_cc/src/DeepPot.cc index 55686bde81..6666af6f21 100644 --- a/source/api_cc/src/NNPInter.cc +++ b/source/api_cc/src/DeepPot.cc @@ -1,5 +1,5 @@ -#include "NNPInter.h" -#include "NNPAtomMap.h" +#include "DeepPot.h" +#include "AtomMap.h" #include "SimulationRegion.h" #include @@ -37,10 +37,10 @@ run_model (ENERGYTYPE & dener, std::vector & dvirial, Session * session, const std::vector> & input_tensors, - const NNPAtomMap& nnpmap, + const AtomMap& atommap, const int nghost = 0) { - unsigned nloc = nnpmap.get_type().size(); + unsigned nloc = atommap.get_type().size(); unsigned nall = nloc + nghost; if (nloc == 0) { dener = 0; @@ -86,7 +86,7 @@ run_model (ENERGYTYPE & dener, dvirial[8] += 1.0 * oav(9*ii+8); } dforce_ = dforce; - nnpmap.backward (dforce_.begin(), dforce.begin(), 3); + atommap.backward (dforce_.begin(), dforce.begin(), 3); } static void run_model (ENERGYTYPE & dener, @@ -96,10 +96,10 @@ static void run_model (ENERGYTYPE & dener, std::vector& datom_virial_, Session* session, const std::vector> & input_tensors, - const NNPAtomMap & nnpmap, + const AtomMap & atommap, const int& nghost = 0) { - unsigned nloc = nnpmap.get_type().size(); + unsigned nloc = atommap.get_type().size(); unsigned nall = nloc + nghost; if (nloc == 0) { dener = 0; @@ -163,31 +163,31 @@ static void run_model (ENERGYTYPE & dener, dforce_ = dforce; datom_energy_ = datom_energy; datom_virial_ = datom_virial; - nnpmap.backward (dforce_.begin(), dforce.begin(), 3); - nnpmap.backward (datom_energy_.begin(), datom_energy.begin(), 1); - nnpmap.backward (datom_virial_.begin(), datom_virial.begin(), 9); + atommap.backward (dforce_.begin(), dforce.begin(), 3); + atommap.backward (datom_energy_.begin(), datom_energy.begin(), 1); + atommap.backward (datom_virial_.begin(), datom_virial.begin(), 9); } -NNPInter:: -NNPInter () +DeepPot:: +DeepPot () : inited (false), init_nbor (false) { get_env_nthreads(num_intra_nthreads, num_inter_nthreads); } -NNPInter:: -NNPInter (const std::string & model, const int & gpu_rank, const std::string & file_content) +DeepPot:: +DeepPot (const std::string & model, const int & gpu_rank, const std::string & file_content) : inited (false), init_nbor (false) { get_env_nthreads(num_intra_nthreads, num_inter_nthreads); init(model, gpu_rank, file_content); } -NNPInter::~NNPInter() {} +DeepPot::~DeepPot() {} void -NNPInter:: +DeepPot:: init (const std::string & model, const int & gpu_rank, const std::string & file_content) { if (inited){ @@ -231,7 +231,7 @@ init (const std::string & model, const int & gpu_rank, const std::string & file_ } void -NNPInter:: +DeepPot:: print_summary(const std::string &pre) const { std::cout << pre << "installed to: " + global_install_prefix << std::endl; @@ -248,7 +248,7 @@ print_summary(const std::string &pre) const template VT -NNPInter:: +DeepPot:: get_scalar (const std::string & name) const { return session_get_scalar(session, name); @@ -276,7 +276,7 @@ std::string graph_info(const GraphDef & graph_def) { } // init the tmp array data -std::vector NNPInter::get_sel_a () const { +std::vector DeepPot::get_sel_a () const { std::vector sel_a; std::istringstream is(graph_info(graph_def)); std::string line = ""; @@ -300,7 +300,7 @@ std::vector NNPInter::get_sel_a () const { } void -NNPInter:: +DeepPot:: validate_fparam_aparam(const int & nloc, const std::vector &fparam, const std::vector &aparam)const @@ -314,7 +314,7 @@ validate_fparam_aparam(const int & nloc, } void -NNPInter:: +DeepPot:: compute (ENERGYTYPE & dener, std::vector & dforce_, std::vector & dvirial, @@ -326,19 +326,19 @@ compute (ENERGYTYPE & dener, { int nall = dcoord_.size() / 3; int nloc = nall; - nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); - assert (nloc == nnpmap.get_type().size()); + atommap = AtomMap (datype_.begin(), datype_.begin() + nloc); + assert (nloc == atommap.get_type().size()); validate_fparam_aparam(nloc, fparam, aparam); std::vector> input_tensors; - int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, fparam, aparam, nnpmap); + int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, fparam, aparam, atommap); assert (ret == nloc); - run_model (dener, dforce_, dvirial, session, input_tensors, nnpmap); + run_model (dener, dforce_, dvirial, session, input_tensors, atommap); } void -NNPInter:: +DeepPot:: compute (ENERGYTYPE & dener, std::vector & dforce_, std::vector & dvirial, @@ -378,7 +378,7 @@ compute (ENERGYTYPE & dener, } void -NNPInter:: +DeepPot:: compute_inner (ENERGYTYPE & dener, std::vector & dforce_, std::vector & dvirial, @@ -398,19 +398,19 @@ compute_inner (ENERGYTYPE & dener, // agp == 0 means that the LAMMPS nbor list has been updated if (ago == 0) { - nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); - assert (nloc == nnpmap.get_type().size()); - nlist_data.shuffle(nnpmap); + atommap = AtomMap (datype_.begin(), datype_.begin() + nloc); + assert (nloc == atommap.get_type().size()); + nlist_data.shuffle(atommap); nlist_data.make_inlist(nlist); } - int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, nnpmap, nghost, ago); + int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, atommap, nghost, ago); assert (nloc == ret); - run_model (dener, dforce_, dvirial, session, input_tensors, nnpmap, nghost); + run_model (dener, dforce_, dvirial, session, input_tensors, atommap, nghost); } void -NNPInter:: +DeepPot:: compute (ENERGYTYPE & dener, std::vector & dforce_, std::vector & dvirial, @@ -422,19 +422,19 @@ compute (ENERGYTYPE & dener, const std::vector & fparam, const std::vector & aparam) { - nnpmap = NNPAtomMap (datype_.begin(), datype_.end()); - validate_fparam_aparam(nnpmap.get_type().size(), fparam, aparam); + atommap = AtomMap (datype_.begin(), datype_.end()); + validate_fparam_aparam(atommap.get_type().size(), fparam, aparam); std::vector> input_tensors; - int nloc = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, fparam, aparam, nnpmap); + int nloc = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, fparam, aparam, atommap); - run_model (dener, dforce_, dvirial, datom_energy_, datom_virial_, session, input_tensors, nnpmap); + run_model (dener, dforce_, dvirial, datom_energy_, datom_virial_, session, input_tensors, atommap); } void -NNPInter:: +DeepPot:: compute (ENERGYTYPE & dener, std::vector & dforce_, std::vector & dvirial, @@ -455,29 +455,29 @@ compute (ENERGYTYPE & dener, std::vector> input_tensors; if (ago == 0) { - nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); - assert (nloc == nnpmap.get_type().size()); + atommap = AtomMap (datype_.begin(), datype_.begin() + nloc); + assert (nloc == atommap.get_type().size()); nlist_data.copy_from_nlist(lmp_list); - nlist_data.shuffle(nnpmap); + nlist_data.shuffle(atommap); nlist_data.make_inlist(nlist); } - int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, nnpmap, nghost, ago); + int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, atommap, nghost, ago); assert (nloc == ret); - run_model (dener, dforce_, dvirial, datom_energy_, datom_virial_, session, input_tensors, nnpmap, nghost); + run_model (dener, dforce_, dvirial, datom_energy_, datom_virial_, session, input_tensors, atommap, nghost); } void -NNPInter:: +DeepPot:: get_type_map(std::string & type_map){ type_map = get_scalar("model_attr/tmap"); } -NNPInterModelDevi:: -NNPInterModelDevi () +DeepPotModelDevi:: +DeepPotModelDevi () : inited (false), init_nbor (false), numb_models (0) @@ -485,8 +485,8 @@ NNPInterModelDevi () get_env_nthreads(num_intra_nthreads, num_inter_nthreads); } -NNPInterModelDevi:: -NNPInterModelDevi (const std::vector & models, const int & gpu_rank, const std::vector & file_contents) +DeepPotModelDevi:: +DeepPotModelDevi (const std::vector & models, const int & gpu_rank, const std::vector & file_contents) : inited (false), init_nbor(false), numb_models (0) @@ -495,10 +495,10 @@ NNPInterModelDevi (const std::vector & models, const int & gpu_rank init(models, gpu_rank, file_contents); } -NNPInterModelDevi::~NNPInterModelDevi() {} +DeepPotModelDevi::~DeepPotModelDevi() {} void -NNPInterModelDevi:: +DeepPotModelDevi:: init (const std::vector & models, const int & gpu_rank, const std::vector & file_contents) { if (inited){ @@ -558,7 +558,7 @@ init (const std::vector & models, const int & gpu_rank, const std:: template VT -NNPInterModelDevi:: +DeepPotModelDevi:: get_scalar(const std::string name) const { VT myrcut = 0; @@ -576,7 +576,7 @@ get_scalar(const std::string name) const // init the tmp array data std::vector > -NNPInterModelDevi:: +DeepPotModelDevi:: get_sel () const { std::vector > sec; @@ -606,7 +606,7 @@ get_sel () const } void -NNPInterModelDevi:: +DeepPotModelDevi:: cum_sum (const std::vector > n_sel) { for (int ii = 0; ii < numb_models; ++ii) { @@ -621,7 +621,7 @@ cum_sum (const std::vector > n_sel) } void -NNPInterModelDevi:: +DeepPotModelDevi:: validate_fparam_aparam(const int & nloc, const std::vector &fparam, const std::vector &aparam)const @@ -635,7 +635,7 @@ validate_fparam_aparam(const int & nloc, } // void -// NNPInterModelDevi:: +// DeepPotModelDevi:: // compute (ENERGYTYPE & dener, // std::vector & dforce_, // std::vector & dvirial, @@ -648,18 +648,18 @@ validate_fparam_aparam(const int & nloc, // { // if (numb_models == 0) return; -// nnpmap = NNPAtomMap (datype_.begin(), datype_.end()); -// validate_fparam_aparam(nnpmap.get_type().size(), fparam, aparam); +// atommap = AtomMap (datype_.begin(), datype_.end()); +// validate_fparam_aparam(atommap.get_type().size(), fparam, aparam); // std::vector> input_tensors; -// int nloc = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, fparam, aparam, nnpmap); +// int nloc = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, fparam, aparam, atommap); // std::vector all_energy (numb_models); // std::vector > all_force (numb_models); // std::vector > all_virial (numb_models); // for (unsigned ii = 0; ii < numb_models; ++ii){ -// run_model (all_energy[ii], all_force[ii], all_virial[ii], sessions[ii], input_tensors, nnpmap); +// run_model (all_energy[ii], all_force[ii], all_virial[ii], sessions[ii], input_tensors, atommap); // } // dener = 0; @@ -682,7 +682,7 @@ validate_fparam_aparam(const int & nloc, // } void -NNPInterModelDevi:: +DeepPotModelDevi:: compute (std::vector & all_energy, std::vector> & all_force, std::vector> & all_virial, @@ -703,26 +703,26 @@ compute (std::vector & all_energy, // agp == 0 means that the LAMMPS nbor list has been updated if (ago == 0) { - nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); - assert (nloc == nnpmap.get_type().size()); + atommap = AtomMap (datype_.begin(), datype_.begin() + nloc); + assert (nloc == atommap.get_type().size()); nlist_data.copy_from_nlist(lmp_list); - nlist_data.shuffle(nnpmap); + nlist_data.shuffle(atommap); nlist_data.make_inlist(nlist); } - int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, nnpmap, nghost, ago); + int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, atommap, nghost, ago); all_energy.resize (numb_models); all_force.resize (numb_models); all_virial.resize (numb_models); assert (nloc == ret); for (unsigned ii = 0; ii < numb_models; ++ii) { - run_model (all_energy[ii], all_force[ii], all_virial[ii], sessions[ii], input_tensors, nnpmap, nghost); + run_model (all_energy[ii], all_force[ii], all_virial[ii], sessions[ii], input_tensors, atommap, nghost); } } void -NNPInterModelDevi:: +DeepPotModelDevi:: compute (std::vector & all_energy, std::vector> & all_force, std::vector> & all_virial, @@ -745,14 +745,14 @@ compute (std::vector & all_energy, // agp == 0 means that the LAMMPS nbor list has been updated if (ago == 0) { - nnpmap = NNPAtomMap (datype_.begin(), datype_.begin() + nloc); - assert (nloc == nnpmap.get_type().size()); + atommap = AtomMap (datype_.begin(), datype_.begin() + nloc); + assert (nloc == atommap.get_type().size()); nlist_data.copy_from_nlist(lmp_list); - nlist_data.shuffle(nnpmap); + nlist_data.shuffle(atommap); nlist_data.make_inlist(nlist); } - int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, nnpmap, nghost, ago); + int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, fparam, aparam, atommap, nghost, ago); all_energy.resize (numb_models); all_force .resize (numb_models); @@ -761,12 +761,12 @@ compute (std::vector & all_energy, all_atom_virial.resize (numb_models); assert (nloc == ret); for (unsigned ii = 0; ii < numb_models; ++ii) { - run_model (all_energy[ii], all_force[ii], all_virial[ii], all_atom_energy[ii], all_atom_virial[ii], sessions[ii], input_tensors, nnpmap, nghost); + run_model (all_energy[ii], all_force[ii], all_virial[ii], all_atom_energy[ii], all_atom_virial[ii], sessions[ii], input_tensors, atommap, nghost); } } void -NNPInterModelDevi:: +DeepPotModelDevi:: compute_avg (VALUETYPE & dener, const std::vector & all_energy) { @@ -782,7 +782,7 @@ compute_avg (VALUETYPE & dener, #ifndef HIGH_PREC void -NNPInterModelDevi:: +DeepPotModelDevi:: compute_avg (ENERGYTYPE & dener, const std::vector& all_energy) { @@ -798,7 +798,7 @@ compute_avg (ENERGYTYPE & dener, #endif void -NNPInterModelDevi:: +DeepPotModelDevi:: compute_avg (std::vector & avg, const std::vector > & xx) { @@ -821,7 +821,7 @@ compute_avg (std::vector & avg, // void -// NNPInterModelDevi:: +// DeepPotModelDevi:: // compute_std (VALUETYPE & std, // const VALUETYPE & avg, // const vector& xx) @@ -836,7 +836,7 @@ compute_avg (std::vector & avg, // } void -NNPInterModelDevi:: +DeepPotModelDevi:: compute_std_e (std::vector & std, const std::vector & avg, const std::vector >&xx) @@ -867,7 +867,7 @@ compute_std_e (std::vector & std, } void -NNPInterModelDevi:: +DeepPotModelDevi:: compute_std_f (std::vector & std, const std::vector & avg, const std::vector >&xx) @@ -901,7 +901,7 @@ compute_std_f (std::vector & std, } void -NNPInterModelDevi:: +DeepPotModelDevi:: compute_relative_std_f (std::vector &std, const std::vector &avg, const VALUETYPE eps) diff --git a/source/api_cc/src/DeepTensor.cc b/source/api_cc/src/DeepTensor.cc index 5a26b85a68..270d307013 100644 --- a/source/api_cc/src/DeepTensor.cc +++ b/source/api_cc/src/DeepTensor.cc @@ -63,10 +63,10 @@ DeepTensor:: run_model (std::vector & d_tensor_, Session * session, const std::vector> & input_tensors, - const NNPAtomMap &nnpmap, + const AtomMap &atommap, const int nghost) { - unsigned nloc = nnpmap.get_type().size(); + unsigned nloc = atommap.get_type().size(); unsigned nall = nloc + nghost; if (nloc == 0) { // return empty @@ -153,14 +153,14 @@ compute_inner (std::vector & dtensor_, { int nall = dcoord_.size() / 3; int nloc = nall; - NNPAtomMap nnpmap (datype_.begin(), datype_.begin() + nloc); - assert (nloc == nnpmap.get_type().size()); + AtomMap atommap (datype_.begin(), datype_.begin() + nloc); + assert (nloc == atommap.get_type().size()); std::vector> input_tensors; - int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, std::vector(), std::vector(), nnpmap, name_scope); + int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, cell_size, std::vector(), std::vector(), atommap, name_scope); assert (ret == nloc); - run_model (dtensor_, session, input_tensors, nnpmap); + run_model (dtensor_, session, input_tensors, atommap); } void @@ -174,18 +174,18 @@ compute_inner (std::vector & dtensor_, { int nall = dcoord_.size() / 3; int nloc = nall - nghost; - NNPAtomMap nnpmap (datype_.begin(), datype_.begin() + nloc); - assert (nloc == nnpmap.get_type().size()); + AtomMap atommap (datype_.begin(), datype_.begin() + nloc); + assert (nloc == atommap.get_type().size()); NeighborListData nlist_data; nlist_data.copy_from_nlist(nlist_); - nlist_data.shuffle(nnpmap); + nlist_data.shuffle(atommap); InputNlist nlist; nlist_data.make_inlist(nlist); std::vector> input_tensors; - int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, std::vector(), std::vector(), nnpmap, nghost, 0, name_scope); + int ret = session_input_tensors (input_tensors, dcoord_, ntypes, datype_, dbox, nlist, std::vector(), std::vector(), atommap, nghost, 0, name_scope); assert (nloc == ret); - run_model (dtensor_, session, input_tensors, nnpmap, nghost); + run_model (dtensor_, session, input_tensors, atommap, nghost); } diff --git a/source/api_cc/src/common.cc b/source/api_cc/src/common.cc index 4603c82492..55b51beda5 100644 --- a/source/api_cc/src/common.cc +++ b/source/api_cc/src/common.cc @@ -1,5 +1,5 @@ #include "common.h" -#include "NNPAtomMap.h" +#include "AtomMap.h" #include "SimulationRegion.h" #include "device.h" @@ -79,7 +79,7 @@ copy_from_nlist(const InputNlist & inlist) void NeighborListData:: -shuffle(const NNPAtomMap & map) +shuffle(const AtomMap & map) { const std::vector & fwd_map = map.get_fwd_map(); shuffle(fwd_map); @@ -201,7 +201,7 @@ session_input_tensors (std::vector> & input_tenso const VALUETYPE & cell_size, const std::vector & fparam_, const std::vector & aparam_, - const NNPAtomMap& nnpmap, + const AtomMap& atommap, const std::string scope) { bool b_pbc = (dbox.size() == 9); @@ -211,7 +211,7 @@ session_input_tensors (std::vector> & input_tenso int nloc = nall; assert (nall == datype_.size()); - std::vector datype = nnpmap.get_type(); + std::vector datype = atommap.get_type(); std::vector type_count (ntypes, 0); for (unsigned ii = 0; ii < datype.size(); ++ii){ type_count[datype[ii]] ++; @@ -267,7 +267,7 @@ session_input_tensors (std::vector> & input_tenso auto aparam = aparam_tensor.matrix (); std::vector dcoord (dcoord_); - nnpmap.forward (dcoord.begin(), dcoord_.begin(), 3); + atommap.forward (dcoord.begin(), dcoord_.begin(), 3); for (int ii = 0; ii < nframes; ++ii){ for (int jj = 0; jj < nall * 3; ++jj){ @@ -334,7 +334,7 @@ session_input_tensors (std::vector> & input_tenso InputNlist & dlist, const std::vector & fparam_, const std::vector & aparam_, - const NNPAtomMap& nnpmap, + const AtomMap& atommap, const int nghost, const int ago, const std::string scope) @@ -346,7 +346,7 @@ session_input_tensors (std::vector> & input_tenso int nloc = nall - nghost; assert (nall == datype_.size()); - std::vector datype = nnpmap.get_type(); + std::vector datype = atommap.get_type(); std::vector type_count (ntypes, 0); for (unsigned ii = 0; ii < datype.size(); ++ii){ type_count[datype[ii]] ++; @@ -397,7 +397,7 @@ session_input_tensors (std::vector> & input_tenso auto aparam = aparam_tensor.matrix (); std::vector dcoord (dcoord_); - nnpmap.forward (dcoord.begin(), dcoord_.begin(), 3); + atommap.forward (dcoord.begin(), dcoord_.begin(), 3); for (int ii = 0; ii < nframes; ++ii){ for (int jj = 0; jj < nall * 3; ++jj){ diff --git a/source/api_cc/tests/test_deeppot_a.cc b/source/api_cc/tests/test_deeppot_a.cc index 0a736a7b88..fc771f6b75 100644 --- a/source/api_cc/tests/test_deeppot_a.cc +++ b/source/api_cc/tests/test_deeppot_a.cc @@ -3,7 +3,7 @@ #include #include #include -#include "NNPInter.h" +#include "DeepPot.h" #include "SimulationRegion.h" #include "neighbor_list.h" #include "test_utils.h" @@ -44,7 +44,7 @@ class TestInferDeepPotA : public ::testing::Test double expected_tot_e; std::vectorexpected_tot_v; - NNPInter dp; + DeepPot dp; void SetUp() override { std::string file_name = "../../tests/infer/deeppot.pbtxt"; @@ -383,7 +383,7 @@ class TestInferDeepPotANoPbc : public ::testing::Test double expected_tot_e; std::vectorexpected_tot_v; - NNPInter dp; + DeepPot dp; void SetUp() override { std::string file_name = "../../tests/infer/deeppot.pbtxt"; diff --git a/source/api_cc/tests/test_deeppot_model_devi.cc b/source/api_cc/tests/test_deeppot_model_devi.cc index fced03d4eb..b700a93e0a 100644 --- a/source/api_cc/tests/test_deeppot_model_devi.cc +++ b/source/api_cc/tests/test_deeppot_model_devi.cc @@ -3,7 +3,7 @@ #include #include #include -#include "NNPInter.h" +#include "DeepPot.h" #include "SimulationRegion.h" #include "neighbor_list.h" #include "test_utils.h" @@ -33,9 +33,9 @@ class TestInferDeepPotModeDevi : public ::testing::Test }; int natoms; - NNPInter dp0; - NNPInter dp1; - NNPInterModelDevi dp_md; + DeepPot dp0; + DeepPot dp1; + DeepPotModelDevi dp_md; void SetUp() override { { diff --git a/source/api_cc/tests/test_deeppot_r.cc b/source/api_cc/tests/test_deeppot_r.cc index ca0511c810..07a5fdcc21 100644 --- a/source/api_cc/tests/test_deeppot_r.cc +++ b/source/api_cc/tests/test_deeppot_r.cc @@ -3,7 +3,7 @@ #include #include #include -#include "NNPInter.h" +#include "DeepPot.h" #include "SimulationRegion.h" #include "neighbor_list.h" #include "test_utils.h" @@ -44,7 +44,7 @@ class TestInferDeepPotR : public ::testing::Test double expected_tot_e; std::vectorexpected_tot_v; - NNPInter dp; + DeepPot dp; void SetUp() override { std::string file_name = "../../tests/infer/deeppot-r.pbtxt"; @@ -383,7 +383,7 @@ class TestInferDeepPotRNoPbc : public ::testing::Test double expected_tot_e; std::vectorexpected_tot_v; - NNPInter dp; + DeepPot dp; void SetUp() override { std::string file_name = "../../tests/infer/deeppot-r.pbtxt"; diff --git a/source/api_cc/tests/test_dipolecharge.cc b/source/api_cc/tests/test_dipolecharge.cc index 8c517057f3..81516ed63f 100644 --- a/source/api_cc/tests/test_dipolecharge.cc +++ b/source/api_cc/tests/test_dipolecharge.cc @@ -133,7 +133,7 @@ TEST_F(TestDipoleCharge, cpu_lmp_nlist) int sel_nloc = sel_nall - sel_nghost; std::vector sel_atype(sel_bwd.size()); select_map(sel_atype, atype, sel_fwd, 1); - NNPAtomMap nnp_map(sel_atype.begin(), sel_atype.begin() + sel_nloc); + AtomMap nnp_map(sel_atype.begin(), sel_atype.begin() + sel_nloc); const std::vector & sort_fwd_map(nnp_map.get_fwd_map()); // // add coords diff --git a/source/cmake/cmake_lammps.cmake.in b/source/cmake/cmake_lammps.cmake.in index 0886733a35..bee237a1c7 100644 --- a/source/cmake/cmake_lammps.cmake.in +++ b/source/cmake/cmake_lammps.cmake.in @@ -19,5 +19,5 @@ file ( file ( INSTALL DESTINATION "${LMP_INSTALL_PREFIX}" TYPE FILE - FILES "@CMAKE_BINARY_DIR@/lmp/pair_nnp.h" + FILES "@CMAKE_BINARY_DIR@/lmp/pair_deepmd.h" ) diff --git a/source/ipi/driver.cc b/source/ipi/driver.cc index 91a54504ea..605a26a1e0 100644 --- a/source/ipi/driver.cc +++ b/source/ipi/driver.cc @@ -1,7 +1,7 @@ #include #include #include "sockets.h" -#include "NNPInter.h" +#include "DeepPot.h" #include "Convert.h" #include "XyzFileManager.h" #include "SimulationRegion.h" @@ -91,7 +91,7 @@ int main(int argc, char * argv[]) } Convert cvt (atom_name, name_type_map); - NNPInter nnp_inter (graph_file); + DeepPot nnp_inter (graph_file); enum { _MSGLEN = 12 }; int MSGLEN = _MSGLEN; diff --git a/source/lmp/CMakeLists.txt b/source/lmp/CMakeLists.txt index 0a5b0be55b..bc52c8fa81 100644 --- a/source/lmp/CMakeLists.txt +++ b/source/lmp/CMakeLists.txt @@ -8,5 +8,5 @@ list (APPEND LMP_INSTALL_FILES ${LMP_SRC}) list (APPEND LMP_INSTALL_FILES ${LMP_SHSCRIPT}) configure_file("env.sh.in" "env.sh" @ONLY) -configure_file("pair_nnp.h.in" "pair_nnp.h" @ONLY) +configure_file("pair_deepmd.h.in" "pair_deepmd.h" @ONLY) configure_file("lammps_install_list.txt.in" "lammps_install_list.txt" @ONLY) diff --git a/source/lmp/fix_dplr.cpp b/source/lmp/fix_dplr.cpp index 637f36bda9..5d89ff8dad 100644 --- a/source/lmp/fix_dplr.cpp +++ b/source/lmp/fix_dplr.cpp @@ -105,8 +105,8 @@ FixDPLR::FixDPLR(LAMMPS *lmp, int narg, char **arg) dpl_type.push_back(type_asso[sel_type[ii]]); } - pair_nnp = (PairNNP *) force->pair_match("deepmd",1); - if (!pair_nnp) { + pair_deepmd = (PairDeepMD *) force->pair_match("deepmd",1); + if (!pair_deepmd) { error->all(FLERR,"pair_style deepmd should be set before this fix\n"); } @@ -262,7 +262,7 @@ void FixDPLR::pre_force(int vflag) } } // get lammps nlist - NeighList * list = pair_nnp->list; + NeighList * list = pair_deepmd->list; InputNlist lmp_list (list->inum, list->ilist, list->numneigh, list->firstneigh); // declear output vector tensor; @@ -305,8 +305,8 @@ void FixDPLR::pre_force(int vflag) vector sel_type(sel_bwd.size()); select_map(sel_type, dtype, sel_fwd, 1); - NNPAtomMap nnp_map(sel_type.begin(), sel_type.begin() + sel_nloc); - const vector & sort_fwd_map(nnp_map.get_fwd_map()); + AtomMap atom_map(sel_type.begin(), sel_type.begin() + sel_nloc); + const vector & sort_fwd_map(atom_map.get_fwd_map()); vector > valid_pairs; get_valid_pairs(valid_pairs); @@ -416,7 +416,7 @@ void FixDPLR::post_force(int vflag) } } // lmp nlist - NeighList * list = pair_nnp->list; + NeighList * list = pair_deepmd->list; InputNlist lmp_list (list->inum, list->ilist, list->numneigh, list->firstneigh); // bonded pairs vector > valid_pairs; diff --git a/source/lmp/fix_dplr.h b/source/lmp/fix_dplr.h index a1bb7e1d60..d81d8bd3db 100644 --- a/source/lmp/fix_dplr.h +++ b/source/lmp/fix_dplr.h @@ -9,7 +9,7 @@ FixStyle(dplr,FixDPLR) #include #include "fix.h" -#include "pair_nnp.h" +#include "pair_deepmd.h" #include "DeepTensor.h" #include "DataModifier.h" @@ -35,7 +35,7 @@ namespace LAMMPS_NS { double compute_scalar(void); double compute_vector(int); private: - PairNNP * pair_nnp; + PairDeepMD * pair_deepmd; DeepTensor dpt; DipoleChargeModifier dtm; std::string model; diff --git a/source/lmp/pair_nnp.cpp b/source/lmp/pair_deepmd.cpp similarity index 86% rename from source/lmp/pair_nnp.cpp rename to source/lmp/pair_deepmd.cpp index 401506df9f..859c7be34e 100644 --- a/source/lmp/pair_nnp.cpp +++ b/source/lmp/pair_deepmd.cpp @@ -20,7 +20,7 @@ #include "fix_ttm_mod.h" #endif -#include "pair_nnp.h" +#include "pair_deepmd.h" using namespace LAMMPS_NS; using namespace std; @@ -58,7 +58,7 @@ static int stringCmp(const void *a, const void* b) return sum; } -int PairNNP::get_node_rank() { +int PairDeepMD::get_node_rank() { char host_name[MPI_MAX_PROCESSOR_NAME]; memset(host_name, '\0', sizeof(char) * MPI_MAX_PROCESSOR_NAME); char (*host_names)[MPI_MAX_PROCESSOR_NAME]; @@ -105,7 +105,7 @@ int PairNNP::get_node_rank() { return looprank; } -std::string PairNNP::get_file_content(const std::string & model) { +std::string PairDeepMD::get_file_content(const std::string & model) { int myrank = 0, root = 0; MPI_Comm_rank(MPI_COMM_WORLD, &myrank); int nchar = 0; @@ -128,7 +128,7 @@ std::string PairNNP::get_file_content(const std::string & model) { return file_content; } -std::vector PairNNP::get_file_content(const std::vector & models) { +std::vector PairDeepMD::get_file_content(const std::vector & models) { std::vector file_contents(models.size()); for (unsigned ii = 0; ii < models.size(); ++ii) { file_contents[ii] = get_file_content(models[ii]); @@ -177,7 +177,7 @@ make_uniform_aparam( } #ifdef USE_TTM -void PairNNP::make_ttm_aparam( +void PairDeepMD::make_ttm_aparam( #ifdef HIGH_PREC vector & daparam #else @@ -229,7 +229,7 @@ void PairNNP::make_ttm_aparam( } #endif -PairNNP::PairNNP(LAMMPS *lmp) +PairDeepMD::PairDeepMD(LAMMPS *lmp) : Pair(lmp) { @@ -259,12 +259,12 @@ PairNNP::PairNNP(LAMMPS *lmp) } void -PairNNP::print_summary(const string pre) const +PairDeepMD::print_summary(const string pre) const { if (comm->me == 0){ cout << "Summary of lammps deepmd module ..." << endl; cout << pre << ">>> Info of deepmd-kit:" << endl; - nnp_inter.print_summary(pre); + deep_pot.print_summary(pre); cout << pre << ">>> Info of lammps module:" << endl; cout << pre << "use deepmd-kit at: " << STR_DEEPMD_ROOT << endl; cout << pre << "source: " << STR_GIT_SUMM << endl; @@ -278,7 +278,7 @@ PairNNP::print_summary(const string pre) const } -PairNNP::~PairNNP() +PairDeepMD::~PairDeepMD() { if (allocated) { memory->destroy(setflag); @@ -287,7 +287,7 @@ PairNNP::~PairNNP() } } -void PairNNP::compute(int eflag, int vflag) +void PairDeepMD::compute(int eflag, int vflag) { if (numb_models == 0) return; if (eflag || vflag) ev_setup(eflag,vflag); @@ -364,7 +364,7 @@ void PairNNP::compute(int eflag, int vflag) if (single_model || multi_models_no_mod_devi) { if ( ! (eflag_atom || vflag_atom) ) { #ifdef HIGH_PREC - nnp_inter.compute (dener, dforce, dvirial, dcoord, dtype, dbox, nghost, lmp_list, ago, fparam, daparam); + deep_pot.compute (dener, dforce, dvirial, dcoord, dtype, dbox, nghost, lmp_list, ago, fparam, daparam); #else vector dcoord_(dcoord.size()); vector dbox_(dbox.size()); @@ -373,7 +373,7 @@ void PairNNP::compute(int eflag, int vflag) vector dforce_(dforce.size(), 0); vector dvirial_(dvirial.size(), 0); double dener_ = 0; - nnp_inter.compute (dener_, dforce_, dvirial_, dcoord_, dtype, dbox_, nghost, lmp_list, ago, fparam, daparam); + deep_pot.compute (dener_, dforce_, dvirial_, dcoord_, dtype, dbox_, nghost, lmp_list, ago, fparam, daparam); for (unsigned dd = 0; dd < dforce.size(); ++dd) dforce[dd] = dforce_[dd]; for (unsigned dd = 0; dd < dvirial.size(); ++dd) dvirial[dd] = dvirial_[dd]; dener = dener_; @@ -384,7 +384,7 @@ void PairNNP::compute(int eflag, int vflag) vector deatom (nall * 1, 0); vector dvatom (nall * 9, 0); #ifdef HIGH_PREC - nnp_inter.compute (dener, dforce, dvirial, deatom, dvatom, dcoord, dtype, dbox, nghost, lmp_list, ago, fparam, daparam); + deep_pot.compute (dener, dforce, dvirial, deatom, dvatom, dcoord, dtype, dbox, nghost, lmp_list, ago, fparam, daparam); #else vector dcoord_(dcoord.size()); vector dbox_(dbox.size()); @@ -395,7 +395,7 @@ void PairNNP::compute(int eflag, int vflag) vector deatom_(dforce.size(), 0); vector dvatom_(dforce.size(), 0); double dener_ = 0; - nnp_inter.compute (dener_, dforce_, dvirial_, deatom_, dvatom_, dcoord_, dtype, dbox_, nghost, lmp_list, ago, fparam, daparam); + deep_pot.compute (dener_, dforce_, dvirial_, deatom_, dvatom_, dcoord_, dtype, dbox_, nghost, lmp_list, ago, fparam, daparam); for (unsigned dd = 0; dd < dforce.size(); ++dd) dforce[dd] = dforce_[dd]; for (unsigned dd = 0; dd < dvirial.size(); ++dd) dvirial[dd] = dvirial_[dd]; for (unsigned dd = 0; dd < deatom.size(); ++dd) deatom[dd] = deatom_[dd]; @@ -425,12 +425,12 @@ void PairNNP::compute(int eflag, int vflag) vector> all_virial; vector> all_atom_energy; vector> all_atom_virial; - nnp_inter_model_devi.compute(all_energy, all_force, all_virial, all_atom_energy, all_atom_virial, dcoord, dtype, dbox, nghost, lmp_list, ago, fparam, daparam); - // nnp_inter_model_devi.compute_avg (dener, all_energy); - // nnp_inter_model_devi.compute_avg (dforce, all_force); - // nnp_inter_model_devi.compute_avg (dvirial, all_virial); - // nnp_inter_model_devi.compute_avg (deatom, all_atom_energy); - // nnp_inter_model_devi.compute_avg (dvatom, all_atom_virial); + deep_pot_model_devi.compute(all_energy, all_force, all_virial, all_atom_energy, all_atom_virial, dcoord, dtype, dbox, nghost, lmp_list, ago, fparam, daparam); + // deep_pot_model_devi.compute_avg (dener, all_energy); + // deep_pot_model_devi.compute_avg (dforce, all_force); + // deep_pot_model_devi.compute_avg (dvirial, all_virial); + // deep_pot_model_devi.compute_avg (deatom, all_atom_energy); + // deep_pot_model_devi.compute_avg (dvatom, all_atom_virial); dener = all_energy[0]; dforce = all_force[0]; dvirial = all_virial[0]; @@ -451,12 +451,12 @@ void PairNNP::compute(int eflag, int vflag) vector> all_virial_; vector> all_atom_energy_; vector> all_atom_virial_; - nnp_inter_model_devi.compute(all_energy_, all_force_, all_virial_, all_atom_energy_, all_atom_virial_, dcoord_, dtype, dbox_, nghost, lmp_list, ago, fparam, daparam); - // nnp_inter_model_devi.compute_avg (dener_, all_energy_); - // nnp_inter_model_devi.compute_avg (dforce_, all_force_); - // nnp_inter_model_devi.compute_avg (dvirial_, all_virial_); - // nnp_inter_model_devi.compute_avg (deatom_, all_atom_energy_); - // nnp_inter_model_devi.compute_avg (dvatom_, all_atom_virial_); + deep_pot_model_devi.compute(all_energy_, all_force_, all_virial_, all_atom_energy_, all_atom_virial_, dcoord_, dtype, dbox_, nghost, lmp_list, ago, fparam, daparam); + // deep_pot_model_devi.compute_avg (dener_, all_energy_); + // deep_pot_model_devi.compute_avg (dforce_, all_force_); + // deep_pot_model_devi.compute_avg (dvirial_, all_virial_); + // deep_pot_model_devi.compute_avg (deatom_, all_atom_energy_); + // deep_pot_model_devi.compute_avg (dvatom_, all_atom_virial_); dener_ = all_energy_[0]; dforce_ = all_force_[0]; dvirial_ = all_virial_[0]; @@ -497,10 +497,10 @@ void PairNNP::compute(int eflag, int vflag) vector std_f; #ifdef HIGH_PREC vector tmp_avg_f; - nnp_inter_model_devi.compute_avg (tmp_avg_f, all_force); - nnp_inter_model_devi.compute_std_f (std_f, tmp_avg_f, all_force); + deep_pot_model_devi.compute_avg (tmp_avg_f, all_force); + deep_pot_model_devi.compute_std_f (std_f, tmp_avg_f, all_force); if (out_rel == 1){ - nnp_inter_model_devi.compute_relative_std_f (std_f, tmp_avg_f, eps); + deep_pot_model_devi.compute_relative_std_f (std_f, tmp_avg_f, eps); } #else vector tmp_avg_f_, std_f_; @@ -509,12 +509,12 @@ void PairNNP::compute(int eflag, int vflag) all_force_[ii][jj] = all_force[ii][jj]; } } - nnp_inter_model_devi.compute_avg (tmp_avg_f_, all_force_); - nnp_inter_model_devi.compute_std_f (std_f_, tmp_avg_f_, all_force_); + deep_pot_model_devi.compute_avg (tmp_avg_f_, all_force_); + deep_pot_model_devi.compute_std_f (std_f_, tmp_avg_f_, all_force_); std_f.resize(std_f_.size()); for (int dd = 0; dd < std_f_.size(); ++dd) std_f[dd] = std_f_[dd]; if (out_rel == 1){ - nnp_inter_model_devi.compute_relative_std_f (std_f_, tmp_avg_f_, eps); + deep_pot_model_devi.compute_relative_std_f (std_f_, tmp_avg_f_, eps); } #endif double min = numeric_limits::max(), max = 0, avg = 0; @@ -530,12 +530,12 @@ void PairNNP::compute(int eflag, int vflag) vector std_e; #ifdef HIGH_PREC vector tmp_avg_e; - nnp_inter_model_devi.compute_avg (tmp_avg_e, all_atom_energy); - nnp_inter_model_devi.compute_std_e (std_e, tmp_avg_e, all_atom_energy); + deep_pot_model_devi.compute_avg (tmp_avg_e, all_atom_energy); + deep_pot_model_devi.compute_std_e (std_e, tmp_avg_e, all_atom_energy); #else vector tmp_avg_e_, std_e_; - nnp_inter_model_devi.compute_avg (tmp_avg_e_, all_atom_energy_); - nnp_inter_model_devi.compute_std_e (std_e_, tmp_avg_e_, all_atom_energy_); + deep_pot_model_devi.compute_avg (tmp_avg_e_, all_atom_energy_); + deep_pot_model_devi.compute_std_e (std_e_, tmp_avg_e_, all_atom_energy_); std_e.resize(std_e_.size()); for (int dd = 0; dd < std_e_.size(); ++dd) std_e[dd] = std_e_[dd]; #endif @@ -552,9 +552,9 @@ void PairNNP::compute(int eflag, int vflag) // MPI_Reduce (&all_energy[0], &sum_e[0], numb_models, MPI_DOUBLE, MPI_SUM, 0, world); if (rank == 0) { // double avg_e = 0; - // nnp_inter_model_devi.compute_avg(avg_e, sum_e); + // deep_pot_model_devi.compute_avg(avg_e, sum_e); // double std_e_1 = 0; - // nnp_inter_model_devi.compute_std(std_e_1, avg_e, sum_e); + // deep_pot_model_devi.compute_std(std_e_1, avg_e, sum_e); fp << setw(12) << update->ntimestep << " " << setw(18) << all_e_max << " " << setw(18) << all_e_min @@ -583,7 +583,7 @@ void PairNNP::compute(int eflag, int vflag) else { if (numb_models == 1) { #ifdef HIGH_PREC - nnp_inter.compute (dener, dforce, dvirial, dcoord, dtype, dbox); + deep_pot.compute (dener, dforce, dvirial, dcoord, dtype, dbox); #else vector dcoord_(dcoord.size()); vector dbox_(dbox.size()); @@ -592,7 +592,7 @@ void PairNNP::compute(int eflag, int vflag) vector dforce_(dforce.size(), 0); vector dvirial_(dvirial.size(), 0); double dener_ = 0; - nnp_inter.compute (dener_, dforce_, dvirial_, dcoord_, dtype, dbox_); + deep_pot.compute (dener_, dforce_, dvirial_, dcoord_, dtype, dbox_); for (unsigned dd = 0; dd < dforce.size(); ++dd) dforce[dd] = dforce_[dd]; for (unsigned dd = 0; dd < dvirial.size(); ++dd) dvirial[dd] = dvirial_[dd]; dener = dener_; @@ -623,7 +623,7 @@ void PairNNP::compute(int eflag, int vflag) } -void PairNNP::allocate() +void PairDeepMD::allocate() { allocated = 1; int n = atom->ntypes; @@ -670,7 +670,7 @@ is_key (const string& input) } -void PairNNP::settings(int narg, char **arg) +void PairDeepMD::settings(int narg, char **arg) { if (narg <= 0) error->all(FLERR,"Illegal pair_style command"); @@ -687,23 +687,23 @@ void PairNNP::settings(int narg, char **arg) } numb_models = models.size(); if (numb_models == 1) { - nnp_inter.init (arg[0], get_node_rank(), get_file_content(arg[0])); - cutoff = nnp_inter.cutoff (); - numb_types = nnp_inter.numb_types(); - dim_fparam = nnp_inter.dim_fparam(); - dim_aparam = nnp_inter.dim_aparam(); + deep_pot.init (arg[0], get_node_rank(), get_file_content(arg[0])); + cutoff = deep_pot.cutoff (); + numb_types = deep_pot.numb_types(); + dim_fparam = deep_pot.dim_fparam(); + dim_aparam = deep_pot.dim_aparam(); } else { - nnp_inter.init (arg[0], get_node_rank(), get_file_content(arg[0])); - nnp_inter_model_devi.init(models, get_node_rank(), get_file_content(models)); - cutoff = nnp_inter_model_devi.cutoff(); - numb_types = nnp_inter_model_devi.numb_types(); - dim_fparam = nnp_inter_model_devi.dim_fparam(); - dim_aparam = nnp_inter_model_devi.dim_aparam(); - assert(cutoff == nnp_inter.cutoff()); - assert(numb_types == nnp_inter.numb_types()); - assert(dim_fparam == nnp_inter.dim_fparam()); - assert(dim_aparam == nnp_inter.dim_aparam()); + deep_pot.init (arg[0], get_node_rank(), get_file_content(arg[0])); + deep_pot_model_devi.init(models, get_node_rank(), get_file_content(models)); + cutoff = deep_pot_model_devi.cutoff(); + numb_types = deep_pot_model_devi.numb_types(); + dim_fparam = deep_pot_model_devi.dim_fparam(); + dim_aparam = deep_pot_model_devi.dim_aparam(); + assert(cutoff == deep_pot.cutoff()); + assert(numb_types == deep_pot.numb_types()); + assert(dim_fparam == deep_pot.dim_fparam()); + assert(dim_aparam == deep_pot.dim_aparam()); } out_freq = 100; @@ -834,7 +834,7 @@ void PairNNP::settings(int narg, char **arg) set coeffs for one or more type pairs ------------------------------------------------------------------------- */ -void PairNNP::coeff(int narg, char **arg) +void PairDeepMD::coeff(int narg, char **arg) { if (!allocated) { allocate(); @@ -867,7 +867,7 @@ void PairNNP::coeff(int narg, char **arg) } -void PairNNP::init_style() +void PairDeepMD::init_style() { int irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]->half = 0; @@ -876,7 +876,7 @@ void PairNNP::init_style() } -double PairNNP::init_one(int i, int j) +double PairDeepMD::init_one(int i, int j) { if (i > numb_types || j > numb_types) { char warning_msg[1024]; @@ -893,7 +893,7 @@ double PairNNP::init_one(int i, int j) /* ---------------------------------------------------------------------- */ -int PairNNP::pack_reverse_comm(int n, int first, double *buf) +int PairDeepMD::pack_reverse_comm(int n, int first, double *buf) { int i,m,last; @@ -911,7 +911,7 @@ int PairNNP::pack_reverse_comm(int n, int first, double *buf) /* ---------------------------------------------------------------------- */ -void PairNNP::unpack_reverse_comm(int n, int *list, double *buf) +void PairDeepMD::unpack_reverse_comm(int n, int *list, double *buf) { int i,j,m; @@ -926,7 +926,7 @@ void PairNNP::unpack_reverse_comm(int n, int *list, double *buf) } } -void *PairNNP::extract(const char *str, int &dim) +void *PairDeepMD::extract(const char *str, int &dim) { if (strcmp(str,"cut_coul") == 0) { dim = 0; diff --git a/source/lmp/pair_nnp.h.in b/source/lmp/pair_deepmd.h.in similarity index 93% rename from source/lmp/pair_nnp.h.in rename to source/lmp/pair_deepmd.h.in index 7b190525e0..6a5c24444a 100644 --- a/source/lmp/pair_nnp.h.in +++ b/source/lmp/pair_deepmd.h.in @@ -13,7 +13,7 @@ #ifdef PAIR_CLASS -PairStyle(deepmd,PairNNP) +PairStyle(deepmd,PairDeepMD) #else @@ -21,7 +21,7 @@ PairStyle(deepmd,PairNNP) #define LMP_PAIR_NNP_H #include "pair.h" -#include "NNPInter.h" +#include "DeepPot.h" #include #include @@ -50,10 +50,10 @@ PairStyle(deepmd,PairNNP) namespace LAMMPS_NS { -class PairNNP : public Pair { +class PairDeepMD : public Pair { public: - PairNNP(class LAMMPS *); - virtual ~PairNNP(); + PairDeepMD(class LAMMPS *); + virtual ~PairDeepMD(); virtual void compute(int, int); virtual void *extract(const char *, int &); void settings(int, char **); @@ -71,8 +71,8 @@ class PairNNP : public Pair { double **scale; private: - NNPInter nnp_inter; - NNPInterModelDevi nnp_inter_model_devi; + DeepPot deep_pot; + DeepPotModelDevi deep_pot_model_devi; unsigned numb_models; double cutoff; int numb_types; From ca1e99ad48f631ded733da258df49b0153e0f800 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Sat, 13 Mar 2021 01:19:45 +0800 Subject: [PATCH 267/562] Reduce the num of device memory copies --- source/lib/src/prod_env_mat.cc | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/source/lib/src/prod_env_mat.cc b/source/lib/src/prod_env_mat.cc index 23d367e10e..a900b99a5c 100644 --- a/source/lib/src/prod_env_mat.cc +++ b/source/lib/src/prod_env_mat.cc @@ -267,7 +267,6 @@ void env_mat_nbor_update( malloc_device_memory(gpu_inlist.numneigh, inum); malloc_device_memory(gpu_inlist.firstneigh, inum); } - gpu_inlist.inum = inum; memcpy_host_to_device(gpu_inlist.ilist, inlist.ilist, inum); memcpy_host_to_device(gpu_inlist.numneigh, inlist.numneigh, inum); int _max_nbor_size = max_numneigh(inlist); @@ -280,17 +279,27 @@ void env_mat_nbor_update( else { _max_nbor_size = 4096; } - if (_max_nbor_size > max_nbor_size || nbor_list_dev == NULL) { + if ( nbor_list_dev == NULL + || _max_nbor_size > max_nbor_size + || inum > gpu_inlist.inum) + { delete_device_memory(nbor_list_dev); - malloc_device_memory(nbor_list_dev, inum * max_nbor_size); + malloc_device_memory(nbor_list_dev, inum * _max_nbor_size); } + // update info + gpu_inlist.inum = inum; max_nbor_size = _max_nbor_size; - int ** _firstneigh = NULL; - _firstneigh = (int**)malloc(sizeof(int*) * inum); + + // copy nbor list from host to the device + std::vector nbor_list_host(inum * max_nbor_size, 0); + int ** _firstneigh = (int**)malloc(sizeof(int*) * inum); for (int ii = 0; ii < inum; ii++) { - memcpy_host_to_device(nbor_list_dev + ii * max_nbor_size, inlist.firstneigh[ii], inlist.numneigh[ii]); _firstneigh[ii] = nbor_list_dev + ii * max_nbor_size; + for (int jj = 0; jj < inlist.numneigh[ii]; jj++) { + nbor_list_host[ii * max_nbor_size + jj] = inlist.firstneigh[ii][jj]; + } } + memcpy_host_to_device(nbor_list_dev, &nbor_list_host[0], inum * max_nbor_size); memcpy_host_to_device(gpu_inlist.firstneigh, _firstneigh, inum); free(_firstneigh); } From 904162a9c2034f4cbe2aefa11c1a096d568647bd Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 14 Mar 2021 15:23:38 +0800 Subject: [PATCH 268/562] fix bug of ewald recp: transposed recp box --- source/lib/include/Ewald.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/lib/include/Ewald.h b/source/lib/include/Ewald.h index 8bd5ce9dfa..4f6b4119c2 100644 --- a/source/lib/include/Ewald.h +++ b/source/lib/include/Ewald.h @@ -222,13 +222,13 @@ EwaldReciprocal(VALUETYPE & ener, // \bm m and \vert m \vert^2 VALUETYPE rm[3] = {0,0,0}; rm[0] += mm0 * rec_box[0*3+0]; - rm[1] += mm0 * rec_box[1*3+0]; - rm[2] += mm0 * rec_box[2*3+0]; - rm[0] += mm1 * rec_box[0*3+1]; + rm[1] += mm0 * rec_box[0*3+1]; + rm[2] += mm0 * rec_box[0*3+2]; + rm[0] += mm1 * rec_box[1*3+0]; rm[1] += mm1 * rec_box[1*3+1]; - rm[2] += mm1 * rec_box[2*3+1]; - rm[0] += mm2 * rec_box[0*3+2]; - rm[1] += mm2 * rec_box[1*3+2]; + rm[2] += mm1 * rec_box[1*3+2]; + rm[0] += mm2 * rec_box[2*3+0]; + rm[1] += mm2 * rec_box[2*3+1]; rm[2] += mm2 * rec_box[2*3+2]; VALUETYPE nmm2 = rm[0] * rm[0] + rm[1] * rm[1] + rm[2] * rm[2]; // energy From ddef801ec3e39dfe8b212f9ff31086defe1d0dc1 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 14 Mar 2021 21:55:23 +0800 Subject: [PATCH 269/562] clean up include of SimulationRegion. Add UT for num diff of force and virial --- source/api_cc/src/DeepPot.cc | 1 - source/api_cc/src/common.cc | 1 - source/api_cc/tests/test_deepdipole.cc | 1 - source/api_cc/tests/test_deeppolar.cc | 1 - source/api_cc/tests/test_deeppot_a.cc | 47 +++++++++- .../api_cc/tests/test_deeppot_model_devi.cc | 1 - source/api_cc/tests/test_deeppot_r.cc | 45 +++++++++- source/api_cc/tests/test_ewald.cc | 78 +++++++++++++++++ source/api_cc/tests/test_utils.h | 85 +++++++++++++++++++ source/lib/include/region.h | 5 ++ source/lib/src/region.cc | 17 ++++ source/lib/tests/CMakeLists.txt | 8 ++ source/lib/tests/test_ewald.cc | 52 ++++++++++++ source/lib/tests/test_simulation_region.cc | 4 + 14 files changed, 338 insertions(+), 8 deletions(-) create mode 100644 source/api_cc/tests/test_ewald.cc create mode 100644 source/lib/tests/test_ewald.cc diff --git a/source/api_cc/src/DeepPot.cc b/source/api_cc/src/DeepPot.cc index 6666af6f21..71ca3226e9 100644 --- a/source/api_cc/src/DeepPot.cc +++ b/source/api_cc/src/DeepPot.cc @@ -1,6 +1,5 @@ #include "DeepPot.h" #include "AtomMap.h" -#include "SimulationRegion.h" #include diff --git a/source/api_cc/src/common.cc b/source/api_cc/src/common.cc index 55b51beda5..4a431602d3 100644 --- a/source/api_cc/src/common.cc +++ b/source/api_cc/src/common.cc @@ -1,6 +1,5 @@ #include "common.h" #include "AtomMap.h" -#include "SimulationRegion.h" #include "device.h" void diff --git a/source/api_cc/tests/test_deepdipole.cc b/source/api_cc/tests/test_deepdipole.cc index 1c69e72cc6..04d068ddfb 100644 --- a/source/api_cc/tests/test_deepdipole.cc +++ b/source/api_cc/tests/test_deepdipole.cc @@ -4,7 +4,6 @@ #include #include #include "DeepTensor.h" -#include "SimulationRegion.h" #include "neighbor_list.h" #include "test_utils.h" diff --git a/source/api_cc/tests/test_deeppolar.cc b/source/api_cc/tests/test_deeppolar.cc index 1d02ac5879..acae6e13e0 100644 --- a/source/api_cc/tests/test_deeppolar.cc +++ b/source/api_cc/tests/test_deeppolar.cc @@ -4,7 +4,6 @@ #include #include #include "DeepTensor.h" -#include "SimulationRegion.h" #include "neighbor_list.h" #include "test_utils.h" diff --git a/source/api_cc/tests/test_deeppot_a.cc b/source/api_cc/tests/test_deeppot_a.cc index fc771f6b75..01f5d6f421 100644 --- a/source/api_cc/tests/test_deeppot_a.cc +++ b/source/api_cc/tests/test_deeppot_a.cc @@ -4,7 +4,6 @@ #include #include #include "DeepPot.h" -#include "SimulationRegion.h" #include "neighbor_list.h" #include "test_utils.h" @@ -82,7 +81,6 @@ class TestInferDeepPotA : public ::testing::Test }; }; - TEST_F(TestInferDeepPotA, cpu_build_nlist) { double ener; @@ -101,6 +99,51 @@ TEST_F(TestInferDeepPotA, cpu_build_nlist) } } +TEST_F(TestInferDeepPotA, cpu_build_nlist_numfv) +{ + class MyModel : public EnergyModelTest + { + DeepPot & mydp; + const std::vector atype; +public: + MyModel( + DeepPot & dp_, + const std::vector & atype_ + ) : mydp(dp_), atype(atype_) {}; + virtual void compute ( + double & ener, + std::vector & force, + std::vector & virial, + const std::vector & coord, + const std::vector & box) { + mydp.compute(ener, force, virial, coord, atype, box); + } + }; + MyModel model(dp, atype); + model.test_f(coord, box); + model.test_v(coord, box); + std::vector box_(box); + box_[1] -= 0.4; + model.test_f(coord, box_); + model.test_v(coord, box_); + box_[2] += 0.5; + model.test_f(coord, box_); + model.test_v(coord, box_); + box_[4] += 0.2; + model.test_f(coord, box_); + model.test_v(coord, box_); + box_[3] -= 0.3; + model.test_f(coord, box_); + model.test_v(coord, box_); + box_[6] -= 0.7; + model.test_f(coord, box_); + model.test_v(coord, box_); + box_[7] += 0.6; + model.test_f(coord, box_); + model.test_v(coord, box_); +} + + TEST_F(TestInferDeepPotA, cpu_build_nlist_atomic) { double ener; diff --git a/source/api_cc/tests/test_deeppot_model_devi.cc b/source/api_cc/tests/test_deeppot_model_devi.cc index b700a93e0a..fc5c116924 100644 --- a/source/api_cc/tests/test_deeppot_model_devi.cc +++ b/source/api_cc/tests/test_deeppot_model_devi.cc @@ -4,7 +4,6 @@ #include #include #include "DeepPot.h" -#include "SimulationRegion.h" #include "neighbor_list.h" #include "test_utils.h" diff --git a/source/api_cc/tests/test_deeppot_r.cc b/source/api_cc/tests/test_deeppot_r.cc index 07a5fdcc21..7002a07f5a 100644 --- a/source/api_cc/tests/test_deeppot_r.cc +++ b/source/api_cc/tests/test_deeppot_r.cc @@ -4,7 +4,6 @@ #include #include #include "DeepPot.h" -#include "SimulationRegion.h" #include "neighbor_list.h" #include "test_utils.h" @@ -101,6 +100,50 @@ TEST_F(TestInferDeepPotR, cpu_build_nlist) } } +TEST_F(TestInferDeepPotR, cpu_build_nlist_numfv) +{ + class MyModel : public EnergyModelTest + { + DeepPot & mydp; + const std::vector & atype; +public: + MyModel( + DeepPot & dp_, + const std::vector & atype_ + ) : mydp(dp_), atype(atype_) {}; + virtual void compute ( + double & ener, + std::vector & force, + std::vector & virial, + const std::vector & coord, + const std::vector & box) { + mydp.compute(ener, force, virial, coord, atype, box); + } + }; + MyModel model(dp, atype); + model.test_f(coord, box); + model.test_v(coord, box); + std::vector box_(box); + box_[1] -= 0.4; + model.test_f(coord, box_); + model.test_v(coord, box_); + box_[2] += 0.5; + model.test_f(coord, box_); + model.test_v(coord, box_); + box_[4] += 0.2; + model.test_f(coord, box_); + model.test_v(coord, box_); + box_[3] -= 0.3; + model.test_f(coord, box_); + model.test_v(coord, box_); + box_[6] -= 0.7; + model.test_f(coord, box_); + model.test_v(coord, box_); + box_[7] += 0.6; + model.test_f(coord, box_); + model.test_v(coord, box_); +} + TEST_F(TestInferDeepPotR, cpu_build_nlist_atomic) { double ener; diff --git a/source/api_cc/tests/test_ewald.cc b/source/api_cc/tests/test_ewald.cc new file mode 100644 index 0000000000..04ecc2d9db --- /dev/null +++ b/source/api_cc/tests/test_ewald.cc @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include +#include "neighbor_list.h" +#include "test_utils.h" +#include "Ewald.h" + +class TestInferEwald : public ::testing::Test +{ +protected: + std::vector coord = { + 12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector charge = { + -2, 1, 1, -2, 1, 1 + }; + std::vector box = { + 13., 0., 0., 0., 13., 0., 0., 0., 13. + }; + void SetUp() override { + }; + void TearDown() override { + }; +}; + +TEST_F(TestInferEwald, cpu_numfv) +{ + class MyModel : public EnergyModelTest + { + const std::vector & charge; + EwaldParameters eparam; +public: + MyModel( + const std::vector & charge_ + ) : charge(charge_) { + eparam.beta = 0.4; + }; + virtual void compute ( + double & ener, + std::vector & force, + std::vector & virial, + const std::vector & coord, + const std::vector & box) { + SimulationRegion region; + region.reinitBox(&box[0]); + EwaldReciprocal(ener, force, virial, coord, charge, region, eparam); + } + }; + MyModel model(charge); + model.test_f(coord, box); + model.test_v(coord, box); + std::vector box_(box); + box_[1] -= 0.2; + model.test_f(coord, box_); + model.test_v(coord, box_); + box_[2] += 0.5; + model.test_f(coord, box_); + model.test_v(coord, box_); + box_[4] += 0.2; + model.test_f(coord, box_); + model.test_v(coord, box_); + box_[3] -= 0.3; + model.test_f(coord, box_); + model.test_v(coord, box_); + box_[6] -= 0.7; + model.test_f(coord, box_); + model.test_v(coord, box_); + box_[7] += 0.6; + model.test_f(coord, box_); + model.test_v(coord, box_); +} diff --git a/source/api_cc/tests/test_utils.h b/source/api_cc/tests/test_utils.h index 4135f46498..ed4b40b5ff 100644 --- a/source/api_cc/tests/test_utils.h +++ b/source/api_cc/tests/test_utils.h @@ -1,4 +1,5 @@ #pragma once +#include inline void _fold_back( @@ -48,3 +49,87 @@ _build_nlist( std::vector> nlist_r_cpy; build_nlist(nlist_data, nlist_r_cpy, coord_cpy, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); } + +template +class EnergyModelTest +{ + double hh = 1e-5; + double level = 1e-6; +public: + virtual void compute ( + VALUETYPE & ener, + std::vector & force, + std::vector & virial, + const std::vector & coord, + const std::vector & box + ) = 0; + void test_f ( + const std::vector & coord, + const std::vector & box) { + int ndof = coord.size(); + VALUETYPE ener; + std::vector force, virial; + compute(ener, force, virial, coord, box); + for(int ii = 0; ii < ndof; ++ii){ + std::vector coord0(coord), coord1(coord); + VALUETYPE ener0, ener1; + std::vector forcet, virialt; + coord0[ii] += hh; + coord1[ii] -= hh; + compute(ener0, forcet, virialt, coord0, box); + compute(ener1, forcet, virialt, coord1, box); + VALUETYPE num = - (ener0 - ener1) / (2.*hh); + VALUETYPE ana = force[ii]; + EXPECT_LT(fabs(num - ana), level); + } + } + void test_v( + const std::vector & coord, + const std::vector & box) { + std::vector num_diff(9); + VALUETYPE ener; + std::vector force, virial; + compute(ener, force, virial, coord, box); + Region region; + init_region_cpu(region, &box[0]); + for(int ii = 0; ii < 9; ++ii){ + std::vector box0(box), box1(box); + box0[ii] += hh; + box1[ii] -= hh; + Region region0, region1; + init_region_cpu(region0, &box0[0]); + init_region_cpu(region1, &box1[0]); + std::vector coord0(coord), coord1(coord); + int natoms = coord.size() / 3; + for(int ii = 0; ii < natoms; ++ii){ + VALUETYPE pi[3]; + convert_to_inter_cpu(pi, region, &coord[ii*3]); + convert_to_phys_cpu(&coord0[ii*3], region0, pi); + } + for(int ii = 0; ii < natoms; ++ii){ + VALUETYPE pi[3]; + convert_to_inter_cpu(pi, region, &coord[ii*3]); + convert_to_phys_cpu(&coord1[ii*3], region1, pi); + } + VALUETYPE ener0, ener1; + std::vector forcet, virialt; + compute(ener0, forcet, virialt, coord0, box0); + compute(ener1, forcet, virialt, coord1, box1); + num_diff[ii] = - (ener0 - ener1) / (2.*hh); + } + std::vector num_virial(9, 0); + for(int dd0 = 0; dd0 < 3; ++dd0){ + for(int dd1 = 0; dd1 < 3; ++dd1){ + for(int dd = 0; dd < 3; ++dd){ + num_virial[dd0*3+dd1] += num_diff[dd*3+dd0] * box[dd*3+dd1]; + // num_virial[dd0*3+dd1] += num_diff[dd0*3+dd] * box[dd1*3+dd]; + } + } + } + for(int ii = 0; ii < 9; ++ii){ + EXPECT_LT(fabs(num_virial[ii] - virial[ii]), level); + } + } +}; + + diff --git a/source/lib/include/region.h b/source/lib/include/region.h index e5e0aab5d7..049ef882cc 100644 --- a/source/lib/include/region.h +++ b/source/lib/include/region.h @@ -15,6 +15,11 @@ init_region_cpu( Region & region, const FPTYPE * boxt); +template +FPTYPE +volume_cpu( + const Region & region); + template void convert_to_inter_cpu( diff --git a/source/lib/src/region.cc b/source/lib/src/region.cc index b4c1aa2e77..b8ab55d1a8 100644 --- a/source/lib/src/region.cc +++ b/source/lib/src/region.cc @@ -108,6 +108,14 @@ convert_to_phys_cpu( tensor_t_dot_vec(rp, region.boxt, ri); } +template +FPTYPE +volume_cpu( + const Region & region) +{ + return compute_volume(region.boxt); +} + template void init_region_cpu( Region & region, @@ -146,3 +154,12 @@ convert_to_phys_cpu( const Region & region, const float * rp); +template +double +volume_cpu( + const Region & region); + +template +float +volume_cpu( + const Region & region); diff --git a/source/lib/tests/CMakeLists.txt b/source/lib/tests/CMakeLists.txt index 874f9768a2..d03eae2e0e 100644 --- a/source/lib/tests/CMakeLists.txt +++ b/source/lib/tests/CMakeLists.txt @@ -43,6 +43,14 @@ endif() file(GLOB TEST_SRC test_*.cc) add_executable( runUnitTests ${TEST_SRC} ) +find_package(Threads) +# find openmp +find_package(OpenMP) +if (OPENMP_FOUND) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") +endif() + if (USE_CUDA_TOOLKIT) target_link_libraries(runUnitTests gtest gtest_main ${libname} pthread deepmd_op_cuda) else() diff --git a/source/lib/tests/test_ewald.cc b/source/lib/tests/test_ewald.cc new file mode 100644 index 0000000000..8f6c83cbb2 --- /dev/null +++ b/source/lib/tests/test_ewald.cc @@ -0,0 +1,52 @@ +#include +#include +#include +#include "Ewald.h" + +class TestEwald : public ::testing::Test +{ +protected: + std::vector coord = { + 12.83, 2.56, 2.18, + 12.09, 2.87, 2.74, + 00.25, 3.32, 1.68, + 3.36, 3.00, 1.81, + 3.51, 2.51, 2.60, + 4.27, 3.22, 1.56 + }; + std::vector charge = { + -2, 1, 1, -2, 1, 1, + }; + std::vector boxt = { + 13., 0., 0., 0., 13., 0., 0., 0., 13. + }; + EwaldParameters eparam; + double expected_e = 4.7215808340392229e+00; + std::vector expected_f = { + -5.4937025715874448e+00,5.6659817006308417e+00,3.8059426028301313e-01,2.5210962791915938e+00,-2.6383552457553545e+00,-4.8998411247787405e-01,2.7390037416771147e+00,-3.2890571945143514e+00,3.8057620258450320e-01,6.7561832843578351e+00,-1.3707287681111919e+00,2.7733203842981604e+00,-3.3297964389679557e+00,1.0404967238120841e+00,-1.8035649784287722e+00,-3.1927842946711418e+00,5.9166278393797123e-01,-1.2409417562590299e+00, + }; + std::vector expected_v = { + 6.5088081157418898e-01,1.9076542856278367e+00,-9.8010077026955389e-01,1.9076542856278367e+00,1.3101841366497322e+00,1.9794445391572657e-01,-9.8010077026955389e-01,1.9794445391572657e-01,1.9232614011636004e+00 + }; + + void SetUp() override { + }; +}; + + +TEST_F(TestEwald, cpu) +{ + double ener; + std::vector force, virial; + SimulationRegion region; + region.reinitBox(&boxt[0]); + EwaldReciprocal(ener, force, virial, coord, charge, region, eparam); + EXPECT_LT(fabs(ener - expected_e), 1e-10); + for(int ii = 0; ii < force.size(); ++ii){ + EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); + } + for(int ii = 0; ii < virial.size(); ++ii){ + EXPECT_LT(fabs(virial[ii] - expected_v[ii]), 1e-10); + } +} + diff --git a/source/lib/tests/test_simulation_region.cc b/source/lib/tests/test_simulation_region.cc index 90424dfd89..dbd65d2883 100644 --- a/source/lib/tests/test_simulation_region.cc +++ b/source/lib/tests/test_simulation_region.cc @@ -10,6 +10,7 @@ class TestRegion : public ::testing::Test std::vector ref_boxt = { 3.27785716, 0.09190842, 0.14751448, 0.02331264, 4.36482777, -0.2999871 , -0.47510999, -0.38123489, 5.33561809 }; + double expected_vol = 76.26958621360133; // rec_boxt = boxt^{-T} std::vector ref_rec_boxt = { 3.0385229041853185e-01, 2.3783430948044884e-04, 2.7073513689027690e-02, -7.1670232142159460e-03, 2.3022911797728179e-01, 1.5811897837543720e-02, -8.8035961973365381e-03, 1.2937710358702505e-02, 1.8756020637229892e-01 @@ -45,6 +46,9 @@ TEST_F(TestRegion, cpu) for(int ii = 0; ii < 9; ++ii){ EXPECT_LT(fabs(region.rec_boxt[ii] - ref_rec_boxt[ii]), 1e-10); } + // check volume + double vol = volume_cpu(region); + EXPECT_LT(fabs(vol - expected_vol), 1e-10); // check conversion between phys and inter coords. double ri[3]; convert_to_inter_cpu(ri, region, &ref_rp[0]); From 2f3bcd65da3d70cb0f293ee0ceeb6451c9f773c1 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 15 Mar 2021 07:53:37 +0800 Subject: [PATCH 270/562] fix bug in test_ewald --- source/tests/test_ewald.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/tests/test_ewald.py b/source/tests/test_ewald.py index 2864336ca0..6fc39d923c 100644 --- a/source/tests/test_ewald.py +++ b/source/tests/test_ewald.py @@ -95,7 +95,7 @@ def test_py_interface(self): def test_force(self): hh = 1e-4 - places = 4 + places = 6 sess = tf.Session() t_energy, t_force, t_virial \ = op_module.ewald_recp(self.coord, self.charge, self.nloc, self.box, @@ -137,7 +137,7 @@ def test_force(self): def test_virial(self): hh = 1e-4 - places = 5 + places = 6 sess = tf.Session() t_energy, t_force, t_virial \ = op_module.ewald_recp(self.coord, self.charge, self.nloc, self.box, @@ -194,8 +194,8 @@ def test_virial(self): self.nloc: [self.natoms], }) num_deriv[:,ii,jj] = -(energyp[0] - energym[0]) / (2.*hh) - dbox3t = np.transpose(self.dbox3, [0,2,1]) - t_esti = np.matmul(num_deriv, dbox3t) + num_deriv_t = np.transpose(num_deriv, [0,2,1]) + t_esti = np.matmul(num_deriv_t, self.dbox3) # # t_esti = np.matmul(num_deriv, self.dbox3) # print(num_deriv[0]) # print(t_esti[0]) From 12ba87bce2743329659ce3ddf67014c15e4d1272 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 15 Mar 2021 08:47:39 +0800 Subject: [PATCH 271/562] clean up ewald, remove dependency on SimulationRegion --- source/api_cc/tests/test_dipolecharge.cc | 8 +- source/api_cc/tests/test_ewald.cc | 8 +- source/lib/include/ewald.h | 34 ++++++++ source/lib/{include/Ewald.h => src/ewald.cc} | 84 ++++++++++---------- source/lib/tests/test_ewald.cc | 2 +- source/op/ewald_recp.cc | 26 ++---- 6 files changed, 92 insertions(+), 70 deletions(-) create mode 100644 source/lib/include/ewald.h rename source/lib/{include/Ewald.h => src/ewald.cc} (85%) diff --git a/source/api_cc/tests/test_dipolecharge.cc b/source/api_cc/tests/test_dipolecharge.cc index 81516ed63f..87fd2f4a78 100644 --- a/source/api_cc/tests/test_dipolecharge.cc +++ b/source/api_cc/tests/test_dipolecharge.cc @@ -6,7 +6,7 @@ #include "DeepTensor.h" #include "DataModifier.h" #include "SimulationRegion.h" -#include "Ewald.h" +#include "ewald.h" #include "neighbor_list.h" #include "test_utils.h" @@ -174,12 +174,12 @@ TEST_F(TestDipoleCharge, cpu_lmp_nlist) // compute the recp part of the ele interaction double eener; std::vector eforce, evirial; - SimulationRegion region; - region.reinitBox(&box[0]); + Region region; + init_region_cpu(region, &box[0]); EwaldParameters eparam; eparam.beta = 0.2; eparam.spacing = 4; - EwaldReciprocal(eener, eforce, evirial, coord, charge, region, eparam); + ewald_recp(eener, eforce, evirial, coord, charge, region, eparam); EXPECT_LT(fabs(eener - expected_e[0]), 1e-6); EXPECT_EQ(eforce.size(), coord.size()); diff --git a/source/api_cc/tests/test_ewald.cc b/source/api_cc/tests/test_ewald.cc index 04ecc2d9db..73dcbe686e 100644 --- a/source/api_cc/tests/test_ewald.cc +++ b/source/api_cc/tests/test_ewald.cc @@ -5,7 +5,7 @@ #include #include "neighbor_list.h" #include "test_utils.h" -#include "Ewald.h" +#include "ewald.h" class TestInferEwald : public ::testing::Test { @@ -48,9 +48,9 @@ TEST_F(TestInferEwald, cpu_numfv) std::vector & virial, const std::vector & coord, const std::vector & box) { - SimulationRegion region; - region.reinitBox(&box[0]); - EwaldReciprocal(ener, force, virial, coord, charge, region, eparam); + Region region; + init_region_cpu(region, &box[0]); + ewald_recp(ener, force, virial, coord, charge, region, eparam); } }; MyModel model(charge); diff --git a/source/lib/include/ewald.h b/source/lib/include/ewald.h new file mode 100644 index 0000000000..10d400e62a --- /dev/null +++ b/source/lib/include/ewald.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include + +#include "utilities.h" +#include "region.h" + +// 8.988e9 / pc.electron_volt / pc.angstrom * (1.602e-19)**2 +const double ElectrostaticConvertion = 14.39964535475696995031; + +template +struct EwaldParameters +{ + VALUETYPE rcut = 6.0; + VALUETYPE beta = 2; + VALUETYPE spacing = 4; +}; + +// compute the reciprocal part of the Ewald sum. +// outputs: energy force virial +// inputs: coordinates charges region +template +void +ewald_recp( + VALUETYPE & ener, + std::vector & force, + std::vector & virial, + const std::vector& coord, + const std::vector& charge, + const Region& region, + const EwaldParameters& param); + diff --git a/source/lib/include/Ewald.h b/source/lib/src/ewald.cc similarity index 85% rename from source/lib/include/Ewald.h rename to source/lib/src/ewald.cc index 4f6b4119c2..b12a4757e7 100644 --- a/source/lib/include/Ewald.h +++ b/source/lib/src/ewald.cc @@ -1,23 +1,6 @@ -#pragma once - -#include -#include -#include - -#include "utilities.h" +#include "ewald.h" #include "SimulationRegion.h" -// 8.988e9 / pc.electron_volt / pc.angstrom * (1.602e-19)**2 -const double ElectrostaticConvertion = 14.39964535475696995031; - -template -struct EwaldParameters -{ - VALUETYPE rcut = 6.0; - VALUETYPE beta = 2; - VALUETYPE spacing = 4; -}; - template VALUETYPE dir_err_esti(const VALUETYPE & test_q, @@ -82,14 +65,9 @@ rec_err_esti(const VALUETYPE & test_q, template void cmpt_k(std::vector & KK, - const SimulationRegion& region, + const VALUETYPE * boxt, const EwaldParameters& param) { - const double * boxt_ = region.getBoxTensor(); - VALUETYPE boxt[9]; - for (int dd = 0; dd < 9; ++dd){ - boxt[dd] = static_cast(boxt_[dd]); - } KK.resize(3); for (int dd = 0; dd < 3; ++dd){ VALUETYPE ll = sqrt(dot3(boxt+dd*3, boxt+dd*3)); @@ -108,13 +86,14 @@ cmpt_k(std::vector & KK, // inputs: coordinates charges region template void -EwaldReciprocal(VALUETYPE & ener, - std::vector & force, - std::vector & virial, - const std::vector& coord, - const std::vector& charge, - const SimulationRegion& region, - const EwaldParameters& param) +ewald_recp( + VALUETYPE & ener, + std::vector & force, + std::vector & virial, + const std::vector& coord, + const std::vector& charge, + const Region& region, + const EwaldParameters& param) { // natoms int natoms = charge.size(); @@ -137,7 +116,7 @@ EwaldReciprocal(VALUETYPE & ener, // K grid std::vector KK(3); int totK = 1; - cmpt_k(KK, region, param); + cmpt_k(KK, region.boxt, param); for (int dd = 0; dd < 3; ++dd){ totK *= (KK[dd]+1); } @@ -154,11 +133,12 @@ EwaldReciprocal(VALUETYPE & ener, #pragma omp parallel for num_threads(nthreads) for (int ii = 0; ii < natoms; ++ii){ int thread_id = omp_get_thread_num(); - double ir[3]; - double tmpcoord[3] = {coord[ii*3], coord[ii*3+1], coord[ii*3+2]}; - region.phys2Inter(ir, tmpcoord); + VALUETYPE ir[3]; + VALUETYPE tmpcoord[3] = {coord[ii*3], coord[ii*3+1], coord[ii*3+2]}; + convert_to_inter_cpu(ir, region, tmpcoord); + // region.phys2Inter(ir, tmpcoord); for (int mm0 = -KK[0]/2; mm0 <= KK[0]/2; ++mm0){ - double mr[3]; + VALUETYPE mr[3]; mr[0] = ir[0] * mm0; int shift0 = (mm0 + KK[0]/2) * stride[1] * stride[2]; for (int mm1 = -KK[1]/2; mm1 <= KK[1]/2; ++mm1){ @@ -168,7 +148,7 @@ EwaldReciprocal(VALUETYPE & ener, if (mm0 == 0 && mm1 == 0 && mm2 == 0) continue; int mc = shift0 + shift1 + mm2 + KK[2]/2; mr[2] = ir[2] * mm2; - double mdotr = 2. * M_PI * (mr[0]+mr[1]+mr[2]); + VALUETYPE mdotr = 2. * M_PI * (mr[0]+mr[1]+mr[2]); thread_sqr[thread_id][mc] += charge[ii] * cos(mdotr); thread_sqi[thread_id][mc] += charge[ii] * sin(mdotr); } @@ -187,11 +167,7 @@ EwaldReciprocal(VALUETYPE & ener, } // get rbox - VALUETYPE rec_box[9]; - const double * rec_box_ = region.getRecBoxTensor(); - for (int ii = 0; ii < 9; ++ii){ - rec_box[ii] = static_cast(rec_box_[ii]); - } + const VALUETYPE * rec_box = region.rec_boxt; std::vector thread_ener(nthreads, 0.); std::vector > thread_force(nthreads); @@ -272,7 +248,7 @@ EwaldReciprocal(VALUETYPE & ener, } } - VALUETYPE vol = static_cast(region.getVolume()); + VALUETYPE vol = volume_cpu(region); ener /= 2 * M_PI * vol; ener *= ElectrostaticConvertion; for (int ii = 0; ii < 3*natoms; ++ii){ @@ -287,3 +263,25 @@ EwaldReciprocal(VALUETYPE & ener, delete[]sqi; } + +template +void +ewald_recp( + float & ener, + std::vector & force, + std::vector & virial, + const std::vector& coord, + const std::vector& charge, + const Region& region, + const EwaldParameters& param); + +template +void +ewald_recp( + double & ener, + std::vector & force, + std::vector & virial, + const std::vector& coord, + const std::vector& charge, + const Region& region, + const EwaldParameters& param); diff --git a/source/lib/tests/test_ewald.cc b/source/lib/tests/test_ewald.cc index 8f6c83cbb2..441e44f782 100644 --- a/source/lib/tests/test_ewald.cc +++ b/source/lib/tests/test_ewald.cc @@ -1,7 +1,7 @@ #include #include #include -#include "Ewald.h" +#include "ewald.h" class TestEwald : public ::testing::Test { diff --git a/source/op/ewald_recp.cc b/source/op/ewald_recp.cc index 956582c8c2..21ac163b5c 100644 --- a/source/op/ewald_recp.cc +++ b/source/op/ewald_recp.cc @@ -1,5 +1,5 @@ #include "custom_op.h" -#include "Ewald.h" +#include "ewald.h" typedef double boxtensor_t ; typedef double compute_t; @@ -79,29 +79,19 @@ class EwaldRecpOp : public OpKernel { int coord_iter = kk * nloc * 3; int charge_iter = kk * nloc; // set region - boxtensor_t boxt [9] = {0}; - for (int dd = 0; dd < 9; ++dd) { - boxt[dd] = box(box_iter + dd); - } - SimulationRegion region; - region.reinitBox (boxt); + Region region; + init_region_cpu(region, &box(box_iter)); // set & normalize coord - std::vector d_coord3_ (nloc*3); + std::vector d_coord3 (nloc*3); for (int ii = 0; ii < nloc; ++ii){ - for (int dd = 0; dd < 3; ++dd){ - d_coord3_[ii*3+dd] = coord(coord_iter + ii*3+dd); - } - double inter[3]; - region.phys2Inter (inter, &d_coord3_[3*ii]); + FPTYPE inter[3]; + convert_to_inter_cpu(inter, region, &coord(coord_iter + ii*3)); for (int dd = 0; dd < 3; ++dd){ if (inter[dd] < 0 ) inter[dd] += 1.; else if (inter[dd] >= 1) inter[dd] -= 1.; } - } - std::vector d_coord3 (nloc*3); - for (int ii = 0; ii < nloc * 3; ++ii) { - d_coord3[ii] = d_coord3_[ii]; + convert_to_phys_cpu(&d_coord3[ii*3], region, inter); } // set charge @@ -114,7 +104,7 @@ class EwaldRecpOp : public OpKernel { std::vector d_virial(9); // compute - EwaldReciprocal(d_ener, d_force, d_virial, d_coord3, d_charge, region, ep); + ewald_recp(d_ener, d_force, d_virial, d_coord3, d_charge, region, ep); // copy output energy(kk) = d_ener; From 3bd863bfa2d7e7cc18d3ef66e15943faf95d0b38 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 15 Mar 2021 09:31:30 +0800 Subject: [PATCH 272/562] fix bug in lib UT --- source/lib/tests/test_ewald.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/lib/tests/test_ewald.cc b/source/lib/tests/test_ewald.cc index 441e44f782..44cb758273 100644 --- a/source/lib/tests/test_ewald.cc +++ b/source/lib/tests/test_ewald.cc @@ -38,9 +38,9 @@ TEST_F(TestEwald, cpu) { double ener; std::vector force, virial; - SimulationRegion region; - region.reinitBox(&boxt[0]); - EwaldReciprocal(ener, force, virial, coord, charge, region, eparam); + Region region; + init_region_cpu(region, &boxt[0]); + ewald_recp(ener, force, virial, coord, charge, region, eparam); EXPECT_LT(fabs(ener - expected_e), 1e-10); for(int ii = 0; ii < force.size(); ++ii){ EXPECT_LT(fabs(force[ii] - expected_f[ii]), 1e-10); From 94d38b7739507646a502289e6c7aaa83dccb31d4 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 15 Mar 2021 20:19:22 +0800 Subject: [PATCH 273/562] add model version support. implemented python interface. --- deepmd/entrypoints/freeze.py | 2 + deepmd/infer/deep_dipole.py | 6 +- deepmd/infer/deep_eval.py | 211 ++++++---------------------- deepmd/infer/deep_polar.py | 8 +- deepmd/infer/deep_pot.py | 55 ++++++-- deepmd/infer/deep_tensor.py | 172 +++++++++++++++++++++++ deepmd/infer/deep_wfc.py | 5 +- source/api_cc/include/version.h.in | 1 + source/tests/infer/deepdipole.pbtxt | 21 +++ source/tests/infer/deeppolar.pbtxt | 21 +++ source/tests/infer/deeppot-1.pbtxt | 21 +++ source/tests/infer/deeppot-r.pbtxt | 21 +++ source/tests/infer/deeppot.pbtxt | 21 +++ source/tests/test_deeppot_a.py | 59 ++++++++ source/train/MODEL_VER | 1 + source/train/model.py | 9 +- source/train/run_config.ini | 3 +- source/train/run_options.py | 2 + 18 files changed, 445 insertions(+), 194 deletions(-) create mode 100644 deepmd/infer/deep_tensor.py create mode 100644 source/train/MODEL_VER diff --git a/deepmd/entrypoints/freeze.py b/deepmd/entrypoints/freeze.py index d47dffaf87..e11ac0c906 100755 --- a/deepmd/entrypoints/freeze.py +++ b/deepmd/entrypoints/freeze.py @@ -43,6 +43,7 @@ def _make_node_names(model_type: str, modifier_type: Optional[str] = None) -> Li "descrpt_attr/ntypes", "model_attr/tmap", "model_attr/model_type", + "model_attr/model_version", ] if model_type == "ener": @@ -59,6 +60,7 @@ def _make_node_names(model_type: str, modifier_type: Optional[str] = None) -> Li nodes += [ "o_wfc", "model_attr/sel_type", + "model_attr/output_dim", ] elif model_type == "dipole": nodes += [ diff --git a/deepmd/infer/deep_dipole.py b/deepmd/infer/deep_dipole.py index 7ad3ee49a5..d158cbafac 100644 --- a/deepmd/infer/deep_dipole.py +++ b/deepmd/infer/deep_dipole.py @@ -1,6 +1,6 @@ -from typing import TYPE_CHECKING +from deepmd.infer.deep_tensor import DeepTensor -from deepmd.infer.deep_eval import DeepTensor +from typing import TYPE_CHECKING if TYPE_CHECKING: from pathlib import Path @@ -33,7 +33,6 @@ def __init__( # instance namespace self.tensors = dict( { - "t_sel_type": "model_attr/sel_type:0", # output tensor "t_tensor": "o_dipole:0", }, @@ -43,7 +42,6 @@ def __init__( DeepTensor.__init__( self, model_file, - 3, load_prefix=load_prefix, default_tf_graph=default_tf_graph, ) diff --git a/deepmd/infer/deep_eval.py b/deepmd/infer/deep_eval.py index 2c52644eb1..dc31995e58 100644 --- a/deepmd/infer/deep_eval.py +++ b/deepmd/infer/deep_eval.py @@ -4,6 +4,7 @@ import numpy as np from deepmd.common import make_default_mesh from deepmd.env import default_tf_session_config, tf +from deepmd.run_options import MODEL_VERSION if TYPE_CHECKING: from pathlib import Path @@ -13,6 +14,7 @@ class DeepEval: """Common methods for DeepPot, DeepWFC, DeepPolar, ...""" _model_type: Optional[str] = None + _model_version: Optional[str] = None load_prefix: str # set by subclass def __init__( @@ -26,6 +28,12 @@ def __init__( ) self.load_prefix = load_prefix + if not self._graph_compatable(): + raise RuntimeError( + f"model in graph (version {self.model_version}) is incompatible" + f"with the model (version {MODEL_VERSION}) supported by the current code." + ) + @property def model_type(self) -> str: """Get type of model. @@ -37,9 +45,44 @@ def model_type(self) -> str: sess = tf.Session(graph=self.graph, config=default_tf_session_config) [mt] = sess.run([t_mt], feed_dict={}) self._model_type = mt.decode("utf-8") - return self._model_type + @property + def model_version(self) -> str: + """Get type of model. + + :type:str + """ + if not self._model_version: + try: + t_mt = self._get_tensor("model_attr/model_version:0") + sess = tf.Session(graph=self.graph, config=default_tf_session_config) + [mt] = sess.run([t_mt], feed_dict={}) + self._model_version = mt.decode("utf-8") + except KeyError: + # For deepmd-kit version 0.x - 1.x, set model version to 0.0 + self._model_version = "0.0" + return self._model_version + + def _graph_compatable( + self + ) -> bool : + """ Check the model compatability + + Return + bool + If the model stored in the graph file is compatable with the current code + """ + model_version_major = int(self.model_version.split('.')[0]) + model_version_minor = int(self.model_version.split('.')[1]) + MODEL_VERSION_MAJOR = int(MODEL_VERSION.split('.')[0]) + MODEL_VERSION_MINOR = int(MODEL_VERSION.split('.')[1]) + if (model_version_major != MODEL_VERSION_MAJOR) or \ + (model_version_minor > MODEL_VERSION_MINOR) : + return False + else: + return True + def _get_tensor( self, tensor_name: str, attr_name: Optional[str] = None ) -> tf.Tensor: @@ -70,8 +113,6 @@ def _get_tensor( def _load_graph( frozen_graph_filename: "Path", prefix: str = "load", default_tf_graph: bool = False ): - - # We load the protobuf file from the disk and parse it to retrieve the # unserialized graph_def with tf.gfile.GFile(str(frozen_graph_filename), "rb") as f: @@ -101,168 +142,6 @@ def _load_graph( return graph -class DeepTensor(DeepEval): - """Evaluates a tensor model. - - Constructor - - Parameters - ---------- - model_file: str - The name of the frozen model file. - variable_dof: int - The DOF of the variable to evaluate. - load_prefix: str - The prefix in the load computational graph - default_tf_graph : bool - If uses the default tf graph, otherwise build a new tf graph for evaluation - """ - - tensors = { - "t_ntypes": "descrpt_attr/ntypes:0", - "t_rcut": "descrpt_attr/rcut:0", - "t_tmap": "model_attr/tmap:0", - # inputs - "t_coord": "t_coord:0", - "t_type": "t_type:0", - "t_natoms": "t_natoms:0", - "t_box": "t_box:0", - "t_mesh": "t_mesh:0", - } - - def __init__( - self, - model_file: "Path", - variable_dof: Optional[int], - load_prefix: str = 'load', - default_tf_graph: bool = False - ) -> None: - DeepEval.__init__( - self, - model_file, - load_prefix=load_prefix, - default_tf_graph=default_tf_graph - ) - self.variable_dof = variable_dof - - # now load tensors to object attributes - for attr_name, tensor_name in self.tensors.items(): - self._get_tensor(tensor_name, attr_name) - - # start a tf session associated to the graph - self.sess = tf.Session(graph=self.graph, config=default_tf_session_config) - self._run_default_sess() - self.tmap = self.tmap.decode('UTF-8').split() - - def _run_default_sess(self): - [self.ntypes, self.rcut, self.tmap, self.tselt] = self.sess.run( - [self.t_ntypes, self.t_rcut, self.t_tmap, self.t_sel_type] - ) - - def get_ntypes(self) -> int: - """Get the number of atom types of this model.""" - return self.ntypes - - def get_rcut(self) -> float: - """Get the cut-off radius of this model.""" - return self.rcut - - def get_type_map(self) -> List[int]: - """Get the type map (element name of the atom types) of this model.""" - return self.tmap - - def get_sel_type(self) -> List[int]: - """Get the selected atom types of this model.""" - return self.tselt - - def get_dim_fparam(self) -> int: - """Get the number (dimension) of frame parameters of this DP.""" - return self.dfparam - - def get_dim_aparam(self) -> int: - """Get the number (dimension) of atomic parameters of this DP.""" - return self.daparam - - def eval( - self, - coords: np.array, - cells: np.array, - atom_types: List[int], - atomic: bool = True, - fparam: Optional[np.array] = None, - aparam: Optional[np.array] = None, - efield: Optional[np.array] = None - ) -> np.array: - """Evaluate the model. - - Parameters - ---------- - coords - The coordinates of atoms. - The array should be of size nframes x natoms x 3 - cells - The cell of the region. - If None then non-PBC is assumed, otherwise using PBC. - The array should be of size nframes x 9 - atom_types - The atom types - The list should contain natoms ints - atomic - Calculate the atomic energy and virial - fparam - Not used in this model - aparam - Not used in this model - efield - Not used in this model - - Returns - ------- - tensor - The returned tensor - If atomic == False then of size nframes x variable_dof - else of size nframes x natoms x variable_dof - """ - # standarize the shape of inputs - coords = np.array(coords) - cells = np.array(cells) - atom_types = np.array(atom_types, dtype = int) - - # reshape the inputs - cells = np.reshape(cells, [-1, 9]) - nframes = cells.shape[0] - coords = np.reshape(coords, [nframes, -1]) - natoms = coords.shape[1] // 3 - - # sort inputs - coords, atom_types, imap, sel_at, sel_imap = self.sort_input(coords, atom_types, sel_atoms = self.get_sel_type()) - - # make natoms_vec and default_mesh - natoms_vec = self.make_natoms_vec(atom_types) - assert(natoms_vec[0] == natoms) - - # evaluate - tensor = [] - feed_dict_test = {} - feed_dict_test[self.t_natoms] = natoms_vec - feed_dict_test[self.t_type ] = np.tile(atom_types, [nframes,1]).reshape([-1]) - t_out = [self.t_tensor] - feed_dict_test[self.t_coord] = np.reshape(coords, [-1]) - feed_dict_test[self.t_box ] = np.reshape(cells , [-1]) - feed_dict_test[self.t_mesh ] = make_default_mesh(cells) - v_out = self.sess.run (t_out, feed_dict = feed_dict_test) - tensor = v_out[0] - - # reverse map of the outputs - if atomic: - tensor = np.array(tensor) - tensor = self.reverse_map(np.reshape(tensor, [nframes,-1,self.variable_dof]), sel_imap) - tensor = np.reshape(tensor, [nframes, len(sel_at), self.variable_dof]) - else: - tensor = np.reshape(tensor, [nframes, self.variable_dof]) - - return tensor - @staticmethod def sort_input( coord : np.array, atom_type : np.array, sel_atoms : List[int] = None @@ -339,6 +218,7 @@ def reverse_map(vec : np.ndarray, imap : List[int]) -> np.ndarray: ret[:,ii,:] = vec[:,idx,:] return ret + def make_natoms_vec(self, atom_types : np.ndarray) -> np.ndarray : """Make the natom vector used by deepmd-kit. @@ -363,4 +243,3 @@ def make_natoms_vec(self, atom_types : np.ndarray) -> np.ndarray : for ii in range (self.ntypes) : natoms_vec[ii+2] = np.count_nonzero(atom_types == ii) return natoms_vec - diff --git a/deepmd/infer/deep_polar.py b/deepmd/infer/deep_polar.py index 48f565faa2..7ee02cf1c8 100644 --- a/deepmd/infer/deep_polar.py +++ b/deepmd/infer/deep_polar.py @@ -1,7 +1,7 @@ -from typing import TYPE_CHECKING, List, Optional - +from deepmd.infer.deep_tensor import DeepTensor import numpy as np -from deepmd.infer.deep_eval import DeepTensor + +from typing import TYPE_CHECKING, List, Optional if TYPE_CHECKING: from pathlib import Path @@ -34,7 +34,6 @@ def __init__( # instance namespace self.tensors = dict( { - "t_sel_type": "model_attr/sel_type:0", # output tensor "t_tensor": "o_polar:0", }, @@ -44,7 +43,6 @@ def __init__( DeepTensor.__init__( self, model_file, - 9, load_prefix=load_prefix, default_tf_graph=default_tf_graph, ) diff --git a/deepmd/infer/deep_pot.py b/deepmd/infer/deep_pot.py index 8fefe843d5..a8e70d5a72 100644 --- a/deepmd/infer/deep_pot.py +++ b/deepmd/infer/deep_pot.py @@ -3,8 +3,9 @@ import numpy as np from deepmd.common import make_default_mesh +from deepmd.env import default_tf_session_config, tf from deepmd.infer.data_modifier import DipoleChargeModifier -from deepmd.infer.deep_eval import DeepEval, DeepTensor +from deepmd.infer.deep_eval import DeepEval if TYPE_CHECKING: from pathlib import Path @@ -12,7 +13,7 @@ log = logging.getLogger(__name__) -class DeepPot(DeepTensor): +class DeepPot(DeepEval): """Constructor. Parameters @@ -43,9 +44,20 @@ def __init__( # instance namespace self.tensors = dict( { - # general + # descrpt attrs + "t_ntypes": "descrpt_attr/ntypes:0", + "t_rcut": "descrpt_attr/rcut:0", + # fitting attrs "t_dfparam": "fitting_attr/dfparam:0", "t_daparam": "fitting_attr/daparam:0", + # model attrs + "t_tmap": "model_attr/tmap:0", + # inputs + "t_coord": "t_coord:0", + "t_type": "t_type:0", + "t_natoms": "t_natoms:0", + "t_box": "t_box:0", + "t_mesh": "t_mesh:0", # add output tensors "t_energy": "o_energy:0", "t_force": "o_force:0", @@ -53,7 +65,6 @@ def __init__( "t_ae": "o_atom_energy:0", "t_av": "o_atom_virial:0" }, - **self.tensors ) DeepEval.__init__( self, @@ -90,15 +101,14 @@ def __init__( self.t_aparam = None self.has_aparam = False - # now when tensors are set initialize DeepTensor which will load them all - # to class attributes, the run session assciated with the graph - DeepTensor.__init__( - self, - model_file, - None, - load_prefix=load_prefix, - default_tf_graph=default_tf_graph - ) + # now load tensors to object attributes + for attr_name, tensor_name in self.tensors.items(): + self._get_tensor(tensor_name, attr_name) + + # start a tf session associated to the graph + self.sess = tf.Session(graph=self.graph, config=default_tf_session_config) + self._run_default_sess() + self.tmap = self.tmap.decode('UTF-8').split() # setup modifier try: @@ -123,9 +133,28 @@ def _run_default_sess(self): [self.t_ntypes, self.t_rcut, self.t_dfparam, self.t_daparam, self.t_tmap] ) + def get_ntypes(self) -> int: + """Get the number of atom types of this model.""" + return self.ntypes + + def get_rcut(self) -> float: + """Get the cut-off radius of this model.""" + return self.rcut + + def get_type_map(self) -> List[int]: + """Get the type map (element name of the atom types) of this model.""" + return self.tmap + def get_sel_type(self) -> List[int]: """Unsupported in this model.""" raise NotImplementedError("This model type does not support this attribute") + def get_dim_fparam(self) -> int: + """Get the number (dimension) of frame parameters of this DP.""" + return self.dfparam + + def get_dim_aparam(self) -> int: + """Get the number (dimension) of atomic parameters of this DP.""" + return self.daparam def eval( self, diff --git a/deepmd/infer/deep_tensor.py b/deepmd/infer/deep_tensor.py new file mode 100644 index 0000000000..24a7832a32 --- /dev/null +++ b/deepmd/infer/deep_tensor.py @@ -0,0 +1,172 @@ +import os +from typing import List, Optional, TYPE_CHECKING + +import numpy as np +from deepmd.common import make_default_mesh +from deepmd.env import default_tf_session_config, tf +from deepmd.infer.deep_eval import DeepEval + +if TYPE_CHECKING: + from pathlib import Path + +class DeepTensor(DeepEval): + """Evaluates a tensor model. + + Constructor + + Parameters + ---------- + model_file: str + The name of the frozen model file. + load_prefix: str + The prefix in the load computational graph + default_tf_graph : bool + If uses the default tf graph, otherwise build a new tf graph for evaluation + """ + + tensors = { + # descriptor attrs + "t_ntypes": "descrpt_attr/ntypes:0", + "t_rcut": "descrpt_attr/rcut:0", + # model attrs + "t_tmap": "model_attr/tmap:0", + "t_sel_type": "model_attr/sel_type:0", + "t_ouput_dim": "model_attr/output_dim:0", + # inputs + "t_coord": "t_coord:0", + "t_type": "t_type:0", + "t_natoms": "t_natoms:0", + "t_box": "t_box:0", + "t_mesh": "t_mesh:0", + } + + def __init__( + self, + model_file: "Path", + load_prefix: str = 'load', + default_tf_graph: bool = False + ) -> None: + DeepEval.__init__( + self, + model_file, + load_prefix=load_prefix, + default_tf_graph=default_tf_graph + ) + # now load tensors to object attributes + for attr_name, tensor_name in self.tensors.items(): + self._get_tensor(tensor_name, attr_name) + + # start a tf session associated to the graph + self.sess = tf.Session(graph=self.graph, config=default_tf_session_config) + self._run_default_sess() + self.tmap = self.tmap.decode('UTF-8').split() + + def _run_default_sess(self): + [self.ntypes, self.rcut, self.tmap, self.tselt, self.output_dim] \ + = self.sess.run( + [self.t_ntypes, self.t_rcut, self.t_tmap, self.t_sel_type, self.t_ouput_dim] + ) + + def get_ntypes(self) -> int: + """Get the number of atom types of this model.""" + return self.ntypes + + def get_rcut(self) -> float: + """Get the cut-off radius of this model.""" + return self.rcut + + def get_type_map(self) -> List[int]: + """Get the type map (element name of the atom types) of this model.""" + return self.tmap + + def get_sel_type(self) -> List[int]: + """Get the selected atom types of this model.""" + return self.tselt + + def get_dim_fparam(self) -> int: + """Get the number (dimension) of frame parameters of this DP.""" + return self.dfparam + + def get_dim_aparam(self) -> int: + """Get the number (dimension) of atomic parameters of this DP.""" + return self.daparam + + def eval( + self, + coords: np.array, + cells: np.array, + atom_types: List[int], + atomic: bool = True, + fparam: Optional[np.array] = None, + aparam: Optional[np.array] = None, + efield: Optional[np.array] = None + ) -> np.array: + """Evaluate the model. + + Parameters + ---------- + coords + The coordinates of atoms. + The array should be of size nframes x natoms x 3 + cells + The cell of the region. + If None then non-PBC is assumed, otherwise using PBC. + The array should be of size nframes x 9 + atom_types + The atom types + The list should contain natoms ints + atomic + Calculate the atomic energy and virial + fparam + Not used in this model + aparam + Not used in this model + efield + Not used in this model + + Returns + ------- + tensor + The returned tensor + If atomic == False then of size nframes x output_dim + else of size nframes x natoms x output_dim + """ + # standarize the shape of inputs + coords = np.array(coords) + cells = np.array(cells) + atom_types = np.array(atom_types, dtype = int) + + # reshape the inputs + cells = np.reshape(cells, [-1, 9]) + nframes = cells.shape[0] + coords = np.reshape(coords, [nframes, -1]) + natoms = coords.shape[1] // 3 + + # sort inputs + coords, atom_types, imap, sel_at, sel_imap = self.sort_input(coords, atom_types, sel_atoms = self.get_sel_type()) + + # make natoms_vec and default_mesh + natoms_vec = self.make_natoms_vec(atom_types) + assert(natoms_vec[0] == natoms) + + # evaluate + tensor = [] + feed_dict_test = {} + feed_dict_test[self.t_natoms] = natoms_vec + feed_dict_test[self.t_type ] = np.tile(atom_types, [nframes,1]).reshape([-1]) + t_out = [self.t_tensor] + feed_dict_test[self.t_coord] = np.reshape(coords, [-1]) + feed_dict_test[self.t_box ] = np.reshape(cells , [-1]) + feed_dict_test[self.t_mesh ] = make_default_mesh(cells) + v_out = self.sess.run (t_out, feed_dict = feed_dict_test) + tensor = v_out[0] + + # reverse map of the outputs + if atomic: + tensor = np.array(tensor) + tensor = self.reverse_map(np.reshape(tensor, [nframes,-1,self.output_dim]), sel_imap) + tensor = np.reshape(tensor, [nframes, len(sel_at), self.output_dim]) + else: + tensor = np.reshape(tensor, [nframes, self.output_dim]) + + return tensor diff --git a/deepmd/infer/deep_wfc.py b/deepmd/infer/deep_wfc.py index 1f976af04a..40d3cd6a5c 100644 --- a/deepmd/infer/deep_wfc.py +++ b/deepmd/infer/deep_wfc.py @@ -1,4 +1,5 @@ -from deepmd.infer.deep_eval import DeepTensor +from deepmd.infer.deep_tensor import DeepTensor + from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -32,7 +33,6 @@ def __init__( # instance namespace self.tensors = dict( { - "t_sel_type": "model_attr/sel_type:0", # output tensor "t_tensor": "o_wfc:0", }, @@ -41,7 +41,6 @@ def __init__( DeepTensor.__init__( self, model_file, - 12, load_prefix=load_prefix, default_tf_graph=default_tf_graph, ) diff --git a/source/api_cc/include/version.h.in b/source/api_cc/include/version.h.in index d3acbf5aff..23c22ae588 100644 --- a/source/api_cc/include/version.h.in +++ b/source/api_cc/include/version.h.in @@ -16,3 +16,4 @@ const std::string global_git_date="@GIT_DATE@"; const std::string global_git_branch="@GIT_BRANCH@"; const std::string global_tf_include_dir="@TensorFlow_INCLUDE_DIRS@"; const std::string global_tf_lib="@TensorFlow_LIBRARY@"; +const std::string global_model_version="@MODEL_VERSION@"; diff --git a/source/tests/infer/deepdipole.pbtxt b/source/tests/infer/deepdipole.pbtxt index a8f09a3331..b503c29336 100644 --- a/source/tests/infer/deepdipole.pbtxt +++ b/source/tests/infer/deepdipole.pbtxt @@ -5950,6 +5950,27 @@ node { } } } +node { + name: "model_attr/model_version" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "1.0" + } + } + } +} node { name: "model_attr/sel_type" op: "Const" diff --git a/source/tests/infer/deeppolar.pbtxt b/source/tests/infer/deeppolar.pbtxt index d7f29bdd87..49b9645b68 100644 --- a/source/tests/infer/deeppolar.pbtxt +++ b/source/tests/infer/deeppolar.pbtxt @@ -6178,6 +6178,27 @@ node { } } } +node { + name: "model_attr/model_version" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "1.0" + } + } + } +} node { name: "model_attr/sel_type" op: "Const" diff --git a/source/tests/infer/deeppot-1.pbtxt b/source/tests/infer/deeppot-1.pbtxt index 3f8034de55..0819df4b9e 100644 --- a/source/tests/infer/deeppot-1.pbtxt +++ b/source/tests/infer/deeppot-1.pbtxt @@ -8875,6 +8875,27 @@ node { } } } +node { + name: "model_attr/model_version" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "1.0" + } + } + } +} node { name: "model_attr/tmap" op: "Const" diff --git a/source/tests/infer/deeppot-r.pbtxt b/source/tests/infer/deeppot-r.pbtxt index 3ddd2effe4..c307be00f0 100644 --- a/source/tests/infer/deeppot-r.pbtxt +++ b/source/tests/infer/deeppot-r.pbtxt @@ -8529,6 +8529,27 @@ node { } } } +node { + name: "model_attr/model_version" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "1.0" + } + } + } +} node { name: "model_attr/tmap" op: "Const" diff --git a/source/tests/infer/deeppot.pbtxt b/source/tests/infer/deeppot.pbtxt index 7a5ba00f78..c7c49e2483 100644 --- a/source/tests/infer/deeppot.pbtxt +++ b/source/tests/infer/deeppot.pbtxt @@ -8875,6 +8875,27 @@ node { } } } +node { + name: "model_attr/model_version" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "1.0" + } + } + } +} node { name: "model_attr/tmap" op: "Const" diff --git a/source/tests/test_deeppot_a.py b/source/tests/test_deeppot_a.py index 8dee81df75..b9a519672d 100644 --- a/source/tests/test_deeppot_a.py +++ b/source/tests/test_deeppot_a.py @@ -4,6 +4,7 @@ from infer.convert2pb import convert_pbtxt_to_pb from deepmd.infer import DeepPot +from deepmd.run_options import MODEL_VERSION from common import tests_path from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION @@ -12,6 +13,64 @@ else : default_places = 10 +class TestModelMajorCompatability(unittest.TestCase) : + def setUp(self): + model_file = str(tests_path / os.path.join("infer","deeppot.pbtxt")) + with open(model_file, 'r') as fp: + # data = fp.read().replace('\n', '') + data = fp.read().split("\n") + for ii in range(len(data)): + if "model_attr/model_version" in data[ii]: + for jj in range(ii, len(data)): + if "string_val:" in data[jj]: + data[jj] = data[jj].replace(MODEL_VERSION, "0.0") + break + with open("deeppot-ver.pbtxt", "w") as fp: + fp.write("\n".join(data)) + + convert_pbtxt_to_pb(str(tests_path / os.path.join("deeppot-ver.pbtxt")), "deeppot.pb") + + def tearDown(self): + os.remove("deeppot-ver.pbtxt") + os.remove("deeppot.pb") + + def test(self): + with self.assertRaises(RuntimeError) as context: + DeepPot("deeppot.pb") + self.assertTrue('incompatible' in str(context.exception)) + self.assertTrue(MODEL_VERSION in str(context.exception)) + self.assertTrue('0.0' in str(context.exception)) + + +class TestModelMinorCompatability(unittest.TestCase) : + def setUp(self): + model_file = str(tests_path / os.path.join("infer","deeppot.pbtxt")) + with open(model_file, 'r') as fp: + # data = fp.read().replace('\n', '') + data = fp.read().split("\n") + for ii in range(len(data)): + if "model_attr/model_version" in data[ii]: + for jj in range(ii, len(data)): + if "string_val:" in data[jj]: + data[jj] = data[jj].replace(MODEL_VERSION, "0.1000000") + break + with open("deeppot-ver.pbtxt", "w") as fp: + fp.write("\n".join(data)) + + convert_pbtxt_to_pb(str(tests_path / os.path.join("deeppot-ver.pbtxt")), "deeppot.pb") + + def tearDown(self): + os.remove("deeppot-ver.pbtxt") + os.remove("deeppot.pb") + + def test(self): + with self.assertRaises(RuntimeError) as context: + DeepPot("deeppot.pb") + self.assertTrue('incompatible' in str(context.exception)) + self.assertTrue(MODEL_VERSION in str(context.exception)) + self.assertTrue('0.1000000' in str(context.exception)) + + class TestDeepPotAPBC(unittest.TestCase) : def setUp(self): convert_pbtxt_to_pb(str(tests_path / os.path.join("infer","deeppot.pbtxt")), "deeppot.pb") diff --git a/source/train/MODEL_VER b/source/train/MODEL_VER new file mode 100644 index 0000000000..d3827e75a5 --- /dev/null +++ b/source/train/MODEL_VER @@ -0,0 +1 @@ +1.0 diff --git a/source/train/model.py b/source/train/model.py index d56d390204..8ccee419bf 100644 --- a/source/train/model.py +++ b/source/train/model.py @@ -4,7 +4,7 @@ from deepmd.utils.pair_tab import PairTab from deepmd.common import ClassArg -from deepmd.run_options import global_cvt_2_ener_float +from deepmd.run_options import global_cvt_2_ener_float, MODEL_VERSION from deepmd.env import op_module @@ -146,6 +146,9 @@ def build (self, t_mt = tf.constant(self.model_type, name = 'model_type', dtype = tf.string) + t_ver = tf.constant(MODEL_VERSION, + name = 'model_version', + dtype = tf.string) if self.srtab is not None : tab_info, tab_data = self.srtab.get() @@ -335,11 +338,13 @@ def build (self, t_mt = tf.constant(self.model_type, name = 'model_type', dtype = tf.string) + t_ver = tf.constant(MODEL_VERSION, + name = 'model_version', + dtype = tf.string) t_od = tf.constant(self.get_out_size(), name = 'output_dim', dtype = tf.int32) - dout \ = self.descrpt.build(coord_, atype_, diff --git a/source/train/run_config.ini b/source/train/run_config.ini index 5579f13134..3f2e8cc86a 100644 --- a/source/train/run_config.ini +++ b/source/train/run_config.ini @@ -6,4 +6,5 @@ GIT_DATE = @GIT_DATE@ GIT_BRANCH = @GIT_BRANCH@ TF_INCLUDE_DIR = @TensorFlow_INCLUDE_DIRS@ TF_LIBS = @TensorFlow_LIBRARY@ -PRECISION = @PREC_DEF@ \ No newline at end of file +PRECISION = @PREC_DEF@ +MODEL_VERSION=@MODEL_VERSION@ diff --git a/source/train/run_options.py b/source/train/run_options.py index 632c18af63..0ef39a7e95 100644 --- a/source/train/run_options.py +++ b/source/train/run_options.py @@ -36,6 +36,7 @@ class TFServerV1(Protocol): "global_cvt_2_tf_float", "global_cvt_2_ener_float", "RunOptions", + "MODEL_VERSION", ] log = logging.getLogger(__name__) @@ -62,6 +63,7 @@ def _get_package_constants( GLOBAL_CONFIG = _get_package_constants() +MODEL_VERSION = GLOBAL_CONFIG["model_version"] if GLOBAL_CONFIG["precision"] == "-DHIGH_PREC": GLOBAL_TF_FLOAT_PRECISION = tf.float64 From 3c307f73014b41106f704d3e94ddab051345f1c7 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 16 Mar 2021 10:36:01 +0800 Subject: [PATCH 274/562] support model version check in c++ interface --- source/CMakeLists.txt | 5 +++ source/api_cc/include/DeepPot.h | 4 +++ source/api_cc/include/DeepTensor.h | 1 + source/api_cc/include/common.h | 5 +++ source/api_cc/src/DeepPot.cc | 18 ++++++++++- source/api_cc/src/DeepTensor.cc | 9 +++++- source/api_cc/src/common.cc | 40 +++++++++++++++++++++++ source/api_cc/tests/CMakeLists.txt | 6 ++-- source/tests/infer/dipolecharge_d.pbtxt | 21 +++++++++++++ source/tests/infer/dipolecharge_e.pbtxt | 42 +++++++++++++++++++++++++ 10 files changed, 147 insertions(+), 4 deletions(-) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 1803a10f5d..3aa8373aba 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -46,6 +46,11 @@ endif(GIT_FOUND) list (APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-ignored-attributes") +# model version +file(READ ${PROJECT_SOURCE_DIR}/train/MODEL_VER MODEL_VERSION) +string(REPLACE "\n" " " MODEL_VERSION ${MODEL_VERSION}) +message(STATUS "Current model version: ${MODEL_VERSION}") + # define USE_CUDA_TOOLKIT if (DEFINED USE_CUDA_TOOLKIT) if (USE_CUDA_TOOLKIT) diff --git a/source/api_cc/include/DeepPot.h b/source/api_cc/include/DeepPot.h index ba6162a62b..53996903c1 100644 --- a/source/api_cc/include/DeepPot.h +++ b/source/api_cc/include/DeepPot.h @@ -70,6 +70,8 @@ class DeepPot // int get_ntypes () const; VALUETYPE rcut; VALUETYPE cell_size; + std::string model_type; + std::string model_version; int ntypes; int dfparam; int daparam; @@ -163,6 +165,8 @@ class DeepPotModelDevi // int get_ntypes () const; VALUETYPE rcut; VALUETYPE cell_size; + std::string model_type; + std::string model_version; int ntypes; int dfparam; int daparam; diff --git a/source/api_cc/include/DeepTensor.h b/source/api_cc/include/DeepTensor.h index 786908f295..a60c6e1ed9 100644 --- a/source/api_cc/include/DeepTensor.h +++ b/source/api_cc/include/DeepTensor.h @@ -38,6 +38,7 @@ class DeepTensor VALUETYPE cell_size; int ntypes; std::string model_type; + std::string model_version; int odim; std::vector sel_type; template VT get_scalar(const std::string & name) const; diff --git a/source/api_cc/include/common.h b/source/api_cc/include/common.h index 698ebe04ed..46eb076d4f 100644 --- a/source/api_cc/include/common.h +++ b/source/api_cc/include/common.h @@ -42,6 +42,10 @@ struct NeighborListData void make_inlist(InputNlist & inlist); }; +bool +model_compatable( + std::string & model_version); + void select_by_type(std::vector & fwd_map, std::vector & bkw_map, @@ -204,3 +208,4 @@ select_map(std::vector & out, } } + diff --git a/source/api_cc/src/DeepPot.cc b/source/api_cc/src/DeepPot.cc index 71ca3226e9..f122f1173d 100644 --- a/source/api_cc/src/DeepPot.cc +++ b/source/api_cc/src/DeepPot.cc @@ -224,6 +224,14 @@ init (const std::string & model, const int & gpu_rank, const std::string & file_ daparam = get_scalar("fitting_attr/daparam"); if (dfparam < 0) dfparam = 0; if (daparam < 0) daparam = 0; + model_type = get_scalar("model_attr/model_type"); + model_version = get_scalar("model_attr/model_version"); + if(! model_compatable(model_version)){ + throw std::runtime_error( + "incompatable model: version " + model_version + + " in graph, but version " + global_model_version + + " supported "); + } inited = true; init_nbor = false; @@ -547,6 +555,14 @@ init (const std::vector & models, const int & gpu_rank, const std:: daparam = get_scalar("fitting_attr/daparam"); if (dfparam < 0) dfparam = 0; if (daparam < 0) daparam = 0; + model_type = get_scalar("model_attr/model_type"); + model_version = get_scalar("model_attr/model_version"); + if(! model_compatable(model_version)){ + throw std::runtime_error( + "incompatable model: version " + model_version + + " in graph, but version " + global_model_version + + " supported "); + } // rcut = get_rcut(); // cell_size = rcut; // ntypes = get_ntypes(); @@ -560,7 +576,7 @@ VT DeepPotModelDevi:: get_scalar(const std::string name) const { - VT myrcut = 0; + VT myrcut; for (unsigned ii = 0; ii < numb_models; ++ii){ VT ret = session_get_scalar(sessions[ii], name); if (ii == 0){ diff --git a/source/api_cc/src/DeepTensor.cc b/source/api_cc/src/DeepTensor.cc index 270d307013..e701c044f9 100644 --- a/source/api_cc/src/DeepTensor.cc +++ b/source/api_cc/src/DeepTensor.cc @@ -36,9 +36,16 @@ init (const std::string & model, rcut = get_scalar("descrpt_attr/rcut"); cell_size = rcut; ntypes = get_scalar("descrpt_attr/ntypes"); - model_type = get_scalar("model_attr/model_type"); odim = get_scalar("model_attr/output_dim"); get_vector(sel_type, "model_attr/sel_type"); + model_type = get_scalar("model_attr/model_type"); + model_version = get_scalar("model_attr/model_version"); + if(! model_compatable(model_version)){ + throw std::runtime_error( + "incompatable model: version " + model_version + + " in graph, but version " + global_model_version + + " supported "); + } inited = true; } diff --git a/source/api_cc/src/common.cc b/source/api_cc/src/common.cc index 4a431602d3..560790c1a1 100644 --- a/source/api_cc/src/common.cc +++ b/source/api_cc/src/common.cc @@ -2,6 +2,46 @@ #include "AtomMap.h" #include "device.h" +static std::vector +split(const std::string &input_, + const std::string &delimiter) +{ + std::string input = input_; + size_t pos = 0; + std::vector res; + while ((pos = input.find(delimiter)) != std::string::npos) { + res.push_back(input.substr(0, pos)); + input.erase(0, pos + delimiter.length()); + } + res.push_back(input); + return res; +} + +bool +model_compatable( + std::string & model_version) +{ + std::vector words_mv = split(model_version, "."); + std::vector words_gmv = split(global_model_version, "."); + if(words_mv.size() != 2){ + throw std::runtime_error("invalid graph model version string " + model_version); + } + if(words_gmv.size() != 2){ + throw std::runtime_error("invalid supported model version string " + global_model_version); + } + int model_version_major = atoi(words_mv[0].c_str()); + int model_version_minor = atoi(words_mv[1].c_str()); + int MODEL_VERSION_MAJOR = atoi(words_gmv[0].c_str()); + int MODEL_VERSION_MINOR = atoi(words_gmv[1].c_str()); + if(model_version_major != MODEL_VERSION_MAJOR || + model_version_minor > MODEL_VERSION_MINOR){ + return false; + } + else{ + return true; + } +} + void select_by_type(std::vector & fwd_map, std::vector & bkw_map, diff --git a/source/api_cc/tests/CMakeLists.txt b/source/api_cc/tests/CMakeLists.txt index aedb5b0f20..8f4bef0492 100644 --- a/source/api_cc/tests/CMakeLists.txt +++ b/source/api_cc/tests/CMakeLists.txt @@ -11,8 +11,10 @@ enable_testing() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") -message(${PROJECT_SOURCE_DIR}) -message(${CMAKE_SOURCE_DIR}) +# model version +file(READ ${PROJECT_SOURCE_DIR}/../../train/MODEL_VER MODEL_VERSION) +string(REPLACE "\n" " " MODEL_VERSION ${MODEL_VERSION}) +message(STATUS "Current model version: ${MODEL_VERSION}") set(libname "deepmd") set(LIB_BASE_DIR ${CMAKE_SOURCE_DIR}/../../lib) diff --git a/source/tests/infer/dipolecharge_d.pbtxt b/source/tests/infer/dipolecharge_d.pbtxt index 6bd2b430e3..6be963119f 100644 --- a/source/tests/infer/dipolecharge_d.pbtxt +++ b/source/tests/infer/dipolecharge_d.pbtxt @@ -7103,6 +7103,27 @@ node { } } } +node { + name: "model_attr/model_version" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "1.0" + } + } + } +} node { name: "model_attr/sel_type" op: "Const" diff --git a/source/tests/infer/dipolecharge_e.pbtxt b/source/tests/infer/dipolecharge_e.pbtxt index 61326137aa..ec9412a111 100644 --- a/source/tests/infer/dipolecharge_e.pbtxt +++ b/source/tests/infer/dipolecharge_e.pbtxt @@ -12402,6 +12402,27 @@ node { } } } +node { + name: "model_attr/model_version" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "1.0" + } + } + } +} node { name: "model_attr/tmap" op: "Const" @@ -56014,6 +56035,27 @@ node { } } } +node { + name: "dipole_charge/model_attr/model_version" + op: "Const" + attr { + key: "dtype" + value { + type: DT_STRING + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_STRING + tensor_shape { + } + string_val: "1.0" + } + } + } +} node { name: "dipole_charge/model_attr/sel_type" op: "Const" From 8d57dc3446e877e9047d18abf90e26c48029d815 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 16 Mar 2021 11:37:26 +0800 Subject: [PATCH 275/562] improved cmake message for model version --- source/CMakeLists.txt | 2 +- source/api_cc/tests/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 3aa8373aba..07f5bf7760 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -49,7 +49,7 @@ set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-ignored-attributes") # model version file(READ ${PROJECT_SOURCE_DIR}/train/MODEL_VER MODEL_VERSION) string(REPLACE "\n" " " MODEL_VERSION ${MODEL_VERSION}) -message(STATUS "Current model version: ${MODEL_VERSION}") +message(STATUS "Supported model version: ${MODEL_VERSION}") # define USE_CUDA_TOOLKIT if (DEFINED USE_CUDA_TOOLKIT) diff --git a/source/api_cc/tests/CMakeLists.txt b/source/api_cc/tests/CMakeLists.txt index 8f4bef0492..aabf452038 100644 --- a/source/api_cc/tests/CMakeLists.txt +++ b/source/api_cc/tests/CMakeLists.txt @@ -14,7 +14,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") # model version file(READ ${PROJECT_SOURCE_DIR}/../../train/MODEL_VER MODEL_VERSION) string(REPLACE "\n" " " MODEL_VERSION ${MODEL_VERSION}) -message(STATUS "Current model version: ${MODEL_VERSION}") +message(STATUS "Supported model version: ${MODEL_VERSION}") set(libname "deepmd") set(LIB_BASE_DIR ${CMAKE_SOURCE_DIR}/../../lib) From bf775f7051dbcde8a205be40ac023a0769a23ee9 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 16 Mar 2021 11:41:17 +0800 Subject: [PATCH 276/562] print model version on summary string --- source/api_cc/src/DeepPot.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/source/api_cc/src/DeepPot.cc b/source/api_cc/src/DeepPot.cc index f122f1173d..a5b9e6db8e 100644 --- a/source/api_cc/src/DeepPot.cc +++ b/source/api_cc/src/DeepPot.cc @@ -246,6 +246,7 @@ print_summary(const std::string &pre) const std::cout << pre << "source brach: " + global_git_branch << std::endl; std::cout << pre << "source commit: " + global_git_hash << std::endl; std::cout << pre << "source commit at: " + global_git_date << std::endl; + std::cout << pre << "surpport model ver.:" + global_model_version << std::endl; std::cout << pre << "build float prec: " + global_float_prec << std::endl; std::cout << pre << "build with tf inc: " + global_tf_include_dir << std::endl; std::cout << pre << "build with tf lib: " + global_tf_lib << std::endl; From 26b24cdf8ab3601f998d04d270adaf2459647dfd Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 16 Mar 2021 14:17:28 +0800 Subject: [PATCH 277/562] fix bugs in UT --- deepmd/infer/deep_eval.py | 1 + source/tests/test_data_modifier.py | 4 ++-- source/tests/test_data_modifier_shuffle.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/deepmd/infer/deep_eval.py b/deepmd/infer/deep_eval.py index dc31995e58..83f9a7aa6d 100644 --- a/deepmd/infer/deep_eval.py +++ b/deepmd/infer/deep_eval.py @@ -28,6 +28,7 @@ def __init__( ) self.load_prefix = load_prefix + # graph_compatable should be called after graph and prefix are set if not self._graph_compatable(): raise RuntimeError( f"model in graph (version {self.model_version}) is incompatible" diff --git a/source/tests/test_data_modifier.py b/source/tests/test_data_modifier.py index 70999f5734..9c47fa15dd 100644 --- a/source/tests/test_data_modifier.py +++ b/source/tests/test_data_modifier.py @@ -79,7 +79,7 @@ def _setUp(self): sess.run(init_op) graph = tf.get_default_graph() input_graph_def = graph.as_graph_def() - nodes = "o_dipole,o_rmat,o_rmat_deriv,o_nlist,o_rij,descrpt_attr/rcut,descrpt_attr/ntypes,descrpt_attr/sel,descrpt_attr/ndescrpt,model_attr/tmap,model_attr/sel_type,model_attr/model_type" + nodes = "o_dipole,o_rmat,o_rmat_deriv,o_nlist,o_rij,descrpt_attr/rcut,descrpt_attr/ntypes,descrpt_attr/sel,descrpt_attr/ndescrpt,model_attr/tmap,model_attr/sel_type,model_attr/model_type,model_attr/output_dim,model_attr/model_version" output_graph_def = tf.graph_util.convert_variables_to_constants( sess, input_graph_def, @@ -150,7 +150,7 @@ def _test_fv (self): num_deriv = np.transpose(num_deriv, [0,2,1]) t_esti = np.matmul(num_deriv, box3) - print(t_esti, '\n', vv.reshape([-1, 3, 3])) + # print(t_esti, '\n', vv.reshape([-1, 3, 3])) for ff in range(nframes): for ii in range(3): for jj in range(3): diff --git a/source/tests/test_data_modifier_shuffle.py b/source/tests/test_data_modifier_shuffle.py index 39269c2ff5..36ebfef35a 100644 --- a/source/tests/test_data_modifier_shuffle.py +++ b/source/tests/test_data_modifier_shuffle.py @@ -83,7 +83,7 @@ def _setUp(self): sess.run(init_op) graph = tf.get_default_graph() input_graph_def = graph.as_graph_def() - nodes = "o_dipole,o_rmat,o_rmat_deriv,o_nlist,o_rij,descrpt_attr/rcut,descrpt_attr/ntypes,descrpt_attr/sel,descrpt_attr/ndescrpt,model_attr/tmap,model_attr/sel_type,model_attr/model_type" + nodes = "o_dipole,o_rmat,o_rmat_deriv,o_nlist,o_rij,descrpt_attr/rcut,descrpt_attr/ntypes,descrpt_attr/sel,descrpt_attr/ndescrpt,model_attr/tmap,model_attr/sel_type,model_attr/model_type,model_attr/output_dim,model_attr/model_version" output_graph_def = tf.graph_util.convert_variables_to_constants( sess, input_graph_def, From 91971a2585ea2df5a686d7741bd1ac5dae34efa6 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 16 Mar 2021 15:02:20 +0800 Subject: [PATCH 278/562] fix bug of model path in UT --- source/tests/test_deeppot_a.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/source/tests/test_deeppot_a.py b/source/tests/test_deeppot_a.py index b9a519672d..8541cb8fa3 100644 --- a/source/tests/test_deeppot_a.py +++ b/source/tests/test_deeppot_a.py @@ -25,18 +25,19 @@ def setUp(self): if "string_val:" in data[jj]: data[jj] = data[jj].replace(MODEL_VERSION, "0.0") break - with open("deeppot-ver.pbtxt", "w") as fp: + self.version_pbtxt = str(tests_path / "deeppot-ver.pbtxt") + self.version_pb = str(tests_path / "deeppot.pb") + with open(self.version_pbtxt, "w") as fp: fp.write("\n".join(data)) - - convert_pbtxt_to_pb(str(tests_path / os.path.join("deeppot-ver.pbtxt")), "deeppot.pb") + convert_pbtxt_to_pb(self.version_pbtxt, self.version_pb) def tearDown(self): - os.remove("deeppot-ver.pbtxt") - os.remove("deeppot.pb") + os.remove(self.version_pbtxt) + os.remove(self.version_pb) def test(self): with self.assertRaises(RuntimeError) as context: - DeepPot("deeppot.pb") + DeepPot(str(self.version_pb)) self.assertTrue('incompatible' in str(context.exception)) self.assertTrue(MODEL_VERSION in str(context.exception)) self.assertTrue('0.0' in str(context.exception)) @@ -54,18 +55,19 @@ def setUp(self): if "string_val:" in data[jj]: data[jj] = data[jj].replace(MODEL_VERSION, "0.1000000") break - with open("deeppot-ver.pbtxt", "w") as fp: + self.version_pbtxt = str(tests_path / "deeppot-ver.pbtxt") + self.version_pb = str(tests_path / "deeppot.pb") + with open(self.version_pbtxt, "w") as fp: fp.write("\n".join(data)) - - convert_pbtxt_to_pb(str(tests_path / os.path.join("deeppot-ver.pbtxt")), "deeppot.pb") + convert_pbtxt_to_pb(self.version_pbtxt, self.version_pb) def tearDown(self): - os.remove("deeppot-ver.pbtxt") - os.remove("deeppot.pb") + os.remove(self.version_pbtxt) + os.remove(self.version_pb) def test(self): with self.assertRaises(RuntimeError) as context: - DeepPot("deeppot.pb") + DeepPot(self.version_pb) self.assertTrue('incompatible' in str(context.exception)) self.assertTrue(MODEL_VERSION in str(context.exception)) self.assertTrue('0.1000000' in str(context.exception)) From 8d6a29f80d6374f831f627fa6f28583b2b9937a1 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 16 Mar 2021 15:59:57 +0800 Subject: [PATCH 279/562] include the c++ api with deepmd prefix --- source/lmp/env.sh.in | 2 +- source/lmp/fix_dplr.h | 4 ++-- source/lmp/pair_deepmd.h.in | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/lmp/env.sh.in b/source/lmp/env.sh.in index 4baf835aff..a59ad84960 100644 --- a/source/lmp/env.sh.in +++ b/source/lmp/env.sh.in @@ -6,6 +6,6 @@ TF_INCLUDE_DIRS=`echo $TENSORFLOW_INCLUDE_DIRS | sed "s/;/ -I/g"` TF_LIBRARY_PATH=`echo $TENSORFLOW_LIBRARY_PATH | sed "s/;/ -L/g"` TF_RPATH=`echo $TENSORFLOW_LIBRARY_PATH | sed "s/;/ -Wl,-rpath=/g"` -NNP_INC=" -std=c++11 @PREC_DEF@ @TTM_DEF@ @OLD_LMP_PPPM_DEF@ -I$TF_INCLUDE_DIRS -I$DEEPMD_ROOT/include/deepmd " +NNP_INC=" -std=c++11 @PREC_DEF@ @TTM_DEF@ @OLD_LMP_PPPM_DEF@ -I$TF_INCLUDE_DIRS -I$DEEPMD_ROOT/include/ " NNP_PATH=" -L$TF_LIBRARY_PATH -L$DEEPMD_ROOT/lib" NNP_LIB=" -Wl,--no-as-needed -l@LIB_DEEPMD_OP_CUDA@ -l@LIB_DEEPMD_OP@ -l@LIB_DEEPMD_CC@ -l@LIB_DEEPMD@ -ltensorflow_cc -ltensorflow_framework -Wl,-rpath=$TF_RPATH -Wl,-rpath=$DEEPMD_ROOT/lib" diff --git a/source/lmp/fix_dplr.h b/source/lmp/fix_dplr.h index d81d8bd3db..aa8c95dd09 100644 --- a/source/lmp/fix_dplr.h +++ b/source/lmp/fix_dplr.h @@ -10,8 +10,8 @@ FixStyle(dplr,FixDPLR) #include #include "fix.h" #include "pair_deepmd.h" -#include "DeepTensor.h" -#include "DataModifier.h" +#include "deepmd/DeepTensor.h" +#include "deepmd/DataModifier.h" #ifdef HIGH_PREC #define FLOAT_PREC double diff --git a/source/lmp/pair_deepmd.h.in b/source/lmp/pair_deepmd.h.in index 6a5c24444a..25d950c948 100644 --- a/source/lmp/pair_deepmd.h.in +++ b/source/lmp/pair_deepmd.h.in @@ -21,7 +21,7 @@ PairStyle(deepmd,PairDeepMD) #define LMP_PAIR_NNP_H #include "pair.h" -#include "DeepPot.h" +#include "deepmd/DeepPot.h" #include #include From 48962fb70b02709cb374edd46a14a346ead05eba Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 16 Mar 2021 19:56:14 +0800 Subject: [PATCH 280/562] add deepmd namespace for the c++ interface --- source/api_cc/include/AtomMap.h | 2 + source/api_cc/include/DataModifier.h | 10 +- source/api_cc/include/DeepPot.h | 17 +- source/api_cc/include/DeepTensor.h | 13 +- source/api_cc/include/common.h | 126 ++------- source/api_cc/src/AtomMap.cc | 2 + source/api_cc/src/DataModifier.cc | 11 +- source/api_cc/src/DeepPot.cc | 26 +- source/api_cc/src/DeepTensor.cc | 11 +- source/api_cc/src/common.cc | 244 +++++++++++++++--- source/api_cc/tests/test_deepdipole.cc | 10 +- source/api_cc/tests/test_deeppolar.cc | 10 +- source/api_cc/tests/test_deeppot_a.cc | 22 +- .../api_cc/tests/test_deeppot_model_devi.cc | 18 +- source/api_cc/tests/test_deeppot_r.cc | 22 +- source/api_cc/tests/test_dipolecharge.cc | 20 +- source/ipi/driver.cc | 14 +- source/lmp/fix_dplr.cpp | 6 +- source/lmp/fix_dplr.h | 4 +- source/lmp/pair_deepmd.cpp | 2 +- source/lmp/pair_deepmd.h.in | 4 +- 21 files changed, 344 insertions(+), 250 deletions(-) diff --git a/source/api_cc/include/AtomMap.h b/source/api_cc/include/AtomMap.h index 32c4ed7c99..bf9a8c650c 100644 --- a/source/api_cc/include/AtomMap.h +++ b/source/api_cc/include/AtomMap.h @@ -4,6 +4,7 @@ // using namespace std; +namespace deepmd{ template class AtomMap { @@ -25,3 +26,4 @@ class AtomMap std::vector fwd_idx_map; std::vector atype; }; +} diff --git a/source/api_cc/include/DataModifier.h b/source/api_cc/include/DataModifier.h index 822812621b..114abfd889 100644 --- a/source/api_cc/include/DataModifier.h +++ b/source/api_cc/include/DataModifier.h @@ -2,6 +2,7 @@ #include "DeepPot.h" +namespace deepmd{ class DipoleChargeModifier { public: @@ -28,10 +29,10 @@ class DipoleChargeModifier int numb_types () const {assert(inited); return ntypes;}; std::vector sel_types () const {assert(inited); return sel_type;}; private: - Session* session; + tensorflow::Session* session; std::string name_scope, name_prefix; int num_intra_nthreads, num_inter_nthreads; - GraphDef graph_def; + tensorflow::GraphDef graph_def; bool inited; VALUETYPE rcut; VALUETYPE cell_size; @@ -42,9 +43,10 @@ class DipoleChargeModifier template void get_vector(std::vector & vec, const std::string & name) const; void run_model (std::vector & dforce, std::vector & dvirial, - Session * session, - const std::vector> & input_tensors, + tensorflow::Session * session, + const std::vector> & input_tensors, const AtomMap & atommap, const int nghost); }; +} diff --git a/source/api_cc/include/DeepPot.h b/source/api_cc/include/DeepPot.h index 53996903c1..63cf568376 100644 --- a/source/api_cc/include/DeepPot.h +++ b/source/api_cc/include/DeepPot.h @@ -2,8 +2,8 @@ #include "common.h" #include "neighbor_list.h" -typedef double compute_t; +namespace deepmd{ class DeepPot { public: @@ -61,9 +61,9 @@ class DeepPot int dim_aparam () const {assert(inited); return daparam;}; void get_type_map (std::string & type_map); private: - Session* session; + tensorflow::Session* session; int num_intra_nthreads, num_inter_nthreads; - GraphDef graph_def; + tensorflow::GraphDef graph_def; bool inited; template VT get_scalar(const std::string & name) const; // VALUETYPE get_rcut () const; @@ -92,7 +92,6 @@ class DeepPot // copy neighbor list info from host bool init_nbor; std::vector sec_a; - compute_t *array_double; NeighborListData nlist_data; InputNlist nlist; AtomMap atommap; @@ -156,9 +155,9 @@ class DeepPotModelDevi const VALUETYPE eps); private: unsigned numb_models; - std::vector sessions; + std::vector sessions; int num_intra_nthreads, num_inter_nthreads; - std::vector graph_defs; + std::vector graph_defs; bool inited; template VT get_scalar(const std::string name) const; // VALUETYPE get_rcut () const; @@ -176,15 +175,15 @@ class DeepPotModelDevi // copy neighbor list info from host bool init_nbor; - compute_t *array_double; std::vector > sec; - AtomMap atommap; + deepmd::AtomMap atommap; NeighborListData nlist_data; InputNlist nlist; // function used for nborlist copy std::vector > get_sel() const; - void cum_sum(const std::vector > n_sel); + void cum_sum(const std::vector > n_sel); }; +} diff --git a/source/api_cc/include/DeepTensor.h b/source/api_cc/include/DeepTensor.h index a60c6e1ed9..bfa5cd1ba8 100644 --- a/source/api_cc/include/DeepTensor.h +++ b/source/api_cc/include/DeepTensor.h @@ -1,7 +1,9 @@ #pragma once -#include "DeepPot.h" +#include "common.h" +#include "neighbor_list.h" +namespace deepmd{ class DeepTensor { public: @@ -29,10 +31,10 @@ class DeepTensor int output_dim () const {assert(inited); return odim;}; const std::vector & sel_types () const {assert(inited); return sel_type;}; private: - Session* session; + tensorflow::Session* session; std::string name_scope; int num_intra_nthreads, num_inter_nthreads; - GraphDef graph_def; + tensorflow::GraphDef graph_def; bool inited; VALUETYPE rcut; VALUETYPE cell_size; @@ -44,8 +46,8 @@ class DeepTensor template VT get_scalar(const std::string & name) const; template void get_vector (std::vector & vec, const std::string & name) const; void run_model (std::vector & d_tensor_, - Session * session, - const std::vector> & input_tensors, + tensorflow::Session * session, + const std::vector> & input_tensors, const AtomMap & atommap, const int nghost = 0); void compute_inner (std::vector & value, @@ -59,4 +61,5 @@ class DeepTensor const int nghost, const InputNlist& inlist); }; +} diff --git a/source/api_cc/include/common.h b/source/api_cc/include/common.h index 46eb076d4f..c489053b6c 100644 --- a/source/api_cc/include/common.h +++ b/source/api_cc/include/common.h @@ -13,7 +13,9 @@ #include #include -using namespace tensorflow; + +namespace deepmd{ + #if TF_MAJOR_VERSION >= 2 && TF_MINOR_VERSION >= 2 typedef tensorflow::tstring STRINGTYPE; #else @@ -37,7 +39,7 @@ struct NeighborListData public: void copy_from_nlist(const InputNlist & inlist); void shuffle(const std::vector & fwd_map); - void shuffle(const AtomMap & map); + void shuffle(const deepmd::AtomMap & map); void shuffle_exclude_empty(const std::vector & fwd_map); void make_inlist(InputNlist & inlist); }; @@ -76,20 +78,30 @@ get_env_nthreads(int & num_intra_nthreads, int & num_inter_nthreads); void -checkStatus(const tensorflow::Status& status); +check_status( + const tensorflow::Status& status); -std::string name_prefix(const std::string & name_scope); +std::string +name_prefix( + const std::string & name_scope); template VT -session_get_scalar(Session* session, const std::string name, const std::string scope = ""); +session_get_scalar( + tensorflow::Session* session, + const std::string name, + const std::string scope = ""); template void -session_get_vector(std::vector & o_vec, Session* session, const std::string name_, const std::string scope = ""); +session_get_vector( + std::vector & o_vec, + tensorflow::Session* session, + const std::string name_, + const std::string scope = ""); int -session_input_tensors (std::vector> & input_tensors, +session_input_tensors (std::vector> & input_tensors, const std::vector & dcoord_, const int & ntypes, const std::vector & datype_, @@ -97,11 +109,11 @@ session_input_tensors (std::vector> & input_tenso const VALUETYPE & cell_size, const std::vector & fparam_, const std::vector & aparam_, - const AtomMap& atommap, + const deepmd::AtomMap&atommap, const std::string scope = ""); int -session_input_tensors (std::vector> & input_tensors, +session_input_tensors (std::vector> & input_tensors, const std::vector & dcoord_, const int & ntypes, const std::vector & datype_, @@ -109,103 +121,9 @@ session_input_tensors (std::vector> & input_tenso InputNlist & dlist, const std::vector & fparam_, const std::vector & aparam_, - const AtomMap& atommap, + const deepmd::AtomMap&atommap, const int nghost, const int ago, const std::string scope = ""); - -// int -// session_input_tensors (std::vector> & input_tensors, -// const std::vector & dcoord_, -// const int & ntypes, -// const std::vector & datype_, -// const std::vector & dbox, -// InputNlist & dlist, -// const std::vector & fparam_, -// const std::vector & aparam_, -// const AtomMap& atommap, -// const int nghost, -// const std::string scope = ""); - -// int -// session_input_tensors (std::vector>& input_tensors, -// const std::vector & dcoord_, -// const int & ntypes, -// const std::vector & atype_, -// const std::vector & dbox, -// const int * ilist, -// const int * jrange, -// const int * jlist, -// const std::vector & fparam_, -// const std::vector & aparam_, -// const AtomMap & atommap, -// const int & nghost); - - -template -VT -session_get_scalar(Session* session, const std::string name_, const std::string scope) -{ - std::string name = name_; - if (scope != "") { - name = scope + "/" + name; - } - std::vector output_tensors; - checkStatus (session->Run(std::vector> ({}), - {name.c_str()}, - {}, - &output_tensors)); - Tensor output_rc = output_tensors[0]; - auto orc = output_rc.flat (); - return orc(0); -} - -template -void -session_get_vector(std::vector & o_vec, Session* session, const std::string name_, const std::string scope) -{ - std::string name = name_; - if (scope != "") { - name = scope + "/" + name; - } - std::vector output_tensors; - checkStatus (session->Run(std::vector> ({}), - {name.c_str()}, - {}, - &output_tensors)); - Tensor output_rc = output_tensors[0]; - assert(1 == output_rc.shape().dims()); - int dof = output_rc.shape().dim_size(0); - o_vec.resize(dof); - auto orc = output_rc.flat (); - for (int ii = 0; ii < dof; ++ii){ - o_vec[ii] = orc(ii); - } -} - - -template -void -select_map(std::vector & out, - const std::vector & in, - const std::vector & idx_map, - const int & stride) -{ -#ifdef DEBUG - assert(in.size() / stride * stride == in.size()), "in size should be multiples of stride" -#endif - for (int ii = 0; ii < in.size() / stride; ++ii){ -#ifdef DEBUG - assert(ii < idx_map.size()), "idx goes over the idx map size"; - assert(idx_map[ii] < out.size()), "mappped idx goes over the out size"; -#endif - if (idx_map[ii] >= 0) { - int to_ii = idx_map[ii]; - for (int dd = 0; dd < stride; ++dd){ - out[to_ii * stride + dd] = in[ii * stride + dd]; - } - } - } } - diff --git a/source/api_cc/src/AtomMap.cc b/source/api_cc/src/AtomMap.cc index dc37669fa6..8e7e82a1ce 100644 --- a/source/api_cc/src/AtomMap.cc +++ b/source/api_cc/src/AtomMap.cc @@ -3,6 +3,8 @@ #include #include +using namespace deepmd; + template AtomMap:: AtomMap() {} diff --git a/source/api_cc/src/DataModifier.cc b/source/api_cc/src/DataModifier.cc index 94ebadf724..f704ba599e 100644 --- a/source/api_cc/src/DataModifier.cc +++ b/source/api_cc/src/DataModifier.cc @@ -1,5 +1,8 @@ #include "DataModifier.h" +using namespace deepmd; +using namespace tensorflow; + DipoleChargeModifier:: DipoleChargeModifier() : inited (false) @@ -30,9 +33,9 @@ init (const std::string & model, get_env_nthreads(num_intra_nthreads, num_inter_nthreads); options.config.set_inter_op_parallelism_threads(num_inter_nthreads); options.config.set_intra_op_parallelism_threads(num_intra_nthreads); - checkStatus(NewSession(options, &session)); - checkStatus(ReadBinaryProto(Env::Default(), model, &graph_def)); - checkStatus(session->Create(graph_def)); + deepmd::check_status(NewSession(options, &session)); + deepmd::check_status(ReadBinaryProto(Env::Default(), model, &graph_def)); + deepmd::check_status(session->Create(graph_def)); // int nnodes = graph_def.node_size(); // for (int ii = 0; ii < nnodes; ++ii){ // cout << ii << " \t " << graph_def.node(ii).name() << endl; @@ -80,7 +83,7 @@ run_model (std::vector & dforce, } std::vector output_tensors; - checkStatus (session->Run(input_tensors, + deepmd::check_status (session->Run(input_tensors, {"o_dm_force", "o_dm_virial", "o_dm_av"}, {}, &output_tensors)); diff --git a/source/api_cc/src/DeepPot.cc b/source/api_cc/src/DeepPot.cc index a5b9e6db8e..9a3e8d7a10 100644 --- a/source/api_cc/src/DeepPot.cc +++ b/source/api_cc/src/DeepPot.cc @@ -2,6 +2,8 @@ #include "AtomMap.h" #include +using namespace tensorflow; +using namespace deepmd; #if GOOGLE_CUDA #include "cuda_runtime.h" @@ -54,7 +56,7 @@ run_model (ENERGYTYPE & dener, } std::vector output_tensors; - checkStatus (session->Run(input_tensors, + check_status (session->Run(input_tensors, {"o_energy", "o_force", "o_atom_virial"}, {}, &output_tensors)); @@ -95,7 +97,7 @@ static void run_model (ENERGYTYPE & dener, std::vector& datom_virial_, Session* session, const std::vector> & input_tensors, - const AtomMap & atommap, + const deepmd::AtomMap & atommap, const int& nghost = 0) { unsigned nloc = atommap.get_type().size(); @@ -119,7 +121,7 @@ static void run_model (ENERGYTYPE & dener, } std::vector output_tensors; - checkStatus (session->Run(input_tensors, + check_status (session->Run(input_tensors, {"o_energy", "o_force", "o_atom_energy", "o_atom_virial"}, {}, &output_tensors)); @@ -199,7 +201,7 @@ init (const std::string & model, const int & gpu_rank, const std::string & file_ options.config.set_intra_op_parallelism_threads(num_intra_nthreads); if(file_content.size() == 0) - checkStatus (ReadBinaryProto(Env::Default(), model, &graph_def)); + check_status (ReadBinaryProto(Env::Default(), model, &graph_def)); else graph_def.ParseFromString(file_content); int gpu_num = -1; @@ -215,8 +217,8 @@ init (const std::string & model, const int & gpu_rank, const std::string & file_ graph::SetDefaultDevice(str, &graph_def); } #endif // GOOGLE_CUDA - checkStatus (NewSession(options, &session)); - checkStatus (session->Create(graph_def)); + check_status (NewSession(options, &session)); + check_status (session->Create(graph_def)); rcut = get_scalar("descrpt_attr/rcut"); cell_size = rcut; ntypes = get_scalar("descrpt_attr/ntypes"); @@ -334,7 +336,7 @@ compute (ENERGYTYPE & dener, { int nall = dcoord_.size() / 3; int nloc = nall; - atommap = AtomMap (datype_.begin(), datype_.begin() + nloc); + atommap = deepmd::AtomMap (datype_.begin(), datype_.begin() + nloc); assert (nloc == atommap.get_type().size()); validate_fparam_aparam(nloc, fparam, aparam); @@ -406,7 +408,7 @@ compute_inner (ENERGYTYPE & dener, // agp == 0 means that the LAMMPS nbor list has been updated if (ago == 0) { - atommap = AtomMap (datype_.begin(), datype_.begin() + nloc); + atommap = deepmd::AtomMap (datype_.begin(), datype_.begin() + nloc); assert (nloc == atommap.get_type().size()); nlist_data.shuffle(atommap); nlist_data.make_inlist(nlist); @@ -430,7 +432,7 @@ compute (ENERGYTYPE & dener, const std::vector & fparam, const std::vector & aparam) { - atommap = AtomMap (datype_.begin(), datype_.end()); + atommap = deepmd::AtomMap (datype_.begin(), datype_.end()); validate_fparam_aparam(atommap.get_type().size(), fparam, aparam); std::vector> input_tensors; @@ -527,7 +529,7 @@ init (const std::vector & models, const int & gpu_rank, const std:: options.config.set_intra_op_parallelism_threads(num_intra_nthreads); for (unsigned ii = 0; ii < numb_models; ++ii){ if (file_contents.size() == 0) - checkStatus (ReadBinaryProto(Env::Default(), models[ii], &graph_defs[ii])); + check_status (ReadBinaryProto(Env::Default(), models[ii], &graph_defs[ii])); else graph_defs[ii].ParseFromString(file_contents[ii]); } @@ -546,8 +548,8 @@ init (const std::vector & models, const int & gpu_rank, const std:: str += std::to_string(gpu_rank % gpu_num); graph::SetDefaultDevice(str, &graph_defs[ii]); } - checkStatus (NewSession(options, &(sessions[ii]))); - checkStatus (sessions[ii]->Create(graph_defs[ii])); + check_status (NewSession(options, &(sessions[ii]))); + check_status (sessions[ii]->Create(graph_defs[ii])); } rcut = get_scalar("descrpt_attr/rcut"); cell_size = rcut; diff --git a/source/api_cc/src/DeepTensor.cc b/source/api_cc/src/DeepTensor.cc index e701c044f9..a907ae0e19 100644 --- a/source/api_cc/src/DeepTensor.cc +++ b/source/api_cc/src/DeepTensor.cc @@ -1,5 +1,8 @@ #include "DeepTensor.h" +using namespace deepmd; +using namespace tensorflow; + DeepTensor:: DeepTensor() : inited (false) @@ -30,9 +33,9 @@ init (const std::string & model, get_env_nthreads(num_intra_nthreads, num_inter_nthreads); options.config.set_inter_op_parallelism_threads(num_inter_nthreads); options.config.set_intra_op_parallelism_threads(num_intra_nthreads); - checkStatus (NewSession(options, &session)); - checkStatus (ReadBinaryProto(Env::Default(), model, &graph_def)); - checkStatus (session->Create(graph_def)); + deepmd::check_status (NewSession(options, &session)); + deepmd::check_status (ReadBinaryProto(Env::Default(), model, &graph_def)); + deepmd::check_status (session->Create(graph_def)); rcut = get_scalar("descrpt_attr/rcut"); cell_size = rcut; ntypes = get_scalar("descrpt_attr/ntypes"); @@ -82,7 +85,7 @@ run_model (std::vector & d_tensor_, } std::vector output_tensors; - checkStatus (session->Run(input_tensors, + deepmd::check_status (session->Run(input_tensors, {name_prefix(name_scope) + "o_" + model_type}, {}, &output_tensors)); diff --git a/source/api_cc/src/common.cc b/source/api_cc/src/common.cc index 560790c1a1..74c317529e 100644 --- a/source/api_cc/src/common.cc +++ b/source/api_cc/src/common.cc @@ -2,6 +2,8 @@ #include "AtomMap.h" #include "device.h" +using namespace tensorflow; + static std::vector split(const std::string &input_, const std::string &delimiter) @@ -18,6 +20,7 @@ split(const std::string &input_, } bool +deepmd:: model_compatable( std::string & model_version) { @@ -43,10 +46,11 @@ model_compatable( } void +deepmd:: select_by_type(std::vector & fwd_map, std::vector & bkw_map, int & nghost_real, - const std::vector & dcoord_, + const std::vector & dcoord_, const std::vector & datype_, const int & nghost, const std::vector & sel_type_) @@ -84,10 +88,11 @@ select_by_type(std::vector & fwd_map, void +deepmd:: select_real_atoms(std::vector & fwd_map, std::vector & bkw_map, int & nghost_real, - const std::vector & dcoord_, + const std::vector & dcoord_, const std::vector & datype_, const int & nghost, const int & ntypes) @@ -96,12 +101,12 @@ select_real_atoms(std::vector & fwd_map, for (int ii = 0; ii < ntypes; ++ii){ sel_type.push_back(ii); } - select_by_type(fwd_map, bkw_map, nghost_real, dcoord_, datype_, nghost, sel_type); + deepmd::select_by_type(fwd_map, bkw_map, nghost_real, dcoord_, datype_, nghost, sel_type); } void -NeighborListData:: +deepmd::NeighborListData:: copy_from_nlist(const InputNlist & inlist) { int inum = inlist.inum; @@ -117,15 +122,15 @@ copy_from_nlist(const InputNlist & inlist) void -NeighborListData:: -shuffle(const AtomMap & map) +deepmd::NeighborListData:: +shuffle(const AtomMap & map) { const std::vector & fwd_map = map.get_fwd_map(); shuffle(fwd_map); } void -NeighborListData:: +deepmd::NeighborListData:: shuffle(const std::vector & fwd_map) { int nloc = fwd_map.size(); @@ -144,7 +149,7 @@ shuffle(const std::vector & fwd_map) } void -NeighborListData:: +deepmd::NeighborListData:: shuffle_exclude_empty (const std::vector & fwd_map) { shuffle(fwd_map); @@ -175,7 +180,7 @@ shuffle_exclude_empty (const std::vector & fwd_map) } void -NeighborListData:: +deepmd::NeighborListData:: make_inlist(InputNlist & inlist) { int nloc = ilist.size(); @@ -192,7 +197,8 @@ make_inlist(InputNlist & inlist) } void -checkStatus(const tensorflow::Status& status) { +deepmd:: +check_status(const tensorflow::Status& status) { if (!status.ok()) { std::cout << status.ToString() << std::endl; exit(1); @@ -200,6 +206,7 @@ checkStatus(const tensorflow::Status& status) { } void +deepmd:: get_env_nthreads(int & num_intra_nthreads, int & num_inter_nthreads) { @@ -222,6 +229,7 @@ get_env_nthreads(int & num_intra_nthreads, } std::string +deepmd:: name_prefix(const std::string & scope) { std::string prefix = ""; @@ -232,16 +240,18 @@ name_prefix(const std::string & scope) } int -session_input_tensors (std::vector> & input_tensors, - const std::vector & dcoord_, - const int & ntypes, - const std::vector & datype_, - const std::vector & dbox, - const VALUETYPE & cell_size, - const std::vector & fparam_, - const std::vector & aparam_, - const AtomMap& atommap, - const std::string scope) +deepmd:: +session_input_tensors ( + std::vector> & input_tensors, + const std::vector & dcoord_, + const int & ntypes, + const std::vector & datype_, + const std::vector & dbox, + const deepmd::VALUETYPE & cell_size, + const std::vector & fparam_, + const std::vector & aparam_, + const deepmd::AtomMap& atommap, + const std::string scope) { bool b_pbc = (dbox.size() == 9); @@ -297,15 +307,15 @@ session_input_tensors (std::vector> & input_tenso Tensor mesh_tensor (DT_INT32, mesh_shape); Tensor natoms_tensor (DT_INT32, natoms_shape); - auto coord = coord_tensor.matrix (); + auto coord = coord_tensor.matrix (); auto type = type_tensor.matrix (); - auto box = box_tensor.matrix (); + auto box = box_tensor.matrix (); auto mesh = mesh_tensor.flat (); auto natoms = natoms_tensor.flat (); - auto fparam = fparam_tensor.matrix (); - auto aparam = aparam_tensor.matrix (); + auto fparam = fparam_tensor.matrix (); + auto aparam = aparam_tensor.matrix (); - std::vector dcoord (dcoord_); + std::vector dcoord (dcoord_); atommap.forward (dcoord.begin(), dcoord_.begin(), 3); for (int ii = 0; ii < nframes; ++ii){ @@ -365,18 +375,20 @@ session_input_tensors (std::vector> & input_tenso } int -session_input_tensors (std::vector> & input_tensors, - const std::vector & dcoord_, - const int & ntypes, - const std::vector & datype_, - const std::vector & dbox, - InputNlist & dlist, - const std::vector & fparam_, - const std::vector & aparam_, - const AtomMap& atommap, - const int nghost, - const int ago, - const std::string scope) +deepmd:: +session_input_tensors ( + std::vector> & input_tensors, + const std::vector & dcoord_, + const int & ntypes, + const std::vector & datype_, + const std::vector & dbox, + InputNlist & dlist, + const std::vector & fparam_, + const std::vector & aparam_, + const deepmd::AtomMap& atommap, + const int nghost, + const int ago, + const std::string scope) { assert (dbox.size() == 9); @@ -427,15 +439,15 @@ session_input_tensors (std::vector> & input_tenso Tensor mesh_tensor (DT_INT32, mesh_shape); Tensor natoms_tensor (DT_INT32, natoms_shape); - auto coord = coord_tensor.matrix (); + auto coord = coord_tensor.matrix (); auto type = type_tensor.matrix (); - auto box = box_tensor.matrix (); + auto box = box_tensor.matrix (); auto mesh = mesh_tensor.flat (); auto natoms = natoms_tensor.flat (); - auto fparam = fparam_tensor.matrix (); - auto aparam = aparam_tensor.matrix (); + auto fparam = fparam_tensor.matrix (); + auto aparam = aparam_tensor.matrix (); - std::vector dcoord (dcoord_); + std::vector dcoord (dcoord_); atommap.forward (dcoord.begin(), dcoord_.begin(), 3); for (int ii = 0; ii < nframes; ++ii){ @@ -493,3 +505,151 @@ session_input_tensors (std::vector> & input_tenso return nloc; } +template +VT +deepmd:: +session_get_scalar(Session* session, const std::string name_, const std::string scope) +{ + std::string name = name_; + if (scope != "") { + name = scope + "/" + name; + } + std::vector output_tensors; + deepmd::check_status (session->Run(std::vector> ({}), + {name.c_str()}, + {}, + &output_tensors)); + Tensor output_rc = output_tensors[0]; + auto orc = output_rc.flat (); + return orc(0); +} + +template +void +deepmd:: +session_get_vector(std::vector & o_vec, Session* session, const std::string name_, const std::string scope) +{ + std::string name = name_; + if (scope != "") { + name = scope + "/" + name; + } + std::vector output_tensors; + deepmd::check_status (session->Run(std::vector> ({}), + {name.c_str()}, + {}, + &output_tensors)); + Tensor output_rc = output_tensors[0]; + assert(1 == output_rc.shape().dims()); + int dof = output_rc.shape().dim_size(0); + o_vec.resize(dof); + auto orc = output_rc.flat (); + for (int ii = 0; ii < dof; ++ii){ + o_vec[ii] = orc(ii); + } +} + + +template +void +deepmd:: +select_map(std::vector & out, + const std::vector & in, + const std::vector & idx_map, + const int & stride) +{ +#ifdef DEBUG + assert(in.size() / stride * stride == in.size()), "in size should be multiples of stride" +#endif + for (int ii = 0; ii < in.size() / stride; ++ii){ +#ifdef DEBUG + assert(ii < idx_map.size()), "idx goes over the idx map size"; + assert(idx_map[ii] < out.size()), "mappped idx goes over the out size"; +#endif + if (idx_map[ii] >= 0) { + int to_ii = idx_map[ii]; + for (int dd = 0; dd < stride; ++dd){ + out[to_ii * stride + dd] = in[ii * stride + dd]; + } + } + } +} + + +template +int +deepmd:: +session_get_scalar(Session*, const std::string, const std::string); + +template +void +deepmd:: +session_get_vector(std::vector &, Session*, const std::string, const std::string); + +template +void +deepmd:: +select_map( + std::vector & out, + const std::vector & in, + const std::vector & idx_map, + const int & stride); + + +template +float +deepmd:: +session_get_scalar(Session*, const std::string, const std::string); + +template +void +deepmd:: +session_get_vector(std::vector &, Session*, const std::string, const std::string); + +template +void +deepmd:: +select_map( + std::vector & out, + const std::vector & in, + const std::vector & idx_map, + const int & stride); + + +template +double +deepmd:: +session_get_scalar(Session*, const std::string, const std::string); + +template +void +deepmd:: +session_get_vector(std::vector &, Session*, const std::string, const std::string); + +template +void +deepmd:: +select_map( + std::vector & out, + const std::vector & in, + const std::vector & idx_map, + const int & stride); + + +template +deepmd::STRINGTYPE +deepmd:: +session_get_scalar(Session*, const std::string, const std::string); + +template +void +deepmd:: +session_get_vector(std::vector &, Session*, const std::string, const std::string); + +template +void +deepmd:: +select_map( + std::vector & out, + const std::vector & in, + const std::vector & idx_map, + const int & stride); diff --git a/source/api_cc/tests/test_deepdipole.cc b/source/api_cc/tests/test_deepdipole.cc index 04d068ddfb..bfdcc1de17 100644 --- a/source/api_cc/tests/test_deepdipole.cc +++ b/source/api_cc/tests/test_deepdipole.cc @@ -35,20 +35,20 @@ class TestInferDeepDipole : public ::testing::Test }; int natoms; - DeepTensor dp; + deepmd::DeepTensor dp; void SetUp() override { std::string file_name = "../../tests/infer/deepdipole.pbtxt"; int fd = open(file_name.c_str(), O_RDONLY); - protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); - GraphDef graph_def; - protobuf::TextFormat::Parse(input, &graph_def); + tensorflow::protobuf::io::ZeroCopyInputStream* input = new tensorflow::protobuf::io::FileInputStream(fd); + tensorflow::GraphDef graph_def; + tensorflow::protobuf::TextFormat::Parse(input, &graph_def); delete input; std::fstream output("deepdipole.pb", std::ios::out | std::ios::trunc | std::ios::binary); graph_def.SerializeToOstream(&output); // check the string by the following commands // string txt; - // protobuf::TextFormat::PrintToString(graph_def, &txt); + // tensorflow::protobuf::TextFormat::PrintToString(graph_def, &txt); dp.init("deepdipole.pb"); diff --git a/source/api_cc/tests/test_deeppolar.cc b/source/api_cc/tests/test_deeppolar.cc index acae6e13e0..19e9b8af7c 100644 --- a/source/api_cc/tests/test_deeppolar.cc +++ b/source/api_cc/tests/test_deeppolar.cc @@ -35,20 +35,20 @@ class TestInferDeepPolar : public ::testing::Test }; int natoms; - DeepTensor dp; + deepmd::DeepTensor dp; void SetUp() override { std::string file_name = "../../tests/infer/deeppolar.pbtxt"; int fd = open(file_name.c_str(), O_RDONLY); - protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); - GraphDef graph_def; - protobuf::TextFormat::Parse(input, &graph_def); + tensorflow::protobuf::io::ZeroCopyInputStream* input = new tensorflow::protobuf::io::FileInputStream(fd); + tensorflow::GraphDef graph_def; + tensorflow::protobuf::TextFormat::Parse(input, &graph_def); delete input; std::fstream output("deeppolar.pb", std::ios::out | std::ios::trunc | std::ios::binary); graph_def.SerializeToOstream(&output); // check the string by the following commands // string txt; - // protobuf::TextFormat::PrintToString(graph_def, &txt); + // tensorflow::protobuf::TextFormat::PrintToString(graph_def, &txt); dp.init("deeppolar.pb"); diff --git a/source/api_cc/tests/test_deeppot_a.cc b/source/api_cc/tests/test_deeppot_a.cc index 01f5d6f421..77b343f91e 100644 --- a/source/api_cc/tests/test_deeppot_a.cc +++ b/source/api_cc/tests/test_deeppot_a.cc @@ -43,20 +43,20 @@ class TestInferDeepPotA : public ::testing::Test double expected_tot_e; std::vectorexpected_tot_v; - DeepPot dp; + deepmd::DeepPot dp; void SetUp() override { std::string file_name = "../../tests/infer/deeppot.pbtxt"; int fd = open(file_name.c_str(), O_RDONLY); - protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); - GraphDef graph_def; - protobuf::TextFormat::Parse(input, &graph_def); + tensorflow::protobuf::io::ZeroCopyInputStream* input = new tensorflow::protobuf::io::FileInputStream(fd); + tensorflow::GraphDef graph_def; + tensorflow::protobuf::TextFormat::Parse(input, &graph_def); delete input; std::fstream output("deeppot.pb", std::ios::out | std::ios::trunc | std::ios::binary); graph_def.SerializeToOstream(&output); // check the string by the following commands // string txt; - // protobuf::TextFormat::PrintToString(graph_def, &txt); + // tensorflow::protobuf::TextFormat::PrintToString(graph_def, &txt); dp.init("deeppot.pb"); @@ -103,11 +103,11 @@ TEST_F(TestInferDeepPotA, cpu_build_nlist_numfv) { class MyModel : public EnergyModelTest { - DeepPot & mydp; + deepmd::DeepPot & mydp; const std::vector atype; public: MyModel( - DeepPot & dp_, + deepmd::DeepPot & dp_, const std::vector & atype_ ) : mydp(dp_), atype(atype_) {}; virtual void compute ( @@ -426,14 +426,14 @@ class TestInferDeepPotANoPbc : public ::testing::Test double expected_tot_e; std::vectorexpected_tot_v; - DeepPot dp; + deepmd::DeepPot dp; void SetUp() override { std::string file_name = "../../tests/infer/deeppot.pbtxt"; int fd = open(file_name.c_str(), O_RDONLY); - protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); - GraphDef graph_def; - protobuf::TextFormat::Parse(input, &graph_def); + tensorflow::protobuf::io::ZeroCopyInputStream* input = new tensorflow::protobuf::io::FileInputStream(fd); + tensorflow::GraphDef graph_def; + tensorflow::protobuf::TextFormat::Parse(input, &graph_def); delete input; std::fstream output("deeppot.pb", std::ios::out | std::ios::trunc | std::ios::binary); graph_def.SerializeToOstream(&output); diff --git a/source/api_cc/tests/test_deeppot_model_devi.cc b/source/api_cc/tests/test_deeppot_model_devi.cc index fc5c116924..f70b66a9eb 100644 --- a/source/api_cc/tests/test_deeppot_model_devi.cc +++ b/source/api_cc/tests/test_deeppot_model_devi.cc @@ -32,17 +32,17 @@ class TestInferDeepPotModeDevi : public ::testing::Test }; int natoms; - DeepPot dp0; - DeepPot dp1; - DeepPotModelDevi dp_md; + deepmd::DeepPot dp0; + deepmd::DeepPot dp1; + deepmd::DeepPotModelDevi dp_md; void SetUp() override { { std::string file_name = "../../tests/infer/deeppot.pbtxt"; int fd = open(file_name.c_str(), O_RDONLY); - protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); - GraphDef graph_def; - protobuf::TextFormat::Parse(input, &graph_def); + tensorflow::protobuf::io::ZeroCopyInputStream* input = new tensorflow::protobuf::io::FileInputStream(fd); + tensorflow::GraphDef graph_def; + tensorflow::protobuf::TextFormat::Parse(input, &graph_def); delete input; std::fstream output("deeppot.pb", std::ios::out | std::ios::trunc | std::ios::binary); graph_def.SerializeToOstream(&output); @@ -51,9 +51,9 @@ class TestInferDeepPotModeDevi : public ::testing::Test { std::string file_name = "../../tests/infer/deeppot-1.pbtxt"; int fd = open(file_name.c_str(), O_RDONLY); - protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); - GraphDef graph_def; - protobuf::TextFormat::Parse(input, &graph_def); + tensorflow::protobuf::io::ZeroCopyInputStream* input = new tensorflow::protobuf::io::FileInputStream(fd); + tensorflow::GraphDef graph_def; + tensorflow::protobuf::TextFormat::Parse(input, &graph_def); delete input; std::fstream output("deeppot-1.pb", std::ios::out | std::ios::trunc | std::ios::binary); graph_def.SerializeToOstream(&output); diff --git a/source/api_cc/tests/test_deeppot_r.cc b/source/api_cc/tests/test_deeppot_r.cc index 7002a07f5a..e9b1c45c85 100644 --- a/source/api_cc/tests/test_deeppot_r.cc +++ b/source/api_cc/tests/test_deeppot_r.cc @@ -43,20 +43,20 @@ class TestInferDeepPotR : public ::testing::Test double expected_tot_e; std::vectorexpected_tot_v; - DeepPot dp; + deepmd::DeepPot dp; void SetUp() override { std::string file_name = "../../tests/infer/deeppot-r.pbtxt"; int fd = open(file_name.c_str(), O_RDONLY); - protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); - GraphDef graph_def; - protobuf::TextFormat::Parse(input, &graph_def); + tensorflow::protobuf::io::ZeroCopyInputStream* input = new tensorflow::protobuf::io::FileInputStream(fd); + tensorflow::GraphDef graph_def; + tensorflow::protobuf::TextFormat::Parse(input, &graph_def); delete input; std::fstream output("deeppot.pb", std::ios::out | std::ios::trunc | std::ios::binary); graph_def.SerializeToOstream(&output); // check the string by the following commands // string txt; - // protobuf::TextFormat::PrintToString(graph_def, &txt); + // tensorflow::protobuf::TextFormat::PrintToString(graph_def, &txt); dp.init("deeppot.pb"); @@ -104,11 +104,11 @@ TEST_F(TestInferDeepPotR, cpu_build_nlist_numfv) { class MyModel : public EnergyModelTest { - DeepPot & mydp; + deepmd::DeepPot & mydp; const std::vector & atype; public: MyModel( - DeepPot & dp_, + deepmd::DeepPot & dp_, const std::vector & atype_ ) : mydp(dp_), atype(atype_) {}; virtual void compute ( @@ -426,14 +426,14 @@ class TestInferDeepPotRNoPbc : public ::testing::Test double expected_tot_e; std::vectorexpected_tot_v; - DeepPot dp; + deepmd::DeepPot dp; void SetUp() override { std::string file_name = "../../tests/infer/deeppot-r.pbtxt"; int fd = open(file_name.c_str(), O_RDONLY); - protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); - GraphDef graph_def; - protobuf::TextFormat::Parse(input, &graph_def); + tensorflow::protobuf::io::ZeroCopyInputStream* input = new tensorflow::protobuf::io::FileInputStream(fd); + tensorflow::GraphDef graph_def; + tensorflow::protobuf::TextFormat::Parse(input, &graph_def); delete input; std::fstream output("deeppot.pb", std::ios::out | std::ios::trunc | std::ios::binary); graph_def.SerializeToOstream(&output); diff --git a/source/api_cc/tests/test_dipolecharge.cc b/source/api_cc/tests/test_dipolecharge.cc index 87fd2f4a78..9ce16b9442 100644 --- a/source/api_cc/tests/test_dipolecharge.cc +++ b/source/api_cc/tests/test_dipolecharge.cc @@ -53,22 +53,22 @@ class TestDipoleCharge : public ::testing::Test double expected_tot_e; std::vectorexpected_tot_v; - DeepTensor dp; - DipoleChargeModifier dm; + deepmd::DeepTensor dp; + deepmd::DipoleChargeModifier dm; void SetUp() override { std::string file_name = "../../tests/infer/dipolecharge_e.pbtxt"; int fd = open(file_name.c_str(), O_RDONLY); - protobuf::io::ZeroCopyInputStream* input = new protobuf::io::FileInputStream(fd); - GraphDef graph_def; - protobuf::TextFormat::Parse(input, &graph_def); + tensorflow::protobuf::io::ZeroCopyInputStream* input = new tensorflow::protobuf::io::FileInputStream(fd); + tensorflow::GraphDef graph_def; + tensorflow::protobuf::TextFormat::Parse(input, &graph_def); delete input; - string model = "dipolecharge_e.pb"; + std::string model = "dipolecharge_e.pb"; std::fstream output(model.c_str(), std::ios::out | std::ios::trunc | std::ios::binary); graph_def.SerializeToOstream(&output); // check the string by the following commands // string txt; - // protobuf::TextFormat::PrintToString(graph_def, &txt); + // tensorflow::protobuf::TextFormat::PrintToString(graph_def, &txt); // dp.init("dipolecharge_d.pb"); // dm.init("dipolecharge_d.pb"); @@ -128,12 +128,12 @@ TEST_F(TestDipoleCharge, cpu_lmp_nlist) std::vector sel_types = dp.sel_types(); std::vector sel_fwd, sel_bwd; int sel_nghost; - select_by_type(sel_fwd, sel_bwd, sel_nghost, coord_cpy, atype_cpy, nghost, sel_types); + deepmd::select_by_type(sel_fwd, sel_bwd, sel_nghost, coord_cpy, atype_cpy, nghost, sel_types); int sel_nall = sel_bwd.size(); int sel_nloc = sel_nall - sel_nghost; std::vector sel_atype(sel_bwd.size()); - select_map(sel_atype, atype, sel_fwd, 1); - AtomMap nnp_map(sel_atype.begin(), sel_atype.begin() + sel_nloc); + deepmd::select_map(sel_atype, atype, sel_fwd, 1); + deepmd::AtomMap nnp_map(sel_atype.begin(), sel_atype.begin() + sel_nloc); const std::vector & sort_fwd_map(nnp_map.get_fwd_map()); // // add coords diff --git a/source/ipi/driver.cc b/source/ipi/driver.cc index 605a26a1e0..2732b9b990 100644 --- a/source/ipi/driver.cc +++ b/source/ipi/driver.cc @@ -75,14 +75,14 @@ int main(int argc, char * argv[]) inet = 0; } int port = jdata["port"]; - string host_str = jdata["host"]; + std::string host_str = jdata["host"]; const char * host = host_str.c_str(); - string graph_file = jdata["graph_file"]; - string coord_file = jdata["coord_file"]; - std::map name_type_map = jdata["atom_type"]; + std::string graph_file = jdata["graph_file"]; + std::string coord_file = jdata["coord_file"]; + std::map name_type_map = jdata["atom_type"]; bool b_verb = jdata["verbose"]; - std::vector atom_name; + std::vector atom_name; { std::vector > posi; std::vector > velo; @@ -91,7 +91,7 @@ int main(int argc, char * argv[]) } Convert cvt (atom_name, name_type_map); - DeepPot nnp_inter (graph_file); + deepmd::DeepPot nnp_inter (graph_file); enum { _MSGLEN = 12 }; int MSGLEN = _MSGLEN; @@ -126,7 +126,7 @@ int main(int argc, char * argv[]) while (true) { readbuffer_ (&socket, header, MSGLEN); - string header_str (trimwhitespace(header)); + std::string header_str (trimwhitespace(header)); if (b_verb) std::cout << "# get header " << header_str << std::endl; if (header_str == "STATUS"){ diff --git a/source/lmp/fix_dplr.cpp b/source/lmp/fix_dplr.cpp index 5d89ff8dad..2a5826aa84 100644 --- a/source/lmp/fix_dplr.cpp +++ b/source/lmp/fix_dplr.cpp @@ -299,13 +299,13 @@ void FixDPLR::pre_force(int vflag) } vector sel_fwd, sel_bwd; int sel_nghost; - select_by_type(sel_fwd, sel_bwd, sel_nghost, dcoord, dtype, nghost, sel_type); + deepmd::select_by_type(sel_fwd, sel_bwd, sel_nghost, dcoord, dtype, nghost, sel_type); int sel_nall = sel_bwd.size(); int sel_nloc = sel_nall - sel_nghost; vector sel_type(sel_bwd.size()); - select_map(sel_type, dtype, sel_fwd, 1); + deepmd::select_map(sel_type, dtype, sel_fwd, 1); - AtomMap atom_map(sel_type.begin(), sel_type.begin() + sel_nloc); + deepmd::AtomMap atom_map(sel_type.begin(), sel_type.begin() + sel_nloc); const vector & sort_fwd_map(atom_map.get_fwd_map()); vector > valid_pairs; diff --git a/source/lmp/fix_dplr.h b/source/lmp/fix_dplr.h index aa8c95dd09..6de055529b 100644 --- a/source/lmp/fix_dplr.h +++ b/source/lmp/fix_dplr.h @@ -36,8 +36,8 @@ namespace LAMMPS_NS { double compute_vector(int); private: PairDeepMD * pair_deepmd; - DeepTensor dpt; - DipoleChargeModifier dtm; + deepmd::DeepTensor dpt; + deepmd::DipoleChargeModifier dtm; std::string model; int ntypes; std::vector sel_type; diff --git a/source/lmp/pair_deepmd.cpp b/source/lmp/pair_deepmd.cpp index 859c7be34e..593e6a4246 100644 --- a/source/lmp/pair_deepmd.cpp +++ b/source/lmp/pair_deepmd.cpp @@ -111,7 +111,7 @@ std::string PairDeepMD::get_file_content(const std::string & model) { int nchar = 0; std::string file_content; if (myrank == root) { - checkStatus (ReadFileToString(Env::Default(), model, &file_content)); + deepmd::check_status(tensorflow::ReadFileToString(tensorflow::Env::Default(), model, &file_content)); nchar = file_content.size(); } MPI_Bcast(&nchar, 1, MPI_INT, root, MPI_COMM_WORLD); diff --git a/source/lmp/pair_deepmd.h.in b/source/lmp/pair_deepmd.h.in index 25d950c948..a54f45c2f3 100644 --- a/source/lmp/pair_deepmd.h.in +++ b/source/lmp/pair_deepmd.h.in @@ -71,8 +71,8 @@ class PairDeepMD : public Pair { double **scale; private: - DeepPot deep_pot; - DeepPotModelDevi deep_pot_model_devi; + deepmd::DeepPot deep_pot; + deepmd::DeepPotModelDevi deep_pot_model_devi; unsigned numb_models; double cutoff; int numb_types; From 3017ab7c7c2ec305ec7e97f64d7a188c0838e53e Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 17 Mar 2021 08:46:48 +0800 Subject: [PATCH 281/562] add deepmd namespace for lib --- source/lib/include/ComputeDescriptor.h | 6 +- source/lib/include/Stopwatch.h | 54 -------------- source/lib/include/coord.h | 8 +- source/lib/include/env_mat.h | 61 ++++++++------- source/lib/include/ewald.h | 5 +- source/lib/include/fmt_nlist.h | 33 +++------ source/lib/include/gelu.h | 4 + source/lib/include/map_aparam.h | 3 + source/lib/include/neighbor_list.h | 28 ++++--- source/lib/include/pair_tab.h | 3 + source/lib/include/prod_env_mat.h | 4 + source/lib/include/prod_force.h | 6 +- source/lib/include/prod_force_grad.h | 3 + source/lib/include/prod_virial.h | 4 + source/lib/include/prod_virial_grad.h | 3 + source/lib/include/region.h | 4 + source/lib/include/soft_min_switch.h | 4 + source/lib/include/soft_min_switch_force.h | 4 + .../lib/include/soft_min_switch_force_grad.h | 4 + source/lib/include/soft_min_switch_virial.h | 3 + .../lib/include/soft_min_switch_virial_grad.h | 3 + source/lib/include/switcher.h | 28 +------ source/lib/src/coord.cc | 16 +++- source/lib/src/env_mat.cc | 32 +++++--- source/lib/src/ewald.cc | 5 ++ source/lib/src/fmt_nlist.cc | 40 ++++++++-- source/lib/src/gelu.cc | 18 ++--- source/lib/src/map_aparam.cc | 6 +- source/lib/src/neighbor_list.cc | 8 +- source/lib/src/pair_tab.cc | 7 +- source/lib/src/prod_env_mat.cc | 26 +++++-- source/lib/src/prod_force.cc | 24 ++++-- source/lib/src/prod_force_grad.cc | 24 ++++-- source/lib/src/prod_virial.cc | 24 ++++-- source/lib/src/prod_virial_grad.cc | 24 ++++-- source/lib/src/region.cc | 36 ++++++--- source/lib/src/soft_min_switch.cc | 8 +- source/lib/src/soft_min_switch_force.cc | 6 +- source/lib/src/soft_min_switch_force_grad.cc | 6 +- source/lib/src/soft_min_switch_virial.cc | 6 +- source/lib/src/soft_min_switch_virial_grad.cc | 6 +- source/lib/tests/test_coord.cc | 10 +-- source/lib/tests/test_env_mat_a.cc | 26 +++---- source/lib/tests/test_env_mat_r.cc | 18 ++--- source/lib/tests/test_ewald.cc | 4 +- source/lib/tests/test_fmt_nlist.cc | 4 +- source/lib/tests/test_gelu.cc | 8 +- source/lib/tests/test_map_aparam.cc | 2 +- source/lib/tests/test_neighbor_list.cc | 4 +- source/lib/tests/test_pair_tab.cc | 74 +++++++++---------- source/lib/tests/test_prod_force_a.cc | 6 +- source/lib/tests/test_prod_force_grad_a.cc | 4 +- source/lib/tests/test_prod_force_grad_r.cc | 4 +- source/lib/tests/test_prod_force_r.cc | 4 +- source/lib/tests/test_prod_virial_a.cc | 6 +- source/lib/tests/test_prod_virial_grad_a.cc | 4 +- source/lib/tests/test_prod_virial_grad_r.cc | 4 +- source/lib/tests/test_prod_virial_r.cc | 6 +- source/lib/tests/test_simulation_region.cc | 2 +- source/lib/tests/test_soft_min_switch.cc | 14 ++-- .../lib/tests/test_soft_min_switch_force.cc | 6 +- .../tests/test_soft_min_switch_force_grad.cc | 6 +- .../lib/tests/test_soft_min_switch_virial.cc | 6 +- .../tests/test_soft_min_switch_virial_grad.cc | 6 +- source/lmp/fix_dplr.cpp | 4 +- source/lmp/pair_deepmd.cpp | 2 +- source/lmp/pair_deepmd.h.in | 13 ---- source/lmp/pppm_dplr.cpp | 13 ---- source/lmp/pppm_dplr.h | 13 ---- source/op/ewald_recp.cc | 4 +- source/op/gelu_multi_device.cc | 8 +- source/op/map_aparam.cc | 2 +- source/op/pair_tab.cc | 2 +- source/op/prod_env_mat_multi_device.cc | 20 ++--- source/op/prod_force_se_a.cc | 15 ++-- source/op/prod_force_se_a_grad.cc | 13 ++-- source/op/prod_force_se_r.cc | 15 ++-- source/op/prod_force_se_r_grad.cc | 2 +- source/op/prod_virial_se_a.cc | 19 ++--- source/op/prod_virial_se_a_grad.cc | 15 ++-- source/op/prod_virial_se_r.cc | 2 +- source/op/prod_virial_se_r_grad.cc | 2 +- source/op/soft_min.cc | 2 +- source/op/soft_min_force.cc | 2 +- source/op/soft_min_force_grad.cc | 2 +- source/op/soft_min_virial.cc | 2 +- source/op/soft_min_virial_grad.cc | 2 +- 87 files changed, 547 insertions(+), 452 deletions(-) delete mode 100644 source/lib/include/Stopwatch.h diff --git a/source/lib/include/ComputeDescriptor.h b/source/lib/include/ComputeDescriptor.h index aaac53b657..7d4d6e0c3a 100644 --- a/source/lib/include/ComputeDescriptor.h +++ b/source/lib/include/ComputeDescriptor.h @@ -826,7 +826,7 @@ void compute_descriptor_se_a_extf (std::vector & descrpt_a, double inr4 = inr2 * inr2; double inr3 = inr4 * nr; double sw, dsw; - spline5_switch(sw, dsw, nr, rmin, rmax); + deepmd::spline5_switch(sw, dsw, nr, rmin, rmax); int idx_deriv = nei_iter * 4 * 3; // 4 components time 3 directions int idx_value = nei_iter * 4; // 4 components // projections @@ -935,7 +935,7 @@ void compute_descriptor_se_a_ef_para (std::vector & descrpt_a, double inr4 = inr2 * inr2; double inr3 = inr4 * nr; double sw, dsw; - spline5_switch(sw, dsw, nr, rmin, rmax); + deepmd::spline5_switch(sw, dsw, nr, rmin, rmax); int idx_deriv = nei_iter * 4 * 3; // 4 components time 3 directions int idx_value = nei_iter * 4; // 4 components // projections @@ -1043,7 +1043,7 @@ void compute_descriptor_se_a_ef_vert (std::vector & descrpt_a, double inr4 = inr2 * inr2; double inr3 = inr4 * nr; double sw, dsw; - spline5_switch(sw, dsw, nr, rmin, rmax); + deepmd::spline5_switch(sw, dsw, nr, rmin, rmax); int idx_deriv = nei_iter * 4 * 3; // 4 components time 3 directions int idx_value = nei_iter * 4; // 4 components // projections diff --git a/source/lib/include/Stopwatch.h b/source/lib/include/Stopwatch.h deleted file mode 100644 index 0abd73bcf1..0000000000 --- a/source/lib/include/Stopwatch.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef __Stopwatch_h_wanghan__ -#define __Stopwatch_h_wanghan__ - -#include -#include -#include - -class Stopwatch -{ -public: - Stopwatch(): HZi (1./HZ) {}; - - void start(); - void stop(); - double system() const; - double user() const; - double real() const; - - static double resolution() {return 1./HZ;}; -private: - struct tms tic, toc; - long r1, r0; - double HZi; -}; - -inline double Stopwatch::user () const -{ - return (double)(toc.tms_utime - tic.tms_utime) * HZi; -} - -inline double Stopwatch::system () const -{ - return (double)(toc.tms_stime - tic.tms_stime) * HZi; -} - -inline double Stopwatch::real () const -{ - return (double)(r1 - r0) * HZi; -} - -inline void Stopwatch::stop () -{ - r1 = times (&toc); -} - -inline void Stopwatch::start() -{ - r0 = times (&tic); -} - - -#endif -// end of file - diff --git a/source/lib/include/coord.h b/source/lib/include/coord.h index dc81efc1b2..0da8eedd23 100644 --- a/source/lib/include/coord.h +++ b/source/lib/include/coord.h @@ -2,13 +2,15 @@ #include "region.h" +namespace deepmd{ + // normalize coords template void normalize_coord_cpu( FPTYPE * coord, const int natom, - const Region & region); + const deepmd::Region & region); // copy coordinates // outputs: @@ -32,4 +34,6 @@ copy_coord_cpu( const int & nloc, const int & mem_nall, const float & rcut, - const Region & region); + const deepmd::Region & region); + +} diff --git a/source/lib/include/env_mat.h b/source/lib/include/env_mat.h index 1217051f70..b94e683027 100644 --- a/source/lib/include/env_mat.h +++ b/source/lib/include/env_mat.h @@ -1,6 +1,41 @@ #pragma once #include + +namespace deepmd{ + +template +void env_mat_a_cpu ( + std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, + const std::vector & type, + const int & i_idx, + const std::vector & fmt_nlist, + const std::vector & sec, + const float & rmin, + const float & rmax) ; + +template +void env_mat_r_cpu ( + std::vector & descrpt_a, + std::vector & descrpt_a_deriv, + std::vector & rij_a, + const std::vector & posi, + const std::vector & type, + const int & i_idx, + const std::vector & fmt_nlist_a, + const std::vector & sec_a, + const float & rmin, + const float & rmax); + +} + +//////////////////////////////////////////////////////// +// legacy code +//////////////////////////////////////////////////////// + #include "SimulationRegion.h" void env_mat_a ( @@ -18,19 +53,6 @@ void env_mat_a ( const double & rmin, const double & rmax); -template -void env_mat_a_cpu ( - std::vector & descrpt_a, - std::vector & descrpt_a_deriv, - std::vector & rij_a, - const std::vector & posi, - const std::vector & type, - const int & i_idx, - const std::vector & fmt_nlist, - const std::vector & sec, - const float & rmin, - const float & rmax) ; - void env_mat_r ( std::vector & descrpt_r, std::vector & descrpt_r_deriv, @@ -46,16 +68,3 @@ void env_mat_r ( const double & rmin, const double & rmax); -template -void env_mat_r_cpu ( - std::vector & descrpt_a, - std::vector & descrpt_a_deriv, - std::vector & rij_a, - const std::vector & posi, - const std::vector & type, - const int & i_idx, - const std::vector & fmt_nlist_a, - const std::vector & sec_a, - const float & rmin, - const float & rmax); - diff --git a/source/lib/include/ewald.h b/source/lib/include/ewald.h index 10d400e62a..bce151365a 100644 --- a/source/lib/include/ewald.h +++ b/source/lib/include/ewald.h @@ -7,6 +7,8 @@ #include "utilities.h" #include "region.h" +namespace deepmd{ + // 8.988e9 / pc.electron_volt / pc.angstrom * (1.602e-19)**2 const double ElectrostaticConvertion = 14.39964535475696995031; @@ -29,6 +31,7 @@ ewald_recp( std::vector & virial, const std::vector& coord, const std::vector& charge, - const Region& region, + const deepmd::Region& region, const EwaldParameters& param); +} diff --git a/source/lib/include/fmt_nlist.h b/source/lib/include/fmt_nlist.h index 3b8a30eefe..13c9082240 100644 --- a/source/lib/include/fmt_nlist.h +++ b/source/lib/include/fmt_nlist.h @@ -2,7 +2,8 @@ #include #include "neighbor_list.h" -#include "SimulationRegion.h" + +namespace deepmd{ template void format_nlist_cpu( @@ -15,6 +16,15 @@ void format_nlist_cpu( const float rcut, const std::vector sec); +} + + +//////////////////////////////////////////////////////// +// legacy code +//////////////////////////////////////////////////////// + +#include "SimulationRegion.h" + // return: -1 OK // > 0 the type of unsuccessful neighbor list int format_nlist_i_fill_a ( @@ -45,24 +55,3 @@ int format_nlist_i_cpu ( -struct NeighborInfo -{ - int type; - double dist; - int index; - NeighborInfo () - : type (0), dist(0), index(0) - { - } - NeighborInfo (int tt, double dd, int ii) - : type (tt), dist(dd), index(ii) - { - } - bool operator < (const NeighborInfo & b) const - { - return (type < b.type || - (type == b.type && - (dist < b.dist || - (dist == b.dist && index < b.index) ) ) ); - } -}; diff --git a/source/lib/include/gelu.h b/source/lib/include/gelu.h index edf1729c4f..20f2d96de5 100644 --- a/source/lib/include/gelu.h +++ b/source/lib/include/gelu.h @@ -1,5 +1,7 @@ #pragma once +namespace deepmd{ + template void gelu_cpu( FPTYPE * out, @@ -43,3 +45,5 @@ void gelu_grad_grad_gpu_cuda( const FPTYPE * dy_2, const int size); #endif // GOOGLE_CUDA + +} diff --git a/source/lib/include/map_aparam.h b/source/lib/include/map_aparam.h index b209d8314a..3ee3d1dc12 100644 --- a/source/lib/include/map_aparam.h +++ b/source/lib/include/map_aparam.h @@ -1,5 +1,7 @@ #pragma once +namespace deepmd{ + template void map_aparam_cpu ( FPTYPE * output, @@ -10,3 +12,4 @@ void map_aparam_cpu ( const int & numb_aparam ); +} diff --git a/source/lib/include/neighbor_list.h b/source/lib/include/neighbor_list.h index ef4013c7d7..ddcf64846c 100644 --- a/source/lib/include/neighbor_list.h +++ b/source/lib/include/neighbor_list.h @@ -9,6 +9,8 @@ #include "utilities.h" #include "SimulationRegion.h" +namespace deepmd{ + // format of the input neighbor list struct InputNlist { @@ -61,6 +63,22 @@ build_nlist_cpu( const int & mem_size, const float & rcut); +#if GOOGLE_CUDA +void convert_nlist_gpu_cuda( + InputNlist & gpu_nlist, + InputNlist & cpu_nlist, + int* & gpu_memory, + const int & max_nbor_size); + +void free_nlist_gpu_cuda(InputNlist & gpu_nlist); +#endif // GOOGLE_CUDA + +} // namespace deepmd + + +//////////////////////////////////////////////////////// +// legacy code +//////////////////////////////////////////////////////// // build nlist by an extended grid void @@ -121,13 +139,3 @@ copy_coord (std::vector & out_c, const std::vector & in_t, const double & rc, const SimulationRegion & region); - -#if GOOGLE_CUDA -void convert_nlist_gpu_cuda( - InputNlist & gpu_nlist, - InputNlist & cpu_nlist, - int* & gpu_memory, - const int & max_nbor_size); - -void free_nlist_gpu_cuda(InputNlist & gpu_nlist); -#endif // GOOGLE_CUDA diff --git a/source/lib/include/pair_tab.h b/source/lib/include/pair_tab.h index 9176b43c0c..db05b68df2 100644 --- a/source/lib/include/pair_tab.h +++ b/source/lib/include/pair_tab.h @@ -1,5 +1,7 @@ #pragma once +namespace deepmd{ + template void pair_tab_cpu( FPTYPE * energy, @@ -16,3 +18,4 @@ void pair_tab_cpu( const std::vector & sel_r ); +} diff --git a/source/lib/include/prod_env_mat.h b/source/lib/include/prod_env_mat.h index 6b866c5590..0789bf75a6 100644 --- a/source/lib/include/prod_env_mat.h +++ b/source/lib/include/prod_env_mat.h @@ -3,6 +3,8 @@ #include "device.h" #include "neighbor_list.h" +namespace deepmd{ + template void prod_env_mat_a_cpu( FPTYPE * em, @@ -89,3 +91,5 @@ void env_mat_nbor_update( const int size); #endif // GOOGLE_CUDA +} + diff --git a/source/lib/include/prod_force.h b/source/lib/include/prod_force.h index 9236f7802f..1667edb61c 100644 --- a/source/lib/include/prod_force.h +++ b/source/lib/include/prod_force.h @@ -1,5 +1,7 @@ #pragma once +namespace deepmd{ + template void prod_force_a_cpu( FPTYPE * force, @@ -40,4 +42,6 @@ void prod_force_r_gpu_cuda( const int nloc, const int nall, const int nnei); -#endif // GOOGLE_CUDA \ No newline at end of file +#endif // GOOGLE_CUDA + +} diff --git a/source/lib/include/prod_force_grad.h b/source/lib/include/prod_force_grad.h index d191fe76fa..b4b95f2ac3 100644 --- a/source/lib/include/prod_force_grad.h +++ b/source/lib/include/prod_force_grad.h @@ -1,5 +1,7 @@ #pragma once +namespace deepmd{ + template void prod_force_grad_a_cpu( FPTYPE * grad_net, @@ -18,3 +20,4 @@ void prod_force_grad_r_cpu( const int nloc, const int nnei); +} diff --git a/source/lib/include/prod_virial.h b/source/lib/include/prod_virial.h index 5a5c9ad996..6655059e12 100644 --- a/source/lib/include/prod_virial.h +++ b/source/lib/include/prod_virial.h @@ -1,5 +1,7 @@ #pragma once +namespace deepmd{ + template void prod_virial_a_cpu( FPTYPE * virial, @@ -49,3 +51,5 @@ void prod_virial_r_gpu_cuda( const int nall, const int nnei); #endif // GOOGLE_CUDA + +} //namespace deepmd diff --git a/source/lib/include/prod_virial_grad.h b/source/lib/include/prod_virial_grad.h index 2ba8c01a44..ab0f84ffec 100644 --- a/source/lib/include/prod_virial_grad.h +++ b/source/lib/include/prod_virial_grad.h @@ -1,5 +1,7 @@ #pragma once +namespace deepmd{ + template void prod_virial_grad_a_cpu( FPTYPE * grad_net, @@ -20,3 +22,4 @@ void prod_virial_grad_r_cpu( const int nloc, const int nnei); +} diff --git a/source/lib/include/region.h b/source/lib/include/region.h index 049ef882cc..fd24bd6b4d 100644 --- a/source/lib/include/region.h +++ b/source/lib/include/region.h @@ -1,5 +1,7 @@ #pragma once +namespace deepmd{ + template struct Region { @@ -34,3 +36,5 @@ convert_to_phys_cpu( const Region & region, const FPTYPE * ri); +} + diff --git a/source/lib/include/soft_min_switch.h b/source/lib/include/soft_min_switch.h index 9d0b20a1c5..4b382cde93 100644 --- a/source/lib/include/soft_min_switch.h +++ b/source/lib/include/soft_min_switch.h @@ -1,5 +1,7 @@ #pragma once +namespace deepmd{ + template void soft_min_switch_cpu( FPTYPE * sw_value, @@ -11,3 +13,5 @@ void soft_min_switch_cpu( const FPTYPE & alpha, const FPTYPE & rmin, const FPTYPE & rmax); + +} diff --git a/source/lib/include/soft_min_switch_force.h b/source/lib/include/soft_min_switch_force.h index dfcb47ca52..854458a3c7 100644 --- a/source/lib/include/soft_min_switch_force.h +++ b/source/lib/include/soft_min_switch_force.h @@ -1,5 +1,7 @@ #pragma once +namespace deepmd{ + template void soft_min_switch_force_cpu( FPTYPE * force, @@ -9,3 +11,5 @@ void soft_min_switch_force_cpu( const int nloc, const int nall, const int nnei); + +} diff --git a/source/lib/include/soft_min_switch_force_grad.h b/source/lib/include/soft_min_switch_force_grad.h index 329ca6e66d..afe4c3b36e 100644 --- a/source/lib/include/soft_min_switch_force_grad.h +++ b/source/lib/include/soft_min_switch_force_grad.h @@ -1,5 +1,7 @@ #pragma once +namespace deepmd{ + template void soft_min_switch_force_grad_cpu( FPTYPE * grad_net, @@ -8,3 +10,5 @@ void soft_min_switch_force_grad_cpu( const int * nlist, const int nloc, const int nnei); + +} diff --git a/source/lib/include/soft_min_switch_virial.h b/source/lib/include/soft_min_switch_virial.h index 8e2dd1de04..4833eec262 100644 --- a/source/lib/include/soft_min_switch_virial.h +++ b/source/lib/include/soft_min_switch_virial.h @@ -1,5 +1,7 @@ #pragma once +namespace deepmd{ + template void soft_min_switch_virial_cpu( FPTYPE * virial, @@ -12,3 +14,4 @@ void soft_min_switch_virial_cpu( const int nall, const int nnei); +} diff --git a/source/lib/include/soft_min_switch_virial_grad.h b/source/lib/include/soft_min_switch_virial_grad.h index 4e4ed1514e..1b1ec0da44 100644 --- a/source/lib/include/soft_min_switch_virial_grad.h +++ b/source/lib/include/soft_min_switch_virial_grad.h @@ -1,5 +1,7 @@ #pragma once +namespace deepmd{ + template void soft_min_switch_virial_grad_cpu( FPTYPE * grad_net, @@ -10,3 +12,4 @@ void soft_min_switch_virial_grad_cpu( const int nloc, const int nnei); +} diff --git a/source/lib/include/switcher.h b/source/lib/include/switcher.h index 671c8be137..606b3c3196 100644 --- a/source/lib/include/switcher.h +++ b/source/lib/include/switcher.h @@ -1,5 +1,7 @@ #pragma once +namespace deepmd{ + inline double cos_switch (const double & xx, const double & rmin, @@ -64,30 +66,6 @@ spline3_switch (double & vv, } } -// template -// inline void -// spline5_switch (TYPE & vv, -// TYPE & dd, -// const TYPE & xx, -// const TYPE & rmin, -// const TYPE & rmax) -// { -// if (xx < rmin) { -// dd = 0; -// vv = 1; -// } -// else if (xx < rmax) { -// double uu = (xx - rmin) / (rmax - rmin) ; -// double du = 1. / (rmax - rmin) ; -// vv = uu*uu*uu * (-6 * uu*uu + 15 * uu - 10) + 1; -// dd = ( 3 * uu*uu * (-6 * uu*uu + 15 * uu - 10) + uu*uu*uu * (-12 * uu + 15) ) * du; -// } -// else { -// dd = 0; -// vv = 0; -// } -// } - template inline void spline5_switch ( @@ -112,3 +90,5 @@ spline5_switch ( vv = 0; } } + +} diff --git a/source/lib/src/coord.cc b/source/lib/src/coord.cc index fb57b2c403..81c44f4925 100644 --- a/source/lib/src/coord.cc +++ b/source/lib/src/coord.cc @@ -3,9 +3,12 @@ #include "SimulationRegion.h" #include +using namespace deepmd; + // normalize coords template void +deepmd:: normalize_coord_cpu( FPTYPE * coord, const int natom, @@ -25,6 +28,7 @@ normalize_coord_cpu( template int +deepmd:: copy_coord_cpu( FPTYPE * out_c, int * out_t, @@ -67,20 +71,23 @@ copy_coord_cpu( template void +deepmd:: normalize_coord_cpu( double * coord, const int natom, - const Region & region); + const deepmd::Region & region); template void +deepmd:: normalize_coord_cpu( float * coord, const int natom, - const Region & region); + const deepmd::Region & region); template int +deepmd:: copy_coord_cpu( double * out_c, int * out_t, @@ -91,10 +98,11 @@ copy_coord_cpu( const int & nloc, const int & mem_nall, const float & rcut, - const Region & region); + const deepmd::Region & region); template int +deepmd:: copy_coord_cpu( float * out_c, int * out_t, @@ -105,7 +113,7 @@ copy_coord_cpu( const int & nloc, const int & mem_nall, const float & rcut, - const Region & region); + const deepmd::Region & region); diff --git a/source/lib/src/env_mat.cc b/source/lib/src/env_mat.cc index c9cadb4b0d..52398a17a8 100644 --- a/source/lib/src/env_mat.cc +++ b/source/lib/src/env_mat.cc @@ -57,7 +57,7 @@ void env_mat_a ( double inr4 = inr2 * inr2; double inr3 = inr4 * nr; double sw, dsw; - spline5_switch(sw, dsw, nr, rmin, rmax); + deepmd::spline5_switch(sw, dsw, nr, rmin, rmax); int idx_deriv = nei_iter * 4 * 3; // 4 components time 3 directions int idx_value = nei_iter * 4; // 4 components // 4 value components @@ -92,7 +92,9 @@ void env_mat_a ( template -void env_mat_a_cpu ( +void +deepmd:: +env_mat_a_cpu ( std::vector & descrpt_a, std::vector & descrpt_a_deriv, std::vector & rij_a, @@ -134,7 +136,7 @@ void env_mat_a_cpu ( FPTYPE inr4 = inr2 * inr2; FPTYPE inr3 = inr4 * nr; FPTYPE sw, dsw; - spline5_switch(sw, dsw, nr, rmin, rmax); + deepmd::spline5_switch(sw, dsw, nr, rmin, rmax); int idx_deriv = nei_iter * 4 * 3; // 4 components time 3 directions int idx_value = nei_iter * 4; // 4 components // 4 value components @@ -222,7 +224,7 @@ void env_mat_r ( double inr4 = inr2 * inr2; double inr3 = inr4 * nr; double sw, dsw; - spline5_switch(sw, dsw, nr, rmin, rmax); + deepmd::spline5_switch(sw, dsw, nr, rmin, rmax); int idx_deriv = nei_iter * 3; // 1 components time 3 directions int idx_value = nei_iter; // 1 components // value components @@ -238,7 +240,9 @@ void env_mat_r ( } template -void env_mat_r_cpu ( +void +deepmd:: +env_mat_r_cpu ( std::vector & descrpt_a, std::vector & descrpt_a_deriv, std::vector & rij_a, @@ -281,7 +285,7 @@ void env_mat_r_cpu ( FPTYPE inr4 = inr2 * inr2; FPTYPE inr3 = inr4 * nr; FPTYPE sw, dsw; - spline5_switch(sw, dsw, nr, rmin, rmax); + deepmd::spline5_switch(sw, dsw, nr, rmin, rmax); int idx_deriv = nei_iter * 3; // 1 components time 3 directions int idx_value = nei_iter; // 1 components // 4 value components @@ -298,7 +302,9 @@ void env_mat_r_cpu ( template -void env_mat_a_cpu ( +void +deepmd:: +env_mat_a_cpu ( std::vector & descrpt_a, std::vector & descrpt_a_deriv, std::vector & rij_a, @@ -312,7 +318,9 @@ void env_mat_a_cpu ( template -void env_mat_a_cpu ( +void +deepmd:: +env_mat_a_cpu ( std::vector & descrpt_a, std::vector & descrpt_a_deriv, std::vector & rij_a, @@ -326,7 +334,9 @@ void env_mat_a_cpu ( template -void env_mat_r_cpu ( +void +deepmd:: +env_mat_r_cpu ( std::vector & descrpt_r, std::vector & descrpt_r_deriv, std::vector & rij_r, @@ -340,7 +350,9 @@ void env_mat_r_cpu ( template -void env_mat_r_cpu ( +void +deepmd:: +env_mat_r_cpu ( std::vector & descrpt_r, std::vector & descrpt_r_deriv, std::vector & rij_r, diff --git a/source/lib/src/ewald.cc b/source/lib/src/ewald.cc index b12a4757e7..5942f6fedc 100644 --- a/source/lib/src/ewald.cc +++ b/source/lib/src/ewald.cc @@ -1,6 +1,8 @@ #include "ewald.h" #include "SimulationRegion.h" +using namespace deepmd; + template VALUETYPE dir_err_esti(const VALUETYPE & test_q, @@ -86,6 +88,7 @@ cmpt_k(std::vector & KK, // inputs: coordinates charges region template void +deepmd:: ewald_recp( VALUETYPE & ener, std::vector & force, @@ -266,6 +269,7 @@ ewald_recp( template void +deepmd:: ewald_recp( float & ener, std::vector & force, @@ -277,6 +281,7 @@ ewald_recp( template void +deepmd:: ewald_recp( double & ener, std::vector & force, diff --git a/source/lib/src/fmt_nlist.cc b/source/lib/src/fmt_nlist.cc index 0d9b921b1b..2c577c2f05 100644 --- a/source/lib/src/fmt_nlist.cc +++ b/source/lib/src/fmt_nlist.cc @@ -5,6 +5,30 @@ #include "SimulationRegion.h" #include +using namespace deepmd; + +struct NeighborInfo +{ + int type; + double dist; + int index; + NeighborInfo () + : type (0), dist(0), index(0) + { + } + NeighborInfo (int tt, double dd, int ii) + : type (tt), dist(dd), index(ii) + { + } + bool operator < (const NeighborInfo & b) const + { + return (type < b.type || + (type == b.type && + (dist < b.dist || + (dist == b.dist && index < b.index) ) ) ); + } +}; + int format_nlist_i_fill_a ( std::vector & fmt_nei_idx_a, std::vector & fmt_nei_idx_r, @@ -123,7 +147,9 @@ int format_nlist_i_cpu ( } template -void format_nlist_cpu ( +void +deepmd:: +format_nlist_cpu ( int * nlist, const InputNlist & in_nlist, const FPTYPE * coord, @@ -187,9 +213,11 @@ int format_nlist_i_cpu ( const std::vector & sec_a); template -void format_nlist_cpu ( +void +deepmd:: +format_nlist_cpu ( int * nlist, - const InputNlist & in_nlist, + const deepmd::InputNlist & in_nlist, const double * coord, const int * type, const int nloc, @@ -199,9 +227,11 @@ void format_nlist_cpu ( template -void format_nlist_cpu ( +void +deepmd:: +format_nlist_cpu ( int * nlist, - const InputNlist & in_nlist, + const deepmd::InputNlist & in_nlist, const float * coord, const int * type, const int nloc, diff --git a/source/lib/src/gelu.cc b/source/lib/src/gelu.cc index b887df89de..c554da0578 100644 --- a/source/lib/src/gelu.cc +++ b/source/lib/src/gelu.cc @@ -3,7 +3,7 @@ #include "device.h" template -void gelu_cpu( +void deepmd::gelu_cpu( FPTYPE * out, const FPTYPE * xx, const int size) @@ -14,7 +14,7 @@ void gelu_cpu( } template -void gelu_grad_cpu( +void deepmd::gelu_grad_cpu( FPTYPE * out, const FPTYPE * xx, const FPTYPE * dy, @@ -27,7 +27,7 @@ void gelu_grad_cpu( } template -void gelu_grad_grad_cpu( +void deepmd::gelu_grad_grad_cpu( FPTYPE * out, const FPTYPE * xx, const FPTYPE * dy, @@ -41,9 +41,9 @@ void gelu_grad_grad_cpu( } } -template void gelu_cpu(float * out, const float * x, const int size); -template void gelu_cpu(double * out, const double * x, const int size); -template void gelu_grad_cpu(float * out, const float * x, const float * dy, const int size); -template void gelu_grad_cpu(double * out, const double * x, const double * dy, const int size); -template void gelu_grad_grad_cpu(float * out, const float * x, const float * dy, const float * dy_2, const int size); -template void gelu_grad_grad_cpu(double * out, const double * x, const double * dy, const double * dy_2, const int size); +template void deepmd::gelu_cpu(float * out, const float * x, const int size); +template void deepmd::gelu_cpu(double * out, const double * x, const int size); +template void deepmd::gelu_grad_cpu(float * out, const float * x, const float * dy, const int size); +template void deepmd::gelu_grad_cpu(double * out, const double * x, const double * dy, const int size); +template void deepmd::gelu_grad_grad_cpu(float * out, const float * x, const float * dy, const float * dy_2, const int size); +template void deepmd::gelu_grad_grad_cpu(double * out, const double * x, const double * dy, const double * dy_2, const int size); diff --git a/source/lib/src/map_aparam.cc b/source/lib/src/map_aparam.cc index b7e9973d5f..7e60f1c3b8 100644 --- a/source/lib/src/map_aparam.cc +++ b/source/lib/src/map_aparam.cc @@ -1,7 +1,7 @@ #include "map_aparam.h" template -void map_aparam_cpu ( +void deepmd::map_aparam_cpu ( FPTYPE * output, const FPTYPE * aparam, const int * nlist, @@ -38,7 +38,7 @@ void map_aparam_cpu ( } template -void map_aparam_cpu ( +void deepmd::map_aparam_cpu ( double * output, const double * aparam, const int * nlist, @@ -48,7 +48,7 @@ void map_aparam_cpu ( ); template -void map_aparam_cpu ( +void deepmd::map_aparam_cpu ( float * output, const float * aparam, const int * nlist, diff --git a/source/lib/src/neighbor_list.cc b/source/lib/src/neighbor_list.cc index 4223b50fe6..e426d63906 100644 --- a/source/lib/src/neighbor_list.cc +++ b/source/lib/src/neighbor_list.cc @@ -743,8 +743,10 @@ copy_coord (std::vector & out_c, } } +using namespace deepmd; void +deepmd:: convert_nlist( InputNlist & to_nlist, std::vector > & from_nlist @@ -759,6 +761,7 @@ convert_nlist( } int +deepmd:: max_numneigh( const InputNlist & nlist ) @@ -772,6 +775,7 @@ max_numneigh( template int +deepmd:: build_nlist_cpu( InputNlist & nlist, int * max_list_size, @@ -817,6 +821,7 @@ build_nlist_cpu( template int +deepmd:: build_nlist_cpu( InputNlist & nlist, int * max_list_size, @@ -828,6 +833,7 @@ build_nlist_cpu( template int +deepmd:: build_nlist_cpu( InputNlist & nlist, int * max_list_size, @@ -868,4 +874,4 @@ void free_nlist_gpu_cuda( delete_device_memory(gpu_nlist.numneigh); delete_device_memory(gpu_nlist.firstneigh); } -#endif // GOOGLE_CUDA \ No newline at end of file +#endif // GOOGLE_CUDA diff --git a/source/lib/src/pair_tab.cc b/source/lib/src/pair_tab.cc index d0a435b1b1..5137e17ac9 100644 --- a/source/lib/src/pair_tab.cc +++ b/source/lib/src/pair_tab.cc @@ -122,7 +122,8 @@ _cum_sum ( } template -void pair_tab_cpu( +void +deepmd::pair_tab_cpu( FPTYPE * energy, FPTYPE * force, FPTYPE * virial, @@ -211,7 +212,7 @@ void pair_tab_cpu( template -void pair_tab_cpu( +void deepmd::pair_tab_cpu( float * energy, float * force, float * virial, @@ -227,7 +228,7 @@ void pair_tab_cpu( ); template -void pair_tab_cpu( +void deepmd::pair_tab_cpu( double * energy, double * force, double * virial, diff --git a/source/lib/src/prod_env_mat.cc b/source/lib/src/prod_env_mat.cc index a900b99a5c..597473021d 100644 --- a/source/lib/src/prod_env_mat.cc +++ b/source/lib/src/prod_env_mat.cc @@ -5,8 +5,12 @@ #include "fmt_nlist.h" #include "env_mat.h" +using namespace deepmd; + template -void prod_env_mat_a_cpu( +void +deepmd:: +prod_env_mat_a_cpu( FPTYPE * em, FPTYPE * em_deriv, FPTYPE * rij, @@ -88,7 +92,9 @@ void prod_env_mat_a_cpu( } template -void prod_env_mat_r_cpu( +void +deepmd:: +prod_env_mat_r_cpu( FPTYPE * em, FPTYPE * em_deriv, FPTYPE * rij, @@ -171,7 +177,9 @@ void prod_env_mat_r_cpu( template -void prod_env_mat_a_cpu( +void +deepmd:: +prod_env_mat_a_cpu( double * em, double * em_deriv, double * rij, @@ -189,7 +197,9 @@ void prod_env_mat_a_cpu( const std::vector sec); template -void prod_env_mat_a_cpu( +void +deepmd:: +prod_env_mat_a_cpu( float * em, float * em_deriv, float * rij, @@ -207,7 +217,9 @@ void prod_env_mat_a_cpu( const std::vector sec); template -void prod_env_mat_r_cpu( +void +deepmd:: +prod_env_mat_r_cpu( double * em, double * em_deriv, double * rij, @@ -225,7 +237,9 @@ void prod_env_mat_r_cpu( const std::vector sec); template -void prod_env_mat_r_cpu( +void +deepmd:: +prod_env_mat_r_cpu( float * em, float * em_deriv, float * rij, diff --git a/source/lib/src/prod_force.cc b/source/lib/src/prod_force.cc index 16d153f9e1..ffe177e16c 100644 --- a/source/lib/src/prod_force.cc +++ b/source/lib/src/prod_force.cc @@ -20,7 +20,9 @@ make_index_range ( template -void prod_force_a_cpu( +void +deepmd:: +prod_force_a_cpu( FPTYPE * force, const FPTYPE * net_deriv, const FPTYPE * env_deriv, @@ -56,7 +58,9 @@ void prod_force_a_cpu( } template -void prod_force_a_cpu( +void +deepmd:: +prod_force_a_cpu( double * force, const double * net_deriv, const double * env_deriv, @@ -66,7 +70,9 @@ void prod_force_a_cpu( const int nnei); template -void prod_force_a_cpu( +void +deepmd:: +prod_force_a_cpu( float * force, const float * net_deriv, const float * env_deriv, @@ -77,7 +83,9 @@ void prod_force_a_cpu( template -void prod_force_r_cpu( +void +deepmd:: +prod_force_r_cpu( FPTYPE * force, const FPTYPE * net_deriv, const FPTYPE * env_deriv, @@ -117,7 +125,9 @@ void prod_force_r_cpu( } template -void prod_force_r_cpu( +void +deepmd:: +prod_force_r_cpu( double * force, const double * net_deriv, const double * env_deriv, @@ -127,7 +137,9 @@ void prod_force_r_cpu( const int nnei); template -void prod_force_r_cpu( +void +deepmd:: +prod_force_r_cpu( float * force, const float * net_deriv, const float * env_deriv, diff --git a/source/lib/src/prod_force_grad.cc b/source/lib/src/prod_force_grad.cc index 49c510c8b5..7872ea5c55 100644 --- a/source/lib/src/prod_force_grad.cc +++ b/source/lib/src/prod_force_grad.cc @@ -21,7 +21,9 @@ make_index_range ( template -void prod_force_grad_a_cpu( +void +deepmd:: +prod_force_grad_a_cpu( FPTYPE * grad_net, const FPTYPE * grad, const FPTYPE * env_deriv, @@ -67,7 +69,9 @@ void prod_force_grad_a_cpu( template -void prod_force_grad_a_cpu( +void +deepmd:: +prod_force_grad_a_cpu( double * grad_net, const double * grad, const double * env_deriv, @@ -76,7 +80,9 @@ void prod_force_grad_a_cpu( const int nnei) ; template -void prod_force_grad_a_cpu( +void +deepmd:: +prod_force_grad_a_cpu( float * grad_net, const float * grad, const float * env_deriv, @@ -87,7 +93,9 @@ void prod_force_grad_a_cpu( template -void prod_force_grad_r_cpu( +void +deepmd:: +prod_force_grad_r_cpu( FPTYPE * grad_net, const FPTYPE * grad, const FPTYPE * env_deriv, @@ -134,7 +142,9 @@ void prod_force_grad_r_cpu( } template -void prod_force_grad_r_cpu( +void +deepmd:: +prod_force_grad_r_cpu( double * grad_net, const double * grad, const double * env_deriv, @@ -143,7 +153,9 @@ void prod_force_grad_r_cpu( const int nnei) ; template -void prod_force_grad_r_cpu( +void +deepmd:: +prod_force_grad_r_cpu( float * grad_net, const float * grad, const float * env_deriv, diff --git a/source/lib/src/prod_virial.cc b/source/lib/src/prod_virial.cc index 89c8f46185..086bc94245 100644 --- a/source/lib/src/prod_virial.cc +++ b/source/lib/src/prod_virial.cc @@ -20,7 +20,9 @@ make_index_range ( } template -void prod_virial_a_cpu( +void +deepmd:: +prod_virial_a_cpu( FPTYPE * virial, FPTYPE * atom_virial, const FPTYPE * net_deriv, @@ -65,7 +67,9 @@ void prod_virial_a_cpu( } template -void prod_virial_a_cpu( +void +deepmd:: +prod_virial_a_cpu( double * virial, double * atom_virial, const double * net_deriv, @@ -77,7 +81,9 @@ void prod_virial_a_cpu( const int nnei) ; template -void prod_virial_a_cpu( +void +deepmd:: +prod_virial_a_cpu( float * virial, float * atom_virial, const float * net_deriv, @@ -90,7 +96,9 @@ void prod_virial_a_cpu( template -void prod_virial_r_cpu( +void +deepmd:: +prod_virial_r_cpu( FPTYPE * virial, FPTYPE * atom_virial, const FPTYPE * net_deriv, @@ -131,7 +139,9 @@ void prod_virial_r_cpu( } template -void prod_virial_r_cpu( +void +deepmd:: +prod_virial_r_cpu( double * virial, double * atom_virial, const double * net_deriv, @@ -143,7 +153,9 @@ void prod_virial_r_cpu( const int nnei); template -void prod_virial_r_cpu( +void +deepmd:: +prod_virial_r_cpu( float * virial, float * atom_virial, const float * net_deriv, diff --git a/source/lib/src/prod_virial_grad.cc b/source/lib/src/prod_virial_grad.cc index 3a53692417..59c3192fc0 100644 --- a/source/lib/src/prod_virial_grad.cc +++ b/source/lib/src/prod_virial_grad.cc @@ -19,7 +19,9 @@ make_index_range ( } template -void prod_virial_grad_a_cpu( +void +deepmd:: +prod_virial_grad_a_cpu( FPTYPE * grad_net, const FPTYPE * grad, const FPTYPE * env_deriv, @@ -61,7 +63,9 @@ void prod_virial_grad_a_cpu( template -void prod_virial_grad_a_cpu( +void +deepmd:: +prod_virial_grad_a_cpu( double * grad_net, const double * grad, const double * env_deriv, @@ -71,7 +75,9 @@ void prod_virial_grad_a_cpu( const int nnei); template -void prod_virial_grad_a_cpu( +void +deepmd:: +prod_virial_grad_a_cpu( float * grad_net, const float * grad, const float * env_deriv, @@ -82,7 +88,9 @@ void prod_virial_grad_a_cpu( template -void prod_virial_grad_r_cpu( +void +deepmd:: +prod_virial_grad_r_cpu( FPTYPE * grad_net, const FPTYPE * grad, const FPTYPE * env_deriv, @@ -127,7 +135,9 @@ void prod_virial_grad_r_cpu( template -void prod_virial_grad_r_cpu( +void +deepmd:: +prod_virial_grad_r_cpu( double * grad_net, const double * grad, const double * env_deriv, @@ -137,7 +147,9 @@ void prod_virial_grad_r_cpu( const int nnei); template -void prod_virial_grad_r_cpu( +void +deepmd:: +prod_virial_grad_r_cpu( float * grad_net, const float * grad, const float * env_deriv, diff --git a/source/lib/src/region.cc b/source/lib/src/region.cc index b8ab55d1a8..62dcdb9b68 100644 --- a/source/lib/src/region.cc +++ b/source/lib/src/region.cc @@ -3,6 +3,8 @@ #include "region.h" #define BOXT_DIM 9 +using namespace deepmd; + template Region:: Region() @@ -80,6 +82,7 @@ tensor_t_dot_vec ( template void +deepmd:: init_region_cpu( Region & region, const FPTYPE * boxt) @@ -90,6 +93,7 @@ init_region_cpu( template void +deepmd:: convert_to_inter_cpu( FPTYPE * ri, const Region & region, @@ -100,6 +104,7 @@ convert_to_inter_cpu( template void +deepmd:: convert_to_phys_cpu( FPTYPE * rp, const Region & region, @@ -110,6 +115,7 @@ convert_to_phys_cpu( template FPTYPE +deepmd:: volume_cpu( const Region & region) { @@ -117,49 +123,59 @@ volume_cpu( } template -void init_region_cpu( - Region & region, +void +deepmd:: +init_region_cpu( + deepmd::Region & region, const double * boxt); template -void init_region_cpu( - Region & region, +void +deepmd:: +init_region_cpu( + deepmd::Region & region, const float * boxt); template void +deepmd:: convert_to_inter_cpu( double * ri, - const Region & region, + const deepmd::Region & region, const double * rp); template void +deepmd:: convert_to_inter_cpu( float * ri, - const Region & region, + const deepmd::Region & region, const float * rp); template void +deepmd:: convert_to_phys_cpu( double * ri, - const Region & region, + const deepmd::Region & region, const double * rp); template void +deepmd:: convert_to_phys_cpu( float * ri, - const Region & region, + const deepmd::Region & region, const float * rp); template double +deepmd:: volume_cpu( - const Region & region); + const deepmd::Region & region); template float +deepmd:: volume_cpu( - const Region & region); + const deepmd::Region & region); diff --git a/source/lib/src/soft_min_switch.cc b/source/lib/src/soft_min_switch.cc index fbbf8bbbdd..88471a3d4b 100644 --- a/source/lib/src/soft_min_switch.cc +++ b/source/lib/src/soft_min_switch.cc @@ -4,7 +4,7 @@ #include "switcher.h" template -void soft_min_switch_cpu( +void deepmd::soft_min_switch_cpu( FPTYPE * sw_value, FPTYPE * sw_deriv, const FPTYPE * rij, @@ -46,7 +46,7 @@ void soft_min_switch_cpu( } FPTYPE smin = bb / aa; FPTYPE vv, dd; - spline5_switch(vv, dd, smin, static_cast(rmin), static_cast(rmax)); + spline5_switch(vv, dd, smin, rmin, rmax); // value of switch sw_value[i_idx] = vv; // deriv of switch distributed as force @@ -80,7 +80,7 @@ void soft_min_switch_cpu( } template -void soft_min_switch_cpu( +void deepmd::soft_min_switch_cpu( double * sw_value, double * sw_deriv, const double * rij, @@ -92,7 +92,7 @@ void soft_min_switch_cpu( const double & rmax); template -void soft_min_switch_cpu( +void deepmd::soft_min_switch_cpu( float * sw_value, float * sw_deriv, const float * rij, diff --git a/source/lib/src/soft_min_switch_force.cc b/source/lib/src/soft_min_switch_force.cc index e189276c6e..724952493d 100644 --- a/source/lib/src/soft_min_switch_force.cc +++ b/source/lib/src/soft_min_switch_force.cc @@ -2,7 +2,7 @@ #include template -void soft_min_switch_force_cpu( +void deepmd::soft_min_switch_force_cpu( FPTYPE * force, const FPTYPE * du, const FPTYPE * sw_deriv, @@ -41,7 +41,7 @@ void soft_min_switch_force_cpu( } template -void soft_min_switch_force_cpu( +void deepmd::soft_min_switch_force_cpu( double * force, const double * du, const double * sw_deriv, @@ -51,7 +51,7 @@ void soft_min_switch_force_cpu( const int nnei); template -void soft_min_switch_force_cpu( +void deepmd::soft_min_switch_force_cpu( float * force, const float * du, const float * sw_deriv, diff --git a/source/lib/src/soft_min_switch_force_grad.cc b/source/lib/src/soft_min_switch_force_grad.cc index 63d388b174..31e46e9d6d 100644 --- a/source/lib/src/soft_min_switch_force_grad.cc +++ b/source/lib/src/soft_min_switch_force_grad.cc @@ -2,7 +2,7 @@ #include template -void soft_min_switch_force_grad_cpu( +void deepmd::soft_min_switch_force_grad_cpu( FPTYPE * grad_net, const FPTYPE * grad, const FPTYPE * sw_deriv, @@ -41,7 +41,7 @@ void soft_min_switch_force_grad_cpu( } template -void soft_min_switch_force_grad_cpu( +void deepmd::soft_min_switch_force_grad_cpu( double * grad_net, const double * grad, const double * sw_deriv, @@ -50,7 +50,7 @@ void soft_min_switch_force_grad_cpu( const int nnei); template -void soft_min_switch_force_grad_cpu( +void deepmd::soft_min_switch_force_grad_cpu( float * grad_net, const float * grad, const float * sw_deriv, diff --git a/source/lib/src/soft_min_switch_virial.cc b/source/lib/src/soft_min_switch_virial.cc index 9ceacc5d72..a93ab3c1fb 100644 --- a/source/lib/src/soft_min_switch_virial.cc +++ b/source/lib/src/soft_min_switch_virial.cc @@ -2,7 +2,7 @@ #include template -void soft_min_switch_virial_cpu( +void deepmd::soft_min_switch_virial_cpu( FPTYPE * virial, FPTYPE * atom_virial, const FPTYPE * du, @@ -47,7 +47,7 @@ void soft_min_switch_virial_cpu( template -void soft_min_switch_virial_cpu( +void deepmd::soft_min_switch_virial_cpu( double * virial, double * atom_virial, const double * du, @@ -59,7 +59,7 @@ void soft_min_switch_virial_cpu( const int nnei); template -void soft_min_switch_virial_cpu( +void deepmd::soft_min_switch_virial_cpu( float * virial, float * atom_virial, const float * du, diff --git a/source/lib/src/soft_min_switch_virial_grad.cc b/source/lib/src/soft_min_switch_virial_grad.cc index 3718810dfd..1bb28a7c63 100644 --- a/source/lib/src/soft_min_switch_virial_grad.cc +++ b/source/lib/src/soft_min_switch_virial_grad.cc @@ -1,7 +1,7 @@ #include "soft_min_switch_virial_grad.h" template -void soft_min_switch_virial_grad_cpu( +void deepmd::soft_min_switch_virial_grad_cpu( FPTYPE * grad_net, const FPTYPE * grad, const FPTYPE * sw_deriv, @@ -41,7 +41,7 @@ void soft_min_switch_virial_grad_cpu( } template -void soft_min_switch_virial_grad_cpu( +void deepmd::soft_min_switch_virial_grad_cpu( double * grad_net, const double * grad, const double * sw_deriv, @@ -51,7 +51,7 @@ void soft_min_switch_virial_grad_cpu( const int nnei); template -void soft_min_switch_virial_grad_cpu( +void deepmd::soft_min_switch_virial_grad_cpu( float * grad_net, const float * grad, const float * sw_deriv, diff --git a/source/lib/tests/test_coord.cc b/source/lib/tests/test_coord.cc index 111b66bb06..3706874b55 100644 --- a/source/lib/tests/test_coord.cc +++ b/source/lib/tests/test_coord.cc @@ -37,7 +37,7 @@ class TestNormCoord : public ::testing::Test TEST_F(TestNormCoord, cpu_case0) { - Region region; + deepmd::Region region; init_region_cpu(region, &boxt[0]); std::vector out_c(r0); normalize_coord_cpu(&out_c[0], natoms, region); @@ -48,7 +48,7 @@ TEST_F(TestNormCoord, cpu_case0) TEST_F(TestNormCoord, cpu_case1) { - Region region; + deepmd::Region region; init_region_cpu(region, &boxt[0]); std::vector out_c(r1); normalize_coord_cpu(&out_c[0], natoms, region); @@ -59,7 +59,7 @@ TEST_F(TestNormCoord, cpu_case1) TEST_F(TestNormCoord, cpu_case2) { - Region region; + deepmd::Region region; init_region_cpu(region, &boxt[0]); std::vector out_c(r2); normalize_coord_cpu(&out_c[0], natoms, region); @@ -167,7 +167,7 @@ TEST_F(TestCopyCoord, cpu) std::vector out_t(mem_size); std::vector mapping(mem_size); int nall; - Region region; + deepmd::Region region; init_region_cpu(region, &boxt[0]); int ret = copy_coord_cpu( @@ -211,7 +211,7 @@ TEST_F(TestCopyCoord, cpu_lessmem) std::vector out_t(mem_size); std::vector mapping(mem_size); int nall; - Region region; + deepmd::Region region; init_region_cpu(region, &boxt[0]); int ret = copy_coord_cpu( diff --git a/source/lib/tests/test_env_mat_a.cc b/source/lib/tests/test_env_mat_a.cc index 25fab3e59d..c08a4f4705 100644 --- a/source/lib/tests/test_env_mat_a.cc +++ b/source/lib/tests/test_env_mat_a.cc @@ -239,7 +239,7 @@ TEST_F(TestEnvMatA, cpu) for(int ii = 0; ii < nloc; ++ii){ int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); - env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]*4); EXPECT_EQ(env.size(), env_deriv.size()/3); EXPECT_EQ(rij_a.size(), sec_a[2]*3); @@ -265,7 +265,7 @@ TEST_F(TestEnvMatA, cpu_equal_orig_cpy) int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_1, -1); - env_mat_a_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); EXPECT_EQ(env_0.size(), env_1.size()); EXPECT_EQ(env_deriv_0.size(), env_deriv_1.size()); @@ -291,7 +291,7 @@ TEST_F(TestEnvMatA, cpu_num_deriv) for(int ii = 0; ii < nloc; ++ii){ int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); - env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]*4); EXPECT_EQ(env.size(), env_deriv.size()/3); EXPECT_EQ(rij_a.size(), sec_a[2]*3); @@ -373,7 +373,7 @@ TEST_F(TestEnvMatAShortSel, cpu) for(int ii = 0; ii < nloc; ++ii){ int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, 1); - env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(env, env_deriv, rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(env.size(), sec_a[2]*4); EXPECT_EQ(env.size(), env_deriv.size()/3); EXPECT_EQ(rij_a.size(), sec_a[2]*3); @@ -399,14 +399,14 @@ TEST_F(TestEnvMatA, prod_cpu) } std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); - convert_nlist(inlist, nlist_a_cpy); + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::convert_nlist(inlist, nlist_a_cpy); std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); std::vector nlist(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); - prod_env_mat_a_cpu( + deepmd::prod_env_mat_a_cpu( &em[0], &em_deriv[0], &rij[0], @@ -448,13 +448,13 @@ TEST_F(TestEnvMatA, prod_cpu_equal_cpu) } std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); convert_nlist(inlist, nlist_a_cpy); std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); std::vector nlist(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); - prod_env_mat_a_cpu( + deepmd::prod_env_mat_a_cpu( &em[0], &em_deriv[0], &rij[0], @@ -476,7 +476,7 @@ TEST_F(TestEnvMatA, prod_cpu_equal_cpu) for(int ii = 0; ii < nloc; ++ii){ int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_1, -1); - env_mat_a_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); EXPECT_EQ(env_1.size(), nnei * 4); EXPECT_EQ(env_deriv_1.size(), nnei * 4 * 3); EXPECT_EQ(rij_a_1.size(), nnei * 3); @@ -535,7 +535,7 @@ TEST_F(TestEnvMatA, prod_gpu_cuda) } std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]), gpu_inlist; + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]), gpu_inlist; convert_nlist(inlist, nlist_a_cpy); std::vector em(nloc * ndescrpt, 0.0), em_deriv(nloc * ndescrpt * 3, 0.0), rij(nloc * nnei * 3, 0.0); std::vector nlist(nloc * nnei, 0); @@ -625,7 +625,7 @@ TEST_F(TestEnvMatA, prod_gpu_cuda_equal_cpu) } std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]), gpu_inlist; + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]), gpu_inlist; convert_nlist(inlist, nlist_a_cpy); std::vector em(nloc * ndescrpt, 0.0), em_deriv(nloc * ndescrpt * 3, 0.0), rij(nloc * nnei * 3, 0.0); std::vector nlist(nloc * nnei, 0); @@ -689,7 +689,7 @@ TEST_F(TestEnvMatA, prod_gpu_cuda_equal_cpu) for(int ii = 0; ii < nloc; ++ii){ int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_1, -1); - env_mat_a_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); EXPECT_EQ(env_1.size(), nnei * 4); EXPECT_EQ(env_deriv_1.size(), nnei * 4 * 3); EXPECT_EQ(rij_a_1.size(), nnei * 3); diff --git a/source/lib/tests/test_env_mat_r.cc b/source/lib/tests/test_env_mat_r.cc index 4dfd369c1a..f571dbdaf1 100644 --- a/source/lib/tests/test_env_mat_r.cc +++ b/source/lib/tests/test_env_mat_r.cc @@ -168,7 +168,7 @@ TEST_F(TestEnvMatR, cpu) for(int ii = 0; ii < nloc; ++ii){ int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); - env_mat_r_cpu(env, env_deriv, rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_r_cpu(env, env_deriv, rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < sec_a[2]; ++jj){ EXPECT_LT(fabs(env[jj] - expected_env[ii*sec_a[2] + jj]) , 1e-5); } @@ -188,7 +188,7 @@ TEST_F(TestEnvMatR, cpu_equal_orig_cpy) int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_1, -1); - env_mat_r_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + deepmd::env_mat_r_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); EXPECT_EQ(env_0.size(), env_1.size()); EXPECT_EQ(env_deriv_0.size(), env_deriv_1.size()); @@ -214,7 +214,7 @@ TEST_F(TestEnvMatR, cpu_num_deriv) for(int ii = 0; ii < nloc; ++ii){ int ret = format_nlist_i_cpu(fmt_nlist_a, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret, -1); - env_mat_r_cpu(env, env_deriv, rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_r_cpu(env, env_deriv, rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < sec_a[2]; ++jj){ int j_idx = fmt_nlist_a[jj]; @@ -251,14 +251,14 @@ TEST_F(TestEnvMatR, prod_cpu) } std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); convert_nlist(inlist, nlist_a_cpy); std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); std::vector nlist(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); - prod_env_mat_r_cpu( + deepmd::prod_env_mat_r_cpu( &em[0], &em_deriv[0], &rij[0], @@ -300,13 +300,13 @@ TEST_F(TestEnvMatR, prod_cpu_equal_cpu) } std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); convert_nlist(inlist, nlist_a_cpy); std::vector em(nloc * ndescrpt), em_deriv(nloc * ndescrpt * 3), rij(nloc * nnei * 3); std::vector nlist(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); - prod_env_mat_r_cpu( + deepmd::prod_env_mat_r_cpu( &em[0], &em_deriv[0], &rij[0], @@ -328,7 +328,7 @@ TEST_F(TestEnvMatR, prod_cpu_equal_cpu) for(int ii = 0; ii < nloc; ++ii){ int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_1, -1); - env_mat_r_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + deepmd::env_mat_r_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); EXPECT_EQ(env_1.size(), nnei * 1); EXPECT_EQ(env_deriv_1.size(), nnei * 1 * 3); EXPECT_EQ(rij_a_1.size(), nnei * 3); @@ -531,7 +531,7 @@ TEST_F(TestEnvMatR, prod_gpu_cuda_equal_cpu) for(int ii = 0; ii < nloc; ++ii){ int ret_1 = format_nlist_i_cpu(fmt_nlist_a_1, posi_cpy, atype_cpy, ii, nlist_a_cpy[ii], rc, sec_a); EXPECT_EQ(ret_1, -1); - env_mat_r_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); + deepmd::env_mat_r_cpu(env_1, env_deriv_1, rij_a_1, posi_cpy, atype_cpy, ii, fmt_nlist_a_1, sec_a, rc_smth, rc); EXPECT_EQ(env_1.size(), nnei * 1); EXPECT_EQ(env_deriv_1.size(), nnei * 1 * 3); EXPECT_EQ(rij_a_1.size(), nnei * 3); diff --git a/source/lib/tests/test_ewald.cc b/source/lib/tests/test_ewald.cc index 44cb758273..cb8e59e1d9 100644 --- a/source/lib/tests/test_ewald.cc +++ b/source/lib/tests/test_ewald.cc @@ -20,7 +20,7 @@ class TestEwald : public ::testing::Test std::vector boxt = { 13., 0., 0., 0., 13., 0., 0., 0., 13. }; - EwaldParameters eparam; + deepmd::EwaldParameters eparam; double expected_e = 4.7215808340392229e+00; std::vector expected_f = { -5.4937025715874448e+00,5.6659817006308417e+00,3.8059426028301313e-01,2.5210962791915938e+00,-2.6383552457553545e+00,-4.8998411247787405e-01,2.7390037416771147e+00,-3.2890571945143514e+00,3.8057620258450320e-01,6.7561832843578351e+00,-1.3707287681111919e+00,2.7733203842981604e+00,-3.3297964389679557e+00,1.0404967238120841e+00,-1.8035649784287722e+00,-3.1927842946711418e+00,5.9166278393797123e-01,-1.2409417562590299e+00, @@ -38,7 +38,7 @@ TEST_F(TestEwald, cpu) { double ener; std::vector force, virial; - Region region; + deepmd::Region region; init_region_cpu(region, &boxt[0]); ewald_recp(ener, force, virial, coord, charge, region, eparam); EXPECT_LT(fabs(ener - expected_e), 1e-10); diff --git a/source/lib/tests/test_fmt_nlist.cc b/source/lib/tests/test_fmt_nlist.cc index a37562a230..6dc539b7d6 100644 --- a/source/lib/tests/test_fmt_nlist.cc +++ b/source/lib/tests/test_fmt_nlist.cc @@ -212,7 +212,7 @@ TEST_F(TestFormatNlist, cpu) std::vector ilist(inum); std::vector numneigh(inum); std::vector firstneigh(inum); - InputNlist in_nlist(inum, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::InputNlist in_nlist(inum, &ilist[0], &numneigh[0], &firstneigh[0]); convert_nlist(in_nlist, nlist_a_0); // allocate the mem for the result std::vector nlist(inum * sec_a.back()); @@ -280,7 +280,7 @@ TEST_F(TestFormatNlistShortSel, cpu) std::vector ilist(inum); std::vector numneigh(inum); std::vector firstneigh(inum); - InputNlist in_nlist(inum, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::InputNlist in_nlist(inum, &ilist[0], &numneigh[0], &firstneigh[0]); convert_nlist(in_nlist, nlist_a_0); // mem std::vector nlist(inum * sec_a.back()); diff --git a/source/lib/tests/test_gelu.cc b/source/lib/tests/test_gelu.cc index f8a65ae308..0b05dd71d5 100644 --- a/source/lib/tests/test_gelu.cc +++ b/source/lib/tests/test_gelu.cc @@ -112,7 +112,7 @@ class TestGelu : public ::testing::Test TEST_F(TestGelu, gelu_cpu) { std::vector gelu(nloc); - gelu_cpu (&gelu[0], &xx[0], nloc); + deepmd::gelu_cpu (&gelu[0], &xx[0], nloc); EXPECT_EQ(gelu.size(), nloc); EXPECT_EQ(gelu.size(), expected_gelu.size()); for (int jj = 0; jj < gelu.size(); ++jj){ @@ -124,7 +124,7 @@ TEST_F(TestGelu, gelu_grad_cpu) { std::vector dy(100, 1.0); std::vector gelu_grad(nloc); - gelu_grad_cpu (&gelu_grad[0], &xx[0], &dy[0], nloc); + deepmd::gelu_grad_cpu (&gelu_grad[0], &xx[0], &dy[0], nloc); EXPECT_EQ(gelu_grad.size(), nloc); EXPECT_EQ(gelu_grad.size(), expected_gelu_grad.size()); for (int jj = 0; jj < gelu_grad.size(); ++jj){ @@ -137,7 +137,7 @@ TEST_F(TestGelu, gelu_grad_grad_cpu) std::vector dy(100, 1.0); std::vector dy_2(100, 1.0); std::vector gelu_grad_grad(nloc); - gelu_grad_grad_cpu (&gelu_grad_grad[0], &xx[0], &dy[0], &dy_2[0], nloc); + deepmd::gelu_grad_grad_cpu (&gelu_grad_grad[0], &xx[0], &dy[0], &dy_2[0], nloc); EXPECT_EQ(gelu_grad_grad.size(), nloc); EXPECT_EQ(gelu_grad_grad.size(), expected_gelu_grad_grad.size()); for (int jj = 0; jj < gelu_grad_grad.size(); ++jj){ @@ -211,4 +211,4 @@ TEST_F(TestGelu, gelu_grad_grad_gpu_cuda) EXPECT_LT(fabs(gelu_grad_grad[jj] - expected_gelu_grad_grad[jj]) , 1e-5); } } -#endif // GOOGLE_CUDA \ No newline at end of file +#endif // GOOGLE_CUDA diff --git a/source/lib/tests/test_map_aparam.cc b/source/lib/tests/test_map_aparam.cc index 286f878ffe..a393345eb0 100644 --- a/source/lib/tests/test_map_aparam.cc +++ b/source/lib/tests/test_map_aparam.cc @@ -71,7 +71,7 @@ class TestMapAparam : public ::testing::Test TEST_F(TestMapAparam, cpu) { std::vector output(nloc * nnei * numb_aparam); - map_aparam_cpu( + deepmd::map_aparam_cpu( &output[0], &aparam[0], &nlist[0], diff --git a/source/lib/tests/test_neighbor_list.cc b/source/lib/tests/test_neighbor_list.cc index a0962cecbf..cd8211fb09 100644 --- a/source/lib/tests/test_neighbor_list.cc +++ b/source/lib/tests/test_neighbor_list.cc @@ -54,7 +54,7 @@ TEST_F(TestNeighborList, cpu) firstneigh[ii] = new int[mem_size]; } - InputNlist nlist(nloc, ilist, numneigh, firstneigh); + deepmd::InputNlist nlist(nloc, ilist, numneigh, firstneigh); int max_list_size; int ret = build_nlist_cpu( nlist, @@ -94,7 +94,7 @@ TEST_F(TestNeighborList, cpu_lessmem) firstneigh[ii] = new int[mem_size]; } - InputNlist nlist(nloc, ilist, numneigh, firstneigh); + deepmd::InputNlist nlist(nloc, ilist, numneigh, firstneigh); int max_list_size; int ret = build_nlist_cpu( nlist, diff --git a/source/lib/tests/test_pair_tab.cc b/source/lib/tests/test_pair_tab.cc index 0c7cf5ea6f..c55e96369f 100644 --- a/source/lib/tests/test_pair_tab.cc +++ b/source/lib/tests/test_pair_tab.cc @@ -98,7 +98,7 @@ class TestPairTab : public ::testing::Test } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < ndescrpt; ++jj){ env[ii*ndescrpt+jj] = t_env[jj]; for (int dd = 0; dd < 3; ++dd){ @@ -134,7 +134,7 @@ TEST_F(TestPairTab, cpu) std::vector virial(nall * 9); std::vector scale(nloc, 1.0); - pair_tab_cpu( + deepmd::pair_tab_cpu( &energy[0], &force[0], &virial[0], @@ -197,7 +197,7 @@ TEST_F(TestPairTab, cpu_f_num_deriv) std::vector virial(9, 0.); std::vector atom_virial(nall * 9); std::vector scale(nloc, 1.0); - pair_tab_cpu( + deepmd::pair_tab_cpu( &energy[0], &force[0], &atom_virial[0], @@ -242,8 +242,8 @@ TEST_F(TestPairTab, cpu_f_num_deriv) build_nlist(nlist_cpy_1, t_nlist, posi_cpy_1, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); std::vector ilist_0(nloc), numneigh_0(nloc), ilist_1(nloc), numneigh_1(nloc);; std::vector firstneigh_0(nloc), firstneigh_1(nloc); - InputNlist inlist_0(nloc, &ilist_0[0], &numneigh_0[0], &firstneigh_0[0]); - InputNlist inlist_1(nloc, &ilist_1[0], &numneigh_1[0], &firstneigh_1[0]); + deepmd::InputNlist inlist_0(nloc, &ilist_0[0], &numneigh_0[0], &firstneigh_0[0]); + deepmd::InputNlist inlist_1(nloc, &ilist_1[0], &numneigh_1[0], &firstneigh_1[0]); convert_nlist(inlist_0, nlist_cpy_0); convert_nlist(inlist_1, nlist_cpy_1); int max_nnei_0 = max_numneigh(inlist_0); @@ -254,11 +254,11 @@ TEST_F(TestPairTab, cpu_f_num_deriv) std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], inlist_0, max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], inlist_1, max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + deepmd::prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], inlist_0, max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + deepmd::prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], inlist_1, max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); - pair_tab_cpu( + deepmd::pair_tab_cpu( &energy_0[0], &t_force[0], &t_virial[0], @@ -271,7 +271,7 @@ TEST_F(TestPairTab, cpu_f_num_deriv) &natoms[0], sel_a, sel_r); - pair_tab_cpu( + deepmd::pair_tab_cpu( &energy_1[0], &t_force[0], &t_virial[0], @@ -305,7 +305,7 @@ TEST_F(TestPairTab, cpu_f_num_deriv_scale) std::vector virial(9, 0.); std::vector atom_virial(nall * 9); std::vector scale(nloc, new_scale); - pair_tab_cpu( + deepmd::pair_tab_cpu( &energy[0], &force[0], &atom_virial[0], @@ -350,8 +350,8 @@ TEST_F(TestPairTab, cpu_f_num_deriv_scale) build_nlist(nlist_cpy_1, t_nlist, posi_cpy_1, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region, ncell); std::vector ilist_0(nloc), numneigh_0(nloc), ilist_1(nloc), numneigh_1(nloc);; std::vector firstneigh_0(nloc), firstneigh_1(nloc); - InputNlist inlist_0(nloc, &ilist_0[0], &numneigh_0[0], &firstneigh_0[0]); - InputNlist inlist_1(nloc, &ilist_1[0], &numneigh_1[0], &firstneigh_1[0]); + deepmd::InputNlist inlist_0(nloc, &ilist_0[0], &numneigh_0[0], &firstneigh_0[0]); + deepmd::InputNlist inlist_1(nloc, &ilist_1[0], &numneigh_1[0], &firstneigh_1[0]); convert_nlist(inlist_0, nlist_cpy_0); convert_nlist(inlist_1, nlist_cpy_1); int max_nnei_0 = max_numneigh(inlist_0); @@ -362,11 +362,11 @@ TEST_F(TestPairTab, cpu_f_num_deriv_scale) std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], inlist_0, max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], inlist_1, max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + deepmd::prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], inlist_0, max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + deepmd::prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], inlist_1, max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); - pair_tab_cpu( + deepmd::pair_tab_cpu( &energy_0[0], &t_force[0], &t_virial[0], @@ -379,7 +379,7 @@ TEST_F(TestPairTab, cpu_f_num_deriv_scale) &natoms[0], sel_a, sel_r); - pair_tab_cpu( + deepmd::pair_tab_cpu( &energy_1[0], &t_force[0], &t_virial[0], @@ -411,7 +411,7 @@ TEST_F(TestPairTab, cpu_v_num_deriv) std::vector virial(9, 0.); std::vector atom_virial(nall * 9); std::vector scale(nloc, 1.0); - pair_tab_cpu( + deepmd::pair_tab_cpu( &energy[0], &force[0], &atom_virial[0], @@ -471,8 +471,8 @@ TEST_F(TestPairTab, cpu_v_num_deriv) build_nlist(nlist_cpy_1, t_nlist, posi_cpy_1, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region_1, ncell); std::vector ilist_0(nloc), numneigh_0(nloc), ilist_1(nloc), numneigh_1(nloc);; std::vector firstneigh_0(nloc), firstneigh_1(nloc); - InputNlist inlist_0(nloc, &ilist_0[0], &numneigh_0[0], &firstneigh_0[0]); - InputNlist inlist_1(nloc, &ilist_1[0], &numneigh_1[0], &firstneigh_1[0]); + deepmd::InputNlist inlist_0(nloc, &ilist_0[0], &numneigh_0[0], &firstneigh_0[0]); + deepmd::InputNlist inlist_1(nloc, &ilist_1[0], &numneigh_1[0], &firstneigh_1[0]); convert_nlist(inlist_0, nlist_cpy_0); convert_nlist(inlist_1, nlist_cpy_1); int max_nnei_0 = max_numneigh(inlist_0); @@ -483,11 +483,11 @@ TEST_F(TestPairTab, cpu_v_num_deriv) std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], inlist_0, max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], inlist_1, max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + deepmd::prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], inlist_0, max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + deepmd::prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], inlist_1, max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); - pair_tab_cpu( + deepmd::pair_tab_cpu( &energy_0[0], &t_force[0], &t_virial[0], @@ -500,7 +500,7 @@ TEST_F(TestPairTab, cpu_v_num_deriv) &natoms[0], sel_a, sel_r); - pair_tab_cpu( + deepmd::pair_tab_cpu( &energy_1[0], &t_force[0], &t_virial[0], @@ -543,7 +543,7 @@ TEST_F(TestPairTab, cpu_v_num_deriv_scale) std::vector virial(9, 0.); std::vector atom_virial(nall * 9); std::vector scale(nloc, new_scale); - pair_tab_cpu( + deepmd::pair_tab_cpu( &energy[0], &force[0], &atom_virial[0], @@ -603,8 +603,8 @@ TEST_F(TestPairTab, cpu_v_num_deriv_scale) build_nlist(nlist_cpy_1, t_nlist, posi_cpy_1, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region_1, ncell); std::vector ilist_0(nloc), numneigh_0(nloc), ilist_1(nloc), numneigh_1(nloc);; std::vector firstneigh_0(nloc), firstneigh_1(nloc); - InputNlist inlist_0(nloc, &ilist_0[0], &numneigh_0[0], &firstneigh_0[0]); - InputNlist inlist_1(nloc, &ilist_1[0], &numneigh_1[0], &firstneigh_1[0]); + deepmd::InputNlist inlist_0(nloc, &ilist_0[0], &numneigh_0[0], &firstneigh_0[0]); + deepmd::InputNlist inlist_1(nloc, &ilist_1[0], &numneigh_1[0], &firstneigh_1[0]); convert_nlist(inlist_0, nlist_cpy_0); convert_nlist(inlist_1, nlist_cpy_1); int max_nnei_0 = max_numneigh(inlist_0); @@ -615,11 +615,11 @@ TEST_F(TestPairTab, cpu_v_num_deriv_scale) std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], inlist_0, max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], inlist_1, max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + deepmd::prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], inlist_0, max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + deepmd::prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], inlist_1, max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); - pair_tab_cpu( + deepmd::pair_tab_cpu( &energy_0[0], &t_force[0], &t_virial[0], @@ -632,7 +632,7 @@ TEST_F(TestPairTab, cpu_v_num_deriv_scale) &natoms[0], sel_a, sel_r); - pair_tab_cpu( + deepmd::pair_tab_cpu( &energy_1[0], &t_force[0], &t_virial[0], @@ -675,7 +675,7 @@ TEST_F(TestPairTabTriBox, cpu_v_num_deriv) std::vector virial(9, 0.); std::vector atom_virial(nall * 9); std::vector scale(nloc, 1.0); - pair_tab_cpu( + deepmd::pair_tab_cpu( &energy[0], &force[0], &atom_virial[0], @@ -735,8 +735,8 @@ TEST_F(TestPairTabTriBox, cpu_v_num_deriv) build_nlist(nlist_cpy_1, t_nlist, posi_cpy_1, nloc, rc, rc, nat_stt, ncell, ext_stt, ext_end, region_1, ncell); std::vector ilist_0(nloc), numneigh_0(nloc), ilist_1(nloc), numneigh_1(nloc);; std::vector firstneigh_0(nloc), firstneigh_1(nloc); - InputNlist inlist_0(nloc, &ilist_0[0], &numneigh_0[0], &firstneigh_0[0]); - InputNlist inlist_1(nloc, &ilist_1[0], &numneigh_1[0], &firstneigh_1[0]); + deepmd::InputNlist inlist_0(nloc, &ilist_0[0], &numneigh_0[0], &firstneigh_0[0]); + deepmd::InputNlist inlist_1(nloc, &ilist_1[0], &numneigh_1[0], &firstneigh_1[0]); convert_nlist(inlist_0, nlist_cpy_0); convert_nlist(inlist_1, nlist_cpy_1); int max_nnei_0 = max_numneigh(inlist_0); @@ -747,11 +747,11 @@ TEST_F(TestPairTabTriBox, cpu_v_num_deriv) std::vector nlist_0(nloc * nnei), nlist_1(nloc * nnei); std::vector avg(ntypes * ndescrpt, 0); std::vector std(ntypes * ndescrpt, 1); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], inlist_0, max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); - prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], inlist_1, max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + deepmd::prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_0[0], &nlist_0[0], &posi_cpy_0[0], &atype_cpy_0[0], inlist_0, max_nnei_0, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); + deepmd::prod_env_mat_a_cpu(&t_em[0], &t_em_deriv[0], &rij_1[0], &nlist_1[0], &posi_cpy_1[0], &atype_cpy_1[0], inlist_1, max_nnei_1, &avg[0], &std[0], nloc, nall, rc, rc_smth, sec_a); std::vector energy_0(nloc), energy_1(nloc); std::vector t_force(nall * 3), t_virial(nall * 9); - pair_tab_cpu( + deepmd::pair_tab_cpu( &energy_0[0], &t_force[0], &t_virial[0], @@ -764,7 +764,7 @@ TEST_F(TestPairTabTriBox, cpu_v_num_deriv) &natoms[0], sel_a, sel_r); - pair_tab_cpu( + deepmd::pair_tab_cpu( &energy_1[0], &t_force[0], &t_virial[0], diff --git a/source/lib/tests/test_prod_force_a.cc b/source/lib/tests/test_prod_force_a.cc index 7cd76e6ed7..7aeb9ca99f 100644 --- a/source/lib/tests/test_prod_force_a.cc +++ b/source/lib/tests/test_prod_force_a.cc @@ -65,7 +65,7 @@ class TestProdForceA : public ::testing::Test } std::vector t_env, t_env_deriv, t_rij_a; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < ndescrpt; ++jj){ env[ii*ndescrpt+jj] = t_env[jj]; for (int dd = 0; dd < 3; ++dd){ @@ -86,7 +86,7 @@ TEST_F(TestProdForceA, cpu) { std::vector force(nall * 3); int n_a_sel = nnei; - prod_force_a_cpu (&force[0], &net_deriv[0], &env_deriv[0], &nlist[0], nloc, nall, nnei); + deepmd::prod_force_a_cpu (&force[0], &net_deriv[0], &env_deriv[0], &nlist[0], nloc, nall, nnei); EXPECT_EQ(force.size(), nall * 3); EXPECT_EQ(force.size(), expected_force.size()); for (int jj = 0; jj < force.size(); ++jj){ @@ -126,4 +126,4 @@ TEST_F(TestProdForceA, gpu_cuda) EXPECT_LT(fabs(force[jj] - expected_force[jj]) , 1e-5); } } -#endif // GOOGLE_CUDA \ No newline at end of file +#endif // GOOGLE_CUDA diff --git a/source/lib/tests/test_prod_force_grad_a.cc b/source/lib/tests/test_prod_force_grad_a.cc index b52c1c951e..82ab484616 100644 --- a/source/lib/tests/test_prod_force_grad_a.cc +++ b/source/lib/tests/test_prod_force_grad_a.cc @@ -64,7 +64,7 @@ class TestProdForceGradA : public ::testing::Test } std::vector t_env, t_env_deriv, t_rij_a; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < ndescrpt; ++jj){ env[ii*ndescrpt+jj] = t_env[jj]; for (int dd = 0; dd < 3; ++dd){ @@ -84,7 +84,7 @@ class TestProdForceGradA : public ::testing::Test TEST_F(TestProdForceGradA, cpu) { std::vector grad_net(nloc * ndescrpt); - prod_force_grad_a_cpu(&grad_net[0], &grad[0], &env_deriv[0], &nlist[0], nloc, nnei); + deepmd::prod_force_grad_a_cpu(&grad_net[0], &grad[0], &env_deriv[0], &nlist[0], nloc, nnei); EXPECT_EQ(grad_net.size(), nloc * ndescrpt); EXPECT_EQ(grad_net.size(), expected_grad_net.size()); for (int jj = 0; jj < grad_net.size(); ++jj){ diff --git a/source/lib/tests/test_prod_force_grad_r.cc b/source/lib/tests/test_prod_force_grad_r.cc index c32ce150e8..37534db7f8 100644 --- a/source/lib/tests/test_prod_force_grad_r.cc +++ b/source/lib/tests/test_prod_force_grad_r.cc @@ -64,7 +64,7 @@ class TestProdForceGradR : public ::testing::Test } std::vector t_env, t_env_deriv, t_rij_a; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < ndescrpt; ++jj){ env[ii*ndescrpt+jj] = t_env[jj]; for (int dd = 0; dd < 3; ++dd){ @@ -84,7 +84,7 @@ class TestProdForceGradR : public ::testing::Test TEST_F(TestProdForceGradR, cpu) { std::vector grad_net(nloc * ndescrpt); - prod_force_grad_r_cpu(&grad_net[0], &grad[0], &env_deriv[0], &nlist[0], nloc, nnei); + deepmd::prod_force_grad_r_cpu(&grad_net[0], &grad[0], &env_deriv[0], &nlist[0], nloc, nnei); EXPECT_EQ(grad_net.size(), nloc * ndescrpt); EXPECT_EQ(grad_net.size(), expected_grad_net.size()); for (int jj = 0; jj < grad_net.size(); ++jj){ diff --git a/source/lib/tests/test_prod_force_r.cc b/source/lib/tests/test_prod_force_r.cc index 6a3d68576b..033c41a7fe 100644 --- a/source/lib/tests/test_prod_force_r.cc +++ b/source/lib/tests/test_prod_force_r.cc @@ -65,7 +65,7 @@ class TestProdForceR : public ::testing::Test } std::vector t_env, t_env_deriv, t_rij_a; // compute env_mat and its deriv, record - env_mat_r_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_r_cpu(t_env, t_env_deriv, t_rij_a, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < ndescrpt; ++jj){ env[ii*ndescrpt+jj] = t_env[jj]; for (int dd = 0; dd < 3; ++dd){ @@ -86,7 +86,7 @@ TEST_F(TestProdForceR, cpu) { std::vector force(nall * 3); int n_a_sel = nnei; - prod_force_r_cpu (&force[0], &net_deriv[0], &env_deriv[0], &nlist[0], nloc, nall, nnei); + deepmd::prod_force_r_cpu (&force[0], &net_deriv[0], &env_deriv[0], &nlist[0], nloc, nall, nnei); EXPECT_EQ(force.size(), nall * 3); EXPECT_EQ(force.size(), expected_force.size()); for (int jj = 0; jj < force.size(); ++jj){ diff --git a/source/lib/tests/test_prod_virial_a.cc b/source/lib/tests/test_prod_virial_a.cc index aa0e7bfac9..f1d4ee619a 100644 --- a/source/lib/tests/test_prod_virial_a.cc +++ b/source/lib/tests/test_prod_virial_a.cc @@ -68,7 +68,7 @@ class TestProdVirialA : public ::testing::Test } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < ndescrpt; ++jj){ env[ii*ndescrpt+jj] = t_env[jj]; for (int dd = 0; dd < 3; ++dd){ @@ -93,7 +93,7 @@ TEST_F(TestProdVirialA, cpu) std::vector virial(9); std::vector atom_virial(nall * 9); int n_a_sel = nnei; - prod_virial_a_cpu (&virial[0], &atom_virial[0], &net_deriv[0], &env_deriv[0], &rij[0], &nlist[0], nloc, nall, nnei); + deepmd::prod_virial_a_cpu (&virial[0], &atom_virial[0], &net_deriv[0], &env_deriv[0], &rij[0], &nlist[0], nloc, nall, nnei); EXPECT_EQ(virial.size(), 9); EXPECT_EQ(virial.size(), expected_virial.size()); EXPECT_EQ(atom_virial.size(), nall * 9); @@ -159,4 +159,4 @@ TEST_F(TestProdVirialA, gpu_cuda) EXPECT_LT(fabs(atom_virial[jj] - expected_atom_virial[jj]) , 1e-5); } } -#endif // GOOGLE_CUDA \ No newline at end of file +#endif // GOOGLE_CUDA diff --git a/source/lib/tests/test_prod_virial_grad_a.cc b/source/lib/tests/test_prod_virial_grad_a.cc index cba31a10a8..53ad63e965 100644 --- a/source/lib/tests/test_prod_virial_grad_a.cc +++ b/source/lib/tests/test_prod_virial_grad_a.cc @@ -64,7 +64,7 @@ class TestProdVirialGradA : public ::testing::Test } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < ndescrpt; ++jj){ env[ii*ndescrpt+jj] = t_env[jj]; for (int dd = 0; dd < 3; ++dd){ @@ -88,7 +88,7 @@ TEST_F(TestProdVirialGradA, cpu) { std::vector grad_net(nloc * ndescrpt); int n_a_sel = nnei; - prod_virial_grad_a_cpu (&grad_net[0], &grad[0], &env_deriv[0], &rij[0], &nlist[0], nloc, nnei); + deepmd::prod_virial_grad_a_cpu (&grad_net[0], &grad[0], &env_deriv[0], &rij[0], &nlist[0], nloc, nnei); EXPECT_EQ(grad_net.size(), nloc * ndescrpt); EXPECT_EQ(grad_net.size(), expected_grad_net.size()); for (int jj = 0; jj < grad_net.size(); ++jj){ diff --git a/source/lib/tests/test_prod_virial_grad_r.cc b/source/lib/tests/test_prod_virial_grad_r.cc index 45e6944590..2cb0c91038 100644 --- a/source/lib/tests/test_prod_virial_grad_r.cc +++ b/source/lib/tests/test_prod_virial_grad_r.cc @@ -64,7 +64,7 @@ class TestProdVirialGradR : public ::testing::Test } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < ndescrpt; ++jj){ env[ii*ndescrpt+jj] = t_env[jj]; for (int dd = 0; dd < 3; ++dd){ @@ -88,7 +88,7 @@ TEST_F(TestProdVirialGradR, cpu) { std::vector grad_net(nloc * ndescrpt); int n_a_sel = nnei; - prod_virial_grad_r_cpu (&grad_net[0], &grad[0], &env_deriv[0], &rij[0], &nlist[0], nloc, nnei); + deepmd::prod_virial_grad_r_cpu (&grad_net[0], &grad[0], &env_deriv[0], &rij[0], &nlist[0], nloc, nnei); EXPECT_EQ(grad_net.size(), nloc * ndescrpt); EXPECT_EQ(grad_net.size(), expected_grad_net.size()); for (int jj = 0; jj < grad_net.size(); ++jj){ diff --git a/source/lib/tests/test_prod_virial_r.cc b/source/lib/tests/test_prod_virial_r.cc index c09a2f04ad..101b1659f8 100644 --- a/source/lib/tests/test_prod_virial_r.cc +++ b/source/lib/tests/test_prod_virial_r.cc @@ -68,7 +68,7 @@ class TestProdVirialR : public ::testing::Test } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_r_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_r_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < ndescrpt; ++jj){ env[ii*ndescrpt+jj] = t_env[jj]; for (int dd = 0; dd < 3; ++dd){ @@ -93,7 +93,7 @@ TEST_F(TestProdVirialR, cpu) std::vector virial(9); std::vector atom_virial(nall * 9); int n_a_sel = nnei; - prod_virial_r_cpu (&virial[0], &atom_virial[0], &net_deriv[0], &env_deriv[0], &rij[0], &nlist[0], nloc, nall, nnei); + deepmd::prod_virial_r_cpu (&virial[0], &atom_virial[0], &net_deriv[0], &env_deriv[0], &rij[0], &nlist[0], nloc, nall, nnei); EXPECT_EQ(virial.size(), 9); EXPECT_EQ(atom_virial.size(), nall * 9); EXPECT_EQ(virial.size(), expected_virial.size()); @@ -159,4 +159,4 @@ TEST_F(TestProdVirialR, gpu_cuda) EXPECT_LT(fabs(atom_virial[jj] - expected_atom_virial[jj]) , 1e-5); } } -#endif // GOOGLE_CUDA \ No newline at end of file +#endif // GOOGLE_CUDA diff --git a/source/lib/tests/test_simulation_region.cc b/source/lib/tests/test_simulation_region.cc index dbd65d2883..674c505c02 100644 --- a/source/lib/tests/test_simulation_region.cc +++ b/source/lib/tests/test_simulation_region.cc @@ -41,7 +41,7 @@ TEST_F(TestRegion, orig) TEST_F(TestRegion, cpu) { // check rec_box - Region region; + deepmd::Region region; init_region_cpu(region, &ref_boxt[0]); for(int ii = 0; ii < 9; ++ii){ EXPECT_LT(fabs(region.rec_boxt[ii] - ref_rec_boxt[ii]), 1e-10); diff --git a/source/lib/tests/test_soft_min_switch.cc b/source/lib/tests/test_soft_min_switch.cc index 0e9319c183..e8e1a0eddc 100644 --- a/source/lib/tests/test_soft_min_switch.cc +++ b/source/lib/tests/test_soft_min_switch.cc @@ -65,7 +65,7 @@ class TestSoftMinSwitch : public ::testing::Test } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < nnei * 3; ++jj){ rij[ii*nnei*3 + jj] = t_rij[jj]; } @@ -79,7 +79,7 @@ TEST_F(TestSoftMinSwitch, cpu) { std::vector sw_value(nloc); std::vector sw_deriv(nloc * nnei * 3); - soft_min_switch_cpu (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); + deepmd::soft_min_switch_cpu (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); EXPECT_EQ(sw_value.size(), nloc); EXPECT_EQ(sw_value.size(), expected_value.size()); EXPECT_EQ(sw_deriv.size(), nloc * nnei * 3); @@ -106,7 +106,7 @@ TEST_F(TestSoftMinSwitch, cpu_num_deriv) std::vector fmt_nlist_a; double hh = 1e-5; - soft_min_switch_cpu (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); + deepmd::soft_min_switch_cpu (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); EXPECT_EQ(sw_value.size(), nloc); EXPECT_EQ(sw_deriv.size(), nloc * nnei * 3); @@ -123,8 +123,8 @@ TEST_F(TestSoftMinSwitch, cpu_num_deriv) std::vector posi_1 = posi_cpy; posi_0[j_idx*3+dd] -= hh; posi_1[j_idx*3+dd] += hh; - env_mat_a_cpu(env, env_deriv, t_rij_0, posi_0, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); - env_mat_a_cpu(env, env_deriv, t_rij_1, posi_1, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(env, env_deriv, t_rij_0, posi_0, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(env, env_deriv, t_rij_1, posi_1, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); EXPECT_EQ(t_rij_0.size(), nnei * 3); EXPECT_EQ(t_rij_1.size(), nnei * 3); rij_0 = rij; @@ -133,8 +133,8 @@ TEST_F(TestSoftMinSwitch, cpu_num_deriv) rij_0[ii*nnei*3 + jj*3 + dd] = t_rij_0[jj*3 + dd]; rij_1[ii*nnei*3 + jj*3 + dd] = t_rij_1[jj*3 + dd]; } - soft_min_switch_cpu (&sw_value_0[0], &sw_deriv_0[0], &rij_0[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); - soft_min_switch_cpu (&sw_value_1[0], &sw_deriv_1[0], &rij_1[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); + deepmd::soft_min_switch_cpu (&sw_value_0[0], &sw_deriv_0[0], &rij_0[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); + deepmd::soft_min_switch_cpu (&sw_value_1[0], &sw_deriv_1[0], &rij_1[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); double ana_deriv = sw_deriv[ii*nnei*3 + jj*3 + dd]; double num_deriv = (sw_value_1[ii] - sw_value_0[ii]) / (2. * hh); EXPECT_LT(fabs(num_deriv - ana_deriv), 1e-5); diff --git a/source/lib/tests/test_soft_min_switch_force.cc b/source/lib/tests/test_soft_min_switch_force.cc index ebe1b62dfe..da40ab662b 100644 --- a/source/lib/tests/test_soft_min_switch_force.cc +++ b/source/lib/tests/test_soft_min_switch_force.cc @@ -66,14 +66,14 @@ class TestSoftMinSwitchForce : public ::testing::Test } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < nnei * 3; ++jj){ rij[ii*nnei*3 + jj] = t_rij[jj]; } } sw_value.resize(nloc); sw_deriv.resize(nloc * nnei * 3); - soft_min_switch_cpu (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, + deepmd::soft_min_switch_cpu (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); du.resize(nloc); for (int ii = 0; ii < nloc; ++ii){ @@ -87,7 +87,7 @@ class TestSoftMinSwitchForce : public ::testing::Test TEST_F(TestSoftMinSwitchForce, cpu) { std::vector force(nall * 3); - soft_min_switch_force_cpu( + deepmd::soft_min_switch_force_cpu( &force[0], &du[0], &sw_deriv[0], diff --git a/source/lib/tests/test_soft_min_switch_force_grad.cc b/source/lib/tests/test_soft_min_switch_force_grad.cc index 66faf0801a..0591b91e3f 100644 --- a/source/lib/tests/test_soft_min_switch_force_grad.cc +++ b/source/lib/tests/test_soft_min_switch_force_grad.cc @@ -66,14 +66,14 @@ class TestSoftMinSwitchForceGrad : public ::testing::Test } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < nnei * 3; ++jj){ rij[ii*nnei*3 + jj] = t_rij[jj]; } } sw_value.resize(nloc); sw_deriv.resize(nloc * nnei * 3); - soft_min_switch_cpu (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, + deepmd::soft_min_switch_cpu (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); grad.resize(nloc * 3); for (int ii = 0; ii < nloc; ++ii){ @@ -87,7 +87,7 @@ class TestSoftMinSwitchForceGrad : public ::testing::Test TEST_F(TestSoftMinSwitchForceGrad, cpu) { std::vector grad_net(nloc); - soft_min_switch_force_grad_cpu( + deepmd::soft_min_switch_force_grad_cpu( &grad_net[0], &grad[0], &sw_deriv[0], diff --git a/source/lib/tests/test_soft_min_switch_virial.cc b/source/lib/tests/test_soft_min_switch_virial.cc index 6132590adf..69471eb9ce 100644 --- a/source/lib/tests/test_soft_min_switch_virial.cc +++ b/source/lib/tests/test_soft_min_switch_virial.cc @@ -69,14 +69,14 @@ class TestSoftMinSwitchVirial : public ::testing::Test } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < nnei * 3; ++jj){ rij[ii*nnei*3 + jj] = t_rij[jj]; } } sw_value.resize(nloc); sw_deriv.resize(nloc * nnei * 3); - soft_min_switch_cpu (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, + deepmd::soft_min_switch_cpu (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); du.resize(nloc); for (int ii = 0; ii < nloc; ++ii){ @@ -91,7 +91,7 @@ TEST_F(TestSoftMinSwitchVirial, cpu) { std::vector virial(9); std::vector atom_virial(nall * 9); - soft_min_switch_virial_cpu( + deepmd::soft_min_switch_virial_cpu( &virial[0], &atom_virial[0], &du[0], diff --git a/source/lib/tests/test_soft_min_switch_virial_grad.cc b/source/lib/tests/test_soft_min_switch_virial_grad.cc index 540e846f73..db5b05fe26 100644 --- a/source/lib/tests/test_soft_min_switch_virial_grad.cc +++ b/source/lib/tests/test_soft_min_switch_virial_grad.cc @@ -66,14 +66,14 @@ class TestSoftMinSwitchVirialGrad : public ::testing::Test } std::vector t_env, t_env_deriv, t_rij; // compute env_mat and its deriv, record - env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); + deepmd::env_mat_a_cpu(t_env, t_env_deriv, t_rij, posi_cpy, atype_cpy, ii, fmt_nlist_a, sec_a, rc_smth, rc); for (int jj = 0; jj < nnei * 3; ++jj){ rij[ii*nnei*3 + jj] = t_rij[jj]; } } sw_value.resize(nloc); sw_deriv.resize(nloc * nnei * 3); - soft_min_switch_cpu (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, + deepmd::soft_min_switch_cpu (&sw_value[0], &sw_deriv[0], &rij[0], &nlist[0], nloc, nnei, alpha, rmin, rmax); grad.resize(nloc * 3); for (int ii = 0; ii < nloc; ++ii){ @@ -87,7 +87,7 @@ class TestSoftMinSwitchVirialGrad : public ::testing::Test TEST_F(TestSoftMinSwitchVirialGrad, cpu) { std::vector grad_net(nloc); - soft_min_switch_virial_grad_cpu( + deepmd::soft_min_switch_virial_grad_cpu( &grad_net[0], &grad[0], &sw_deriv[0], diff --git a/source/lmp/fix_dplr.cpp b/source/lmp/fix_dplr.cpp index 2a5826aa84..5ce85490fc 100644 --- a/source/lmp/fix_dplr.cpp +++ b/source/lmp/fix_dplr.cpp @@ -263,7 +263,7 @@ void FixDPLR::pre_force(int vflag) } // get lammps nlist NeighList * list = pair_deepmd->list; - InputNlist lmp_list (list->inum, list->ilist, list->numneigh, list->firstneigh); + deepmd::InputNlist lmp_list (list->inum, list->ilist, list->numneigh, list->firstneigh); // declear output vector tensor; // compute @@ -417,7 +417,7 @@ void FixDPLR::post_force(int vflag) } // lmp nlist NeighList * list = pair_deepmd->list; - InputNlist lmp_list (list->inum, list->ilist, list->numneigh, list->firstneigh); + deepmd::InputNlist lmp_list (list->inum, list->ilist, list->numneigh, list->firstneigh); // bonded pairs vector > valid_pairs; get_valid_pairs(valid_pairs); diff --git a/source/lmp/pair_deepmd.cpp b/source/lmp/pair_deepmd.cpp index 593e6a4246..8e2d691562 100644 --- a/source/lmp/pair_deepmd.cpp +++ b/source/lmp/pair_deepmd.cpp @@ -360,7 +360,7 @@ void PairDeepMD::compute(int eflag, int vflag) multi_models_no_mod_devi = (numb_models > 1 && (out_freq == 0 || update->ntimestep % out_freq != 0)); multi_models_mod_devi = (numb_models > 1 && (out_freq > 0 && update->ntimestep % out_freq == 0)); if (do_ghost) { - InputNlist lmp_list (list->inum, list->ilist, list->numneigh, list->firstneigh); + deepmd::InputNlist lmp_list (list->inum, list->ilist, list->numneigh, list->firstneigh); if (single_model || multi_models_no_mod_devi) { if ( ! (eflag_atom || vflag_atom) ) { #ifdef HIGH_PREC diff --git a/source/lmp/pair_deepmd.h.in b/source/lmp/pair_deepmd.h.in index a54f45c2f3..ee20de13c6 100644 --- a/source/lmp/pair_deepmd.h.in +++ b/source/lmp/pair_deepmd.h.in @@ -1,16 +1,3 @@ -/* -*- c++ -*- ---------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov - - Copyright (2003) Sandia Corporation. Under the terms of Contract - DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains - certain rights in this software. This software is distributed under - the GNU General Public License. - - See the README file in the top-level LAMMPS directory. -------------------------------------------------------------------------- */ - #ifdef PAIR_CLASS PairStyle(deepmd,PairDeepMD) diff --git a/source/lmp/pppm_dplr.cpp b/source/lmp/pppm_dplr.cpp index da95f58c9d..7b2fbe6e65 100644 --- a/source/lmp/pppm_dplr.cpp +++ b/source/lmp/pppm_dplr.cpp @@ -1,16 +1,3 @@ -/* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - https://lammps.sandia.gov/, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov - - Copyright (2003) Sandia Corporation. Under the terms of Contract - DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains - certain rights in this software. This software is distributed under - the GNU General Public License. - - See the README file in the top-level LAMMPS directory. -------------------------------------------------------------------------- */ - #include #include "pppm_dplr.h" #include "atom.h" diff --git a/source/lmp/pppm_dplr.h b/source/lmp/pppm_dplr.h index d9752583d5..4f22a9c621 100644 --- a/source/lmp/pppm_dplr.h +++ b/source/lmp/pppm_dplr.h @@ -1,16 +1,3 @@ -/* -*- c++ -*- ---------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov - - Copyright (2003) Sandia Corporation. Under the terms of Contract - DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains - certain rights in this software. This software is distributed under - the GNU General Public License. - - See the README file in the top-level LAMMPS directory. -------------------------------------------------------------------------- */ - #ifdef KSPACE_CLASS KSpaceStyle(pppm/dplr,PPPMDPLR) diff --git a/source/op/ewald_recp.cc b/source/op/ewald_recp.cc index 21ac163b5c..ae3aa84bc1 100644 --- a/source/op/ewald_recp.cc +++ b/source/op/ewald_recp.cc @@ -79,7 +79,7 @@ class EwaldRecpOp : public OpKernel { int coord_iter = kk * nloc * 3; int charge_iter = kk * nloc; // set region - Region region; + deepmd::Region region; init_region_cpu(region, &box(box_iter)); // set & normalize coord @@ -117,7 +117,7 @@ class EwaldRecpOp : public OpKernel { } } private: - EwaldParameters ep; + deepmd::EwaldParameters ep; }; #define REGISTER_CPU(T) \ diff --git a/source/op/gelu_multi_device.cc b/source/op/gelu_multi_device.cc index 4ea7afad17..5923ee5675 100644 --- a/source/op/gelu_multi_device.cc +++ b/source/op/gelu_multi_device.cc @@ -51,7 +51,7 @@ class GeluOp : public OpKernel { #endif // GOOGLE_CUDA } else if (device == "CPU") { - gelu_cpu( + deepmd::gelu_cpu( out, x, size); } @@ -94,7 +94,7 @@ class GeluGradOp : public OpKernel { #endif // GOOGLE_CUDA } else if (device == "CPU") { - gelu_grad_cpu( + deepmd::gelu_grad_cpu( out, x, dy, size); } @@ -135,7 +135,7 @@ class GeluGradGradOp : public OpKernel { #endif // GOOGLE_CUDA } else if (device == "CPU") { - gelu_grad_grad_cpu( + deepmd::gelu_grad_grad_cpu( out, x, dy, dy_2, size); } @@ -170,4 +170,4 @@ REGISTER_KERNEL_BUILDER( \ GeluGradGradOp); REGISTER_GPU(float); REGISTER_GPU(double); -#endif // GOOGLE_CUDA \ No newline at end of file +#endif // GOOGLE_CUDA diff --git a/source/op/map_aparam.cc b/source/op/map_aparam.cc index 1a08b678c3..3eba13990a 100644 --- a/source/op/map_aparam.cc +++ b/source/op/map_aparam.cc @@ -62,7 +62,7 @@ class MapAparamOp : public OpKernel { int output_iter = kk * nloc * nnei * numb_aparam; int aparam_iter = kk * nall * numb_aparam; int nlist_iter = kk * nloc * nnei; - map_aparam_cpu( + deepmd::map_aparam_cpu( &output(output_iter), &aparam(aparam_iter), &nlist(nlist_iter), diff --git a/source/op/pair_tab.cc b/source/op/pair_tab.cc index 31c2083cf7..fb3689b5a8 100644 --- a/source/op/pair_tab.cc +++ b/source/op/pair_tab.cc @@ -126,7 +126,7 @@ class PairTabOp : public OpKernel { // loop over samples #pragma omp parallel for for (int kk = 0; kk < nframes; ++kk){ - pair_tab_cpu( + deepmd::pair_tab_cpu( &energy(kk,0), &force(kk,0), &virial(kk,0), diff --git a/source/op/prod_env_mat_multi_device.cc b/source/op/prod_env_mat_multi_device.cc index e12fa73017..c0423db358 100644 --- a/source/op/prod_env_mat_multi_device.cc +++ b/source/op/prod_env_mat_multi_device.cc @@ -89,7 +89,7 @@ _prepare_coord_nlist_cpu( int const** type, std::vector & type_cpy, std::vector & idx_mapping, - InputNlist & inlist, + deepmd::InputNlist & inlist, std::vector & ilist, std::vector & numneigh, std::vector & firstneigh, @@ -271,7 +271,7 @@ class ProdEnvMatAOp : public OpKernel { array_longlong = uint64_temp.flat().data(); // update nbor list - InputNlist inlist; + deepmd::InputNlist inlist; inlist.inum = nloc; env_mat_nbor_update( inlist, gpu_inlist, max_nbor_size, nbor_list_dev, @@ -284,7 +284,7 @@ class ProdEnvMatAOp : public OpKernel { #endif //GOOGLE_CUDA } else if (device == "CPU") { - InputNlist inlist; + deepmd::InputNlist inlist; // some buffers, be freed after the evaluation of this frame std::vector idx_mapping; std::vector ilist(nloc), numneigh(nloc); @@ -325,7 +325,7 @@ class ProdEnvMatAOp : public OpKernel { std::string device; int * array_int = NULL; unsigned long long * array_longlong = NULL; - InputNlist gpu_inlist; + deepmd::InputNlist gpu_inlist; int * nbor_list_dev = NULL; }; @@ -481,7 +481,7 @@ class ProdEnvMatROp : public OpKernel { array_longlong = uint64_temp.flat().data(); // update nbor list - InputNlist inlist; + deepmd::InputNlist inlist; inlist.inum = nloc; env_mat_nbor_update( inlist, gpu_inlist, max_nbor_size, nbor_list_dev, @@ -494,7 +494,7 @@ class ProdEnvMatROp : public OpKernel { #endif //GOOGLE_CUDA } else if (device == "CPU") { - InputNlist inlist; + deepmd::InputNlist inlist; // some buffers, be freed after the evaluation of this frame std::vector idx_mapping; std::vector ilist(nloc), numneigh(nloc); @@ -533,7 +533,7 @@ class ProdEnvMatROp : public OpKernel { std::string device; int * array_int = NULL; unsigned long long * array_longlong = NULL; - InputNlist gpu_inlist; + deepmd::InputNlist gpu_inlist; int * nbor_list_dev = NULL; }; @@ -557,7 +557,7 @@ _norm_copy_coord_cpu( { std::vector tmp_coord(nall*3); std::copy(coord, coord+nall*3, tmp_coord.begin()); - Region region; + deepmd::Region region; init_region_cpu(region, box); normalize_coord_cpu(&tmp_coord[0], nall, region); int tt; @@ -599,7 +599,7 @@ _build_nlist_cpu( jlist[ii].resize(mem_nnei); firstneigh[ii] = &jlist[ii][0]; } - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); int ret = build_nlist_cpu( inlist, &max_nnei, coord, nloc, new_nall, mem_nnei, rcut_r); @@ -639,7 +639,7 @@ _prepare_coord_nlist_cpu( int const** type, std::vector & type_cpy, std::vector & idx_mapping, - InputNlist & inlist, + deepmd::InputNlist & inlist, std::vector & ilist, std::vector & numneigh, std::vector & firstneigh, diff --git a/source/op/prod_force_se_a.cc b/source/op/prod_force_se_a.cc index d286326c76..a07cd1d02d 100644 --- a/source/op/prod_force_se_a.cc +++ b/source/op/prod_force_se_a.cc @@ -90,13 +90,14 @@ class ProdForceSeAOp : public OpKernel { int in_iter = kk * nloc * ndescrpt * 3; int nlist_iter = kk * nloc * nnei; - prod_force_a_cpu(&force(force_iter), - &net_deriv(net_iter), - &in_deriv(in_iter), - &nlist(nlist_iter), - nloc, - nall, - nnei); + deepmd::prod_force_a_cpu( + &force(force_iter), + &net_deriv(net_iter), + &in_deriv(in_iter), + &nlist(nlist_iter), + nloc, + nall, + nnei); } } private: diff --git a/source/op/prod_force_se_a_grad.cc b/source/op/prod_force_se_a_grad.cc index aa8dd4e62b..59878bf7d9 100644 --- a/source/op/prod_force_se_a_grad.cc +++ b/source/op/prod_force_se_a_grad.cc @@ -87,12 +87,13 @@ class ProdForceSeAGradOp : public OpKernel int nlist_iter = kk * nloc * nnei; int grad_net_iter = kk * nloc * ndescrpt; - prod_force_grad_a_cpu(&grad_net(grad_net_iter), - &grad(grad_iter), - &in_deriv(in_iter), - &nlist(nlist_iter), - nloc, - nnei); + deepmd::prod_force_grad_a_cpu( + &grad_net(grad_net_iter), + &grad(grad_iter), + &in_deriv(in_iter), + &nlist(nlist_iter), + nloc, + nnei); } } private: diff --git a/source/op/prod_force_se_r.cc b/source/op/prod_force_se_r.cc index 8ce34a1489..1aa6d76760 100644 --- a/source/op/prod_force_se_r.cc +++ b/source/op/prod_force_se_r.cc @@ -81,13 +81,14 @@ class ProdForceSeROp : public OpKernel { int in_iter = kk * nloc * ndescrpt * 3; int nlist_iter = kk * nloc * nnei; - prod_force_r_cpu(&force(force_iter), - &net_deriv(net_iter), - &in_deriv(in_iter), - &nlist(nlist_iter), - nloc, - nall, - nnei); + deepmd::prod_force_r_cpu( + &force(force_iter), + &net_deriv(net_iter), + &in_deriv(in_iter), + &nlist(nlist_iter), + nloc, + nall, + nnei); } } }; diff --git a/source/op/prod_force_se_r_grad.cc b/source/op/prod_force_se_r_grad.cc index 039a452e94..be8ebec213 100644 --- a/source/op/prod_force_se_r_grad.cc +++ b/source/op/prod_force_se_r_grad.cc @@ -81,7 +81,7 @@ class ProdForceSeRGradOp : public OpKernel int nlist_iter = kk * nloc * nnei; int grad_net_iter = kk * nloc * ndescrpt; - prod_force_grad_r_cpu( + deepmd::prod_force_grad_r_cpu( &grad_net(grad_net_iter), &grad(grad_iter), &in_deriv(in_iter), diff --git a/source/op/prod_virial_se_a.cc b/source/op/prod_virial_se_a.cc index 454edb2fbd..80223f5e67 100644 --- a/source/op/prod_virial_se_a.cc +++ b/source/op/prod_virial_se_a.cc @@ -91,15 +91,16 @@ class ProdVirialSeAOp : public OpKernel { int virial_iter = kk * 9; int atom_virial_iter = kk * nall * 9; - prod_virial_a_cpu(&virial(virial_iter), - &atom_virial(atom_virial_iter), - &net_deriv(net_iter), - &in_deriv(in_iter), - &rij(rij_iter), - &nlist(nlist_iter), - nloc, - nall, - nnei); + deepmd::prod_virial_a_cpu( + &virial(virial_iter), + &atom_virial(atom_virial_iter), + &net_deriv(net_iter), + &in_deriv(in_iter), + &rij(rij_iter), + &nlist(nlist_iter), + nloc, + nall, + nnei); } } private: diff --git a/source/op/prod_virial_se_a_grad.cc b/source/op/prod_virial_se_a_grad.cc index d1366baf6f..2e6056c09c 100644 --- a/source/op/prod_virial_se_a_grad.cc +++ b/source/op/prod_virial_se_a_grad.cc @@ -95,13 +95,14 @@ class ProdVirialSeAGradOp : public OpKernel int nlist_iter = kk * nloc * nnei; int grad_net_iter = kk * nloc * ndescrpt; - prod_virial_grad_a_cpu(&grad_net(grad_net_iter), - &grad(grad_iter), - &in_deriv(in_iter), - &rij(rij_iter), - &nlist(nlist_iter), - nloc, - nnei); + deepmd::prod_virial_grad_a_cpu( + &grad_net(grad_net_iter), + &grad(grad_iter), + &in_deriv(in_iter), + &rij(rij_iter), + &nlist(nlist_iter), + nloc, + nnei); } } private: diff --git a/source/op/prod_virial_se_r.cc b/source/op/prod_virial_se_r.cc index 4b6285ff48..d063de03a3 100644 --- a/source/op/prod_virial_se_r.cc +++ b/source/op/prod_virial_se_r.cc @@ -84,7 +84,7 @@ class ProdVirialSeROp : public OpKernel { int virial_iter = kk * 9; int atom_virial_iter = kk * nall * 9; - prod_virial_r_cpu( + deepmd::prod_virial_r_cpu( &virial(virial_iter), &atom_virial(atom_virial_iter), &net_deriv(net_iter), diff --git a/source/op/prod_virial_se_r_grad.cc b/source/op/prod_virial_se_r_grad.cc index d900781709..57482f0f8a 100644 --- a/source/op/prod_virial_se_r_grad.cc +++ b/source/op/prod_virial_se_r_grad.cc @@ -89,7 +89,7 @@ class ProdVirialSeRGradOp : public OpKernel int nlist_iter = kk * nloc * nnei; int grad_net_iter = kk * nloc * ndescrpt; - prod_virial_grad_r_cpu( + deepmd::prod_virial_grad_r_cpu( &grad_net(grad_net_iter), &grad(grad_iter), &in_deriv(in_iter), diff --git a/source/op/soft_min.cc b/source/op/soft_min.cc index 4dcedbaea1..cae371fc70 100644 --- a/source/op/soft_min.cc +++ b/source/op/soft_min.cc @@ -91,7 +91,7 @@ class SoftMinSwitchOp : public OpKernel { // loop over samples #pragma omp parallel for for (int kk = 0; kk < nframes; ++kk){ - soft_min_switch_cpu( + deepmd::soft_min_switch_cpu( &sw_value(kk, 0), &sw_deriv(kk, 0), &rij(kk, 0), diff --git a/source/op/soft_min_force.cc b/source/op/soft_min_force.cc index 143d70d5ae..15e5e3b41d 100644 --- a/source/op/soft_min_force.cc +++ b/source/op/soft_min_force.cc @@ -68,7 +68,7 @@ class SoftMinForceOp : public OpKernel { // loop over samples #pragma omp parallel for for (int kk = 0; kk < nframes; ++kk){ - soft_min_switch_force_cpu( + deepmd::soft_min_switch_force_cpu( &force(kk,0), &du(kk,0), &sw_deriv(kk,0), diff --git a/source/op/soft_min_force_grad.cc b/source/op/soft_min_force_grad.cc index 59ccb32351..6a161e4f4d 100644 --- a/source/op/soft_min_force_grad.cc +++ b/source/op/soft_min_force_grad.cc @@ -80,7 +80,7 @@ class SoftMinForceGradOp : public OpKernel // loop over frames #pragma omp parallel for for (int kk = 0; kk < nframes; ++kk){ - soft_min_switch_force_grad_cpu( + deepmd::soft_min_switch_force_grad_cpu( &grad_net(kk,0), &grad(kk,0), &sw_deriv(kk,0), diff --git a/source/op/soft_min_virial.cc b/source/op/soft_min_virial.cc index 05e76d2741..3dcc2e6daa 100644 --- a/source/op/soft_min_virial.cc +++ b/source/op/soft_min_virial.cc @@ -82,7 +82,7 @@ class SoftMinVirialOp : public OpKernel { // loop over samples #pragma omp parallel for for (int kk = 0; kk < nframes; ++kk){ - soft_min_switch_virial_cpu( + deepmd::soft_min_switch_virial_cpu( &virial(kk,0), &atom_virial(kk,0), &du(kk,0), diff --git a/source/op/soft_min_virial_grad.cc b/source/op/soft_min_virial_grad.cc index a115c461e3..c5c5399195 100644 --- a/source/op/soft_min_virial_grad.cc +++ b/source/op/soft_min_virial_grad.cc @@ -87,7 +87,7 @@ class SoftMinVirialGradOp : public OpKernel // loop over frames #pragma omp parallel for for (int kk = 0; kk < nframes; ++kk){ - soft_min_switch_virial_grad_cpu( + deepmd::soft_min_switch_virial_grad_cpu( &grad_net(kk, 0), &grad(kk, 0), &sw_deriv(kk, 0), From cccefd7ca957e1617e89c105c8bfc21601c19be6 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 17 Mar 2021 08:56:52 +0800 Subject: [PATCH 282/562] fix bug in tests --- source/api_cc/tests/test_deepdipole.cc | 2 +- source/api_cc/tests/test_deeppolar.cc | 2 +- source/api_cc/tests/test_deeppot_a.cc | 8 ++++---- source/api_cc/tests/test_deeppot_model_devi.cc | 4 ++-- source/api_cc/tests/test_deeppot_r.cc | 8 ++++---- source/api_cc/tests/test_dipolecharge.cc | 6 +++--- source/api_cc/tests/test_ewald.cc | 4 ++-- source/api_cc/tests/test_utils.h | 4 ++-- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/source/api_cc/tests/test_deepdipole.cc b/source/api_cc/tests/test_deepdipole.cc index bfdcc1de17..fbc7388f7a 100644 --- a/source/api_cc/tests/test_deepdipole.cc +++ b/source/api_cc/tests/test_deepdipole.cc @@ -88,7 +88,7 @@ TEST_F(TestInferDeepDipole, cpu_lmp_nlist) std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); std::vector > nlist_data; - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, coord, atype, box, rc); int nall = coord_cpy.size() / 3; diff --git a/source/api_cc/tests/test_deeppolar.cc b/source/api_cc/tests/test_deeppolar.cc index 19e9b8af7c..a76e84179a 100644 --- a/source/api_cc/tests/test_deeppolar.cc +++ b/source/api_cc/tests/test_deeppolar.cc @@ -88,7 +88,7 @@ TEST_F(TestInferDeepPolar, cpu_lmp_nlist) std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); std::vector > nlist_data; - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); _build_nlist(nlist_data, coord_cpy, atype_cpy, mapping, coord, atype, box, rc); int nall = coord_cpy.size() / 3; diff --git a/source/api_cc/tests/test_deeppot_a.cc b/source/api_cc/tests/test_deeppot_a.cc index 77b343f91e..61336c4e33 100644 --- a/source/api_cc/tests/test_deeppot_a.cc +++ b/source/api_cc/tests/test_deeppot_a.cc @@ -183,7 +183,7 @@ TEST_F(TestInferDeepPotA, cpu_lmp_nlist) int nall = coord_cpy.size() / 3; std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); convert_nlist(inlist, nlist_data); double ener; @@ -234,7 +234,7 @@ TEST_F(TestInferDeepPotA, cpu_lmp_nlist_atomic) int nall = coord_cpy.size() / 3; std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); convert_nlist(inlist, nlist_data); double ener; @@ -307,7 +307,7 @@ TEST_F(TestInferDeepPotA, cpu_lmp_nlist_2rc) int nall = coord_cpy.size() / 3; std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); convert_nlist(inlist, nlist_data); double ener; @@ -373,7 +373,7 @@ TEST_F(TestInferDeepPotA, cpu_lmp_nlist_type_sel) int nall = coord_cpy.size() / 3; std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); convert_nlist(inlist, nlist_data); // dp compute diff --git a/source/api_cc/tests/test_deeppot_model_devi.cc b/source/api_cc/tests/test_deeppot_model_devi.cc index f70b66a9eb..678b30a2ea 100644 --- a/source/api_cc/tests/test_deeppot_model_devi.cc +++ b/source/api_cc/tests/test_deeppot_model_devi.cc @@ -93,7 +93,7 @@ TEST_F(TestInferDeepPotModeDevi, cpu_lmp_list) int nall = coord_cpy.size() / 3; std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); convert_nlist(inlist, nlist_data); int nmodel = 2; @@ -170,7 +170,7 @@ TEST_F(TestInferDeepPotModeDevi, cpu_lmp_list_atomic) int nall = coord_cpy.size() / 3; std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); convert_nlist(inlist, nlist_data); int nmodel = 2; diff --git a/source/api_cc/tests/test_deeppot_r.cc b/source/api_cc/tests/test_deeppot_r.cc index e9b1c45c85..2d6af9f6ae 100644 --- a/source/api_cc/tests/test_deeppot_r.cc +++ b/source/api_cc/tests/test_deeppot_r.cc @@ -183,7 +183,7 @@ TEST_F(TestInferDeepPotR, cpu_lmp_nlist) int nall = coord_cpy.size() / 3; std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); convert_nlist(inlist, nlist_data); double ener; @@ -234,7 +234,7 @@ TEST_F(TestInferDeepPotR, cpu_lmp_nlist_atomic) int nall = coord_cpy.size() / 3; std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); convert_nlist(inlist, nlist_data); double ener; @@ -307,7 +307,7 @@ TEST_F(TestInferDeepPotR, cpu_lmp_nlist_2rc) int nall = coord_cpy.size() / 3; std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); convert_nlist(inlist, nlist_data); double ener; @@ -373,7 +373,7 @@ TEST_F(TestInferDeepPotR, cpu_lmp_nlist_type_sel) int nall = coord_cpy.size() / 3; std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); convert_nlist(inlist, nlist_data); // dp compute diff --git a/source/api_cc/tests/test_dipolecharge.cc b/source/api_cc/tests/test_dipolecharge.cc index 9ce16b9442..b13c3c7d7a 100644 --- a/source/api_cc/tests/test_dipolecharge.cc +++ b/source/api_cc/tests/test_dipolecharge.cc @@ -116,7 +116,7 @@ TEST_F(TestDipoleCharge, cpu_lmp_nlist) int nghost = nall - nloc; std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]); convert_nlist(inlist, nlist_data); // evaluate dipole @@ -174,9 +174,9 @@ TEST_F(TestDipoleCharge, cpu_lmp_nlist) // compute the recp part of the ele interaction double eener; std::vector eforce, evirial; - Region region; + deepmd::Region region; init_region_cpu(region, &box[0]); - EwaldParameters eparam; + deepmd::EwaldParameters eparam; eparam.beta = 0.2; eparam.spacing = 4; ewald_recp(eener, eforce, evirial, coord, charge, region, eparam); diff --git a/source/api_cc/tests/test_ewald.cc b/source/api_cc/tests/test_ewald.cc index 73dcbe686e..e27b1087e3 100644 --- a/source/api_cc/tests/test_ewald.cc +++ b/source/api_cc/tests/test_ewald.cc @@ -35,7 +35,7 @@ TEST_F(TestInferEwald, cpu_numfv) class MyModel : public EnergyModelTest { const std::vector & charge; - EwaldParameters eparam; + deepmd::EwaldParameters eparam; public: MyModel( const std::vector & charge_ @@ -48,7 +48,7 @@ TEST_F(TestInferEwald, cpu_numfv) std::vector & virial, const std::vector & coord, const std::vector & box) { - Region region; + deepmd::Region region; init_region_cpu(region, &box[0]); ewald_recp(ener, force, virial, coord, charge, region, eparam); } diff --git a/source/api_cc/tests/test_utils.h b/source/api_cc/tests/test_utils.h index ed4b40b5ff..e6a496e374 100644 --- a/source/api_cc/tests/test_utils.h +++ b/source/api_cc/tests/test_utils.h @@ -90,13 +90,13 @@ class EnergyModelTest VALUETYPE ener; std::vector force, virial; compute(ener, force, virial, coord, box); - Region region; + deepmd::Region region; init_region_cpu(region, &box[0]); for(int ii = 0; ii < 9; ++ii){ std::vector box0(box), box1(box); box0[ii] += hh; box1[ii] -= hh; - Region region0, region1; + deepmd::Region region0, region1; init_region_cpu(region0, &box0[0]); init_region_cpu(region1, &box1[0]); std::vector coord0(coord), coord1(coord); From 122875771b81ea0663ac538507c27791f88b8efa Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 17 Mar 2021 09:52:38 +0800 Subject: [PATCH 283/562] fix bugs in multi_device ops --- source/op/gelu_multi_device.cc | 6 +++--- source/op/prod_env_mat_multi_device.cc | 10 +++++----- source/op/prod_force_multi_device.cc | 8 ++++---- source/op/prod_virial_multi_device.cc | 10 +++++----- source/op/tabulate_multi_device.cc | 8 ++++---- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/source/op/gelu_multi_device.cc b/source/op/gelu_multi_device.cc index 5923ee5675..ece0d07ab3 100644 --- a/source/op/gelu_multi_device.cc +++ b/source/op/gelu_multi_device.cc @@ -45,7 +45,7 @@ class GeluOp : public OpKernel { if (device == "GPU") { #if GOOGLE_CUDA - gelu_gpu_cuda( + deepmd::gelu_gpu_cuda( out, x, size); #endif // GOOGLE_CUDA @@ -88,7 +88,7 @@ class GeluGradOp : public OpKernel { if (device == "GPU") { #if GOOGLE_CUDA - gelu_grad_gpu_cuda( + deepmd::gelu_grad_gpu_cuda( out, x, dy, size); #endif // GOOGLE_CUDA @@ -129,7 +129,7 @@ class GeluGradGradOp : public OpKernel { if (device == "GPU") { #if GOOGLE_CUDA - gelu_grad_grad_gpu_cuda( + deepmd::gelu_grad_grad_gpu_cuda( out, x, dy, dy_2, size); #endif // GOOGLE_CUDA diff --git a/source/op/prod_env_mat_multi_device.cc b/source/op/prod_env_mat_multi_device.cc index c0423db358..10b3f837b0 100644 --- a/source/op/prod_env_mat_multi_device.cc +++ b/source/op/prod_env_mat_multi_device.cc @@ -273,12 +273,12 @@ class ProdEnvMatAOp : public OpKernel { // update nbor list deepmd::InputNlist inlist; inlist.inum = nloc; - env_mat_nbor_update( + deepmd::env_mat_nbor_update( inlist, gpu_inlist, max_nbor_size, nbor_list_dev, mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); OP_REQUIRES (context, (max_numneigh(inlist) <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_numneigh(inlist)) + " is larger than " + std::to_string(GPU_MAX_NBOR_SIZE) + ", which currently is not supported by deepmd-kit.")); // launch the gpu(nv) compute function - prod_env_mat_a_gpu_cuda( + deepmd::prod_env_mat_a_gpu_cuda( em, em_deriv, rij, nlist, coord, type, gpu_inlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, rcut_r, rcut_r_smth, sec_a); #endif //GOOGLE_CUDA @@ -300,7 +300,7 @@ class ProdEnvMatAOp : public OpKernel { frame_nall, mem_cpy, mem_nnei, max_nbor_size, box, mesh_tensor.flat().data(), nloc, nei_mode, rcut_r, max_cpy_trial, max_nnei_trial); // launch the cpu compute function - prod_env_mat_a_cpu( + deepmd::prod_env_mat_a_cpu( em, em_deriv, rij, nlist, coord, type, inlist, max_nbor_size, avg, std, nloc, frame_nall, rcut_r, rcut_r_smth, sec_a); // do nlist mapping if coords were copied @@ -483,12 +483,12 @@ class ProdEnvMatROp : public OpKernel { // update nbor list deepmd::InputNlist inlist; inlist.inum = nloc; - env_mat_nbor_update( + deepmd::env_mat_nbor_update( inlist, gpu_inlist, max_nbor_size, nbor_list_dev, mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); OP_REQUIRES (context, (max_numneigh(inlist) <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_numneigh(inlist)) + " is larger than " + std::to_string(GPU_MAX_NBOR_SIZE) + ", which currently is not supported by deepmd-kit.")); // launch the gpu(nv) compute function - prod_env_mat_r_gpu_cuda( + deepmd::prod_env_mat_r_gpu_cuda( em, em_deriv, rij, nlist, coord, type, gpu_inlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); #endif //GOOGLE_CUDA diff --git a/source/op/prod_force_multi_device.cc b/source/op/prod_force_multi_device.cc index 209a12639f..29af42379a 100644 --- a/source/op/prod_force_multi_device.cc +++ b/source/op/prod_force_multi_device.cc @@ -78,13 +78,13 @@ class ProdForceSeAOp : public OpKernel { if (device == "GPU") { #if GOOGLE_CUDA - prod_force_a_gpu_cuda( + deepmd::prod_force_a_gpu_cuda( force, net_deriv, in_deriv, nlist, nloc, nall, nnei); #endif // GOOGLE_CUDA } else if (device == "CPU") { - prod_force_a_cpu( + deepmd::prod_force_a_cpu( force, net_deriv, in_deriv, nlist, nloc, nall, nnei); } @@ -151,13 +151,13 @@ class ProdForceSeROp : public OpKernel { if (device == "GPU") { #if GOOGLE_CUDA - prod_force_r_gpu_cuda( + deepmd::prod_force_r_gpu_cuda( force, net_deriv, in_deriv, nlist, nloc, nall, nnei); #endif // GOOGLE_CUDA } else if (device == "CPU") { - prod_force_r_cpu( + deepmd::prod_force_r_cpu( force, net_deriv, in_deriv, nlist, nloc, nall, nnei); } diff --git a/source/op/prod_virial_multi_device.cc b/source/op/prod_virial_multi_device.cc index 9aab65443c..9e16437b44 100644 --- a/source/op/prod_virial_multi_device.cc +++ b/source/op/prod_virial_multi_device.cc @@ -86,13 +86,13 @@ class ProdVirialSeAOp : public OpKernel { if (device == "GPU") { #if GOOGLE_CUDA - prod_virial_a_gpu_cuda( + deepmd::prod_virial_a_gpu_cuda( virial, atom_virial, net_deriv, in_deriv, rij, nlist, nloc, nall, nnei); #endif // GOOGLE_CUDA } else if (device == "CPU") { - prod_virial_a_cpu( + deepmd::prod_virial_a_cpu( virial, atom_virial, net_deriv, in_deriv, rij, nlist, nloc, nall, nnei); } @@ -164,13 +164,13 @@ class ProdVirialSeROp : public OpKernel { if (device == "GPU") { #if GOOGLE_CUDA - prod_virial_r_gpu_cuda( + deepmd::prod_virial_r_gpu_cuda( virial, atom_virial, net_deriv, in_deriv, rij, nlist, nloc, nall, nnei); #endif // GOOGLE_CUDA } else if (device == "CPU") { - prod_virial_r_cpu( + deepmd::prod_virial_r_cpu( virial, atom_virial, net_deriv, in_deriv, rij, nlist, nloc, nall, nnei); } @@ -200,4 +200,4 @@ REGISTER_KERNEL_BUILDER( ProdVirialSeROp); REGISTER_GPU(float); REGISTER_GPU(double); -#endif // GOOGLE_CUDA \ No newline at end of file +#endif // GOOGLE_CUDA diff --git a/source/op/tabulate_multi_device.cc b/source/op/tabulate_multi_device.cc index b4e891518d..8d8f9e82d6 100644 --- a/source/op/tabulate_multi_device.cc +++ b/source/op/tabulate_multi_device.cc @@ -63,13 +63,13 @@ class TabulateFusionOp : public OpKernel { if (device == "GPU") { #if GOOGLE_CUDA - tabulate_fusion_gpu_cuda( + deepmd::tabulate_fusion_gpu_cuda( descriptor, table, table_info, em_x, em, nloc, nnei, last_layer_size); #endif // GOOGLE_CUDA } else if (device == "CPU") { - tabulate_fusion_cpu( + deepmd::tabulate_fusion_cpu( descriptor, table, table_info, em_x, em, nloc, nnei, last_layer_size); } @@ -125,13 +125,13 @@ class TabulateFusionGradOp : public OpKernel { if (device == "GPU") { #if GOOGLE_CUDA - tabulate_fusion_grad_gpu_cuda( + deepmd::tabulate_fusion_grad_gpu_cuda( dy_dem_x, dy_dem, table, table_info, em_x, em, dy, nloc, nnei, last_layer_size); #endif // GOOGLE_CUDA } else if (device == "CPU") { - tabulate_fusion_grad_cpu( + deepmd::tabulate_fusion_grad_cpu( dy_dem_x, dy_dem, table, table_info, em_x, em, dy, nloc, nnei, last_layer_size); } From 9ec178631ea4475f053da657c6fa7247a2c9c491 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 17 Mar 2021 10:19:00 +0800 Subject: [PATCH 284/562] namespace for tabulate and utilities --- source/api_cc/src/DeepPot.cc | 4 +- source/lib/include/ComputeDescriptor.h | 92 +++++++++++----------- source/lib/include/SimulationRegion_Impl.h | 12 +-- source/lib/include/tabulate.h | 5 ++ source/lib/include/utilities.h | 3 + source/lib/src/env_mat.cc | 8 +- source/lib/src/ewald.cc | 2 +- source/lib/src/fmt_nlist.cc | 4 +- source/lib/src/neighbor_list.cc | 8 +- source/lib/src/tabulate.cc | 12 +-- source/lib/src/utilities.cc | 4 +- source/lib/tests/test_tabulate.cc | 10 +-- source/op/descrpt.cc | 10 +-- source/op/prod_env_mat_multi_device.cc | 8 +- 14 files changed, 95 insertions(+), 87 deletions(-) diff --git a/source/api_cc/src/DeepPot.cc b/source/api_cc/src/DeepPot.cc index 9a3e8d7a10..b9412a505b 100644 --- a/source/api_cc/src/DeepPot.cc +++ b/source/api_cc/src/DeepPot.cc @@ -908,7 +908,7 @@ compute_std_f (std::vector & std, vdiff[0] = tmp_f[0] - tmp_avg[0]; vdiff[1] = tmp_f[1] - tmp_avg[1]; vdiff[2] = tmp_f[2] - tmp_avg[2]; - std[jj] += dot3(vdiff, vdiff); + std[jj] += deepmd::dot3(vdiff, vdiff); } } @@ -931,7 +931,7 @@ compute_relative_std_f (std::vector &std, vdiff[0] = tmp_avg[0]; vdiff[1] = tmp_avg[1]; vdiff[2] = tmp_avg[2]; - VALUETYPE f_norm = sqrt(dot3(vdiff, vdiff)); + VALUETYPE f_norm = sqrt(deepmd::dot3(vdiff, vdiff)); // relative std = std/(abs(f)+eps) std[ii] /= f_norm + eps; } diff --git a/source/lib/include/ComputeDescriptor.h b/source/lib/include/ComputeDescriptor.h index 7d4d6e0c3a..8bc246881a 100644 --- a/source/lib/include/ComputeDescriptor.h +++ b/source/lib/include/ComputeDescriptor.h @@ -110,11 +110,11 @@ compute_dRdT (double (* dRdT)[9], const double *xx = rot; const double *yy = rot+3; - double nr1 = sqrt(dot3(r1, r1)); + double nr1 = sqrt(deepmd::dot3(r1, r1)); double nr12 = nr1 * nr1; double nr13 = nr1 * nr12; double nr14 = nr12 * nr12; - double r1dr2 = dot3(r1, r2); + double r1dr2 = deepmd::dot3(r1, r2); // dRdT0 for (int ii = 0; ii < 3; ++ii){ @@ -137,7 +137,7 @@ compute_dRdT (double (* dRdT)[9], } double tmpy[3]; for (int dd = 0; dd < 3; ++dd) tmpy[dd] = r2[dd] - r1dr2 / nr12 * r1[dd]; - double ntmpy = sqrt(dot3(tmpy, tmpy)); + double ntmpy = sqrt(deepmd::dot3(tmpy, tmpy)); double ydRdy [3] = {0}; for (int ii = 0; ii < 3; ++ii){ for (int jj = 0; jj < 3; ++jj){ @@ -153,8 +153,8 @@ compute_dRdT (double (* dRdT)[9], // dRdT2 for (int ii = 0; ii < 3; ++ii){ double res[3]; - cprod(dRdT0 + ii*3, yy, dRdT2 + ii*3); - cprod(xx, dRdT1 + ii*3, res); + deepmd::cprod(dRdT0 + ii*3, yy, dRdT2 + ii*3); + deepmd::cprod(xx, dRdT1 + ii*3, res); for (int dd = 0; dd < 3; ++dd) dRdT2[ii*3+dd] += res[dd]; } } @@ -171,11 +171,11 @@ compute_dRdT_1 (double (* dRdT)[9], const double *xx = rot; const double *yy = rot+3; - double nr1 = sqrt(dot3(r1, r1)); + double nr1 = sqrt(deepmd::dot3(r1, r1)); double nr12 = nr1 * nr1; double nr13 = nr1 * nr12; double nr14 = nr12 * nr12; - double r1dr2 = dot3(r1, r2); + double r1dr2 = deepmd::dot3(r1, r2); // dRdT0 for (int ii = 0; ii < 3; ++ii){ @@ -198,7 +198,7 @@ compute_dRdT_1 (double (* dRdT)[9], } double tmpy[3]; for (int dd = 0; dd < 3; ++dd) tmpy[dd] = r2[dd] - r1dr2 / nr12 * r1[dd]; - double ntmpy = sqrt(dot3(tmpy, tmpy)); + double ntmpy = sqrt(deepmd::dot3(tmpy, tmpy)); double ydRdy [3] = {0}; for (int ii = 0; ii < 3; ++ii){ for (int jj = 0; jj < 3; ++jj){ @@ -214,8 +214,8 @@ compute_dRdT_1 (double (* dRdT)[9], // dRdT2 for (int ii = 0; ii < 3; ++ii){ double res[3]; - cprod(dRdT0 + ii*3, yy, dRdT2 + ii*3); - cprod(xx, dRdT1 + ii*3, res); + deepmd::cprod(dRdT0 + ii*3, yy, dRdT2 + ii*3); + deepmd::cprod(xx, dRdT1 + ii*3, res); for (int dd = 0; dd < 3; ++dd) dRdT2[ii*3+dd] += res[dd]; } } @@ -233,9 +233,9 @@ compute_dRdT_2 (double (* dRdT)[9], const double *xx = rot; const double *yy = rot+3; - double nr1 = sqrt(dot3(r1, r1)); + double nr1 = sqrt(deepmd::dot3(r1, r1)); double nr12 = nr1 * nr1; - double r1dr2 = dot3(r1, r2); + double r1dr2 = deepmd::dot3(r1, r2); // dRdT0 for (int ii = 0; ii < 3; ++ii){ @@ -256,7 +256,7 @@ compute_dRdT_2 (double (* dRdT)[9], } double tmpy[3]; for (int dd = 0; dd < 3; ++dd) tmpy[dd] = r2[dd] - r1dr2 / nr12 * r1[dd]; - double ntmpy = sqrt(dot3(tmpy, tmpy)); + double ntmpy = sqrt(deepmd::dot3(tmpy, tmpy)); double ydRdy [3] = {0}; for (int ii = 0; ii < 3; ++ii){ for (int jj = 0; jj < 3; ++jj){ @@ -272,8 +272,8 @@ compute_dRdT_2 (double (* dRdT)[9], // dRdT2 for (int ii = 0; ii < 3; ++ii){ double res[3]; - cprod(dRdT0 + ii*3, yy, dRdT2 + ii*3); - cprod(xx, dRdT1 + ii*3, res); + deepmd::cprod(dRdT0 + ii*3, yy, dRdT2 + ii*3); + deepmd::cprod(xx, dRdT1 + ii*3, res); for (int dd = 0; dd < 3; ++dd) dRdT2[ii*3+dd] += res[dd]; } } @@ -353,7 +353,7 @@ void compute_descriptor (std::vector & descrpt_a, // cout << jj << "\t jidx " << j_idx; // if (j_idx >= 0){ // cout << "\t type " << type[j_idx]; - // cout << "\t " << sqrt(dot3(&sel_a_diff[jj][0], &sel_a_diff[jj][0])); + // cout << "\t " << sqrt(deepmd::dot3(&sel_a_diff[jj][0], &sel_a_diff[jj][0])); // } // cout << endl; // } @@ -365,7 +365,7 @@ void compute_descriptor (std::vector & descrpt_a, // cout << jj << "\t jidx " << j_idx; // if (j_idx >= 0){ // cout << "\t type " << type[j_idx]; - // cout << "\t " << sqrt(dot3(&sel_r_diff[jj][0], &sel_r_diff[jj][0])); + // cout << "\t " << sqrt(deepmd::dot3(&sel_r_diff[jj][0], &sel_r_diff[jj][0])); // } // cout << endl; // } @@ -402,13 +402,13 @@ void compute_descriptor (std::vector & descrpt_a, xx[dd] = r1[dd]; yy[dd] = r2[dd]; } - double norm_xx = sqrt(dot3(xx, xx)); + double norm_xx = sqrt(deepmd::dot3(xx, xx)); for (unsigned dd = 0; dd < 3; ++dd) xx[dd] /= norm_xx; - double dxy = dot3(xx, yy); + double dxy = deepmd::dot3(xx, yy); for (unsigned dd = 0; dd < 3; ++dd) yy[dd] -= dxy * xx[dd]; - double norm_yy = sqrt(dot3(yy, yy)); + double norm_yy = sqrt(deepmd::dot3(yy, yy)); for (unsigned dd = 0; dd < 3; ++dd) yy[dd] /= norm_yy; - cprod(xx, yy, zz); + deepmd::cprod(xx, yy, zz); rot_mat.resize (9); for (int dd = 0; dd < 9; ++dd) rot_mat[dd] = rot[dd]; @@ -419,8 +419,8 @@ void compute_descriptor (std::vector & descrpt_a, for (int jj = sec_a[ii]; jj < sec_a[ii+1]; ++jj){ if (fmt_nlist_a[jj] < 0) break; double rdiff[3] ; - dotmv3(rdiff, rot, &sel_a_diff[jj][0]); - double rr2 = dot3(rdiff, rdiff); + deepmd::dotmv3(rdiff, rot, &sel_a_diff[jj][0]); + double rr2 = deepmd::dot3(rdiff, rdiff); double rr = sqrt(rr2); #ifdef DESCRPT_THETAPHI double cos_theta = rdiff[2] / rr; @@ -445,7 +445,7 @@ void compute_descriptor (std::vector & descrpt_a, for (int jj = sec_r[ii]; jj < sec_r[ii+1]; ++jj){ if (fmt_nlist_r[jj] < 0) break; const double *rdiff = &sel_r_diff[jj][0]; - double rr = sqrt (dot3(rdiff, rdiff)); + double rr = sqrt (deepmd::dot3(rdiff, rdiff)); descrpt_r[jj] = 1./rr; } } @@ -474,8 +474,8 @@ void compute_descriptor (std::vector & descrpt_a, double dtrdST[4][3]; double * rr = &sel_a_diff[nei_iter][0]; double tr[3] ; - dotmv3(tr, rot, rr); - double nr2 = dot3(tr, tr); + deepmd::dotmv3(tr, rot, rr); + double nr2 = deepmd::dot3(tr, tr); double nr = sqrt(nr2); double nr3 = nr * nr2; for (int dd = 0; dd < 3; ++dd){ @@ -601,7 +601,7 @@ void compute_descriptor (std::vector & descrpt_a, if (fmt_nlist_r[nei_iter] < 0) break; const double * rr = &sel_r_diff[nei_iter][0]; - double nr = sqrt(dot3(rr, rr)); + double nr = sqrt(deepmd::dot3(rr, rr)); double nr3 = nr * nr * nr; int idx = nei_iter * 12; @@ -699,13 +699,13 @@ void compute_descriptor (std::vector & descrpt_a, xx[dd] = r1[dd]; yy[dd] = r2[dd]; } - double norm_xx = sqrt(dot3(xx, xx)); + double norm_xx = sqrt(deepmd::dot3(xx, xx)); for (unsigned dd = 0; dd < 3; ++dd) xx[dd] /= norm_xx; - double dxy = dot3(xx, yy); + double dxy = deepmd::dot3(xx, yy); for (unsigned dd = 0; dd < 3; ++dd) yy[dd] -= dxy * xx[dd]; - double norm_yy = sqrt(dot3(yy, yy)); + double norm_yy = sqrt(deepmd::dot3(yy, yy)); for (unsigned dd = 0; dd < 3; ++dd) yy[dd] /= norm_yy; - cprod(xx, yy, zz); + deepmd::cprod(xx, yy, zz); rot_mat.resize (9); for (int dd = 0; dd < 9; ++dd) rot_mat[dd] = rot[dd]; @@ -716,8 +716,8 @@ void compute_descriptor (std::vector & descrpt_a, for (int jj = sec_a[ii]; jj < sec_a[ii+1]; ++jj){ if (fmt_nlist_a[jj] < 0) break; double rdiff[3] ; - dotmv3(rdiff, rot, &sel_a_diff[jj][0]); - double rr2 = dot3(rdiff, rdiff); + deepmd::dotmv3(rdiff, rot, &sel_a_diff[jj][0]); + double rr2 = deepmd::dot3(rdiff, rdiff); double rr = sqrt(rr2); #ifdef DESCRPT_THETAPHI double cos_theta = rdiff[2] / rr; @@ -742,8 +742,8 @@ void compute_descriptor (std::vector & descrpt_a, for (int jj = sec_r[ii]; jj < sec_r[ii+1]; ++jj){ if (fmt_nlist_r[jj] < 0) break; double rdiff[3] ; - dotmv3(rdiff, rot, &sel_r_diff[jj][0]); - double rr = sqrt (dot3(rdiff, rdiff)); + deepmd::dotmv3(rdiff, rot, &sel_r_diff[jj][0]); + double rr = sqrt (deepmd::dot3(rdiff, rdiff)); descrpt_r[jj] = 1./rr; } } @@ -784,7 +784,7 @@ void compute_descriptor_se_a_extf (std::vector & descrpt_a, ef[ii] = ef_[ii]; } } - assert( fabs(dot3(ef, ef) - 1.0) < 1e-12 ), "ef should be a normalized std::vector"; + assert( fabs(deepmd::dot3(ef, ef) - 1.0) < 1e-12 ), "ef should be a normalized std::vector"; // compute the diff of the neighbors std::vector > sel_a_diff (sec_a.back()); @@ -819,7 +819,7 @@ void compute_descriptor_se_a_extf (std::vector & descrpt_a, if (fmt_nlist_a[nei_iter] < 0) break; const double * rr = &sel_a_diff[nei_iter][0]; // check validity of ef - double nr2 = dot3(rr, rr); + double nr2 = deepmd::dot3(rr, rr); double inr = 1./sqrt(nr2); double nr = nr2 * inr; double inr2 = inr * inr; @@ -830,7 +830,7 @@ void compute_descriptor_se_a_extf (std::vector & descrpt_a, int idx_deriv = nei_iter * 4 * 3; // 4 components time 3 directions int idx_value = nei_iter * 4; // 4 components // projections - double rp = dot3(rr, ef); + double rp = deepmd::dot3(rr, ef); double rv[3]; rv[0] = rr[0] - rp * ef[0]; rv[1] = rr[1] - rp * ef[1]; @@ -893,7 +893,7 @@ void compute_descriptor_se_a_ef_para (std::vector & descrpt_a, ef[ii] = ef_[ii]; } } - assert( fabs(dot3(ef, ef) - 1.0) < 1e-12 ), "ef should be a normalized vector"; + assert( fabs(deepmd::dot3(ef, ef) - 1.0) < 1e-12 ), "ef should be a normalized vector"; // compute the diff of the neighbors std::vector > sel_a_diff (sec_a.back()); @@ -928,7 +928,7 @@ void compute_descriptor_se_a_ef_para (std::vector & descrpt_a, if (fmt_nlist_a[nei_iter] < 0) break; const double * rr = &sel_a_diff[nei_iter][0]; // check validity of ef - double nr2 = dot3(rr, rr); + double nr2 = deepmd::dot3(rr, rr); double inr = 1./sqrt(nr2); double nr = nr2 * inr; double inr2 = inr * inr; @@ -940,9 +940,9 @@ void compute_descriptor_se_a_ef_para (std::vector & descrpt_a, int idx_value = nei_iter * 4; // 4 components // projections double rp[3]; - rp[0] = dot3(rr, ef) * ef[0]; - rp[1] = dot3(rr, ef) * ef[1]; - rp[2] = dot3(rr, ef) * ef[2]; + rp[0] = deepmd::dot3(rr, ef) * ef[0]; + rp[1] = deepmd::dot3(rr, ef) * ef[1]; + rp[2] = deepmd::dot3(rr, ef) * ef[2]; // 4 value components descrpt_a[idx_value + 0] = 1 / nr; descrpt_a[idx_value + 1] = rp[0] / nr2; @@ -1001,7 +1001,7 @@ void compute_descriptor_se_a_ef_vert (std::vector & descrpt_a, ef[ii] = ef_[ii]; } } - assert( fabs(dot3(ef, ef) - 1.0) < 1e-12 ), "ef should be a normalized vector"; + assert( fabs(deepmd::dot3(ef, ef) - 1.0) < 1e-12 ), "ef should be a normalized vector"; // compute the diff of the neighbors std::vector > sel_a_diff (sec_a.back()); @@ -1036,7 +1036,7 @@ void compute_descriptor_se_a_ef_vert (std::vector & descrpt_a, if (fmt_nlist_a[nei_iter] < 0) break; const double * rr = &sel_a_diff[nei_iter][0]; // check validity of ef - double nr2 = dot3(rr, rr); + double nr2 = deepmd::dot3(rr, rr); double inr = 1./sqrt(nr2); double nr = nr2 * inr; double inr2 = inr * inr; @@ -1047,7 +1047,7 @@ void compute_descriptor_se_a_ef_vert (std::vector & descrpt_a, int idx_deriv = nei_iter * 4 * 3; // 4 components time 3 directions int idx_value = nei_iter * 4; // 4 components // projections - double rp = dot3(rr, ef); + double rp = deepmd::dot3(rr, ef); double rv[3]; rv[0] = rr[0] - rp * ef[0]; rv[1] = rr[1] - rp * ef[1]; diff --git a/source/lib/include/SimulationRegion_Impl.h b/source/lib/include/SimulationRegion_Impl.h index d19f1a5650..5b7b8248fd 100644 --- a/source/lib/include/SimulationRegion_Impl.h +++ b/source/lib/include/SimulationRegion_Impl.h @@ -417,12 +417,12 @@ SimulationRegion:: toFaceDistance (double * dd) const { double tmp[3]; - cprod(boxt+3, boxt+6, tmp); - dd[0] = volume * invsqrt(dot3(tmp,tmp)); - cprod(boxt+6, boxt+0, tmp); - dd[1] = volume * invsqrt(dot3(tmp,tmp)); - cprod(boxt+0, boxt+3, tmp); - dd[2] = volume * invsqrt(dot3(tmp,tmp)); + deepmd::cprod(boxt+3, boxt+6, tmp); + dd[0] = volume * deepmd::invsqrt(deepmd::dot3(tmp,tmp)); + deepmd::cprod(boxt+6, boxt+0, tmp); + dd[1] = volume * deepmd::invsqrt(deepmd::dot3(tmp,tmp)); + deepmd::cprod(boxt+0, boxt+3, tmp); + dd[2] = volume * deepmd::invsqrt(deepmd::dot3(tmp,tmp)); } // static int tmp_count = 0; diff --git a/source/lib/include/tabulate.h b/source/lib/include/tabulate.h index 77507ec8eb..b684be3c4c 100644 --- a/source/lib/include/tabulate.h +++ b/source/lib/include/tabulate.h @@ -1,5 +1,7 @@ #pragma once +namespace deepmd{ + template void tabulate_fusion_cpu( FPTYPE * out, @@ -49,3 +51,6 @@ void tabulate_fusion_grad_gpu_cuda( const int nnei, const int last_layer_size); #endif // GOOGLE_CUDA + +} + diff --git a/source/lib/include/utilities.h b/source/lib/include/utilities.h index 08a808ac11..e95ca3e684 100644 --- a/source/lib/include/utilities.h +++ b/source/lib/include/utilities.h @@ -5,6 +5,8 @@ #include #include +namespace deepmd{ + void cum_sum( std::vector & sec, const std::vector & n_sel); @@ -74,3 +76,4 @@ invsqrt (const float x) return 1./sqrtf (x); } +} diff --git a/source/lib/src/env_mat.cc b/source/lib/src/env_mat.cc index 52398a17a8..7b0d3e4140 100644 --- a/source/lib/src/env_mat.cc +++ b/source/lib/src/env_mat.cc @@ -50,7 +50,7 @@ void env_mat_a ( for (int nei_iter = sec_a[sec_iter]; nei_iter < sec_a[sec_iter+1]; ++nei_iter) { if (fmt_nlist_a[nei_iter] < 0) break; const double * rr = &sel_a_diff[nei_iter][0]; - double nr2 = dot3(rr, rr); + double nr2 = deepmd::dot3(rr, rr); double inr = 1./sqrt(nr2); double nr = nr2 * inr; double inr2 = inr * inr; @@ -129,7 +129,7 @@ env_mat_a_cpu ( for (int nei_iter = sec_a[sec_iter]; nei_iter < sec_a[sec_iter+1]; ++nei_iter) { if (fmt_nlist_a[nei_iter] < 0) break; const FPTYPE * rr = &rij_a[nei_iter * 3]; - FPTYPE nr2 = dot3(rr, rr); + FPTYPE nr2 = deepmd::dot3(rr, rr); FPTYPE inr = 1./sqrt(nr2); FPTYPE nr = nr2 * inr; FPTYPE inr2 = inr * inr; @@ -217,7 +217,7 @@ void env_mat_r ( for (int nei_iter = sec[sec_iter]; nei_iter < sec[sec_iter+1]; ++nei_iter) { if (fmt_nlist[nei_iter] < 0) break; const double * rr = &sel_diff[nei_iter][0]; - double nr2 = dot3(rr, rr); + double nr2 = deepmd::dot3(rr, rr); double inr = 1./sqrt(nr2); double nr = nr2 * inr; double inr2 = inr * inr; @@ -278,7 +278,7 @@ env_mat_r_cpu ( for (int nei_iter = sec[sec_iter]; nei_iter < sec[sec_iter+1]; ++nei_iter) { if (fmt_nlist[nei_iter] < 0) break; const FPTYPE * rr = &rij_a[nei_iter * 3]; - FPTYPE nr2 = dot3(rr, rr); + FPTYPE nr2 = deepmd::dot3(rr, rr); FPTYPE inr = 1./sqrt(nr2); FPTYPE nr = nr2 * inr; FPTYPE inr2 = inr * inr; diff --git a/source/lib/src/ewald.cc b/source/lib/src/ewald.cc index 5942f6fedc..486d2cbb73 100644 --- a/source/lib/src/ewald.cc +++ b/source/lib/src/ewald.cc @@ -72,7 +72,7 @@ cmpt_k(std::vector & KK, { KK.resize(3); for (int dd = 0; dd < 3; ++dd){ - VALUETYPE ll = sqrt(dot3(boxt+dd*3, boxt+dd*3)); + VALUETYPE ll = sqrt(deepmd::dot3(boxt+dd*3, boxt+dd*3)); KK[dd] = ll / param.spacing; // KK[dd] should be large enough if (KK[dd] * param.spacing < ll) KK[dd] += 1; diff --git a/source/lib/src/fmt_nlist.cc b/source/lib/src/fmt_nlist.cc index 2c577c2f05..add83dadcf 100644 --- a/source/lib/src/fmt_nlist.cc +++ b/source/lib/src/fmt_nlist.cc @@ -72,7 +72,7 @@ int format_nlist_i_fill_a ( else { for (int dd = 0; dd < 3; ++dd) diff[dd] = posi[j_idx*3+dd] - posi[i_idx*3+dd]; } - double rr = sqrt(dot3(diff, diff)); + double rr = sqrt(deepmd::dot3(diff, diff)); if (rr <= rcut) { sel_nei.push_back(NeighborInfo (type[j_idx], rr, j_idx)); } @@ -125,7 +125,7 @@ int format_nlist_i_cpu ( for (int dd = 0; dd < 3; ++dd) { diff[dd] = posi[j_idx * 3 + dd] - posi[i_idx * 3 + dd]; } - FPTYPE rr = sqrt(dot3(diff, diff)); + FPTYPE rr = sqrt(deepmd::dot3(diff, diff)); if (rr <= rcut) { sel_nei.push_back(NeighborInfo(type[j_idx], rr, j_idx)); } diff --git a/source/lib/src/neighbor_list.cc b/source/lib/src/neighbor_list.cc index e426d63906..e0ceae4a38 100644 --- a/source/lib/src/neighbor_list.cc +++ b/source/lib/src/neighbor_list.cc @@ -213,7 +213,7 @@ build_nlist_cell (std::vector > & nlist0, diff[dd0] += shift[dd1] * boxt[3*dd1+dd0]; } } - double r2 = dot3(diff, diff); + double r2 = deepmd::dot3(diff, diff); if (r2 < rc02) { if (i_idx < nloc) nlist0[i_idx].push_back (j_idx); if (j_idx < nloc) nlist0[j_idx].push_back (i_idx); @@ -254,7 +254,7 @@ build_nlist_cell (std::vector > & nlist0, diff[dd0] += shift[dd1] * boxt[3*dd1+dd0]; } } - double r2 = dot3(diff, diff); + double r2 = deepmd::dot3(diff, diff); if (r2 < rc02) { nlist0[i_idx].push_back (j_idx); } @@ -612,7 +612,7 @@ build_nlist (std::vector > & nlist0, diff[1] = posi3[jj*3+1] - posi3[ii*3+1]; diff[2] = posi3[jj*3+2] - posi3[ii*3+2]; } - double r2 = dot3(diff, diff); + double r2 = deepmd::dot3(diff, diff); if (r2 < rc02) { nlist0[ii].push_back (jj); nlist0[jj].push_back (ii); @@ -800,7 +800,7 @@ build_nlist_cpu( for(int dd = 0; dd < 3; ++dd){ diff[dd] = c_cpy[ii*3+dd] - c_cpy[jj*3+dd]; } - FPTYPE diff2 = dot3(diff, diff); + FPTYPE diff2 = deepmd::dot3(diff, diff); if(diff2 < rcut2){ jlist.push_back(jj); } diff --git a/source/lib/src/tabulate.cc b/source/lib/src/tabulate.cc index 98b561a348..b1049226d3 100644 --- a/source/lib/src/tabulate.cc +++ b/source/lib/src/tabulate.cc @@ -51,7 +51,7 @@ inline FPTYPE dot( } template -void tabulate_fusion_cpu( +void deepmd::tabulate_fusion_cpu( FPTYPE * out, const FPTYPE * table, const FPTYPE * table_info, @@ -112,7 +112,7 @@ void tabulate_fusion_cpu( } template -void tabulate_fusion_grad_cpu( +void deepmd::tabulate_fusion_grad_cpu( FPTYPE * dy_dem_x, FPTYPE * dy_dem, const FPTYPE * table, @@ -186,7 +186,7 @@ void tabulate_fusion_grad_cpu( } } -template void tabulate_fusion_cpu(float * out, const float * table, const float * table_info, const float * em_x, const float * em, const int nloc, const int nnei, const int last_layer_size); -template void tabulate_fusion_cpu(double * out, const double * table, const double * table_info, const double * em_x, const double * em, const int nloc, const int nnei, const int last_layer_size); -template void tabulate_fusion_grad_cpu (float * dy_dem_x, float * dy_dem, const float * table, const float * table_info, const float * em_x, const float * em, const float * dy, const int nloc, const int nnei, const int last_layer_size); -template void tabulate_fusion_grad_cpu (double * dy_dem_x, double * dy_dem, const double * table, const double * table_info, const double * em_x, const double * em, const double * dy, const int nloc, const int nnei, const int last_layer_size); +template void deepmd::tabulate_fusion_cpu(float * out, const float * table, const float * table_info, const float * em_x, const float * em, const int nloc, const int nnei, const int last_layer_size); +template void deepmd::tabulate_fusion_cpu(double * out, const double * table, const double * table_info, const double * em_x, const double * em, const int nloc, const int nnei, const int last_layer_size); +template void deepmd::tabulate_fusion_grad_cpu (float * dy_dem_x, float * dy_dem, const float * table, const float * table_info, const float * em_x, const float * em, const float * dy, const int nloc, const int nnei, const int last_layer_size); +template void deepmd::tabulate_fusion_grad_cpu (double * dy_dem_x, double * dy_dem, const double * table, const double * table_info, const double * em_x, const double * em, const double * dy, const int nloc, const int nnei, const int last_layer_size); diff --git a/source/lib/src/utilities.cc b/source/lib/src/utilities.cc index 2176715938..df7bac98f5 100644 --- a/source/lib/src/utilities.cc +++ b/source/lib/src/utilities.cc @@ -1,7 +1,7 @@ #include "utilities.h" // functions used in custom ops -void cum_sum( +void deepmd::cum_sum( std::vector & sec, const std::vector & n_sel) { @@ -10,4 +10,4 @@ void cum_sum( for (int ii = 1; ii < sec.size(); ++ii) { sec[ii] = sec[ii-1] + n_sel[ii-1]; } -} \ No newline at end of file +} diff --git a/source/lib/tests/test_tabulate.cc b/source/lib/tests/test_tabulate.cc index a17f2474b7..f92629efb4 100644 --- a/source/lib/tests/test_tabulate.cc +++ b/source/lib/tests/test_tabulate.cc @@ -147,7 +147,7 @@ class TestTabulate : public ::testing::Test TEST_F(TestTabulate, tabulate_fusion_cpu) { std::vector xyz_scatter(nloc * nnei * last_layer_size); - tabulate_fusion_cpu(&xyz_scatter[0], &table[0], &info[0], &em_x[0], &em[0], nloc, nnei, last_layer_size); + deepmd::tabulate_fusion_cpu(&xyz_scatter[0], &table[0], &info[0], &em_x[0], &em[0], nloc, nnei, last_layer_size); EXPECT_EQ(xyz_scatter.size(), nloc * nnei * last_layer_size); EXPECT_EQ(xyz_scatter.size(), expected_xyz_scatter.size()); for (int jj = 0; jj < xyz_scatter.size(); ++jj){ @@ -160,7 +160,7 @@ TEST_F(TestTabulate, tabulate_fusion_grad_cpu) std::vector dy_dem_x(em_x.size()); std::vector dy_dem(em.size()); std::vector dy(nloc * nnei * last_layer_size, 1.0); - tabulate_fusion_grad_cpu(&dy_dem_x[0], &dy_dem[0], &table[0], &info[0], &em_x[0], &em[0], &dy[0], nloc, nnei, last_layer_size); + deepmd::tabulate_fusion_grad_cpu(&dy_dem_x[0], &dy_dem[0], &table[0], &info[0], &em_x[0], &em[0], &dy[0], nloc, nnei, last_layer_size); EXPECT_EQ(dy_dem_x.size(), nloc * nnei); EXPECT_EQ(dy_dem.size(), nloc * nnei * 4); EXPECT_EQ(dy_dem_x.size(), expected_dy_dem_x.size()); @@ -183,7 +183,7 @@ TEST_F(TestTabulate, tabulate_fusion_gpu_cuda) malloc_device_memory_sync(table_dev, table); malloc_device_memory_sync(em_x_dev, em_x); malloc_device_memory_sync(em_dev, em); - tabulate_fusion_gpu_cuda(xyz_scatter_dev, table_dev, &info[0], em_x_dev, em_dev, nloc, nnei, last_layer_size); + deepmd::tabulate_fusion_gpu_cuda(xyz_scatter_dev, table_dev, &info[0], em_x_dev, em_dev, nloc, nnei, last_layer_size); memcpy_device_to_host(xyz_scatter_dev, xyz_scatter); delete_device_memory(xyz_scatter_dev); delete_device_memory(table_dev); @@ -210,7 +210,7 @@ TEST_F(TestTabulate, tabulate_fusion_grad_gpu_cuda) malloc_device_memory_sync(em_x_dev, em_x); malloc_device_memory_sync(em_dev, em); malloc_device_memory_sync(dy_dev, dy); - tabulate_fusion_grad_gpu_cuda(dy_dem_x_dev, dy_dem_dev, table_dev, &info[0], em_x_dev, em_dev, dy_dev, nloc, nnei, last_layer_size); + deepmd::tabulate_fusion_grad_gpu_cuda(dy_dem_x_dev, dy_dem_dev, table_dev, &info[0], em_x_dev, em_dev, dy_dev, nloc, nnei, last_layer_size); memcpy_device_to_host(dy_dem_x_dev, dy_dem_x); memcpy_device_to_host(dy_dem_dev, dy_dem); delete_device_memory(dy_dem_x_dev); @@ -231,4 +231,4 @@ TEST_F(TestTabulate, tabulate_fusion_grad_gpu_cuda) EXPECT_LT(fabs(dy_dem[jj] - expected_dy_dem[jj]) , 1e-5); } } -#endif // GOOGLE_CUDA \ No newline at end of file +#endif // GOOGLE_CUDA diff --git a/source/op/descrpt.cc b/source/op/descrpt.cc index 1cbfb96574..48fc4f3943 100644 --- a/source/op/descrpt.cc +++ b/source/op/descrpt.cc @@ -495,7 +495,7 @@ class DescrptOp : public OpKernel { } } sort_info.push_back (std::pair - (dot3(diff, diff), list_idx) ); + (deepmd::dot3(diff, diff), list_idx) ); } } sort (sort_info.begin(), sort_info.end()); @@ -527,7 +527,7 @@ class DescrptOp : public OpKernel { } } sort_info.push_back (std::pair - (dot3(diff, diff), list_idx) ); + (deepmd::dot3(diff, diff), list_idx) ); } } sort (sort_info.begin(), sort_info.end()); @@ -580,9 +580,9 @@ class DescrptOp : public OpKernel { } } } - compute_t rij = dot3(diff[0], diff[1]); - compute_t rii = dot3(diff[0], diff[0]); - compute_t rjj = dot3(diff[1], diff[1]); + compute_t rij = deepmd::dot3(diff[0], diff[1]); + compute_t rii = deepmd::dot3(diff[0], diff[0]); + compute_t rjj = deepmd::dot3(diff[1], diff[1]); if ( fabs (rij / sqrt(rii * rjj) + 1) < 1e-4 ) { return false; } diff --git a/source/op/prod_env_mat_multi_device.cc b/source/op/prod_env_mat_multi_device.cc index 10b3f837b0..7a26ce2b41 100644 --- a/source/op/prod_env_mat_multi_device.cc +++ b/source/op/prod_env_mat_multi_device.cc @@ -120,8 +120,8 @@ class ProdEnvMatAOp : public OpKernel { OP_REQUIRES_OK(context, context->GetAttr("sel_r", &sel_r)); // OP_REQUIRES_OK(context, context->GetAttr("nloc", &nloc_f)); // OP_REQUIRES_OK(context, context->GetAttr("nall", &nall_f)); - cum_sum (sec_a, sel_a); - cum_sum (sec_r, sel_r); + deepmd::cum_sum (sec_a, sel_a); + deepmd::cum_sum (sec_r, sel_r); ndescrpt_a = sec_a.back() * 4; ndescrpt_r = sec_r.back() * 1; ndescrpt = ndescrpt_a + ndescrpt_r; @@ -336,9 +336,9 @@ class ProdEnvMatROp : public OpKernel { OP_REQUIRES_OK(context, context->GetAttr("rcut", &rcut)); OP_REQUIRES_OK(context, context->GetAttr("rcut_smth", &rcut_smth)); OP_REQUIRES_OK(context, context->GetAttr("sel", &sel)); - cum_sum (sec, sel); + deepmd::cum_sum (sec, sel); sel_null.resize(3, 0); - cum_sum (sec_null, sel_null); + deepmd::cum_sum (sec_null, sel_null); ndescrpt = sec.back() * 1; nnei = sec.back(); max_nbor_size = 1024; From f38678f320a76e463893e898cb18c9fea6030b3f Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 17 Mar 2021 10:27:36 +0800 Subject: [PATCH 285/562] fix bug : namespace in cuda compiling --- source/lib/src/cuda/prod_env_mat.cu | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/lib/src/cuda/prod_env_mat.cu b/source/lib/src/cuda/prod_env_mat.cu index d26e089efa..febdc093f4 100644 --- a/source/lib/src/cuda/prod_env_mat.cu +++ b/source/lib/src/cuda/prod_env_mat.cu @@ -4,6 +4,8 @@ #include #include +using namespace deepmd; + // common part of prod_env_mat template < typename Key, From ebdb4043fbd0ee7d716921828ffd0dc74f7b747c Mon Sep 17 00:00:00 2001 From: denghuilu Date: Fri, 19 Mar 2021 04:26:31 +0800 Subject: [PATCH 286/562] fix bugs of single precision training and transfer --- deepmd/entrypoints/transfer.py | 30 ++++++++++++------------------ deepmd/loss/ener.py | 2 +- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/deepmd/entrypoints/transfer.py b/deepmd/entrypoints/transfer.py index 3e1aa1b5f2..0af45a4244 100644 --- a/deepmd/entrypoints/transfer.py +++ b/deepmd/entrypoints/transfer.py @@ -72,7 +72,7 @@ def transfer(*, old_model: str, raw_model: str, output: str, **kwargs): new_graph_def = transform_graph(raw_graph, old_graph) with tf.gfile.GFile(output, mode="wb") as f: f.write(new_graph_def.SerializeToString()) - log.info("the output model is saved in {output:s}") + log.info("the output model is saved in " + output) def load_graph(graph_name: str) -> tf.Graph: @@ -136,22 +136,20 @@ def transform_graph(raw_graph: tf.Graph, old_graph: tf.Graph) -> tf.Graph: if raw_graph_dtype == np.float16: if old_graph_dtype == np.float64 or old_graph_dtype == np.float32: if (len(tensor_shape) != 1) or (tensor_shape[0] != 1): - tensor = np.frombuffer(old_node.tensor_content, dtype=np.float16) - cp_attr.from_array(tensor, tf.float16, shape=tensor_shape) + tensor = np.frombuffer(old_node.tensor_content).astype(raw_graph_dtype) + cp_attr.from_array(tensor, tf.float16, shape = tensor_shape) else: - tensor = load_tensor(old_node, old_graph_dtype, np.float16) + tensor = load_tensor(old_node, old_graph_dtype, raw_graph_dtype) cp_attr.from_array(tensor, tf.float16, [1]) - elif old_graph_dtype == np.float16: - tensor = convert_matrix(np.array(old_node.half_val), tensor_shape) - cp_attr.from_array(tensor, tf.float16) + elif old_graph_dtype[1] == "float16": + tensor = convertMatrix(np.array(old_node.half_val), tensor_shape) + cp_attr.from_array(tensor, raw_graph_dtype) elif raw_graph_dtype == np.float64 or raw_graph_dtype == np.float32: if old_graph_dtype == np.float64 or old_graph_dtype == np.float32: if (len(tensor_shape) != 1) or (tensor_shape[0] != 1): - tensor = np.frombuffer( - old_node.tensor_content, dtype=raw_graph_dtype - ) + tensor = np.frombuffer(old_node.tensor_content).astype(raw_graph_dtype) cp_attr.from_str(tensor) else: tensor = load_tensor(old_node, old_graph_dtype, raw_graph_dtype) @@ -159,14 +157,10 @@ def transform_graph(raw_graph: tf.Graph, old_graph: tf.Graph) -> tf.Graph: elif old_graph_dtype == np.float16: if (len(tensor_shape) != 1) or (tensor_shape[0] != 1): - tensor = convert_matrix( - np.array(old_node.half_val), tensor_shape, dtype=raw_graph_dtype - ) + tensor = convertMatrix(np.array(old_node.half_val), tensor_shape).astype(raw_graph_dtype) cp_attr.from_str(tensor) else: - tensor = convert_matrix( - np.array(old_node.half_val), tensor_shape, dtype=raw_graph_dtype - ) + tensor = convertMatrix(np.array(old_node.half_val), tensor_shape).astype(raw_graph_dtype) cp_attr.from_array(tensor, raw_graph_dtype) return raw_graph_def @@ -191,9 +185,9 @@ def from_str(self, tensor: np.ndarray): def load_tensor(node: tf.Tensor, dtype_old: type, dtype_new: type) -> np.ndarray: if dtype_old == np.float64: - tensor = np.array(node.double_val, dtype=dtype_new) + tensor = np.array(node.double_val).astype(dtype_new) elif dtype_old == np.float32: - tensor = np.array(node.float_val, dtype=dtype_new) + tensor = np.array(node.float_val).astype(dtype_new) return tensor diff --git a/deepmd/loss/ener.py b/deepmd/loss/ener.py index 08e631bc0b..89d15b3add 100644 --- a/deepmd/loss/ener.py +++ b/deepmd/loss/ener.py @@ -119,7 +119,7 @@ def build (self, # only used when tensorboard was set as true self.l2_loss_summary = tf.summary.scalar('l2_loss', tf.sqrt(l2_loss)) - self.l2_loss_ener_summary = tf.summary.scalar('l2_ener_loss', tf.sqrt(l2_ener_loss) / global_cvt_2_tf_float(natoms[0])) + self.l2_loss_ener_summary = tf.summary.scalar('l2_ener_loss', global_cvt_2_tf_float(tf.sqrt(l2_ener_loss)) / global_cvt_2_tf_float(natoms[0])) self.l2_loss_force_summary = tf.summary.scalar('l2_force_loss', tf.sqrt(l2_force_loss)) self.l2_loss_virial_summary = tf.summary.scalar('l2_virial_loss', tf.sqrt(l2_virial_loss) / global_cvt_2_tf_float(natoms[0])) From 3dc97689feca7a3e74c8acefe5c16a38eac66daf Mon Sep 17 00:00:00 2001 From: denghuilu Date: Fri, 19 Mar 2021 07:50:23 +0800 Subject: [PATCH 287/562] fix bug of nbor sorting --- source/lib/src/cuda/prod_env_mat.cu | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/lib/src/cuda/prod_env_mat.cu b/source/lib/src/cuda/prod_env_mat.cu index d26e089efa..1e38d45f4b 100644 --- a/source/lib/src/cuda/prod_env_mat.cu +++ b/source/lib/src/cuda/prod_env_mat.cu @@ -114,7 +114,7 @@ __global__ void format_nlist_fill_a( } FPTYPE rr = sqrt(dev_dot(diff, diff)); if (rr <= rcut) { - key_in[idy] = type[j_idx] * 1E15+ (int_64)(rr * 1.0E13) / 100000 * 100000 + j_idx; + key_in[idy] = type[j_idx] * 1E15+ (int_64)(rr * 1.0E13) / 10000000 * 10000000 + j_idx; } } @@ -144,7 +144,7 @@ __global__ void format_nlist_fill_b( for (unsigned int kk = 0; key_out[kk] != key_out[max_nbor_size - 1]; kk++) { const int & nei_type = key_out[kk] / 1E15; if (nei_iter[nei_type] < sec[nei_type + 1]) { - row_nlist[nei_iter[nei_type]++] = key_out[kk] % 100000; + row_nlist[nei_iter[nei_type]++] = key_out[kk] % 10000000; } } } From 53de560b81cd6ed81d2fdfc41f2ec4a799b94c87 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Fri, 19 Mar 2021 16:47:26 +0800 Subject: [PATCH 288/562] fix bug of gpu namespace --- source/lib/include/gpu_cuda.h | 26 ++++++++++++++++++++++++++ source/lib/src/cuda/gelu.cu | 3 ++- source/lib/src/cuda/prod_env_mat.cu | 12 ++++++------ source/lib/src/cuda/prod_force.cu | 19 ++----------------- source/lib/src/cuda/prod_virial.cu | 19 ++----------------- source/lib/src/cuda/tabulate.cu | 4 ++-- source/lib/src/neighbor_list.cc | 4 ++-- source/lib/src/prod_env_mat.cc | 2 +- source/lib/tests/test_env_mat_a.cc | 8 ++++---- source/lib/tests/test_env_mat_r.cc | 8 ++++---- source/lib/tests/test_gelu.cc | 6 +++--- source/lib/tests/test_prod_force_a.cc | 2 +- source/lib/tests/test_prod_force_r.cc | 2 +- source/lib/tests/test_prod_virial_a.cc | 2 +- source/lib/tests/test_prod_virial_r.cc | 2 +- 15 files changed, 58 insertions(+), 61 deletions(-) diff --git a/source/lib/include/gpu_cuda.h b/source/lib/include/gpu_cuda.h index 845e0b9d9f..6ccbbb9356 100644 --- a/source/lib/include/gpu_cuda.h +++ b/source/lib/include/gpu_cuda.h @@ -13,6 +13,23 @@ inline void cudaAssert(cudaError_t code, const char *file, int line, bool abort= } } +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600 +static __inline__ __device__ double atomicAdd( + double* address, + double val) +{ + unsigned long long int* address_as_ull = (unsigned long long int*)address; + unsigned long long int old = *address_as_ull, assumed; + do { + assumed = old; + old = atomicCAS(address_as_ull, assumed, + __double_as_longlong(val + __longlong_as_double(assumed))); + // Note: uses integer comparison to avoid hang in case of NaN (since NaN != NaN) } while (assumed != old); + } while (assumed != old); + return __longlong_as_double(old); +} +#endif + template void memcpy_host_to_device( FPTYPE * device, @@ -70,4 +87,13 @@ void delete_device_memory( if (device != NULL) { cudaErrcheck(cudaFree(device)); } +} + +template +void memset_device_memory( + FPTYPE * device, + const FPTYPE var, + const int size) +{ + cudaErrcheck(cudaMemset(device, var, sizeof(FPTYPE) * size)); } \ No newline at end of file diff --git a/source/lib/src/cuda/gelu.cu b/source/lib/src/cuda/gelu.cu index cd4cfa0541..2b5b3074bb 100644 --- a/source/lib/src/cuda/gelu.cu +++ b/source/lib/src/cuda/gelu.cu @@ -1,6 +1,5 @@ #include "gelu.h" #include "device.h" -#include "gpu_cuda.h" template __global__ void gelu( @@ -49,6 +48,7 @@ __global__ void gelu_grad_grad( out[idx] = dy[idx] * dy_2[idx] * (0.134145 * SQRT_2_PI * xx[idx] * xx[idx] * (1 - var1 * var1) - SQRT_2_PI * xx[idx] * var2 * (0.134145 * xx[idx] * xx[idx] + 1) * var1 + var2); } +namespace deepmd { template void gelu_gpu_cuda( FPTYPE * out, @@ -94,3 +94,4 @@ template void gelu_grad_gpu_cuda(float * out, const float * x, const floa template void gelu_grad_gpu_cuda(double * out, const double * x, const double * dy, const int size); template void gelu_grad_grad_gpu_cuda(float * out, const float * x, const float * dy, const float * dy_2, const int size); template void gelu_grad_grad_gpu_cuda(double * out, const double * x, const double * dy, const double * dy_2, const int size); +} \ No newline at end of file diff --git a/source/lib/src/cuda/prod_env_mat.cu b/source/lib/src/cuda/prod_env_mat.cu index febdc093f4..00a7401f85 100644 --- a/source/lib/src/cuda/prod_env_mat.cu +++ b/source/lib/src/cuda/prod_env_mat.cu @@ -4,8 +4,6 @@ #include #include -using namespace deepmd; - // common part of prod_env_mat template < typename Key, @@ -156,7 +154,7 @@ void format_nbor_list_1024 ( int_64 * key, const FPTYPE* coord, const int* type, - const InputNlist & gpu_inlist, + const deepmd::InputNlist & gpu_inlist, const int& nloc, const float& rcut, int * i_idx) @@ -182,7 +180,7 @@ void format_nbor_list_2048 ( int_64 * key, const FPTYPE* coord, const int* type, - const InputNlist & gpu_inlist, + const deepmd::InputNlist & gpu_inlist, const int& nloc, const float& rcut, int * i_idx) @@ -208,7 +206,7 @@ void format_nbor_list_4096 ( int_64 * key, const FPTYPE* coord, const int* type, - const InputNlist & gpu_inlist, + const deepmd::InputNlist & gpu_inlist, const int& nloc, const float& rcut, int * i_idx) @@ -234,7 +232,7 @@ void format_nbor_list( int * nlist, const FPTYPE * coord, const int * type, - const InputNlist & gpu_inlist, + const deepmd::InputNlist & gpu_inlist, int * array_int, int_64 * array_longlong, const int max_nbor_size, @@ -433,6 +431,7 @@ __global__ void compute_env_mat_r( } } +namespace deepmd { template void prod_env_mat_a_gpu_cuda( FPTYPE * em, @@ -505,3 +504,4 @@ template void prod_env_mat_a_gpu_cuda(float * em, float * em_deriv, float template void prod_env_mat_a_gpu_cuda(double * em, double * em_deriv, double * rij, int * nlist, const double * coord, const int * type, const InputNlist & gpu_inlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const double * avg, const double * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); template void prod_env_mat_r_gpu_cuda(float * em, float * em_deriv, float * rij, int * nlist, const float * coord, const int * type, const InputNlist & gpu_inlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const float * avg, const float * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); template void prod_env_mat_r_gpu_cuda(double * em, double * em_deriv, double * rij, int * nlist, const double * coord, const int * type, const InputNlist & gpu_inlist, int * array_int, unsigned long long * array_longlong, const int max_nbor_size, const double * avg, const double * std, const int nloc, const int nall, const float rcut, const float rcut_smth, const std::vector sec); +} diff --git a/source/lib/src/cuda/prod_force.cu b/source/lib/src/cuda/prod_force.cu index d440d3b153..97321e74e8 100644 --- a/source/lib/src/cuda/prod_force.cu +++ b/source/lib/src/cuda/prod_force.cu @@ -2,23 +2,6 @@ #include "gpu_cuda.h" #include "prod_force.h" -#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600 -static __inline__ __device__ double atomicAdd( - double* address, - double val) -{ - unsigned long long int* address_as_ull = (unsigned long long int*)address; - unsigned long long int old = *address_as_ull, assumed; - do { - assumed = old; - old = atomicCAS(address_as_ull, assumed, - __double_as_longlong(val + __longlong_as_double(assumed))); - // Note: uses integer comparison to avoid hang in case of NaN (since NaN != NaN) } while (assumed != old); - } while (assumed != old); - return __longlong_as_double(old); -} -#endif - template < typename FPTYPE, int THREADS_PER_BLOCK> @@ -112,6 +95,7 @@ __global__ void force_deriv_wrt_neighbors_r( net_deriv[idx * ndescrpt + idy] * in_deriv[idx * ndescrpt * 3 + idy * 3 + idz]); } +namespace deepmd { template void prod_force_a_gpu_cuda( FPTYPE * force, @@ -172,3 +156,4 @@ template void prod_force_a_gpu_cuda(float * force, const float * net_deri template void prod_force_a_gpu_cuda(double * force, const double * net_deriv, const double * in_deriv, const int * nlist, const int nloc, const int nall, const int nnei); template void prod_force_r_gpu_cuda(float * force, const float * net_deriv, const float * in_deriv, const int * nlist, const int nloc, const int nall, const int nnei); template void prod_force_r_gpu_cuda(double * force, const double * net_deriv, const double * in_deriv, const int * nlist, const int nloc, const int nall, const int nnei); +} diff --git a/source/lib/src/cuda/prod_virial.cu b/source/lib/src/cuda/prod_virial.cu index 19fb6c1b2f..032e1b1c09 100644 --- a/source/lib/src/cuda/prod_virial.cu +++ b/source/lib/src/cuda/prod_virial.cu @@ -1,23 +1,6 @@ #include "gpu_cuda.h" #include "prod_virial.h" -#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600 -static __inline__ __device__ double atomicAdd( - double* address, - double val) -{ - unsigned long long int* address_as_ull = (unsigned long long int*)address; - unsigned long long int old = *address_as_ull, assumed; - do { - assumed = old; - old = atomicCAS(address_as_ull, assumed, - __double_as_longlong(val + __longlong_as_double(assumed))); - // Note: uses integer comparison to avoid hang in case of NaN (since NaN != NaN) } while (assumed != old); - } while (assumed != old); - return __longlong_as_double(old); -} -#endif - template __global__ void virial_deriv_wrt_neighbors_a( FPTYPE * virial, @@ -90,6 +73,7 @@ __global__ void virial_deriv_wrt_neighbors_r( net_deriv[idx * ndescrpt + idy] * rij[idx * nnei * 3 + idy * 3 + idz % 3] * in_deriv[idx * ndescrpt * 3 + idy * 3 + idz / 3]); } +namespace deepmd { template void prod_virial_a_gpu_cuda( FPTYPE * virial, @@ -152,3 +136,4 @@ template void prod_virial_a_gpu_cuda(float * virial, float * atom_virial, template void prod_virial_a_gpu_cuda(double * virial, double * atom_virial, const double * net_deriv, const double * in_deriv, const double * rij, const int * nlist, const int nloc, const int nall, const int nnei); template void prod_virial_r_gpu_cuda(float * virial, float * atom_virial, const float * net_deriv, const float * in_deriv, const float * rij, const int * nlist, const int nloc, const int nall, const int nnei); template void prod_virial_r_gpu_cuda(double * virial, double * atom_virial, const double * net_deriv, const double * in_deriv, const double * rij, const int * nlist, const int nloc, const int nall, const int nnei); +} diff --git a/source/lib/src/cuda/tabulate.cu b/source/lib/src/cuda/tabulate.cu index 83803733ff..281c8adbc2 100644 --- a/source/lib/src/cuda/tabulate.cu +++ b/source/lib/src/cuda/tabulate.cu @@ -1,5 +1,3 @@ -#include -#include #include "tabulate.h" #include "gpu_cuda.h" @@ -193,6 +191,7 @@ __global__ void tabulate_fusion_grad_fifth_order_polynomial( } } +namespace deepmd { template void tabulate_fusion_gpu_cuda( FPTYPE * out, @@ -238,3 +237,4 @@ template void tabulate_fusion_gpu_cuda(float * out, const float * table, template void tabulate_fusion_gpu_cuda(double * out, const double * table, const double * table_info, const double * em_x, const double * em, const int nloc, const int nnei, const int last_layer_size); template void tabulate_fusion_grad_gpu_cuda (float * dy_dem_x, float * dy_dem, const float * table, const float * table_info, const float * em_x, const float * em, const float * dy, const int nloc, const int nnei, const int last_layer_size); template void tabulate_fusion_grad_gpu_cuda (double * dy_dem_x, double * dy_dem, const double * table, const double * table_info, const double * em_x, const double * em, const double * dy, const int nloc, const int nnei, const int last_layer_size); +} diff --git a/source/lib/src/neighbor_list.cc b/source/lib/src/neighbor_list.cc index e0ceae4a38..89e8552524 100644 --- a/source/lib/src/neighbor_list.cc +++ b/source/lib/src/neighbor_list.cc @@ -844,7 +844,7 @@ build_nlist_cpu( const float & rcut); #if GOOGLE_CUDA -void convert_nlist_gpu_cuda( +void deepmd::convert_nlist_gpu_cuda( InputNlist & gpu_nlist, InputNlist & cpu_nlist, int* & gpu_memory, @@ -867,7 +867,7 @@ void convert_nlist_gpu_cuda( free(_firstneigh); } -void free_nlist_gpu_cuda( +void deepmd::free_nlist_gpu_cuda( InputNlist & gpu_nlist) { delete_device_memory(gpu_nlist.ilist); diff --git a/source/lib/src/prod_env_mat.cc b/source/lib/src/prod_env_mat.cc index 597473021d..c5e3223e9e 100644 --- a/source/lib/src/prod_env_mat.cc +++ b/source/lib/src/prod_env_mat.cc @@ -257,7 +257,7 @@ prod_env_mat_r_cpu( const std::vector sec); #if GOOGLE_CUDA -void env_mat_nbor_update( +void deepmd::env_mat_nbor_update( InputNlist &inlist, InputNlist &gpu_inlist, int &max_nbor_size, diff --git a/source/lib/tests/test_env_mat_a.cc b/source/lib/tests/test_env_mat_a.cc index c08a4f4705..369d09d872 100644 --- a/source/lib/tests/test_env_mat_a.cc +++ b/source/lib/tests/test_env_mat_a.cc @@ -557,9 +557,9 @@ TEST_F(TestEnvMatA, prod_gpu_cuda) malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); malloc_device_memory(memory_dev, nloc * max_nbor_size); - convert_nlist_gpu_cuda(gpu_inlist, inlist, memory_dev, max_nbor_size); + deepmd::convert_nlist_gpu_cuda(gpu_inlist, inlist, memory_dev, max_nbor_size); - prod_env_mat_a_gpu_cuda( + deepmd::prod_env_mat_a_gpu_cuda( em_dev, em_deriv_dev, rij_dev, @@ -648,9 +648,9 @@ TEST_F(TestEnvMatA, prod_gpu_cuda_equal_cpu) malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); malloc_device_memory(memory_dev, nloc * max_nbor_size); - convert_nlist_gpu_cuda(gpu_inlist, inlist, memory_dev, max_nbor_size); + deepmd::convert_nlist_gpu_cuda(gpu_inlist, inlist, memory_dev, max_nbor_size); - prod_env_mat_a_gpu_cuda( + deepmd::prod_env_mat_a_gpu_cuda( em_dev, em_deriv_dev, rij_dev, diff --git a/source/lib/tests/test_env_mat_r.cc b/source/lib/tests/test_env_mat_r.cc index f571dbdaf1..3a50a892ff 100644 --- a/source/lib/tests/test_env_mat_r.cc +++ b/source/lib/tests/test_env_mat_r.cc @@ -377,7 +377,7 @@ TEST_F(TestEnvMatR, prod_gpu_cuda) } std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]), gpu_inlist; + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]), gpu_inlist; convert_nlist(inlist, nlist_a_cpy); std::vector em(nloc * ndescrpt, 0.0), em_deriv(nloc * ndescrpt * 3, 0.0), rij(nloc * nnei * 3, 0.0); std::vector nlist(nloc * nnei, 0); @@ -402,7 +402,7 @@ TEST_F(TestEnvMatR, prod_gpu_cuda) malloc_device_memory(memory_dev, nloc * max_nbor_size); convert_nlist_gpu_cuda(gpu_inlist, inlist, memory_dev, max_nbor_size); - prod_env_mat_r_gpu_cuda( + deepmd::prod_env_mat_r_gpu_cuda( em_dev, em_deriv_dev, rij_dev, @@ -467,7 +467,7 @@ TEST_F(TestEnvMatR, prod_gpu_cuda_equal_cpu) } std::vector ilist(nloc), numneigh(nloc); std::vector firstneigh(nloc); - InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]), gpu_inlist; + deepmd::InputNlist inlist(nloc, &ilist[0], &numneigh[0], &firstneigh[0]), gpu_inlist; convert_nlist(inlist, nlist_a_cpy); std::vector em(nloc * ndescrpt, 0.0), em_deriv(nloc * ndescrpt * 3, 0.0), rij(nloc * nnei * 3, 0.0); std::vector nlist(nloc * nnei, 0); @@ -492,7 +492,7 @@ TEST_F(TestEnvMatR, prod_gpu_cuda_equal_cpu) malloc_device_memory(memory_dev, nloc * max_nbor_size); convert_nlist_gpu_cuda(gpu_inlist, inlist, memory_dev, max_nbor_size); - prod_env_mat_r_gpu_cuda( + deepmd::prod_env_mat_r_gpu_cuda( em_dev, em_deriv_dev, rij_dev, diff --git a/source/lib/tests/test_gelu.cc b/source/lib/tests/test_gelu.cc index 0b05dd71d5..9becbcac47 100644 --- a/source/lib/tests/test_gelu.cc +++ b/source/lib/tests/test_gelu.cc @@ -153,7 +153,7 @@ TEST_F(TestGelu, gelu_gpu_cuda) double * gelu_dev = NULL, * xx_dev = NULL; malloc_device_memory_sync(gelu_dev, gelu); malloc_device_memory_sync(xx_dev, xx); - gelu_gpu_cuda (gelu_dev, xx_dev, nloc); + deepmd::gelu_gpu_cuda (gelu_dev, xx_dev, nloc); memcpy_device_to_host(gelu_dev, gelu); delete_device_memory(gelu_dev); delete_device_memory(xx_dev); @@ -174,7 +174,7 @@ TEST_F(TestGelu, gelu_grad_gpu_cuda) malloc_device_memory_sync(gelu_grad_dev, gelu_grad); malloc_device_memory_sync(xx_dev, xx); malloc_device_memory_sync(dy_dev, dy); - gelu_grad_gpu_cuda (gelu_grad_dev, xx_dev, dy_dev, nloc); + deepmd::gelu_grad_gpu_cuda (gelu_grad_dev, xx_dev, dy_dev, nloc); memcpy_device_to_host(gelu_grad_dev, gelu_grad); delete_device_memory(gelu_grad_dev); delete_device_memory(xx_dev); @@ -198,7 +198,7 @@ TEST_F(TestGelu, gelu_grad_grad_gpu_cuda) malloc_device_memory_sync(xx_dev, xx); malloc_device_memory_sync(dy_dev, dy); malloc_device_memory_sync(dy_2_dev, dy_2); - gelu_grad_grad_gpu_cuda (gelu_grad_grad_dev, xx_dev, dy_dev, dy_2_dev, nloc); + deepmd::gelu_grad_grad_gpu_cuda (gelu_grad_grad_dev, xx_dev, dy_dev, dy_2_dev, nloc); memcpy_device_to_host(gelu_grad_grad_dev, gelu_grad_grad); delete_device_memory(gelu_grad_grad_dev); delete_device_memory(xx_dev); diff --git a/source/lib/tests/test_prod_force_a.cc b/source/lib/tests/test_prod_force_a.cc index 7aeb9ca99f..3318714aff 100644 --- a/source/lib/tests/test_prod_force_a.cc +++ b/source/lib/tests/test_prod_force_a.cc @@ -112,7 +112,7 @@ TEST_F(TestProdForceA, gpu_cuda) malloc_device_memory_sync(net_deriv_dev, net_deriv); malloc_device_memory_sync(env_deriv_dev, env_deriv); - prod_force_a_gpu_cuda (force_dev, net_deriv_dev, env_deriv_dev, nlist_dev, nloc, nall, nnei); + deepmd::prod_force_a_gpu_cuda (force_dev, net_deriv_dev, env_deriv_dev, nlist_dev, nloc, nall, nnei); memcpy_device_to_host(force_dev, force); delete_device_memory(nlist_dev); diff --git a/source/lib/tests/test_prod_force_r.cc b/source/lib/tests/test_prod_force_r.cc index 033c41a7fe..1247a94dda 100644 --- a/source/lib/tests/test_prod_force_r.cc +++ b/source/lib/tests/test_prod_force_r.cc @@ -112,7 +112,7 @@ TEST_F(TestProdForceR, gpu_cuda) malloc_device_memory_sync(net_deriv_dev, net_deriv); malloc_device_memory_sync(env_deriv_dev, env_deriv); - prod_force_r_gpu_cuda (force_dev, net_deriv_dev, env_deriv_dev, nlist_dev, nloc, nall, nnei); + deepmd::prod_force_r_gpu_cuda (force_dev, net_deriv_dev, env_deriv_dev, nlist_dev, nloc, nall, nnei); memcpy_device_to_host(force_dev, force); delete_device_memory(nlist_dev); diff --git a/source/lib/tests/test_prod_virial_a.cc b/source/lib/tests/test_prod_virial_a.cc index f1d4ee619a..1eb7d0f0f9 100644 --- a/source/lib/tests/test_prod_virial_a.cc +++ b/source/lib/tests/test_prod_virial_a.cc @@ -130,7 +130,7 @@ TEST_F(TestProdVirialA, gpu_cuda) malloc_device_memory_sync(env_deriv_dev, env_deriv); malloc_device_memory_sync(rij_dev, rij); - prod_virial_a_gpu_cuda (virial_dev, atom_virial_dev, net_deriv_dev, env_deriv_dev, rij_dev, nlist_dev, nloc, nall, nnei); + deepmd::prod_virial_a_gpu_cuda (virial_dev, atom_virial_dev, net_deriv_dev, env_deriv_dev, rij_dev, nlist_dev, nloc, nall, nnei); memcpy_device_to_host(virial_dev, virial); memcpy_device_to_host(atom_virial_dev, atom_virial); diff --git a/source/lib/tests/test_prod_virial_r.cc b/source/lib/tests/test_prod_virial_r.cc index 101b1659f8..4780d9358d 100644 --- a/source/lib/tests/test_prod_virial_r.cc +++ b/source/lib/tests/test_prod_virial_r.cc @@ -130,7 +130,7 @@ TEST_F(TestProdVirialR, gpu_cuda) malloc_device_memory_sync(env_deriv_dev, env_deriv); malloc_device_memory_sync(rij_dev, rij); - prod_virial_r_gpu_cuda (virial_dev, atom_virial_dev, net_deriv_dev, env_deriv_dev, rij_dev, nlist_dev, nloc, nall, nnei); + deepmd::prod_virial_r_gpu_cuda (virial_dev, atom_virial_dev, net_deriv_dev, env_deriv_dev, rij_dev, nlist_dev, nloc, nall, nnei); memcpy_device_to_host(virial_dev, virial); memcpy_device_to_host(atom_virial_dev, atom_virial); From a8ada896734b9443b3dbeb5e371870ea2ad28d99 Mon Sep 17 00:00:00 2001 From: denghuilu Date: Fri, 19 Mar 2021 18:33:33 +0800 Subject: [PATCH 289/562] add namespace deepmd for gpu_cuda.h --- source/lib/include/gpu_cuda.h | 4 +- source/lib/tests/test_env_mat_a.cc | 100 ++++++++++++------------ source/lib/tests/test_env_mat_r.cc | 102 ++++++++++++------------- source/lib/tests/test_gelu.cc | 42 +++++----- source/lib/tests/test_prod_force_a.cc | 18 ++--- source/lib/tests/test_prod_force_r.cc | 18 ++--- source/lib/tests/test_prod_virial_a.cc | 28 +++---- source/lib/tests/test_prod_virial_r.cc | 28 +++---- source/lib/tests/test_tabulate.cc | 46 +++++------ 9 files changed, 194 insertions(+), 192 deletions(-) diff --git a/source/lib/include/gpu_cuda.h b/source/lib/include/gpu_cuda.h index 6ccbbb9356..48db721436 100644 --- a/source/lib/include/gpu_cuda.h +++ b/source/lib/include/gpu_cuda.h @@ -30,6 +30,7 @@ static __inline__ __device__ double atomicAdd( } #endif +namespace deepmd { template void memcpy_host_to_device( FPTYPE * device, @@ -96,4 +97,5 @@ void memset_device_memory( const int size) { cudaErrcheck(cudaMemset(device, var, sizeof(FPTYPE) * size)); -} \ No newline at end of file +} +} // end of namespace deepmd \ No newline at end of file diff --git a/source/lib/tests/test_env_mat_a.cc b/source/lib/tests/test_env_mat_a.cc index 369d09d872..d32203c692 100644 --- a/source/lib/tests/test_env_mat_a.cc +++ b/source/lib/tests/test_env_mat_a.cc @@ -546,17 +546,17 @@ TEST_F(TestEnvMatA, prod_gpu_cuda) double * posi_cpy_dev = NULL, * avg_dev = NULL, * std_dev = NULL; int * atype_cpy_dev = NULL, * nlist_dev = NULL, * array_int_dev = NULL, * memory_dev = NULL; int_64 * array_longlong_dev = NULL; - malloc_device_memory_sync(em_dev, em); - malloc_device_memory_sync(em_deriv_dev, em_deriv); - malloc_device_memory_sync(rij_dev, rij); - malloc_device_memory_sync(posi_cpy_dev, posi_cpy); - malloc_device_memory_sync(avg_dev, avg); - malloc_device_memory_sync(std_dev, std); - malloc_device_memory_sync(atype_cpy_dev, atype_cpy); - malloc_device_memory_sync(nlist_dev, nlist); - malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); - malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); - malloc_device_memory(memory_dev, nloc * max_nbor_size); + deepmd::malloc_device_memory_sync(em_dev, em); + deepmd::malloc_device_memory_sync(em_deriv_dev, em_deriv); + deepmd::malloc_device_memory_sync(rij_dev, rij); + deepmd::malloc_device_memory_sync(posi_cpy_dev, posi_cpy); + deepmd::malloc_device_memory_sync(avg_dev, avg); + deepmd::malloc_device_memory_sync(std_dev, std); + deepmd::malloc_device_memory_sync(atype_cpy_dev, atype_cpy); + deepmd::malloc_device_memory_sync(nlist_dev, nlist); + deepmd::malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); + deepmd::malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); + deepmd::malloc_device_memory(memory_dev, nloc * max_nbor_size); deepmd::convert_nlist_gpu_cuda(gpu_inlist, inlist, memory_dev, max_nbor_size); deepmd::prod_env_mat_a_gpu_cuda( @@ -577,18 +577,18 @@ TEST_F(TestEnvMatA, prod_gpu_cuda) rc, rc_smth, sec_a); - memcpy_device_to_host(em_dev, em); - delete_device_memory(em_dev); - delete_device_memory(em_deriv_dev); - delete_device_memory(nlist_dev); - delete_device_memory(posi_cpy_dev); - delete_device_memory(atype_cpy_dev); - delete_device_memory(array_int_dev); - delete_device_memory(array_longlong_dev); - delete_device_memory(avg_dev); - delete_device_memory(std_dev); - delete_device_memory(memory_dev); - free_nlist_gpu_cuda(gpu_inlist); + deepmd::memcpy_device_to_host(em_dev, em); + deepmd::delete_device_memory(em_dev); + deepmd::delete_device_memory(em_deriv_dev); + deepmd::delete_device_memory(nlist_dev); + deepmd::delete_device_memory(posi_cpy_dev); + deepmd::delete_device_memory(atype_cpy_dev); + deepmd::delete_device_memory(array_int_dev); + deepmd::delete_device_memory(array_longlong_dev); + deepmd::delete_device_memory(avg_dev); + deepmd::delete_device_memory(std_dev); + deepmd::delete_device_memory(memory_dev); + deepmd::free_nlist_gpu_cuda(gpu_inlist); for(int ii = 0; ii < nloc; ++ii){ for (int jj = 0; jj < nnei; ++jj){ @@ -636,18 +636,18 @@ TEST_F(TestEnvMatA, prod_gpu_cuda_equal_cpu) double * posi_cpy_dev = NULL, * avg_dev = NULL, * std_dev = NULL; int * atype_cpy_dev = NULL, * nlist_dev = NULL, * array_int_dev = NULL, * memory_dev = NULL; int_64 * array_longlong_dev = NULL; - malloc_device_memory_sync(em_dev, em); - malloc_device_memory_sync(em_deriv_dev, em_deriv); - malloc_device_memory_sync(rij_dev, rij); - malloc_device_memory_sync(posi_cpy_dev, posi_cpy); - malloc_device_memory_sync(avg_dev, avg); - malloc_device_memory_sync(std_dev, std); - - malloc_device_memory_sync(atype_cpy_dev, atype_cpy); - malloc_device_memory_sync(nlist_dev, nlist); - malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); - malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); - malloc_device_memory(memory_dev, nloc * max_nbor_size); + deepmd::malloc_device_memory_sync(em_dev, em); + deepmd::malloc_device_memory_sync(em_deriv_dev, em_deriv); + deepmd::malloc_device_memory_sync(rij_dev, rij); + deepmd::malloc_device_memory_sync(posi_cpy_dev, posi_cpy); + deepmd::malloc_device_memory_sync(avg_dev, avg); + deepmd::malloc_device_memory_sync(std_dev, std); + + deepmd::malloc_device_memory_sync(atype_cpy_dev, atype_cpy); + deepmd::malloc_device_memory_sync(nlist_dev, nlist); + deepmd::malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); + deepmd::malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); + deepmd::malloc_device_memory(memory_dev, nloc * max_nbor_size); deepmd::convert_nlist_gpu_cuda(gpu_inlist, inlist, memory_dev, max_nbor_size); deepmd::prod_env_mat_a_gpu_cuda( @@ -668,21 +668,21 @@ TEST_F(TestEnvMatA, prod_gpu_cuda_equal_cpu) rc, rc_smth, sec_a); - memcpy_device_to_host(em_dev, em); - memcpy_device_to_host(em_deriv_dev, em_deriv); - memcpy_device_to_host(rij_dev, rij); - memcpy_device_to_host(nlist_dev, nlist); - delete_device_memory(em_dev); - delete_device_memory(em_deriv_dev); - delete_device_memory(nlist_dev); - delete_device_memory(posi_cpy_dev); - delete_device_memory(atype_cpy_dev); - delete_device_memory(array_int_dev); - delete_device_memory(array_longlong_dev); - delete_device_memory(avg_dev); - delete_device_memory(std_dev); - delete_device_memory(memory_dev); - free_nlist_gpu_cuda(gpu_inlist); + deepmd::memcpy_device_to_host(em_dev, em); + deepmd::memcpy_device_to_host(em_deriv_dev, em_deriv); + deepmd::memcpy_device_to_host(rij_dev, rij); + deepmd::memcpy_device_to_host(nlist_dev, nlist); + deepmd::delete_device_memory(em_dev); + deepmd::delete_device_memory(em_deriv_dev); + deepmd::delete_device_memory(nlist_dev); + deepmd::delete_device_memory(posi_cpy_dev); + deepmd::delete_device_memory(atype_cpy_dev); + deepmd::delete_device_memory(array_int_dev); + deepmd::delete_device_memory(array_longlong_dev); + deepmd::delete_device_memory(avg_dev); + deepmd::delete_device_memory(std_dev); + deepmd::delete_device_memory(memory_dev); + deepmd::free_nlist_gpu_cuda(gpu_inlist); std::vector fmt_nlist_a_1, fmt_nlist_r_1; std::vector env_1, env_deriv_1, rij_a_1; diff --git a/source/lib/tests/test_env_mat_r.cc b/source/lib/tests/test_env_mat_r.cc index 3a50a892ff..aac71eff8c 100644 --- a/source/lib/tests/test_env_mat_r.cc +++ b/source/lib/tests/test_env_mat_r.cc @@ -388,19 +388,19 @@ TEST_F(TestEnvMatR, prod_gpu_cuda) double * posi_cpy_dev = NULL, * avg_dev = NULL, * std_dev = NULL; int * atype_cpy_dev = NULL, * nlist_dev = NULL, * array_int_dev = NULL, * memory_dev = NULL; int_64 * array_longlong_dev = NULL; - malloc_device_memory_sync(em_dev, em); - malloc_device_memory_sync(em_deriv_dev, em_deriv); - malloc_device_memory_sync(rij_dev, rij); - malloc_device_memory_sync(posi_cpy_dev, posi_cpy); - malloc_device_memory_sync(avg_dev, avg); - malloc_device_memory_sync(std_dev, std); + deepmd::malloc_device_memory_sync(em_dev, em); + deepmd::malloc_device_memory_sync(em_deriv_dev, em_deriv); + deepmd::malloc_device_memory_sync(rij_dev, rij); + deepmd::malloc_device_memory_sync(posi_cpy_dev, posi_cpy); + deepmd::malloc_device_memory_sync(avg_dev, avg); + deepmd::malloc_device_memory_sync(std_dev, std); - malloc_device_memory_sync(atype_cpy_dev, atype_cpy); - malloc_device_memory_sync(nlist_dev, nlist); - malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); - malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); - malloc_device_memory(memory_dev, nloc * max_nbor_size); - convert_nlist_gpu_cuda(gpu_inlist, inlist, memory_dev, max_nbor_size); + deepmd::malloc_device_memory_sync(atype_cpy_dev, atype_cpy); + deepmd::malloc_device_memory_sync(nlist_dev, nlist); + deepmd::malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); + deepmd::malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); + deepmd::malloc_device_memory(memory_dev, nloc * max_nbor_size); + deepmd::convert_nlist_gpu_cuda(gpu_inlist, inlist, memory_dev, max_nbor_size); deepmd::prod_env_mat_r_gpu_cuda( em_dev, @@ -420,18 +420,18 @@ TEST_F(TestEnvMatR, prod_gpu_cuda) rc, rc_smth, sec_a); - memcpy_device_to_host(em_dev, em); - delete_device_memory(em_dev); - delete_device_memory(em_deriv_dev); - delete_device_memory(nlist_dev); - delete_device_memory(posi_cpy_dev); - delete_device_memory(atype_cpy_dev); - delete_device_memory(array_int_dev); - delete_device_memory(array_longlong_dev); - delete_device_memory(avg_dev); - delete_device_memory(std_dev); - delete_device_memory(memory_dev); - free_nlist_gpu_cuda(gpu_inlist); + deepmd::memcpy_device_to_host(em_dev, em); + deepmd::delete_device_memory(em_dev); + deepmd::delete_device_memory(em_deriv_dev); + deepmd::delete_device_memory(nlist_dev); + deepmd::delete_device_memory(posi_cpy_dev); + deepmd::delete_device_memory(atype_cpy_dev); + deepmd::delete_device_memory(array_int_dev); + deepmd::delete_device_memory(array_longlong_dev); + deepmd::delete_device_memory(avg_dev); + deepmd::delete_device_memory(std_dev); + deepmd::delete_device_memory(memory_dev); + deepmd::free_nlist_gpu_cuda(gpu_inlist); for(int ii = 0; ii < nloc; ++ii){ for (int jj = 0; jj < nnei; ++jj){ @@ -478,19 +478,19 @@ TEST_F(TestEnvMatR, prod_gpu_cuda_equal_cpu) double * posi_cpy_dev = NULL, * avg_dev = NULL, * std_dev = NULL; int * atype_cpy_dev = NULL, * nlist_dev = NULL, * array_int_dev = NULL, * memory_dev = NULL; int_64 * array_longlong_dev = NULL; - malloc_device_memory_sync(em_dev, em); - malloc_device_memory_sync(em_deriv_dev, em_deriv); - malloc_device_memory_sync(rij_dev, rij); - malloc_device_memory_sync(posi_cpy_dev, posi_cpy); - malloc_device_memory_sync(avg_dev, avg); - malloc_device_memory_sync(std_dev, std); + deepmd::malloc_device_memory_sync(em_dev, em); + deepmd::malloc_device_memory_sync(em_deriv_dev, em_deriv); + deepmd::malloc_device_memory_sync(rij_dev, rij); + deepmd::malloc_device_memory_sync(posi_cpy_dev, posi_cpy); + deepmd::malloc_device_memory_sync(avg_dev, avg); + deepmd::malloc_device_memory_sync(std_dev, std); - malloc_device_memory_sync(atype_cpy_dev, atype_cpy); - malloc_device_memory_sync(nlist_dev, nlist); - malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); - malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); - malloc_device_memory(memory_dev, nloc * max_nbor_size); - convert_nlist_gpu_cuda(gpu_inlist, inlist, memory_dev, max_nbor_size); + deepmd::malloc_device_memory_sync(atype_cpy_dev, atype_cpy); + deepmd::malloc_device_memory_sync(nlist_dev, nlist); + deepmd::malloc_device_memory(array_int_dev, sec_a.size() + nloc * sec_a.size() + nloc); + deepmd::malloc_device_memory(array_longlong_dev, nloc * GPU_MAX_NBOR_SIZE * 2); + deepmd::malloc_device_memory(memory_dev, nloc * max_nbor_size); + deepmd::convert_nlist_gpu_cuda(gpu_inlist, inlist, memory_dev, max_nbor_size); deepmd::prod_env_mat_r_gpu_cuda( em_dev, @@ -510,21 +510,21 @@ TEST_F(TestEnvMatR, prod_gpu_cuda_equal_cpu) rc, rc_smth, sec_a); - memcpy_device_to_host(em_dev, em); - memcpy_device_to_host(em_deriv_dev, em_deriv); - memcpy_device_to_host(rij_dev, rij); - memcpy_device_to_host(nlist_dev, nlist); - delete_device_memory(em_dev); - delete_device_memory(em_deriv_dev); - delete_device_memory(nlist_dev); - delete_device_memory(posi_cpy_dev); - delete_device_memory(atype_cpy_dev); - delete_device_memory(array_int_dev); - delete_device_memory(array_longlong_dev); - delete_device_memory(avg_dev); - delete_device_memory(std_dev); - delete_device_memory(memory_dev); - free_nlist_gpu_cuda(gpu_inlist); + deepmd::memcpy_device_to_host(em_dev, em); + deepmd::memcpy_device_to_host(em_deriv_dev, em_deriv); + deepmd::memcpy_device_to_host(rij_dev, rij); + deepmd::memcpy_device_to_host(nlist_dev, nlist); + deepmd::delete_device_memory(em_dev); + deepmd::delete_device_memory(em_deriv_dev); + deepmd::delete_device_memory(nlist_dev); + deepmd::delete_device_memory(posi_cpy_dev); + deepmd::delete_device_memory(atype_cpy_dev); + deepmd::delete_device_memory(array_int_dev); + deepmd::delete_device_memory(array_longlong_dev); + deepmd::delete_device_memory(avg_dev); + deepmd::delete_device_memory(std_dev); + deepmd::delete_device_memory(memory_dev); + deepmd::free_nlist_gpu_cuda(gpu_inlist); std::vector fmt_nlist_a_1, fmt_nlist_r_1; std::vector env_1, env_deriv_1, rij_a_1; diff --git a/source/lib/tests/test_gelu.cc b/source/lib/tests/test_gelu.cc index 9becbcac47..4d85b2dd27 100644 --- a/source/lib/tests/test_gelu.cc +++ b/source/lib/tests/test_gelu.cc @@ -151,12 +151,12 @@ TEST_F(TestGelu, gelu_gpu_cuda) std::vector gelu(nloc, 0.0); double * gelu_dev = NULL, * xx_dev = NULL; - malloc_device_memory_sync(gelu_dev, gelu); - malloc_device_memory_sync(xx_dev, xx); + deepmd::malloc_device_memory_sync(gelu_dev, gelu); + deepmd::malloc_device_memory_sync(xx_dev, xx); deepmd::gelu_gpu_cuda (gelu_dev, xx_dev, nloc); - memcpy_device_to_host(gelu_dev, gelu); - delete_device_memory(gelu_dev); - delete_device_memory(xx_dev); + deepmd::memcpy_device_to_host(gelu_dev, gelu); + deepmd::delete_device_memory(gelu_dev); + deepmd::delete_device_memory(xx_dev); EXPECT_EQ(gelu.size(), nloc); EXPECT_EQ(gelu.size(), expected_gelu.size()); @@ -171,14 +171,14 @@ TEST_F(TestGelu, gelu_grad_gpu_cuda) std::vector gelu_grad(nloc, 0.0); double * gelu_grad_dev = NULL, * xx_dev = NULL, * dy_dev = NULL; - malloc_device_memory_sync(gelu_grad_dev, gelu_grad); - malloc_device_memory_sync(xx_dev, xx); - malloc_device_memory_sync(dy_dev, dy); + deepmd::malloc_device_memory_sync(gelu_grad_dev, gelu_grad); + deepmd::malloc_device_memory_sync(xx_dev, xx); + deepmd::malloc_device_memory_sync(dy_dev, dy); deepmd::gelu_grad_gpu_cuda (gelu_grad_dev, xx_dev, dy_dev, nloc); - memcpy_device_to_host(gelu_grad_dev, gelu_grad); - delete_device_memory(gelu_grad_dev); - delete_device_memory(xx_dev); - delete_device_memory(dy_dev); + deepmd::memcpy_device_to_host(gelu_grad_dev, gelu_grad); + deepmd::delete_device_memory(gelu_grad_dev); + deepmd::delete_device_memory(xx_dev); + deepmd::delete_device_memory(dy_dev); EXPECT_EQ(gelu_grad.size(), nloc); EXPECT_EQ(gelu_grad.size(), expected_gelu_grad.size()); @@ -194,16 +194,16 @@ TEST_F(TestGelu, gelu_grad_grad_gpu_cuda) std::vector gelu_grad_grad(nloc, 0.0); double * gelu_grad_grad_dev = NULL, * xx_dev = NULL, * dy_dev = NULL, * dy_2_dev = NULL; - malloc_device_memory_sync(gelu_grad_grad_dev, gelu_grad_grad); - malloc_device_memory_sync(xx_dev, xx); - malloc_device_memory_sync(dy_dev, dy); - malloc_device_memory_sync(dy_2_dev, dy_2); + deepmd::malloc_device_memory_sync(gelu_grad_grad_dev, gelu_grad_grad); + deepmd::malloc_device_memory_sync(xx_dev, xx); + deepmd::malloc_device_memory_sync(dy_dev, dy); + deepmd::malloc_device_memory_sync(dy_2_dev, dy_2); deepmd::gelu_grad_grad_gpu_cuda (gelu_grad_grad_dev, xx_dev, dy_dev, dy_2_dev, nloc); - memcpy_device_to_host(gelu_grad_grad_dev, gelu_grad_grad); - delete_device_memory(gelu_grad_grad_dev); - delete_device_memory(xx_dev); - delete_device_memory(dy_dev); - delete_device_memory(dy_2_dev); + deepmd::memcpy_device_to_host(gelu_grad_grad_dev, gelu_grad_grad); + deepmd::delete_device_memory(gelu_grad_grad_dev); + deepmd::delete_device_memory(xx_dev); + deepmd::delete_device_memory(dy_dev); + deepmd::delete_device_memory(dy_2_dev); EXPECT_EQ(gelu_grad_grad.size(), nloc); EXPECT_EQ(gelu_grad_grad.size(), expected_gelu_grad_grad.size()); diff --git a/source/lib/tests/test_prod_force_a.cc b/source/lib/tests/test_prod_force_a.cc index 3318714aff..d9c7c1319d 100644 --- a/source/lib/tests/test_prod_force_a.cc +++ b/source/lib/tests/test_prod_force_a.cc @@ -107,18 +107,18 @@ TEST_F(TestProdForceA, gpu_cuda) int * nlist_dev = NULL; double * force_dev = NULL, * net_deriv_dev = NULL, * env_deriv_dev = NULL; - malloc_device_memory_sync(nlist_dev, nlist); - malloc_device_memory_sync(force_dev, force); - malloc_device_memory_sync(net_deriv_dev, net_deriv); - malloc_device_memory_sync(env_deriv_dev, env_deriv); + deepmd::malloc_device_memory_sync(nlist_dev, nlist); + deepmd::malloc_device_memory_sync(force_dev, force); + deepmd::malloc_device_memory_sync(net_deriv_dev, net_deriv); + deepmd::malloc_device_memory_sync(env_deriv_dev, env_deriv); deepmd::prod_force_a_gpu_cuda (force_dev, net_deriv_dev, env_deriv_dev, nlist_dev, nloc, nall, nnei); - memcpy_device_to_host(force_dev, force); - delete_device_memory(nlist_dev); - delete_device_memory(force_dev); - delete_device_memory(net_deriv_dev); - delete_device_memory(env_deriv_dev); + deepmd::memcpy_device_to_host(force_dev, force); + deepmd::delete_device_memory(nlist_dev); + deepmd::delete_device_memory(force_dev); + deepmd::delete_device_memory(net_deriv_dev); + deepmd::delete_device_memory(env_deriv_dev); EXPECT_EQ(force.size(), nall * 3); EXPECT_EQ(force.size(), expected_force.size()); diff --git a/source/lib/tests/test_prod_force_r.cc b/source/lib/tests/test_prod_force_r.cc index 1247a94dda..e77cafdace 100644 --- a/source/lib/tests/test_prod_force_r.cc +++ b/source/lib/tests/test_prod_force_r.cc @@ -107,18 +107,18 @@ TEST_F(TestProdForceR, gpu_cuda) int * nlist_dev = NULL; double * force_dev = NULL, * net_deriv_dev = NULL, * env_deriv_dev = NULL; - malloc_device_memory_sync(nlist_dev, nlist); - malloc_device_memory_sync(force_dev, force); - malloc_device_memory_sync(net_deriv_dev, net_deriv); - malloc_device_memory_sync(env_deriv_dev, env_deriv); + deepmd::malloc_device_memory_sync(nlist_dev, nlist); + deepmd::malloc_device_memory_sync(force_dev, force); + deepmd::malloc_device_memory_sync(net_deriv_dev, net_deriv); + deepmd::malloc_device_memory_sync(env_deriv_dev, env_deriv); deepmd::prod_force_r_gpu_cuda (force_dev, net_deriv_dev, env_deriv_dev, nlist_dev, nloc, nall, nnei); - memcpy_device_to_host(force_dev, force); - delete_device_memory(nlist_dev); - delete_device_memory(force_dev); - delete_device_memory(net_deriv_dev); - delete_device_memory(env_deriv_dev); + deepmd::memcpy_device_to_host(force_dev, force); + deepmd::delete_device_memory(nlist_dev); + deepmd::delete_device_memory(force_dev); + deepmd::delete_device_memory(net_deriv_dev); + deepmd::delete_device_memory(env_deriv_dev); EXPECT_EQ(force.size(), nall * 3); EXPECT_EQ(force.size(), expected_force.size()); diff --git a/source/lib/tests/test_prod_virial_a.cc b/source/lib/tests/test_prod_virial_a.cc index 1eb7d0f0f9..4cade7c771 100644 --- a/source/lib/tests/test_prod_virial_a.cc +++ b/source/lib/tests/test_prod_virial_a.cc @@ -123,23 +123,23 @@ TEST_F(TestProdVirialA, gpu_cuda) int * nlist_dev = NULL; double * virial_dev = NULL, *atom_virial_dev = NULL, * net_deriv_dev = NULL, * env_deriv_dev = NULL, * rij_dev = NULL; - malloc_device_memory_sync(nlist_dev, nlist); - malloc_device_memory_sync(virial_dev, virial); - malloc_device_memory_sync(atom_virial_dev, atom_virial); - malloc_device_memory_sync(net_deriv_dev, net_deriv); - malloc_device_memory_sync(env_deriv_dev, env_deriv); - malloc_device_memory_sync(rij_dev, rij); + deepmd::malloc_device_memory_sync(nlist_dev, nlist); + deepmd::malloc_device_memory_sync(virial_dev, virial); + deepmd::malloc_device_memory_sync(atom_virial_dev, atom_virial); + deepmd::malloc_device_memory_sync(net_deriv_dev, net_deriv); + deepmd::malloc_device_memory_sync(env_deriv_dev, env_deriv); + deepmd::malloc_device_memory_sync(rij_dev, rij); deepmd::prod_virial_a_gpu_cuda (virial_dev, atom_virial_dev, net_deriv_dev, env_deriv_dev, rij_dev, nlist_dev, nloc, nall, nnei); - memcpy_device_to_host(virial_dev, virial); - memcpy_device_to_host(atom_virial_dev, atom_virial); - delete_device_memory(nlist_dev); - delete_device_memory(virial_dev); - delete_device_memory(atom_virial_dev); - delete_device_memory(net_deriv_dev); - delete_device_memory(env_deriv_dev); - delete_device_memory(rij_dev); + deepmd::memcpy_device_to_host(virial_dev, virial); + deepmd::memcpy_device_to_host(atom_virial_dev, atom_virial); + deepmd::delete_device_memory(nlist_dev); + deepmd::delete_device_memory(virial_dev); + deepmd::delete_device_memory(atom_virial_dev); + deepmd::delete_device_memory(net_deriv_dev); + deepmd::delete_device_memory(env_deriv_dev); + deepmd::delete_device_memory(rij_dev); // virial are not calculated in gpu currently; for (int ii = 0; ii < 9; ii++) { virial[ii] = 0; diff --git a/source/lib/tests/test_prod_virial_r.cc b/source/lib/tests/test_prod_virial_r.cc index 4780d9358d..b321454b8e 100644 --- a/source/lib/tests/test_prod_virial_r.cc +++ b/source/lib/tests/test_prod_virial_r.cc @@ -123,23 +123,23 @@ TEST_F(TestProdVirialR, gpu_cuda) int * nlist_dev = NULL; double * virial_dev = NULL, *atom_virial_dev = NULL, * net_deriv_dev = NULL, * env_deriv_dev = NULL, * rij_dev = NULL; - malloc_device_memory_sync(nlist_dev, nlist); - malloc_device_memory_sync(virial_dev, virial); - malloc_device_memory_sync(atom_virial_dev, atom_virial); - malloc_device_memory_sync(net_deriv_dev, net_deriv); - malloc_device_memory_sync(env_deriv_dev, env_deriv); - malloc_device_memory_sync(rij_dev, rij); + deepmd::malloc_device_memory_sync(nlist_dev, nlist); + deepmd::malloc_device_memory_sync(virial_dev, virial); + deepmd::malloc_device_memory_sync(atom_virial_dev, atom_virial); + deepmd::malloc_device_memory_sync(net_deriv_dev, net_deriv); + deepmd::malloc_device_memory_sync(env_deriv_dev, env_deriv); + deepmd::malloc_device_memory_sync(rij_dev, rij); deepmd::prod_virial_r_gpu_cuda (virial_dev, atom_virial_dev, net_deriv_dev, env_deriv_dev, rij_dev, nlist_dev, nloc, nall, nnei); - memcpy_device_to_host(virial_dev, virial); - memcpy_device_to_host(atom_virial_dev, atom_virial); - delete_device_memory(nlist_dev); - delete_device_memory(virial_dev); - delete_device_memory(atom_virial_dev); - delete_device_memory(net_deriv_dev); - delete_device_memory(env_deriv_dev); - delete_device_memory(rij_dev); + deepmd::memcpy_device_to_host(virial_dev, virial); + deepmd::memcpy_device_to_host(atom_virial_dev, atom_virial); + deepmd::delete_device_memory(nlist_dev); + deepmd::delete_device_memory(virial_dev); + deepmd::delete_device_memory(atom_virial_dev); + deepmd::delete_device_memory(net_deriv_dev); + deepmd::delete_device_memory(env_deriv_dev); + deepmd::delete_device_memory(rij_dev); // virial are not calculated in gpu currently; for (int ii = 0; ii < 9; ii++) { virial[ii] = 0; diff --git a/source/lib/tests/test_tabulate.cc b/source/lib/tests/test_tabulate.cc index f92629efb4..b22cca03d8 100644 --- a/source/lib/tests/test_tabulate.cc +++ b/source/lib/tests/test_tabulate.cc @@ -179,16 +179,16 @@ TEST_F(TestTabulate, tabulate_fusion_gpu_cuda) std::vector xyz_scatter(nloc * nnei * last_layer_size, 0.0); double * xyz_scatter_dev = NULL, * table_dev = NULL, * em_x_dev = NULL, * em_dev = NULL; - malloc_device_memory_sync(xyz_scatter_dev, xyz_scatter); - malloc_device_memory_sync(table_dev, table); - malloc_device_memory_sync(em_x_dev, em_x); - malloc_device_memory_sync(em_dev, em); + deepmd::malloc_device_memory_sync(xyz_scatter_dev, xyz_scatter); + deepmd::malloc_device_memory_sync(table_dev, table); + deepmd::malloc_device_memory_sync(em_x_dev, em_x); + deepmd::malloc_device_memory_sync(em_dev, em); deepmd::tabulate_fusion_gpu_cuda(xyz_scatter_dev, table_dev, &info[0], em_x_dev, em_dev, nloc, nnei, last_layer_size); - memcpy_device_to_host(xyz_scatter_dev, xyz_scatter); - delete_device_memory(xyz_scatter_dev); - delete_device_memory(table_dev); - delete_device_memory(em_x_dev); - delete_device_memory(em_dev); + deepmd::memcpy_device_to_host(xyz_scatter_dev, xyz_scatter); + deepmd::delete_device_memory(xyz_scatter_dev); + deepmd::delete_device_memory(table_dev); + deepmd::delete_device_memory(em_x_dev); + deepmd::delete_device_memory(em_dev); EXPECT_EQ(xyz_scatter.size(), nloc * nnei * last_layer_size); EXPECT_EQ(xyz_scatter.size(), expected_xyz_scatter.size()); @@ -204,21 +204,21 @@ TEST_F(TestTabulate, tabulate_fusion_grad_gpu_cuda) std::vector dy(nloc * nnei * last_layer_size, 1.0); double * dy_dem_x_dev = NULL, * dy_dem_dev = NULL, * table_dev = NULL, * em_x_dev = NULL, * em_dev = NULL, * dy_dev = NULL; - malloc_device_memory_sync(dy_dem_x_dev, dy_dem_x); - malloc_device_memory_sync(dy_dem_dev, dy_dem); - malloc_device_memory_sync(table_dev, table); - malloc_device_memory_sync(em_x_dev, em_x); - malloc_device_memory_sync(em_dev, em); - malloc_device_memory_sync(dy_dev, dy); + deepmd::malloc_device_memory_sync(dy_dem_x_dev, dy_dem_x); + deepmd::malloc_device_memory_sync(dy_dem_dev, dy_dem); + deepmd::malloc_device_memory_sync(table_dev, table); + deepmd::malloc_device_memory_sync(em_x_dev, em_x); + deepmd::malloc_device_memory_sync(em_dev, em); + deepmd::malloc_device_memory_sync(dy_dev, dy); deepmd::tabulate_fusion_grad_gpu_cuda(dy_dem_x_dev, dy_dem_dev, table_dev, &info[0], em_x_dev, em_dev, dy_dev, nloc, nnei, last_layer_size); - memcpy_device_to_host(dy_dem_x_dev, dy_dem_x); - memcpy_device_to_host(dy_dem_dev, dy_dem); - delete_device_memory(dy_dem_x_dev); - delete_device_memory(dy_dem_dev); - delete_device_memory(table_dev); - delete_device_memory(em_x_dev); - delete_device_memory(em_dev); - delete_device_memory(dy_dev); + deepmd::memcpy_device_to_host(dy_dem_x_dev, dy_dem_x); + deepmd::memcpy_device_to_host(dy_dem_dev, dy_dem); + deepmd::delete_device_memory(dy_dem_x_dev); + deepmd::delete_device_memory(dy_dem_dev); + deepmd::delete_device_memory(table_dev); + deepmd::delete_device_memory(em_x_dev); + deepmd::delete_device_memory(em_dev); + deepmd::delete_device_memory(dy_dev); EXPECT_EQ(dy_dem_x.size(), nloc * nnei); EXPECT_EQ(dy_dem.size(), nloc * nnei * 4); From 708de6ceb9c17983dc3430bad830f20b2eb2af2f Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 20 Mar 2021 00:32:28 +0800 Subject: [PATCH 290/562] better output format during training, testing and in lcurve.out --- deepmd/entrypoints/test.py | 34 +++++++++++++++++----------------- deepmd/loggers/loggers.py | 6 ++++-- deepmd/loss/ener.py | 16 ++++++++-------- deepmd/loss/tensor.py | 6 +++--- deepmd/utils/data_system.py | 24 +++++++++++++----------- 5 files changed, 45 insertions(+), 41 deletions(-) diff --git a/deepmd/entrypoints/test.py b/deepmd/entrypoints/test.py index 6d4a2c4ad8..5c91547866 100644 --- a/deepmd/entrypoints/test.py +++ b/deepmd/entrypoints/test.py @@ -292,13 +292,13 @@ def test_ener( # print ("# energies: %s" % energy) log.info(f"# number of test data : {numb_test:d} ") - log.info(f"Energy L2err : {l2e:e} eV") - log.info(f"Energy L2err/Natoms : {l2ea:e} eV") - log.info(f"Force L2err : {l2f:e} eV/A") - log.info(f"Virial L2err : {l2v:e} eV") - log.info(f"Virial L2err/Natoms : {l2va:e} eV") + log.info(f"Energy RMSE : {l2e:e} eV") + log.info(f"Energy RMSE/Natoms : {l2ea:e} eV") + log.info(f"Force RMSE : {l2f:e} eV/A") + log.info(f"Virial RMSE : {l2v:e} eV") + log.info(f"Virial RMSE/Natoms : {l2va:e} eV") if has_atom_ener: - log.info(f"Atomic ener L2err : {l2ae:e} eV") + log.info(f"Atomic ener RMSE : {l2ae:e} eV") if detail_file is not None: detail_path = Path(detail_file) @@ -355,9 +355,9 @@ def print_ener_sys_avg(avg: np.ndarray): avg : np.ndarray array with summaries """ - log.info(f"Energy L2err/Natoms : {avg[0]:e} eV") - log.info(f"Force L2err : {avg[1]:e} eV/A") - log.info(f"Virial L2err/Natoms : {avg[2]:e} eV") + log.info(f"Energy RMSE/Natoms : {avg[0]:e} eV") + log.info(f"Force RMSE : {avg[1]:e} eV/A") + log.info(f"Virial RMSE/Natoms : {avg[2]:e} eV") def run_test(dp: "DeepTensor", test_data: dict, numb_test: int): @@ -420,7 +420,7 @@ def test_wfc( l2f = l2err(wfc - test_data["wfc"][:numb_test]) log.info("# number of test data : {numb_test:d} ") - log.info("WFC L2err : {l2f:e} eV/A") + log.info("WFC RMSE : {l2f:e} eV/A") if detail_file is not None: detail_path = Path(detail_file) @@ -447,7 +447,7 @@ def print_wfc_sys_avg(avg): avg : np.ndarray array with summaries """ - log.info(f"WFC L2err : {avg[0]:e} eV/A") + log.info(f"WFC RMSE : {avg[0]:e} eV/A") def test_polar( @@ -509,10 +509,10 @@ def test_polar( l2fa = l2f / sel_natoms log.info(f"# number of test data : {numb_test:d} ") - log.info(f"Polarizability L2err : {l2f:e} eV/A") + log.info(f"Polarizability RMSE : {l2f:e} eV/A") if global_polar: - log.info(f"Polarizability L2err/sqrtN : {l2fs:e} eV/A") - log.info(f"Polarizability L2err/N : {l2fa:e} eV/A") + log.info(f"Polarizability RMSE/sqrtN : {l2fs:e} eV/A") + log.info(f"Polarizability RMSE/N : {l2fa:e} eV/A") if detail_file is not None: detail_path = Path(detail_file) @@ -542,7 +542,7 @@ def print_polar_sys_avg(avg): avg : np.ndarray array with summaries """ - log.info(f"Polarizability L2err : {avg[0]:e} eV/A") + log.info(f"Polarizability RMSE : {avg[0]:e} eV/A") def test_dipole( @@ -577,7 +577,7 @@ def test_dipole( l2f = l2err(dipole - test_data["dipole"][:numb_test]) log.info(f"# number of test data : {numb_test:d}") - log.info(f"Dipole L2err : {l2f:e} eV/A") + log.info(f"Dipole RMSE : {l2f:e} eV/A") if detail_file is not None: detail_path = Path(detail_file) @@ -605,4 +605,4 @@ def print_dipole_sys_avg(avg): avg : np.ndarray array with summaries """ - log.info(f"Dipole L2err : {avg[0]:e} eV/A") + log.info(f"Dipole RMSE : {avg[0]:e} eV/A") diff --git a/deepmd/loggers/loggers.py b/deepmd/loggers/loggers.py index 6400cb0a15..f787ff1e1a 100644 --- a/deepmd/loggers/loggers.py +++ b/deepmd/loggers/loggers.py @@ -20,13 +20,15 @@ "[%(asctime)s] %(app_name)s %(levelname)-7s %(name)-45s %(message)s" ) CFORMATTER = logging.Formatter( - "%(app_name)s %(levelname)-7s |-> %(name)-45s %(message)s" +# "%(app_name)s %(levelname)-7s |-> %(name)-45s %(message)s" + "%(app_name)s %(levelname)-7s %(message)s" ) FFORMATTER_MPI = logging.Formatter( "[%(asctime)s] %(app_name)s rank:%(rank)-2s %(levelname)-7s %(name)-45s %(message)s" ) CFORMATTER_MPI = logging.Formatter( - "%(app_name)s rank:%(rank)-2s %(levelname)-7s |-> %(name)-45s %(message)s" +# "%(app_name)s rank:%(rank)-2s %(levelname)-7s |-> %(name)-45s %(message)s" + "%(app_name)s rank:%(rank)-2s %(levelname)-7s %(message)s" ) diff --git a/deepmd/loss/ener.py b/deepmd/loss/ener.py index 89d15b3add..d4a5b11509 100644 --- a/deepmd/loss/ener.py +++ b/deepmd/loss/ener.py @@ -128,19 +128,19 @@ def build (self, return l2_loss, more_loss def print_header(self): - prop_fmt = ' %9s %9s' + prop_fmt = ' %11s %11s' print_str = '' - print_str += prop_fmt % ('l2_tst', 'l2_trn') + print_str += prop_fmt % ('rmse_tst', 'rmse_trn') if self.has_e : - print_str += prop_fmt % ('l2_e_tst', 'l2_e_trn') + print_str += prop_fmt % ('rmse_e_tst', 'rmse_e_trn') if self.has_ae : - print_str += prop_fmt % ('l2_ae_tst', 'l2_ae_trn') + print_str += prop_fmt % ('rmse_ae_tst', 'rmse_ae_trn') if self.has_f : - print_str += prop_fmt % ('l2_f_tst', 'l2_f_trn') + print_str += prop_fmt % ('rmse_f_tst', 'rmse_f_trn') if self.has_v : - print_str += prop_fmt % ('l2_v_tst', 'l2_v_trn') + print_str += prop_fmt % ('rmse_v_tst', 'rmse_v_trn') if self.has_pf : - print_str += prop_fmt % ('l2_pf_tst', 'l2_pf_trn') + print_str += prop_fmt % ('rmse_pf_tst', 'rmse_pf_trn') return print_str def print_on_training(self, @@ -180,7 +180,7 @@ def print_on_training(self, print_str = "" - prop_fmt = " %9.2e %9.2e" + prop_fmt = " %11.2e %11.2e" print_str += prop_fmt % (np.sqrt(error_test), np.sqrt(error_train)) if self.has_e : print_str += prop_fmt % (np.sqrt(error_e_test) / natoms[0], np.sqrt(error_e_train) / natoms[0]) diff --git a/deepmd/loss/tensor.py b/deepmd/loss/tensor.py index 8784427808..3327c418d5 100644 --- a/deepmd/loss/tensor.py +++ b/deepmd/loss/tensor.py @@ -52,9 +52,9 @@ def build (self, @staticmethod def print_header(): - prop_fmt = ' %9s %9s' + prop_fmt = ' %11s %11s' print_str = '' - print_str += prop_fmt % ('l2_tst', 'l2_trn') + print_str += prop_fmt % ('rmse_tst', 'rmse_trn') return print_str def print_on_training(self, @@ -85,7 +85,7 @@ def print_on_training(self, error_test = test_out[0] print_str = "" - prop_fmt = " %9.2e %9.2e" + prop_fmt = " %11.2e %11.2e" print_str += prop_fmt % (np.sqrt(error_test), np.sqrt(error_train)) return print_str diff --git a/deepmd/utils/data_system.py b/deepmd/utils/data_system.py index e9d07a51ad..557a2c6bd0 100644 --- a/deepmd/utils/data_system.py +++ b/deepmd/utils/data_system.py @@ -404,20 +404,22 @@ def print_summary(self, prob = self._get_sys_probs(sys_probs, auto_prob_style) # width 65 sys_width = 42 - log.info("---Summary of DataSystem------------------------------------------------") + log.info("---Summary of DataSystem--------------------------------------------------------------") log.info("found %d system(s):" % self.nsystems) - log.info("%s " % self._format_name_length('system', sys_width)) - log.info("%s %s %s %s %5s" % ('natoms', 'bch_sz', 'n_bch', "n_test", 'prob')) + log.info(("%s " % self._format_name_length('system', sys_width)) + + ("%6s %6s %6s %6s %5s %3s" % ('natoms', 'bch_sz', 'n_bch', "n_test", 'prob', 'pbc'))) for ii in range(self.nsystems) : - log.info("%s %6d %6d %6d %6d %5.3f" % + log.info("%s %6d %6d %6d %6d %5.3f %3s" % (self._format_name_length(self.system_dirs[ii], sys_width), - self.natoms[ii], - # TODO batch size * nbatches = number of structures - self.batch_size[ii], - self.nbatches[ii], - self.test_size[ii], - prob[ii]) ) - log.info("------------------------------------------------------------------------\n") + self.natoms[ii], + # TODO batch size * nbatches = number of structures + self.batch_size[ii], + self.nbatches[ii], + self.test_size[ii], + prob[ii], + "T" if self.data_systems[ii].pbc else "F" + ) ) + log.info("--------------------------------------------------------------------------------------") def _make_auto_bs(self, rule) : bs = [] From c3e9292dc97586ef497d36bf682f2ca7c3438d28 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sun, 21 Mar 2021 20:34:25 -0400 Subject: [PATCH 291/562] fix bugs of ase calculator and add tests --- source/tests/test_deeppot_a.py | 14 ++++++++++++++ source/train/calculator.py | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/source/tests/test_deeppot_a.py b/source/tests/test_deeppot_a.py index 8541cb8fa3..6f8c800d16 100644 --- a/source/tests/test_deeppot_a.py +++ b/source/tests/test_deeppot_a.py @@ -324,4 +324,18 @@ def test_1frame_atm(self): for ii in range(nframes, 9): self.assertAlmostEqual(vv.reshape([-1])[ii], expected_sv.reshape([-1])[ii], places = default_places) + def test_ase(self): + from ase import Atoms + from deepmd.calculator import DP + water = Atoms('OHHOHH', + positions=self.coords.reshape((-1,3)), + cell=self.box.reshpae((3,3)), + calculator=self.dp) + ee = water.get_potential_energy() + ff = water.get_forces() + for ii in range(ff.size): + self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) + expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) + for ii in range(nframes): + self.assertAlmostEqual(ee.reshape([-1])[ii], expected_se.reshape([-1])[ii], places = default_places) diff --git a/source/train/calculator.py b/source/train/calculator.py index e9c8e63c7d..b70305a26c 100644 --- a/source/train/calculator.py +++ b/source/train/calculator.py @@ -62,7 +62,7 @@ def __init__( **kwargs ) -> None: Calculator.__init__(self, label=label, **kwargs) - self.dp = DeepPot(str(Path(model).resolve())) + self.dp = DeepPotential(str(Path(model).resolve())) if type_dict: self.type_dict = type_dict else: From 373349c231da586b3830e8df5938f79645df2dc6 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sun, 21 Mar 2021 20:37:06 -0400 Subject: [PATCH 292/562] add ase to tests --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index cf83e4955f..729d62650d 100644 --- a/setup.py +++ b/setup.py @@ -104,7 +104,7 @@ cmake_source_dir="source", cmake_minimum_required_version="3.0", extras_require={ - "test": ["dpdata>=0.1.9", "pytest", "pytest-cov", "pytest-sugar"], + "test": ["dpdata>=0.1.9", "ase", "pytest", "pytest-cov", "pytest-sugar"], "docs": ["sphinx", "recommonmark", "sphinx_rtd_theme"], **extras_require, }, From c5eef2f8182b0e858059b467989e541afc1abeb6 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sun, 21 Mar 2021 21:03:56 -0400 Subject: [PATCH 293/562] fix typo --- source/tests/test_deeppot_a.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/tests/test_deeppot_a.py b/source/tests/test_deeppot_a.py index 6f8c800d16..ed24fa5875 100644 --- a/source/tests/test_deeppot_a.py +++ b/source/tests/test_deeppot_a.py @@ -329,7 +329,7 @@ def test_ase(self): from deepmd.calculator import DP water = Atoms('OHHOHH', positions=self.coords.reshape((-1,3)), - cell=self.box.reshpae((3,3)), + cell=self.box.reshape((3,3)), calculator=self.dp) ee = water.get_potential_energy() ff = water.get_forces() From d5354fdd383ecb8e8589fbb4762407232b05641c Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sun, 21 Mar 2021 21:19:57 -0400 Subject: [PATCH 294/562] fix bug --- source/tests/test_deeppot_a.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/tests/test_deeppot_a.py b/source/tests/test_deeppot_a.py index ed24fa5875..f4e73682f3 100644 --- a/source/tests/test_deeppot_a.py +++ b/source/tests/test_deeppot_a.py @@ -330,9 +330,10 @@ def test_ase(self): water = Atoms('OHHOHH', positions=self.coords.reshape((-1,3)), cell=self.box.reshape((3,3)), - calculator=self.dp) + calculator=DP("deeppot.pb")) ee = water.get_potential_energy() ff = water.get_forces() + nframes = 1 for ii in range(ff.size): self.assertAlmostEqual(ff.reshape([-1])[ii], self.expected_f.reshape([-1])[ii], places = default_places) expected_se = np.sum(self.expected_e.reshape([nframes, -1]), axis = 1) From c7475d731347c2e9921a9f5afbf8d327b3b8bdbf Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Mon, 22 Mar 2021 23:30:25 -0400 Subject: [PATCH 295/562] import Path for runtime --- source/train/calculator.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/train/calculator.py b/source/train/calculator.py index b70305a26c..7ca7943d7a 100644 --- a/source/train/calculator.py +++ b/source/train/calculator.py @@ -1,13 +1,12 @@ """ASE calculator interface module.""" from typing import TYPE_CHECKING, Dict, List, Optional, Union +from pathlib import Path from deepmd import DeepPotential from ase.calculators.calculator import Calculator, all_changes if TYPE_CHECKING: - from pathlib import Path - from ase import Atoms __all__ = ["DP"] From 578e89b849c9b99b86ae466ee524d1e8534057f1 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 26 Mar 2021 23:39:46 +0800 Subject: [PATCH 296/562] refact model --- deepmd/model/__init__.py | 5 + source/train/model.py => deepmd/model/ener.py | 244 ++++-------------- deepmd/model/model_stat.py | 60 +++++ deepmd/model/tensor.py | 151 +++++++++++ deepmd/utils/argcheck.py | 2 + setup.py | 3 +- source/train/CMakeLists.txt | 4 +- source/train/trainer.py | 40 ++- 8 files changed, 303 insertions(+), 206 deletions(-) create mode 100644 deepmd/model/__init__.py rename source/train/model.py => deepmd/model/ener.py (53%) create mode 100644 deepmd/model/model_stat.py create mode 100644 deepmd/model/tensor.py diff --git a/deepmd/model/__init__.py b/deepmd/model/__init__.py new file mode 100644 index 0000000000..e50a138aec --- /dev/null +++ b/deepmd/model/__init__.py @@ -0,0 +1,5 @@ +from .ener import EnerModel +from .tensor import WFCModel +from .tensor import DipoleModel +from .tensor import PolarModel +from .tensor import GlobalPolarModel diff --git a/source/train/model.py b/deepmd/model/ener.py similarity index 53% rename from source/train/model.py rename to deepmd/model/ener.py index 8ccee419bf..26c93ed9ba 100644 --- a/source/train/model.py +++ b/deepmd/model/ener.py @@ -1,92 +1,65 @@ import numpy as np +from typing import Tuple, List + from deepmd.env import tf -from collections import defaultdict from deepmd.utils.pair_tab import PairTab from deepmd.common import ClassArg - from deepmd.run_options import global_cvt_2_ener_float, MODEL_VERSION from deepmd.env import op_module +from .model_stat import make_stat_input, merge_sys_stat - -def _make_all_stat_ref(data, nbatches): - all_stat = defaultdict(list) - for ii in range(data.get_nsystems()) : - for jj in range(nbatches) : - stat_data = data.get_batch (sys_idx = ii) - for dd in stat_data: - if dd == "natoms_vec": - stat_data[dd] = stat_data[dd].astype(np.int32) - all_stat[dd].append(stat_data[dd]) - return all_stat - - -def make_stat_input(data, nbatches, merge_sys = True): - """ - pack data for statistics - Parameters - ---------- - data: - The data - merge_sys: bool (True) - Merge system data - Returns - ------- - all_stat: - A dictionary of list of list storing data for stat. - if merge_sys == False data can be accessed by - all_stat[key][sys_idx][batch_idx][frame_idx] - else merge_sys == True can be accessed by - all_stat[key][batch_idx][frame_idx] - """ - all_stat = defaultdict(list) - for ii in range(data.get_nsystems()) : - sys_stat = defaultdict(list) - for jj in range(nbatches) : - stat_data = data.get_batch (sys_idx = ii) - for dd in stat_data: - if dd == "natoms_vec": - stat_data[dd] = stat_data[dd].astype(np.int32) - sys_stat[dd].append(stat_data[dd]) - for dd in sys_stat: - if merge_sys: - for bb in sys_stat[dd]: - all_stat[dd].append(bb) - else: - all_stat[dd].append(sys_stat[dd]) - return all_stat - -def merge_sys_stat(all_stat): - first_key = list(all_stat.keys())[0] - nsys = len(all_stat[first_key]) - ret = defaultdict(list) - for ii in range(nsys): - for dd in all_stat: - for bb in all_stat[dd][ii]: - ret[dd].append(bb) - return ret - - -class Model() : +class EnerModel() : model_type = 'ener' - def __init__ (self, jdata, descrpt, fitting): + def __init__ ( + self, + descrpt, + fitting, + type_map : List[str], + data_stat_nbatch : int = 10, + data_stat_protect : float = 1e-2, + use_srtab : str = None, + smin_alpha : float = None, + sw_rmin : float = None, + sw_rmax : float = None + ) -> None: + """ + Constructor + + Parameters + ---------- + descrpt + Descriptor + fitting + Fitting net + type_map + Mapping atom type to the name (str) of the type. + For example `type_map[1]` gives the name of the type 1. + data_stat_nbatch + Number of frames used for data statistic + data_stat_protect + Protect parameter for atomic energy regression + use_srtab + The table for the short-range pairwise interaction added on top of DP. The table is a text data file with (N_t + 1) * N_t / 2 + 1 columes. The first colume is the distance between atoms. The second to the last columes are energies for pairs of certain types. For example we have two atom types, 0 and 1. The columes from 2nd to 4th are for 0-0, 0-1 and 1-1 correspondingly. + smin_alpha + The short-range tabulated interaction will be swithed according to the distance of the nearest neighbor. This distance is calculated by softmin. This parameter is the decaying parameter in the softmin. It is only required when `use_srtab` is provided. + sw_rmin + The lower boundary of the interpolation between short-range tabulated interaction and DP. It is only required when `use_srtab` is provided. + sw_rmin + The upper boundary of the interpolation between short-range tabulated interaction and DP. It is only required when `use_srtab` is provided. + """ + # descriptor self.descrpt = descrpt self.rcut = self.descrpt.get_rcut() self.ntypes = self.descrpt.get_ntypes() # fitting self.fitting = fitting self.numb_fparam = self.fitting.get_numb_fparam() - - args = ClassArg()\ - .add('type_map', list, default = []) \ - .add('data_stat_nbatch', int, default = 10) \ - .add('data_stat_protect',float, default = 1e-2) \ - .add('use_srtab', str) - class_data = args.parse(jdata) - self.type_map = class_data['type_map'] - self.srtab_name = class_data['use_srtab'] - self.data_stat_nbatch = class_data['data_stat_nbatch'] - self.data_stat_protect = class_data['data_stat_protect'] + # other inputs + self.type_map = type_map + self.data_stat_nbatch = data_stat_nbatch + self.data_stat_protect = data_stat_protect + self.srtab_name = use_srtab if self.srtab_name is not None : self.srtab = PairTab(self.srtab_name) args.add('smin_alpha', float, must = True)\ @@ -265,126 +238,3 @@ def build (self, return model_dict - -class TensorModel() : - def __init__ (self, jdata, descrpt, fitting, var_name): - self.model_type = var_name - self.descrpt = descrpt - self.rcut = self.descrpt.get_rcut() - self.ntypes = self.descrpt.get_ntypes() - # fitting - self.fitting = fitting - - args = ClassArg()\ - .add('type_map', list, default = []) \ - .add('data_stat_nbatch', int, default = 10) \ - .add('data_stat_protect',float, default = 1e-2) - class_data = args.parse(jdata) - self.type_map = class_data['type_map'] - self.data_stat_nbatch = class_data['data_stat_nbatch'] - self.data_stat_protect = class_data['data_stat_protect'] - - def get_rcut (self) : - return self.rcut - - def get_ntypes (self) : - return self.ntypes - - def get_type_map (self) : - return self.type_map - - def get_sel_type(self): - return self.fitting.get_sel_type() - - def get_out_size (self) : - return self.fitting.get_out_size() - - def data_stat(self, data): - all_stat = make_stat_input(data, self.data_stat_nbatch, merge_sys = False) - m_all_stat = merge_sys_stat(all_stat) - self._compute_input_stat (m_all_stat, protection = self.data_stat_protect) - self._compute_output_stat(all_stat) - - def _compute_input_stat(self, all_stat, protection = 1e-2) : - self.descrpt.compute_input_stats(all_stat['coord'], - all_stat['box'], - all_stat['type'], - all_stat['natoms_vec'], - all_stat['default_mesh'], - all_stat) - if hasattr(self.fitting, 'compute_input_stats'): - self.fitting.compute_input_stats(all_stat, protection = protection) - - def _compute_output_stat (self, all_stat) : - if hasattr(self.fitting, 'compute_output_stats'): - self.fitting.compute_output_stats(all_stat) - - def build (self, - coord_, - atype_, - natoms, - box, - mesh, - input_dict, - suffix = '', - reuse = None): - with tf.variable_scope('model_attr' + suffix, reuse = reuse) : - t_tmap = tf.constant(' '.join(self.type_map), - name = 'tmap', - dtype = tf.string) - t_st = tf.constant(self.get_sel_type(), - name = 'sel_type', - dtype = tf.int32) - t_mt = tf.constant(self.model_type, - name = 'model_type', - dtype = tf.string) - t_ver = tf.constant(MODEL_VERSION, - name = 'model_version', - dtype = tf.string) - t_od = tf.constant(self.get_out_size(), - name = 'output_dim', - dtype = tf.int32) - - dout \ - = self.descrpt.build(coord_, - atype_, - natoms, - box, - mesh, - input_dict, - suffix = suffix, - reuse = reuse) - dout = tf.identity(dout, name='o_descriptor') - rot_mat = self.descrpt.get_rot_mat() - rot_mat = tf.identity(rot_mat, name = 'o_rot_mat') - - output = self.fitting.build (dout, - rot_mat, - natoms, - reuse = reuse, - suffix = suffix) - output = tf.identity(output, name = 'o_' + self.model_type) - - return {self.model_type: output} - - -class WFCModel(TensorModel): - def __init__(self, jdata, descrpt, fitting) : - TensorModel.__init__(self, jdata, descrpt, fitting, 'wfc') - - -class DipoleModel(TensorModel): - def __init__(self, jdata, descrpt, fitting) : - TensorModel.__init__(self, jdata, descrpt, fitting, 'dipole') - - -class PolarModel(TensorModel): - def __init__(self, jdata, descrpt, fitting) : - TensorModel.__init__(self, jdata, descrpt, fitting, 'polar') - - -class GlobalPolarModel(TensorModel): - def __init__(self, jdata, descrpt, fitting) : - TensorModel.__init__(self, jdata, descrpt, fitting, 'global_polar') - - diff --git a/deepmd/model/model_stat.py b/deepmd/model/model_stat.py new file mode 100644 index 0000000000..61f151f27b --- /dev/null +++ b/deepmd/model/model_stat.py @@ -0,0 +1,60 @@ +import numpy as np +from collections import defaultdict + +def _make_all_stat_ref(data, nbatches): + all_stat = defaultdict(list) + for ii in range(data.get_nsystems()) : + for jj in range(nbatches) : + stat_data = data.get_batch (sys_idx = ii) + for dd in stat_data: + if dd == "natoms_vec": + stat_data[dd] = stat_data[dd].astype(np.int32) + all_stat[dd].append(stat_data[dd]) + return all_stat + + +def make_stat_input(data, nbatches, merge_sys = True): + """ + pack data for statistics + Parameters + ---------- + data: + The data + merge_sys: bool (True) + Merge system data + Returns + ------- + all_stat: + A dictionary of list of list storing data for stat. + if merge_sys == False data can be accessed by + all_stat[key][sys_idx][batch_idx][frame_idx] + else merge_sys == True can be accessed by + all_stat[key][batch_idx][frame_idx] + """ + all_stat = defaultdict(list) + for ii in range(data.get_nsystems()) : + sys_stat = defaultdict(list) + for jj in range(nbatches) : + stat_data = data.get_batch (sys_idx = ii) + for dd in stat_data: + if dd == "natoms_vec": + stat_data[dd] = stat_data[dd].astype(np.int32) + sys_stat[dd].append(stat_data[dd]) + for dd in sys_stat: + if merge_sys: + for bb in sys_stat[dd]: + all_stat[dd].append(bb) + else: + all_stat[dd].append(sys_stat[dd]) + return all_stat + +def merge_sys_stat(all_stat): + first_key = list(all_stat.keys())[0] + nsys = len(all_stat[first_key]) + ret = defaultdict(list) + for ii in range(nsys): + for dd in all_stat: + for bb in all_stat[dd][ii]: + ret[dd].append(bb) + return ret + diff --git a/deepmd/model/tensor.py b/deepmd/model/tensor.py new file mode 100644 index 0000000000..fa60171255 --- /dev/null +++ b/deepmd/model/tensor.py @@ -0,0 +1,151 @@ +import numpy as np +from typing import Tuple, List + +from deepmd.env import tf +from deepmd.common import ClassArg +from deepmd.run_options import global_cvt_2_ener_float, MODEL_VERSION +from deepmd.env import op_module +from .model_stat import make_stat_input, merge_sys_stat + +class TensorModel() : + def __init__ ( + self, + tensor_name : str, + descrpt, + fitting, + type_map : List[str], + data_stat_nbatch : int = 10, + data_stat_protect : float = 1e-2, + )->None: + """ + Constructor + + Parameters + ---------- + tensor_name + Name of the tensor. + descrpt + Descriptor + fitting + Fitting net + type_map + Mapping atom type to the name (str) of the type. + For example `type_map[1]` gives the name of the type 1. + data_stat_nbatch + Number of frames used for data statistic + data_stat_protect + Protect parameter for atomic energy regression + """ + self.model_type = tensor_name + # descriptor + self.descrpt = descrpt + self.rcut = self.descrpt.get_rcut() + self.ntypes = self.descrpt.get_ntypes() + # fitting + self.fitting = fitting + # other params + self.type_map = type_map + self.data_stat_nbatch = data_stat_nbatch + self.data_stat_protect = data_stat_protect + + def get_rcut (self) : + return self.rcut + + def get_ntypes (self) : + return self.ntypes + + def get_type_map (self) : + return self.type_map + + def get_sel_type(self): + return self.fitting.get_sel_type() + + def get_out_size (self) : + return self.fitting.get_out_size() + + def data_stat(self, data): + all_stat = make_stat_input(data, self.data_stat_nbatch, merge_sys = False) + m_all_stat = merge_sys_stat(all_stat) + self._compute_input_stat (m_all_stat, protection = self.data_stat_protect) + self._compute_output_stat(all_stat) + + def _compute_input_stat(self, all_stat, protection = 1e-2) : + self.descrpt.compute_input_stats(all_stat['coord'], + all_stat['box'], + all_stat['type'], + all_stat['natoms_vec'], + all_stat['default_mesh'], + all_stat) + if hasattr(self.fitting, 'compute_input_stats'): + self.fitting.compute_input_stats(all_stat, protection = protection) + + def _compute_output_stat (self, all_stat) : + if hasattr(self.fitting, 'compute_output_stats'): + self.fitting.compute_output_stats(all_stat) + + def build (self, + coord_, + atype_, + natoms, + box, + mesh, + input_dict, + suffix = '', + reuse = None): + with tf.variable_scope('model_attr' + suffix, reuse = reuse) : + t_tmap = tf.constant(' '.join(self.type_map), + name = 'tmap', + dtype = tf.string) + t_st = tf.constant(self.get_sel_type(), + name = 'sel_type', + dtype = tf.int32) + t_mt = tf.constant(self.model_type, + name = 'model_type', + dtype = tf.string) + t_ver = tf.constant(MODEL_VERSION, + name = 'model_version', + dtype = tf.string) + t_od = tf.constant(self.get_out_size(), + name = 'output_dim', + dtype = tf.int32) + + dout \ + = self.descrpt.build(coord_, + atype_, + natoms, + box, + mesh, + input_dict, + suffix = suffix, + reuse = reuse) + dout = tf.identity(dout, name='o_descriptor') + rot_mat = self.descrpt.get_rot_mat() + rot_mat = tf.identity(rot_mat, name = 'o_rot_mat') + + output = self.fitting.build (dout, + rot_mat, + natoms, + reuse = reuse, + suffix = suffix) + output = tf.identity(output, name = 'o_' + self.model_type) + + return {self.model_type: output} + + +class WFCModel(TensorModel): + def __init__(self, descrpt, fitting, tm, dsn, dsp) : + TensorModel.__init__(self, 'wfc', descrpt, fitting, tm, dsn, dsp) + +class DipoleModel(TensorModel): + def __init__(self, descrpt, fitting, tm, dsn, dsp) : + TensorModel.__init__(self, 'dipole', descrpt, fitting, tm, dsn, dsp) + +class PolarModel(TensorModel): + def __init__(self, descrpt, fitting, tm, dsn, dsp) : + TensorModel.__init__(self, 'polar', descrpt, fitting, tm, dsn, dsp) + +class GlobalPolarModel(TensorModel): + def __init__(self, descrpt, fitting, tm, dsn, dsp) : + TensorModel.__init__(self, 'global_polar', descrpt, fitting, tm, dsn, dsp) + + diff --git a/deepmd/utils/argcheck.py b/deepmd/utils/argcheck.py index a3f4d56b1e..ac993ef107 100644 --- a/deepmd/utils/argcheck.py +++ b/deepmd/utils/argcheck.py @@ -276,6 +276,7 @@ def fitting_variant_type_args(): def model_args (): doc_type_map = 'A list of strings. Give the name to each type of atoms.' doc_data_stat_nbatch = 'The model determines the normalization from the statistics of the data. This key specifies the number of `frames` in each `system` used for statistics.' + doc_data_stat_protect = 'Protect parameter for atomic energy regression.' doc_descrpt = 'The descriptor of atomic environment.' doc_fitting = 'The fitting of physical properties.' doc_use_srtab = 'The table for the short-range pairwise interaction added on top of DP. The table is a text data file with (N_t + 1) * N_t / 2 + 1 columes. The first colume is the distance between atoms. The second to the last columes are energies for pairs of certain types. For example we have two atom types, 0 and 1. The columes from 2nd to 4th are for 0-0, 0-1 and 1-1 correspondingly.' @@ -286,6 +287,7 @@ def model_args (): ca = Argument("model", dict, [Argument("type_map", list, optional = True, doc = doc_type_map), Argument("data_stat_nbatch", int, optional = True, default = 10, doc = doc_data_stat_nbatch), + Argument("data_stat_protect", float, optional = True, default = 1e-2, doc = doc_data_stat_protect), Argument("use_srtab", str, optional = True, doc = doc_use_srtab), Argument("smin_alpha", float, optional = True, doc = doc_smin_alpha), Argument("sw_rmin", float, optional = True, doc = doc_sw_rmin), diff --git a/setup.py b/setup.py index 729d62650d..a415187f35 100644 --- a/setup.py +++ b/setup.py @@ -86,7 +86,8 @@ "deepmd/loggers", "deepmd/cluster", "deepmd/entrypoints", - "deepmd/op" + "deepmd/op", + "deepmd/model", ], python_requires=">=3.6", classifiers=[ diff --git a/source/train/CMakeLists.txt b/source/train/CMakeLists.txt index 8a5317a1d0..8dd7c60d04 100644 --- a/source/train/CMakeLists.txt +++ b/source/train/CMakeLists.txt @@ -2,7 +2,7 @@ configure_file("run_config.ini" "${CMAKE_CURRENT_BINARY_DIR}/run_config.ini" @ONLY) -file(GLOB LIB_PY main.py calculator.py model.py trainer.py run_options.py ) +file(GLOB LIB_PY main.py calculator.py trainer.py run_options.py ) install( FILES ${LIB_PY} @@ -11,4 +11,4 @@ install( install( FILES ${CMAKE_CURRENT_BINARY_DIR}/run_config.ini DESTINATION deepmd/pkg_config -) \ No newline at end of file +) diff --git a/source/train/trainer.py b/source/train/trainer.py index d730a2980a..5331af84c6 100644 --- a/source/train/trainer.py +++ b/source/train/trainer.py @@ -17,7 +17,7 @@ from deepmd.descriptor import DescrptSeR from deepmd.descriptor import DescrptSeAR from deepmd.descriptor import DescrptHybrid -from deepmd.model import Model, WFCModel, DipoleModel, PolarModel, GlobalPolarModel +from deepmd.model import EnerModel, WFCModel, DipoleModel, PolarModel, GlobalPolarModel from deepmd.loss import EnerStdLoss, EnerDipoleLoss, TensorLoss from deepmd.utils.learning_rate import LearningRateExp from deepmd.utils.neighbor_stat import NeighborStat @@ -134,16 +134,44 @@ def _init_param(self, jdata): # init model # infer model type by fitting_type - if fitting_type == Model.model_type: - self.model = Model(model_param, self.descrpt, self.fitting) + if fitting_type == 'ener': + self.model = EnerModel( + self.descrpt, + self.fitting, + model_param['type_map'], + model_param['data_stat_nbatch'], + model_param['data_stat_protect'], + model_param.get('use_srtab'), + model_param.get('smin_alpha'), + model_param.get('sw_rmin'), + model_param.get('sw_rmax') + ) # elif fitting_type == 'wfc': # self.model = WFCModel(model_param, self.descrpt, self.fitting) elif fitting_type == 'dipole': - self.model = DipoleModel(model_param, self.descrpt, self.fitting) + self.model = DipoleModel( + self.descrpt, + self.fitting, + model_param['type_map'], + model_param['data_stat_nbatch'], + model_param['data_stat_protect'] + ) elif fitting_type == 'polar': - self.model = PolarModel(model_param, self.descrpt, self.fitting) + self.model = PolarModel( + self.descrpt, + self.fitting, + model_param['type_map'], + model_param['data_stat_nbatch'], + model_param['data_stat_protect'] + ) elif fitting_type == 'global_polar': - self.model = GlobalPolarModel(model_param, self.descrpt, self.fitting) + self.model = GlobalPolarModel( + self.descrpt, + self.fitting, + model_param['type_map'], + model_param['data_stat_nbatch'], + model_param['data_stat_protect'] + ) else : raise RuntimeError('get unknown fitting type when building model') From d72252622e66067923d56e70ebc2b69c4af18bd1 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 27 Mar 2021 08:56:41 +0800 Subject: [PATCH 297/562] fix bug of getting inputs --- source/train/trainer.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/source/train/trainer.py b/source/train/trainer.py index 5331af84c6..fd9962ec90 100644 --- a/source/train/trainer.py +++ b/source/train/trainer.py @@ -138,9 +138,9 @@ def _init_param(self, jdata): self.model = EnerModel( self.descrpt, self.fitting, - model_param['type_map'], - model_param['data_stat_nbatch'], - model_param['data_stat_protect'], + model_param.get('type_map'), + model_param.get('data_stat_nbatch', 10), + model_param.get('data_stat_protect', 1e-2), model_param.get('use_srtab'), model_param.get('smin_alpha'), model_param.get('sw_rmin'), @@ -152,25 +152,25 @@ def _init_param(self, jdata): self.model = DipoleModel( self.descrpt, self.fitting, - model_param['type_map'], - model_param['data_stat_nbatch'], - model_param['data_stat_protect'] + model_param.get('type_map'), + model_param.get('data_stat_nbatch', 10), + model_param.get('data_stat_protect', 1e-2) ) elif fitting_type == 'polar': self.model = PolarModel( self.descrpt, self.fitting, - model_param['type_map'], - model_param['data_stat_nbatch'], - model_param['data_stat_protect'] + model_param.get('type_map'), + model_param.get('data_stat_nbatch', 10), + model_param.get('data_stat_protect', 1e-2) ) elif fitting_type == 'global_polar': self.model = GlobalPolarModel( self.descrpt, self.fitting, - model_param['type_map'], - model_param['data_stat_nbatch'], - model_param['data_stat_protect'] + model_param.get('type_map'), + model_param.get('data_stat_nbatch', 10), + model_param.get('data_stat_protect', 1e-2) ) else : raise RuntimeError('get unknown fitting type when building model') From 716a7fa0358d8765affda7035ff82636e5164785 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 27 Mar 2021 09:26:43 +0800 Subject: [PATCH 298/562] fix bug of UTs and srtab --- deepmd/model/ener.py | 17 ++++++++--------- source/tests/test_gen_stat_data.py | 2 +- source/tests/test_model_loc_frame.py | 7 +++++-- source/tests/test_model_se_a.py | 4 ++-- source/tests/test_model_se_a_aparam.py | 4 ++-- source/tests/test_model_se_a_fparam.py | 4 ++-- source/tests/test_model_se_a_srtab.py | 22 ++++++++++++++++------ source/tests/test_model_se_r.py | 4 ++-- 8 files changed, 38 insertions(+), 26 deletions(-) diff --git a/deepmd/model/ener.py b/deepmd/model/ener.py index 26c93ed9ba..56f4880840 100644 --- a/deepmd/model/ener.py +++ b/deepmd/model/ener.py @@ -15,7 +15,7 @@ def __init__ ( self, descrpt, fitting, - type_map : List[str], + type_map : List[str] = None, data_stat_nbatch : int = 10, data_stat_protect : float = 1e-2, use_srtab : str = None, @@ -56,19 +56,18 @@ def __init__ ( self.fitting = fitting self.numb_fparam = self.fitting.get_numb_fparam() # other inputs - self.type_map = type_map + if type_map is None: + self.type_map = [] + else: + self.type_map = type_map self.data_stat_nbatch = data_stat_nbatch self.data_stat_protect = data_stat_protect self.srtab_name = use_srtab if self.srtab_name is not None : self.srtab = PairTab(self.srtab_name) - args.add('smin_alpha', float, must = True)\ - .add('sw_rmin', float, must = True)\ - .add('sw_rmax', float, must = True) - class_data = args.parse(jdata) - self.smin_alpha = class_data['smin_alpha'] - self.sw_rmin = class_data['sw_rmin'] - self.sw_rmax = class_data['sw_rmax'] + self.smin_alpha = smin_alpha + self.sw_rmin = sw_rmin + self.sw_rmax = sw_rmax else : self.srtab = None diff --git a/source/tests/test_gen_stat_data.py b/source/tests/test_gen_stat_data.py index f70d63c3e9..62647efba1 100644 --- a/source/tests/test_gen_stat_data.py +++ b/source/tests/test_gen_stat_data.py @@ -5,7 +5,7 @@ from deepmd.utils.data_system import DeepmdDataSystem from deepmd.fit import EnerFitting -from deepmd.model import make_stat_input, merge_sys_stat, _make_all_stat_ref +from deepmd.model.model_stat import make_stat_input, merge_sys_stat, _make_all_stat_ref def gen_sys(nframes, atom_types): natoms = len(atom_types) diff --git a/source/tests/test_model_loc_frame.py b/source/tests/test_model_loc_frame.py index b0d189e528..c94b71be01 100644 --- a/source/tests/test_model_loc_frame.py +++ b/source/tests/test_model_loc_frame.py @@ -6,7 +6,7 @@ from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptLocFrame from deepmd.fit import EnerFitting -from deepmd.model import Model +from deepmd.model import EnerModel from deepmd.common import j_must_have GLOBAL_ENER_FLOAT_PRECISION = tf.float64 @@ -41,7 +41,10 @@ def test_model(self): fitting = EnerFitting(descrpt, neuron = [240, 120, 60, 30, 10], seed = 1) - model = Model(jdata['model'], descrpt, fitting) + model = EnerModel( + descrpt, + fitting, + ) # model._compute_dstats([test_data['coord']], [test_data['box']], [test_data['type']], [test_data['natoms_vec']], [test_data['default_mesh']]) input_data = {'coord' : [test_data['coord']], diff --git a/source/tests/test_model_se_a.py b/source/tests/test_model_se_a.py index da6f7af3e0..837d344f90 100644 --- a/source/tests/test_model_se_a.py +++ b/source/tests/test_model_se_a.py @@ -7,7 +7,7 @@ from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting -from deepmd.model import Model +from deepmd.model import EnerModel from deepmd.common import j_must_have GLOBAL_ENER_FLOAT_PRECISION = tf.float64 @@ -40,7 +40,7 @@ def test_model(self): descrpt = DescrptSeA(**jdata['model']['descriptor']) jdata['model']['fitting_net']['descrpt'] = descrpt fitting = EnerFitting(**jdata['model']['fitting_net']) - model = Model(jdata['model'], descrpt, fitting) + model = EnerModel(descrpt, fitting) # model._compute_dstats([test_data['coord']], [test_data['box']], [test_data['type']], [test_data['natoms_vec']], [test_data['default_mesh']]) input_data = {'coord' : [test_data['coord']], diff --git a/source/tests/test_model_se_a_aparam.py b/source/tests/test_model_se_a_aparam.py index c3879604f0..7a07a30d20 100644 --- a/source/tests/test_model_se_a_aparam.py +++ b/source/tests/test_model_se_a_aparam.py @@ -6,7 +6,7 @@ from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting -from deepmd.model import Model +from deepmd.model import EnerModel from deepmd.common import j_must_have GLOBAL_ENER_FLOAT_PRECISION = tf.float64 @@ -40,7 +40,7 @@ def test_model(self): descrpt = DescrptSeA(**jdata['model']['descriptor']) jdata['model']['fitting_net']['descrpt'] = descrpt fitting = EnerFitting(**jdata['model']['fitting_net']) - model = Model(jdata['model'], descrpt, fitting) + model = EnerModel(descrpt, fitting) # model._compute_dstats([test_data['coord']], [test_data['box']], [test_data['type']], [test_data['natoms_vec']], [test_data['default_mesh']]) input_data = {'coord' : [test_data['coord']], diff --git a/source/tests/test_model_se_a_fparam.py b/source/tests/test_model_se_a_fparam.py index 36719c9a29..a045c5e520 100644 --- a/source/tests/test_model_se_a_fparam.py +++ b/source/tests/test_model_se_a_fparam.py @@ -6,7 +6,7 @@ from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting -from deepmd.model import Model +from deepmd.model import EnerModel from deepmd.common import j_must_have GLOBAL_ENER_FLOAT_PRECISION = tf.float64 @@ -41,7 +41,7 @@ def test_model(self): fitting = EnerFitting(**jdata['model']['fitting_net']) # descrpt = DescrptSeA(jdata['model']['descriptor']) # fitting = EnerFitting(jdata['model']['fitting_net'], descrpt) - model = Model(jdata['model'], descrpt, fitting) + model = EnerModel(descrpt, fitting) # model._compute_dstats([test_data['coord']], [test_data['box']], [test_data['type']], [test_data['natoms_vec']], [test_data['default_mesh']]) input_data = {'coord' : [test_data['coord']], diff --git a/source/tests/test_model_se_a_srtab.py b/source/tests/test_model_se_a_srtab.py index bd3e69cf67..f1d70a93ff 100644 --- a/source/tests/test_model_se_a_srtab.py +++ b/source/tests/test_model_se_a_srtab.py @@ -6,7 +6,7 @@ from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeA from deepmd.fit import EnerFitting -from deepmd.model import Model +from deepmd.model import EnerModel from deepmd.common import j_must_have GLOBAL_ENER_FLOAT_PRECISION = tf.float64 @@ -28,7 +28,7 @@ def setUp(self) : gen_data() def test_model(self): - jfile = 'water_se_a.json' + jfile = 'water_se_a_srtab.json' jdata = j_loader(jfile) systems = j_must_have(jdata, 'systems') @@ -51,7 +51,17 @@ def test_model(self): fitting = EnerFitting(**jdata['model']['fitting_net']) # descrpt = DescrptSeA(jdata['model']['descriptor']) # fitting = EnerFitting(jdata['model']['fitting_net'], descrpt) - model = Model(jdata['model'], descrpt, fitting) + model = EnerModel( + descrpt, + fitting, + jdata['model'].get('type_map'), + jdata['model'].get('data_stat_nbatch'), + jdata['model'].get('data_stat_protect'), + jdata['model'].get('use_srtab'), + jdata['model'].get('smin_alpha'), + jdata['model'].get('sw_rmin'), + jdata['model'].get('sw_rmax') + ) # model._compute_dstats([test_data['coord']], [test_data['box']], [test_data['type']], [test_data['natoms_vec']], [test_data['default_mesh']]) input_data = {'coord' : [test_data['coord']], @@ -111,9 +121,9 @@ def test_model(self): f = f.reshape([-1]) v = v.reshape([-1]) - refe = [6.135449167779321300e+01] - reff = [7.799691562262310585e-02,9.423098804815030483e-02,3.790560997388224204e-03,1.432522403799846578e-01,1.148392791403983204e-01,-1.321871172563671148e-02,-7.318966526325138000e-02,6.516069212737778116e-02,5.406418483320515412e-04,5.870713761026503247e-02,-1.605402669549013672e-01,-5.089516979826595386e-03,-2.554593467731766654e-01,3.092063507347833987e-02,1.510355029451411479e-02,4.869271842355533952e-02,-1.446113274345035005e-01,-1.126524434771078789e-03] - refv = [-6.076776685178300053e-01,1.103174323630009418e-01,1.984250991380156690e-02,1.103174323630009557e-01,-3.319759402259439551e-01,-6.007404107650986258e-03,1.984250991380157036e-02,-6.007404107650981921e-03,-1.200076017439753642e-03] + refe = [1.141610882066236599e+02] + reff = [-1.493121233165248043e+02,-1.831419491743885715e+02,-8.439542992300344437e+00,-1.811987095947552859e+02,-1.476380826187439084e+02,1.264271856742560018e+01,1.544377958934875323e+02,-7.816520233903435866e+00,1.287925245463442225e+00,-4.000393268449002449e+00,1.910748885843098890e+02,7.134789955349889468e+00,1.826908441979261113e+02,3.677156386479059513e+00,-1.122312112141401741e+01,-2.617413911684622008e+00,1.438445070562470391e+02,-1.402769654524568033e+00] + refv = [3.585047655925112622e+02,-7.569252978336677984e+00,-1.068382043878426124e+01,-7.569252978336677096e+00,3.618439481685132932e+02,5.448668500896081568e+00,-1.068382043878426302e+01,5.448668500896082456e+00,1.050393462151727686e+00] refe = np.reshape(refe, [-1]) reff = np.reshape(reff, [-1]) refv = np.reshape(refv, [-1]) diff --git a/source/tests/test_model_se_r.py b/source/tests/test_model_se_r.py index f7d2fa07fe..f178dbda56 100644 --- a/source/tests/test_model_se_r.py +++ b/source/tests/test_model_se_r.py @@ -6,7 +6,7 @@ from deepmd.utils.data_system import DataSystem from deepmd.descriptor import DescrptSeR from deepmd.fit import EnerFitting -from deepmd.model import Model +from deepmd.model import EnerModel from deepmd.common import j_must_have GLOBAL_ENER_FLOAT_PRECISION = tf.float64 @@ -40,7 +40,7 @@ def test_model(self): jdata['model']['fitting_net']['descrpt'] = descrpt fitting = EnerFitting(**jdata['model']['fitting_net']) # fitting = EnerFitting(jdata['model']['fitting_net'], descrpt) - model = Model(jdata['model'], descrpt, fitting) + model = EnerModel(descrpt, fitting) # model._compute_dstats([test_data['coord']], [test_data['box']], [test_data['type']], [test_data['natoms_vec']], [test_data['default_mesh']]) input_data = {'coord' : [test_data['coord']], From 5ba6456cefb6d043b6af800cf6c7214fb7a9c2be Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 27 Mar 2021 09:54:42 +0800 Subject: [PATCH 299/562] fix bug of gen tab.xvg --- source/tests/test_model_se_a_srtab.py | 4 ++++ source/tests/test_tab_nonsmth.py | 3 +++ source/tests/test_tab_smooth.py | 3 +++ 3 files changed, 10 insertions(+) diff --git a/source/tests/test_model_se_a_srtab.py b/source/tests/test_model_se_a_srtab.py index f1d70a93ff..7ef371ae3b 100644 --- a/source/tests/test_model_se_a_srtab.py +++ b/source/tests/test_model_se_a_srtab.py @@ -26,6 +26,10 @@ def _make_tab(ntype) : class TestModel(unittest.TestCase): def setUp(self) : gen_data() + _make_tab(2) + + def tearDown(self): + os.remove('tab.xvg') def test_model(self): jfile = 'water_se_a_srtab.json' diff --git a/source/tests/test_tab_nonsmth.py b/source/tests/test_tab_nonsmth.py index 9181ba5977..f6496bbb1d 100644 --- a/source/tests/test_tab_nonsmth.py +++ b/source/tests/test_tab_nonsmth.py @@ -51,6 +51,9 @@ def setUp (self, dtype = tf.float64, trainable = False, initializer = tf.constant_initializer(tab_data)) + + def tearDown(self): + os.remove('tab.xvg') def comp_interpl_ef (self, dcoord, diff --git a/source/tests/test_tab_smooth.py b/source/tests/test_tab_smooth.py index 2917582446..ad6ad22044 100644 --- a/source/tests/test_tab_smooth.py +++ b/source/tests/test_tab_smooth.py @@ -51,6 +51,9 @@ def setUp (self, dtype = tf.float64, trainable = False, initializer = tf.constant_initializer(tab_data)) + + def tearDown(self): + os.remove('tab.xvg') def comp_ef (self, dcoord, From 8cfc0e839f66d6e69705cfefdf256d7388ca0ac6 Mon Sep 17 00:00:00 2001 From: Duo Date: Sat, 27 Mar 2021 17:35:37 +0800 Subject: [PATCH 300/562] prod_env_mat gpu update prod_env_mat gpu update --- source/lib/include/coord.h | 55 ++++ source/lib/include/gpu_cuda.h | 19 +- source/lib/include/neighbor_list.h | 30 ++ source/lib/src/coord.cc | 28 ++ source/lib/src/cuda/CMakeLists.txt | 2 +- source/lib/src/cuda/coord.cu | 378 +++++++++++++++++++++++++ source/lib/src/cuda/neighbor_list.cu | 178 ++++++++++++ source/lib/tests/test_coord.cc | 207 ++++++++++++++ source/lib/tests/test_neighbor_list.cc | 110 +++++++ source/op/prod_env_mat_multi_device.cc | 375 +++++++++++++++++++++--- 10 files changed, 1342 insertions(+), 40 deletions(-) create mode 100644 source/lib/src/cuda/coord.cu create mode 100644 source/lib/src/cuda/neighbor_list.cu diff --git a/source/lib/include/coord.h b/source/lib/include/coord.h index 0da8eedd23..7aeede656a 100644 --- a/source/lib/include/coord.h +++ b/source/lib/include/coord.h @@ -36,4 +36,59 @@ copy_coord_cpu( const float & rcut, const deepmd::Region & region); +// compute cell information +// output: +// cell_info: nat_stt,ncell,ext_stt,ext_end,ngcell,cell_shift,cell_iter,total_cellnum,loc_cellnum +// input: +// boxt +void +compute_cell_info( + int * cell_info, + const float & rcut, + const double * boxt +); + +#if GOOGLE_CUDA +// normalize coords +// output: +// coord +// input: +// natom, box_info: boxt, rec_boxt +template +void +normalize_coord_gpu( + FPTYPE * coord, + const int natom, + const double * box_info); + +// copy coordinates +// outputs: +// out_c, out_t, mapping, nall, +// int_data(temp cuda memory):idx_map,idx_map_noshift,temp_idx_order,loc_cellnum_map,total_cellnum_map,mask_cellnum_map, +// cell_map,cell_shift_map,sec_loc_cellnum_map,sec_total_cellnum_map,loc_clist +// inputs: +// in_c, in_t, nloc, mem_nall, loc_cellnum, total_cellnum, cell_info, box_info +// mem_nall is the size of allocated memory for out_c, out_t, mapping +// returns +// 0: succssful +// 1: the memory is not large enough to hold all copied coords and types. +// i.e. nall > mem_nall +template +int +copy_coord_gpu( + FPTYPE * out_c, + int * out_t, + int * mapping, + int * nall, + int * int_data, + const FPTYPE * in_c, + const int * in_t, + const int & nloc, + const int & mem_nall, + const int & loc_cellnum, + const int & total_cellnum, + const int * cell_info, + const double * box_info); +#endif // GOOGLE_CUDA + } diff --git a/source/lib/include/gpu_cuda.h b/source/lib/include/gpu_cuda.h index 48db721436..570db416fb 100644 --- a/source/lib/include/gpu_cuda.h +++ b/source/lib/include/gpu_cuda.h @@ -34,7 +34,7 @@ namespace deepmd { template void memcpy_host_to_device( FPTYPE * device, - std::vector &host) + const std::vector &host) { cudaErrcheck(cudaMemcpy(device, &host[0], sizeof(FPTYPE) * host.size(), cudaMemcpyHostToDevice)); } @@ -42,7 +42,7 @@ void memcpy_host_to_device( template void memcpy_host_to_device( FPTYPE * device, - FPTYPE * host, + const FPTYPE * host, const int size) { cudaErrcheck(cudaMemcpy(device, host, sizeof(FPTYPE) * size, cudaMemcpyHostToDevice)); @@ -50,16 +50,25 @@ void memcpy_host_to_device( template void memcpy_device_to_host( - FPTYPE * device, + const FPTYPE * device, std::vector &host) { cudaErrcheck(cudaMemcpy(&host[0], device, sizeof(FPTYPE) * host.size(), cudaMemcpyDeviceToHost)); } +template +void memcpy_device_to_host( + const FPTYPE * device, + FPTYPE * host, + const int size) +{ + cudaErrcheck(cudaMemcpy(host, device, sizeof(FPTYPE) * size, cudaMemcpyDeviceToHost)); +} + template void malloc_device_memory( FPTYPE * &device, - std::vector &host) + const std::vector &host) { cudaErrcheck(cudaMalloc((void **)&device, sizeof(FPTYPE) * host.size())); } @@ -75,7 +84,7 @@ void malloc_device_memory( template void malloc_device_memory_sync( FPTYPE * &device, - std::vector &host) + const std::vector &host) { cudaErrcheck(cudaMalloc((void **)&device, sizeof(FPTYPE) * host.size())); memcpy_host_to_device(device, host); diff --git a/source/lib/include/neighbor_list.h b/source/lib/include/neighbor_list.h index ddcf64846c..b14524db50 100644 --- a/source/lib/include/neighbor_list.h +++ b/source/lib/include/neighbor_list.h @@ -71,6 +71,36 @@ void convert_nlist_gpu_cuda( const int & max_nbor_size); void free_nlist_gpu_cuda(InputNlist & gpu_nlist); + +// build neighbor list. +// outputs +// nlist, max_list_size +// max_list_size is the maximal size of jlist. +// inputs +// c_cpy, nloc, nall, mem_size, rcut, region +// mem_size is the size of allocated memory for jlist. +// returns +// 0: succssful +// 1: the memory is not large enough to hold all neighbors. +// i.e. max_list_size > mem_nall +template +int +build_nlist_gpu( + InputNlist & nlist, + int * max_list_size, + int * nlist_data, + const FPTYPE * c_cpy, + const int & nloc, + const int & nall, + const int & mem_size, + const float & rcut); + +void use_nlist_map( + int * nlist, + const int * nlist_map, + const int nloc, + const int nnei); + #endif // GOOGLE_CUDA } // namespace deepmd diff --git a/source/lib/src/coord.cc b/source/lib/src/coord.cc index 81c44f4925..6c9bb3bb04 100644 --- a/source/lib/src/coord.cc +++ b/source/lib/src/coord.cc @@ -68,6 +68,34 @@ copy_coord_cpu( return 0; } +void +deepmd:: +compute_cell_info( + int * cell_info, //nat_stt,ncell,ext_stt,ext_end,ngcell,cell_shift,cell_iter,loc_cellnum,total_cellnum + const float & rcut, + const double * boxt +) +{ + SimulationRegion region; + double to_face [3]; + region.reinitBox(boxt); + region.toFaceDistance (to_face); + double cell_size [3]; + for (int dd = 0; dd < 3; ++dd){ + cell_info[dd]=0; //nat_stt + cell_info[3+dd] = to_face[dd] / rcut; //ncell + if (cell_info[3+dd] == 0) cell_info[3+dd] = 1; + cell_size[dd] = to_face[dd] / cell_info[3+dd]; + cell_info[12+dd] = int(rcut / cell_size[dd]) + 1; //ngcell + cell_info[6+dd]=-cell_info[12+dd]; //ext_stt + cell_info[9+dd]=cell_info[3+dd]+cell_info[12+dd]; //ext_end + cell_info[15+dd]=cell_info[12+dd]; //cell_shift + cell_info[18+dd]= rcut / cell_size[dd]; //cell_iter + if (cell_info[18+dd] * cell_size[dd] < rcut) cell_info[18+dd] += 1; + } + cell_info[21] = (cell_info[3+0]) * (cell_info[3+1]) * (cell_info[3+2]); //loc_cellnum + cell_info[22] = (2 * cell_info[12+0] + cell_info[3+0]) * (2 * cell_info[12+1] + cell_info[3+1]) * (2 * cell_info[12+2] + cell_info[3+2]); //total_cellnum +} template void diff --git a/source/lib/src/cuda/CMakeLists.txt b/source/lib/src/cuda/CMakeLists.txt index da21899dcf..540f616379 100644 --- a/source/lib/src/cuda/CMakeLists.txt +++ b/source/lib/src/cuda/CMakeLists.txt @@ -106,7 +106,7 @@ endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -DCUB_IGNORE_DEPRECATED_CPP_DIALECT -DCUB_IGNORE_DEPRECATED_CPP_DIALECT") set (SOURCE_FILES - prod_env_mat.cu prod_force.cu prod_virial.cu gelu.cu tabulate.cu + prod_env_mat.cu prod_force.cu prod_virial.cu gelu.cu tabulate.cu coord.cu neighbor_list.cu ) cuda_add_library(deepmd_op_cuda SHARED ${SOURCE_FILES}) diff --git a/source/lib/src/cuda/coord.cu b/source/lib/src/cuda/coord.cu new file mode 100644 index 0000000000..e3e856f550 --- /dev/null +++ b/source/lib/src/cuda/coord.cu @@ -0,0 +1,378 @@ +#include "device.h" +#include "gpu_cuda.h" +#include "coord.h" + +template +__device__ inline void tensorDotVector(FPTYPE *o_v, const FPTYPE *i_v, const double *i_t) +{ + o_v[0] = i_v[0] * i_t[0*3+0] + i_v[1] * i_t[0*3+1] + i_v[2] * i_t[0*3+2]; + o_v[1] = i_v[0] * i_t[1*3+0] + i_v[1] * i_t[1*3+1] + i_v[2] * i_t[1*3+2]; + o_v[2] = i_v[0] * i_t[2*3+0] + i_v[1] * i_t[2*3+1] + i_v[2] * i_t[2*3+2]; +} +template +__device__ inline void tensorTransDotVector(FPTYPE *o_v, const FPTYPE *i_v, const double *i_t) +{ + o_v[0] = i_v[0] * i_t[0*3+0] + i_v[1] * i_t[1*3+0] + i_v[2] * i_t[2*3+0]; + o_v[1] = i_v[0] * i_t[0*3+1] + i_v[1] * i_t[1*3+1] + i_v[2] * i_t[2*3+1]; + o_v[2] = i_v[0] * i_t[0*3+2] + i_v[1] * i_t[1*3+2] + i_v[2] * i_t[2*3+2]; +} +template +__device__ inline void phys2Inter(FPTYPE *inter, const FPTYPE *phys, const double *rec_boxt) +{ + tensorDotVector(inter, phys, rec_boxt); +} +template +__device__ inline void inter2Phys(FPTYPE *phys, const FPTYPE *inter, const double *boxt) +{ + tensorTransDotVector(phys, inter, boxt); +} +__device__ inline int collapse_index(const int * idx,const int * size) +{ + return (idx[0] * size[1] + idx[1]) * size[2] + idx[2]; +} +__device__ inline void index_recover(const int in_idx,const int * size, int * idx) +{ + idx[2]=in_idx%size[2]; + idx[1]=int(in_idx/size[2])%size[1]; + idx[0]=int(int(in_idx/size[2])/size[1]); +} +__device__ inline void idx_addshift(int * idx, const int * shift) +{ + for(int dd=0;dd<3;dd++) + { + idx[dd]+=shift[dd]; + } +} +__device__ inline void idx_unshift(int * idx, const int * shift) +{ + for(int dd=0;dd<3;dd++) + { + idx[dd]-=shift[dd]; + } +} +__device__ inline int compute_pbc_shift (int idx, int ncell) +{ + int shift = 0; + if (idx < 0) { + shift = 1; + while (idx + shift * ncell < 0) shift ++; + } + else if (idx >= ncell) { + shift = -1; + while (idx + shift * ncell >= ncell) shift --; + } + return shift; +} + +template +__global__ void normalize_one( + FPTYPE *out_c, + const double *boxt, + const double *rec_boxt, + const int nall +) +{ + // <<>> + int idy=blockIdx.x*blockDim.x+threadIdx.x; + if (idy>=nall){return;} + FPTYPE inter[3]; + phys2Inter(inter,out_c+idy*3,rec_boxt); + for (int dd = 0; dd < 3; ++dd) { + while(inter[dd] >= 1.) inter[dd] -= 1.; + while(inter[dd] < 0.) inter[dd] += 1.; + } + inter2Phys(out_c+idy*3,inter,boxt); +} + +template +__global__ void _compute_int_data( + const FPTYPE *in_c, + const int *nat_stt, + const int *nat_end, + const int *ext_stt, + const int *ext_end, + const int *ngcell, + const double *boxt, + const double *rec_boxt, + int * idx_cellmap, + int * idx_cellmap_noshift, + int * total_cellnum_map, + int * mask_cellnum_map, + int * cell_map, + int * loc_cellnum_map, + int * cell_shift_map, + int * temp_idx_order, + const int nloc, + const int loc_cellnum, + const int total_cellnum) +{ + int idy = blockIdx.x*blockDim.x+threadIdx.x; + int ext_ncell[3]; + int global_grid[3]; + int idx_orig_shift[3]; + FPTYPE cell_size[3]; + FPTYPE nat_orig[3]; + for (int dd = 0; dd < 3; ++dd) + { + ext_ncell[dd] = ext_end[dd] - ext_stt[dd]; + global_grid[dd] = nat_end[dd] - nat_stt[dd]; + idx_orig_shift[dd] = nat_stt[dd] - ext_stt[dd]; + cell_size[dd] = 1./global_grid[dd]; + nat_orig[dd] = nat_stt[dd] * cell_size[dd]; + } + if (idy= nat_end[dd]) + { + idx_noshift[dd] = nat_end[dd] - 1; + } + idx[dd] = idx_noshift[dd]+idx_orig_shift[dd]; + } + idx_cellmap_noshift[idy]=collapse_index(idx_noshift, global_grid); + idx_cellmap[idy]=collapse_index(idx, ext_ncell); + } + __syncthreads(); + if (idy=nloc){return;} + int cell_idx=idx_cellmap[idy]; + int * clist_row = clist+sec_num_map[cell_idx]; + clist_row[idx_order[idy]]=idy; +} + +template +__global__ void _copy_coord( + FPTYPE * out_c, + int * out_t, + int * mapping, + const FPTYPE * in_c, + const int * in_t, + const int * cell_map, + const int * cell_shift_map, + const int * sec_loc_cellnum_map, + const int * sec_total_cellnum_map, + const int * loc_clist, + const int nloc, + const int nall, + const int total_cellnum, + const double * boxt, + const double * rec_boxt +) +{ + int idy = blockIdx.x*blockDim.x+threadIdx.x; + if(idy>=nall){return;} + if(idy=sec_total_cellnum_map[ii+1])cell_idx++; + else break; + } + for(int dd=0;dd<3;dd++) + { + shift[dd]=cell_shift_map[cell_idx*3+dd]; + d_shift[dd]=shift[dd]; + } + atom_idx=idy-sec_total_cellnum_map[cell_idx]; + orig_cell_idx=cell_map[cell_idx]; + orig_idy=loc_clist[sec_loc_cellnum_map[orig_cell_idx]+atom_idx]; + mapping[idy]=orig_idy; + out_t[idy]=in_t[orig_idy]; + FPTYPE shift_v[3]; + inter2Phys(shift_v,d_shift,boxt); + for(int dd=0;dd<3;dd++) + { + out_c[idy*3+dd]=in_c[orig_idy*3+dd]-shift_v[dd]; + } + } +} + +template +void compute_int_data(int * int_data, const FPTYPE * in_c, const int * cell_info, const double * box_info, const int nloc, const int loc_cellnum, const int total_cellnum) +{ + const int nn=(nloc>=total_cellnum)?nloc:total_cellnum; + const int nblock=(nn+TPB-1)/TPB; + int * idx_cellmap=int_data; + int * idx_cellmap_noshift=idx_cellmap+nloc; + int * temp_idx_order=idx_cellmap_noshift+nloc; + int * loc_cellnum_map=temp_idx_order+nloc; + int * total_cellnum_map=loc_cellnum_map+loc_cellnum; + int * mask_cellnum_map=total_cellnum_map+total_cellnum; + int * cell_map=mask_cellnum_map+total_cellnum; + int * cell_shift_map=cell_map+total_cellnum; + + const int * nat_stt=cell_info; + const int * nat_end=cell_info+3; + const int * ext_stt=cell_info+6; + const int * ext_end=cell_info+9; + const int * ngcell=cell_info+12; + const double * boxt = box_info; + const double * rec_boxt = box_info+9; + _compute_int_data<<>>(in_c,nat_stt,nat_end,ext_stt,ext_end,ngcell,boxt,rec_boxt,idx_cellmap,idx_cellmap_noshift,total_cellnum_map,mask_cellnum_map,cell_map,loc_cellnum_map,cell_shift_map,temp_idx_order,nloc,loc_cellnum,total_cellnum); +} + +void build_loc_clist(int * int_data, const int nloc, const int loc_cellnum, const int total_cellnum) +{ + const int nblock=(nloc+TPB-1)/TPB; + const int * idx_cellmap_noshift=int_data+nloc; + const int * temp_idx_order=idx_cellmap_noshift+nloc; + const int * sec_loc_cellnum_map=temp_idx_order+nloc+loc_cellnum+2*total_cellnum+total_cellnum+3*total_cellnum; + int * loc_clist=int_data+nloc*3+loc_cellnum+total_cellnum*3+total_cellnum*3+loc_cellnum+1+total_cellnum+1; + _build_loc_clist<<>>(loc_clist,idx_cellmap_noshift,temp_idx_order,sec_loc_cellnum_map,nloc); +} + +template +void copy_coord(FPTYPE * out_c, int * out_t, int * mapping, const int * int_data, const FPTYPE * in_c, const int * in_t, const int nloc, const int nall, const int loc_cellnum, const int total_cellnum, const double * box_info) +{ + const int nblock=(nall+TPB-1)/TPB; + const int * cell_map=int_data+3*nloc+loc_cellnum+2*total_cellnum; + const int * cell_shift_map=cell_map+total_cellnum; + const int * sec_loc_cellnum_map=cell_shift_map+3*total_cellnum; + const int * sec_total_cellnum_map=sec_loc_cellnum_map+loc_cellnum+1; + const int * loc_clist=sec_total_cellnum_map+total_cellnum+1; + + const double *boxt = box_info; + const double *rec_boxt = box_info+9; + _copy_coord<<>>(out_c, out_t, mapping, in_c, in_t, cell_map, cell_shift_map, sec_loc_cellnum_map, sec_total_cellnum_map, loc_clist, nloc, nall, total_cellnum, boxt, rec_boxt); +} + +namespace deepmd { +template +void +normalize_coord_gpu( + FPTYPE * coord, + const int natom, + const double * box_info) +{ + const double * boxt=box_info; + const double * rec_boxt=box_info + 9; + const int nblock=(natom+TPB-1)/TPB; + normalize_one<<>>(coord, boxt, rec_boxt, natom); +} + +// int_data(temp cuda memory):idx_map,idx_map_noshift,temp_idx_order,loc_cellnum_map,total_cellnum_map,mask_cellnum_map, +// cell_map,cell_shift_map,sec_loc_cellnum_map,sec_total_cellnum_map,loc_clist +template +int +copy_coord_gpu( + FPTYPE * out_c, + int * out_t, + int * mapping, + int * nall, + int * int_data, + const FPTYPE * in_c, + const int * in_t, + const int & nloc, + const int & mem_nall, + const int & loc_cellnum, + const int & total_cellnum, + const int * cell_info, + const double * box_info) +{ + compute_int_data(int_data, in_c, cell_info, box_info, nloc, loc_cellnum, total_cellnum); + int * int_data_cpu=new int [loc_cellnum+2*total_cellnum+loc_cellnum+1+total_cellnum+1];//loc_cellnum_map,total_cellnum_map,mask_cellnum_map,sec_loc_cellnum_map,sec_total_cellnum_map + cudaErrcheck(cudaMemcpy(int_data_cpu, int_data+3*nloc, sizeof(int) * (loc_cellnum + 2 * total_cellnum), cudaMemcpyDeviceToHost)); + int * loc_cellnum_map=int_data_cpu; + int * total_cellnum_map=loc_cellnum_map+loc_cellnum; + int * mask_cellnum_map=total_cellnum_map+total_cellnum; + int * sec_loc_cellnum_map=mask_cellnum_map+total_cellnum; + int * sec_total_cellnum_map=sec_loc_cellnum_map+loc_cellnum+1; + sec_loc_cellnum_map[0]=0; + sec_total_cellnum_map[0]=nloc; + int max_cell=0; + for(int iii=0;iii mem_nall){ + delete[] int_data_cpu; + // size of the output arrays is not large enough + return 1; + } + else{ + cudaErrcheck(cudaMemcpy(int_data+nloc*3+loc_cellnum+total_cellnum*3+total_cellnum*3, sec_loc_cellnum_map, sizeof(int) * (loc_cellnum+1+total_cellnum+1), cudaMemcpyHostToDevice)); + delete[] int_data_cpu; + build_loc_clist(int_data, nloc, loc_cellnum, total_cellnum); + copy_coord(out_c, out_t, mapping, int_data, in_c, in_t, nloc, *nall, loc_cellnum, total_cellnum, box_info); + } + return 0; +} + +template void normalize_coord_gpu(float * coord, const int natom, const double * box_info); +template void normalize_coord_gpu(double * coord, const int natom, const double * box_info); +template int copy_coord_gpu(float * out_c, int * out_t, int * mapping, int * nall, int * int_data, const float * in_c, const int * in_t, const int & nloc, const int & mem_nall, const int & loc_cellnum, const int & total_cellnum, const int * cell_info, const double * box_info); +template int copy_coord_gpu(double * out_c, int * out_t, int * mapping, int * nall, int * int_data, const double * in_c, const int * in_t, const int & nloc, const int & mem_nall, const int & loc_cellnum, const int & total_cellnum, const int * cell_info, const double * box_info); +} \ No newline at end of file diff --git a/source/lib/src/cuda/neighbor_list.cu b/source/lib/src/cuda/neighbor_list.cu new file mode 100644 index 0000000000..7b67c907dc --- /dev/null +++ b/source/lib/src/cuda/neighbor_list.cu @@ -0,0 +1,178 @@ +#include "device.h" +#include "gpu_cuda.h" +#include "neighbor_list.h" + +template +__device__ inline FPTYPE dev_dot(FPTYPE * arr1, FPTYPE * arr2) { + return arr1[0] * arr2[0] + arr1[1] * arr2[1] + arr1[2] * arr2[2]; +} + +template +__global__ void build_nlist(int * ilist, + int * temp_nlist, + const FPTYPE * c_cpy, + const FPTYPE rcut2, + const int nloc, + const int nall, + const int mem_size) +{ + const unsigned int atom_idx = blockIdx.x; + const unsigned int neighbor_idx = blockIdx.y * blockDim.y + threadIdx.y; + if(neighbor_idx=nnei){return;} + int nlist_idx=atom_idx*nnei+nei_idx; + int nlist_item=nlist[nlist_idx]; + if(nlist_item!=-1){ + nlist[nlist_idx]=nlist_map[nlist_item]; + } +} + +namespace deepmd { +template +int build_nlist_gpu( + InputNlist & nlist, + int * max_list_size, + int * nlist_data, + const FPTYPE * c_cpy, + const int & nloc, + const int & nall, + const int & mem_size, + const float & rcut) +{ + if(mem_size < nall){ + return 1; + } + const int nblock = (nall+TPB-1)/TPB; + int * ilist = nlist.ilist; + int * numneigh = nlist.numneigh; + int ** firstneigh = nlist.firstneigh; + cudaErrcheck(cudaMemset(nlist_data, -1, sizeof(int) * 2 * nloc * mem_size)); + int * temp_nlist = nlist_data; //nloc*mem_size + int * nei_order = temp_nlist + nloc * mem_size; + nlist.inum = nloc; + FPTYPE rcut2 = rcut * rcut; + + + dim3 block_grid(nloc, nblock); + dim3 thread_grid(1, TPB); + build_nlist<<>>( + ilist, + temp_nlist, + c_cpy, + rcut2, + nloc, + nall, + mem_size); + const int nblock_ = (nloc+TPB-1)/TPB; + scan_nlist<<>>( + numneigh, + nei_order, + temp_nlist, + mem_size, + nloc, + nall); + fill_nlist<<>>( + firstneigh, + temp_nlist, + nei_order, + mem_size, + nall + ); + int * numneigh_host = new int[nloc]; + cudaErrcheck(cudaMemcpy(numneigh_host, numneigh, sizeof(int) * nloc, cudaMemcpyDeviceToHost)); + int max_nei = 0; + for(int ii=0;iimax_nei)max_nei=numneigh_host[ii]; + } + *max_list_size = max_nei; + delete [] numneigh_host; + return 0; +} + +void use_nlist_map( + int * nlist, + const int * nlist_map, + const int nloc, + const int nnei) +{ + int nblock=(nnei+TPB-1)/TPB; + dim3 block_grid(nloc, nblock); + dim3 thread_grid(1, TPB); + map_nlist<<>>(nlist,nlist_map,nloc,nnei); +} + +template int build_nlist_gpu(InputNlist & nlist, int * max_list_size, int * nlist_data, const float * c_cpy, const int & nloc, const int & nall, const int & mem_size, const float & rcut); +template int build_nlist_gpu(InputNlist & nlist, int * max_list_size, int * nlist_data, const double * c_cpy, const int & nloc, const int & nall, const int & mem_size, const float & rcut); +} \ No newline at end of file diff --git a/source/lib/tests/test_coord.cc b/source/lib/tests/test_coord.cc index 3706874b55..d1dfd08ca2 100644 --- a/source/lib/tests/test_coord.cc +++ b/source/lib/tests/test_coord.cc @@ -2,6 +2,7 @@ #include #include #include "coord.h" +#include "device.h" class TestNormCoord : public ::testing::Test { @@ -68,6 +69,74 @@ TEST_F(TestNormCoord, cpu_case2) } } +#if GOOGLE_CUDA +TEST_F(TestNormCoord, gpu_case0) +{ + deepmd::Region region; + init_region_cpu(region, &boxt[0]); + std::vector box_info; + box_info.resize(18); + memcpy(&box_info[0], &boxt[0], sizeof(double)*9); + memcpy(&box_info[9], region.rec_boxt, sizeof(double)*9); + double * box_info_dev=NULL; + double * out_c_dev=NULL; + std::vector out_c(r0); + deepmd::malloc_device_memory_sync(box_info_dev, box_info); + deepmd::malloc_device_memory_sync(out_c_dev, out_c); + deepmd::normalize_coord_gpu(out_c_dev, natoms, box_info_dev); + deepmd::memcpy_device_to_host(out_c_dev, out_c); + deepmd::delete_device_memory(box_info_dev); + deepmd::delete_device_memory(out_c_dev); + for(int ii = 0; ii < posi.size(); ++ii){ + EXPECT_LT(fabs(out_c[ii] - posi[ii]), 1e-12); + } +} + +TEST_F(TestNormCoord, gpu_case1) +{ + deepmd::Region region; + init_region_cpu(region, &boxt[0]); + std::vector box_info; + box_info.resize(18); + memcpy(&box_info[0], &boxt[0], sizeof(double)*9); + memcpy(&box_info[9], region.rec_boxt, sizeof(double)*9); + double * box_info_dev=NULL; + double * out_c_dev=NULL; + std::vector out_c(r1); + deepmd::malloc_device_memory_sync(box_info_dev, box_info); + deepmd::malloc_device_memory_sync(out_c_dev, out_c); + deepmd::normalize_coord_gpu(out_c_dev, natoms, box_info_dev); + deepmd::memcpy_device_to_host(out_c_dev, out_c); + deepmd::delete_device_memory(box_info_dev); + deepmd::delete_device_memory(out_c_dev); + for(int ii = 0; ii < posi.size(); ++ii){ + EXPECT_LT(fabs(out_c[ii] - posi[ii]), 1e-12); + } +} + +TEST_F(TestNormCoord, gpu_case2) +{ + deepmd::Region region; + init_region_cpu(region, &boxt[0]); + std::vector box_info; + box_info.resize(18); + memcpy(&box_info[0], &boxt[0], sizeof(double)*9); + memcpy(&box_info[9], region.rec_boxt, sizeof(double)*9); + double * box_info_dev=NULL; + double * out_c_dev=NULL; + std::vector out_c(r2); + deepmd::malloc_device_memory_sync(box_info_dev, box_info); + deepmd::malloc_device_memory_sync(out_c_dev, out_c); + deepmd::normalize_coord_gpu(out_c_dev, natoms, box_info_dev); + deepmd::memcpy_device_to_host(out_c_dev, out_c); + deepmd::delete_device_memory(box_info_dev); + deepmd::delete_device_memory(out_c_dev); + for(int ii = 0; ii < posi.size(); ++ii){ + EXPECT_LT(fabs(out_c[ii] - posi[ii]), 1e-12); + } +} + +#endif //GOOGLE_CUDA typedef std::pair,std::vector> atom; @@ -231,3 +300,141 @@ TEST_F(TestCopyCoord, cpu_lessmem) // << nloc << " " // << nall << std::endl; } + +#if GOOGLE_CUDA +TEST_F(TestCopyCoord, gpu) +{ + int mem_size = 1000; + std::vector out_c(mem_size * 3); + std::vector out_t(mem_size); + std::vector mapping(mem_size); + int nall; + std::vector cell_info; + cell_info.resize(23); + deepmd::compute_cell_info(&cell_info[0], rc, &boxt[0]); + deepmd::Region region; + init_region_cpu(region, &boxt[0]); + std::vector box_info; + box_info.resize(18); + memcpy(&box_info[0], &boxt[0], sizeof(double)*9); + memcpy(&box_info[9], region.rec_boxt, sizeof(double)*9); + const int loc_cellnum=cell_info[21]; + const int total_cellnum=cell_info[22]; + int * cell_info_dev=NULL; + double * box_info_dev=NULL; + double * out_c_dev=NULL, * in_c_dev=NULL; + int * out_t_dev=NULL, * in_t_dev=NULL, * mapping_dev=NULL, * int_data_dev=NULL; + deepmd::malloc_device_memory_sync(cell_info_dev, cell_info); + deepmd::malloc_device_memory_sync(box_info_dev, box_info); + deepmd::malloc_device_memory_sync(in_c_dev, posi); + deepmd::malloc_device_memory_sync(in_t_dev, atype); + deepmd::malloc_device_memory(out_c_dev, mem_size * 3); + deepmd::malloc_device_memory(out_t_dev, mem_size); + deepmd::malloc_device_memory(mapping_dev, mem_size); + deepmd::malloc_device_memory(int_data_dev, nloc*3+loc_cellnum+total_cellnum*3+total_cellnum*3+loc_cellnum+1+total_cellnum+1+nloc); + int ret = deepmd::copy_coord_gpu( + out_c_dev, + out_t_dev, + mapping_dev, + &nall, + int_data_dev, + in_c_dev, + in_t_dev, + nloc, + mem_size, + loc_cellnum, + total_cellnum, + cell_info_dev, + box_info_dev); + deepmd::memcpy_device_to_host(out_c_dev, out_c); + deepmd::memcpy_device_to_host(out_t_dev, out_t); + deepmd::memcpy_device_to_host(mapping_dev, mapping); + deepmd::delete_device_memory(cell_info_dev); + deepmd::delete_device_memory(box_info_dev); + deepmd::delete_device_memory(in_c_dev); + deepmd::delete_device_memory(in_t_dev); + deepmd::delete_device_memory(out_c_dev); + deepmd::delete_device_memory(out_t_dev); + deepmd::delete_device_memory(mapping_dev); + deepmd::delete_device_memory(int_data_dev); + EXPECT_EQ(ret, 0); + EXPECT_EQ(nall, expected_nall); + out_c.resize(nall*3); + out_t.resize(nall); + mapping.resize(nall); + + std::vector out_c_1(mem_size * 3); + std::vector out_t_1(mem_size); + std::vector mapping_1(mem_size); + sort_atoms(out_c_1, out_t_1, mapping_1, out_c, out_t, mapping, nloc, nall); + for(int ii = 0; ii < expected_nall; ++ii){ + for(int dd = 0; dd < 3; ++dd){ + EXPECT_LT(fabs(out_c_1[ii*3+dd] - expected_posi_cpy[ii*3+dd]), 1e-12); + } + EXPECT_EQ(out_t_1[ii], expected_atype_cpy[ii]); + EXPECT_EQ(mapping_1[ii], expected_mapping[ii]); + } +} + +TEST_F(TestCopyCoord, gpu_lessmem) +{ + int mem_size = 40; + std::vector out_c(mem_size * 3); + std::vector out_t(mem_size); + std::vector mapping(mem_size); + int nall; + std::vector cell_info; + cell_info.resize(23); + deepmd::compute_cell_info(&cell_info[0], rc, &boxt[0]); + deepmd::Region region; + init_region_cpu(region, &boxt[0]); + std::vector box_info; + box_info.resize(18); + memcpy(&box_info[0], &boxt[0], sizeof(double)*9); + memcpy(&box_info[9], region.rec_boxt, sizeof(double)*9); + const int loc_cellnum=cell_info[21]; + const int total_cellnum=cell_info[22]; + int * cell_info_dev=NULL; + double * box_info_dev=NULL; + double * out_c_dev=NULL, * in_c_dev=NULL; + int * out_t_dev=NULL, * in_t_dev=NULL, * mapping_dev=NULL, * int_data_dev=NULL; + deepmd::malloc_device_memory_sync(cell_info_dev, cell_info); + deepmd::malloc_device_memory_sync(box_info_dev, box_info); + deepmd::malloc_device_memory_sync(in_c_dev, posi); + deepmd::malloc_device_memory_sync(in_t_dev, atype); + deepmd::malloc_device_memory(out_c_dev, mem_size * 3); + deepmd::malloc_device_memory(out_t_dev, mem_size); + deepmd::malloc_device_memory(mapping_dev, mem_size); + deepmd::malloc_device_memory(int_data_dev, nloc*3+loc_cellnum+total_cellnum*3+total_cellnum*3+loc_cellnum+1+total_cellnum+1+nloc); + int ret = deepmd::copy_coord_gpu( + out_c_dev, + out_t_dev, + mapping_dev, + &nall, + int_data_dev, + in_c_dev, + in_t_dev, + nloc, + mem_size, + loc_cellnum, + total_cellnum, + cell_info_dev, + box_info_dev); + deepmd::memcpy_device_to_host(out_c_dev, out_c); + deepmd::memcpy_device_to_host(out_t_dev, out_t); + deepmd::memcpy_device_to_host(mapping_dev, mapping); + deepmd::delete_device_memory(cell_info_dev); + deepmd::delete_device_memory(box_info_dev); + deepmd::delete_device_memory(in_c_dev); + deepmd::delete_device_memory(in_t_dev); + deepmd::delete_device_memory(out_c_dev); + deepmd::delete_device_memory(out_t_dev); + deepmd::delete_device_memory(mapping_dev); + deepmd::delete_device_memory(int_data_dev); + EXPECT_EQ(ret, 1); + // EXPECT_EQ(nall, expected_nall); + // std::cout << "---------------------" + // << nloc << " " + // << nall << std::endl; +} +#endif //GOOGLE_CUDA diff --git a/source/lib/tests/test_neighbor_list.cc b/source/lib/tests/test_neighbor_list.cc index cd8211fb09..5cf74f7382 100644 --- a/source/lib/tests/test_neighbor_list.cc +++ b/source/lib/tests/test_neighbor_list.cc @@ -1,6 +1,7 @@ #include #include "fmt_nlist.h" #include "neighbor_list.h" +#include "device.h" class TestNeighborList : public ::testing::Test { @@ -116,3 +117,112 @@ TEST_F(TestNeighborList, cpu_lessmem) delete[] firstneigh; } +#if GOOGLE_CUDA +TEST_F(TestNeighborList, gpu) +{ + int mem_size = 48; + + int * nlist_data_dev=NULL, * jlist_dev=NULL, * ilist_dev=NULL, * numneigh_dev=NULL; + int ** firstneigh_dev=NULL; + std::vector temp_firstneigh(nloc); + double * c_cpy_dev=NULL; + + deepmd::malloc_device_memory(nlist_data_dev, 2 * nloc * mem_size); + deepmd::malloc_device_memory(jlist_dev, nloc * mem_size); + deepmd::malloc_device_memory(ilist_dev, nloc); + deepmd::malloc_device_memory(numneigh_dev, nloc); + for(int ii = 0; ii < nloc; ++ii){ + temp_firstneigh[ii] = jlist_dev + ii * mem_size; + } + deepmd::malloc_device_memory_sync(firstneigh_dev, temp_firstneigh); + deepmd::malloc_device_memory_sync(c_cpy_dev, posi_cpy); + deepmd::InputNlist nlist_dev(nloc, ilist_dev, numneigh_dev, firstneigh_dev); + + int max_list_size; + int ret = deepmd::build_nlist_gpu( + nlist_dev, + &max_list_size, + nlist_data_dev, + c_cpy_dev, + nloc, + nall, + mem_size, + rc); + + EXPECT_EQ(ret, 0); + int * ilist = new int[nloc]; + int * numneigh = new int[nloc]; + int ** firstneigh = new int*[nloc]; + int * jlist = new int[nloc * mem_size]; + deepmd::memcpy_device_to_host(jlist_dev, jlist, nloc * mem_size); + deepmd::memcpy_device_to_host(ilist_dev, ilist, nloc); + deepmd::memcpy_device_to_host(numneigh_dev, numneigh, nloc); + for(int ii = 0; ii < nloc; ++ii){ + firstneigh[ii] = jlist + ii * mem_size; + } + + deepmd::InputNlist nlist(nlist_dev.inum, ilist, numneigh, firstneigh); + EXPECT_EQ(nlist.inum, nloc); + EXPECT_EQ(max_list_size, 5); + for(int ii = 0; ii < nloc; ++ii){ + EXPECT_EQ(nlist.ilist[ii], ii); + EXPECT_EQ(nlist.numneigh[ii], expect_nlist_cpy[ii].size()); + std::sort(nlist.firstneigh[ii], nlist.firstneigh[ii] + nlist.numneigh[ii]); + for(int jj = 0; jj < nlist.numneigh[ii]; ++jj){ + EXPECT_EQ(nlist.firstneigh[ii][jj], expect_nlist_cpy[ii][jj]); + } + } + + delete[] ilist; + delete[] numneigh; + delete[] jlist; + delete[] firstneigh; + deepmd::delete_device_memory(nlist_data_dev); + deepmd::delete_device_memory(jlist_dev); + deepmd::delete_device_memory(ilist_dev); + deepmd::delete_device_memory(numneigh_dev); + deepmd::delete_device_memory(firstneigh_dev); + deepmd::delete_device_memory(c_cpy_dev); +} + +TEST_F(TestNeighborList, gpu_lessmem) +{ + int mem_size = 47; + + int * nlist_data_dev=NULL, * jlist_dev=NULL, * ilist_dev=NULL, * numneigh_dev=NULL; + int ** firstneigh_dev=NULL; + std::vector temp_firstneigh(nloc); + double * c_cpy_dev=NULL; + + deepmd::malloc_device_memory(nlist_data_dev, 2 * nloc * mem_size); + deepmd::malloc_device_memory(jlist_dev, nloc * mem_size); + deepmd::malloc_device_memory(ilist_dev, nloc); + deepmd::malloc_device_memory(numneigh_dev, nloc); + for(int ii = 0; ii < nloc; ++ii){ + temp_firstneigh[ii] = jlist_dev + ii * mem_size; + } + deepmd::malloc_device_memory_sync(firstneigh_dev, temp_firstneigh); + deepmd::malloc_device_memory_sync(c_cpy_dev, posi_cpy); + deepmd::InputNlist nlist_dev(nloc, ilist_dev, numneigh_dev, firstneigh_dev); + + int max_list_size; + int ret = deepmd::build_nlist_gpu( + nlist_dev, + &max_list_size, + nlist_data_dev, + c_cpy_dev, + nloc, + nall, + mem_size, + rc); + + EXPECT_EQ(ret, 1); + deepmd::delete_device_memory(nlist_data_dev); + deepmd::delete_device_memory(jlist_dev); + deepmd::delete_device_memory(ilist_dev); + deepmd::delete_device_memory(numneigh_dev); + deepmd::delete_device_memory(firstneigh_dev); + deepmd::delete_device_memory(c_cpy_dev); +} + +#endif //GOOGLE_CUDA \ No newline at end of file diff --git a/source/op/prod_env_mat_multi_device.cc b/source/op/prod_env_mat_multi_device.cc index 7a26ce2b41..79f7f71b1a 100644 --- a/source/op/prod_env_mat_multi_device.cc +++ b/source/op/prod_env_mat_multi_device.cc @@ -106,6 +106,78 @@ _prepare_coord_nlist_cpu( const int & max_cpy_trial, const int & max_nnei_trial); +#if GOOGLE_CUDA +template +static int +_norm_copy_coord_gpu( + OpKernelContext* context, + Tensor * tensor_list, + FPTYPE * & coord_cpy, + int * & type_cpy, + int * & idx_mapping, + int & nall, + int & mem_cpy, + const FPTYPE * coord, + const FPTYPE * box, + const int * type, + const int &nloc, + const int &max_cpy_trial, + const float & rcut_r); + +template +static int +_build_nlist_gpu( + OpKernelContext* context, + Tensor * tensor_list, + int * &ilist, + int * &numneigh, + int ** &firstneigh, + int * &jlist, + int & max_nnei, + int & mem_nnei, + const FPTYPE *coord, + const int & nloc, + const int & new_nall, + const int & max_nnei_trial, + const float & rcut_r); + +static void +_map_nlist_gpu( + int * nlist, + const int * idx_mapping, + const int & nloc, + const int & nnei); + +template +static void +_prepare_coord_nlist_gpu( + OpKernelContext* context, + Tensor * tensor_list, + FPTYPE const ** coord, + FPTYPE * & coord_cpy, + int const** type, + int * & type_cpy, + int * & idx_mapping, + deepmd::InputNlist & inlist, + int * & ilist, + int * & numneigh, + int ** & firstneigh, + int * & jlist, + int * & nbor_list_dev, + int & new_nall, + int & mem_cpy, + int & mem_nnei, + int & max_nbor_size, + const FPTYPE * box, + const int * mesh_tensor_data, + const int mesh_tensor_size, + const int & nloc, + const int & nei_mode, + const float & rcut_r, + const int & max_cpy_trial, + const int & max_nnei_trial); + +#endif //GOOGLE_CUDA template @@ -258,6 +330,23 @@ class ProdEnvMatAOp : public OpKernel { if(device == "GPU") { #if GOOGLE_CUDA + int * idx_mapping = NULL; + int * ilist = NULL, * numneigh = NULL; + int ** firstneigh = NULL; + deepmd::malloc_device_memory(firstneigh, nloc); + int * jlist = NULL; + FPTYPE * coord_cpy; + int * type_cpy; + int frame_nall = nall; + int mesh_tensor_size = static_cast(mesh_tensor.NumElements()); + std::vector tensor_list(7); + // prepare coord and nlist + _prepare_coord_nlist_gpu( + context, &tensor_list[0], &coord, coord_cpy, &type, type_cpy, idx_mapping, + gpu_inlist, ilist, numneigh, firstneigh, jlist, nbor_list_dev, + frame_nall, mem_cpy, mem_nnei, max_nbor_size, + box, mesh_tensor.flat().data(), mesh_tensor_size, nloc, nei_mode, rcut_r, max_cpy_trial, max_nnei_trial); + // allocate temp memory, temp memory must not be used after this operation! Tensor int_temp; TensorShape int_shape; @@ -270,17 +359,12 @@ class ProdEnvMatAOp : public OpKernel { array_int = int_temp.flat().data(); array_longlong = uint64_temp.flat().data(); - // update nbor list - deepmd::InputNlist inlist; - inlist.inum = nloc; - deepmd::env_mat_nbor_update( - inlist, gpu_inlist, max_nbor_size, nbor_list_dev, - mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); - OP_REQUIRES (context, (max_numneigh(inlist) <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_numneigh(inlist)) + " is larger than " + std::to_string(GPU_MAX_NBOR_SIZE) + ", which currently is not supported by deepmd-kit.")); // launch the gpu(nv) compute function deepmd::prod_env_mat_a_gpu_cuda( em, em_deriv, rij, nlist, - coord, type, gpu_inlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, rcut_r, rcut_r_smth, sec_a); + coord, type, gpu_inlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, frame_nall, rcut_r, rcut_r_smth, sec_a); + if(b_nlist_map) _map_nlist_gpu(nlist, idx_mapping, nloc, nnei); + deepmd::delete_device_memory(firstneigh); #endif //GOOGLE_CUDA } else if (device == "CPU") { @@ -468,6 +552,23 @@ class ProdEnvMatROp : public OpKernel { if(device == "GPU") { #if GOOGLE_CUDA + int * idx_mapping = NULL; + int * ilist = NULL, * numneigh = NULL; + int ** firstneigh = NULL; + deepmd::malloc_device_memory(firstneigh, nloc); + int * jlist = NULL; + FPTYPE * coord_cpy; + int * type_cpy; + int frame_nall = nall; + int mesh_tensor_size = static_cast(mesh_tensor.NumElements()); + std::vector tensor_list(7); + // prepare coord and nlist + _prepare_coord_nlist_gpu( + context, &tensor_list[0], &coord, coord_cpy, &type, type_cpy, idx_mapping, + gpu_inlist, ilist, numneigh, firstneigh, jlist, nbor_list_dev, + frame_nall, mem_cpy, mem_nnei, max_nbor_size, + box, mesh_tensor.flat().data(), mesh_tensor_size, nloc, nei_mode, rcut, max_cpy_trial, max_nnei_trial); + // allocate temp memory, temp memory must not be used after this operation! Tensor int_temp; TensorShape int_shape; @@ -480,17 +581,12 @@ class ProdEnvMatROp : public OpKernel { array_int = int_temp.flat().data(); array_longlong = uint64_temp.flat().data(); - // update nbor list - deepmd::InputNlist inlist; - inlist.inum = nloc; - deepmd::env_mat_nbor_update( - inlist, gpu_inlist, max_nbor_size, nbor_list_dev, - mesh_tensor.flat().data(), static_cast(mesh_tensor.NumElements())); - OP_REQUIRES (context, (max_numneigh(inlist) <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_numneigh(inlist)) + " is larger than " + std::to_string(GPU_MAX_NBOR_SIZE) + ", which currently is not supported by deepmd-kit.")); // launch the gpu(nv) compute function deepmd::prod_env_mat_r_gpu_cuda( em, em_deriv, rij, nlist, - coord, type, gpu_inlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, nall, rcut, rcut_smth, sec); + coord, type, gpu_inlist, array_int, array_longlong, max_nbor_size, avg, std, nloc, frame_nall, rcut, rcut_smth, sec); + if(b_nlist_map) _map_nlist_gpu(nlist, idx_mapping, nloc, nnei); + deepmd::delete_device_memory(firstneigh); #endif //GOOGLE_CUDA } else if (device == "CPU") { @@ -686,26 +782,237 @@ _prepare_coord_nlist_cpu( } } +#if GOOGLE_CUDA +template +static int +_norm_copy_coord_gpu( + OpKernelContext* context, + Tensor * tensor_list, + FPTYPE * & coord_cpy, + int * & type_cpy, + int * & idx_mapping, + int & nall, + int & mem_cpy, + const FPTYPE * coord, + const FPTYPE * box, + const int * type, + const int &nloc, + const int &max_cpy_trial, + const float & rcut_r) +{ + // Tensor FPTYPE_temp; + TensorShape FPTYPE_shape; + FPTYPE_shape.AddDim(nall*3); + context->allocate_temp(DT_DOUBLE, FPTYPE_shape, tensor_list); + FPTYPE * tmp_coord = (*tensor_list).flat().data(); + cudaErrcheck(cudaMemcpy(tmp_coord, coord, sizeof(FPTYPE) * nall * 3, cudaMemcpyDeviceToDevice)); + + deepmd::Region region; + init_region_cpu(region, box); + double box_info[18]; + std::copy(region.boxt, region.boxt+9, box_info); + std::copy(region.rec_boxt, region.rec_boxt+9, box_info+9); + + int cell_info[23]; + deepmd::compute_cell_info(cell_info, rcut_r, box_info); + const int loc_cellnum=cell_info[21]; + const int total_cellnum=cell_info[22]; + + //Tensor double_temp; + TensorShape double_shape; + double_shape.AddDim(18); + context->allocate_temp(DT_DOUBLE, double_shape, tensor_list+1); + //Tensor int_temp; + TensorShape int_shape; + int_shape.AddDim(23+nloc*3+loc_cellnum+total_cellnum*3+total_cellnum*3+loc_cellnum+1+total_cellnum+1+nloc); + context, context->allocate_temp(DT_INT32, int_shape, tensor_list+2); + double * box_info_dev = (*(tensor_list+1)).flat().data(); + int * cell_info_dev = (*(tensor_list+2)).flat().data(); + int * int_data_dev = cell_info_dev + 23; + deepmd::memcpy_host_to_device(box_info_dev, box_info, 18); + deepmd::memcpy_host_to_device(cell_info_dev, cell_info, 23); + deepmd::normalize_coord_gpu(tmp_coord, nall, box_info_dev); + int tt; + //Tensor cpy_temp; + //Tensor t_temp; + for(tt = 0; tt < max_cpy_trial; ++tt){ + + TensorShape cpy_shape; + cpy_shape.AddDim(mem_cpy*3); + context->allocate_temp(DT_DOUBLE, cpy_shape, tensor_list+3); + + TensorShape t_shape; + t_shape.AddDim(mem_cpy*2); + context, context->allocate_temp(DT_INT32, t_shape, tensor_list+4); + + coord_cpy = (*(tensor_list+3)).flat().data(); + type_cpy = (*(tensor_list+4)).flat().data(); + idx_mapping = type_cpy + mem_cpy; + int ret = deepmd::copy_coord_gpu( + coord_cpy, type_cpy, idx_mapping, &nall, int_data_dev, + tmp_coord, type, nloc, mem_cpy, loc_cellnum, total_cellnum, cell_info_dev, box_info_dev); + if(ret == 0){ + break; + } + else{ + mem_cpy *= 2; + } + } + return (tt != max_cpy_trial); +} + +template +static int +_build_nlist_gpu( + OpKernelContext* context, + Tensor * tensor_list, + int * &ilist, + int * &numneigh, + int ** &firstneigh, + int * &jlist, + int & max_nnei, + int & mem_nnei, + const FPTYPE *coord, + const int & nloc, + const int & new_nall, + const int & max_nnei_trial, + const float & rcut_r) +{ + //Tensor nlist_temp; + TensorShape nlist_shape; + nlist_shape.AddDim(nloc*2); + context->allocate_temp(DT_INT32, nlist_shape, tensor_list); + ilist = (*tensor_list).flat().data(); + numneigh = ilist + nloc; + //Tensor jlist_temp; + int * ind_data = NULL; + + std::vector firstneigh_host(nloc); + int tt; + for(tt = 0; tt < max_nnei_trial; ++tt){ + TensorShape jlist_shape; + jlist_shape.AddDim(3*nloc*mem_nnei); + context->allocate_temp(DT_INT32, jlist_shape, tensor_list+1); + jlist = (*(tensor_list+1)).flat().data(); + ind_data = jlist + nloc * mem_nnei; + for(int ii = 0; ii < nloc; ++ii){ + firstneigh_host[ii] = jlist + ii * mem_nnei; + } + deepmd::memcpy_host_to_device(firstneigh, firstneigh_host); + deepmd::InputNlist inlist(nloc, ilist, numneigh, firstneigh); + int ret = deepmd::build_nlist_gpu( + inlist, &max_nnei, ind_data, + coord, nloc, new_nall, mem_nnei, rcut_r); + if(ret == 0){ + break; + } + else{ + mem_nnei *= 2; + } + } + return (tt != max_nnei_trial); +} + +static void +_map_nlist_gpu( + int * nlist, + const int * idx_mapping, + const int & nloc, + const int & nnei) +{ + deepmd::use_nlist_map(nlist, idx_mapping, nloc, nnei); +} + +template +static void +_prepare_coord_nlist_gpu( + OpKernelContext* context, + Tensor * tensor_list, + FPTYPE const ** coord, + FPTYPE * & coord_cpy, + int const** type, + int * & type_cpy, + int * & idx_mapping, + deepmd::InputNlist & inlist, + int * & ilist, + int * & numneigh, + int ** & firstneigh, + int * & jlist, + int * & nbor_list_dev, + int & new_nall, + int & mem_cpy, + int & mem_nnei, + int & max_nbor_size, + const FPTYPE * box, + const int * mesh_tensor_data, + const int mesh_tensor_size, + const int & nloc, + const int & nei_mode, + const float & rcut_r, + const int & max_cpy_trial, + const int & max_nnei_trial) +{ + inlist.inum = nloc; + if(nei_mode != 3){ + // build nlist by myself + // normalize and copy coord + if(nei_mode == 1){ + int copy_ok = _norm_copy_coord_gpu( + context, tensor_list, coord_cpy, type_cpy, idx_mapping, new_nall, mem_cpy, + *coord, box, *type, nloc, max_cpy_trial, rcut_r); + OP_REQUIRES (context, copy_ok, errors::Aborted("cannot allocate mem for copied coords")); + *coord = coord_cpy; + *type = type_cpy; + } + //build nlist + int build_ok = _build_nlist_gpu( + context, tensor_list + 5, ilist, numneigh, firstneigh, jlist, max_nbor_size, mem_nnei, + *coord, nloc, new_nall, max_nnei_trial, rcut_r); + OP_REQUIRES (context, build_ok, errors::Aborted("cannot allocate mem for nlist")); + if (max_nbor_size <= 1024) { + max_nbor_size = 1024; + } + else if (max_nbor_size <= 2048) { + max_nbor_size = 2048; + } + else { + max_nbor_size = 4096; + } + inlist.ilist = ilist; + inlist.numneigh = numneigh; + inlist.firstneigh = firstneigh; + } + else{ + // update nbor list + deepmd::InputNlist inlist_temp; + inlist_temp.inum = nloc; + deepmd::env_mat_nbor_update( + inlist_temp, inlist, max_nbor_size, nbor_list_dev, + mesh_tensor_data, mesh_tensor_size); + OP_REQUIRES (context, (max_numneigh(inlist_temp) <= GPU_MAX_NBOR_SIZE), errors::InvalidArgument ("Assert failed, max neighbor size of atom(lammps) " + std::to_string(max_numneigh(inlist_temp)) + " is larger than " + std::to_string(GPU_MAX_NBOR_SIZE) + ", which currently is not supported by deepmd-kit.")); + } +} +#endif // GOOGLE_CUDA // Register the CPU kernels. -#define REGISTER_CPU(T) \ -REGISTER_KERNEL_BUILDER( \ - Name("ProdEnvMatA").Device(DEVICE_CPU).TypeConstraint("T"), \ - ProdEnvMatAOp); \ -REGISTER_KERNEL_BUILDER( \ - Name("ProdEnvMatR").Device(DEVICE_CPU).TypeConstraint("T"), \ - ProdEnvMatROp); -REGISTER_CPU(float); -REGISTER_CPU(double); - -// Register the GPU kernels. -#if GOOGLE_CUDA -#define REGISTER_GPU(T) \ -REGISTER_KERNEL_BUILDER( \ - Name("ProdEnvMatA").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ - ProdEnvMatAOp); \ -REGISTER_KERNEL_BUILDER( \ - Name("ProdEnvMatR").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ +#define REGISTER_CPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdEnvMatA").Device(DEVICE_CPU).TypeConstraint("T"), \ + ProdEnvMatAOp); \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdEnvMatR").Device(DEVICE_CPU).TypeConstraint("T"), \ + ProdEnvMatROp); +REGISTER_CPU(float); +REGISTER_CPU(double); + +// Register the GPU kernels. +#if GOOGLE_CUDA +#define REGISTER_GPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdEnvMatA").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms").HostMemory("box"), \ + ProdEnvMatAOp); \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdEnvMatR").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms").HostMemory("box"), \ ProdEnvMatROp); REGISTER_GPU(float); REGISTER_GPU(double); From aeef9b9b8c82b4e9adf1ce970183f3cb4a640bfc Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 27 Mar 2021 20:20:31 +0800 Subject: [PATCH 301/562] fix bugs of tensor model --- deepmd/model/tensor.py | 51 ++++++++++++++++++++++++++------- source/tests/test_polar_se_a.py | 2 +- source/tests/test_wfc.py | 2 +- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/deepmd/model/tensor.py b/deepmd/model/tensor.py index fa60171255..8df73f4ff0 100644 --- a/deepmd/model/tensor.py +++ b/deepmd/model/tensor.py @@ -13,7 +13,7 @@ def __init__ ( tensor_name : str, descrpt, fitting, - type_map : List[str], + type_map : List[str] = None, data_stat_nbatch : int = 10, data_stat_protect : float = 1e-2, )->None: @@ -44,7 +44,10 @@ def __init__ ( # fitting self.fitting = fitting # other params - self.type_map = type_map + if type_map is None: + self.type_map = [] + else: + self.type_map = type_map self.data_stat_nbatch = data_stat_nbatch self.data_stat_protect = data_stat_protect @@ -133,19 +136,47 @@ def build (self, class WFCModel(TensorModel): - def __init__(self, descrpt, fitting, tm, dsn, dsp) : - TensorModel.__init__(self, 'wfc', descrpt, fitting, tm, dsn, dsp) + def __init__( + self, + descrpt, + fitting, + type_map : List[str] = None, + data_stat_nbatch : int = 10, + data_stat_protect : float = 1e-2 + ) -> None: + TensorModel.__init__(self, 'wfc', descrpt, fitting, type_map, data_stat_nbatch, data_stat_protect) class DipoleModel(TensorModel): - def __init__(self, descrpt, fitting, tm, dsn, dsp) : - TensorModel.__init__(self, 'dipole', descrpt, fitting, tm, dsn, dsp) + def __init__( + self, + descrpt, + fitting, + type_map : List[str] = None, + data_stat_nbatch : int = 10, + data_stat_protect : float = 1e-2 + ) -> None: + TensorModel.__init__(self, 'dipole', descrpt, fitting, type_map, data_stat_nbatch, data_stat_protect) class PolarModel(TensorModel): - def __init__(self, descrpt, fitting, tm, dsn, dsp) : - TensorModel.__init__(self, 'polar', descrpt, fitting, tm, dsn, dsp) + def __init__( + self, + descrpt, + fitting, + type_map : List[str] = None, + data_stat_nbatch : int = 10, + data_stat_protect : float = 1e-2 + ) -> None: + TensorModel.__init__(self, 'polar', descrpt, fitting, type_map, data_stat_nbatch, data_stat_protect) class GlobalPolarModel(TensorModel): - def __init__(self, descrpt, fitting, tm, dsn, dsp) : - TensorModel.__init__(self, 'global_polar', descrpt, fitting, tm, dsn, dsp) + def __init__( + self, + descrpt, + fitting, + type_map : List[str] = None, + data_stat_nbatch : int = 10, + data_stat_protect : float = 1e-2 + ) -> None: + TensorModel.__init__(self, 'global_polar', descrpt, fitting, type_map, data_stat_nbatch, data_stat_protect) diff --git a/source/tests/test_polar_se_a.py b/source/tests/test_polar_se_a.py index 1c265057a4..8ca358b585 100644 --- a/source/tests/test_polar_se_a.py +++ b/source/tests/test_polar_se_a.py @@ -40,7 +40,7 @@ def test_model(self): descrpt = DescrptSeA(**jdata['model']['descriptor']) jdata['model']['fitting_net']['descrpt'] = descrpt fitting = PolarFittingSeA(**jdata['model']['fitting_net']) - model = PolarModel(jdata['model'], descrpt, fitting) + model = PolarModel(descrpt, fitting) # model._compute_dstats([test_data['coord']], [test_data['box']], [test_data['type']], [test_data['natoms_vec']], [test_data['default_mesh']]) input_data = {'coord' : [test_data['coord']], diff --git a/source/tests/test_wfc.py b/source/tests/test_wfc.py index 9bae04ed04..9038c6d177 100644 --- a/source/tests/test_wfc.py +++ b/source/tests/test_wfc.py @@ -39,7 +39,7 @@ def test_model(self): jdata['model']['descriptor'].pop('_comment', None) descrpt = DescrptLocFrame(**jdata['model']['descriptor']) fitting = WFCFitting(jdata['model']['fitting_net'], descrpt) - model = WFCModel(jdata['model'], descrpt, fitting) + model = WFCModel(descrpt, fitting) input_data = {'coord' : [test_data['coord']], 'box': [test_data['box']], From 967ad7cb1dcec4c9d93a2ba3d5cdd953b2a1f805 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 27 Mar 2021 22:30:37 +0800 Subject: [PATCH 302/562] add module train. mv some global vars from run_opt to env --- {source/train => deepmd}/calculator.py | 0 deepmd/common.py | 2 +- deepmd/descriptor/hybrid.py | 4 +- deepmd/descriptor/loc_frame.py | 4 +- deepmd/descriptor/se_a.py | 4 +- deepmd/descriptor/se_a_ebd.py | 4 +- deepmd/descriptor/se_a_ef.py | 4 +- deepmd/descriptor/se_a_t.py | 4 +- deepmd/descriptor/se_r.py | 4 +- deepmd/entrypoints/print_old_model.py | 83 -------------------- deepmd/entrypoints/train.py | 6 +- deepmd/env.py | 89 +++++++++++++++++++++- deepmd/fit/dipole.py | 4 +- deepmd/fit/ener.py | 4 +- deepmd/fit/polar.py | 4 +- deepmd/fit/wfc.py | 4 +- deepmd/infer/data_modifier.py | 10 +-- deepmd/infer/deep_eval.py | 3 +- deepmd/infer/ewald_recp.py | 10 +-- deepmd/loss/ener.py | 4 +- deepmd/loss/tensor.py | 4 +- deepmd/model/ener.py | 2 +- deepmd/model/tensor.py | 2 +- {source => deepmd}/train/run_options.py | 75 +----------------- {source => deepmd}/train/trainer.py | 6 +- deepmd/utils/data.py | 4 +- deepmd/utils/neighbor_stat.py | 2 +- deepmd/utils/network.py | 2 +- setup.py | 1 + source/CMakeLists.txt | 2 +- source/tests/common.py | 6 +- source/tests/test_data_modifier.py | 12 +-- source/tests/test_data_modifier_shuffle.py | 12 +-- source/tests/test_deepdipole.py | 2 +- source/tests/test_deepmd_data.py | 2 +- source/tests/test_deepmd_data_sys.py | 2 +- source/tests/test_deeppolar.py | 2 +- source/tests/test_deeppot_a.py | 4 +- source/tests/test_deeppot_r.py | 2 +- source/tests/test_descrpt_nonsmth.py | 6 +- source/tests/test_descrpt_se_ar.py | 6 +- source/tests/test_descrpt_se_r.py | 6 +- source/tests/test_descrpt_sea_ef.py | 6 +- source/tests/test_descrpt_sea_ef_para.py | 6 +- source/tests/test_descrpt_sea_ef_rot.py | 6 +- source/tests/test_descrpt_sea_ef_vert.py | 6 +- source/tests/test_descrpt_smooth.py | 6 +- source/tests/test_dipolecharge.py | 2 +- source/tests/test_embedding_net.py | 6 +- source/tests/test_ewald.py | 6 +- source/tests/test_prod_env_mat.py | 6 +- source/tests/test_transfer.py | 2 +- 52 files changed, 196 insertions(+), 269 deletions(-) rename {source/train => deepmd}/calculator.py (100%) delete mode 100644 deepmd/entrypoints/print_old_model.py rename {source => deepmd}/train/run_options.py (85%) rename {source => deepmd}/train/trainer.py (99%) diff --git a/source/train/calculator.py b/deepmd/calculator.py similarity index 100% rename from source/train/calculator.py rename to deepmd/calculator.py diff --git a/deepmd/common.py b/deepmd/common.py index 1486260408..e4613aeabb 100644 --- a/deepmd/common.py +++ b/deepmd/common.py @@ -20,7 +20,7 @@ import yaml from deepmd.env import op_module, tf -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION, GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION, GLOBAL_NP_FLOAT_PRECISION if TYPE_CHECKING: _DICT_VAL = TypeVar("_DICT_VAL") diff --git a/deepmd/descriptor/hybrid.py b/deepmd/descriptor/hybrid.py index f576e65abd..0b9a5bb508 100644 --- a/deepmd/descriptor/hybrid.py +++ b/deepmd/descriptor/hybrid.py @@ -4,8 +4,8 @@ from deepmd.env import tf from deepmd.common import ClassArg from deepmd.env import op_module -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION # from deepmd.descriptor import DescrptLocFrame # from deepmd.descriptor import DescrptSeA # from deepmd.descriptor import DescrptSeAT diff --git a/deepmd/descriptor/loc_frame.py b/deepmd/descriptor/loc_frame.py index f9dab549ee..d8cd4f6366 100644 --- a/deepmd/descriptor/loc_frame.py +++ b/deepmd/descriptor/loc_frame.py @@ -2,8 +2,8 @@ from typing import Tuple, List from deepmd.env import tf -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION from deepmd.env import op_module from deepmd.env import default_tf_session_config diff --git a/deepmd/descriptor/se_a.py b/deepmd/descriptor/se_a.py index 3d502730de..54325ca77c 100644 --- a/deepmd/descriptor/se_a.py +++ b/deepmd/descriptor/se_a.py @@ -5,8 +5,8 @@ from deepmd.env import tf from deepmd.common import get_activation_func, get_precision, ACTIVATION_FN_DICT, PRECISION_DICT, docstring_parameter, get_np_precision from deepmd.utils.argcheck import list_to_doc -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION from deepmd.env import op_module from deepmd.env import default_tf_session_config from deepmd.utils.network import embedding_net diff --git a/deepmd/descriptor/se_a_ebd.py b/deepmd/descriptor/se_a_ebd.py index c88bc83e0b..d827925389 100644 --- a/deepmd/descriptor/se_a_ebd.py +++ b/deepmd/descriptor/se_a_ebd.py @@ -4,8 +4,8 @@ from deepmd.env import tf from deepmd.common import ClassArg, get_activation_func, get_precision, add_data_requirement from deepmd.utils.network import one_layer -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION from deepmd.env import op_module from deepmd.env import default_tf_session_config from deepmd.utils.network import embedding_net diff --git a/deepmd/descriptor/se_a_ef.py b/deepmd/descriptor/se_a_ef.py index 3f30c52f08..e97f011af0 100644 --- a/deepmd/descriptor/se_a_ef.py +++ b/deepmd/descriptor/se_a_ef.py @@ -4,8 +4,8 @@ from deepmd.env import tf from deepmd.common import add_data_requirement,get_activation_func, get_precision, ACTIVATION_FN_DICT, PRECISION_DICT, docstring_parameter from deepmd.utils.argcheck import list_to_doc -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION from deepmd.env import op_module from deepmd.env import default_tf_session_config from .se_a import DescrptSeA diff --git a/deepmd/descriptor/se_a_t.py b/deepmd/descriptor/se_a_t.py index f2f44e8c2a..2515126690 100644 --- a/deepmd/descriptor/se_a_t.py +++ b/deepmd/descriptor/se_a_t.py @@ -4,8 +4,8 @@ from deepmd.env import tf from deepmd.common import get_activation_func, get_precision, ACTIVATION_FN_DICT, PRECISION_DICT, docstring_parameter from deepmd.utils.argcheck import list_to_doc -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION from deepmd.env import op_module from deepmd.env import default_tf_session_config from deepmd.utils.network import embedding_net diff --git a/deepmd/descriptor/se_r.py b/deepmd/descriptor/se_r.py index 4a73457299..91055aef17 100644 --- a/deepmd/descriptor/se_r.py +++ b/deepmd/descriptor/se_r.py @@ -4,8 +4,8 @@ from deepmd.env import tf from deepmd.common import get_activation_func, get_precision, ACTIVATION_FN_DICT, PRECISION_DICT, docstring_parameter from deepmd.utils.argcheck import list_to_doc -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION from deepmd.env import op_module from deepmd.env import default_tf_session_config from deepmd.utils.network import embedding_net diff --git a/deepmd/entrypoints/print_old_model.py b/deepmd/entrypoints/print_old_model.py deleted file mode 100644 index cf941b8e25..0000000000 --- a/deepmd/entrypoints/print_old_model.py +++ /dev/null @@ -1,83 +0,0 @@ -import dpdata,os,sys -import numpy as np -import tensorflow as tf -from common import Data - -# hash: b721960c9d5c61ee161f9e929c7d76f77673bc10 - -lib_path = os.path.dirname(os.path.realpath(__file__)) + ".." -sys.path.append (lib_path) - -from deepmd.run_options import RunOptions -from deepmd.DataSystem import DataSystem -from deepmd.model import NNPModel -from deepmd.model import LearingRate -from deepmd.common import j_must_have, j_loader - -def gen_data() : - tmpdata = Data(rand_pert = 0.1, seed = 1) - sys = dpdata.LabeledSystem() - sys.data['coords'] = tmpdata.coord - sys.data['atom_types'] = tmpdata.atype - sys.data['cells'] = tmpdata.cell - nframes = tmpdata.nframes - natoms = tmpdata.natoms - print(sys.data['coords']) - sys.data['coords'] = sys.data['coords'].reshape([nframes,natoms,3]) - sys.data['cells'] = sys.data['cells'].reshape([nframes,3,3]) - sys.data['energies'] = np.zeros([nframes,1]) - sys.data['forces'] = np.zeros([nframes,natoms,3]) - sys.data['virials'] = [] - sys.to_deepmd_npy('system', prec=np.float64) - np.save('system/set.000/fparam.npy', tmpdata.fparam) - -def compute_efv(jfile): - jdata = j_loader(jfile) - run_opt = RunOptions() - systems = j_must_have(jdata, 'systems') - set_pfx = j_must_have(jdata, 'set_prefix') - batch_size = j_must_have(jdata, 'batch_size') - test_size = j_must_have(jdata, 'numb_test') - batch_size = 1 - test_size = 1 - rcut = j_must_have (jdata, 'rcut') - - data = DataSystem(systems, set_pfx, batch_size, test_size, rcut, run_opt) - - tot_numb_batches = sum(data.get_nbatches()) - lr = LearingRate (jdata, tot_numb_batches) - - model = NNPModel (jdata, run_opt = run_opt) - model.build (data, lr) - - test_data = data.get_test () - - feed_dict_test = {model.t_prop_c: test_data["prop_c"], - model.t_energy: test_data["energy"] [:model.numb_test], - model.t_force: np.reshape(test_data["force"] [:model.numb_test, :], [-1]), - model.t_virial: np.reshape(test_data["virial"] [:model.numb_test, :], [-1]), - model.t_atom_ener: np.reshape(test_data["atom_ener"][:model.numb_test, :], [-1]), - model.t_atom_pref: np.reshape(test_data["atom_pref"][:model.numb_test, :], [-1]), - model.t_coord: np.reshape(test_data["coord"] [:model.numb_test, :], [-1]), - model.t_box: test_data["box"] [:model.numb_test, :], - model.t_type: np.reshape(test_data["type"] [:model.numb_test, :], [-1]), - model.t_natoms: test_data["natoms_vec"], - model.t_mesh: test_data["default_mesh"], - model.t_fparam: np.reshape(test_data["fparam"] [:model.numb_test, :], [-1]), - model.is_training: False} - - sess = tf.Session() - sess.run(tf.global_variables_initializer()) - [e, f, v] = sess.run([model.energy, model.force, model.virial], - feed_dict = feed_dict_test) - return e,f,v - -def _main() : - gen_data() - e,f,v = compute_efv('water_smth.json') - np.savetxt('e.out', e, delimiter=',') - np.savetxt('f.out', f, delimiter=',') - np.savetxt('v.out', v, delimiter=',') - - -_main() diff --git a/deepmd/entrypoints/train.py b/deepmd/entrypoints/train.py index 3bc629ae4e..685815db17 100755 --- a/deepmd/entrypoints/train.py +++ b/deepmd/entrypoints/train.py @@ -12,8 +12,8 @@ from deepmd.common import data_requirement, expand_sys_str, j_loader, j_must_have from deepmd.env import tf from deepmd.infer.data_modifier import DipoleChargeModifier -from deepmd.run_options import BUILD, CITATION, WELCOME, RunOptions -from deepmd.trainer import NNPTrainer +from deepmd.train.run_options import BUILD, CITATION, WELCOME, RunOptions +from deepmd.train.trainer import DPTrainer from deepmd.utils.argcheck import normalize from deepmd.utils.compat import convert_input_v0_v1 from deepmd.utils.data_system import DeepmdDataSystem @@ -230,7 +230,7 @@ def _do_work(jdata: Dict[str, Any], run_opt: RunOptions): assert "training" in jdata # init the model - model = NNPTrainer(jdata, run_opt=run_opt) + model = DPTrainer(jdata, run_opt=run_opt) rcut = model.model.get_rcut() type_map = model.model.get_type_map() if len(type_map) == 0: diff --git a/deepmd/env.py b/deepmd/env.py index b39b3fe6e0..8c6937b7f7 100644 --- a/deepmd/env.py +++ b/deepmd/env.py @@ -4,9 +4,10 @@ from pathlib import Path import logging import platform -from typing import Tuple, TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Any import numpy as np from imp import reload +from configparser import ConfigParser if TYPE_CHECKING: from types import ModuleType @@ -19,8 +20,22 @@ except ImportError: import tensorflow as tf -SHARED_LIB_MODULE = "op" +__all__ = [ + "GLOBAL_CONFIG", + "GLOBAL_TF_FLOAT_PRECISION", + "GLOBAL_NP_FLOAT_PRECISION", + "GLOBAL_ENER_FLOAT_PRECISION", + "global_float_prec", + "global_cvt_2_tf_float", + "global_cvt_2_ener_float", + "MODEL_VERSION", + "SHARED_LIB_MODULE", + "default_tf_session_config", + "op_module", + "op_grads_module", +] +SHARED_LIB_MODULE = "op" def set_env_if_empty(key: str, value: str, verbose: bool = True): """Set environment variable only if it is empty. @@ -103,6 +118,7 @@ def get_tf_session_config() -> Any: intra_op_parallelism_threads=intra, inter_op_parallelism_threads=inter ) +default_tf_session_config = get_tf_session_config() def get_module(module_name: str) -> "ModuleType": """Load force module. @@ -139,4 +155,71 @@ def get_module(module_name: str) -> "ModuleType": op_module = get_module("libop_abi") op_grads_module = get_module("libop_grads") -default_tf_session_config = get_tf_session_config() + + +def _get_package_constants( + config_file: Path = Path(__file__).parent / "pkg_config/run_config.ini", +) -> Dict[str, str]: + """Read package constants set at compile time by CMake to dictionary. + + Parameters + ---------- + config_file : str, optional + path to CONFIG file, by default "config/run_config.ini" + + Returns + ------- + Dict[str, str] + dictionary with package constants + """ + config = ConfigParser() + config.read(config_file) + return dict(config.items("CONFIG")) + +GLOBAL_CONFIG = _get_package_constants() +MODEL_VERSION = GLOBAL_CONFIG["model_version"] + +if GLOBAL_CONFIG["precision"] == "-DHIGH_PREC": + GLOBAL_TF_FLOAT_PRECISION = tf.float64 + GLOBAL_NP_FLOAT_PRECISION = np.float64 + GLOBAL_ENER_FLOAT_PRECISION = np.float64 + global_float_prec = "double" +else: + GLOBAL_TF_FLOAT_PRECISION = tf.float32 + GLOBAL_NP_FLOAT_PRECISION = np.float32 + GLOBAL_ENER_FLOAT_PRECISION = np.float64 + global_float_prec = "float" + + +def global_cvt_2_tf_float(xx: tf.Tensor) -> tf.Tensor: + """Cast tensor to globally set TF precision. + + Parameters + ---------- + xx : tf.Tensor + input tensor + + Returns + ------- + tf.Tensor + output tensor cast to `GLOBAL_TF_FLOAT_PRECISION` + """ + return tf.cast(xx, GLOBAL_TF_FLOAT_PRECISION) + + +def global_cvt_2_ener_float(xx: tf.Tensor) -> tf.Tensor: + """Cast tensor to globally set energy precision. + + Parameters + ---------- + xx : tf.Tensor + input tensor + + Returns + ------- + tf.Tensor + output tensor cast to `GLOBAL_ENER_FLOAT_PRECISION` + """ + return tf.cast(xx, GLOBAL_ENER_FLOAT_PRECISION) + + diff --git a/deepmd/fit/dipole.py b/deepmd/fit/dipole.py index f940675ac1..623f8a782e 100644 --- a/deepmd/fit/dipole.py +++ b/deepmd/fit/dipole.py @@ -8,8 +8,8 @@ from deepmd.utils.network import one_layer from deepmd.descriptor import DescrptSeA -from deepmd.run_options import global_cvt_2_tf_float -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import global_cvt_2_tf_float +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION class DipoleFittingSeA () : """ diff --git a/deepmd/fit/ener.py b/deepmd/fit/ener.py index 24debd43fc..5d60ffcc09 100644 --- a/deepmd/fit/ener.py +++ b/deepmd/fit/ener.py @@ -9,8 +9,8 @@ from deepmd.descriptor import DescrptLocFrame from deepmd.descriptor import DescrptSeA -from deepmd.run_options import global_cvt_2_tf_float -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import global_cvt_2_tf_float +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION class EnerFitting (): @docstring_parameter(list_to_doc(ACTIVATION_FN_DICT.keys()), list_to_doc(PRECISION_DICT.keys())) diff --git a/deepmd/fit/polar.py b/deepmd/fit/polar.py index 969491f484..709d00c1df 100644 --- a/deepmd/fit/polar.py +++ b/deepmd/fit/polar.py @@ -9,8 +9,8 @@ from deepmd.descriptor import DescrptLocFrame from deepmd.descriptor import DescrptSeA -from deepmd.run_options import global_cvt_2_tf_float -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import global_cvt_2_tf_float +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION class PolarFittingLocFrame () : diff --git a/deepmd/fit/wfc.py b/deepmd/fit/wfc.py index 063b1a9071..fc28744fb1 100644 --- a/deepmd/fit/wfc.py +++ b/deepmd/fit/wfc.py @@ -8,8 +8,8 @@ from deepmd.utils.network import one_layer from deepmd.descriptor import DescrptLocFrame -from deepmd.run_options import global_cvt_2_tf_float -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import global_cvt_2_tf_float +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION class WFCFitting () : """ diff --git a/deepmd/infer/data_modifier.py b/deepmd/infer/data_modifier.py index 0db33c2b02..c6fec62564 100644 --- a/deepmd/infer/data_modifier.py +++ b/deepmd/infer/data_modifier.py @@ -6,11 +6,11 @@ from deepmd.infer.ewald_recp import EwaldRecp from deepmd.env import tf from deepmd.common import select_idx_map, make_default_mesh -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION -from deepmd.run_options import global_cvt_2_tf_float -from deepmd.run_options import global_cvt_2_ener_float +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.env import global_cvt_2_tf_float +from deepmd.env import global_cvt_2_ener_float from deepmd.env import op_module diff --git a/deepmd/infer/deep_eval.py b/deepmd/infer/deep_eval.py index 83f9a7aa6d..92a45e3cd4 100644 --- a/deepmd/infer/deep_eval.py +++ b/deepmd/infer/deep_eval.py @@ -3,8 +3,7 @@ import numpy as np from deepmd.common import make_default_mesh -from deepmd.env import default_tf_session_config, tf -from deepmd.run_options import MODEL_VERSION +from deepmd.env import default_tf_session_config, tf, MODEL_VERSION if TYPE_CHECKING: from pathlib import Path diff --git a/deepmd/infer/ewald_recp.py b/deepmd/infer/ewald_recp.py index 2554b40114..68ee06c552 100644 --- a/deepmd/infer/ewald_recp.py +++ b/deepmd/infer/ewald_recp.py @@ -3,11 +3,11 @@ from deepmd.env import tf from deepmd.common import ClassArg -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION -from deepmd.run_options import global_cvt_2_tf_float -from deepmd.run_options import global_cvt_2_ener_float +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.env import global_cvt_2_tf_float +from deepmd.env import global_cvt_2_ener_float from deepmd.env import op_module from deepmd.env import default_tf_session_config diff --git a/deepmd/loss/ener.py b/deepmd/loss/ener.py index d4a5b11509..f25cb42219 100644 --- a/deepmd/loss/ener.py +++ b/deepmd/loss/ener.py @@ -2,8 +2,8 @@ from deepmd.env import tf from deepmd.common import ClassArg, add_data_requirement -from deepmd.run_options import global_cvt_2_tf_float -from deepmd.run_options import global_cvt_2_ener_float +from deepmd.env import global_cvt_2_tf_float +from deepmd.env import global_cvt_2_ener_float class EnerStdLoss () : """ diff --git a/deepmd/loss/tensor.py b/deepmd/loss/tensor.py index 3327c418d5..ceff94e14b 100644 --- a/deepmd/loss/tensor.py +++ b/deepmd/loss/tensor.py @@ -2,8 +2,8 @@ from deepmd.env import tf from deepmd.common import ClassArg, add_data_requirement -from deepmd.run_options import global_cvt_2_tf_float -from deepmd.run_options import global_cvt_2_ener_float +from deepmd.env import global_cvt_2_tf_float +from deepmd.env import global_cvt_2_ener_float class TensorLoss () : """ diff --git a/deepmd/model/ener.py b/deepmd/model/ener.py index 56f4880840..3cc3d4bd8b 100644 --- a/deepmd/model/ener.py +++ b/deepmd/model/ener.py @@ -4,7 +4,7 @@ from deepmd.env import tf from deepmd.utils.pair_tab import PairTab from deepmd.common import ClassArg -from deepmd.run_options import global_cvt_2_ener_float, MODEL_VERSION +from deepmd.env import global_cvt_2_ener_float, MODEL_VERSION from deepmd.env import op_module from .model_stat import make_stat_input, merge_sys_stat diff --git a/deepmd/model/tensor.py b/deepmd/model/tensor.py index 8df73f4ff0..114a319edd 100644 --- a/deepmd/model/tensor.py +++ b/deepmd/model/tensor.py @@ -3,7 +3,7 @@ from deepmd.env import tf from deepmd.common import ClassArg -from deepmd.run_options import global_cvt_2_ener_float, MODEL_VERSION +from deepmd.env import global_cvt_2_ener_float, MODEL_VERSION from deepmd.env import op_module from .model_stat import make_stat_input, merge_sys_stat diff --git a/source/train/run_options.py b/deepmd/train/run_options.py similarity index 85% rename from source/train/run_options.py rename to deepmd/train/run_options.py index 0ef39a7e95..cdfea06ff8 100644 --- a/source/train/run_options.py +++ b/deepmd/train/run_options.py @@ -2,13 +2,12 @@ import logging import os -from configparser import ConfigParser from pathlib import Path from typing import TYPE_CHECKING, Dict, List, Optional, Tuple import numpy as np from deepmd.cluster import get_resource -from deepmd.env import get_tf_default_nthreads, tf +from deepmd.env import get_tf_default_nthreads, tf, GLOBAL_CONFIG, global_float_prec from deepmd.loggers import set_log_handles if TYPE_CHECKING: @@ -27,55 +26,15 @@ class TFServerV1(Protocol): __all__ = [ - "GLOBAL_TF_FLOAT_PRECISION", - "GLOBAL_NP_FLOAT_PRECISION", - "GLOBAL_ENER_FLOAT_PRECISION", "WELCOME", "CITATION", "BUILD", - "global_cvt_2_tf_float", - "global_cvt_2_ener_float", "RunOptions", - "MODEL_VERSION", ] log = logging.getLogger(__name__) -def _get_package_constants( - config_file: Path = Path(__file__).parent / "pkg_config/run_config.ini", -) -> Dict[str, str]: - """Read package constants set at compile time by CMake to dictionary. - - Parameters - ---------- - config_file : str, optional - path to CONFIG file, by default "config/run_config.ini" - - Returns - ------- - Dict[str, str] - dictionary with package constants - """ - config = ConfigParser() - config.read(config_file) - return dict(config.items("CONFIG")) - - -GLOBAL_CONFIG = _get_package_constants() -MODEL_VERSION = GLOBAL_CONFIG["model_version"] - -if GLOBAL_CONFIG["precision"] == "-DHIGH_PREC": - GLOBAL_TF_FLOAT_PRECISION = tf.float64 - GLOBAL_NP_FLOAT_PRECISION = np.float64 - GLOBAL_ENER_FLOAT_PRECISION = np.float64 - global_float_prec = "double" -else: - GLOBAL_TF_FLOAT_PRECISION = tf.float32 - GLOBAL_NP_FLOAT_PRECISION = np.float32 - GLOBAL_ENER_FLOAT_PRECISION = np.float64 - global_float_prec = "float" - # http://patorjk.com/software/taag. Font:Big" WELCOME = ( # noqa " _____ _____ __ __ _____ _ _ _ ", @@ -104,38 +63,6 @@ def _get_package_constants( ) -def global_cvt_2_tf_float(xx: tf.Tensor) -> tf.Tensor: - """Cast tensor to globally set TF precision. - - Parameters - ---------- - xx : tf.Tensor - input tensor - - Returns - ------- - tf.Tensor - output tensor cast to `GLOBAL_TF_FLOAT_PRECISION` - """ - return tf.cast(xx, GLOBAL_TF_FLOAT_PRECISION) - - -def global_cvt_2_ener_float(xx: tf.Tensor) -> tf.Tensor: - """Cast tensor to globally set energy precision. - - Parameters - ---------- - xx : tf.Tensor - input tensor - - Returns - ------- - tf.Tensor - output tensor cast to `GLOBAL_ENER_FLOAT_PRECISION` - """ - return tf.cast(xx, GLOBAL_ENER_FLOAT_PRECISION) - - def _is_distributed(MPI: "MPI") -> bool: """Check if there are more than one MPI processes. diff --git a/source/train/trainer.py b/deepmd/train/trainer.py similarity index 99% rename from source/train/trainer.py rename to deepmd/train/trainer.py index fd9962ec90..1ea177fd95 100644 --- a/source/train/trainer.py +++ b/deepmd/train/trainer.py @@ -6,8 +6,8 @@ import numpy as np from deepmd.env import tf from deepmd.env import default_tf_session_config -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_ENER_FLOAT_PRECISION from deepmd.fit import EnerFitting, WFCFitting, PolarFittingLocFrame, PolarFittingSeA, GlobalPolarFittingSeA, DipoleFittingSeA from deepmd.descriptor import DescrptLocFrame from deepmd.descriptor import DescrptSeA @@ -72,7 +72,7 @@ def _generate_descrpt_from_param_dict(descrpt_param): return descrpt -class NNPTrainer (object): +class DPTrainer (object): def __init__(self, jdata, run_opt): diff --git a/deepmd/utils/data.py b/deepmd/utils/data.py index 958de14583..4b8edebb2d 100644 --- a/deepmd/utils/data.py +++ b/deepmd/utils/data.py @@ -6,8 +6,8 @@ import os.path from typing import Tuple, List -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_ENER_FLOAT_PRECISION class DeepmdData() : """ diff --git a/deepmd/utils/neighbor_stat.py b/deepmd/utils/neighbor_stat.py index 255a81b453..991993e364 100644 --- a/deepmd/utils/neighbor_stat.py +++ b/deepmd/utils/neighbor_stat.py @@ -6,7 +6,7 @@ from typing import Tuple, List from deepmd.env import op_module from deepmd.env import default_tf_session_config -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION from deepmd.utils.data_system import DeepmdDataSystem log = logging.getLogger(__name__) diff --git a/deepmd/utils/network.py b/deepmd/utils/network.py index 6bebcd044e..ab32308bdd 100644 --- a/deepmd/utils/network.py +++ b/deepmd/utils/network.py @@ -1,7 +1,7 @@ import numpy as np from deepmd.env import tf -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION def one_layer(inputs, outputs_size, diff --git a/setup.py b/setup.py index a415187f35..59d7060471 100644 --- a/setup.py +++ b/setup.py @@ -88,6 +88,7 @@ "deepmd/entrypoints", "deepmd/op", "deepmd/model", + "deepmd/train", ], python_requires=">=3.6", classifiers=[ diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 07f5bf7760..d08f933471 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -211,7 +211,7 @@ add_subdirectory (op/) add_subdirectory (lib/) if (BUILD_PY_IF) add_subdirectory (train/) - add_subdirectory (tests/) + # add_subdirectory (tests/) endif (BUILD_PY_IF) if (BUILD_CPP_IF) add_subdirectory (api_cc/) diff --git a/source/tests/common.py b/source/tests/common.py index d1e23c89ea..1b1f37c3f5 100644 --- a/source/tests/common.py +++ b/source/tests/common.py @@ -3,9 +3,9 @@ import pathlib from deepmd.env import tf -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_ENER_FLOAT_PRECISION from deepmd.common import j_loader as dp_j_loader if GLOBAL_NP_FLOAT_PRECISION == np.float32 : diff --git a/source/tests/test_data_modifier.py b/source/tests/test_data_modifier.py index 9c47fa15dd..c824262eb1 100644 --- a/source/tests/test_data_modifier.py +++ b/source/tests/test_data_modifier.py @@ -4,12 +4,12 @@ from deepmd.env import tf from deepmd.common import j_must_have, data_requirement -from deepmd.run_options import RunOptions -from deepmd.trainer import NNPTrainer +from deepmd.train.run_options import RunOptions +from deepmd.train.trainer import DPTrainer from deepmd.utils.data_system import DeepmdDataSystem -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_ENER_FLOAT_PRECISION from deepmd.infer.ewald_recp import EwaldRecp from deepmd.infer.data_modifier import DipoleChargeModifier @@ -50,7 +50,7 @@ def _setUp(self): jdata = j_loader(INPUT) # init model - model = NNPTrainer (jdata, run_opt = run_opt) + model = DPTrainer (jdata, run_opt = run_opt) rcut = model.model.get_rcut() # init data system diff --git a/source/tests/test_data_modifier_shuffle.py b/source/tests/test_data_modifier_shuffle.py index 36ebfef35a..6476ac2a63 100644 --- a/source/tests/test_data_modifier_shuffle.py +++ b/source/tests/test_data_modifier_shuffle.py @@ -5,12 +5,12 @@ from deepmd.env import tf from deepmd.common import j_must_have, data_requirement -from deepmd.run_options import RunOptions -from deepmd.trainer import NNPTrainer +from deepmd.train.run_options import RunOptions +from deepmd.train.trainer import DPTrainer from deepmd.utils.data_system import DeepmdDataSystem -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_ENER_FLOAT_PRECISION from deepmd.infer.ewald_recp import EwaldRecp from deepmd.infer.data_modifier import DipoleChargeModifier from deepmd.infer.deep_dipole import DeepDipole @@ -56,7 +56,7 @@ def _setUp(self): self._setUp_data() # init model - model = NNPTrainer (jdata, run_opt = run_opt) + model = DPTrainer (jdata, run_opt = run_opt) rcut = model.model.get_rcut() # init data system diff --git a/source/tests/test_deepdipole.py b/source/tests/test_deepdipole.py index 6d0e84aa14..2856b4f319 100644 --- a/source/tests/test_deepdipole.py +++ b/source/tests/test_deepdipole.py @@ -6,7 +6,7 @@ from deepmd.infer import DeepDipole from common import tests_path -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION if GLOBAL_NP_FLOAT_PRECISION == np.float32 : default_places = 4 else : diff --git a/source/tests/test_deepmd_data.py b/source/tests/test_deepmd_data.py index 2f01099137..3b1352ad93 100644 --- a/source/tests/test_deepmd_data.py +++ b/source/tests/test_deepmd_data.py @@ -3,7 +3,7 @@ import unittest from deepmd.utils.data import DeepmdData -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION if GLOBAL_NP_FLOAT_PRECISION == np.float32 : places = 6 diff --git a/source/tests/test_deepmd_data_sys.py b/source/tests/test_deepmd_data_sys.py index c710878f73..5f78e6e116 100644 --- a/source/tests/test_deepmd_data_sys.py +++ b/source/tests/test_deepmd_data_sys.py @@ -3,7 +3,7 @@ import unittest from deepmd.utils.data_system import DeepmdDataSystem -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION if GLOBAL_NP_FLOAT_PRECISION == np.float32 : places = 6 diff --git a/source/tests/test_deeppolar.py b/source/tests/test_deeppolar.py index da0fd6b377..0783381548 100644 --- a/source/tests/test_deeppolar.py +++ b/source/tests/test_deeppolar.py @@ -6,7 +6,7 @@ from deepmd.infer import DeepPolar from common import tests_path -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION if GLOBAL_NP_FLOAT_PRECISION == np.float32 : default_places = 4 else : diff --git a/source/tests/test_deeppot_a.py b/source/tests/test_deeppot_a.py index f4e73682f3..3726299fb5 100644 --- a/source/tests/test_deeppot_a.py +++ b/source/tests/test_deeppot_a.py @@ -4,10 +4,10 @@ from infer.convert2pb import convert_pbtxt_to_pb from deepmd.infer import DeepPot -from deepmd.run_options import MODEL_VERSION +from deepmd.env import MODEL_VERSION from common import tests_path -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION if GLOBAL_NP_FLOAT_PRECISION == np.float32 : default_places = 4 else : diff --git a/source/tests/test_deeppot_r.py b/source/tests/test_deeppot_r.py index 7f9a97ce66..c43a71677a 100644 --- a/source/tests/test_deeppot_r.py +++ b/source/tests/test_deeppot_r.py @@ -6,7 +6,7 @@ from deepmd.infer import DeepPot from common import tests_path -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION if GLOBAL_NP_FLOAT_PRECISION == np.float32 : default_places = 4 else : diff --git a/source/tests/test_descrpt_nonsmth.py b/source/tests/test_descrpt_nonsmth.py index ee336f8fe4..1b99934d12 100644 --- a/source/tests/test_descrpt_nonsmth.py +++ b/source/tests/test_descrpt_nonsmth.py @@ -16,9 +16,9 @@ from deepmd.env import op_module -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_ENER_FLOAT_PRECISION class Inter(): def setUp (self, diff --git a/source/tests/test_descrpt_se_ar.py b/source/tests/test_descrpt_se_ar.py index f2ec7bc8aa..03026cff97 100644 --- a/source/tests/test_descrpt_se_ar.py +++ b/source/tests/test_descrpt_se_ar.py @@ -16,9 +16,9 @@ from deepmd.descriptor import DescrptSeAR -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_ENER_FLOAT_PRECISION class Inter(): def setUp (self, diff --git a/source/tests/test_descrpt_se_r.py b/source/tests/test_descrpt_se_r.py index b2fa7ab3e5..f1d6623e64 100644 --- a/source/tests/test_descrpt_se_r.py +++ b/source/tests/test_descrpt_se_r.py @@ -16,9 +16,9 @@ from deepmd.env import op_module -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_ENER_FLOAT_PRECISION class Inter(): def setUp (self, diff --git a/source/tests/test_descrpt_sea_ef.py b/source/tests/test_descrpt_sea_ef.py index a75bd6d436..43b95f1cbc 100644 --- a/source/tests/test_descrpt_sea_ef.py +++ b/source/tests/test_descrpt_sea_ef.py @@ -16,9 +16,9 @@ from deepmd.env import op_module -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_ENER_FLOAT_PRECISION class Inter(): def setUp (self, diff --git a/source/tests/test_descrpt_sea_ef_para.py b/source/tests/test_descrpt_sea_ef_para.py index 602eafb54d..0e94147161 100644 --- a/source/tests/test_descrpt_sea_ef_para.py +++ b/source/tests/test_descrpt_sea_ef_para.py @@ -16,9 +16,9 @@ from deepmd.env import op_module -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_ENER_FLOAT_PRECISION class Inter(): def setUp (self, diff --git a/source/tests/test_descrpt_sea_ef_rot.py b/source/tests/test_descrpt_sea_ef_rot.py index 904ccfd965..10e38cdbda 100644 --- a/source/tests/test_descrpt_sea_ef_rot.py +++ b/source/tests/test_descrpt_sea_ef_rot.py @@ -4,9 +4,9 @@ from deepmd.env import tf from tensorflow.python.framework import ops -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_ENER_FLOAT_PRECISION from deepmd.env import op_module from deepmd.descriptor import DescrptSeA diff --git a/source/tests/test_descrpt_sea_ef_vert.py b/source/tests/test_descrpt_sea_ef_vert.py index 3f44e4d15b..a0d160e966 100644 --- a/source/tests/test_descrpt_sea_ef_vert.py +++ b/source/tests/test_descrpt_sea_ef_vert.py @@ -16,9 +16,9 @@ from deepmd.env import op_module -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_ENER_FLOAT_PRECISION class Inter(): def setUp (self, diff --git a/source/tests/test_descrpt_smooth.py b/source/tests/test_descrpt_smooth.py index 6a72af7db5..05cb14b26e 100644 --- a/source/tests/test_descrpt_smooth.py +++ b/source/tests/test_descrpt_smooth.py @@ -16,9 +16,9 @@ from deepmd.env import op_module -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_ENER_FLOAT_PRECISION class Inter(): def setUp (self, diff --git a/source/tests/test_dipolecharge.py b/source/tests/test_dipolecharge.py index 94b94dffe2..ccda444a32 100644 --- a/source/tests/test_dipolecharge.py +++ b/source/tests/test_dipolecharge.py @@ -6,7 +6,7 @@ from deepmd.infer import DipoleChargeModifier from common import tests_path -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION if GLOBAL_NP_FLOAT_PRECISION == np.float32 : default_places = 4 else : diff --git a/source/tests/test_embedding_net.py b/source/tests/test_embedding_net.py index f7839b6408..58cc331001 100644 --- a/source/tests/test_embedding_net.py +++ b/source/tests/test_embedding_net.py @@ -7,9 +7,9 @@ from deepmd.utils.network import embedding_net -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_ENER_FLOAT_PRECISION class Inter(unittest.TestCase): def setUp (self) : diff --git a/source/tests/test_ewald.py b/source/tests/test_ewald.py index 6fc39d923c..83c5bc3a6d 100644 --- a/source/tests/test_ewald.py +++ b/source/tests/test_ewald.py @@ -3,9 +3,9 @@ import unittest from deepmd.env import tf -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_ENER_FLOAT_PRECISION from deepmd.infer.ewald_recp import op_module from deepmd.infer.ewald_recp import EwaldRecp diff --git a/source/tests/test_prod_env_mat.py b/source/tests/test_prod_env_mat.py index 347eb913ea..853d900109 100644 --- a/source/tests/test_prod_env_mat.py +++ b/source/tests/test_prod_env_mat.py @@ -5,9 +5,9 @@ import deepmd.op from deepmd.env import tf from deepmd.env import op_module -from deepmd.run_options import GLOBAL_TF_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION -from deepmd.run_options import GLOBAL_ENER_FLOAT_PRECISION +from deepmd.env import GLOBAL_TF_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_ENER_FLOAT_PRECISION class TestProdEnvMat(unittest.TestCase): def setUp(self): diff --git a/source/tests/test_transfer.py b/source/tests/test_transfer.py index bbc0719f0f..410ee20fc1 100644 --- a/source/tests/test_transfer.py +++ b/source/tests/test_transfer.py @@ -8,7 +8,7 @@ from infer.convert2pb import convert_pbtxt_to_pb from deepmd.entrypoints.transfer import load_graph, transform_graph -from deepmd.run_options import GLOBAL_NP_FLOAT_PRECISION +from deepmd.env import GLOBAL_NP_FLOAT_PRECISION if GLOBAL_NP_FLOAT_PRECISION == np.float32 : default_places = 4 else : From b570868dba0f05bb342b31a778a12b1a33fde5fe Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 27 Mar 2021 22:31:01 +0800 Subject: [PATCH 303/562] do not install moved files --- source/train/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/train/CMakeLists.txt b/source/train/CMakeLists.txt index 8dd7c60d04..4b3843d6f9 100644 --- a/source/train/CMakeLists.txt +++ b/source/train/CMakeLists.txt @@ -2,7 +2,7 @@ configure_file("run_config.ini" "${CMAKE_CURRENT_BINARY_DIR}/run_config.ini" @ONLY) -file(GLOB LIB_PY main.py calculator.py trainer.py run_options.py ) +file(GLOB LIB_PY main.py ) install( FILES ${LIB_PY} From 028e8c82f870500aadb5e074e71f64dda85c7d5a Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 27 Mar 2021 22:44:32 +0800 Subject: [PATCH 304/562] mv main to entrypoints, mv source/train to source/config --- deepmd/__main__.py | 2 +- {source/train => deepmd/entrypoints}/main.py | 0 setup.py | 2 +- source/{train => config}/CMakeLists.txt | 8 +------- source/{train => config}/MODEL_VER | 0 source/{train => config}/run_config.ini | 0 6 files changed, 3 insertions(+), 9 deletions(-) rename {source/train => deepmd/entrypoints}/main.py (100%) rename source/{train => config}/CMakeLists.txt (67%) rename source/{train => config}/MODEL_VER (100%) rename source/{train => config}/run_config.ini (100%) diff --git a/deepmd/__main__.py b/deepmd/__main__.py index 7ffb7018f9..2dea15ee78 100644 --- a/deepmd/__main__.py +++ b/deepmd/__main__.py @@ -1,6 +1,6 @@ """Package dp entry point.""" -from .main import main +from .entrypoints.main import main if __name__ == '__main__': main() diff --git a/source/train/main.py b/deepmd/entrypoints/main.py similarity index 100% rename from source/train/main.py rename to deepmd/entrypoints/main.py diff --git a/setup.py b/setup.py index 59d7060471..5f7f2fa8bc 100644 --- a/setup.py +++ b/setup.py @@ -110,5 +110,5 @@ "docs": ["sphinx", "recommonmark", "sphinx_rtd_theme"], **extras_require, }, - entry_points={"console_scripts": ["dp = deepmd.main:main"]}, + entry_points={"console_scripts": ["dp = deepmd.entrypoints.main:main"]}, ) diff --git a/source/train/CMakeLists.txt b/source/config/CMakeLists.txt similarity index 67% rename from source/train/CMakeLists.txt rename to source/config/CMakeLists.txt index 4b3843d6f9..faab6e3e36 100644 --- a/source/train/CMakeLists.txt +++ b/source/config/CMakeLists.txt @@ -1,13 +1,7 @@ -# train +# config configure_file("run_config.ini" "${CMAKE_CURRENT_BINARY_DIR}/run_config.ini" @ONLY) -file(GLOB LIB_PY main.py ) - -install( - FILES ${LIB_PY} - DESTINATION deepmd -) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/run_config.ini DESTINATION deepmd/pkg_config diff --git a/source/train/MODEL_VER b/source/config/MODEL_VER similarity index 100% rename from source/train/MODEL_VER rename to source/config/MODEL_VER diff --git a/source/train/run_config.ini b/source/config/run_config.ini similarity index 100% rename from source/train/run_config.ini rename to source/config/run_config.ini From eab28a718cda16424e1380382ba0276da4bf58c1 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 27 Mar 2021 22:45:32 +0800 Subject: [PATCH 305/562] fix bugs --- source/tests/test_argument_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/tests/test_argument_parser.py b/source/tests/test_argument_parser.py index ac5ea959a2..356dd430c1 100644 --- a/source/tests/test_argument_parser.py +++ b/source/tests/test_argument_parser.py @@ -7,7 +7,7 @@ from io import StringIO from contextlib import redirect_stderr -from deepmd.main import parse_args, get_ll +from deepmd.entrypoints.main import parse_args, get_ll if TYPE_CHECKING: try: From 7b1ff75acbbd28f11ce4b81ec655ca5bf2353605 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 27 Mar 2021 22:45:54 +0800 Subject: [PATCH 306/562] fix bug --- source/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index d08f933471..908edd2b0a 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -47,7 +47,7 @@ list (APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-ignored-attributes") # model version -file(READ ${PROJECT_SOURCE_DIR}/train/MODEL_VER MODEL_VERSION) +file(READ ${PROJECT_SOURCE_DIR}/config/MODEL_VER MODEL_VERSION) string(REPLACE "\n" " " MODEL_VERSION ${MODEL_VERSION}) message(STATUS "Supported model version: ${MODEL_VERSION}") @@ -210,7 +210,7 @@ endif (BUILD_CPP_IF) add_subdirectory (op/) add_subdirectory (lib/) if (BUILD_PY_IF) - add_subdirectory (train/) + add_subdirectory (config/) # add_subdirectory (tests/) endif (BUILD_PY_IF) if (BUILD_CPP_IF) From f142eb566603af19deb6213c4f147d783cade109 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 28 Mar 2021 00:03:30 +0800 Subject: [PATCH 307/562] fig bug: wrong place of model version --- source/api_cc/tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/api_cc/tests/CMakeLists.txt b/source/api_cc/tests/CMakeLists.txt index aabf452038..0c8819fe46 100644 --- a/source/api_cc/tests/CMakeLists.txt +++ b/source/api_cc/tests/CMakeLists.txt @@ -12,7 +12,7 @@ enable_testing() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") # model version -file(READ ${PROJECT_SOURCE_DIR}/../../train/MODEL_VER MODEL_VERSION) +file(READ ${PROJECT_SOURCE_DIR}/../../config/MODEL_VER MODEL_VERSION) string(REPLACE "\n" " " MODEL_VERSION ${MODEL_VERSION}) message(STATUS "Supported model version: ${MODEL_VERSION}") From 1388bcdccf445f1b626e3a04ef92834f5e0b8f65 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 29 Mar 2021 14:58:46 +0800 Subject: [PATCH 308/562] rm old-style implementation of prod_env_mat, prod_force and prod_virial --- source/op/CMakeLists.txt | 2 +- source/op/{ => legacy}/descrpt_se_a.cc | 0 source/op/{ => legacy}/descrpt_se_r.cc | 0 source/op/{ => legacy}/prod_force_se_a.cc | 0 source/op/{ => legacy}/prod_force_se_r.cc | 0 source/op/{ => legacy}/prod_virial_se_a.cc | 0 source/op/{ => legacy}/prod_virial_se_r.cc | 0 7 files changed, 1 insertion(+), 1 deletion(-) rename source/op/{ => legacy}/descrpt_se_a.cc (100%) rename source/op/{ => legacy}/descrpt_se_r.cc (100%) rename source/op/{ => legacy}/prod_force_se_a.cc (100%) rename source/op/{ => legacy}/prod_force_se_r.cc (100%) rename source/op/{ => legacy}/prod_virial_se_a.cc (100%) rename source/op/{ => legacy}/prod_virial_se_r.cc (100%) diff --git a/source/op/CMakeLists.txt b/source/op/CMakeLists.txt index ced3cd0bf5..8ec98461be 100644 --- a/source/op/CMakeLists.txt +++ b/source/op/CMakeLists.txt @@ -3,7 +3,7 @@ set(OP_LIB ${PROJECT_SOURCE_DIR}/lib/src/SimulationRegion.cpp ${PROJECT_SOURCE_DIR}/lib/src/neighbor_list.cc) set (OP_CXX_FLAG -D_GLIBCXX_USE_CXX11_ABI=${OP_CXX_ABI} ) -file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc descrpt_se_r.cc pair_tab.cc prod_force_se_a.cc prod_virial_se_a.cc prod_force_se_r.cc prod_virial_se_r.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc gelu_multi_device.cc map_aparam.cc neighbor_stat.cc unaggregated_grad.cc tabulate_multi_device.cc prod_env_mat_multi_device.cc) +file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc pair_tab.cc prod_force_multi_device.cc prod_virial_multi_device.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc gelu_multi_device.cc map_aparam.cc neighbor_stat.cc unaggregated_grad.cc tabulate_multi_device.cc prod_env_mat_multi_device.cc) file(GLOB OP_CUDA_SRC prod_force.cc prod_virial.cc descrpt.cc prod_env_mat_multi_device.cc pair_tab.cc prod_force_multi_device.cc prod_virial_multi_device.cc soft_min.cc soft_min_force.cc soft_min_virial.cc gelu_multi_device.cc tabulate_multi_device.cc) file(GLOB OP_GRADS_SRC prod_force_grad.cc prod_force_se_a_grad.cc prod_force_se_r_grad.cc prod_virial_grad.cc prod_virial_se_a_grad.cc prod_virial_se_r_grad.cc soft_min_force_grad.cc soft_min_virial_grad.cc ) file(GLOB OP_PY *.py) diff --git a/source/op/descrpt_se_a.cc b/source/op/legacy/descrpt_se_a.cc similarity index 100% rename from source/op/descrpt_se_a.cc rename to source/op/legacy/descrpt_se_a.cc diff --git a/source/op/descrpt_se_r.cc b/source/op/legacy/descrpt_se_r.cc similarity index 100% rename from source/op/descrpt_se_r.cc rename to source/op/legacy/descrpt_se_r.cc diff --git a/source/op/prod_force_se_a.cc b/source/op/legacy/prod_force_se_a.cc similarity index 100% rename from source/op/prod_force_se_a.cc rename to source/op/legacy/prod_force_se_a.cc diff --git a/source/op/prod_force_se_r.cc b/source/op/legacy/prod_force_se_r.cc similarity index 100% rename from source/op/prod_force_se_r.cc rename to source/op/legacy/prod_force_se_r.cc diff --git a/source/op/prod_virial_se_a.cc b/source/op/legacy/prod_virial_se_a.cc similarity index 100% rename from source/op/prod_virial_se_a.cc rename to source/op/legacy/prod_virial_se_a.cc diff --git a/source/op/prod_virial_se_r.cc b/source/op/legacy/prod_virial_se_r.cc similarity index 100% rename from source/op/prod_virial_se_r.cc rename to source/op/legacy/prod_virial_se_r.cc From d99124c35042a44c5c6315b911e13fa787e03aaa Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 29 Mar 2021 15:06:57 +0800 Subject: [PATCH 309/562] fix bug in cmake config of api UT --- source/api_cc/tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/api_cc/tests/CMakeLists.txt b/source/api_cc/tests/CMakeLists.txt index 0c8819fe46..3cdddd0d56 100644 --- a/source/api_cc/tests/CMakeLists.txt +++ b/source/api_cc/tests/CMakeLists.txt @@ -37,7 +37,7 @@ configure_file( set(opname "deepmd_op") set(OP_BASE_DIR ${CMAKE_SOURCE_DIR}/../../op) # file(GLOB OP_SRC ${OP_BASE_DIR}/*.cc) -file(GLOB OP_SRC ${OP_BASE_DIR}/prod_force.cc ${OP_BASE_DIR}/prod_virial.cc ${OP_BASE_DIR}/descrpt.cc ${OP_BASE_DIR}/descrpt_se_a.cc ${OP_BASE_DIR}/descrpt_se_a_ef.cc ${OP_BASE_DIR}/descrpt_se_a_ef.cc ${OP_BASE_DIR}/descrpt_se_a_ef_para.cc ${OP_BASE_DIR}/descrpt_se_a_ef_vert.cc ${OP_BASE_DIR}/descrpt_se_r.cc ${OP_BASE_DIR}/pair_tab.cc ${OP_BASE_DIR}/prod_force_se_a.cc ${OP_BASE_DIR}/prod_virial_se_a.cc ${OP_BASE_DIR}/prod_force_se_r.cc ${OP_BASE_DIR}/prod_virial_se_r.cc ${OP_BASE_DIR}/soft_min.cc ${OP_BASE_DIR}/soft_min_force.cc ${OP_BASE_DIR}/soft_min_virial.cc ${OP_BASE_DIR}/ewald_recp.cc ${OP_BASE_DIR}/gelu_multi_device.cc ${OP_BASE_DIR}/map_aparam.cc ${OP_BASE_DIR}/neighbor_stat.cc ${OP_BASE_DIR}/unaggregated_grad.cc ${OP_BASE_DIR}/tabulate_multi_device.cc ${OP_BASE_DIR}/prod_env_mat_multi_device.cc) +file(GLOB OP_SRC ${OP_BASE_DIR}/prod_force.cc ${OP_BASE_DIR}/prod_virial.cc ${OP_BASE_DIR}/descrpt.cc ${OP_BASE_DIR}/descrpt_se_a_ef.cc ${OP_BASE_DIR}/descrpt_se_a_ef.cc ${OP_BASE_DIR}/descrpt_se_a_ef_para.cc ${OP_BASE_DIR}/descrpt_se_a_ef_vert.cc ${OP_BASE_DIR}/pair_tab.cc ${OP_BASE_DIR}/prod_force_multi_device.cc ${OP_BASE_DIR}/prod_virial_multi_device.cc ${OP_BASE_DIR}/soft_min.cc ${OP_BASE_DIR}/soft_min_force.cc ${OP_BASE_DIR}/soft_min_virial.cc ${OP_BASE_DIR}/ewald_recp.cc ${OP_BASE_DIR}/gelu_multi_device.cc ${OP_BASE_DIR}/map_aparam.cc ${OP_BASE_DIR}/neighbor_stat.cc ${OP_BASE_DIR}/unaggregated_grad.cc ${OP_BASE_DIR}/tabulate_multi_device.cc ${OP_BASE_DIR}/prod_env_mat_multi_device.cc) add_library(${opname} SHARED ${OP_SRC}) list (APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/../../cmake/) From 29598ea9b7ffe3c7243c2cc860acca4333c986ed Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 29 Mar 2021 16:06:21 +0800 Subject: [PATCH 310/562] fix bug in multi frame support --- source/op/prod_force_multi_device.cc | 29 +++++++++++++------ source/op/prod_virial_multi_device.cc | 40 +++++++++++++++++++-------- 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/source/op/prod_force_multi_device.cc b/source/op/prod_force_multi_device.cc index 29af42379a..a49b9c1913 100644 --- a/source/op/prod_force_multi_device.cc +++ b/source/op/prod_force_multi_device.cc @@ -70,12 +70,18 @@ class ProdForceSeAOp : public OpKernel { assert (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)); assert (nloc * nnei == nlist_tensor.shape().dim_size(1)); assert (nnei * 4 == ndescrpt); + // flat the tensors - FPTYPE * force = force_tensor->flat().data(); - const FPTYPE * net_deriv = net_deriv_tensor.flat().data(); - const FPTYPE * in_deriv = in_deriv_tensor.flat().data(); - const int * nlist = nlist_tensor.flat().data(); + FPTYPE * p_force = force_tensor->flat().data(); + const FPTYPE * p_net_deriv = net_deriv_tensor.flat().data(); + const FPTYPE * p_in_deriv = in_deriv_tensor.flat().data(); + const int * p_nlist = nlist_tensor.flat().data(); + for(int kk = 0; kk < nframes; ++kk){ + FPTYPE * force = p_force + kk * nall * 3; + const FPTYPE * net_deriv = p_net_deriv + kk * nloc * ndescrpt; + const FPTYPE * in_deriv = p_in_deriv + kk * nloc * ndescrpt * 3; + const int * nlist = p_nlist + kk * nloc * nnei; if (device == "GPU") { #if GOOGLE_CUDA deepmd::prod_force_a_gpu_cuda( @@ -88,6 +94,7 @@ class ProdForceSeAOp : public OpKernel { force, net_deriv, in_deriv, nlist, nloc, nall, nnei); } + } } private: std::string device; @@ -144,11 +151,16 @@ class ProdForceSeROp : public OpKernel { assert (nloc * nnei == nlist_tensor.shape().dim_size(1)); assert (nnei * 1 == ndescrpt); // flat the tensors - FPTYPE * force = force_tensor->flat().data(); - const FPTYPE * net_deriv = net_deriv_tensor.flat().data(); - const FPTYPE * in_deriv = in_deriv_tensor.flat().data(); - const int * nlist = nlist_tensor.flat().data(); + FPTYPE * p_force = force_tensor->flat().data(); + const FPTYPE * p_net_deriv = net_deriv_tensor.flat().data(); + const FPTYPE * p_in_deriv = in_deriv_tensor.flat().data(); + const int * p_nlist = nlist_tensor.flat().data(); + for(int kk = 0; kk < nframes; ++kk){ + FPTYPE * force = p_force + kk * nall * 3; + const FPTYPE * net_deriv = p_net_deriv + kk * nloc * ndescrpt; + const FPTYPE * in_deriv = p_in_deriv + kk * nloc * ndescrpt * 3; + const int * nlist = p_nlist + kk * nloc * nnei; if (device == "GPU") { #if GOOGLE_CUDA deepmd::prod_force_r_gpu_cuda( @@ -161,6 +173,7 @@ class ProdForceSeROp : public OpKernel { force, net_deriv, in_deriv, nlist, nloc, nall, nnei); } + } } private: std::string device; diff --git a/source/op/prod_virial_multi_device.cc b/source/op/prod_virial_multi_device.cc index 9e16437b44..14189082a4 100644 --- a/source/op/prod_virial_multi_device.cc +++ b/source/op/prod_virial_multi_device.cc @@ -77,13 +77,20 @@ class ProdVirialSeAOp : public OpKernel { context->eigen_device() ); // flat the tensors - FPTYPE * virial = virial_tensor->flat().data(); - FPTYPE * atom_virial = atom_virial_tensor->flat().data(); - const FPTYPE * net_deriv = net_deriv_tensor.flat().data(); - const FPTYPE * in_deriv = in_deriv_tensor.flat().data(); - const FPTYPE * rij = rij_tensor.flat().data(); - const int * nlist = nlist_tensor.flat().data(); + FPTYPE * p_virial = virial_tensor->flat().data(); + FPTYPE * p_atom_virial = atom_virial_tensor->flat().data(); + const FPTYPE * p_net_deriv = net_deriv_tensor.flat().data(); + const FPTYPE * p_in_deriv = in_deriv_tensor.flat().data(); + const FPTYPE * p_rij = rij_tensor.flat().data(); + const int * p_nlist = nlist_tensor.flat().data(); + for(int kk = 0; kk < nframes; ++kk){ + FPTYPE * virial = p_virial + kk * 9; + FPTYPE * atom_virial = p_atom_virial + kk * nall * 9; + const FPTYPE * net_deriv = p_net_deriv + kk * nloc * ndescrpt; + const FPTYPE * in_deriv = p_in_deriv + kk * nloc * ndescrpt * 3; + const FPTYPE * rij = p_rij + kk * nloc * nnei * 3; + const int * nlist = p_nlist + kk * nloc * nnei; if (device == "GPU") { #if GOOGLE_CUDA deepmd::prod_virial_a_gpu_cuda( @@ -96,6 +103,7 @@ class ProdVirialSeAOp : public OpKernel { virial, atom_virial, net_deriv, in_deriv, rij, nlist, nloc, nall, nnei); } + } } private: std::string device; @@ -155,13 +163,20 @@ class ProdVirialSeROp : public OpKernel { context->eigen_device() ); // flat the tensors - FPTYPE * virial = virial_tensor->flat().data(); - FPTYPE * atom_virial = atom_virial_tensor->flat().data(); - const FPTYPE * net_deriv = net_deriv_tensor.flat().data(); - const FPTYPE * in_deriv = in_deriv_tensor.flat().data(); - const FPTYPE * rij = rij_tensor.flat().data(); - const int * nlist = nlist_tensor.flat().data(); + FPTYPE * p_virial = virial_tensor->flat().data(); + FPTYPE * p_atom_virial = atom_virial_tensor->flat().data(); + const FPTYPE * p_net_deriv = net_deriv_tensor.flat().data(); + const FPTYPE * p_in_deriv = in_deriv_tensor.flat().data(); + const FPTYPE * p_rij = rij_tensor.flat().data(); + const int * p_nlist = nlist_tensor.flat().data(); + for(int kk = 0; kk < nframes; ++kk){ + FPTYPE * virial = p_virial + kk * 9; + FPTYPE * atom_virial = p_atom_virial + kk * nall * 9; + const FPTYPE * net_deriv = p_net_deriv + kk * nloc * ndescrpt; + const FPTYPE * in_deriv = p_in_deriv + kk * nloc * ndescrpt * 3; + const FPTYPE * rij = p_rij + kk * nloc * nnei * 3; + const int * nlist = p_nlist + kk * nloc * nnei; if (device == "GPU") { #if GOOGLE_CUDA deepmd::prod_virial_r_gpu_cuda( @@ -174,6 +189,7 @@ class ProdVirialSeROp : public OpKernel { virial, atom_virial, net_deriv, in_deriv, rij, nlist, nloc, nall, nnei); } + } } private: std::string device; From 3b4044b90c40b221d40afc3d71840e96d0094c03 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 29 Mar 2021 16:27:41 +0800 Subject: [PATCH 311/562] fix bugs of calling old OPs --- source/tests/test_descrpt_se_r.py | 2 +- source/tests/test_descrpt_sea_ef_rot.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/tests/test_descrpt_se_r.py b/source/tests/test_descrpt_se_r.py index f1d6623e64..4d6222a728 100644 --- a/source/tests/test_descrpt_se_r.py +++ b/source/tests/test_descrpt_se_r.py @@ -73,7 +73,7 @@ def comp_ef (self, name, reuse = None) : descrpt, descrpt_deriv, rij, nlist \ - = op_module.descrpt_se_r (dcoord, + = op_module.prod_env_mat_r(dcoord, dtype, tnatoms, dbox, diff --git a/source/tests/test_descrpt_sea_ef_rot.py b/source/tests/test_descrpt_sea_ef_rot.py index 10e38cdbda..31d2fafa3f 100644 --- a/source/tests/test_descrpt_sea_ef_rot.py +++ b/source/tests/test_descrpt_sea_ef_rot.py @@ -59,7 +59,7 @@ def build_efv(self, efield = tf.reshape(self.efield, [-1, 3]) efield = self._normalize_3d(efield) efield = tf.reshape(efield, [-1, tnatoms[0] * 3]) - if op != op_module.descrpt_se_a : + if op != op_module.prod_env_mat_a : descrpt = DescrptSeAEfLower(op, **{'sel':self.sel_a, 'rcut': 6, 'rcut_smth' : 5.5}) else: descrpt = DescrptSeA(**{'sel':self.sel_a, 'rcut': 6, 'rcut_smth' : 0.5}) @@ -119,7 +119,7 @@ def test_rot_axis(self, suffix=''): t_v_e, t_v_f, t_v_f, t_v_ae, t_v_av \ = self.build_efv (self.coord, self.box, self.type, self.tnatoms, name = "test_rot" + suffix, op = op_module.descrpt_se_a_ef_vert, reuse = True) t_e, t_f, t_f, t_ae, t_av \ - = self.build_efv (self.coord, self.box, self.type, self.tnatoms, name = "test_rot" + suffix, op = op_module.descrpt_se_a, reuse = True) + = self.build_efv (self.coord, self.box, self.type, self.tnatoms, name = "test_rot" + suffix, op = op_module.prod_env_mat_a, reuse = True) self.sess.run (tf.global_variables_initializer()) np.random.seed(0) @@ -214,7 +214,7 @@ def test_rot_diff_axis(self, suffix=''): t_v_e, t_v_f, t_v_f, t_v_ae, t_v_av \ = self.build_efv (self.coord, self.box, self.type, self.tnatoms, name = "test_rot" + suffix, op = op_module.descrpt_se_a_ef_vert, reuse = True) t_e, t_f, t_f, t_ae, t_av \ - = self.build_efv (self.coord, self.box, self.type, self.tnatoms, name = "test_rot" + suffix, op = op_module.descrpt_se_a, reuse = True) + = self.build_efv (self.coord, self.box, self.type, self.tnatoms, name = "test_rot" + suffix, op = op_module.prod_env_mat_a, reuse = True) self.sess.run (tf.global_variables_initializer()) np.random.seed(0) @@ -289,7 +289,7 @@ def test_rot_field_corot(self, suffix=''): t_v_e, t_v_f, t_v_f, t_v_ae, t_v_av \ = self.build_efv (self.coord, self.box, self.type, self.tnatoms, name = "test_rot" + suffix, op = op_module.descrpt_se_a_ef_vert, reuse = True) t_e, t_f, t_f, t_ae, t_av \ - = self.build_efv (self.coord, self.box, self.type, self.tnatoms, name = "test_rot" + suffix, op = op_module.descrpt_se_a, reuse = True) + = self.build_efv (self.coord, self.box, self.type, self.tnatoms, name = "test_rot" + suffix, op = op_module.prod_env_mat_a, reuse = True) self.sess.run (tf.global_variables_initializer()) np.random.seed(0) From 056471d9a4a5cda038c8d5b7f9b96b7e40304edf Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 29 Mar 2021 16:30:24 +0800 Subject: [PATCH 312/562] fix bug in UT --- source/tests/test_tab_smooth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/tests/test_tab_smooth.py b/source/tests/test_tab_smooth.py index ad6ad22044..55c16d57cc 100644 --- a/source/tests/test_tab_smooth.py +++ b/source/tests/test_tab_smooth.py @@ -63,7 +63,7 @@ def comp_ef (self, name, reuse = None) : descrpt, descrpt_deriv, rij, nlist \ - = op_module.descrpt_se_a (dcoord, + = op_module.prod_env_mat_a (dcoord, dtype, tnatoms, dbox, From 9d3bb1b23b356e33b6af1d1625b7385fb0aad990 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 29 Mar 2021 17:28:48 +0800 Subject: [PATCH 313/562] fix bug of using old se_r --- deepmd/descriptor/se_r.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deepmd/descriptor/se_r.py b/deepmd/descriptor/se_r.py index 91055aef17..b3f56bf206 100644 --- a/deepmd/descriptor/se_r.py +++ b/deepmd/descriptor/se_r.py @@ -112,7 +112,7 @@ def __init__ (self, self.place_holders['natoms_vec'] = tf.placeholder(tf.int32, [self.ntypes+2], name=name_pfx+'t_natoms') self.place_holders['default_mesh'] = tf.placeholder(tf.int32, [None], name=name_pfx+'t_mesh') self.stat_descrpt, descrpt_deriv, rij, nlist \ - = op_module.descrpt_se_r(self.place_holders['coord'], + = op_module.prod_env_mat_r(self.place_holders['coord'], self.place_holders['type'], self.place_holders['natoms_vec'], self.place_holders['box'], @@ -285,7 +285,7 @@ def build (self, atype = tf.reshape (atype_, [-1, natoms[1]]) self.descrpt, self.descrpt_deriv, self.rij, self.nlist \ - = op_module.descrpt_se_r (coord, + = op_module.prod_env_mat_r(coord, atype, natoms, box, From 95bd33f7640fb9af57697d322f90cdf0a9341088 Mon Sep 17 00:00:00 2001 From: Duo Date: Mon, 29 Mar 2021 21:20:13 +0800 Subject: [PATCH 314/562] gpu region update --- source/lib/include/coord.h | 8 +- source/lib/include/gpu_cuda.h | 10 +++ source/lib/include/region.h | 24 ++++++ source/lib/src/coord.cc | 28 +++++-- source/lib/src/cuda/CMakeLists.txt | 2 +- source/lib/src/cuda/coord.cu | 71 ++++++----------- source/lib/src/cuda/region.cu | 92 ++++++++++++++++++++++ source/lib/tests/test_coord.cc | 49 ++++++++++-- source/lib/tests/test_simulation_region.cc | 74 +++++++++++++++++ source/op/prod_env_mat_multi_device.cc | 28 ++++--- 10 files changed, 309 insertions(+), 77 deletions(-) create mode 100644 source/lib/src/cuda/region.cu diff --git a/source/lib/include/coord.h b/source/lib/include/coord.h index 7aeede656a..d2beb1a6f2 100644 --- a/source/lib/include/coord.h +++ b/source/lib/include/coord.h @@ -41,12 +41,12 @@ copy_coord_cpu( // cell_info: nat_stt,ncell,ext_stt,ext_end,ngcell,cell_shift,cell_iter,total_cellnum,loc_cellnum // input: // boxt +template void compute_cell_info( int * cell_info, const float & rcut, - const double * boxt -); + const deepmd::Region & region); #if GOOGLE_CUDA // normalize coords @@ -59,7 +59,7 @@ void normalize_coord_gpu( FPTYPE * coord, const int natom, - const double * box_info); + const deepmd::Region & region); // copy coordinates // outputs: @@ -88,7 +88,7 @@ copy_coord_gpu( const int & loc_cellnum, const int & total_cellnum, const int * cell_info, - const double * box_info); + const deepmd::Region & region); #endif // GOOGLE_CUDA } diff --git a/source/lib/include/gpu_cuda.h b/source/lib/include/gpu_cuda.h index 570db416fb..a9988b1caa 100644 --- a/source/lib/include/gpu_cuda.h +++ b/source/lib/include/gpu_cuda.h @@ -90,6 +90,16 @@ void malloc_device_memory_sync( memcpy_host_to_device(device, host); } +template +void malloc_device_memory_sync( + FPTYPE * &device, + const FPTYPE * host, + const int size) +{ + cudaErrcheck(cudaMalloc((void **)&device, sizeof(FPTYPE) * size)); + memcpy_host_to_device(device, host, size); +} + template void delete_device_memory( FPTYPE * &device) diff --git a/source/lib/include/region.h b/source/lib/include/region.h index fd24bd6b4d..901299a241 100644 --- a/source/lib/include/region.h +++ b/source/lib/include/region.h @@ -36,5 +36,29 @@ convert_to_phys_cpu( const Region & region, const FPTYPE * ri); +#if GOOGLE_CUDA +//only for unittest +template +void +convert_to_inter_gpu( + FPTYPE * ri, + const Region & region, + const FPTYPE * rp); + +template +void +convert_to_phys_gpu( + FPTYPE * rp, + const Region & region, + const FPTYPE * ri); + +template +void +volume_gpu( + FPTYPE * volume, + const Region & region); +#endif // GOOGLE_CUDA + } + diff --git a/source/lib/src/coord.cc b/source/lib/src/coord.cc index 6c9bb3bb04..b88800f7f7 100644 --- a/source/lib/src/coord.cc +++ b/source/lib/src/coord.cc @@ -68,18 +68,20 @@ copy_coord_cpu( return 0; } +template void deepmd:: compute_cell_info( int * cell_info, //nat_stt,ncell,ext_stt,ext_end,ngcell,cell_shift,cell_iter,loc_cellnum,total_cellnum const float & rcut, - const double * boxt -) + const Region & region) { - SimulationRegion region; + SimulationRegion tmpr; double to_face [3]; - region.reinitBox(boxt); - region.toFaceDistance (to_face); + double tmp_boxt[9]; + std::copy(region.boxt, region.boxt+9, tmp_boxt); + tmpr.reinitBox(tmp_boxt); + tmpr.toFaceDistance (to_face); double cell_size [3]; for (int dd = 0; dd < 3; ++dd){ cell_info[dd]=0; //nat_stt @@ -143,5 +145,21 @@ copy_coord_cpu( const float & rcut, const deepmd::Region & region); +template +void +deepmd:: +compute_cell_info( + int * cell_info, //nat_stt,ncell,ext_stt,ext_end,ngcell,cell_shift,cell_iter,loc_cellnum,total_cellnum + const float & rcut, + const Region & region); + +template +void +deepmd:: +compute_cell_info( + int * cell_info, //nat_stt,ncell,ext_stt,ext_end,ngcell,cell_shift,cell_iter,loc_cellnum,total_cellnum + const float & rcut, + const Region & region); + diff --git a/source/lib/src/cuda/CMakeLists.txt b/source/lib/src/cuda/CMakeLists.txt index 540f616379..f9832caefd 100644 --- a/source/lib/src/cuda/CMakeLists.txt +++ b/source/lib/src/cuda/CMakeLists.txt @@ -106,7 +106,7 @@ endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -DCUB_IGNORE_DEPRECATED_CPP_DIALECT -DCUB_IGNORE_DEPRECATED_CPP_DIALECT") set (SOURCE_FILES - prod_env_mat.cu prod_force.cu prod_virial.cu gelu.cu tabulate.cu coord.cu neighbor_list.cu + prod_env_mat.cu prod_force.cu prod_virial.cu gelu.cu tabulate.cu coord.cu neighbor_list.cu region.cu ) cuda_add_library(deepmd_op_cuda SHARED ${SOURCE_FILES}) diff --git a/source/lib/src/cuda/coord.cu b/source/lib/src/cuda/coord.cu index e3e856f550..98b7ad582f 100644 --- a/source/lib/src/cuda/coord.cu +++ b/source/lib/src/cuda/coord.cu @@ -1,31 +1,8 @@ #include "device.h" #include "gpu_cuda.h" #include "coord.h" +#include "region.cu" -template -__device__ inline void tensorDotVector(FPTYPE *o_v, const FPTYPE *i_v, const double *i_t) -{ - o_v[0] = i_v[0] * i_t[0*3+0] + i_v[1] * i_t[0*3+1] + i_v[2] * i_t[0*3+2]; - o_v[1] = i_v[0] * i_t[1*3+0] + i_v[1] * i_t[1*3+1] + i_v[2] * i_t[1*3+2]; - o_v[2] = i_v[0] * i_t[2*3+0] + i_v[1] * i_t[2*3+1] + i_v[2] * i_t[2*3+2]; -} -template -__device__ inline void tensorTransDotVector(FPTYPE *o_v, const FPTYPE *i_v, const double *i_t) -{ - o_v[0] = i_v[0] * i_t[0*3+0] + i_v[1] * i_t[1*3+0] + i_v[2] * i_t[2*3+0]; - o_v[1] = i_v[0] * i_t[0*3+1] + i_v[1] * i_t[1*3+1] + i_v[2] * i_t[2*3+1]; - o_v[2] = i_v[0] * i_t[0*3+2] + i_v[1] * i_t[1*3+2] + i_v[2] * i_t[2*3+2]; -} -template -__device__ inline void phys2Inter(FPTYPE *inter, const FPTYPE *phys, const double *rec_boxt) -{ - tensorDotVector(inter, phys, rec_boxt); -} -template -__device__ inline void inter2Phys(FPTYPE *phys, const FPTYPE *inter, const double *boxt) -{ - tensorTransDotVector(phys, inter, boxt); -} __device__ inline int collapse_index(const int * idx,const int * size) { return (idx[0] * size[1] + idx[1]) * size[2] + idx[2]; @@ -50,7 +27,7 @@ __device__ inline void idx_unshift(int * idx, const int * shift) idx[dd]-=shift[dd]; } } -__device__ inline int compute_pbc_shift (int idx, int ncell) +__device__ inline int compute_pbc_shift(int idx, int ncell) { int shift = 0; if (idx < 0) { @@ -67,8 +44,8 @@ __device__ inline int compute_pbc_shift (int idx, int ncell) template __global__ void normalize_one( FPTYPE *out_c, - const double *boxt, - const double *rec_boxt, + const FPTYPE *boxt, + const FPTYPE *rec_boxt, const int nall ) { @@ -92,8 +69,8 @@ __global__ void _compute_int_data( const int *ext_stt, const int *ext_end, const int *ngcell, - const double *boxt, - const double *rec_boxt, + const FPTYPE *boxt, + const FPTYPE *rec_boxt, int * idx_cellmap, int * idx_cellmap_noshift, int * total_cellnum_map, @@ -210,8 +187,8 @@ __global__ void _copy_coord( const int nloc, const int nall, const int total_cellnum, - const double * boxt, - const double * rec_boxt + const FPTYPE * boxt, + const FPTYPE * rec_boxt ) { int idy = blockIdx.x*blockDim.x+threadIdx.x; @@ -258,7 +235,7 @@ __global__ void _copy_coord( } template -void compute_int_data(int * int_data, const FPTYPE * in_c, const int * cell_info, const double * box_info, const int nloc, const int loc_cellnum, const int total_cellnum) +void compute_int_data(int * int_data, const FPTYPE * in_c, const int * cell_info, const deepmd::Region & region, const int nloc, const int loc_cellnum, const int total_cellnum) { const int nn=(nloc>=total_cellnum)?nloc:total_cellnum; const int nblock=(nn+TPB-1)/TPB; @@ -276,8 +253,8 @@ void compute_int_data(int * int_data, const FPTYPE * in_c, const int * cell_info const int * ext_stt=cell_info+6; const int * ext_end=cell_info+9; const int * ngcell=cell_info+12; - const double * boxt = box_info; - const double * rec_boxt = box_info+9; + const FPTYPE * boxt = region.boxt; + const FPTYPE * rec_boxt = region.rec_boxt; _compute_int_data<<>>(in_c,nat_stt,nat_end,ext_stt,ext_end,ngcell,boxt,rec_boxt,idx_cellmap,idx_cellmap_noshift,total_cellnum_map,mask_cellnum_map,cell_map,loc_cellnum_map,cell_shift_map,temp_idx_order,nloc,loc_cellnum,total_cellnum); } @@ -292,7 +269,7 @@ void build_loc_clist(int * int_data, const int nloc, const int loc_cellnum, cons } template -void copy_coord(FPTYPE * out_c, int * out_t, int * mapping, const int * int_data, const FPTYPE * in_c, const int * in_t, const int nloc, const int nall, const int loc_cellnum, const int total_cellnum, const double * box_info) +void copy_coord(FPTYPE * out_c, int * out_t, int * mapping, const int * int_data, const FPTYPE * in_c, const int * in_t, const int nloc, const int nall, const int loc_cellnum, const int total_cellnum, const deepmd::Region & region) { const int nblock=(nall+TPB-1)/TPB; const int * cell_map=int_data+3*nloc+loc_cellnum+2*total_cellnum; @@ -301,8 +278,8 @@ void copy_coord(FPTYPE * out_c, int * out_t, int * mapping, const int * int_data const int * sec_total_cellnum_map=sec_loc_cellnum_map+loc_cellnum+1; const int * loc_clist=sec_total_cellnum_map+total_cellnum+1; - const double *boxt = box_info; - const double *rec_boxt = box_info+9; + const FPTYPE *boxt = region.boxt; + const FPTYPE *rec_boxt = region.rec_boxt; _copy_coord<<>>(out_c, out_t, mapping, in_c, in_t, cell_map, cell_shift_map, sec_loc_cellnum_map, sec_total_cellnum_map, loc_clist, nloc, nall, total_cellnum, boxt, rec_boxt); } @@ -312,10 +289,10 @@ void normalize_coord_gpu( FPTYPE * coord, const int natom, - const double * box_info) + const Region & region) { - const double * boxt=box_info; - const double * rec_boxt=box_info + 9; + const FPTYPE * boxt=region.boxt; + const FPTYPE * rec_boxt=region.rec_boxt; const int nblock=(natom+TPB-1)/TPB; normalize_one<<>>(coord, boxt, rec_boxt, natom); } @@ -337,9 +314,9 @@ copy_coord_gpu( const int & loc_cellnum, const int & total_cellnum, const int * cell_info, - const double * box_info) + const Region & region) { - compute_int_data(int_data, in_c, cell_info, box_info, nloc, loc_cellnum, total_cellnum); + compute_int_data(int_data, in_c, cell_info, region, nloc, loc_cellnum, total_cellnum); int * int_data_cpu=new int [loc_cellnum+2*total_cellnum+loc_cellnum+1+total_cellnum+1];//loc_cellnum_map,total_cellnum_map,mask_cellnum_map,sec_loc_cellnum_map,sec_total_cellnum_map cudaErrcheck(cudaMemcpy(int_data_cpu, int_data+3*nloc, sizeof(int) * (loc_cellnum + 2 * total_cellnum), cudaMemcpyDeviceToHost)); int * loc_cellnum_map=int_data_cpu; @@ -366,13 +343,13 @@ copy_coord_gpu( cudaErrcheck(cudaMemcpy(int_data+nloc*3+loc_cellnum+total_cellnum*3+total_cellnum*3, sec_loc_cellnum_map, sizeof(int) * (loc_cellnum+1+total_cellnum+1), cudaMemcpyHostToDevice)); delete[] int_data_cpu; build_loc_clist(int_data, nloc, loc_cellnum, total_cellnum); - copy_coord(out_c, out_t, mapping, int_data, in_c, in_t, nloc, *nall, loc_cellnum, total_cellnum, box_info); + copy_coord(out_c, out_t, mapping, int_data, in_c, in_t, nloc, *nall, loc_cellnum, total_cellnum, region); } return 0; } -template void normalize_coord_gpu(float * coord, const int natom, const double * box_info); -template void normalize_coord_gpu(double * coord, const int natom, const double * box_info); -template int copy_coord_gpu(float * out_c, int * out_t, int * mapping, int * nall, int * int_data, const float * in_c, const int * in_t, const int & nloc, const int & mem_nall, const int & loc_cellnum, const int & total_cellnum, const int * cell_info, const double * box_info); -template int copy_coord_gpu(double * out_c, int * out_t, int * mapping, int * nall, int * int_data, const double * in_c, const int * in_t, const int & nloc, const int & mem_nall, const int & loc_cellnum, const int & total_cellnum, const int * cell_info, const double * box_info); +template void normalize_coord_gpu(float * coord, const int natom, const Region & region); +template void normalize_coord_gpu(double * coord, const int natom, const Region & region); +template int copy_coord_gpu(float * out_c, int * out_t, int * mapping, int * nall, int * int_data, const float * in_c, const int * in_t, const int & nloc, const int & mem_nall, const int & loc_cellnum, const int & total_cellnum, const int * cell_info, const Region & region); +template int copy_coord_gpu(double * out_c, int * out_t, int * mapping, int * nall, int * int_data, const double * in_c, const int * in_t, const int & nloc, const int & mem_nall, const int & loc_cellnum, const int & total_cellnum, const int * cell_info, const Region & region); } \ No newline at end of file diff --git a/source/lib/src/cuda/region.cu b/source/lib/src/cuda/region.cu new file mode 100644 index 0000000000..d8c05f0965 --- /dev/null +++ b/source/lib/src/cuda/region.cu @@ -0,0 +1,92 @@ +#include "device.h" +#include "gpu_cuda.h" +#include "region.h" + +template +__device__ inline void tensorDotVector(FPTYPE *o_v, const FPTYPE *i_v, const FPTYPE *i_t) +{ + o_v[0] = i_v[0] * i_t[0*3+0] + i_v[1] * i_t[0*3+1] + i_v[2] * i_t[0*3+2]; + o_v[1] = i_v[0] * i_t[1*3+0] + i_v[1] * i_t[1*3+1] + i_v[2] * i_t[1*3+2]; + o_v[2] = i_v[0] * i_t[2*3+0] + i_v[1] * i_t[2*3+1] + i_v[2] * i_t[2*3+2]; +} +template +__device__ inline void tensorTransDotVector(FPTYPE *o_v, const FPTYPE *i_v, const FPTYPE *i_t) +{ + o_v[0] = i_v[0] * i_t[0*3+0] + i_v[1] * i_t[1*3+0] + i_v[2] * i_t[2*3+0]; + o_v[1] = i_v[0] * i_t[0*3+1] + i_v[1] * i_t[1*3+1] + i_v[2] * i_t[2*3+1]; + o_v[2] = i_v[0] * i_t[0*3+2] + i_v[1] * i_t[1*3+2] + i_v[2] * i_t[2*3+2]; +} +template +__device__ inline void phys2Inter(FPTYPE *inter, const FPTYPE *phys, const FPTYPE *rec_boxt) +{ + tensorDotVector(inter, phys, rec_boxt); +} +template +__device__ inline void inter2Phys(FPTYPE *phys, const FPTYPE *inter, const FPTYPE *boxt) +{ + tensorTransDotVector(phys, inter, boxt); +} +template +__device__ inline FPTYPE compute_volume(const FPTYPE * boxt) +{ + FPTYPE volume = + boxt[0*3+0] * (boxt[1*3+1]*boxt[2*3+2] - boxt[2*3+1]*boxt[1*3+2]) - + boxt[0*3+1] * (boxt[1*3+0]*boxt[2*3+2] - boxt[2*3+0]*boxt[1*3+2]) + + boxt[0*3+2] * (boxt[1*3+0]*boxt[2*3+1] - boxt[2*3+0]*boxt[1*3+1]); + return volume; +} + +template +__global__ void _phys2Inter(FPTYPE *inter, const FPTYPE *phys, const FPTYPE *rec_boxt) +{ + phys2Inter(inter, phys, rec_boxt); +} + +template +__global__ void _inter2Phys(FPTYPE *phys, const FPTYPE *inter, const FPTYPE *boxt) +{ + inter2Phys(phys, inter, boxt); +} + +template +__global__ void _compute_volume(FPTYPE * volume, const FPTYPE * boxt) +{ + volume[0] = compute_volume(boxt); +} + +namespace deepmd { +//only for unittest +template +void +convert_to_inter_gpu( + FPTYPE * ri, + const Region & region, + const FPTYPE * rp) +{ + _phys2Inter<<<1, 1>>>(ri, rp, region.rec_boxt); +} + +template +void +convert_to_phys_gpu( + FPTYPE * rp, + const Region & region, + const FPTYPE * ri) +{ + _inter2Phys<<<1, 1>>>(rp, ri, region.boxt); +} + +template +void +volume_gpu(FPTYPE * volume, const Region & region) +{ + _compute_volume<<<1, 1>>>(volume, region.boxt); +} + +template void convert_to_inter_gpu(float * ri, const Region & region, const float * rp); +template void convert_to_inter_gpu(double * ri, const Region & region, const double * rp); +template void convert_to_phys_gpu(float * rp, const Region & region, const float * ri); +template void convert_to_phys_gpu(double * rp, const Region & region, const double * ri); +template void volume_gpu(float * volume, const Region & region); +template void volume_gpu(double * volume, const Region & region); +} \ No newline at end of file diff --git a/source/lib/tests/test_coord.cc b/source/lib/tests/test_coord.cc index d1dfd08ca2..e3b0552b1d 100644 --- a/source/lib/tests/test_coord.cc +++ b/source/lib/tests/test_coord.cc @@ -73,6 +73,9 @@ TEST_F(TestNormCoord, cpu_case2) TEST_F(TestNormCoord, gpu_case0) { deepmd::Region region; + deepmd::Region region_dev; + double * new_boxt = region_dev.boxt; + double * new_rec_boxt = region_dev.rec_boxt; init_region_cpu(region, &boxt[0]); std::vector box_info; box_info.resize(18); @@ -83,7 +86,11 @@ TEST_F(TestNormCoord, gpu_case0) std::vector out_c(r0); deepmd::malloc_device_memory_sync(box_info_dev, box_info); deepmd::malloc_device_memory_sync(out_c_dev, out_c); - deepmd::normalize_coord_gpu(out_c_dev, natoms, box_info_dev); + region_dev.boxt = box_info_dev; + region_dev.rec_boxt = box_info_dev + 9; + deepmd::normalize_coord_gpu(out_c_dev, natoms, region_dev); + region_dev.boxt = new_boxt; + region_dev.rec_boxt = new_rec_boxt; deepmd::memcpy_device_to_host(out_c_dev, out_c); deepmd::delete_device_memory(box_info_dev); deepmd::delete_device_memory(out_c_dev); @@ -95,6 +102,9 @@ TEST_F(TestNormCoord, gpu_case0) TEST_F(TestNormCoord, gpu_case1) { deepmd::Region region; + deepmd::Region region_dev; + double * new_boxt = region_dev.boxt; + double * new_rec_boxt = region_dev.rec_boxt; init_region_cpu(region, &boxt[0]); std::vector box_info; box_info.resize(18); @@ -105,7 +115,11 @@ TEST_F(TestNormCoord, gpu_case1) std::vector out_c(r1); deepmd::malloc_device_memory_sync(box_info_dev, box_info); deepmd::malloc_device_memory_sync(out_c_dev, out_c); - deepmd::normalize_coord_gpu(out_c_dev, natoms, box_info_dev); + region_dev.boxt = box_info_dev; + region_dev.rec_boxt = box_info_dev + 9; + deepmd::normalize_coord_gpu(out_c_dev, natoms, region_dev); + region_dev.boxt = new_boxt; + region_dev.rec_boxt = new_rec_boxt; deepmd::memcpy_device_to_host(out_c_dev, out_c); deepmd::delete_device_memory(box_info_dev); deepmd::delete_device_memory(out_c_dev); @@ -117,6 +131,9 @@ TEST_F(TestNormCoord, gpu_case1) TEST_F(TestNormCoord, gpu_case2) { deepmd::Region region; + deepmd::Region region_dev; + double * new_boxt = region_dev.boxt; + double * new_rec_boxt = region_dev.rec_boxt; init_region_cpu(region, &boxt[0]); std::vector box_info; box_info.resize(18); @@ -127,7 +144,11 @@ TEST_F(TestNormCoord, gpu_case2) std::vector out_c(r2); deepmd::malloc_device_memory_sync(box_info_dev, box_info); deepmd::malloc_device_memory_sync(out_c_dev, out_c); - deepmd::normalize_coord_gpu(out_c_dev, natoms, box_info_dev); + region_dev.boxt = box_info_dev; + region_dev.rec_boxt = box_info_dev + 9; + deepmd::normalize_coord_gpu(out_c_dev, natoms, region_dev); + region_dev.boxt = new_boxt; + region_dev.rec_boxt = new_rec_boxt; deepmd::memcpy_device_to_host(out_c_dev, out_c); deepmd::delete_device_memory(box_info_dev); deepmd::delete_device_memory(out_c_dev); @@ -311,9 +332,12 @@ TEST_F(TestCopyCoord, gpu) int nall; std::vector cell_info; cell_info.resize(23); - deepmd::compute_cell_info(&cell_info[0], rc, &boxt[0]); deepmd::Region region; + deepmd::Region region_dev; + double * new_boxt = region_dev.boxt; + double * new_rec_boxt = region_dev.rec_boxt; init_region_cpu(region, &boxt[0]); + deepmd::compute_cell_info(&cell_info[0], rc, region); std::vector box_info; box_info.resize(18); memcpy(&box_info[0], &boxt[0], sizeof(double)*9); @@ -332,6 +356,8 @@ TEST_F(TestCopyCoord, gpu) deepmd::malloc_device_memory(out_t_dev, mem_size); deepmd::malloc_device_memory(mapping_dev, mem_size); deepmd::malloc_device_memory(int_data_dev, nloc*3+loc_cellnum+total_cellnum*3+total_cellnum*3+loc_cellnum+1+total_cellnum+1+nloc); + region_dev.boxt = box_info_dev; + region_dev.rec_boxt = box_info_dev + 9; int ret = deepmd::copy_coord_gpu( out_c_dev, out_t_dev, @@ -345,7 +371,9 @@ TEST_F(TestCopyCoord, gpu) loc_cellnum, total_cellnum, cell_info_dev, - box_info_dev); + region_dev); + region_dev.boxt = new_boxt; + region_dev.rec_boxt = new_rec_boxt; deepmd::memcpy_device_to_host(out_c_dev, out_c); deepmd::memcpy_device_to_host(out_t_dev, out_t); deepmd::memcpy_device_to_host(mapping_dev, mapping); @@ -385,9 +413,12 @@ TEST_F(TestCopyCoord, gpu_lessmem) int nall; std::vector cell_info; cell_info.resize(23); - deepmd::compute_cell_info(&cell_info[0], rc, &boxt[0]); deepmd::Region region; + deepmd::Region region_dev; + double * new_boxt = region_dev.boxt; + double * new_rec_boxt = region_dev.rec_boxt; init_region_cpu(region, &boxt[0]); + deepmd::compute_cell_info(&cell_info[0], rc, region); std::vector box_info; box_info.resize(18); memcpy(&box_info[0], &boxt[0], sizeof(double)*9); @@ -406,6 +437,8 @@ TEST_F(TestCopyCoord, gpu_lessmem) deepmd::malloc_device_memory(out_t_dev, mem_size); deepmd::malloc_device_memory(mapping_dev, mem_size); deepmd::malloc_device_memory(int_data_dev, nloc*3+loc_cellnum+total_cellnum*3+total_cellnum*3+loc_cellnum+1+total_cellnum+1+nloc); + region_dev.boxt = box_info_dev; + region_dev.rec_boxt = box_info_dev + 9; int ret = deepmd::copy_coord_gpu( out_c_dev, out_t_dev, @@ -419,7 +452,9 @@ TEST_F(TestCopyCoord, gpu_lessmem) loc_cellnum, total_cellnum, cell_info_dev, - box_info_dev); + region_dev); + region_dev.boxt = new_boxt; + region_dev.rec_boxt = new_rec_boxt; deepmd::memcpy_device_to_host(out_c_dev, out_c); deepmd::memcpy_device_to_host(out_t_dev, out_t); deepmd::memcpy_device_to_host(mapping_dev, mapping); diff --git a/source/lib/tests/test_simulation_region.cc b/source/lib/tests/test_simulation_region.cc index 674c505c02..5c8951de0e 100644 --- a/source/lib/tests/test_simulation_region.cc +++ b/source/lib/tests/test_simulation_region.cc @@ -3,6 +3,7 @@ #include #include "region.h" #include "SimulationRegion.h" +#include "device.h" class TestRegion : public ::testing::Test { @@ -71,6 +72,79 @@ TEST_F(TestRegion, cpu) EXPECT_LT(fabs(ri2[ii] - ref_ri[ii]), 1e-10); } } +#if GOOGLE_CUDA +TEST_F(TestRegion, gpu) +{ + // check rec_box + deepmd::Region region; + deepmd::Region region_dev; + double * new_boxt = region_dev.boxt; + double * new_rec_boxt = region_dev.rec_boxt; + double * boxt_dev = NULL, * rec_boxt_dev = NULL; + double * ref_rp_dev = NULL, * ref_ri_dev = NULL; + init_region_cpu(region, &ref_boxt[0]); + for(int ii = 0; ii < 9; ++ii){ + EXPECT_LT(fabs(region.rec_boxt[ii] - ref_rec_boxt[ii]), 1e-10); + } + deepmd::malloc_device_memory_sync(boxt_dev, region.boxt, 9); + deepmd::malloc_device_memory_sync(rec_boxt_dev, region.rec_boxt, 9); + deepmd::malloc_device_memory_sync(ref_rp_dev, ref_rp); + deepmd::malloc_device_memory_sync(ref_ri_dev, ref_ri); + region_dev.boxt = boxt_dev; + region_dev.rec_boxt = rec_boxt_dev; + // check volume + double vol[1]; + double * vol_dev = NULL; + deepmd::malloc_device_memory(vol_dev, 1); + deepmd::volume_gpu(vol_dev, region_dev); + deepmd::memcpy_device_to_host(vol_dev, vol, 1); + EXPECT_LT(fabs(vol[0] - expected_vol), 1e-10); + // check conversion between phys and inter coords. + double ri[3]; + double * ri_dev = NULL; + deepmd::malloc_device_memory(ri_dev, 3); + deepmd::convert_to_inter_gpu(ri_dev, region_dev, ref_rp_dev); + deepmd::memcpy_device_to_host(ri_dev, ri, 3); + for(int ii = 0; ii < 3; ++ii){ + EXPECT_LT(fabs(ri[ii] - ref_ri[ii]), 1e-10); + } + double rp2[3]; + double * rp2_dev = NULL; + deepmd::malloc_device_memory(rp2_dev, 3); + deepmd::convert_to_phys_gpu(rp2_dev, region_dev, ri_dev); + deepmd::memcpy_device_to_host(rp2_dev, rp2, 3); + for(int ii = 0; ii < 3; ++ii){ + EXPECT_LT(fabs(rp2[ii] - ref_rp[ii]), 1e-10); + } + double rp[3]; + double * rp_dev = NULL; + deepmd::malloc_device_memory(rp_dev, 3); + deepmd::convert_to_phys_gpu(rp_dev, region_dev, ref_ri_dev); + deepmd::memcpy_device_to_host(rp_dev, rp, 3); + for(int ii = 0; ii < 3; ++ii){ + EXPECT_LT(fabs(rp[ii] - ref_rp[ii]), 1e-10); + } + double ri2[3]; + double * ri2_dev = NULL; + deepmd::malloc_device_memory(ri2_dev, 3); + deepmd::convert_to_inter_gpu(ri2_dev, region_dev, rp_dev); + deepmd::memcpy_device_to_host(ri2_dev, ri2, 3); + for(int ii = 0; ii < 3; ++ii){ + EXPECT_LT(fabs(ri2[ii] - ref_ri[ii]), 1e-10); + } + deepmd::delete_device_memory(boxt_dev); + deepmd::delete_device_memory(rec_boxt_dev); + deepmd::delete_device_memory(vol_dev); + deepmd::delete_device_memory(ref_rp_dev); + deepmd::delete_device_memory(ref_ri_dev); + deepmd::delete_device_memory(ri_dev); + deepmd::delete_device_memory(rp2_dev); + deepmd::delete_device_memory(rp_dev); + deepmd::delete_device_memory(ri2_dev); + region_dev.boxt = new_boxt; + region_dev.rec_boxt = new_rec_boxt; +} +#endif // GOOGLE_CUDA // double square_root (const double xx) diff --git a/source/op/prod_env_mat_multi_device.cc b/source/op/prod_env_mat_multi_device.cc index 79f7f71b1a..f1843f9afe 100644 --- a/source/op/prod_env_mat_multi_device.cc +++ b/source/op/prod_env_mat_multi_device.cc @@ -806,18 +806,16 @@ _norm_copy_coord_gpu( context->allocate_temp(DT_DOUBLE, FPTYPE_shape, tensor_list); FPTYPE * tmp_coord = (*tensor_list).flat().data(); cudaErrcheck(cudaMemcpy(tmp_coord, coord, sizeof(FPTYPE) * nall * 3, cudaMemcpyDeviceToDevice)); - + deepmd::Region region; init_region_cpu(region, box); - double box_info[18]; + FPTYPE box_info[18]; std::copy(region.boxt, region.boxt+9, box_info); std::copy(region.rec_boxt, region.rec_boxt+9, box_info+9); - int cell_info[23]; - deepmd::compute_cell_info(cell_info, rcut_r, box_info); + deepmd::compute_cell_info(cell_info, rcut_r, region); const int loc_cellnum=cell_info[21]; const int total_cellnum=cell_info[22]; - //Tensor double_temp; TensorShape double_shape; double_shape.AddDim(18); @@ -826,31 +824,33 @@ _norm_copy_coord_gpu( TensorShape int_shape; int_shape.AddDim(23+nloc*3+loc_cellnum+total_cellnum*3+total_cellnum*3+loc_cellnum+1+total_cellnum+1+nloc); context, context->allocate_temp(DT_INT32, int_shape, tensor_list+2); - double * box_info_dev = (*(tensor_list+1)).flat().data(); + FPTYPE * box_info_dev = (*(tensor_list+1)).flat().data(); int * cell_info_dev = (*(tensor_list+2)).flat().data(); int * int_data_dev = cell_info_dev + 23; deepmd::memcpy_host_to_device(box_info_dev, box_info, 18); deepmd::memcpy_host_to_device(cell_info_dev, cell_info, 23); - deepmd::normalize_coord_gpu(tmp_coord, nall, box_info_dev); + deepmd::Region region_dev; + FPTYPE * new_boxt = region_dev.boxt; + FPTYPE * new_rec_boxt = region_dev.rec_boxt; + region_dev.boxt = box_info_dev; + region_dev.rec_boxt = box_info_dev + 9; + deepmd::normalize_coord_gpu(tmp_coord, nall, region_dev); int tt; - //Tensor cpy_temp; - //Tensor t_temp; for(tt = 0; tt < max_cpy_trial; ++tt){ - + //Tensor cpy_temp; TensorShape cpy_shape; cpy_shape.AddDim(mem_cpy*3); context->allocate_temp(DT_DOUBLE, cpy_shape, tensor_list+3); - + //Tensor t_temp; TensorShape t_shape; t_shape.AddDim(mem_cpy*2); context, context->allocate_temp(DT_INT32, t_shape, tensor_list+4); - coord_cpy = (*(tensor_list+3)).flat().data(); type_cpy = (*(tensor_list+4)).flat().data(); idx_mapping = type_cpy + mem_cpy; int ret = deepmd::copy_coord_gpu( coord_cpy, type_cpy, idx_mapping, &nall, int_data_dev, - tmp_coord, type, nloc, mem_cpy, loc_cellnum, total_cellnum, cell_info_dev, box_info_dev); + tmp_coord, type, nloc, mem_cpy, loc_cellnum, total_cellnum, cell_info_dev, region_dev); if(ret == 0){ break; } @@ -858,6 +858,8 @@ _norm_copy_coord_gpu( mem_cpy *= 2; } } + region_dev.boxt = new_boxt; + region_dev.rec_boxt = new_rec_boxt; return (tt != max_cpy_trial); } From e5bc8044920a0e45a2c37c07b0b3581b8b4d4c30 Mon Sep 17 00:00:00 2001 From: Duo Date: Mon, 29 Mar 2021 21:39:49 +0800 Subject: [PATCH 315/562] format update --- source/lib/include/neighbor_list.h | 3 +- source/lib/src/cuda/coord.cu | 70 +++++++++++++++++++++------- source/lib/src/cuda/neighbor_list.cu | 46 ++++++++++-------- source/lib/src/cuda/region.cu | 41 ++++++++++++---- 4 files changed, 112 insertions(+), 48 deletions(-) diff --git a/source/lib/include/neighbor_list.h b/source/lib/include/neighbor_list.h index b14524db50..afd0a674a0 100644 --- a/source/lib/include/neighbor_list.h +++ b/source/lib/include/neighbor_list.h @@ -70,7 +70,8 @@ void convert_nlist_gpu_cuda( int* & gpu_memory, const int & max_nbor_size); -void free_nlist_gpu_cuda(InputNlist & gpu_nlist); +void free_nlist_gpu_cuda( + InputNlist & gpu_nlist); // build neighbor list. // outputs diff --git a/source/lib/src/cuda/coord.cu b/source/lib/src/cuda/coord.cu index 98b7ad582f..a48ac7b02a 100644 --- a/source/lib/src/cuda/coord.cu +++ b/source/lib/src/cuda/coord.cu @@ -3,31 +3,42 @@ #include "coord.h" #include "region.cu" -__device__ inline int collapse_index(const int * idx,const int * size) +__device__ inline int collapse_index( + const int * idx, + const int * size) { return (idx[0] * size[1] + idx[1]) * size[2] + idx[2]; } -__device__ inline void index_recover(const int in_idx,const int * size, int * idx) +__device__ inline void index_recover( + const int in_idx, + const int * size, + int * idx) { idx[2]=in_idx%size[2]; idx[1]=int(in_idx/size[2])%size[1]; idx[0]=int(int(in_idx/size[2])/size[1]); } -__device__ inline void idx_addshift(int * idx, const int * shift) +__device__ inline void idx_addshift( + int * idx, + const int * shift) { for(int dd=0;dd<3;dd++) { idx[dd]+=shift[dd]; } } -__device__ inline void idx_unshift(int * idx, const int * shift) +__device__ inline void idx_unshift( + int * idx, + const int * shift) { for(int dd=0;dd<3;dd++) { idx[dd]-=shift[dd]; } } -__device__ inline int compute_pbc_shift(int idx, int ncell) +__device__ inline int compute_pbc_shift( + int idx, + int ncell) { int shift = 0; if (idx < 0) { @@ -46,8 +57,7 @@ __global__ void normalize_one( FPTYPE *out_c, const FPTYPE *boxt, const FPTYPE *rec_boxt, - const int nall -) + const int nall) { // <<>> int idy=blockIdx.x*blockDim.x+threadIdx.x; @@ -162,8 +172,7 @@ __global__ void _build_loc_clist( const int *idx_cellmap, const int *idx_order, const int *sec_num_map, - const int nloc -) + const int nloc) { int idy = blockIdx.x*blockDim.x+threadIdx.x; if(idy>=nloc){return;} @@ -188,8 +197,7 @@ __global__ void _copy_coord( const int nall, const int total_cellnum, const FPTYPE * boxt, - const FPTYPE * rec_boxt -) + const FPTYPE * rec_boxt) { int idy = blockIdx.x*blockDim.x+threadIdx.x; if(idy>=nall){return;} @@ -235,7 +243,14 @@ __global__ void _copy_coord( } template -void compute_int_data(int * int_data, const FPTYPE * in_c, const int * cell_info, const deepmd::Region & region, const int nloc, const int loc_cellnum, const int total_cellnum) +void compute_int_data( + int * int_data, + const FPTYPE * in_c, + const int * cell_info, + const deepmd::Region & region, + const int nloc, + const int loc_cellnum, + const int total_cellnum) { const int nn=(nloc>=total_cellnum)?nloc:total_cellnum; const int nblock=(nn+TPB-1)/TPB; @@ -255,21 +270,38 @@ void compute_int_data(int * int_data, const FPTYPE * in_c, const int * cell_info const int * ngcell=cell_info+12; const FPTYPE * boxt = region.boxt; const FPTYPE * rec_boxt = region.rec_boxt; - _compute_int_data<<>>(in_c,nat_stt,nat_end,ext_stt,ext_end,ngcell,boxt,rec_boxt,idx_cellmap,idx_cellmap_noshift,total_cellnum_map,mask_cellnum_map,cell_map,loc_cellnum_map,cell_shift_map,temp_idx_order,nloc,loc_cellnum,total_cellnum); + _compute_int_data<<>>(in_c, nat_stt, nat_end, ext_stt, ext_end, ngcell, + boxt, rec_boxt, idx_cellmap, idx_cellmap_noshift, total_cellnum_map, mask_cellnum_map, + cell_map, loc_cellnum_map, cell_shift_map, temp_idx_order, nloc, loc_cellnum, total_cellnum); } -void build_loc_clist(int * int_data, const int nloc, const int loc_cellnum, const int total_cellnum) +void build_loc_clist( + int * int_data, + const int nloc, + const int loc_cellnum, + const int total_cellnum) { const int nblock=(nloc+TPB-1)/TPB; const int * idx_cellmap_noshift=int_data+nloc; const int * temp_idx_order=idx_cellmap_noshift+nloc; const int * sec_loc_cellnum_map=temp_idx_order+nloc+loc_cellnum+2*total_cellnum+total_cellnum+3*total_cellnum; int * loc_clist=int_data+nloc*3+loc_cellnum+total_cellnum*3+total_cellnum*3+loc_cellnum+1+total_cellnum+1; - _build_loc_clist<<>>(loc_clist,idx_cellmap_noshift,temp_idx_order,sec_loc_cellnum_map,nloc); + _build_loc_clist<<>>(loc_clist, idx_cellmap_noshift, temp_idx_order, sec_loc_cellnum_map, nloc); } template -void copy_coord(FPTYPE * out_c, int * out_t, int * mapping, const int * int_data, const FPTYPE * in_c, const int * in_t, const int nloc, const int nall, const int loc_cellnum, const int total_cellnum, const deepmd::Region & region) +void copy_coord( + FPTYPE * out_c, + int * out_t, + int * mapping, + const int * int_data, + const FPTYPE * in_c, + const int * in_t, + const int nloc, + const int nall, + const int loc_cellnum, + const int total_cellnum, + const deepmd::Region & region) { const int nblock=(nall+TPB-1)/TPB; const int * cell_map=int_data+3*nloc+loc_cellnum+2*total_cellnum; @@ -280,7 +312,8 @@ void copy_coord(FPTYPE * out_c, int * out_t, int * mapping, const int * int_data const FPTYPE *boxt = region.boxt; const FPTYPE *rec_boxt = region.rec_boxt; - _copy_coord<<>>(out_c, out_t, mapping, in_c, in_t, cell_map, cell_shift_map, sec_loc_cellnum_map, sec_total_cellnum_map, loc_clist, nloc, nall, total_cellnum, boxt, rec_boxt); + _copy_coord<<>>(out_c, out_t, mapping, in_c, in_t, cell_map, cell_shift_map, + sec_loc_cellnum_map, sec_total_cellnum_map, loc_clist, nloc, nall, total_cellnum, boxt, rec_boxt); } namespace deepmd { @@ -340,7 +373,8 @@ copy_coord_gpu( return 1; } else{ - cudaErrcheck(cudaMemcpy(int_data+nloc*3+loc_cellnum+total_cellnum*3+total_cellnum*3, sec_loc_cellnum_map, sizeof(int) * (loc_cellnum+1+total_cellnum+1), cudaMemcpyHostToDevice)); + cudaErrcheck(cudaMemcpy(int_data+nloc*3+loc_cellnum+total_cellnum*3+total_cellnum*3, + sec_loc_cellnum_map, sizeof(int) * (loc_cellnum+1+total_cellnum+1), cudaMemcpyHostToDevice)); delete[] int_data_cpu; build_loc_clist(int_data, nloc, loc_cellnum, total_cellnum); copy_coord(out_c, out_t, mapping, int_data, in_c, in_t, nloc, *nall, loc_cellnum, total_cellnum, region); diff --git a/source/lib/src/cuda/neighbor_list.cu b/source/lib/src/cuda/neighbor_list.cu index 7b67c907dc..33bf33aa3c 100644 --- a/source/lib/src/cuda/neighbor_list.cu +++ b/source/lib/src/cuda/neighbor_list.cu @@ -3,18 +3,22 @@ #include "neighbor_list.h" template -__device__ inline FPTYPE dev_dot(FPTYPE * arr1, FPTYPE * arr2) { +__device__ inline FPTYPE dev_dot( + FPTYPE * arr1, + FPTYPE * arr2) +{ return arr1[0] * arr2[0] + arr1[1] * arr2[1] + arr1[2] * arr2[2]; } template -__global__ void build_nlist(int * ilist, - int * temp_nlist, - const FPTYPE * c_cpy, - const FPTYPE rcut2, - const int nloc, - const int nall, - const int mem_size) +__global__ void build_nlist( + int * ilist, + int * temp_nlist, + const FPTYPE * c_cpy, + const FPTYPE rcut2, + const int nloc, + const int nall, + const int mem_size) { const unsigned int atom_idx = blockIdx.x; const unsigned int neighbor_idx = blockIdx.y * blockDim.y + threadIdx.y; @@ -41,12 +45,13 @@ __global__ void build_nlist(int * ilist, } } -__global__ void scan_nlist(int * numneigh, - int * nei_order, - const int * temp_nlist, - const int mem_size, - const int nloc, - const int nall) +__global__ void scan_nlist( + int * numneigh, + int * nei_order, + const int * temp_nlist, + const int mem_size, + const int nloc, + const int nall) { const unsigned int atom_idx = blockIdx.x * blockDim.x + threadIdx.x; if(atom_idx>>(nlist,nlist_map,nloc,nnei); + map_nlist<<>>(nlist, nlist_map, nloc, nnei); } template int build_nlist_gpu(InputNlist & nlist, int * max_list_size, int * nlist_data, const float * c_cpy, const int & nloc, const int & nall, const int & mem_size, const float & rcut); diff --git a/source/lib/src/cuda/region.cu b/source/lib/src/cuda/region.cu index d8c05f0965..d26803c4ed 100644 --- a/source/lib/src/cuda/region.cu +++ b/source/lib/src/cuda/region.cu @@ -3,31 +3,44 @@ #include "region.h" template -__device__ inline void tensorDotVector(FPTYPE *o_v, const FPTYPE *i_v, const FPTYPE *i_t) +__device__ inline void tensorDotVector( + FPTYPE *o_v, + const FPTYPE *i_v, + const FPTYPE *i_t) { o_v[0] = i_v[0] * i_t[0*3+0] + i_v[1] * i_t[0*3+1] + i_v[2] * i_t[0*3+2]; o_v[1] = i_v[0] * i_t[1*3+0] + i_v[1] * i_t[1*3+1] + i_v[2] * i_t[1*3+2]; o_v[2] = i_v[0] * i_t[2*3+0] + i_v[1] * i_t[2*3+1] + i_v[2] * i_t[2*3+2]; } template -__device__ inline void tensorTransDotVector(FPTYPE *o_v, const FPTYPE *i_v, const FPTYPE *i_t) +__device__ inline void tensorTransDotVector( + FPTYPE *o_v, + const FPTYPE *i_v, + const FPTYPE *i_t) { o_v[0] = i_v[0] * i_t[0*3+0] + i_v[1] * i_t[1*3+0] + i_v[2] * i_t[2*3+0]; o_v[1] = i_v[0] * i_t[0*3+1] + i_v[1] * i_t[1*3+1] + i_v[2] * i_t[2*3+1]; o_v[2] = i_v[0] * i_t[0*3+2] + i_v[1] * i_t[1*3+2] + i_v[2] * i_t[2*3+2]; } template -__device__ inline void phys2Inter(FPTYPE *inter, const FPTYPE *phys, const FPTYPE *rec_boxt) +__device__ inline void phys2Inter( + FPTYPE *inter, + const FPTYPE *phys, + const FPTYPE *rec_boxt) { tensorDotVector(inter, phys, rec_boxt); } template -__device__ inline void inter2Phys(FPTYPE *phys, const FPTYPE *inter, const FPTYPE *boxt) +__device__ inline void inter2Phys( + FPTYPE *phys, + const FPTYPE *inter, + const FPTYPE *boxt) { tensorTransDotVector(phys, inter, boxt); } template -__device__ inline FPTYPE compute_volume(const FPTYPE * boxt) +__device__ inline FPTYPE compute_volume( + const FPTYPE * boxt) { FPTYPE volume = boxt[0*3+0] * (boxt[1*3+1]*boxt[2*3+2] - boxt[2*3+1]*boxt[1*3+2]) - @@ -37,19 +50,27 @@ __device__ inline FPTYPE compute_volume(const FPTYPE * boxt) } template -__global__ void _phys2Inter(FPTYPE *inter, const FPTYPE *phys, const FPTYPE *rec_boxt) +__global__ void _phys2Inter( + FPTYPE *inter, + const FPTYPE *phys, + const FPTYPE *rec_boxt) { phys2Inter(inter, phys, rec_boxt); } template -__global__ void _inter2Phys(FPTYPE *phys, const FPTYPE *inter, const FPTYPE *boxt) +__global__ void _inter2Phys( + FPTYPE *phys, + const FPTYPE *inter, + const FPTYPE *boxt) { inter2Phys(phys, inter, boxt); } template -__global__ void _compute_volume(FPTYPE * volume, const FPTYPE * boxt) +__global__ void _compute_volume( + FPTYPE * volume, + const FPTYPE * boxt) { volume[0] = compute_volume(boxt); } @@ -78,7 +99,9 @@ convert_to_phys_gpu( template void -volume_gpu(FPTYPE * volume, const Region & region) +volume_gpu( + FPTYPE * volume, + const Region & region) { _compute_volume<<<1, 1>>>(volume, region.boxt); } From 7a3496aa120f563875fe789b43f46baddc2e788f Mon Sep 17 00:00:00 2001 From: Duo Date: Mon, 29 Mar 2021 23:46:45 +0800 Subject: [PATCH 316/562] add region.cuh --- source/lib/include/region.cuh | 48 +++++++++++++++++++++++++++++++++++ source/lib/src/cuda/coord.cu | 2 +- source/lib/src/cuda/region.cu | 48 +---------------------------------- 3 files changed, 50 insertions(+), 48 deletions(-) create mode 100644 source/lib/include/region.cuh diff --git a/source/lib/include/region.cuh b/source/lib/include/region.cuh new file mode 100644 index 0000000000..d3da188239 --- /dev/null +++ b/source/lib/include/region.cuh @@ -0,0 +1,48 @@ +#pragma once + +template +__device__ inline void tensorDotVector( + FPTYPE *o_v, + const FPTYPE *i_v, + const FPTYPE *i_t) +{ + o_v[0] = i_v[0] * i_t[0*3+0] + i_v[1] * i_t[0*3+1] + i_v[2] * i_t[0*3+2]; + o_v[1] = i_v[0] * i_t[1*3+0] + i_v[1] * i_t[1*3+1] + i_v[2] * i_t[1*3+2]; + o_v[2] = i_v[0] * i_t[2*3+0] + i_v[1] * i_t[2*3+1] + i_v[2] * i_t[2*3+2]; +} +template +__device__ inline void tensorTransDotVector( + FPTYPE *o_v, + const FPTYPE *i_v, + const FPTYPE *i_t) +{ + o_v[0] = i_v[0] * i_t[0*3+0] + i_v[1] * i_t[1*3+0] + i_v[2] * i_t[2*3+0]; + o_v[1] = i_v[0] * i_t[0*3+1] + i_v[1] * i_t[1*3+1] + i_v[2] * i_t[2*3+1]; + o_v[2] = i_v[0] * i_t[0*3+2] + i_v[1] * i_t[1*3+2] + i_v[2] * i_t[2*3+2]; +} +template +__device__ inline void phys2Inter( + FPTYPE *inter, + const FPTYPE *phys, + const FPTYPE *rec_boxt) +{ + tensorDotVector(inter, phys, rec_boxt); +} +template +__device__ inline void inter2Phys( + FPTYPE *phys, + const FPTYPE *inter, + const FPTYPE *boxt) +{ + tensorTransDotVector(phys, inter, boxt); +} +template +__device__ inline FPTYPE compute_volume( + const FPTYPE * boxt) +{ + FPTYPE volume = + boxt[0*3+0] * (boxt[1*3+1]*boxt[2*3+2] - boxt[2*3+1]*boxt[1*3+2]) - + boxt[0*3+1] * (boxt[1*3+0]*boxt[2*3+2] - boxt[2*3+0]*boxt[1*3+2]) + + boxt[0*3+2] * (boxt[1*3+0]*boxt[2*3+1] - boxt[2*3+0]*boxt[1*3+1]); + return volume; +} \ No newline at end of file diff --git a/source/lib/src/cuda/coord.cu b/source/lib/src/cuda/coord.cu index a48ac7b02a..24bd9fdf2d 100644 --- a/source/lib/src/cuda/coord.cu +++ b/source/lib/src/cuda/coord.cu @@ -1,7 +1,7 @@ #include "device.h" #include "gpu_cuda.h" #include "coord.h" -#include "region.cu" +#include "region.cuh" __device__ inline int collapse_index( const int * idx, diff --git a/source/lib/src/cuda/region.cu b/source/lib/src/cuda/region.cu index d26803c4ed..4a95e5f9da 100644 --- a/source/lib/src/cuda/region.cu +++ b/source/lib/src/cuda/region.cu @@ -1,53 +1,7 @@ #include "device.h" #include "gpu_cuda.h" #include "region.h" - -template -__device__ inline void tensorDotVector( - FPTYPE *o_v, - const FPTYPE *i_v, - const FPTYPE *i_t) -{ - o_v[0] = i_v[0] * i_t[0*3+0] + i_v[1] * i_t[0*3+1] + i_v[2] * i_t[0*3+2]; - o_v[1] = i_v[0] * i_t[1*3+0] + i_v[1] * i_t[1*3+1] + i_v[2] * i_t[1*3+2]; - o_v[2] = i_v[0] * i_t[2*3+0] + i_v[1] * i_t[2*3+1] + i_v[2] * i_t[2*3+2]; -} -template -__device__ inline void tensorTransDotVector( - FPTYPE *o_v, - const FPTYPE *i_v, - const FPTYPE *i_t) -{ - o_v[0] = i_v[0] * i_t[0*3+0] + i_v[1] * i_t[1*3+0] + i_v[2] * i_t[2*3+0]; - o_v[1] = i_v[0] * i_t[0*3+1] + i_v[1] * i_t[1*3+1] + i_v[2] * i_t[2*3+1]; - o_v[2] = i_v[0] * i_t[0*3+2] + i_v[1] * i_t[1*3+2] + i_v[2] * i_t[2*3+2]; -} -template -__device__ inline void phys2Inter( - FPTYPE *inter, - const FPTYPE *phys, - const FPTYPE *rec_boxt) -{ - tensorDotVector(inter, phys, rec_boxt); -} -template -__device__ inline void inter2Phys( - FPTYPE *phys, - const FPTYPE *inter, - const FPTYPE *boxt) -{ - tensorTransDotVector(phys, inter, boxt); -} -template -__device__ inline FPTYPE compute_volume( - const FPTYPE * boxt) -{ - FPTYPE volume = - boxt[0*3+0] * (boxt[1*3+1]*boxt[2*3+2] - boxt[2*3+1]*boxt[1*3+2]) - - boxt[0*3+1] * (boxt[1*3+0]*boxt[2*3+2] - boxt[2*3+0]*boxt[1*3+2]) + - boxt[0*3+2] * (boxt[1*3+0]*boxt[2*3+1] - boxt[2*3+0]*boxt[1*3+1]); - return volume; -} +#include "region.cuh" template __global__ void _phys2Inter( From 35789ffa032c80a629773a96fe23b2937cd51a15 Mon Sep 17 00:00:00 2001 From: tuoping <80671886+tuoping@users.noreply.github.com> Date: Thu, 1 Apr 2021 16:47:32 +0800 Subject: [PATCH 317/562] Update install.md --- doc/install.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/install.md b/doc/install.md index ebbf7c2989..1dab9f734b 100644 --- a/doc/install.md +++ b/doc/install.md @@ -10,6 +10,7 @@ - [Install the Tensorflow's C++ interface](#install-the-tensorflows-c-interface) - [Install the DeePMD-kit's C++ interface](#install-the-deepmd-kits-c-interface) - [Install LAMMPS's DeePMD-kit module](#install-lammpss-deepmd-kit-module) + - [Hardware platforms](#install-on-various-hardware-platforms) # Download and install @@ -202,3 +203,7 @@ The DeePMD-kit module can be removed from LAMMPS source code by ```bash make no-user-deepmd ``` + +## Hardware platforms + + From b536512190c5297fa8f630ea8127cf2ae98e576d Mon Sep 17 00:00:00 2001 From: tuoping <80671886+tuoping@users.noreply.github.com> Date: Thu, 1 Apr 2021 16:52:13 +0800 Subject: [PATCH 318/562] Update use-deepmd-kit.md --- doc/use-deepmd-kit.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/use-deepmd-kit.md b/doc/use-deepmd-kit.md index d182c61b50..d0168a11a2 100644 --- a/doc/use-deepmd-kit.md +++ b/doc/use-deepmd-kit.md @@ -10,6 +10,7 @@ - [Run MD with Lammps](#run-md-with-lammps) - [Include deepmd in the pair style](#include-deepmd-in-the-pair-style) - [Long-range interaction](#long-range-interaction) + - [Model deviation with lammps](#Model-deviation-with-lammps) - [Run path-integral MD with i-PI](#run-path-integral-md-with-i-pi) - [Use deep potential with ASE](#use-deep-potential-with-ase) @@ -361,6 +362,8 @@ kspace_modify gewald 0.45 ``` Please notice that the DeePMD does nothing to the direct space part of the electrostatic interaction, because this part is assumed to be fitted in the DeePMD model (the direct space cut-off is thus the cut-off of the DeePMD model). The splitting parameter `gewald` is modified by the `kspace_modify` command. +### Model deviation with lammps + ## Run path-integral MD with i-PI The i-PI works in a client-server model. The i-PI provides the server for integrating the replica positions of atoms, while the DeePMD-kit provides a client named `dp_ipi` that computes the interactions (including energy, force and virial). The server and client communicates via the Unix domain socket or the Internet socket. The client can be started by ```bash From d452d95dc58720fae5dbafb6d0c24dfe656d3b19 Mon Sep 17 00:00:00 2001 From: tuoping <80671886+tuoping@users.noreply.github.com> Date: Thu, 1 Apr 2021 16:53:45 +0800 Subject: [PATCH 319/562] Update index.rst --- doc/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/index.rst b/doc/index.rst index c5b2a2af22..9b0982deee 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -15,6 +15,7 @@ DeePMD-kit's documentation use-deepmd-kit train-input lammps-pair-style-deepmd + Novel auxiliary options tensorboard api developement From 2716b34c99553c2e1c12726737313d7e893742a4 Mon Sep 17 00:00:00 2001 From: tuoping <80671886+tuoping@users.noreply.github.com> Date: Thu, 1 Apr 2021 16:55:51 +0800 Subject: [PATCH 320/562] Update index.rst --- doc/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/index.rst b/doc/index.rst index 9b0982deee..608ebab58b 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -15,7 +15,7 @@ DeePMD-kit's documentation use-deepmd-kit train-input lammps-pair-style-deepmd - Novel auxiliary options + novel auxiliary options tensorboard api developement From 8c660b400109187aa67f6ca6e155337a7605e5fc Mon Sep 17 00:00:00 2001 From: tuoping <80671886+tuoping@users.noreply.github.com> Date: Thu, 1 Apr 2021 17:00:18 +0800 Subject: [PATCH 321/562] Create novel-auxiliary-options --- doc/novel-auxiliary-options | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 doc/novel-auxiliary-options diff --git a/doc/novel-auxiliary-options b/doc/novel-auxiliary-options new file mode 100644 index 0000000000..9e92382d10 --- /dev/null +++ b/doc/novel-auxiliary-options @@ -0,0 +1,17 @@ +# Novel Auxiliary Options +## Type embedding +Instead of training embedding net for each atom pair (regard as G_ij, and turns out to be N^2 networks), we now share a public embedding net (regard as G) and present each atom with a special vector, named as type embedding (v_i). So, our algorithm for generating a description change from G_ij(s_ij) to G(s_ij, v_i, v_j). +1. We obtain the type embedding by a small embedding net, projecting atom type to embedding vector. +2. As for the fitting net, we fix the type embedding and replace individual fitting net with shared fitting net. (while adding type embedding information to its input) + +### Training hyper-parameter +descriptor: +"type" : "se_a_ebd" # for applying share embedding algorithm +"type_filter" : list # network architecture of the small embedding net, which output type embedding +"type_one_side" : bool # when generating descriptor, whether use the centric atom type embedding (true: G(s_ij, v_i, v_j), false: G(s_ij, v_j)) + +fitting_net: +"share_fitting" : bool # if applying share fitting net, set true + + +## Interpolation with tabulated pair potentials From 4f6362d20675f94585aa7999c420d3ebae5137b5 Mon Sep 17 00:00:00 2001 From: tuoping <80671886+tuoping@users.noreply.github.com> Date: Thu, 1 Apr 2021 17:02:37 +0800 Subject: [PATCH 322/562] Update index.rst --- doc/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/index.rst b/doc/index.rst index 608ebab58b..7b24b702aa 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -15,7 +15,7 @@ DeePMD-kit's documentation use-deepmd-kit train-input lammps-pair-style-deepmd - novel auxiliary options + novel-auxiliary-options tensorboard api developement From 370e874478f2c3ac2031e16eee75a61c07a440e5 Mon Sep 17 00:00:00 2001 From: tuoping <80671886+tuoping@users.noreply.github.com> Date: Thu, 1 Apr 2021 17:04:48 +0800 Subject: [PATCH 323/562] Update use-deepmd-kit.md --- doc/use-deepmd-kit.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/use-deepmd-kit.md b/doc/use-deepmd-kit.md index d0168a11a2..0f27c67ad3 100644 --- a/doc/use-deepmd-kit.md +++ b/doc/use-deepmd-kit.md @@ -362,8 +362,6 @@ kspace_modify gewald 0.45 ``` Please notice that the DeePMD does nothing to the direct space part of the electrostatic interaction, because this part is assumed to be fitted in the DeePMD model (the direct space cut-off is thus the cut-off of the DeePMD model). The splitting parameter `gewald` is modified by the `kspace_modify` command. -### Model deviation with lammps - ## Run path-integral MD with i-PI The i-PI works in a client-server model. The i-PI provides the server for integrating the replica positions of atoms, while the DeePMD-kit provides a client named `dp_ipi` that computes the interactions (including energy, force and virial). The server and client communicates via the Unix domain socket or the Internet socket. The client can be started by ```bash From 71316a01af1cb73425b8a5a1b1baab2e60b0c405 Mon Sep 17 00:00:00 2001 From: tuoping Date: Fri, 2 Apr 2021 09:50:18 +0800 Subject: [PATCH 324/562] Adding entries in document --- doc/application-examples.md | 7 +++++++ doc/index.rst | 1 + doc/install.md | 2 +- ...{novel-auxiliary-options => novel-auxiliary-options.md} | 0 doc/use-deepmd-kit.md | 4 ++-- 5 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 doc/application-examples.md rename doc/{novel-auxiliary-options => novel-auxiliary-options.md} (100%) diff --git a/doc/application-examples.md b/doc/application-examples.md new file mode 100644 index 0000000000..ede982a87c --- /dev/null +++ b/doc/application-examples.md @@ -0,0 +1,7 @@ +# Application Examples + +## Dipole and polarizability model training + +## Training with non-periodic systems + +## MD on different hardware platforms diff --git a/doc/index.rst b/doc/index.rst index 7b24b702aa..8c1dff0071 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -19,6 +19,7 @@ DeePMD-kit's documentation tensorboard api developement + application-examples Indices and tables diff --git a/doc/install.md b/doc/install.md index 1dab9f734b..d18f54cd1f 100644 --- a/doc/install.md +++ b/doc/install.md @@ -10,7 +10,7 @@ - [Install the Tensorflow's C++ interface](#install-the-tensorflows-c-interface) - [Install the DeePMD-kit's C++ interface](#install-the-deepmd-kits-c-interface) - [Install LAMMPS's DeePMD-kit module](#install-lammpss-deepmd-kit-module) - - [Hardware platforms](#install-on-various-hardware-platforms) + - [Hardware platforms](#hardware-platforms) # Download and install diff --git a/doc/novel-auxiliary-options b/doc/novel-auxiliary-options.md similarity index 100% rename from doc/novel-auxiliary-options rename to doc/novel-auxiliary-options.md diff --git a/doc/use-deepmd-kit.md b/doc/use-deepmd-kit.md index 0f27c67ad3..b7ef11ba69 100644 --- a/doc/use-deepmd-kit.md +++ b/doc/use-deepmd-kit.md @@ -10,7 +10,6 @@ - [Run MD with Lammps](#run-md-with-lammps) - [Include deepmd in the pair style](#include-deepmd-in-the-pair-style) - [Long-range interaction](#long-range-interaction) - - [Model deviation with lammps](#Model-deviation-with-lammps) - [Run path-integral MD with i-PI](#run-path-integral-md-with-i-pi) - [Use deep potential with ASE](#use-deep-potential-with-ase) @@ -33,6 +32,7 @@ Time | ps Length | Å Energy | eV Force | eV/Å +Virial | kBar Pressure| Bar The frames of the system are stored in two formats. A raw file is a plain text file with each information item written in one file and one frame written on one line. The default files that provide box, coordinate, force, energy and virial are `box.raw`, `coord.raw`, `force.raw`, `energy.raw` and `virial.raw`, respectively. *We recommend you use these file names*. Here is an example of force.raw: @@ -42,7 +42,7 @@ $ cat force.raw 6.737 1.554 -5.587 -2.803 0.062 2.222 -1.968 -0.163 1.020 -0.225 -0.789 0.343 ``` -This `force.raw` contains 3 frames with each frame having the forces of 2 atoms, thus it has 3 lines and 6 columns. Each line provides all the 3 force components of 2 atoms in 1 frame. The first three numbers are the 3 force components of the first atom, while the second three numbers are the 3 force components of the second atom. The coordinate file `coord.raw` is organized similarly. In `box.raw`, the 9 components of the box vectors should be provided on each line. In `virial.raw`, the 9 components of the virial tensor should be provided on each line. The number of lines of all raw files should be identical. +This `force.raw` contains 3 frames with each frame having the forces of 2 atoms, thus it has 3 lines and 6 columns. Each line provides all the 3 force components of 2 atoms in 1 frame. The first three numbers are the 3 force components of the first atom, while the second three numbers are the 3 force components of the second atom. The coordinate file `coord.raw` is organized similarly. In `box.raw`, the 9 components of the box vectors should be provided on each line. In `virial.raw`, the 9 components of the virial tensor should be provided on each line in the order `XX YY ZZ XY YX YZ ZY XZ ZX`. The number of lines of all raw files should be identical. We assume that the atom types do not change in all frames. It is provided by `type.raw`, which has one line with the types of atoms written one by one. The atom types should be integers. For example the `type.raw` of a system that has 2 atoms with 0 and 1: ```bash From 4a94973b8a1490be6a32b73affbb6aa2ecf49650 Mon Sep 17 00:00:00 2001 From: tuoping Date: Fri, 2 Apr 2021 15:31:58 +0800 Subject: [PATCH 325/562] doc modification strike 2 --- doc/use-deepmd-kit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/use-deepmd-kit.md b/doc/use-deepmd-kit.md index b7ef11ba69..27a4ccc29f 100644 --- a/doc/use-deepmd-kit.md +++ b/doc/use-deepmd-kit.md @@ -42,7 +42,7 @@ $ cat force.raw 6.737 1.554 -5.587 -2.803 0.062 2.222 -1.968 -0.163 1.020 -0.225 -0.789 0.343 ``` -This `force.raw` contains 3 frames with each frame having the forces of 2 atoms, thus it has 3 lines and 6 columns. Each line provides all the 3 force components of 2 atoms in 1 frame. The first three numbers are the 3 force components of the first atom, while the second three numbers are the 3 force components of the second atom. The coordinate file `coord.raw` is organized similarly. In `box.raw`, the 9 components of the box vectors should be provided on each line. In `virial.raw`, the 9 components of the virial tensor should be provided on each line in the order `XX YY ZZ XY YX YZ ZY XZ ZX`. The number of lines of all raw files should be identical. +This `force.raw` contains 3 frames with each frame having the forces of 2 atoms, thus it has 3 lines and 6 columns. Each line provides all the 3 force components of 2 atoms in 1 frame. The first three numbers are the 3 force components of the first atom, while the second three numbers are the 3 force components of the second atom. The coordinate file `coord.raw` is organized similarly. In `box.raw`, the 9 components of the box vectors should be provided on each line. In `virial.raw`, the 9 components of the virial tensor should be provided on each line in the order `XX XY XZ YX YY YZ ZX ZY ZZ`. The number of lines of all raw files should be identical. We assume that the atom types do not change in all frames. It is provided by `type.raw`, which has one line with the types of atoms written one by one. The atom types should be integers. For example the `type.raw` of a system that has 2 atoms with 0 and 1: ```bash From 93dd14334103bf96b3fc4ab89e3abd063867a4f1 Mon Sep 17 00:00:00 2001 From: tuoping Date: Fri, 2 Apr 2021 16:23:57 +0800 Subject: [PATCH 326/562] doc modification strike 3 --- doc/novel-auxiliary-options.md | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/novel-auxiliary-options.md b/doc/novel-auxiliary-options.md index 9e92382d10..8918146a9f 100644 --- a/doc/novel-auxiliary-options.md +++ b/doc/novel-auxiliary-options.md @@ -13,5 +13,4 @@ descriptor: fitting_net: "share_fitting" : bool # if applying share fitting net, set true - ## Interpolation with tabulated pair potentials From db40236e1110ba66e17466caf72ca604ac10f06c Mon Sep 17 00:00:00 2001 From: tuoping Date: Fri, 2 Apr 2021 16:37:13 +0800 Subject: [PATCH 327/562] doc modification strike 4 --- doc/application-examples.md | 1 + doc/novel-auxiliary-options.md | 1 + 2 files changed, 2 insertions(+) diff --git a/doc/application-examples.md b/doc/application-examples.md index ede982a87c..4fa2674713 100644 --- a/doc/application-examples.md +++ b/doc/application-examples.md @@ -5,3 +5,4 @@ ## Training with non-periodic systems ## MD on different hardware platforms + diff --git a/doc/novel-auxiliary-options.md b/doc/novel-auxiliary-options.md index 8918146a9f..9e92382d10 100644 --- a/doc/novel-auxiliary-options.md +++ b/doc/novel-auxiliary-options.md @@ -13,4 +13,5 @@ descriptor: fitting_net: "share_fitting" : bool # if applying share fitting net, set true + ## Interpolation with tabulated pair potentials From e1119de1cf09fb1365fec29c9690f63d4e4436fb Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Fri, 2 Apr 2021 14:45:11 -0400 Subject: [PATCH 328/562] install g++-7 in GitHub Actions See https://github.com/actions/virtual-environments/issues/2950 for details --- .github/workflows/build_cc.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_cc.yml b/.github/workflows/build_cc.yml index 6f7d9f047b..1a2b14b38d 100644 --- a/.github/workflows/build_cc.yml +++ b/.github/workflows/build_cc.yml @@ -21,7 +21,8 @@ jobs: - uses: actions/checkout@master with: submodules: true - - run: sudo apt update && sudo apt install nvidia-cuda-toolkit + - run: sudo apt update && sudo apt install g++-7 + - run: sudo apt install nvidia-cuda-toolkit if: matrix.variant == 'gpu' - run: source/install/build_cc.sh env: From c539dba9c56793c0e0fed2d6d9de3557e411ca2b Mon Sep 17 00:00:00 2001 From: tuoping Date: Mon, 5 Apr 2021 15:54:43 +0800 Subject: [PATCH 329/562] changed the unit of virial --- doc/use-deepmd-kit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/use-deepmd-kit.md b/doc/use-deepmd-kit.md index 27a4ccc29f..e456137578 100644 --- a/doc/use-deepmd-kit.md +++ b/doc/use-deepmd-kit.md @@ -32,7 +32,7 @@ Time | ps Length | Å Energy | eV Force | eV/Å -Virial | kBar +Virial | eV Pressure| Bar The frames of the system are stored in two formats. A raw file is a plain text file with each information item written in one file and one frame written on one line. The default files that provide box, coordinate, force, energy and virial are `box.raw`, `coord.raw`, `force.raw`, `energy.raw` and `virial.raw`, respectively. *We recommend you use these file names*. Here is an example of force.raw: From 476399495fb0673cc32b4dab5376499bef237629 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 5 Apr 2021 17:51:14 +0800 Subject: [PATCH 330/562] update doc for intallation --- doc/install.md | 74 ++++++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/doc/install.md b/doc/install.md index 5e00d3275a..e222c1f073 100644 --- a/doc/install.md +++ b/doc/install.md @@ -1,29 +1,26 @@ -- [Download and install](#download-and-install) - - [Easy installation methods](#easy-installation-methods) - - [Offline packages](#offline-packages) - - [With Docker](#with-docker) - - [With conda](#with-conda) +- [Easy installation methods](#easy-installation-methods) + - [Offline packages](#offline-packages) + - [With Docker](#with-docker) + - [With conda](#with-conda) +- [From source code](#from-source-code) - [Install the python interaction](#install-the-python-interface) - [Install the Tensorflow's python interface](#install-the-tensorflows-python-interface) - [Install the DeePMD-kit's python interface](#install-the-deepmd-kits-python-interface) - [Install the C++ interface](#install-the-c-interface) - - [Install the Tensorflow's C++ interface](#install-the-tensorflows-c-interface) - - [Install the DeePMD-kit's C++ interface](#install-the-deepmd-kits-c-interface) - - [Install LAMMPS's DeePMD-kit module](#install-lammpss-deepmd-kit-module) + - [Install the Tensorflow's C++ interface](#install-the-tensorflows-c-interface) + - [Install the DeePMD-kit's C++ interface](#install-the-deepmd-kits-c-interface) + - [Install LAMMPS's DeePMD-kit module](#install-lammpss-deepmd-kit-module) -# Download and install -Please follow our [github](https://github.com/deepmodeling/deepmd-kit) webpage to download the [latest released version](https://github.com/deepmodeling/deepmd-kit/tree/master) and [development version](https://github.com/deepmodeling/deepmd-kit/tree/devel). - -## Easy installation methods +# Easy installation methods There various easy methods to install DeePMD-kit. Choose one that you prefer. If you want to build by yourself, jump to the next two sections. After your easy installation, DeePMD-kit (`dp`) and LAMMPS (`lmp`) will be available to execute. You can try `dp -h` and `lmp -h` to see the help. `mpirun` is also available considering you may want to run LAMMPS in parallel. -### Offline packages +## Offline packages Both CPU and GPU version offline packages are avaiable in [the Releases page](https://github.com/deepmodeling/deepmd-kit/releases). -### With conda +## With conda DeePMD-kit is avaiable with [conda](https://github.com/conda/conda). Install [Anaconda](https://www.anaconda.com/distribution/#download-section) or [Miniconda](https://docs.conda.io/en/latest/miniconda.html) first. To install the CPU version: @@ -36,7 +33,7 @@ To install the GPU version containing [CUDA 10.1](https://docs.nvidia.com/deploy conda install deepmd-kit=*=*gpu lammps-dp=*=*gpu -c deepmodeling ``` -### With Docker +## With Docker A docker for installing the DeePMD-kit is available [here](https://github.com/orgs/deepmodeling/packages/container/package/deepmd-kit). To pull the CPU version: @@ -49,6 +46,25 @@ To pull the GPU version: docker pull ghcr.io/deepmodeling/deepmd-kit:1.2.2_cuda10.1_gpu ``` + +# From source code + +Please follow our [github](https://github.com/deepmodeling/deepmd-kit) webpage to download the [latest released version](https://github.com/deepmodeling/deepmd-kit/tree/master) and [development version](https://github.com/deepmodeling/deepmd-kit/tree/devel). + +Or get the DeePMD-kit source code by `git clone` +```bash +cd /some/workspace +git clone --recursive https://github.com/deepmodeling/deepmd-kit.git deepmd-kit +``` +The `--recursive` option clones all [submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) needed by DeePMD-kit. + +For convenience, you may want to record the location of source to a variable, saying `deepmd_source_dir` by +```bash +cd deepmd-kit +deepmd_source_dir=`pwd` +``` + + ## Install the python interface ### Install the Tensorflow's python interface First, check the python version on your machine @@ -89,9 +105,14 @@ One should remember to activate the virtual environment every time he/she uses d Execute ```bash -pip install deepmd-kit +cd $deepmd_source_dir +pip install . +``` +To test the installation, one should firstly jump out of the source directory +``` +cd /some/other/workspace ``` -To test the installation, one may execute +then execute ```bash dp -h ``` @@ -130,18 +151,6 @@ First the C++ interface of Tensorflow should be installed. It is noted that the ### Install the DeePMD-kit's C++ interface -Clone the DeePMD-kit source code -```bash -cd /some/workspace -git clone --recursive https://github.com/deepmodeling/deepmd-kit.git deepmd-kit -``` - -For convenience, you may want to record the location of source to a variable, saying `deepmd_source_dir` by -```bash -cd deepmd-kit -deepmd_source_dir=`pwd` -``` - Now goto the source code directory of DeePMD-kit and make a build place. ```bash cd $deepmd_source_dir/source @@ -175,18 +184,19 @@ DeePMD-kit provide module for running MD simulation with LAMMPS. Now make the De cd $deepmd_source_dir/source/build make lammps ``` -DeePMD-kit will generate a module called `USER-DEEPMD` in the `build` directory. Now download your favorite LAMMPS code, and uncompress it (I assume that you have downloaded the tar `lammps-stable.tar.gz`) +DeePMD-kit will generate a module called `USER-DEEPMD` in the `build` directory. Now download a LAMMPS code with version later than `stable_29Oct2020`, and uncompress it (I assume that you have downloaded the tar `lammps-stable.tar.gz`) ```bash cd /some/workspace tar xf lammps-stable.tar.gz ``` -The source code of LAMMPS is stored in directory, for example `lammps-31Mar17`. Now go into the LAMMPS code and copy the DeePMD-kit module like this +The source code of LAMMPS is stored in directory, Now go into the LAMMPS code and copy the DeePMD-kit module like this ```bash -cd lammps-31Mar17/src/ +cd lammps-29Oct2020/src/ cp -r $deepmd_source_dir/source/build/USER-DEEPMD . ``` Now build LAMMPS ```bash +make yes-kspace make yes-user-deepmd make mpi -j4 ``` From 89c9dfdabfa307a1f069b5c5e1e488ca955388d0 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Fri, 2 Apr 2021 14:45:11 -0400 Subject: [PATCH 331/562] install g++-7 in GitHub Actions See https://github.com/actions/virtual-environments/issues/2950 for details --- .github/workflows/build_cc.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_cc.yml b/.github/workflows/build_cc.yml index 6f7d9f047b..1a2b14b38d 100644 --- a/.github/workflows/build_cc.yml +++ b/.github/workflows/build_cc.yml @@ -21,7 +21,8 @@ jobs: - uses: actions/checkout@master with: submodules: true - - run: sudo apt update && sudo apt install nvidia-cuda-toolkit + - run: sudo apt update && sudo apt install g++-7 + - run: sudo apt install nvidia-cuda-toolkit if: matrix.variant == 'gpu' - run: source/install/build_cc.sh env: From f0617adf7d4de6db690f77a47227f381ddf972d2 Mon Sep 17 00:00:00 2001 From: Duo Date: Wed, 7 Apr 2021 01:37:55 +0800 Subject: [PATCH 332/562] prod_force_grad&prod_virial_grad gpu update --- source/lib/include/prod_force_grad.h | 20 ++ source/lib/include/prod_virial_grad.h | 22 ++ source/lib/src/cuda/CMakeLists.txt | 2 +- source/lib/src/cuda/prod_force_grad.cu | 143 ++++++++++ source/lib/src/cuda/prod_virial.cu | 36 +++ source/lib/src/cuda/prod_virial_grad.cu | 141 ++++++++++ source/lib/tests/test_prod_force_grad_a.cc | 31 +++ source/lib/tests/test_prod_force_grad_r.cc | 31 +++ source/lib/tests/test_prod_virial_a.cc | 13 +- source/lib/tests/test_prod_virial_grad_a.cc | 34 +++ source/lib/tests/test_prod_virial_grad_r.cc | 34 +++ source/lib/tests/test_prod_virial_r.cc | 13 +- source/op/CMakeLists.txt | 2 +- source/op/prod_force_grad_multi_device.cc | 251 ++++++++++++++++++ source/op/prod_virial_grad_multi_device.cc | 275 ++++++++++++++++++++ 15 files changed, 1032 insertions(+), 16 deletions(-) create mode 100644 source/lib/src/cuda/prod_force_grad.cu create mode 100644 source/lib/src/cuda/prod_virial_grad.cu create mode 100644 source/op/prod_force_grad_multi_device.cc create mode 100644 source/op/prod_virial_grad_multi_device.cc diff --git a/source/lib/include/prod_force_grad.h b/source/lib/include/prod_force_grad.h index b4b95f2ac3..f6ac58269f 100644 --- a/source/lib/include/prod_force_grad.h +++ b/source/lib/include/prod_force_grad.h @@ -20,4 +20,24 @@ void prod_force_grad_r_cpu( const int nloc, const int nnei); +#if GOOGLE_CUDA +template +void prod_force_grad_a_gpu_cuda( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const int * nlist, + const int nloc, + const int nnei); + +template +void prod_force_grad_r_gpu_cuda( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const int * nlist, + const int nloc, + const int nnei); +#endif // GOOGLE_CUDA + } diff --git a/source/lib/include/prod_virial_grad.h b/source/lib/include/prod_virial_grad.h index ab0f84ffec..7a8c87c0dd 100644 --- a/source/lib/include/prod_virial_grad.h +++ b/source/lib/include/prod_virial_grad.h @@ -22,4 +22,26 @@ void prod_virial_grad_r_cpu( const int nloc, const int nnei); +#if GOOGLE_CUDA +template +void prod_virial_grad_a_gpu_cuda( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nnei); + +template +void prod_virial_grad_r_gpu_cuda( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nnei); +#endif // GOOGLE_CUDA + } diff --git a/source/lib/src/cuda/CMakeLists.txt b/source/lib/src/cuda/CMakeLists.txt index f9832caefd..41a2ea091e 100644 --- a/source/lib/src/cuda/CMakeLists.txt +++ b/source/lib/src/cuda/CMakeLists.txt @@ -106,7 +106,7 @@ endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -DCUB_IGNORE_DEPRECATED_CPP_DIALECT -DCUB_IGNORE_DEPRECATED_CPP_DIALECT") set (SOURCE_FILES - prod_env_mat.cu prod_force.cu prod_virial.cu gelu.cu tabulate.cu coord.cu neighbor_list.cu region.cu + prod_env_mat.cu prod_force.cu prod_force_grad.cu prod_virial.cu prod_virial_grad.cu gelu.cu tabulate.cu coord.cu neighbor_list.cu region.cu ) cuda_add_library(deepmd_op_cuda SHARED ${SOURCE_FILES}) diff --git a/source/lib/src/cuda/prod_force_grad.cu b/source/lib/src/cuda/prod_force_grad.cu new file mode 100644 index 0000000000..7fd9359cfe --- /dev/null +++ b/source/lib/src/cuda/prod_force_grad.cu @@ -0,0 +1,143 @@ +#include "device.h" +#include "gpu_cuda.h" +#include "prod_force_grad.h" + +template +__device__ inline FPTYPE dev_dot( + const FPTYPE * arr1, + const FPTYPE * arr2) +{ + return arr1[0] * arr2[0] + arr1[1] * arr2[1] + arr1[2] * arr2[2]; +} + +template +__global__ void force_grad_wrt_center_atom( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const int ndescrpt) +{ + __shared__ FPTYPE grad_one[3]; + unsigned int center_idx = blockIdx.x; + unsigned int tid = threadIdx.x; + if(tid < 3){ + grad_one[tid] = grad[center_idx * 3 + tid]; + } + __syncthreads(); + unsigned int descrpt_idx = blockIdx.y * blockDim.x + tid; + if(descrpt_idx < ndescrpt){ + grad_net[center_idx * ndescrpt + descrpt_idx] -= dev_dot(grad_one, env_deriv + center_idx * ndescrpt * 3 + descrpt_idx * 3); + } +} + +template +__global__ void force_grad_wrt_neighbors_a( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const int * nlist, + const int nloc, + const int nnei) +{ + // idy -> nnei + const unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x; + const unsigned int idy = blockIdx.y; + const unsigned int idw = threadIdx.y; + if (idx >= nloc) { + return; + } + int j_idx = nlist[idx * nnei + idy]; + if (j_idx < 0) { + return; + } + if (j_idx >= nloc) j_idx = j_idx % nloc; + grad_net[idx * nnei * 4 + idy * 4 + idw] += dev_dot(grad + j_idx * 3, env_deriv + idx * nnei * 4 * 3 + idy * 4 * 3 + idw * 3); +} + +template +__global__ void force_grad_wrt_neighbors_r( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const int * nlist, + const int nloc, + const int nnei) +{ + // idy -> nnei + const unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x; + const unsigned int idy = blockIdx.y; + if (idx >= nloc) { + return; + } + int j_idx = nlist[idx * nnei + idy]; + if (j_idx < 0) { + return; + } + if (j_idx >= nloc) j_idx = j_idx % nloc; + grad_net[idx * nnei + idy] += dev_dot(grad + j_idx * 3, env_deriv + idx * nnei * 3 + idy * 3); +} + +namespace deepmd { +template +void prod_force_grad_a_gpu_cuda( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const int * nlist, + const int nloc, + const int nnei) +{ + const int ndescrpt = nnei * 4; + cudaErrcheck(cudaMemset( + grad_net, + 0.0, sizeof(FPTYPE) * nloc * ndescrpt)); + const int nblock = (ndescrpt + TPB - 1) / TPB; + dim3 block_grid(nloc, nblock); + dim3 thread_grid(TPB, 1); + force_grad_wrt_center_atom<<>>( + grad_net, + grad, env_deriv, ndescrpt); + + const int LEN = 128; + const int nblock_ = (nloc + LEN -1) / LEN; + dim3 block_grid_(nblock_, nnei); + dim3 thread_grid_(LEN, 4); + force_grad_wrt_neighbors_a<<>>( + grad_net, + grad, env_deriv, nlist, nloc, nnei); +} + +template +void prod_force_grad_r_gpu_cuda( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const int * nlist, + const int nloc, + const int nnei) +{ + const int ndescrpt = nnei * 1; + cudaErrcheck(cudaMemset( + grad_net, + 0.0, sizeof(FPTYPE) * nloc * ndescrpt)); + const int nblock = (ndescrpt + TPB - 1) / TPB; + dim3 block_grid(nloc, nblock); + dim3 thread_grid(TPB, 1); + force_grad_wrt_center_atom<<>>( + grad_net, + grad, env_deriv, ndescrpt); + + const int LEN = 128; + const int nblock_ = (nloc + LEN -1) / LEN; + dim3 block_grid_(nblock_, nnei); + dim3 thread_grid_(LEN, 1); + force_grad_wrt_neighbors_r<<>>( + grad_net, + grad, env_deriv, nlist, nloc, nnei); +} + +template void prod_force_grad_a_gpu_cuda(float * grad_net, const float * grad, const float * env_deriv, const int * nlist, const int nloc, const int nnei); +template void prod_force_grad_a_gpu_cuda(double * grad_net, const double * grad, const double * env_deriv, const int * nlist, const int nloc, const int nnei); +template void prod_force_grad_r_gpu_cuda(float * grad_net, const float * grad, const float * env_deriv, const int * nlist, const int nloc, const int nnei); +template void prod_force_grad_r_gpu_cuda(double * grad_net, const double * grad, const double * env_deriv, const int * nlist, const int nloc, const int nnei); +} \ No newline at end of file diff --git a/source/lib/src/cuda/prod_virial.cu b/source/lib/src/cuda/prod_virial.cu index 032e1b1c09..addb4df92a 100644 --- a/source/lib/src/cuda/prod_virial.cu +++ b/source/lib/src/cuda/prod_virial.cu @@ -1,6 +1,34 @@ +#include "device.h" #include "gpu_cuda.h" #include "prod_virial.h" +template < + typename FPTYPE, + int THREADS_PER_BLOCK> +__global__ void atom_virial_reduction( + FPTYPE * virial, + const FPTYPE * atom_virial, + const int nall) +{ + unsigned int bid = blockIdx.x; + unsigned int tid = threadIdx.x; + __shared__ FPTYPE data[THREADS_PER_BLOCK]; + data[tid] = 0.f; + for (int ii = tid; ii < nall; ii += THREADS_PER_BLOCK) { + data[tid] += atom_virial[ii * 9 + bid]; + } + __syncthreads(); + // do reduction in shared memory + for (int ii = THREADS_PER_BLOCK >> 1; ii > 0; ii >>= 1) { + if (tid < ii) { + data[tid] += data[tid + ii]; + } + __syncthreads(); + } + // write result for this block to global memory + if (tid == 0) virial[bid] = data[0]; +} + template __global__ void virial_deriv_wrt_neighbors_a( FPTYPE * virial, @@ -101,6 +129,10 @@ void prod_virial_a_gpu_cuda( virial_deriv_wrt_neighbors_a<<>>( virial, atom_virial, net_deriv, in_deriv, rij, nlist, nloc, nnei); + // reduction atom_virial to virial + atom_virial_reduction <<<9, TPB>>>( + virial, + atom_virial, nall); } template @@ -130,6 +162,10 @@ void prod_virial_r_gpu_cuda( virial_deriv_wrt_neighbors_r<<>>( virial, atom_virial, net_deriv, in_deriv, rij, nlist, nloc, nnei); + // reduction atom_virial to virial + atom_virial_reduction <<<9, TPB>>>( + virial, + atom_virial, nall); } template void prod_virial_a_gpu_cuda(float * virial, float * atom_virial, const float * net_deriv, const float * in_deriv, const float * rij, const int * nlist, const int nloc, const int nall, const int nnei); diff --git a/source/lib/src/cuda/prod_virial_grad.cu b/source/lib/src/cuda/prod_virial_grad.cu new file mode 100644 index 0000000000..2cdd25ec38 --- /dev/null +++ b/source/lib/src/cuda/prod_virial_grad.cu @@ -0,0 +1,141 @@ +#include "device.h" +#include "gpu_cuda.h" +#include "prod_virial_grad.h" + +template +__device__ inline FPTYPE dev_dot9( + const FPTYPE * arr1, + const FPTYPE * arr2) +{ + FPTYPE result = 0.0; + for(int ii=0; ii<9; ii++){ + result += arr1[ii] * arr2[ii]; + } + return result; +} + +template +__global__ void virial_grad_wrt_neighbors_a( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nnei) +{ + // idy -> nnei + const unsigned int tid = threadIdx.x; + const unsigned int idx = blockIdx.x * blockDim.x + tid; + const unsigned int idy = blockIdx.y; + const unsigned int idw = threadIdx.y; + const int ndescrpt = nnei * 4; + __shared__ FPTYPE grad_one[9]; + if(tid < 9){ + grad_one[tid] = grad[tid]; + } + __syncthreads(); + if (idx >= nloc) { + return; + } + int j_idx = nlist[idx * nnei + idy]; + if (j_idx < 0) { + return; + } + FPTYPE tmp[9]; + for (int dd0 = 0; dd0 < 3; ++dd0){ + for (int dd1 = 0; dd1 < 3; ++dd1){ + tmp[dd0 * 3 + dd1] = rij[idx * nnei * 3 + idy * 3 + dd1] * env_deriv[idx * ndescrpt * 3 + idy * 4 * 3 + idw * 3 + dd0]; + } + } + grad_net[idx * ndescrpt + idy * 4 + idw] -= -1.0 * dev_dot9(grad_one, tmp); +} + +template +__global__ void virial_grad_wrt_neighbors_r( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nnei) +{ + // idy -> nnei + const unsigned int tid = threadIdx.x; + const unsigned int idx = blockIdx.x * blockDim.x + tid; + const unsigned int idy = blockIdx.y; + const int ndescrpt = nnei; + __shared__ FPTYPE grad_one[9]; + if(tid < 9){ + grad_one[tid] = grad[tid]; + } + __syncthreads(); + if (idx >= nloc) { + return; + } + int j_idx = nlist[idx * nnei + idy]; + if (j_idx < 0) { + return; + } + FPTYPE tmp[9]; + for (int dd0 = 0; dd0 < 3; ++dd0){ + for (int dd1 = 0; dd1 < 3; ++dd1){ + tmp[dd0 * 3 + dd1] = rij[idx * nnei * 3 + idy * 3 + dd1] * env_deriv[idx * ndescrpt * 3 + idy * 3 + dd0]; + } + } + grad_net[idx * ndescrpt + idy] -= -1.0 * dev_dot9(grad_one, tmp); +} + +namespace deepmd { +template +void prod_virial_grad_a_gpu_cuda( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nnei) +{ + const int ndescrpt = nnei * 4; + cudaErrcheck(cudaMemset( + grad_net, + 0.0, sizeof(FPTYPE) * nloc * ndescrpt)); + const int LEN = 128; + const int nblock = (nloc + LEN -1) / LEN; + dim3 block_grid(nblock, nnei); + dim3 thread_grid(LEN, 4); + virial_grad_wrt_neighbors_a<<>>( + grad_net, + grad, env_deriv, rij, nlist, nloc, nnei); +} + +template +void prod_virial_grad_r_gpu_cuda( + FPTYPE * grad_net, + const FPTYPE * grad, + const FPTYPE * env_deriv, + const FPTYPE * rij, + const int * nlist, + const int nloc, + const int nnei) +{ + const int ndescrpt = nnei; + cudaErrcheck(cudaMemset( + grad_net, + 0.0, sizeof(FPTYPE) * nloc * ndescrpt)); + const int LEN = 128; + const int nblock = (nloc + LEN -1) / LEN; + dim3 block_grid(nblock, nnei); + dim3 thread_grid(LEN, 1); + virial_grad_wrt_neighbors_r<<>>( + grad_net, + grad, env_deriv, rij, nlist, nloc, nnei); +} + +template void prod_virial_grad_a_gpu_cuda(float * grad_net, const float * grad, const float * env_deriv, const float * rij, const int * nlist, const int nloc, const int nnei); +template void prod_virial_grad_a_gpu_cuda(double * grad_net, const double * grad, const double * env_deriv, const double * rij, const int * nlist, const int nloc, const int nnei); +template void prod_virial_grad_r_gpu_cuda(float * grad_net, const float * grad, const float * env_deriv, const float * rij, const int * nlist, const int nloc, const int nnei); +template void prod_virial_grad_r_gpu_cuda(double * grad_net, const double * grad, const double * env_deriv, const double * rij, const int * nlist, const int nloc, const int nnei); +} \ No newline at end of file diff --git a/source/lib/tests/test_prod_force_grad_a.cc b/source/lib/tests/test_prod_force_grad_a.cc index 82ab484616..e456e2a8dd 100644 --- a/source/lib/tests/test_prod_force_grad_a.cc +++ b/source/lib/tests/test_prod_force_grad_a.cc @@ -4,6 +4,7 @@ #include "env_mat.h" #include "neighbor_list.h" #include "prod_force_grad.h" +#include "device.h" class TestProdForceGradA : public ::testing::Test { @@ -95,3 +96,33 @@ TEST_F(TestProdForceGradA, cpu) // } // printf("\n"); } + +#if GOOGLE_CUDA +TEST_F(TestProdForceGradA, gpu) +{ + std::vector grad_net(nloc * ndescrpt); + int * nlist_dev = NULL; + double * grad_net_dev = NULL, * grad_dev = NULL, * env_deriv_dev = NULL; + + deepmd::malloc_device_memory_sync(nlist_dev, nlist); + deepmd::malloc_device_memory_sync(grad_dev, grad); + deepmd::malloc_device_memory_sync(env_deriv_dev, env_deriv); + deepmd::malloc_device_memory(grad_net_dev, nloc * ndescrpt); + deepmd::prod_force_grad_a_gpu_cuda(grad_net_dev, grad_dev, env_deriv_dev, nlist_dev, nloc, nnei); + deepmd::memcpy_device_to_host(grad_net_dev, grad_net); + deepmd::delete_device_memory(nlist_dev); + deepmd::delete_device_memory(grad_dev); + deepmd::delete_device_memory(env_deriv_dev); + deepmd::delete_device_memory(grad_net_dev); + + EXPECT_EQ(grad_net.size(), nloc * ndescrpt); + EXPECT_EQ(grad_net.size(), expected_grad_net.size()); + for (int jj = 0; jj < grad_net.size(); ++jj){ + EXPECT_LT(fabs(grad_net[jj] - expected_grad_net[jj]) , 1e-5); + } + // for (int jj = 0; jj < nloc * ndescrpt; ++jj){ + // printf("%8.5f, ", grad_net[jj]); + // } + // printf("\n"); +} +#endif // GOOGLE_CUDA diff --git a/source/lib/tests/test_prod_force_grad_r.cc b/source/lib/tests/test_prod_force_grad_r.cc index 37534db7f8..da4ac96d3b 100644 --- a/source/lib/tests/test_prod_force_grad_r.cc +++ b/source/lib/tests/test_prod_force_grad_r.cc @@ -4,6 +4,7 @@ #include "env_mat.h" #include "neighbor_list.h" #include "prod_force_grad.h" +#include "device.h" class TestProdForceGradR : public ::testing::Test { @@ -95,3 +96,33 @@ TEST_F(TestProdForceGradR, cpu) // } // printf("\n"); } + +#if GOOGLE_CUDA +TEST_F(TestProdForceGradR, gpu) +{ + std::vector grad_net(nloc * ndescrpt); + int * nlist_dev = NULL; + double * grad_net_dev = NULL, * grad_dev = NULL, * env_deriv_dev = NULL; + + deepmd::malloc_device_memory_sync(nlist_dev, nlist); + deepmd::malloc_device_memory_sync(grad_dev, grad); + deepmd::malloc_device_memory_sync(env_deriv_dev, env_deriv); + deepmd::malloc_device_memory(grad_net_dev, nloc * ndescrpt); + deepmd::prod_force_grad_r_gpu_cuda(grad_net_dev, grad_dev, env_deriv_dev, nlist_dev, nloc, nnei); + deepmd::memcpy_device_to_host(grad_net_dev, grad_net); + deepmd::delete_device_memory(nlist_dev); + deepmd::delete_device_memory(grad_dev); + deepmd::delete_device_memory(env_deriv_dev); + deepmd::delete_device_memory(grad_net_dev); + + EXPECT_EQ(grad_net.size(), nloc * ndescrpt); + EXPECT_EQ(grad_net.size(), expected_grad_net.size()); + for (int jj = 0; jj < grad_net.size(); ++jj){ + EXPECT_LT(fabs(grad_net[jj] - expected_grad_net[jj]) , 1e-5); + } + // for (int jj = 0; jj < nloc * ndescrpt; ++jj){ + // printf("%8.5f, ", grad_net[jj]); + // } + // printf("\n"); +} +#endif // GOOGLE_CUDA diff --git a/source/lib/tests/test_prod_virial_a.cc b/source/lib/tests/test_prod_virial_a.cc index 4cade7c771..f63fc00fb5 100644 --- a/source/lib/tests/test_prod_virial_a.cc +++ b/source/lib/tests/test_prod_virial_a.cc @@ -141,13 +141,12 @@ TEST_F(TestProdVirialA, gpu_cuda) deepmd::delete_device_memory(env_deriv_dev); deepmd::delete_device_memory(rij_dev); // virial are not calculated in gpu currently; - for (int ii = 0; ii < 9; ii++) { - virial[ii] = 0; - } - for (int ii = 0; ii < nall * 9; ii++) { - virial[ii % 9] += atom_virial[ii]; - } - + // for (int ii = 0; ii < 9; ii++) { + // virial[ii] = 0; + // } + // for (int ii = 0; ii < nall * 9; ii++) { + // virial[ii % 9] += atom_virial[ii]; + // } EXPECT_EQ(virial.size(), 9); EXPECT_EQ(virial.size(), expected_virial.size()); EXPECT_EQ(atom_virial.size(), nall * 9); diff --git a/source/lib/tests/test_prod_virial_grad_a.cc b/source/lib/tests/test_prod_virial_grad_a.cc index 53ad63e965..461552c5a3 100644 --- a/source/lib/tests/test_prod_virial_grad_a.cc +++ b/source/lib/tests/test_prod_virial_grad_a.cc @@ -4,6 +4,7 @@ #include "env_mat.h" #include "neighbor_list.h" #include "prod_virial_grad.h" +#include "device.h" class TestProdVirialGradA : public ::testing::Test { @@ -99,3 +100,36 @@ TEST_F(TestProdVirialGradA, cpu) // } // printf("\n"); } + +#if GOOGLE_CUDA +TEST_F(TestProdVirialGradA, gpu) +{ + std::vector grad_net(nloc * ndescrpt); + int n_a_sel = nnei; + int * nlist_dev = NULL; + double * grad_net_dev = NULL, * grad_dev = NULL, * env_deriv_dev = NULL, * rij_dev = NULL; + + deepmd::malloc_device_memory_sync(nlist_dev, nlist); + deepmd::malloc_device_memory_sync(grad_dev, grad); + deepmd::malloc_device_memory_sync(env_deriv_dev, env_deriv); + deepmd::malloc_device_memory_sync(rij_dev, rij); + deepmd::malloc_device_memory(grad_net_dev, nloc * ndescrpt); + deepmd::prod_virial_grad_a_gpu_cuda(grad_net_dev, grad_dev, env_deriv_dev, rij_dev, nlist_dev, nloc, nnei); + deepmd::memcpy_device_to_host(grad_net_dev, grad_net); + deepmd::delete_device_memory(nlist_dev); + deepmd::delete_device_memory(grad_dev); + deepmd::delete_device_memory(env_deriv_dev); + deepmd::delete_device_memory(rij_dev); + deepmd::delete_device_memory(grad_net_dev); + + EXPECT_EQ(grad_net.size(), nloc * ndescrpt); + EXPECT_EQ(grad_net.size(), expected_grad_net.size()); + for (int jj = 0; jj < grad_net.size(); ++jj){ + EXPECT_LT(fabs(grad_net[jj] - expected_grad_net[jj]) , 1e-5); + } + // for (int jj = 0; jj < nloc * ndescrpt; ++jj){ + // printf("%8.5f, ", grad_net[jj]); + // } + // printf("\n"); +} +#endif // GOOGLE_CUDA \ No newline at end of file diff --git a/source/lib/tests/test_prod_virial_grad_r.cc b/source/lib/tests/test_prod_virial_grad_r.cc index 2cb0c91038..3f12599232 100644 --- a/source/lib/tests/test_prod_virial_grad_r.cc +++ b/source/lib/tests/test_prod_virial_grad_r.cc @@ -4,6 +4,7 @@ #include "env_mat.h" #include "neighbor_list.h" #include "prod_virial_grad.h" +#include "device.h" class TestProdVirialGradR : public ::testing::Test { @@ -99,3 +100,36 @@ TEST_F(TestProdVirialGradR, cpu) // } // printf("\n"); } + +#if GOOGLE_CUDA +TEST_F(TestProdVirialGradR, gpu) +{ + std::vector grad_net(nloc * ndescrpt); + int n_a_sel = nnei; + int * nlist_dev = NULL; + double * grad_net_dev = NULL, * grad_dev = NULL, * env_deriv_dev = NULL, * rij_dev = NULL; + + deepmd::malloc_device_memory_sync(nlist_dev, nlist); + deepmd::malloc_device_memory_sync(grad_dev, grad); + deepmd::malloc_device_memory_sync(env_deriv_dev, env_deriv); + deepmd::malloc_device_memory_sync(rij_dev, rij); + deepmd::malloc_device_memory(grad_net_dev, nloc * ndescrpt); + deepmd::prod_virial_grad_r_gpu_cuda(grad_net_dev, grad_dev, env_deriv_dev, rij_dev, nlist_dev, nloc, nnei); + deepmd::memcpy_device_to_host(grad_net_dev, grad_net); + deepmd::delete_device_memory(nlist_dev); + deepmd::delete_device_memory(grad_dev); + deepmd::delete_device_memory(env_deriv_dev); + deepmd::delete_device_memory(rij_dev); + deepmd::delete_device_memory(grad_net_dev); + + EXPECT_EQ(grad_net.size(), nloc * ndescrpt); + EXPECT_EQ(grad_net.size(), expected_grad_net.size()); + for (int jj = 0; jj < grad_net.size(); ++jj){ + EXPECT_LT(fabs(grad_net[jj] - expected_grad_net[jj]) , 1e-5); + } + // for (int jj = 0; jj < nloc * ndescrpt; ++jj){ + // printf("%8.5f, ", grad_net[jj]); + // } + // printf("\n"); +} +#endif // GOOGLE_CUDA diff --git a/source/lib/tests/test_prod_virial_r.cc b/source/lib/tests/test_prod_virial_r.cc index b321454b8e..be7e865962 100644 --- a/source/lib/tests/test_prod_virial_r.cc +++ b/source/lib/tests/test_prod_virial_r.cc @@ -141,13 +141,12 @@ TEST_F(TestProdVirialR, gpu_cuda) deepmd::delete_device_memory(env_deriv_dev); deepmd::delete_device_memory(rij_dev); // virial are not calculated in gpu currently; - for (int ii = 0; ii < 9; ii++) { - virial[ii] = 0; - } - for (int ii = 0; ii < nall * 9; ii++) { - virial[ii % 9] += atom_virial[ii]; - } - + // for (int ii = 0; ii < 9; ii++) { + // virial[ii] = 0; + // } + // for (int ii = 0; ii < nall * 9; ii++) { + // virial[ii % 9] += atom_virial[ii]; + // } EXPECT_EQ(virial.size(), 9); EXPECT_EQ(virial.size(), expected_virial.size()); EXPECT_EQ(atom_virial.size(), nall * 9); diff --git a/source/op/CMakeLists.txt b/source/op/CMakeLists.txt index 8ec98461be..c3dc7b6815 100644 --- a/source/op/CMakeLists.txt +++ b/source/op/CMakeLists.txt @@ -5,7 +5,7 @@ set(OP_LIB ${PROJECT_SOURCE_DIR}/lib/src/SimulationRegion.cpp ${PROJECT_SOURCE_D set (OP_CXX_FLAG -D_GLIBCXX_USE_CXX11_ABI=${OP_CXX_ABI} ) file(GLOB OP_SRC prod_force.cc prod_virial.cc descrpt.cc descrpt_se_a_ef.cc descrpt_se_a_ef.cc descrpt_se_a_ef_para.cc descrpt_se_a_ef_vert.cc pair_tab.cc prod_force_multi_device.cc prod_virial_multi_device.cc soft_min.cc soft_min_force.cc soft_min_virial.cc ewald_recp.cc gelu_multi_device.cc map_aparam.cc neighbor_stat.cc unaggregated_grad.cc tabulate_multi_device.cc prod_env_mat_multi_device.cc) file(GLOB OP_CUDA_SRC prod_force.cc prod_virial.cc descrpt.cc prod_env_mat_multi_device.cc pair_tab.cc prod_force_multi_device.cc prod_virial_multi_device.cc soft_min.cc soft_min_force.cc soft_min_virial.cc gelu_multi_device.cc tabulate_multi_device.cc) -file(GLOB OP_GRADS_SRC prod_force_grad.cc prod_force_se_a_grad.cc prod_force_se_r_grad.cc prod_virial_grad.cc prod_virial_se_a_grad.cc prod_virial_se_r_grad.cc soft_min_force_grad.cc soft_min_virial_grad.cc ) +file(GLOB OP_GRADS_SRC prod_force_grad.cc prod_force_grad_multi_device.cc prod_virial_grad.cc prod_virial_grad_multi_device.cc soft_min_force_grad.cc soft_min_virial_grad.cc ) file(GLOB OP_PY *.py) if (BUILD_CPP_IF) diff --git a/source/op/prod_force_grad_multi_device.cc b/source/op/prod_force_grad_multi_device.cc new file mode 100644 index 0000000000..1bda63903b --- /dev/null +++ b/source/op/prod_force_grad_multi_device.cc @@ -0,0 +1,251 @@ +#include "custom_op.h" +#include "prod_force_grad.h" + +REGISTER_OP("ProdForceSeAGrad") + .Attr("T: {float, double}") + .Input("grad: T") + .Input("net_deriv: T") + .Input("in_deriv: T") + .Input("nlist: int32") + .Input("natoms: int32") + .Attr("n_a_sel: int") + .Attr("n_r_sel: int") + .Output("grad_net: T"); + +REGISTER_OP("ProdForceSeRGrad") + .Attr("T: {float, double}") + .Input("grad: T") + .Input("net_deriv: T") + .Input("in_deriv: T") + .Input("nlist: int32") + .Input("natoms: int32") + .Output("grad_net: T"); + +template +class ProdForceSeAGradOp : public OpKernel { +public: + explicit ProdForceSeAGradOp(OpKernelConstruction* context) : OpKernel(context) { + OP_REQUIRES_OK(context, context->GetAttr("n_a_sel", &n_a_sel)); + OP_REQUIRES_OK(context, context->GetAttr("n_r_sel", &n_r_sel)); + n_a_shift = n_a_sel * 4; + } + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& grad_tensor = context->input(context_input_index++); + const Tensor& net_deriv_tensor = context->input(context_input_index++); + const Tensor& in_deriv_tensor = context->input(context_input_index++); + const Tensor& nlist_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); + + // set size of the sample + TensorShape grad_shape = grad_tensor.shape(); + TensorShape net_deriv_shape = net_deriv_tensor.shape(); + TensorShape in_deriv_shape = in_deriv_tensor.shape(); + TensorShape nlist_shape = nlist_tensor.shape(); + + OP_REQUIRES (context, (grad_shape.dims() == 2), errors::InvalidArgument ("Dim of grad should be 2")); + OP_REQUIRES (context, (net_deriv_shape.dims() == 2),errors::InvalidArgument ("Dim of net deriv should be 2")); + OP_REQUIRES (context, (in_deriv_shape.dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); + OP_REQUIRES (context, (nlist_shape.dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + auto natoms = natoms_tensor .flat(); + + int nframes = net_deriv_tensor.shape().dim_size(0); + int nloc = natoms(0); + int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; + int nnei = nlist_tensor.shape().dim_size(1) / nloc; + + // check the sizes + OP_REQUIRES (context, (nframes == grad_shape.dim_size(0)), errors::InvalidArgument ("number of frames should match")); + OP_REQUIRES (context, (nframes == in_deriv_shape.dim_size(0)), errors::InvalidArgument ("number of frames should match")); + OP_REQUIRES (context, (nframes == nlist_shape.dim_size(0)), errors::InvalidArgument ("number of frames should match")); + + OP_REQUIRES (context, (nloc * 3 == grad_shape.dim_size(1)), errors::InvalidArgument ("input grad shape should be 3 x natoms")); + OP_REQUIRES (context, (nloc * ndescrpt * 3 == in_deriv_shape.dim_size(1)),errors::InvalidArgument ("number of descriptors should match")); + OP_REQUIRES (context, (nnei == n_a_sel + n_r_sel), errors::InvalidArgument ("number of neighbors should match")); + + // Create an output tensor + TensorShape grad_net_shape ; + grad_net_shape.AddDim (nframes); + grad_net_shape.AddDim (nloc * ndescrpt); + + // allocate the output tensor + Tensor* grad_net_tensor = NULL; + int context_output_index = 0; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + grad_net_shape, + &grad_net_tensor)); + DeviceFunctor() ( + device, + context->eigen_device() + ); + assert (nframes == grad_net_shape.dim_size(0)); + assert (nframes == grad_shape.dim_size(0)); + assert (nframes == net_deriv_tensor.shape().dim_size(0)); + assert (nframes == in_deriv_tensor.shape().dim_size(0)); + assert (nframes == nlist_tensor.shape().dim_size(0)); + assert (nloc * ndescrpt == grad_net_shape.dim_size(1)); + assert (nloc * 3 == grad_shape.dim_size(1)); + assert (nloc * ndescrpt == net_deriv_tensor.shape().dim_size(1)); + assert (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)); + assert (nloc * nnei == nlist_tensor.shape().dim_size(1)); + assert (nnei * 4 == ndescrpt); + // flat the tensors + FPTYPE * p_grad_net = grad_net_tensor->flat().data(); + const FPTYPE * p_grad = grad_tensor.flat().data(); + const FPTYPE * p_net_deriv = net_deriv_tensor.flat().data(); + const FPTYPE * p_in_deriv = in_deriv_tensor.flat().data(); + const int * p_nlist = nlist_tensor.flat().data(); + + for (int kk = 0; kk < nframes; ++kk){ + FPTYPE * grad_net = p_grad_net + kk * nloc * ndescrpt; + const FPTYPE * grad = p_grad + kk * nloc * 3; + const FPTYPE * in_deriv = p_in_deriv + kk * nloc * ndescrpt * 3; + const int * nlist = p_nlist + kk * nloc * nnei; + if (device == "GPU") { + #if GOOGLE_CUDA + deepmd::prod_force_grad_a_gpu_cuda( + grad_net, + grad, in_deriv, nlist, nloc, nnei); + #endif // GOOGLE_CUDA + } + else if (device == "CPU") { + deepmd::prod_force_grad_a_cpu( + grad_net, + grad, in_deriv, nlist, nloc, nnei); + } + } + } +private: + std::string device; + int n_r_sel, n_a_sel, n_a_shift; +}; + +template +class ProdForceSeRGradOp : public OpKernel +{ +public: + explicit ProdForceSeRGradOp(OpKernelConstruction* context) : OpKernel(context) {} + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& grad_tensor = context->input(context_input_index++); + const Tensor& net_deriv_tensor = context->input(context_input_index++); + const Tensor& in_deriv_tensor = context->input(context_input_index++); + const Tensor& nlist_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); + + // set size of the sample + TensorShape grad_shape = grad_tensor.shape(); + TensorShape net_deriv_shape = net_deriv_tensor.shape(); + TensorShape in_deriv_shape = in_deriv_tensor.shape(); + TensorShape nlist_shape = nlist_tensor.shape(); + + OP_REQUIRES (context, (grad_shape.dims() == 2), errors::InvalidArgument ("Dim of grad should be 2")); + OP_REQUIRES (context, (net_deriv_shape.dims() == 2),errors::InvalidArgument ("Dim of net deriv should be 2")); + OP_REQUIRES (context, (in_deriv_shape.dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); + OP_REQUIRES (context, (nlist_shape.dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + auto natoms = natoms_tensor .flat(); + + int nframes = net_deriv_tensor.shape().dim_size(0); + int nloc = natoms(0); + int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; + int nnei = nlist_tensor.shape().dim_size(1) / nloc; + + // check the sizes + OP_REQUIRES (context, (nframes == grad_shape.dim_size(0)), errors::InvalidArgument ("number of frames should match")); + OP_REQUIRES (context, (nframes == in_deriv_shape.dim_size(0)), errors::InvalidArgument ("number of frames should match")); + OP_REQUIRES (context, (nframes == nlist_shape.dim_size(0)), errors::InvalidArgument ("number of frames should match")); + + OP_REQUIRES (context, (nloc * 3 == grad_shape.dim_size(1)), errors::InvalidArgument ("input grad shape should be 3 x natoms")); + OP_REQUIRES (context, (nloc * ndescrpt * 3 == in_deriv_shape.dim_size(1)),errors::InvalidArgument ("number of descriptors should match")); + + // Create an output tensor + TensorShape grad_net_shape ; + grad_net_shape.AddDim (nframes); + grad_net_shape.AddDim (nloc * ndescrpt); + + // allocate the output tensor + Tensor* grad_net_tensor = NULL; + int context_output_index = 0; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + grad_net_shape, + &grad_net_tensor)); + DeviceFunctor() ( + device, + context->eigen_device() + ); + assert (nframes == grad_net_shape.dim_size(0)); + assert (nframes == grad_shape.dim_size(0)); + assert (nframes == net_deriv_tensor.shape().dim_size(0)); + assert (nframes == in_deriv_tensor.shape().dim_size(0)); + assert (nframes == nlist_tensor.shape().dim_size(0)); + assert (nloc * ndescrpt == grad_net_shape.dim_size(1)); + assert (nloc * 3 == grad_shape.dim_size(1)); + assert (nloc * ndescrpt == net_deriv_tensor.shape().dim_size(1)); + assert (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)); + assert (nloc * nnei == nlist_tensor.shape().dim_size(1)); + assert (nnei * 1 == ndescrpt); + // flat the tensors + FPTYPE * p_grad_net = grad_net_tensor->flat().data(); + const FPTYPE * p_grad = grad_tensor.flat().data(); + const FPTYPE * p_net_deriv = net_deriv_tensor.flat().data(); + const FPTYPE * p_in_deriv = in_deriv_tensor.flat().data(); + const int * p_nlist = nlist_tensor.flat().data(); + + // loop over frames + for (int kk = 0; kk < nframes; ++kk){ + FPTYPE * grad_net = p_grad_net + kk * nloc * ndescrpt; + const FPTYPE * grad = p_grad + kk * nloc * 3; + const FPTYPE * in_deriv = p_in_deriv + kk * nloc * ndescrpt * 3; + const int * nlist = p_nlist + kk * nloc * nnei; + if (device == "GPU") { + #if GOOGLE_CUDA + deepmd::prod_force_grad_r_gpu_cuda( + grad_net, + grad, in_deriv, nlist, nloc, nnei); + #endif // GOOGLE_CUDA + } + else if (device == "CPU") { + deepmd::prod_force_grad_r_cpu( + grad_net, + grad, in_deriv, nlist, nloc, nnei); + } + } + } + private: + std::string device; +}; + +// Register the CPU kernels. +#define REGISTER_CPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdForceSeAGrad").Device(DEVICE_CPU).TypeConstraint("T"), \ + ProdForceSeAGradOp); \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdForceSeRGrad").Device(DEVICE_CPU).TypeConstraint("T"), \ + ProdForceSeRGradOp); +REGISTER_CPU(float); +REGISTER_CPU(double); +// Register the GPU kernels. +#if GOOGLE_CUDA +#define REGISTER_GPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdForceSeAGrad").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ + ProdForceSeAGradOp); \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdForceSeRGrad").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ + ProdForceSeRGradOp); +REGISTER_GPU(float); +REGISTER_GPU(double); +#endif // GOOGLE_CUDA \ No newline at end of file diff --git a/source/op/prod_virial_grad_multi_device.cc b/source/op/prod_virial_grad_multi_device.cc new file mode 100644 index 0000000000..ac74d1d141 --- /dev/null +++ b/source/op/prod_virial_grad_multi_device.cc @@ -0,0 +1,275 @@ +#include "custom_op.h" +#include "prod_virial_grad.h" + +REGISTER_OP("ProdVirialSeAGrad") + .Attr("T: {float, double}") + .Input("grad: T") + .Input("net_deriv: T") + .Input("in_deriv: T") + .Input("rij: T") + .Input("nlist: int32") + .Input("natoms: int32") + .Attr("n_a_sel: int") + .Attr("n_r_sel: int") + .Output("grad_net: T"); + +REGISTER_OP("ProdVirialSeRGrad") + .Attr("T: {float, double}") + .Input("grad: T") + .Input("net_deriv: T") + .Input("in_deriv: T") + .Input("rij: T") + .Input("nlist: int32") + .Input("natoms: int32") + .Output("grad_net: T"); + +template +class ProdVirialSeAGradOp : public OpKernel +{ +public: + explicit ProdVirialSeAGradOp(OpKernelConstruction* context) : OpKernel(context) { + OP_REQUIRES_OK(context, context->GetAttr("n_a_sel", &n_a_sel)); + OP_REQUIRES_OK(context, context->GetAttr("n_r_sel", &n_r_sel)); + n_a_shift = n_a_sel * 4; + } + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& grad_tensor = context->input(context_input_index++); + const Tensor& net_deriv_tensor = context->input(context_input_index++); + const Tensor& in_deriv_tensor = context->input(context_input_index++); + const Tensor& rij_tensor = context->input(context_input_index++); + const Tensor& nlist_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); + + // set size of the sample + TensorShape grad_shape = grad_tensor.shape(); + TensorShape net_deriv_shape = net_deriv_tensor.shape(); + TensorShape in_deriv_shape = in_deriv_tensor.shape(); + TensorShape rij_shape = rij_tensor.shape(); + TensorShape nlist_shape = nlist_tensor.shape(); + + OP_REQUIRES (context, (grad_shape.dims() == 2), errors::InvalidArgument ("Dim of grad should be 2")); + OP_REQUIRES (context, (net_deriv_shape.dims() == 2),errors::InvalidArgument ("Dim of net deriv should be 2")); + OP_REQUIRES (context, (in_deriv_shape.dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); + OP_REQUIRES (context, (rij_shape.dims() == 2), errors::InvalidArgument ("Dim of rij should be 2")); + OP_REQUIRES (context, (nlist_shape.dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + auto natoms = natoms_tensor .flat(); + + int nframes = net_deriv_tensor.shape().dim_size(0); + int nloc = natoms(0); + int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; + int nnei = nlist_tensor.shape().dim_size(1) / nloc; + + // check the sizes + OP_REQUIRES (context, (nframes == grad_shape.dim_size(0)), errors::InvalidArgument ("number of frames should match")); + OP_REQUIRES (context, (nframes == in_deriv_shape.dim_size(0)), errors::InvalidArgument ("number of frames should match")); + OP_REQUIRES (context, (nframes == rij_shape.dim_size(0)), errors::InvalidArgument ("number of frames should match")); + OP_REQUIRES (context, (nframes == nlist_shape.dim_size(0)), errors::InvalidArgument ("number of frames should match")); + + OP_REQUIRES (context, (9 == grad_shape.dim_size(1)), errors::InvalidArgument ("input grad shape should be 3 x natoms")); + OP_REQUIRES (context, (nloc * ndescrpt * 3 == in_deriv_shape.dim_size(1)),errors::InvalidArgument ("number of descriptors should match")); + OP_REQUIRES (context, (nloc * nnei * 3 == rij_shape.dim_size(1)), errors::InvalidArgument ("dim of rij should be nnei * 3")); + OP_REQUIRES (context, (nnei == n_a_sel + n_r_sel), errors::InvalidArgument ("number of neighbors should match")); + + // Create an output tensor + TensorShape grad_net_shape ; + grad_net_shape.AddDim (nframes); + grad_net_shape.AddDim (nloc * ndescrpt); + + // allocate the output tensor + Tensor* grad_net_tensor = NULL; + int context_output_index = 0; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + grad_net_shape, + &grad_net_tensor)); + DeviceFunctor() ( + device, + context->eigen_device() + ); + assert (nframes == grad_net_shape.dim_size(0)); + assert (nframes == grad_shape.dim_size(0)); + assert (nframes == net_deriv_tensor.shape().dim_size(0)); + assert (nframes == in_deriv_tensor.shape().dim_size(0)); + assert (nframes == rij_tensor.shape().dim_size(0)); + assert (nframes == nlist_tensor.shape().dim_size(0)); + assert (nloc * ndescrpt == grad_net_shape.dim_size(1)); + assert (9 == grad_shape.dim_size(1)); + assert (nloc * ndescrpt == net_deriv_tensor.shape().dim_size(1)); + assert (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)); + assert (nloc * nnei * 3 == rij_tensor.shape().dim_size(1)); + assert (nloc * nnei == nlist_tensor.shape().dim_size(1)); + assert (nnei * 4 == ndescrpt); + + // flat the tensors + FPTYPE * p_grad_net = grad_net_tensor->flat().data(); + const FPTYPE * p_grad = grad_tensor.flat().data(); + const FPTYPE * p_net_deriv = net_deriv_tensor.flat().data(); + const FPTYPE * p_in_deriv = in_deriv_tensor.flat().data(); + const FPTYPE * p_rij = rij_tensor.flat().data(); + const int * p_nlist = nlist_tensor.flat().data(); + + // loop over frames + for (int kk = 0; kk < nframes; ++kk){ + FPTYPE * grad_net = p_grad_net + kk * nloc * ndescrpt; + const FPTYPE * grad = p_grad + kk * nloc * 3; + const FPTYPE * in_deriv = p_in_deriv + kk * nloc * ndescrpt * 3; + const FPTYPE * rij = p_rij + kk * nloc * nnei * 3; + const int * nlist = p_nlist + kk * nloc * nnei; + if (device == "GPU") { + #if GOOGLE_CUDA + deepmd::prod_virial_grad_a_gpu_cuda( + grad_net, + grad, in_deriv, rij, nlist, nloc, nnei); + #endif // GOOGLE_CUDA + } + else if (device == "CPU") { + deepmd::prod_virial_grad_a_cpu( + grad_net, + grad, in_deriv, rij, nlist, nloc, nnei); + } + } + } +private: + std::string device; + int n_r_sel, n_a_sel, n_a_shift; +}; + +template +class ProdVirialSeRGradOp : public OpKernel +{ +public: + explicit ProdVirialSeRGradOp(OpKernelConstruction* context) : OpKernel(context) {} + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + int context_input_index = 0; + const Tensor& grad_tensor = context->input(context_input_index++); + const Tensor& net_deriv_tensor = context->input(context_input_index++); + const Tensor& in_deriv_tensor = context->input(context_input_index++); + const Tensor& rij_tensor = context->input(context_input_index++); + const Tensor& nlist_tensor = context->input(context_input_index++); + const Tensor& natoms_tensor = context->input(context_input_index++); + + // set size of the sample + TensorShape grad_shape = grad_tensor.shape(); + TensorShape net_deriv_shape = net_deriv_tensor.shape(); + TensorShape in_deriv_shape = in_deriv_tensor.shape(); + TensorShape rij_shape = rij_tensor.shape(); + TensorShape nlist_shape = nlist_tensor.shape(); + + OP_REQUIRES (context, (grad_shape.dims() == 2), errors::InvalidArgument ("Dim of grad should be 2")); + OP_REQUIRES (context, (net_deriv_shape.dims() == 2),errors::InvalidArgument ("Dim of net deriv should be 2")); + OP_REQUIRES (context, (in_deriv_shape.dims() == 2), errors::InvalidArgument ("Dim of input deriv should be 2")); + OP_REQUIRES (context, (rij_shape.dims() == 2), errors::InvalidArgument ("Dim of rij should be 2")); + OP_REQUIRES (context, (nlist_shape.dims() == 2), errors::InvalidArgument ("Dim of nlist should be 2")); + OP_REQUIRES (context, (natoms_tensor.shape().dims() == 1), errors::InvalidArgument ("Dim of natoms should be 1")); + + OP_REQUIRES (context, (natoms_tensor.shape().dim_size(0) >= 3), errors::InvalidArgument ("number of atoms should be larger than (or equal to) 3")); + auto natoms = natoms_tensor .flat(); + + int nframes = net_deriv_tensor.shape().dim_size(0); + int nloc = natoms(0); + int ndescrpt = net_deriv_tensor.shape().dim_size(1) / nloc; + int nnei = nlist_tensor.shape().dim_size(1) / nloc; + + // check the sizes + OP_REQUIRES (context, (nframes == grad_shape.dim_size(0)), errors::InvalidArgument ("number of frames should match")); + OP_REQUIRES (context, (nframes == in_deriv_shape.dim_size(0)), errors::InvalidArgument ("number of frames should match")); + OP_REQUIRES (context, (nframes == rij_shape.dim_size(0)), errors::InvalidArgument ("number of frames should match")); + OP_REQUIRES (context, (nframes == nlist_shape.dim_size(0)), errors::InvalidArgument ("number of frames should match")); + + OP_REQUIRES (context, (9 == grad_shape.dim_size(1)), errors::InvalidArgument ("input grad shape should be 3 x natoms")); + OP_REQUIRES (context, (nloc * ndescrpt * 3 == in_deriv_shape.dim_size(1)),errors::InvalidArgument ("number of descriptors should match")); + OP_REQUIRES (context, (nloc * nnei * 3 == rij_shape.dim_size(1)), errors::InvalidArgument ("dim of rij should be nnei * 3")); + + // Create an output tensor + TensorShape grad_net_shape ; + grad_net_shape.AddDim (nframes); + grad_net_shape.AddDim (nloc * ndescrpt); + + // allocate the output tensor + Tensor* grad_net_tensor = NULL; + int context_output_index = 0; + OP_REQUIRES_OK(context, context->allocate_output( + context_output_index++, + grad_net_shape, + &grad_net_tensor)); + DeviceFunctor() ( + device, + context->eigen_device() + ); + assert (nframes == grad_net_shape.dim_size(0)); + assert (nframes == grad_shape.dim_size(0)); + assert (nframes == net_deriv_tensor.shape().dim_size(0)); + assert (nframes == in_deriv_tensor.shape().dim_size(0)); + assert (nframes == rij_tensor.shape().dim_size(0)); + assert (nframes == nlist_tensor.shape().dim_size(0)); + assert (nloc * ndescrpt == grad_net_shape.dim_size(1)); + assert (9 == grad_shape.dim_size(1)); + assert (nloc * ndescrpt == net_deriv_tensor.shape().dim_size(1)); + assert (nloc * ndescrpt * 3 == in_deriv_tensor.shape().dim_size(1)); + assert (nloc * nnei * 3 == rij_tensor.shape().dim_size(1)); + assert (nloc * nnei == nlist_tensor.shape().dim_size(1)); + assert (nnei * 1 == ndescrpt); + + // flat the tensors + FPTYPE * p_grad_net = grad_net_tensor->flat().data(); + const FPTYPE * p_grad = grad_tensor.flat().data(); + const FPTYPE * p_net_deriv = net_deriv_tensor.flat().data(); + const FPTYPE * p_in_deriv = in_deriv_tensor.flat().data(); + const FPTYPE * p_rij = rij_tensor.flat().data(); + const int * p_nlist = nlist_tensor.flat().data(); + + // loop over frames + for (int kk = 0; kk < nframes; ++kk){ + FPTYPE * grad_net = p_grad_net + kk * nloc * ndescrpt; + const FPTYPE * grad = p_grad + kk * nloc * 3; + const FPTYPE * in_deriv = p_in_deriv + kk * nloc * ndescrpt * 3; + const FPTYPE * rij = p_rij + kk * nloc * nnei * 3; + const int * nlist = p_nlist + kk * nloc * nnei; + if (device == "GPU") { + #if GOOGLE_CUDA + deepmd::prod_virial_grad_r_gpu_cuda( + grad_net, + grad, in_deriv, rij, nlist, nloc, nnei); + #endif // GOOGLE_CUDA + } + else if (device == "CPU") { + deepmd::prod_virial_grad_r_cpu( + grad_net, + grad, in_deriv, rij, nlist, nloc, nnei); + } + } + } +private: + std::string device; +}; + +// Register the CPU kernels. +#define REGISTER_CPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdVirialSeAGrad").Device(DEVICE_CPU).TypeConstraint("T"), \ + ProdVirialSeAGradOp); \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdVirialSeRGrad").Device(DEVICE_CPU).TypeConstraint("T"), \ + ProdVirialSeRGradOp); +REGISTER_CPU(float); +REGISTER_CPU(double); +// Register the GPU kernels. +#if GOOGLE_CUDA +#define REGISTER_GPU(T) \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdVirialSeAGrad").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ + ProdVirialSeAGradOp); \ +REGISTER_KERNEL_BUILDER( \ + Name("ProdVirialSeRGrad").Device(DEVICE_GPU).TypeConstraint("T").HostMemory("natoms"), \ + ProdVirialSeRGradOp); +REGISTER_GPU(float); +REGISTER_GPU(double); +#endif // GOOGLE_CUDA \ No newline at end of file From 5ac571d2663f13907058723b25349fd82d724771 Mon Sep 17 00:00:00 2001 From: Duo Date: Thu, 8 Apr 2021 14:40:49 +0800 Subject: [PATCH 333/562] fix bug in prod_env_mat.cu --- source/lib/src/cuda/prod_env_mat.cu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/lib/src/cuda/prod_env_mat.cu b/source/lib/src/cuda/prod_env_mat.cu index fcc1aa970d..68573991bb 100644 --- a/source/lib/src/cuda/prod_env_mat.cu +++ b/source/lib/src/cuda/prod_env_mat.cu @@ -114,7 +114,7 @@ __global__ void format_nlist_fill_a( } FPTYPE rr = sqrt(dev_dot(diff, diff)); if (rr <= rcut) { - key_in[idy] = type[j_idx] * 1E15+ (int_64)(rr * 1.0E13) / 10000000 * 10000000 + j_idx; + key_in[idy] = type[j_idx] * 1E14+ (int_64)(rr * 1.0E12) / 10000000 * 10000000 + j_idx; } } From 0cc22bc698f5d192cd53885621571936f5ad9f8f Mon Sep 17 00:00:00 2001 From: Duo Date: Thu, 8 Apr 2021 16:22:55 +0800 Subject: [PATCH 334/562] fix bug in prod_env_mat.cu --- source/lib/src/cuda/prod_env_mat.cu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/lib/src/cuda/prod_env_mat.cu b/source/lib/src/cuda/prod_env_mat.cu index 68573991bb..807b2c37de 100644 --- a/source/lib/src/cuda/prod_env_mat.cu +++ b/source/lib/src/cuda/prod_env_mat.cu @@ -142,7 +142,7 @@ __global__ void format_nlist_fill_b( } for (unsigned int kk = 0; key_out[kk] != key_out[max_nbor_size - 1]; kk++) { - const int & nei_type = key_out[kk] / 1E15; + const int & nei_type = key_out[kk] / 1E14; if (nei_iter[nei_type] < sec[nei_type + 1]) { row_nlist[nei_iter[nei_type]++] = key_out[kk] % 10000000; } From 2ac43ebf2d2a7c8e5029583f44d81335e59cba7e Mon Sep 17 00:00:00 2001 From: YWolfeee <1800017704@pku.edu.cn> Date: Fri, 9 Apr 2021 22:14:58 +0800 Subject: [PATCH 335/562] update dipole training and test: support combination of glocal and atomic dipole --- deepmd/entrypoints/main.py | 4 +- deepmd/entrypoints/test.py | 22 ++++-- deepmd/loss/tensor.py | 133 ++++++++++++++++++++++++++++++++----- 3 files changed, 136 insertions(+), 23 deletions(-) diff --git a/deepmd/entrypoints/main.py b/deepmd/entrypoints/main.py index bf88a9a1e6..e5d291e7dc 100644 --- a/deepmd/entrypoints/main.py +++ b/deepmd/entrypoints/main.py @@ -232,10 +232,10 @@ def parse_args(args: Optional[List[str]] = None): ) parser_tst.add_argument( "-a", - "--atomic-energy", + "--atomic", action="store_true", default=False, - help="Test the accuracy of atomic energy", + help="Test the accuracy of atomic label, i.e. energy / dipole / polar", ) # * compress model ***************************************************************** diff --git a/deepmd/entrypoints/test.py b/deepmd/entrypoints/test.py index 5c91547866..8cbca7c974 100644 --- a/deepmd/entrypoints/test.py +++ b/deepmd/entrypoints/test.py @@ -26,7 +26,7 @@ def test( rand_seed: Optional[int], shuffle_test: bool, detail_file: str, - atomic_energy: bool, + atomic: bool, **kwargs, ): """Test model predictions. @@ -47,7 +47,7 @@ def test( whether to shuffle tests detail_file : Optional[str] file where test details will be output - atomic_energy : bool + atomic : bool whether per atom quantities should be computed Raises @@ -83,11 +83,11 @@ def test( system, numb_test, detail_file, - atomic_energy, + atomic, append_detail=(cc != 0), ) elif dp.model_type == "dipole": - err, siz = test_dipole(dp, data, numb_test, detail_file) + err, siz = test_dipole(dp, data, numb_test, detail_file, atomic) elif dp.model_type == "polar": err, siz = test_polar(dp, data, numb_test, detail_file, global_polar=False) elif dp.model_type == "global_polar": @@ -550,6 +550,7 @@ def test_dipole( data: DeepmdData, numb_test: int, detail_file: Optional[str], + has_atom_dipole: bool, ) -> Tuple[List[np.ndarray], List[int]]: """Test energy type model. @@ -563,6 +564,8 @@ def test_dipole( munber of tests to do detail_file : Optional[str] file where test details will be output + has_atom_dipole : bool + whether atomic dipole is provided Returns ------- @@ -570,12 +573,21 @@ def test_dipole( arrays with results and their shapes """ data.add( - "dipole", 3, atomic=True, must=True, high_prec=False, type_sel=dp.get_sel_type() + "dipole", 3, atomic=has_atom_dipole, must=True, high_prec=False, type_sel=dp.get_sel_type() ) test_data = data.get_test() dipole, numb_test, _ = run_test(dp, test_data, numb_test) + + # do summation in atom dimension + if has_atom_dipole == False: + atoms = dipole.shape[1] + dipole = np.sum(dipole,axis=1) + l2f = l2err(dipole - test_data["dipole"][:numb_test]) + if has_atom_dipole == False: + l2f = l2f / atoms + log.info(f"# number of test data : {numb_test:d}") log.info(f"Dipole RMSE : {l2f:e} eV/A") diff --git a/deepmd/loss/tensor.py b/deepmd/loss/tensor.py index ceff94e14b..9ec366abdc 100644 --- a/deepmd/loss/tensor.py +++ b/deepmd/loss/tensor.py @@ -12,24 +12,60 @@ class TensorLoss () : def __init__ (self, jdata, **kwarg) : try: model = kwarg['model'] - type_sel = model.get_sel_type() + self.type_sel = model.get_sel_type() except : - type_sel = None + self.type_sel = None self.tensor_name = kwarg['tensor_name'] self.tensor_size = kwarg['tensor_size'] self.label_name = kwarg['label_name'] - self.atomic = kwarg.get('atomic', True) + self.atomic = kwarg.get('atomic', None) if jdata is not None: self.scale = jdata.get('scale', 1.0) else: self.scale = 1.0 + + # YHT: added for global / local dipole combination + if self.atomic is True: # upper regulation, will control the lower behavior + self.local_weight,self.global_weight = 1.0,0.0 + elif self.atomic is False: # upper regulation, will control the lower behavior + self.local_weight,self.global_weight = 0.0,1.0 + else: # self.atomic is None, let the loss parameter decide which mode to use + if jdata is not None: + self.local_weight = jdata.get('atomic_' + self.tensor_name,None) + self.global_weight = jdata.get(self.tensor_name,None) + + # get the input parameter first + if self.local_weight is None and self.global_weight is None: + # default: downward compatibility, using local mode + self.local_weight , self.global_weight = 1.0, 0.0 + self.atomic = True + elif self.local_weight is None and self.global_weight is not None: + # using global mode only, normalize to 1 + assert self.global_weight > 0.0, AssertionError('assign a zero weight to global dipole without setting a local weight') + self.local_weight,self.global_weight=0.0,1.0 + self.atomic = False + elif self.local_weight is not None and self.global_weight is None: + assert self.local_weight > 0.0, AssertionError('assign a zero weight to local dipole without setting a global weight') + self.local_weight,self.global_weight = 1.0,0.0 + self.atomic = True + else: # Both are not None + self.atomic = True if self.local_weight != 0.0 else False + assert (self.local_weight >0.0) or (self.global_weight>0.0), AssertionError('can not assian zero weight to both local and global mode') + # normalize + temp_sum = self.local_weight + self.global_weight + self.local_weight /= temp_sum + self.global_weight /= temp_sum + else: # Nothing been set, use default setting + self.local_weight,self.global_weight = 1.0,0.0 + self.atomic = True + # data required add_data_requirement(self.label_name, self.tensor_size, atomic=self.atomic, must=True, high_prec=False, - type_sel = type_sel) + type_sel = self.type_sel) def build (self, learning_rate, @@ -39,22 +75,69 @@ def build (self, suffix): polar_hat = label_dict[self.label_name] polar = model_dict[self.tensor_name] - l2_loss = tf.reduce_mean( tf.square(self.scale*(polar - polar_hat)), name='l2_'+suffix) - more_loss = {'nonorm': l2_loss} - if not self.atomic : - atom_norm = 1./ global_cvt_2_tf_float(natoms[0]) - l2_loss = l2_loss * atom_norm + + # YHT: added for global / local dipole combination + l2_loss = global_cvt_2_tf_float(0.0) + more_loss = { + "local_loss":global_cvt_2_tf_float(0.0), + "global_loss":global_cvt_2_tf_float(0.0) + } + + + if self.local_weight > 0.0: + local_loss = tf.reduce_mean( tf.square(self.scale*(polar - polar_hat)), name='l2_'+suffix) + more_loss['local_loss'] = local_loss + l2_loss += self.local_weight * local_loss + + + if self.global_weight > 0.0: # Need global loss + atoms = 0 + if self.type_sel is not None: + for w in self.type_sel: + atoms += natoms[2+w] + else: + atoms = natoms[0] + nframes = tf.shape(polar)[0] // self.tensor_size // atoms + # get global results + global_polar = tf.reshape(tf.reduce_sum(tf.reshape( + polar, [nframes, -1, self.tensor_size]), axis=1),[-1]) + if self.atomic: # If label is local, however + global_polar_hat = tf.reshape(tf.reduce_sum(tf.reshape( + polar_hat, [nframes, -1, self.tensor_size]), axis=1),[-1]) + else: + global_polar_hat = polar_hat + + global_loss = tf.reduce_mean( tf.square(self.scale*(global_polar - global_polar_hat)), name='l2_'+suffix) + + more_loss['global_loss'] = global_loss + + # YHT: should only consider atoms with dipole, i.e. atoms + # atom_norm = 1./ global_cvt_2_tf_float(natoms[0]) + atom_norm = 1./ global_cvt_2_tf_float(atoms) + global_loss *= atom_norm + + l2_loss += self.global_weight * global_loss + + self.l2_more = more_loss self.l2_l = l2_loss - self.l2_more = more_loss['nonorm'] self.l2_loss_summary = tf.summary.scalar('l2_loss', tf.sqrt(l2_loss)) + if self.local_weight > 0.0: + self.l2_loss_local_summary = tf.summary.scalar('l2_local_loss', + tf.sqrt(more_loss['local_loss']) / atoms) + if self.global_weight > 0.0: + self.l2_loss_global_summary = tf.summary.scalar('l2_global_loss', + tf.sqrt(more_loss['global_loss']) / atoms) return l2_loss, more_loss - @staticmethod - def print_header(): + def print_header(self): prop_fmt = ' %11s %11s' print_str = '' print_str += prop_fmt % ('rmse_tst', 'rmse_trn') + if self.local_weight > 0.0: + print_str += prop_fmt % ('rmse_lc_tst', 'rmse_lc_trn') + if self.global_weight > 0.0: + print_str += prop_fmt % ('rmse_gl_tst', 'rmse_gl_trn') return print_str def print_on_training(self, @@ -65,7 +148,20 @@ def print_on_training(self, feed_dict_test, feed_dict_batch) : - run_data = [self.l2_l] + # YHT: added to calculate the atoms number + atoms = 0 + if self.type_sel is not None: + for w in self.type_sel: + atoms += natoms[2+w] + else: + atoms = natoms[0] + + run_data = [self.l2_l, self.l2_more['local_loss'], self.l2_more['global_loss']] + summary_list = [self.l2_loss_summary] + if self.local_weight > 0.0: + summary_list.append(self.l2_loss_local_summary) + if self.global_weight > 0.0: + summary_list.append(self.l2_loss_global_summary) # first train data error_train = sess.run(run_data, feed_dict=feed_dict_batch) @@ -73,7 +169,8 @@ def print_on_training(self, # than test data, if tensorboard log writter is present, commpute summary # and write tensorboard logs if tb_writer: - summary_merged_op = tf.summary.merge([self.l2_loss_summary]) + #summary_merged_op = tf.summary.merge([self.l2_loss_summary]) + summary_merged_op = tf.summary.merge(summary_list) run_data.insert(0, summary_merged_op) test_out = sess.run(run_data, feed_dict=feed_dict_test) @@ -82,10 +179,14 @@ def print_on_training(self, summary = test_out.pop(0) tb_writer.add_summary(summary, cur_batch) - error_test = test_out[0] + error_test = test_out print_str = "" prop_fmt = " %11.2e %11.2e" - print_str += prop_fmt % (np.sqrt(error_test), np.sqrt(error_train)) + print_str += prop_fmt % (np.sqrt(error_test[0]), np.sqrt(error_train[0])) + if self.local_weight > 0.0: + print_str += prop_fmt % (np.sqrt(error_test[1]), np.sqrt(error_train[1]) ) + if self.global_weight > 0.0: + print_str += prop_fmt % (np.sqrt(error_test[2])/atoms, np.sqrt(error_train[2])/atoms) return print_str From a579b0d4b801df5d2a98bc183759b22a4cfb682b Mon Sep 17 00:00:00 2001 From: YWolfeee <1800017704@pku.edu.cn> Date: Fri, 9 Apr 2021 15:02:04 +0000 Subject: [PATCH 336/562] final check of updated dipole mode, few modification --- deepmd/entrypoints/test.py | 1 + deepmd/loss/tensor.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/deepmd/entrypoints/test.py b/deepmd/entrypoints/test.py index 8cbca7c974..62687866a8 100644 --- a/deepmd/entrypoints/test.py +++ b/deepmd/entrypoints/test.py @@ -580,6 +580,7 @@ def test_dipole( # do summation in atom dimension if has_atom_dipole == False: + dipole = np.reshape(dipole,(dipole.shape[0], -1, 3)) atoms = dipole.shape[1] dipole = np.sum(dipole,axis=1) diff --git a/deepmd/loss/tensor.py b/deepmd/loss/tensor.py index 9ec366abdc..7b77dd0556 100644 --- a/deepmd/loss/tensor.py +++ b/deepmd/loss/tensor.py @@ -124,10 +124,10 @@ def build (self, self.l2_loss_summary = tf.summary.scalar('l2_loss', tf.sqrt(l2_loss)) if self.local_weight > 0.0: self.l2_loss_local_summary = tf.summary.scalar('l2_local_loss', - tf.sqrt(more_loss['local_loss']) / atoms) + tf.sqrt(more_loss['local_loss']) / global_cvt_2_tf_float(atoms)) if self.global_weight > 0.0: self.l2_loss_global_summary = tf.summary.scalar('l2_global_loss', - tf.sqrt(more_loss['global_loss']) / atoms) + tf.sqrt(more_loss['global_loss']) / global_cvt_2_tf_float(atoms)) return l2_loss, more_loss def print_header(self): From bac3462d5759253bd891a38a41f84f7213f14d96 Mon Sep 17 00:00:00 2001 From: YWolfeee <1800017704@pku.edu.cn> Date: Fri, 9 Apr 2021 15:26:25 +0000 Subject: [PATCH 337/562] few modifaction, compatile with polar mode --- deepmd/loss/tensor.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/deepmd/loss/tensor.py b/deepmd/loss/tensor.py index 7b77dd0556..255a249a3d 100644 --- a/deepmd/loss/tensor.py +++ b/deepmd/loss/tensor.py @@ -88,6 +88,8 @@ def build (self, local_loss = tf.reduce_mean( tf.square(self.scale*(polar - polar_hat)), name='l2_'+suffix) more_loss['local_loss'] = local_loss l2_loss += self.local_weight * local_loss + self.l2_loss_local_summary = tf.summary.scalar('l2_local_loss', + tf.sqrt(more_loss['local_loss'])) if self.global_weight > 0.0: # Need global loss @@ -110,6 +112,8 @@ def build (self, global_loss = tf.reduce_mean( tf.square(self.scale*(global_polar - global_polar_hat)), name='l2_'+suffix) more_loss['global_loss'] = global_loss + self.l2_loss_global_summary = tf.summary.scalar('l2_global_loss', + tf.sqrt(more_loss['global_loss']) / global_cvt_2_tf_float(atoms)) # YHT: should only consider atoms with dipole, i.e. atoms # atom_norm = 1./ global_cvt_2_tf_float(natoms[0]) @@ -122,12 +126,6 @@ def build (self, self.l2_l = l2_loss self.l2_loss_summary = tf.summary.scalar('l2_loss', tf.sqrt(l2_loss)) - if self.local_weight > 0.0: - self.l2_loss_local_summary = tf.summary.scalar('l2_local_loss', - tf.sqrt(more_loss['local_loss']) / global_cvt_2_tf_float(atoms)) - if self.global_weight > 0.0: - self.l2_loss_global_summary = tf.summary.scalar('l2_global_loss', - tf.sqrt(more_loss['global_loss']) / global_cvt_2_tf_float(atoms)) return l2_loss, more_loss def print_header(self): From 056853cd0ecaff9df8a7a8122b941d7498e72145 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 9 Apr 2021 23:59:09 +0800 Subject: [PATCH 338/562] add options `sys_probs` and `auto_prob_style`, fix bug in sys_probs --- deepmd/utils/argcheck.py | 10 +++++- deepmd/utils/data_system.py | 17 +++++----- doc/train-input-auto.rst | 62 ++++++++++++++++++++++++++----------- 3 files changed, 63 insertions(+), 26 deletions(-) diff --git a/deepmd/utils/argcheck.py b/deepmd/utils/argcheck.py index ac993ef107..0170ea8bae 100644 --- a/deepmd/utils/argcheck.py +++ b/deepmd/utils/argcheck.py @@ -379,9 +379,17 @@ def training_args(): doc_time_training = 'Timing durining training.' doc_profiling = 'Profiling during training.' doc_profiling_file = 'Output file for profiling.' + doc_train_auto_prob_style = 'Determine the probability of systems automatically. The method is assigned by this key and can be\n\n\ +- "prob_uniform" : the probability all the systems are equal, namely 1.0/self.get_nsystems()\n\n\ +- "prob_sys_size" : the probability of a system is proportional to the number of batches in the system\n\n\ +- "prob_sys_size;stt_idx:end_idx:weight;stt_idx:end_idx:weight;..." : \n\n\ + the list of systems is devided into blocks. A block is specified by `stt_idx:end_idx:weight`, where `stt_idx` is the starting index of the system, `end_idx` is then ending (not including) index of the system, the probabilities of the systems in this block sums up to `weight`, and the relatively probabilities within this block is proportional to the number of batches in the system.' + doc_train_sys_probs = "A list of float, should be of the same length as `train_systems`, specifying the probability of each system." args = [ - Argument("systems", [list,str], optional = False, doc = doc_systems), + Argument("systems", [list,str], optional = False, doc = doc_systems, alias = ["train_systems"]), + Argument("auto_prob_style", str, optional = True, default = "prob_sys_size", doc = doc_train_auto_prob_style, alias = ["train_auto_prob_style"]), + Argument("sys_probs", list, optional = True, default = None, doc = doc_train_sys_probs, alias = ["train_sys_probs"]), Argument("set_prefix", str, optional = True, default = 'set', doc = doc_set_prefix), Argument("stop_batch", int, optional = False, doc = doc_stop_batch), Argument("batch_size", [list,int,str], optional = True, default = 'auto', doc = doc_batch_size), diff --git a/deepmd/utils/data_system.py b/deepmd/utils/data_system.py index 557a2c6bd0..b4efa7b255 100644 --- a/deepmd/utils/data_system.py +++ b/deepmd/utils/data_system.py @@ -273,9 +273,9 @@ def _get_sys_probs(self, def get_batch (self, - sys_idx = None, - sys_probs = None, - auto_prob_style = "prob_sys_size") : + sys_idx : int = None, + sys_probs : List[float] = None, + auto_prob_style : str = "prob_sys_size") : """ Get a batch of data from the data systems @@ -289,7 +289,7 @@ def get_batch (self, The probabilitis of systems to get the batch. Summation of positive elements of this list should be no greater than 1. Element of this list can be negative, the probability of the corresponding system is determined automatically by the number of batches in the system. - auto_prob_style: float + auto_prob_style: str Determine the probability of systems automatically. The method is assigned by this key and can be - "prob_uniform" : the probability all the systems are equal, namely 1.0/self.get_nsystems() - "prob_sys_size" : the probability of a system is proportional to the number of batches in the system @@ -459,9 +459,12 @@ def _process_sys_probs(self, sys_probs) : assigned_sum_prob = np.sum(type_filter * sys_probs) assert assigned_sum_prob <= 1, "the sum of assigned probability should be less than 1" rest_sum_prob = 1. - assigned_sum_prob - rest_nbatch = (1 - type_filter) * self.nbatches - rest_prob = rest_sum_prob * rest_nbatch / np.sum(rest_nbatch) - ret_prob = rest_prob + type_filter * sys_probs + if rest_sum_prob != 0 : + rest_nbatch = (1 - type_filter) * self.nbatches + rest_prob = rest_sum_prob * rest_nbatch / np.sum(rest_nbatch) + ret_prob = rest_prob + type_filter * sys_probs + else : + ret_prob = sys_probs assert np.sum(ret_prob) == 1, "sum of probs should be 1" return ret_prob diff --git a/doc/train-input-auto.rst b/doc/train-input-auto.rst index aa85750cbc..ae1af27d22 100644 --- a/doc/train-input-auto.rst +++ b/doc/train-input-auto.rst @@ -23,6 +23,15 @@ model: The model determines the normalization from the statistics of the data. This key specifies the number of `frames` in each `system` used for statistics. + .. raw:: html + + + data_stat_protect: + | type: ``float``, optional, default: ``0.01`` + | argument path: ``model/data_stat_protect`` + + Protect parameter for atomic energy regression. + .. raw:: html @@ -233,7 +242,7 @@ model: | type: ``str``, optional, default: ``float64`` | argument path: ``model/descriptor[se_a]/precision`` - The precision of the embedding net parameters, supported options are "float64", "float32", "float16". + The precision of the embedding net parameters, supported options are "default", "float16", "float32", "float64". .. raw:: html @@ -347,7 +356,7 @@ model: | type: ``str``, optional, default: ``float64`` | argument path: ``model/descriptor[se_r]/precision`` - The precision of the embedding net parameters, supported options are "float64", "float32", "float16". + The precision of the embedding net parameters, supported options are "default", "float16", "float32", "float64". .. raw:: html @@ -452,7 +461,7 @@ model: | type: ``str``, optional, default: ``float64`` | argument path: ``model/descriptor[se_a_3be]/precision`` - The precision of the embedding net parameters, supported options are "float64", "float32", "float16". + The precision of the embedding net parameters, supported options are "default", "float16", "float32", "float64". .. raw:: html @@ -472,15 +481,6 @@ model: Random seed for parameter initialization - .. raw:: html - - - exclude_types: - | type: ``list``, optional, default: ``[]`` - | argument path: ``model/descriptor[se_a_3be]/exclude_types`` - - The Excluded types - .. raw:: html @@ -575,7 +575,7 @@ model: | type: ``str``, optional, default: ``float64`` | argument path: ``model/descriptor[se_a_tpe]/precision`` - The precision of the embedding net parameters, supported options are "float64", "float32", "float16". + The precision of the embedding net parameters, supported options are "default", "float16", "float32", "float64". .. raw:: html @@ -757,7 +757,7 @@ model: | type: ``str``, optional, default: ``float64`` | argument path: ``model/fitting_net[ener]/precision`` - The precision of the fitting net parameters, supported options are "float64", "float32", "float16". + The precision of the fitting net parameters, supported options are "default", "float16", "float32", "float64". .. raw:: html @@ -848,7 +848,7 @@ model: | type: ``str``, optional, default: ``float64`` | argument path: ``model/fitting_net[dipole]/precision`` - The precision of the fitting net parameters, supported options are "float64", "float32", "float16". + The precision of the fitting net parameters, supported options are "default", "float16", "float32", "float64". .. raw:: html @@ -908,7 +908,7 @@ model: | type: ``str``, optional, default: ``float64`` | argument path: ``model/fitting_net[polar]/precision`` - The precision of the fitting net parameters, supported options are "float64", "float32", "float16". + The precision of the fitting net parameters, supported options are "default", "float16", "float32", "float64". .. raw:: html @@ -995,7 +995,7 @@ model: | type: ``str``, optional, default: ``float64`` | argument path: ``model/fitting_net[global_polar]/precision`` - The precision of the fitting net parameters, supported options are "float64", "float32", "float16". + The precision of the fitting net parameters, supported options are "default", "float16", "float32", "float64". .. raw:: html @@ -1047,7 +1047,7 @@ model: loss: - | type: ``dict`` + | type: ``dict``, optional | argument path: ``loss`` The definition of loss function. The type of the loss depends on the type of the fitting. For fitting type `ener`, the prefactors before energy, force, virial and atomic energy losses may be provided. For fitting type `dipole`, `polar` and `global_polar`, the loss may be an empty `dict` or unset. @@ -1208,6 +1208,32 @@ training: The data systems. This key can be provided with a listthat specifies the systems, or be provided with a string by which the prefix of all systems are given and the list of the systems is automatically generated. + .. raw:: html + + + auto_prob_style: + | type: ``str``, optional, default: ``prob_sys_size`` + | argument path: ``training/auto_prob_style`` + + Determine the probability of systems automatically. The method is assigned by this key and can be + + - "prob_uniform" : the probability all the systems are equal, namely 1.0/self.get_nsystems() + + - "prob_sys_size" : the probability of a system is proportional to the number of batches in the system + + - "prob_sys_size;stt_idx:end_idx:weight;stt_idx:end_idx:weight;..." : + + the list of systems is devided into blocks. A block is specified by `stt_idx:end_idx:weight`, where `stt_idx` is the starting index of the system, `end_idx` is then ending (not including) index of the system, the probabilities of the systems in this block sums up to `weight`, and the relatively probabilities within this block is proportional to the number of batches in the system. + + .. raw:: html + + + sys_probs: + | type: ``NoneType`` | ``list``, optional, default: ``None`` + | argument path: ``training/sys_probs`` + + A list of float, should be of the same length as `train_systems`, specifying the probability of each system. + .. raw:: html From e23945a9b2f4e3de64b3f8bead3eaa515d8de017 Mon Sep 17 00:00:00 2001 From: YWolfeee <1800017704@pku.edu.cn> Date: Sat, 10 Apr 2021 05:34:26 +0000 Subject: [PATCH 339/562] ut test debug: change input argument atomic-energy to atomic --- source/tests/test_argument_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/tests/test_argument_parser.py b/source/tests/test_argument_parser.py index 356dd430c1..a7e42ad81e 100644 --- a/source/tests/test_argument_parser.py +++ b/source/tests/test_argument_parser.py @@ -262,7 +262,7 @@ def test_parser_test(self): "--numb-test": dict(type=int, value=1), "--rand-seed": dict(type=(int, type(None)), value=12321), "--detail-file": dict(type=(str, type(None)), value="TARGET.FILE"), - "--atomic-energy": dict(type=bool), + "--atomic": dict(type=bool), } self.run_test(command="test", mapping=ARGS) From c45918315b404779b8b7054a40970bec75b031cd Mon Sep 17 00:00:00 2001 From: YWolfeee <1800017704@pku.edu.cn> Date: Mon, 12 Apr 2021 11:03:35 +0000 Subject: [PATCH 340/562] PR debug: take Han Wang's advice, not to change the value of weight; change the name of the weight to pref_dipole and pref_atomic_dipole --- deepmd/loss/tensor.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/deepmd/loss/tensor.py b/deepmd/loss/tensor.py index 255a249a3d..addccdcadf 100644 --- a/deepmd/loss/tensor.py +++ b/deepmd/loss/tensor.py @@ -31,8 +31,8 @@ def __init__ (self, jdata, **kwarg) : self.local_weight,self.global_weight = 0.0,1.0 else: # self.atomic is None, let the loss parameter decide which mode to use if jdata is not None: - self.local_weight = jdata.get('atomic_' + self.tensor_name,None) - self.global_weight = jdata.get(self.tensor_name,None) + self.local_weight = jdata.get('pref_atomic_' + self.tensor_name,None) + self.global_weight = jdata.get('pref_' + self.tensor_name,None) # get the input parameter first if self.local_weight is None and self.global_weight is None: @@ -42,19 +42,21 @@ def __init__ (self, jdata, **kwarg) : elif self.local_weight is None and self.global_weight is not None: # using global mode only, normalize to 1 assert self.global_weight > 0.0, AssertionError('assign a zero weight to global dipole without setting a local weight') - self.local_weight,self.global_weight=0.0,1.0 + self.local_weight = 0.0 self.atomic = False elif self.local_weight is not None and self.global_weight is None: assert self.local_weight > 0.0, AssertionError('assign a zero weight to local dipole without setting a global weight') - self.local_weight,self.global_weight = 1.0,0.0 + self.global_weight = 0.0 self.atomic = True else: # Both are not None self.atomic = True if self.local_weight != 0.0 else False assert (self.local_weight >0.0) or (self.global_weight>0.0), AssertionError('can not assian zero weight to both local and global mode') - # normalize - temp_sum = self.local_weight + self.global_weight - self.local_weight /= temp_sum - self.global_weight /= temp_sum + + # normalize, not do according to Han Wang's suggestion + #temp_sum = self.local_weight + self.global_weight + #self.local_weight /= temp_sum + #self.global_weight /= temp_sum + else: # Nothing been set, use default setting self.local_weight,self.global_weight = 1.0,0.0 self.atomic = True From 6b7c2dbc55942d9268ea9893b4726acf1e370dad Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 13 Apr 2021 07:38:23 +0800 Subject: [PATCH 341/562] training on all sets in the training data systems. strict argcheck. --- deepmd/entrypoints/train.py | 6 +- deepmd/train/trainer.py | 4 +- deepmd/utils/argcheck.py | 57 ++++++++++++------- deepmd/utils/data.py | 14 +++-- deepmd/utils/data_system.py | 17 ++++-- doc/train-input-auto.rst | 106 ++++++++++++++++++++++++------------ requirements.txt | 4 +- 7 files changed, 136 insertions(+), 72 deletions(-) diff --git a/deepmd/entrypoints/train.py b/deepmd/entrypoints/train.py index 685815db17..62391c861c 100755 --- a/deepmd/entrypoints/train.py +++ b/deepmd/entrypoints/train.py @@ -253,9 +253,9 @@ def _do_work(jdata: Dict[str, Any], run_opt: RunOptions): # get batch sizes batch_size = j_must_have(jdata["training"], "batch_size") test_size = j_must_have(jdata["training"], "numb_test") - stop_batch = j_must_have(jdata["training"], "stop_batch") + stop_batch = j_must_have(jdata["training"], "numb_steps") sys_probs = jdata["training"].get("sys_probs") - auto_prob_style = jdata["training"].get("auto_prob_style", "prob_sys_size") + auto_prob = jdata["training"].get("auto_prob", "prob_sys_size") # setup data modifier modifier: Optional[DipoleChargeModifier] @@ -284,7 +284,7 @@ def _do_work(jdata: Dict[str, Any], run_opt: RunOptions): type_map=ipt_type_map, modifier=modifier, ) - data.print_summary(run_opt, sys_probs=sys_probs, auto_prob_style=auto_prob_style) + data.print_summary(run_opt, sys_probs=sys_probs, auto_prob_style=auto_prob) data.add_dict(data_requirement) # build the model with stats from the first system diff --git a/deepmd/train/trainer.py b/deepmd/train/trainer.py index 1ea177fd95..1ae50e1e89 100644 --- a/deepmd/train/trainer.py +++ b/deepmd/train/trainer.py @@ -251,7 +251,7 @@ def _init_param(self, jdata): .add('tensorboard', bool, default = False)\ .add('tensorboard_log_dir',str, default = 'log')\ .add('sys_probs', list )\ - .add('auto_prob_style', str, default = "prob_sys_size") + .add('auto_prob', str, default = "prob_sys_size") tr_data = tr_args.parse(training_param) # not needed # self.numb_test = tr_data['numb_test'] @@ -266,7 +266,7 @@ def _init_param(self, jdata): self.tensorboard = tr_data['tensorboard'] self.tensorboard_log_dir = tr_data['tensorboard_log_dir'] self.sys_probs = tr_data['sys_probs'] - self.auto_prob_style = tr_data['auto_prob_style'] + self.auto_prob_style = tr_data['auto_prob'] self.useBN = False if fitting_type == 'ener' and self.fitting.get_numb_fparam() > 0 : self.numb_fparam = self.fitting.get_numb_fparam() diff --git a/deepmd/utils/argcheck.py b/deepmd/utils/argcheck.py index 0170ea8bae..310090adfd 100644 --- a/deepmd/utils/argcheck.py +++ b/deepmd/utils/argcheck.py @@ -299,7 +299,7 @@ def model_args (): return ca -def learning_rate_args(): +def learning_rate_exp(): doc_start_lr = 'The learning rate the start of the training.' doc_stop_lr = 'The desired learning rate at the end of the training.' doc_decay_steps = 'The learning rate is decaying every this number of training steps.' @@ -309,9 +309,24 @@ def learning_rate_args(): Argument("stop_lr", float, optional = True, default = 1e-8, doc = doc_stop_lr), Argument("decay_steps", int, optional = True, default = 5000, doc = doc_decay_steps) ] + return args + + +def learning_rate_variant_type_args(): + doc_lr = 'The type of the learning rate. Current type `exp`, the exponentially decaying learning rate is supported.' + + return Variant("type", + [Argument("exp", dict, learning_rate_exp())], + optional = True, + default_tag = 'exp', + doc = doc_lr) - doc_lr = "The learning rate options" - return Argument("learning_rate", dict, args, [], doc = doc_lr) + +def learning_rate_args(): + doc_lr = "The definitio of learning rate" + return Argument("learning_rate", dict, [], + [learning_rate_variant_type_args()], + doc = doc_lr) def start_pref(item): @@ -361,15 +376,16 @@ def loss_args(): return ca def training_args(): + link_sys = make_link("systems", "training/systems") doc_systems = 'The data systems. This key can be provided with a listthat specifies the systems, or be provided with a string by which the prefix of all systems are given and the list of the systems is automatically generated.' - doc_set_prefix = 'The prefix of the sets in the systems.' + doc_set_prefix = f'The prefix of the sets in the {link_sys}.' doc_stop_batch = 'Number of training batch. Each training uses one batch of data.' - doc_batch_size = 'This key can be \n\n\ -- list: the length of which is the same as the `systems`. The batch size of each system is given by the elements of the list.\n\n\ -- int: all `systems` uses the same batch size.\n\n\ -- string "auto": automatically determines the batch size os that the batch_size times the number of atoms in the system is no less than 32.\n\n\ -- string "auto:N": automatically determines the batch size os that the batch_size times the number of atoms in the system is no less than N.' - doc_seed = 'The random seed for training.' + doc_batch_size = f'This key can be \n\n\ +- list: the length of which is the same as the {link_sys}. The batch size of each system is given by the elements of the list.\n\n\ +- int: all {link_sys} use the same batch size.\n\n\ +- string "auto": automatically determines the batch size so that the batch_size times the number of atoms in the system is no less than 32.\n\n\ +- string "auto:N": automatically determines the batch size so that the batch_size times the number of atoms in the system is no less than N.' + doc_seed = 'The random seed for getting frames from the training data set.' doc_disp_file = 'The file for printing learning curve.' doc_disp_freq = 'The frequency of printing learning curve.' doc_numb_test = 'Number of frames used for the test during training.' @@ -382,17 +398,18 @@ def training_args(): doc_train_auto_prob_style = 'Determine the probability of systems automatically. The method is assigned by this key and can be\n\n\ - "prob_uniform" : the probability all the systems are equal, namely 1.0/self.get_nsystems()\n\n\ - "prob_sys_size" : the probability of a system is proportional to the number of batches in the system\n\n\ -- "prob_sys_size;stt_idx:end_idx:weight;stt_idx:end_idx:weight;..." : \n\n\ - the list of systems is devided into blocks. A block is specified by `stt_idx:end_idx:weight`, where `stt_idx` is the starting index of the system, `end_idx` is then ending (not including) index of the system, the probabilities of the systems in this block sums up to `weight`, and the relatively probabilities within this block is proportional to the number of batches in the system.' +- "prob_sys_size;stt_idx:end_idx:weight;stt_idx:end_idx:weight;..." : the list of systems is devided into blocks. A block is specified by `stt_idx:end_idx:weight`, where `stt_idx` is the starting index of the system, `end_idx` is then ending (not including) index of the system, the probabilities of the systems in this block sums up to `weight`, and the relatively probabilities within this block is proportional to the number of batches in the system.' doc_train_sys_probs = "A list of float, should be of the same length as `train_systems`, specifying the probability of each system." + doc_tensorboard = 'Enable tensorboard' + doc_tensorboard_log_dir = 'The log directory of tensorboard outputs' args = [ - Argument("systems", [list,str], optional = False, doc = doc_systems, alias = ["train_systems"]), - Argument("auto_prob_style", str, optional = True, default = "prob_sys_size", doc = doc_train_auto_prob_style, alias = ["train_auto_prob_style"]), - Argument("sys_probs", list, optional = True, default = None, doc = doc_train_sys_probs, alias = ["train_sys_probs"]), + Argument("systems", [list,str], optional = False, doc = doc_systems, alias = ["trn_systems"]), Argument("set_prefix", str, optional = True, default = 'set', doc = doc_set_prefix), - Argument("stop_batch", int, optional = False, doc = doc_stop_batch), - Argument("batch_size", [list,int,str], optional = True, default = 'auto', doc = doc_batch_size), + Argument("auto_prob", str, optional = True, default = "prob_sys_size", doc = doc_train_auto_prob_style, alias = ["trn_auto_prob", "auto_prob_style"]), + Argument("sys_probs", list, optional = True, default = None, doc = doc_train_sys_probs, alias = ["trn_sys_probs"]), + Argument("batch_size", [list,int,str], optional = True, default = 'auto', doc = doc_batch_size, alias = ["trn_batch_size"]), + Argument("numb_steps", int, optional = False, doc = doc_stop_batch, alias = ["stop_batch"]), Argument("seed", [int,None], optional = True, doc = doc_seed), Argument("disp_file", str, optional = True, default = 'lcueve.out', doc = doc_disp_file), Argument("disp_freq", int, optional = True, default = 1000, doc = doc_disp_freq), @@ -402,7 +419,9 @@ def training_args(): Argument("disp_training", bool, optional = True, default = True, doc = doc_disp_training), Argument("time_training", bool, optional = True, default = True, doc = doc_time_training), Argument("profiling", bool, optional = True, default = False, doc = doc_profiling), - Argument("profiling_file", str, optional = True, default = 'timeline.json', doc = doc_profiling_file) + Argument("profiling_file", str, optional = True, default = 'timeline.json', doc = doc_profiling_file), + Argument("tensorboard", bool, optional = True, default = False, doc = doc_tensorboard), + Argument("tensorboard_log_dir", str, optional = True, default = 'log', doc = doc_tensorboard_log_dir), ] doc_training = 'The training options' @@ -443,7 +462,7 @@ def normalize(data): base = Argument("base", dict, [ma, lra, la, ta]) data = base.normalize_value(data, trim_pattern = "_*") - base.check_value(data) + base.check_value(data, strict = True) return data diff --git a/deepmd/utils/data.py b/deepmd/utils/data.py index 4b8edebb2d..b52c6e17c8 100644 --- a/deepmd/utils/data.py +++ b/deepmd/utils/data.py @@ -19,7 +19,8 @@ def __init__ (self, set_prefix : str = 'set', shuffle_test : bool = True, type_map : List[str] = None, - modifier = None) : + modifier = None, + trn_all_set : bool = False) : """ Constructor @@ -35,6 +36,8 @@ def __init__ (self, Gives the name of different atom types modifier Data modifier that has the method `modify_data` + trn_all_set + Use all sets as training dataset. Otherwise, if the number of sets is more than 1, the last set is left for test. """ self.dirs = glob.glob (os.path.join(sys_path, set_prefix + ".*")) self.dirs.sort() @@ -57,10 +60,13 @@ def __init__ (self, self.idx_map = self._make_idx_map(self.atom_type) # train dirs self.test_dir = self.dirs[-1] - if len(self.dirs) == 1 : + if trn_all_set: self.train_dirs = self.dirs - else : - self.train_dirs = self.dirs[:-1] + else: + if len(self.dirs) == 1 : + self.train_dirs = self.dirs + else : + self.train_dirs = self.dirs[:-1] self.data_dict = {} # add box and coord self.add('box', 9, must = True) diff --git a/deepmd/utils/data_system.py b/deepmd/utils/data_system.py index b4efa7b255..bac613f5ec 100644 --- a/deepmd/utils/data_system.py +++ b/deepmd/utils/data_system.py @@ -55,11 +55,15 @@ def __init__ (self, self.nsystems = len(self.system_dirs) self.data_systems = [] for ii in self.system_dirs : - self.data_systems.append(DeepmdData(ii, - set_prefix=set_prefix, - shuffle_test=shuffle_test, - type_map = type_map, - modifier = modifier)) + self.data_systems.append( + DeepmdData( + ii, + set_prefix=set_prefix, + shuffle_test=shuffle_test, + type_map = type_map, + modifier = modifier, + trn_all_set = True + )) # batch size self.batch_size = batch_size if isinstance(self.batch_size, int) : @@ -260,7 +264,8 @@ def _get_sys_probs(self, auto_prob_style) : if sys_probs is None : if auto_prob_style == "prob_uniform" : - prob = None + prob_v = 1./float(self.nsystems) + prob = [prob_v for ii in range(self.nsystems)] elif auto_prob_style == "prob_sys_size" : prob = self.prob_nbatches elif auto_prob_style[:14] == "prob_sys_size;" : diff --git a/doc/train-input-auto.rst b/doc/train-input-auto.rst index ae1af27d22..6da37d5264 100644 --- a/doc/train-input-auto.rst +++ b/doc/train-input-auto.rst @@ -1160,32 +1160,50 @@ learning_rate: | type: ``dict`` | argument path: ``learning_rate`` - The learning rate options + The definitio of learning rate + + + Depending on the value of *type*, different sub args are accepted. .. raw:: html - + + type: + | type: ``str`` (flag key), default: ``exp`` + | argument path: ``learning_rate/type`` + + The type of the learning rate. Current type `exp`, the exponentially decaying learning rate is supported. + + + .. raw:: html + + + When *type* is set to ``exp``: + + .. raw:: html + + start_lr: | type: ``float``, optional, default: ``0.001`` - | argument path: ``learning_rate/start_lr`` + | argument path: ``learning_rate[exp]/start_lr`` The learning rate the start of the training. .. raw:: html - + stop_lr: | type: ``float``, optional, default: ``1e-08`` - | argument path: ``learning_rate/stop_lr`` + | argument path: ``learning_rate[exp]/stop_lr`` The desired learning rate at the end of the training. .. raw:: html - + decay_steps: | type: ``int``, optional, default: ``5000`` - | argument path: ``learning_rate/decay_steps`` + | argument path: ``learning_rate[exp]/decay_steps`` The learning rate is decaying every this number of training steps. @@ -1210,10 +1228,19 @@ training: .. raw:: html - - auto_prob_style: + + set_prefix: + | type: ``str``, optional, default: ``set`` + | argument path: ``training/set_prefix`` + + The prefix of the sets in the `systems <#training/systems>`__. + + .. raw:: html + + + auto_prob: | type: ``str``, optional, default: ``prob_sys_size`` - | argument path: ``training/auto_prob_style`` + | argument path: ``training/auto_prob`` Determine the probability of systems automatically. The method is assigned by this key and can be @@ -1221,9 +1248,7 @@ training: - "prob_sys_size" : the probability of a system is proportional to the number of batches in the system - - "prob_sys_size;stt_idx:end_idx:weight;stt_idx:end_idx:weight;..." : - - the list of systems is devided into blocks. A block is specified by `stt_idx:end_idx:weight`, where `stt_idx` is the starting index of the system, `end_idx` is then ending (not including) index of the system, the probabilities of the systems in this block sums up to `weight`, and the relatively probabilities within this block is proportional to the number of batches in the system. + - "prob_sys_size;stt_idx:end_idx:weight;stt_idx:end_idx:weight;..." : the list of systems is devided into blocks. A block is specified by `stt_idx:end_idx:weight`, where `stt_idx` is the starting index of the system, `end_idx` is then ending (not including) index of the system, the probabilities of the systems in this block sums up to `weight`, and the relatively probabilities within this block is proportional to the number of batches in the system. .. raw:: html @@ -1234,24 +1259,6 @@ training: A list of float, should be of the same length as `train_systems`, specifying the probability of each system. - .. raw:: html - - - set_prefix: - | type: ``str``, optional, default: ``set`` - | argument path: ``training/set_prefix`` - - The prefix of the sets in the systems. - - .. raw:: html - - - stop_batch: - | type: ``int`` - | argument path: ``training/stop_batch`` - - Number of training batch. Each training uses one batch of data. - .. raw:: html @@ -1261,13 +1268,22 @@ training: This key can be - - list: the length of which is the same as the `systems`. The batch size of each system is given by the elements of the list. + - list: the length of which is the same as the `systems <#training/systems>`__. The batch size of each system is given by the elements of the list. - - int: all `systems` uses the same batch size. + - int: all `systems <#training/systems>`__ use the same batch size. - - string "auto": automatically determines the batch size os that the batch_size times the number of atoms in the system is no less than 32. + - string "auto": automatically determines the batch size so that the batch_size times the number of atoms in the system is no less than 32. - - string "auto:N": automatically determines the batch size os that the batch_size times the number of atoms in the system is no less than N. + - string "auto:N": automatically determines the batch size so that the batch_size times the number of atoms in the system is no less than N. + + .. raw:: html + + + numb_steps: + | type: ``int`` + | argument path: ``training/numb_steps`` + + Number of training batch. Each training uses one batch of data. .. raw:: html @@ -1276,7 +1292,7 @@ training: | type: ``int`` | ``NoneType``, optional | argument path: ``training/seed`` - The random seed for training. + The random seed for getting frames from the training data set. .. raw:: html @@ -1359,3 +1375,21 @@ training: Output file for profiling. + .. raw:: html + + + tensorboard: + | type: ``bool``, optional, default: ``False`` + | argument path: ``training/tensorboard`` + + Enable tensorboard + + .. raw:: html + + + tensorboard_log_dir: + | type: ``str``, optional, default: ``log`` + | argument path: ``training/tensorboard_log_dir`` + + The log directory of tensorboard outputs + diff --git a/requirements.txt b/requirements.txt index 3b80afd9c0..c8a81216ab 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ numpy scipy pyyaml -dargs +dargs >= 0.2.0 tqdm -typing_extensions \ No newline at end of file +typing_extensions From 008f10b1869d480d21f9bc74dd24caeb57a72fce Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 13 Apr 2021 08:10:18 +0800 Subject: [PATCH 342/562] set as default training data excludes "test set". --- deepmd/entrypoints/train.py | 1 + deepmd/utils/data_system.py | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/deepmd/entrypoints/train.py b/deepmd/entrypoints/train.py index 62391c861c..790cc227f6 100755 --- a/deepmd/entrypoints/train.py +++ b/deepmd/entrypoints/train.py @@ -283,6 +283,7 @@ def _do_work(jdata: Dict[str, Any], run_opt: RunOptions): set_prefix=set_pfx, type_map=ipt_type_map, modifier=modifier, + trn_all_set = True ) data.print_summary(run_opt, sys_probs=sys_probs, auto_prob_style=auto_prob) data.add_dict(data_requirement) diff --git a/deepmd/utils/data_system.py b/deepmd/utils/data_system.py index bac613f5ec..188366540b 100644 --- a/deepmd/utils/data_system.py +++ b/deepmd/utils/data_system.py @@ -26,7 +26,8 @@ def __init__ (self, set_prefix : str = 'set', shuffle_test : bool = True, type_map : List[str] = None, - modifier = None) : + modifier = None, + trn_all_set = False) : """ Constructor @@ -48,6 +49,8 @@ def __init__ (self, Gives the name of different atom types modifier Data modifier that has the method `modify_data` + trn_all_set + Use all sets as training dataset. Otherwise, if the number of sets is more than 1, the last set is left for test. """ # init data self.rcut = rcut @@ -62,7 +65,7 @@ def __init__ (self, shuffle_test=shuffle_test, type_map = type_map, modifier = modifier, - trn_all_set = True + trn_all_set = trn_all_set )) # batch size self.batch_size = batch_size From 8a5706ef705d1341de52ab05e732240d340af875 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 13 Apr 2021 15:56:06 +0800 Subject: [PATCH 343/562] update the argcheck to use the auto generated ref for variants from dargs --- deepmd/utils/argcheck.py | 16 ++++++++-------- requirements.txt | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/deepmd/utils/argcheck.py b/deepmd/utils/argcheck.py index 310090adfd..661e3ee247 100644 --- a/deepmd/utils/argcheck.py +++ b/deepmd/utils/argcheck.py @@ -164,7 +164,7 @@ def descrpt_variant_type_args(): link_se_a_3be = make_link('se_a_3be', 'model/descriptor[se_a_3be]') link_se_a_tpe = make_link('se_a_tpe', 'model/descriptor[se_a_tpe]') link_hybrid = make_link('hybrid', 'model/descriptor[hybrid]') - doc_descrpt_type = f'The type of the descritpor. Valid types are {link_lf}, {link_se_a}, {link_se_r}, {link_se_a_3be}, {link_se_a_tpe}, {link_hybrid}. \n\n\ + doc_descrpt_type = f'The type of the descritpor. See explanation below. \n\n\ - `loc_frame`: Defines a local frame at each atom, and the compute the descriptor as local coordinates under this frame.\n\n\ - `se_a`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor.\n\n\ - `se_r`: Used by the smooth edition of Deep Potential. Only the distance between atoms is used to construct the descriptor.\n\n\ @@ -258,7 +258,7 @@ def fitting_dipole(): def fitting_variant_type_args(): - doc_descrpt_type = 'The type of the fitting. Valid types are `ener`, `dipole`, `polar` and `global_polar`. \n\n\ + doc_descrpt_type = 'The type of the fitting. See explanation below. \n\n\ - `ener`: Fit an energy model (potential energy surface).\n\n\ - `dipole`: Fit an atomic dipole model. Atomic dipole labels for all the selected atoms (see `sel_type`) should be provided by `dipole.npy` in each data system. The file has number of frames lines and 3 times of number of selected atoms columns.\n\n\ - `polar`: Fit an atomic polarizability model. Atomic polarizability labels for all the selected atoms (see `sel_type`) should be provided by `polarizability.npy` in each data system. The file has number of frames lines and 9 times of number of selected atoms columns.\n\n\ @@ -313,7 +313,7 @@ def learning_rate_exp(): def learning_rate_variant_type_args(): - doc_lr = 'The type of the learning rate. Current type `exp`, the exponentially decaying learning rate is supported.' + doc_lr = 'The type of the learning rate.' return Variant("type", [Argument("exp", dict, learning_rate_exp())], @@ -359,7 +359,7 @@ def loss_ener(): def loss_variant_type_args(): - doc_loss = 'The type of the loss. For fitting type `ener`, the loss type should be set to `ener` or left unset. For tensorial fitting types `dipole`, `polar` and `global_polar`, the type should be left unset.\n\.' + doc_loss = 'The type of the loss. \n\.' return Variant("type", [Argument("ener", dict, loss_ener())], @@ -441,10 +441,10 @@ def gen_doc(**kwargs): la = loss_args() ta = training_args() ptr = [] - ptr.append(ma.gen_doc(**kwargs)) - ptr.append(la.gen_doc(**kwargs)) - ptr.append(lra.gen_doc(**kwargs)) - ptr.append(ta.gen_doc(**kwargs)) + ptr.append(ma.gen_doc(**kwargs, make_link = True)) + ptr.append(la.gen_doc(**kwargs, make_link = True)) + ptr.append(lra.gen_doc(**kwargs, make_link = True)) + ptr.append(ta.gen_doc(**kwargs, make_link = True)) key_words = [] for ii in "\n\n".join(ptr).split('\n'): diff --git a/requirements.txt b/requirements.txt index c8a81216ab..f57f40b611 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ numpy scipy pyyaml -dargs >= 0.2.0 +dargs >= 0.2.1 tqdm typing_extensions From 6f489be9076e18f26c12db77906ef6b632318300 Mon Sep 17 00:00:00 2001 From: ziyao Date: Tue, 13 Apr 2021 17:16:47 +0800 Subject: [PATCH 344/562] test removed; validation supported. --- deepmd/entrypoints/train.py | 87 ++++++++++-------- deepmd/loss/ener.py | 45 +++++++++- deepmd/loss/tensor.py | 22 ++++- deepmd/train/trainer.py | 172 ++++++++++++++++++++---------------- deepmd/utils/data_system.py | 21 +++-- 5 files changed, 218 insertions(+), 129 deletions(-) diff --git a/deepmd/entrypoints/train.py b/deepmd/entrypoints/train.py index 790cc227f6..3e7e022b6e 100755 --- a/deepmd/entrypoints/train.py +++ b/deepmd/entrypoints/train.py @@ -238,28 +238,64 @@ def _do_work(jdata: Dict[str, Any], run_opt: RunOptions): else: ipt_type_map = type_map - # init params and run options - systems = j_must_have(jdata["training"], "systems") - if isinstance(systems, str): - systems = expand_sys_str(systems) - set_pfx = j_must_have(jdata["training"], "set_prefix") - #  init random seed seed = jdata["training"].get("seed", None) if seed is not None: seed = seed % (2 ** 32) np.random.seed(seed) - # get batch sizes - batch_size = j_must_have(jdata["training"], "batch_size") - test_size = j_must_have(jdata["training"], "numb_test") + # setup data modifier + modifier = get_modifier(jdata["model"].get("modifier", None)) + + # init data + train_data = get_data(jdata["training"]["training_data"], rcut, ipt_type_map, modifier) + train_data.print_summary() + if "validation_data" in jdata["training"]: + valid_data = get_data(jdata["training"]["validation_data"], rcut, ipt_type_map, modifier) + valid_data.print_summary() + else: + valid_data = None + + # get training info stop_batch = j_must_have(jdata["training"], "numb_steps") - sys_probs = jdata["training"].get("sys_probs") - auto_prob = jdata["training"].get("auto_prob", "prob_sys_size") + model.build(train_data, stop_batch) - # setup data modifier + # train the model with the provided systems in a cyclic way + start_time = time.time() + model.train(train_data, valid_data) + end_time = time.time() + log.info("finished training") + log.info(f"wall time: {(end_time - start_time):.3f} s") + + +def get_data(jdata: Dict[str, Any], rcut, type_map, modifier): + systems = j_must_have(jdata, "systems") + if isinstance(systems, str): + systems = expand_sys_str(systems) + + batch_size = j_must_have(jdata, "batch_size") + sys_probs = jdata.get("sys_probs", None) + auto_prob = jdata.get("auto_prob", "prob_sys_size") + + data = DeepmdDataSystem( + systems=systems, + batch_size=batch_size, + test_size=1, # to satisfy the old api + shuffle_test=True, # to satisfy the old api + rcut=rcut, + type_map=type_map, + modifier=modifier, + trn_all_set=True, # sample from all sets + sys_probs=sys_probs, + auto_prob=auto_prob + ) + data.add_dict(data_requirement) + + return data + + +def get_modifier(modi_data=None): modifier: Optional[DipoleChargeModifier] - modi_data = jdata["model"].get("modifier", None) if modi_data is not None: if modi_data["type"] == "dipole_charge": modifier = DipoleChargeModifier( @@ -273,27 +309,4 @@ def _do_work(jdata: Dict[str, Any], run_opt: RunOptions): raise RuntimeError("unknown modifier type " + str(modi_data["type"])) else: modifier = None - - # init data - data = DeepmdDataSystem( - systems, - batch_size, - test_size, - rcut, - set_prefix=set_pfx, - type_map=ipt_type_map, - modifier=modifier, - trn_all_set = True - ) - data.print_summary(run_opt, sys_probs=sys_probs, auto_prob_style=auto_prob) - data.add_dict(data_requirement) - - # build the model with stats from the first system - model.build(data, stop_batch) - - # train the model with the provided systems in a cyclic way - start_time = time.time() - model.train(data) - end_time = time.time() - log.info("finished training") - log.info(f"wall time: {(end_time - start_time):.3f} s") + return modifier \ No newline at end of file diff --git a/deepmd/loss/ener.py b/deepmd/loss/ener.py index f25cb42219..ea54494273 100644 --- a/deepmd/loss/ener.py +++ b/deepmd/loss/ener.py @@ -127,7 +127,30 @@ def build (self, self.l2_more = more_loss return l2_loss, more_loss - def print_header(self): + def eval(self, sess, feed_dict, natoms): + run_data = [ + self.l2_l, + self.l2_more['l2_ener_loss'], + self.l2_more['l2_force_loss'], + self.l2_more['l2_virial_loss'], + self.l2_more['l2_atom_ener_loss'], + self.l2_more['l2_pref_force_loss'] + ] + error, error_e, error_f, error_v, error_ae, error_pf = sess.run(run_data, feed_dict=feed_dict) + results = {"rmse": np.sqrt(error)} + if self.has_e: + results["rmse_e"] = np.sqrt(error_e) / natoms[0] + if self.has_ae: + results["rmse_ae"] = np.sqrt(error_ae) + if self.has_f: + results["rmse_f"] = np.sqrt(error_f) + if self.has_v: + results["rmse_v"] = np.sqrt(error_v) / natoms[0] + if self.has_pf: + results["rmse_pf"] = np.sqrt(error_pf) + return results + + def print_header(self): # depreciated prop_fmt = ' %11s %11s' print_str = '' print_str += prop_fmt % ('rmse_tst', 'rmse_trn') @@ -149,7 +172,7 @@ def print_on_training(self, sess, natoms, feed_dict_test, - feed_dict_batch): + feed_dict_batch): # depreciated run_data = [ self.l2_l, @@ -268,8 +291,22 @@ def build (self, self.l2_more = more_loss return l2_loss, more_loss + def eval(self, sess, feed_dict, natoms): + run_data = [ + self.l2_l, + self.l2_more['l2_ener_loss'], + self.l2_more['l2_ener_dipole_loss'] + ] + error, error_e, error_ed = sess.run(run_data, feed_dict=feed_dict) + results = { + 'rmse': np.sqrt(error), + 'rmse_e': np.sqrt(error_e) / natoms[0], + 'rmse_ed': np.sqrt(error_ed) + } + return results + @staticmethod - def print_header() : + def print_header() : # depreciated prop_fmt = ' %9s %9s' print_str = '' print_str += prop_fmt % ('l2_tst', 'l2_trn') @@ -283,7 +320,7 @@ def print_on_training(self, sess, natoms, feed_dict_test, - feed_dict_batch): + feed_dict_batch): # depreciated run_data = [ self.l2_l, diff --git a/deepmd/loss/tensor.py b/deepmd/loss/tensor.py index addccdcadf..7652e9cfcf 100644 --- a/deepmd/loss/tensor.py +++ b/deepmd/loss/tensor.py @@ -130,7 +130,25 @@ def build (self, self.l2_loss_summary = tf.summary.scalar('l2_loss', tf.sqrt(l2_loss)) return l2_loss, more_loss - def print_header(self): + def eval(self, sess, feed_dict, natoms): + atoms = 0 + if self.type_sel is not None: + for w in self.type_sel: + atoms += natoms[2+w] + else: + atoms = natoms[0] + + run_data = [self.l2_l, self.l2_more['local_loss'], self.l2_more['global_loss']] + error, error_lc, error_gl = sess.run(run_data, feed_dict=feed_dict) + + results = {"rmse": np.sqrt(error)} + if self.local_weight > 0.0: + results["rmse_lc"] = np.sqrt(error_lc) + if self.global_weight > 0.0: + results["rmse_gl"] = np.sqrt(error_gl) / atoms + return results + + def print_header(self): # depreciated prop_fmt = ' %11s %11s' print_str = '' print_str += prop_fmt % ('rmse_tst', 'rmse_trn') @@ -146,7 +164,7 @@ def print_on_training(self, sess, natoms, feed_dict_test, - feed_dict_batch) : + feed_dict_batch) : # depreciated # YHT: added to calculate the atoms number atoms = 0 diff --git a/deepmd/train/trainer.py b/deepmd/train/trainer.py index 1ae50e1e89..de7718d891 100644 --- a/deepmd/train/trainer.py +++ b/deepmd/train/trainer.py @@ -239,7 +239,6 @@ def _init_param(self, jdata): # ! first .add() altered by Marián Rynik tr_args = ClassArg()\ - .add('numb_test', [int, list, str], default = 1)\ .add('disp_file', str, default = 'lcurve.out')\ .add('disp_freq', int, default = 100)\ .add('save_freq', int, default = 1000)\ @@ -249,9 +248,9 @@ def _init_param(self, jdata): .add('profiling', bool, default = False)\ .add('profiling_file',str, default = 'timeline.json')\ .add('tensorboard', bool, default = False)\ - .add('tensorboard_log_dir',str, default = 'log')\ - .add('sys_probs', list )\ - .add('auto_prob', str, default = "prob_sys_size") + .add('tensorboard_log_dir',str, default = 'log') + # .add('sys_probs', list )\ + # .add('auto_prob', str, default = "prob_sys_size") tr_data = tr_args.parse(training_param) # not needed # self.numb_test = tr_data['numb_test'] @@ -265,14 +264,19 @@ def _init_param(self, jdata): self.profiling_file = tr_data['profiling_file'] self.tensorboard = tr_data['tensorboard'] self.tensorboard_log_dir = tr_data['tensorboard_log_dir'] - self.sys_probs = tr_data['sys_probs'] - self.auto_prob_style = tr_data['auto_prob'] + # self.sys_probs = tr_data['sys_probs'] + # self.auto_prob_style = tr_data['auto_prob'] self.useBN = False if fitting_type == 'ener' and self.fitting.get_numb_fparam() > 0 : self.numb_fparam = self.fitting.get_numb_fparam() else : self.numb_fparam = 0 + if "validation_data" in tr_data.keys(): # if validation set specified + self.valid_numb_batch = tr_data["validation_data"].get("numb_btch", 1) + else: + self.valid_numb_batch = 1 + def build (self, data, stop_batch = 0) : @@ -443,15 +447,18 @@ def _init_sess_distrib(self): # , # save_checkpoint_steps = self.save_freq) - def train (self, - data) : + def train (self, train_data, valid_data=None) : + + if valid_data is None: # no validation set specified. + valid_data = train_data # using training set as validation set. + stop_batch = self.stop_batch if self.run_opt.is_distrib : self._init_sess_distrib() else : self._init_sess_serial() - self.print_head() + # self.print_head() fp = None if self.run_opt.is_chief : fp = open(self.disp_file, "a") @@ -478,41 +485,27 @@ def train (self, summary_merged_op = tf.summary.merge_all() shutil.rmtree(self.tensorboard_log_dir) tb_train_writer = tf.summary.FileWriter(self.tensorboard_log_dir + '/train', self.sess.graph) - tb_test_writer = tf.summary.FileWriter(self.tensorboard_log_dir + '/test') + tb_valid_writer = tf.summary.FileWriter(self.tensorboard_log_dir + '/test') else: tb_train_writer = None - tb_test_writer = None + tb_valid_writer = None train_time = 0 while cur_batch < stop_batch : - batch_data = data.get_batch (sys_probs = self.sys_probs, - auto_prob_style = self.auto_prob_style - ) - feed_dict_batch = {} - for kk in batch_data.keys(): - if kk == 'find_type' or kk == 'type' : - continue - if 'find_' in kk : - feed_dict_batch[self.place_holders[kk]] = batch_data[kk] - else: - feed_dict_batch[self.place_holders[kk]] = np.reshape(batch_data[kk], [-1]) - for ii in ['type'] : - feed_dict_batch[self.place_holders[ii]] = np.reshape(batch_data[ii], [-1]) - for ii in ['natoms_vec', 'default_mesh'] : - feed_dict_batch[self.place_holders[ii]] = batch_data[ii] - feed_dict_batch[self.place_holders['is_training']] = True - + train_feed_dict, train_natoms = self.get_feed_dict(train_data, is_training=True) if self.display_in_training and is_first_step : - self.test_on_the_fly(fp, data, feed_dict_batch, tb_test_writer) + self.valid_on_the_fly(fp, train_data, valid_data, print_header=True) is_first_step = False if self.timing_in_training : tic = time.time() # use tensorboard to visualize the training of deepmd-kit # it will takes some extra execution time to generate the tensorboard data if self.tensorboard : - summary, _ = self.sess.run([summary_merged_op, self.train_op], feed_dict = feed_dict_batch, options=prf_options, run_metadata=prf_run_metadata) + summary, _ = self.sess.run([summary_merged_op, self.train_op], feed_dict=train_feed_dict, + options=prf_options, run_metadata=prf_run_metadata) tb_train_writer.add_summary(summary, cur_batch) else : - self.sess.run([self.train_op], feed_dict = feed_dict_batch, options=prf_options, run_metadata=prf_run_metadata) + self.sess.run([self.train_op], feed_dict=train_feed_dict, + options=prf_options, run_metadata=prf_run_metadata) if self.timing_in_training : toc = time.time() if self.timing_in_training : train_time += toc - tic cur_batch = self.sess.run(self.global_step) @@ -520,7 +513,7 @@ def train (self, if self.display_in_training and (cur_batch % self.disp_freq == 0) : tic = time.time() - self.test_on_the_fly(fp, data, feed_dict_batch, tb_test_writer) + self.valid_on_the_fly(fp, train_data, valid_data) toc = time.time() test_time = toc - tic if self.timing_in_training : @@ -539,56 +532,81 @@ def train (self, with open(self.profiling_file, 'w') as f: f.write(chrome_trace) + def get_feed_dict (self, data, is_training) : + batch = data.get_batch() + feed_dict = {} + for kk in batch.keys(): + if kk == 'find_type' or kk == 'type': + continue + if 'find_' in kk: + feed_dict[self.place_holders[kk]] = batch[kk] + else: + feed_dict[self.place_holders[kk]] = np.reshape(batch[kk], [-1]) + for ii in ['type']: + feed_dict[self.place_holders[ii]] = np.reshape(batch[ii], [-1]) + for ii in ['natoms_vec', 'default_mesh']: + feed_dict[self.place_holders[ii]] = batch[ii] + feed_dict[self.place_holders['is_training']] = is_training + return feed_dict, batch['natoms_vec'] + def get_global_step (self) : return self.sess.run(self.global_step) - def print_head (self) : - if self.run_opt.is_chief: - fp = open(self.disp_file, "a") - print_str = "# %5s" % 'batch' - print_str += self.loss.print_header() - print_str += ' %8s\n' % 'lr' - fp.write(print_str) - fp.close () + # def print_head (self) : # depreciated + # if self.run_opt.is_chief: + # fp = open(self.disp_file, "a") + # print_str = "# %5s" % 'batch' + # print_str += self.loss.print_header() + # print_str += ' %8s\n' % 'lr' + # fp.write(print_str) + # fp.close () - def test_on_the_fly (self, + def valid_on_the_fly(self, fp, - data, - feed_dict_batch, - tb_writer) : - # Do not need to pass numb_test here as data object already knows it. - # Both DeepmdDataSystem and ClassArg parse the same json file - test_data = data.get_test(n_test=data.get_sys_ntest()) - feed_dict_test = {} - for kk in test_data.keys(): - if kk == 'find_type' or kk == 'type' : - continue - if 'find_' in kk: - feed_dict_test[self.place_holders[kk]] = test_data[kk] - else: - # again the data object knows appropriate test data shape, - # there is no need to slice again! - # feed_dict_test[self.place_holders[kk]] = np.reshape(test_data[kk][:self.numb_test[data.pick_idx]], [-1]) - feed_dict_test[self.place_holders[kk]] = np.reshape(test_data[kk], [-1]) - for ii in ['type'] : - feed_dict_test[self.place_holders[ii]] = np.reshape(test_data[ii], [-1]) - for ii in ['natoms_vec', 'default_mesh'] : - feed_dict_test[self.place_holders[ii]] = test_data[ii] - feed_dict_test[self.place_holders['is_training']] = False + train_data, + valid_data, + print_header=False): + train_results = self.get_evaluation_results(train_data, self.valid_numb_batch) + valid_results = self.get_evaluation_results(valid_data, self.valid_numb_batch) cur_batch = self.cur_batch current_lr = self.sess.run(self.learning_rate) - if self.run_opt.is_chief: - print_str = "%7d" % cur_batch - print_str += self.loss.print_on_training( - tb_writer, - cur_batch, - self.sess, - test_data['natoms_vec'], - feed_dict_test, - feed_dict_batch - ) - - print_str += " %8.1e\n" % current_lr - fp.write(print_str) - fp.flush () + if print_header: + self.print_header(fp, valid_results) + self.print_on_training(fp, train_results, valid_results, cur_batch, current_lr) + + @staticmethod + def print_header(fp, results): + print_str = '' + print_str += "# %5s" % 'batch' + prop_fmt = ' %11s %11s' + for k in results.keys(): + print_str += prop_fmt % (k + '_val', k + '_trn') + print_str += ' %8s\n' % 'lr' + fp.write(print_str) + fp.flush() + + @staticmethod + def print_on_training(fp, train_results, valid_results, cur_batch, cur_lr): + print_str = '' + print_str += "%7d" % cur_batch + prop_fmt = " %11.2e %11.2e" + for k in valid_results.keys(): + # assert k in train_results.keys() + print_str += prop_fmt % (valid_results[k], train_results[k]) + print_str += " %8.1e\n" % cur_lr + fp.write(print_str) + fp.flush() + + def get_evaluation_results(self, data, numb_batch): + sum_results = None + for i in range(numb_batch): + feed_dict, natoms = self.get_feed_dict(data, is_training=False) + results = self.loss.eval(self.sess, feed_dict, natoms) + if sum_results is None: + sum_results = results + else: + for k, v in results: + sum_results[k] += v + avg_results = {k: v / numb_batch for k, v in sum_results.items()} + return avg_results \ No newline at end of file diff --git a/deepmd/utils/data_system.py b/deepmd/utils/data_system.py index 188366540b..9ed70e9a6f 100644 --- a/deepmd/utils/data_system.py +++ b/deepmd/utils/data_system.py @@ -27,7 +27,9 @@ def __init__ (self, shuffle_test : bool = True, type_map : List[str] = None, modifier = None, - trn_all_set = False) : + trn_all_set = False, + sys_probs = None, + auto_prob = "prob_sys_size") : """ Constructor @@ -103,6 +105,9 @@ def __init__ (self, type_map_list.append(self.data_systems[ii].get_type_map()) self.type_map = self._check_type_map_consistency(type_map_list) + self.sys_probs = sys_probs + self.auto_prob = auto_prob + # ! altered by Marián Rynik # test size # now test size can be set as a percentage of systems data or test size @@ -255,13 +260,12 @@ def reduce(self, The name of the data item to be reduced """ for ii in self.data_systems: - ii.reduce(key_out, k_in) + ii.reduce(key_out, key_in) def get_data_dict(self, ii : int = 0) -> dict: return self.data_systems[ii].get_data_dict() - def _get_sys_probs(self, sys_probs, auto_prob_style) : @@ -307,6 +311,8 @@ def get_batch (self, the probabilities of the systems in this block sums up to `weight`, and the relatively probabilities within this block is proportional to the number of batches in the system. """ + sys_probs = self.sys_probs + auto_prob_style = self.auto_prob if not hasattr(self, 'default_mesh') : self._make_default_mesh() if sys_idx is not None : @@ -405,11 +411,8 @@ def _format_name_length(self, name, width) : name = '-- ' + name return name - def print_summary(self, - run_opt, - sys_probs = None, - auto_prob_style = "prob_sys_size") : - prob = self._get_sys_probs(sys_probs, auto_prob_style) + def print_summary(self) : + prob = self._get_sys_probs(self.sys_probs, self.auto_prob) # width 65 sys_width = 42 log.info("---Summary of DataSystem--------------------------------------------------------------") @@ -601,7 +604,7 @@ def format_name_length(self, name, width) : name = '-- ' + name return name - def print_summary(self, run_opt) : + def print_summary(self) : tmp_msg = "" # width 65 sys_width = 42 From d4d11e8dd0ff5b7a23478fc5ca26f5952c9d43b3 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 13 Apr 2021 21:46:59 +0800 Subject: [PATCH 345/562] fix bugs in examples. unsed key does not pass argcheck in strict mode --- examples/water/train/polar.json | 1 - examples/water/train/polar_se_a.json | 1 - examples/water/train/wannier.json | 1 - examples/water/train/water.json | 1 - examples/water/train/water_se_a.json | 1 - examples/water/train/water_se_ar.json | 1 - examples/water/train/water_se_r.json | 1 - examples/water/train/water_srtab_example.json | 1 - 8 files changed, 8 deletions(-) diff --git a/examples/water/train/polar.json b/examples/water/train/polar.json index 28e82d4587..3075dc6066 100644 --- a/examples/water/train/polar.json +++ b/examples/water/train/polar.json @@ -53,7 +53,6 @@ "numb_test": 10, "save_freq": 1000, "save_ckpt": "model.ckpt", - "load_ckpt": "model.ckpt", "disp_training":true, "time_training":true, "_comment": "that's all" diff --git a/examples/water/train/polar_se_a.json b/examples/water/train/polar_se_a.json index 048c12f765..ae32b63163 100644 --- a/examples/water/train/polar_se_a.json +++ b/examples/water/train/polar_se_a.json @@ -51,7 +51,6 @@ "numb_test": 10, "save_freq": 1000, "save_ckpt": "model.ckpt", - "load_ckpt": "model.ckpt", "disp_training":true, "time_training":true, "_comment": "that's all" diff --git a/examples/water/train/wannier.json b/examples/water/train/wannier.json index f23f5e0d62..62f975ec13 100644 --- a/examples/water/train/wannier.json +++ b/examples/water/train/wannier.json @@ -54,7 +54,6 @@ "numb_test": 10, "save_freq": 1000, "save_ckpt": "model.ckpt", - "load_ckpt": "model.ckpt", "disp_training":true, "time_training":true, "_comment": "that's all" diff --git a/examples/water/train/water.json b/examples/water/train/water.json index 23ba559aed..e0b967628c 100644 --- a/examples/water/train/water.json +++ b/examples/water/train/water.json @@ -61,7 +61,6 @@ "numb_test": 10, "save_freq": 1000, "save_ckpt": "model.ckpt", - "load_ckpt": "model.ckpt", "disp_training":true, "time_training":true, "_comment": "that's all" diff --git a/examples/water/train/water_se_a.json b/examples/water/train/water_se_a.json index 368170a77f..33bb8bab58 100644 --- a/examples/water/train/water_se_a.json +++ b/examples/water/train/water_se_a.json @@ -56,7 +56,6 @@ "numb_test": 10, "save_freq": 1000, "save_ckpt": "model.ckpt", - "load_ckpt": "model.ckpt", "disp_training":true, "time_training":true, "tensorboard": false, diff --git a/examples/water/train/water_se_ar.json b/examples/water/train/water_se_ar.json index 2173f2e1d9..ab029f3f44 100644 --- a/examples/water/train/water_se_ar.json +++ b/examples/water/train/water_se_ar.json @@ -67,7 +67,6 @@ "numb_test": 10, "save_freq": 1000, "save_ckpt": "model.ckpt", - "load_ckpt": "model.ckpt", "disp_training":true, "time_training":true, "profiling": false, diff --git a/examples/water/train/water_se_r.json b/examples/water/train/water_se_r.json index 7faf55a3c3..4b2a81a987 100644 --- a/examples/water/train/water_se_r.json +++ b/examples/water/train/water_se_r.json @@ -56,7 +56,6 @@ "numb_test": 10, "save_freq": 1000, "save_ckpt": "model.ckpt", - "load_ckpt": "model.ckpt", "disp_training":true, "time_training":true, "profiling": false, diff --git a/examples/water/train/water_srtab_example.json b/examples/water/train/water_srtab_example.json index f2a0a4a39c..2e104e2c03 100644 --- a/examples/water/train/water_srtab_example.json +++ b/examples/water/train/water_srtab_example.json @@ -64,7 +64,6 @@ "numb_test": 10, "save_freq": 1000, "save_ckpt": "model.ckpt", - "load_ckpt": "model.ckpt", "disp_training":true, "time_training":true, "_comment": "that's all" From a4bda743001954f8d8cffc3f8a6d1124d5de4578 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 13 Apr 2021 21:47:41 +0800 Subject: [PATCH 346/562] add doc for modifier --- deepmd/utils/argcheck.py | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/deepmd/utils/argcheck.py b/deepmd/utils/argcheck.py index 661e3ee247..fa69eef3d1 100644 --- a/deepmd/utils/argcheck.py +++ b/deepmd/utils/argcheck.py @@ -272,6 +272,31 @@ def fitting_variant_type_args(): default_tag = 'ener', doc = doc_descrpt_type) +def modifier_dipole_charge(): + doc_model_name = "The name of the frozen dipole model file." + doc_model_charge_map = f"The charge of the WFCC. The list length should be the same as the {make_link('sel_type', 'model/fitting_net[dipole]/sel_type')}. " + doc_sys_charge_map = f"The charge of real atoms. The list length should be the same as the {make_link('type_map', 'model/type_map')}" + doc_ewald_h = f"The grid spacing of the FFT grid. Unit is A" + doc_ewald_beta = f"The splitting parameter of Ewald sum. Unit is A^{-1}" + + return [ + Argument("model_name", str, optional = False, doc = doc_model_name), + Argument("model_charge_map", list, optional = False, doc = doc_model_charge_map), + Argument("sys_charge_map", list, optional = False, doc = doc_sys_charge_map), + Argument("ewald_beta", float, optional = True, default = 0.4, doc = doc_ewald_beta), + Argument("ewald_h", float, optional = True, default = 1.0, doc = doc_ewald_h), + ] + +def modifier_variant_type_args(): + doc_modifier_type = "The type of modifier. See explanation below.\n\n\ +-`dipole_charge`: Use WFCC to model the electronic structure of the system. Correct the long-range interaction" + return Variant("type", + [ + Argument("dipole_charge", dict, modifier_dipole_charge()), + ], + optional = False, + doc = doc_modifier_type) + def model_args (): doc_type_map = 'A list of strings. Give the name to each type of atoms.' @@ -279,6 +304,7 @@ def model_args (): doc_data_stat_protect = 'Protect parameter for atomic energy regression.' doc_descrpt = 'The descriptor of atomic environment.' doc_fitting = 'The fitting of physical properties.' + doc_modifier = 'The modifier of model output.' doc_use_srtab = 'The table for the short-range pairwise interaction added on top of DP. The table is a text data file with (N_t + 1) * N_t / 2 + 1 columes. The first colume is the distance between atoms. The second to the last columes are energies for pairs of certain types. For example we have two atom types, 0 and 1. The columes from 2nd to 4th are for 0-0, 0-1 and 1-1 correspondingly.' doc_smin_alpha = 'The short-range tabulated interaction will be swithed according to the distance of the nearest neighbor. This distance is calculated by softmin. This parameter is the decaying parameter in the softmin. It is only required when `use_srtab` is provided.' doc_sw_rmin = 'The lower boundary of the interpolation between short-range tabulated interaction and DP. It is only required when `use_srtab` is provided.' @@ -293,7 +319,8 @@ def model_args (): Argument("sw_rmin", float, optional = True, doc = doc_sw_rmin), Argument("sw_rmax", float, optional = True, doc = doc_sw_rmax), Argument("descriptor", dict, [], [descrpt_variant_type_args()], doc = doc_descrpt), - Argument("fitting_net", dict, [], [fitting_variant_type_args()], doc = doc_fitting) + Argument("fitting_net", dict, [], [fitting_variant_type_args()], doc = doc_fitting), + Argument("modifier", dict, [], [modifier_variant_type_args()], optional = True, doc = doc_modifier), ]) # print(ca.gen_doc()) return ca From eff1a3c8a8ca604e241c31b3aa2e407364906cbb Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 13 Apr 2021 22:50:05 +0800 Subject: [PATCH 347/562] fix bugs: 1, exclude type in ebd. 2, remove se_ar, use hybrid instead --- deepmd/descriptor/se_a_ebd.py | 3 ++- deepmd/utils/argcheck.py | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/deepmd/descriptor/se_a_ebd.py b/deepmd/descriptor/se_a_ebd.py index d827925389..0ea6d0646d 100644 --- a/deepmd/descriptor/se_a_ebd.py +++ b/deepmd/descriptor/se_a_ebd.py @@ -27,7 +27,8 @@ def __init__ (self, numb_aparam : int = 0, set_davg_zero: bool = False, activation_function: str = 'tanh', - precision: str = 'default' + precision: str = 'default', + exclude_types: List[int] = [], ) -> None: """ Constructor diff --git a/deepmd/utils/argcheck.py b/deepmd/utils/argcheck.py index fa69eef3d1..f260f6434e 100644 --- a/deepmd/utils/argcheck.py +++ b/deepmd/utils/argcheck.py @@ -170,8 +170,7 @@ def descrpt_variant_type_args(): - `se_r`: Used by the smooth edition of Deep Potential. Only the distance between atoms is used to construct the descriptor.\n\n\ - `se_a_3be`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Three-body embedding will be used by this descriptor.\n\n\ - `se_a_tpe`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Type embedding will be used by this descriptor.\n\n\ -- `hybrid`: Concatenate of a list of descriptors as a new descriptor.\n\n\ -- `se_ar`: A hybrid of `se_a` and `se_r`. Typically `se_a` has a smaller cut-off while the `se_r` has a larger cut-off. Deprecated, use `hybrid` instead.' +- `hybrid`: Concatenate of a list of descriptors as a new descriptor.' return Variant("type", [ Argument("loc_frame", dict, descrpt_local_frame_args()), @@ -180,7 +179,6 @@ def descrpt_variant_type_args(): Argument("se_a_3be", dict, descrpt_se_a_3be_args(), alias = ['se_at']), Argument("se_a_tpe", dict, descrpt_se_a_tpe_args(), alias = ['se_a_ebd']), Argument("hybrid", dict, descrpt_hybrid_args()), - Argument("se_ar", dict, descrpt_se_ar_args()), ], doc = doc_descrpt_type) From 2019b6f047b4c57937b983c2a3b6d1ac6a81f497 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 13 Apr 2021 22:52:46 +0800 Subject: [PATCH 348/562] fix bugs. remove outdated examples --- examples/water/train/polar.json | 63 ------------------ examples/water/train/polar_se_a.json | 5 +- examples/water/train/wannier.json | 64 ------------------- examples/water/train/water.json | 1 - examples/water/train/water_se_ar.json | 10 ++- examples/water/train/water_se_r.json | 1 - examples/water/train/water_srtab_example.json | 1 - 7 files changed, 9 insertions(+), 136 deletions(-) delete mode 100644 examples/water/train/polar.json delete mode 100644 examples/water/train/wannier.json diff --git a/examples/water/train/polar.json b/examples/water/train/polar.json deleted file mode 100644 index 3075dc6066..0000000000 --- a/examples/water/train/polar.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "with_distrib": false, - "_comment": " model parameters", - "model":{ - "type_map": ["O", "H"], - "data_stat_nbatch": 1, - "descriptor": { - "type": "loc_frame", - "sel_a": [16, 32], - "sel_r": [30, 60], - "rcut": 6.00, - "axis_rule": [0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0], - "_comment": " default rule: []", - "_comment": " user defined rule: for each type provides two axes, ", - "_comment": " for each axis: (a_or_r, type, idx)", - "_comment": " if type < 0, exclude type -(type+1)", - "_comment": " for water (O:0, H:1) it can be", - "_comment": " [0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0]", - "_comment": " that's all" - }, - "fitting_net": { - "type": "polar", - "sel_type": [0], - "neuron": [100, 100, 100], - "resnet_dt": true, - "seed": 1, - "_comment": " that's all" - }, - "_comment": " that's all" - }, - - "learning_rate" :{ - "type": "exp", - "decay_steps": 5000, - "start_lr": 0.001, - "stop_lr": 3.51e-8, - "_comment": "that's all" - }, - - "_comment": " traing controls", - "training": { - "systems": ["/path/to/data/polar/bulk"], - "set_prefix": "set", - "stop_batch": 1000000, - "batch_size": [4], - - "seed": 1, - - "_comment": " display and restart", - "_comment": " frequencies counted in batch", - "disp_file": "lcurve.out", - "disp_freq": 100, - "numb_test": 10, - "save_freq": 1000, - "save_ckpt": "model.ckpt", - "disp_training":true, - "time_training":true, - "_comment": "that's all" - }, - - "_comment": "that's all" -} - diff --git a/examples/water/train/polar_se_a.json b/examples/water/train/polar_se_a.json index ae32b63163..48e7c74b4a 100644 --- a/examples/water/train/polar_se_a.json +++ b/examples/water/train/polar_se_a.json @@ -1,5 +1,4 @@ { - "with_distrib": false, "_comment": " model parameters", "model":{ "type_map": ["O", "H"], @@ -37,8 +36,8 @@ "_comment": " traing controls", "training": { - "systems": ["/path/to/data/polar/bulk"], - "set_prefix": "set", + "systems": ["/path/to/data/polar/bulk"], + "set_prefix": "set", "stop_batch": 1000000, "batch_size": [1], diff --git a/examples/water/train/wannier.json b/examples/water/train/wannier.json deleted file mode 100644 index 62f975ec13..0000000000 --- a/examples/water/train/wannier.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "with_distrib": false, - "_comment": " model parameters", - "model":{ - "type_map": ["O", "H"], - "data_stat_nbatch": 1, - "descriptor": { - "type": "loc_frame", - "sel_a": [16, 32], - "sel_r": [30, 60], - "rcut": 6.00, - "axis_rule": [0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0], - "_comment": " default rule: []", - "_comment": " user defined rule: for each type provides two axes, ", - "_comment": " for each axis: (a_or_r, type, idx)", - "_comment": " if type < 0, exclude type -(type+1)", - "_comment": " for water (O:0, H:1) it can be", - "_comment": " [0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0]", - "_comment": " that's all" - }, - "fitting_net": { - "type": "wfc", - "wfc_numb": 4, - "sel_type": [0], - "neuron": [100, 100, 100], - "resnet_dt": true, - "seed": 1, - "_comment": " that's all" - }, - "_comment": " that's all" - }, - - "learning_rate" :{ - "type": "exp", - "decay_steps": 5000, - "start_lr": 0.001, - "stop_lr": 3.51e-8, - "_comment": "that's all" - }, - - "_comment": " traing controls", - "training": { - "systems": ["../data.wfc/"], - "set_prefix": "set", - "stop_batch": 1000000, - "batch_size": [4], - - "seed": 1, - - "_comment": " display and restart", - "_comment": " frequencies counted in batch", - "disp_file": "lcurve.out", - "disp_freq": 100, - "numb_test": 10, - "save_freq": 1000, - "save_ckpt": "model.ckpt", - "disp_training":true, - "time_training":true, - "_comment": "that's all" - }, - - "_comment": "that's all" -} - diff --git a/examples/water/train/water.json b/examples/water/train/water.json index e0b967628c..9564b0ab27 100644 --- a/examples/water/train/water.json +++ b/examples/water/train/water.json @@ -1,5 +1,4 @@ { - "with_distrib": false, "_comment": " model parameters", "model":{ "type_map": ["O", "H"], diff --git a/examples/water/train/water_se_ar.json b/examples/water/train/water_se_ar.json index ab029f3f44..6c4786d2c8 100644 --- a/examples/water/train/water_se_ar.json +++ b/examples/water/train/water_se_ar.json @@ -3,8 +3,10 @@ "model": { "type_map": ["O", "H"], "descriptor" :{ - "type": "se_ar", - "a" : { + "type": "hybrid", + "list": [ + { + "type": "se_a", "sel": [20, 40], "rcut_smth": 3.50, "rcut": 4.00, @@ -14,7 +16,8 @@ "seed": 1, "_comment": " that's all" }, - "r": { + { + "type": "se_r", "sel": [46, 92], "rcut_smth": 1.00, "rcut": 6.00, @@ -23,6 +26,7 @@ "seed": 1, "_comment": " that's all" } + ] }, "fitting_net" : { "neuron": [240, 240, 240], diff --git a/examples/water/train/water_se_r.json b/examples/water/train/water_se_r.json index 4b2a81a987..8ff31452b8 100644 --- a/examples/water/train/water_se_r.json +++ b/examples/water/train/water_se_r.json @@ -1,6 +1,5 @@ { "_comment": " model parameters", - "model_type": "se_r", "model": { "type_map": ["O", "H"], "descriptor": { diff --git a/examples/water/train/water_srtab_example.json b/examples/water/train/water_srtab_example.json index 2e104e2c03..2bfe3e32fc 100644 --- a/examples/water/train/water_srtab_example.json +++ b/examples/water/train/water_srtab_example.json @@ -1,5 +1,4 @@ { - "with_distrib": false, "_comment": " model parameters", "model":{ "type_map": ["O", "H"], From 2200c539918831f30fae5dffc568b02ff71e3a8b Mon Sep 17 00:00:00 2001 From: Yixiao Chen <19890787+y1xiaoc@users.noreply.github.com> Date: Tue, 13 Apr 2021 13:50:01 -0500 Subject: [PATCH 349/562] use new reference style in gen_doc --- deepmd/utils/argcheck.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/deepmd/utils/argcheck.py b/deepmd/utils/argcheck.py index f260f6434e..28cbf8f2c0 100644 --- a/deepmd/utils/argcheck.py +++ b/deepmd/utils/argcheck.py @@ -1,4 +1,4 @@ -from dargs import Argument, Variant +from dargs import dargs, Argument, Variant from deepmd.common import ACTIVATION_FN_DICT, PRECISION_DICT def list_to_doc (xx): @@ -13,7 +13,7 @@ def list_to_doc (xx): def make_link(content, ref_key) : - return f'`{content} <#{ref_key}>`__' + return f'`{content} <{ref_key}_>`_' if not dargs.RAW_ANCHOR else f'`{content} <#{ref_key}>`_' def descrpt_local_frame_args (): @@ -460,16 +460,18 @@ def make_index(keys): return ', '.join(ret) -def gen_doc(**kwargs): +def gen_doc(*, make_anchor=True, make_link=True, **kwargs): + if make_link: + make_anchor = True ma = model_args() lra = learning_rate_args() la = loss_args() ta = training_args() ptr = [] - ptr.append(ma.gen_doc(**kwargs, make_link = True)) - ptr.append(la.gen_doc(**kwargs, make_link = True)) - ptr.append(lra.gen_doc(**kwargs, make_link = True)) - ptr.append(ta.gen_doc(**kwargs, make_link = True)) + ptr.append(ma.gen_doc(make_anchor=make_anchor, make_link=make_link, **kwargs)) + ptr.append(la.gen_doc(make_anchor=make_anchor, make_link=make_link, **kwargs)) + ptr.append(lra.gen_doc(make_anchor=make_anchor, make_link=make_link, **kwargs)) + ptr.append(ta.gen_doc(make_anchor=make_anchor, make_link=make_link, **kwargs)) key_words = [] for ii in "\n\n".join(ptr).split('\n'): From 0368aad14035f8c48e961454fe4f382b469e6e75 Mon Sep 17 00:00:00 2001 From: Yixiao Chen <19890787+y1xiaoc@users.noreply.github.com> Date: Tue, 13 Apr 2021 15:31:58 -0500 Subject: [PATCH 350/562] clean up doc for coding conventions --- doc/developement.rst | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/doc/developement.rst b/doc/developement.rst index fbbd3edda1..856634cbef 100644 --- a/doc/developement.rst +++ b/doc/developement.rst @@ -64,6 +64,10 @@ Conventions`_ and `Typing Conventions`_ PEPs, clarified and extended as follows: * Use ``"double quotes"`` for string literals, and ``"""triple double quotes"""`` for docstring's. Single quotes are OK for something like + + .. code-block:: python + + f"something {'this' if x else 'that'}" * Use f-strings ``s = f"{x:.2f}"`` instead of old style formating with ``"%f" % x``. string format method ``"{x:.2f}".format()`` may be used sparsely where it is more @@ -83,6 +87,7 @@ Python is not C/C++ so whitespace should be used sparingly to maintain code rea * You should have blank spaces after commas, colons, and semi-colons if it isn’t trailing next to the end of a bracket, brace, or parentheses. + * With any operators you should use a space in on both sides of the operator. * Colons for slicing are considered a binary operator, and should not have any spaces @@ -99,10 +104,6 @@ Python is not C/C++ so whitespace should be used sparingly to maintain code rea * Make sure you are consistent with the formats you choose when optional choices are available. - .. code-block:: python - - f"something {'this' if x else 'that'}" - .. _Style Guide for Python Code: .. _PEP8: https://www.python.org/dev/peps/pep-0008/ .. _Docstring Conventions: https://www.python.org/dev/peps/pep-0257/ @@ -112,24 +113,15 @@ Python is not C/C++ so whitespace should be used sparingly to maintain code rea .. _trailing whitespaces: http://www.gnu.org/software/emacs/manual/html_node/ emacs/Useless-Whitespace.html -.. attention:: - - Thus spake the Lord: Thou shalt indent with four spaces. No more, no less. - Four shall be the number of spaces thou shalt indent, and the number of thy - indenting shall be four. Eight shalt thou not indent, nor either indent thou - two, excepting that thou then proceed to four. Tabs are right out. - - Georg Brandl - - General advice ============== - * Get rid of as many ``break`` and ``continue`` statements as possible. +* Get rid of as many ``break`` and ``continue`` statements as possible. - * Write short functions. All functions should fit within a standard screen. +* Write short functions. + All functions should fit within a standard screen. - * Use descriptive variable names. +* Use descriptive variable names. Writing documentation in the code ================================= From 045dd6dde40deff3a496f459661b70f3b27d3860 Mon Sep 17 00:00:00 2001 From: ziyao Date: Thu, 15 Apr 2021 13:26:06 +0800 Subject: [PATCH 351/562] cheating the argcheck for debugging --- deepmd/entrypoints/train.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deepmd/entrypoints/train.py b/deepmd/entrypoints/train.py index 3e7e022b6e..3e265a559e 100755 --- a/deepmd/entrypoints/train.py +++ b/deepmd/entrypoints/train.py @@ -171,7 +171,7 @@ def train( if "model" not in jdata.keys(): jdata = convert_input_v0_v1(jdata, warning=True, dump="input_v1_compat.json") - jdata = normalize(jdata) + # jdata = normalize(jdata) with open(output, "w") as fp: json.dump(jdata, fp, indent=4) diff --git a/setup.py b/setup.py index 5f7f2fa8bc..e77b1b78a7 100644 --- a/setup.py +++ b/setup.py @@ -101,7 +101,7 @@ f"-DTENSORFLOW_ROOT:STRING={tf_install_dir}", "-DBUILD_PY_IF:BOOL=TRUE", "-DBUILD_CPP_IF:BOOL=FALSE", - "-DFLOAT_PREC:STRING=high", + "-DFLOAT_PREC:STRING=low", ], cmake_source_dir="source", cmake_minimum_required_version="3.0", From 596a4b2485b0549024ab2635b74813c1bdc13636 Mon Sep 17 00:00:00 2001 From: ziyao Date: Thu, 15 Apr 2021 14:30:57 +0800 Subject: [PATCH 352/562] variable names optimized; get_batch function optimized. --- deepmd/entrypoints/train.py | 2 +- deepmd/utils/data_system.py | 92 ++++++++++++++++++++----------------- 2 files changed, 51 insertions(+), 43 deletions(-) diff --git a/deepmd/entrypoints/train.py b/deepmd/entrypoints/train.py index 3e265a559e..17a732e52a 100755 --- a/deepmd/entrypoints/train.py +++ b/deepmd/entrypoints/train.py @@ -287,7 +287,7 @@ def get_data(jdata: Dict[str, Any], rcut, type_map, modifier): modifier=modifier, trn_all_set=True, # sample from all sets sys_probs=sys_probs, - auto_prob=auto_prob + auto_prob_style=auto_prob ) data.add_dict(data_requirement) diff --git a/deepmd/utils/data_system.py b/deepmd/utils/data_system.py index 9ed70e9a6f..5ad98a6463 100644 --- a/deepmd/utils/data_system.py +++ b/deepmd/utils/data_system.py @@ -19,17 +19,17 @@ class DeepmdDataSystem() : It is implemented with the help of DeepmdData """ def __init__ (self, - systems : List[str], + systems : List[str], batch_size : int, test_size : int, rcut : float, set_prefix : str = 'set', shuffle_test : bool = True, - type_map : List[str] = None, - modifier = None, + type_map : List[str] = None, + modifier = None, trn_all_set = False, sys_probs = None, - auto_prob = "prob_sys_size") : + auto_prob_style ="prob_sys_size") : """ Constructor @@ -53,7 +53,20 @@ def __init__ (self, Data modifier that has the method `modify_data` trn_all_set Use all sets as training dataset. Otherwise, if the number of sets is more than 1, the last set is left for test. - """ + sys_probs: list of float + The probabilitis of systems to get the batch. + Summation of positive elements of this list should be no greater than 1. + Element of this list can be negative, the probability of the corresponding system is determined + automatically by the number of batches in the system. + auto_prob_style: str + Determine the probability of systems automatically. The method is assigned by this key and can be + - "prob_uniform" : the probability all the systems are equal, namely 1.0/self.get_nsystems() + - "prob_sys_size" : the probability of a system is proportional to the number of batches in the system + - "prob_sys_size;stt_idx:end_idx:weight;stt_idx:end_idx:weight;..." : + the list of systems is devided into blocks. A block is specified by `stt_idx:end_idx:weight`, + where `stt_idx` is the starting index of the system, `end_idx` is then ending (not including) index of the system, + the probabilities of the systems in this block sums up to `weight`, and the relatively probabilities within this block is proportional + to the number of batches in the system.""" # init data self.rcut = rcut self.system_dirs = systems @@ -71,7 +84,7 @@ def __init__ (self, )) # batch size self.batch_size = batch_size - if isinstance(self.batch_size, int) : + if isinstance(self.batch_size, int): self.batch_size = self.batch_size * np.ones(self.nsystems, dtype=int) elif isinstance(self.batch_size, str): words = self.batch_size.split(':') @@ -105,8 +118,8 @@ def __init__ (self, type_map_list.append(self.data_systems[ii].get_type_map()) self.type_map = self._check_type_map_consistency(type_map_list) - self.sys_probs = sys_probs - self.auto_prob = auto_prob + self.sys_probs = None + self.set_sys_probs(sys_probs, auto_prob_style) # ! altered by Marián Rynik # test size @@ -185,10 +198,7 @@ def compute_energy_shift(self, rcond = 1e-3, key = 'energy') : = np.linalg.lstsq(sys_tynatom, sys_ener, rcond = rcond) return energy_shift - - def add_dict(self, - adict : dict - ) -> None: + def add_dict(self, adict: dict) -> None: """ Add items to the data system by a `dict`. `adict` should have items like @@ -246,9 +256,7 @@ def add(self, for ii in self.data_systems: ii.add(key, ndof, atomic=atomic, must=must, high_prec=high_prec, repeat=repeat, type_sel=type_sel) - def reduce(self, - key_out, - key_in) : + def reduce(self, key_out, key_in): """ Generate a new item from the reduction of another atom @@ -262,13 +270,28 @@ def reduce(self, for ii in self.data_systems: ii.reduce(key_out, key_in) - def get_data_dict(self, - ii : int = 0) -> dict: + def get_data_dict(self, ii: int = 0) -> dict: return self.data_systems[ii].get_data_dict() + def set_sys_probs(self, sys_probs=None, + auto_prob_style: str = "prob_sys_size"): + if sys_probs is None : + if auto_prob_style == "prob_uniform": + prob_v = 1./float(self.nsystems) + probs = [prob_v for ii in range(self.nsystems)] + elif auto_prob_style == "prob_sys_size": + probs = self.prob_nbatches + elif auto_prob_style[:14] == "prob_sys_size;": + probs = self._prob_sys_size_ext(auto_prob_style) + else: + raise RuntimeError("Unknown auto prob style: " + auto_prob_style) + else: + probs = self._process_sys_probs(sys_probs) + self.sys_probs = probs + def _get_sys_probs(self, sys_probs, - auto_prob_style) : + auto_prob_style) : # depreciated if sys_probs is None : if auto_prob_style == "prob_uniform" : prob_v = 1./float(self.nsystems) @@ -283,11 +306,12 @@ def _get_sys_probs(self, prob = self._process_sys_probs(sys_probs) return prob - - def get_batch (self, - sys_idx : int = None, - sys_probs : List[float] = None, - auto_prob_style : str = "prob_sys_size") : + def get_batch(self, sys_idx : int = None): + # batch generation style altered by Ziyao Li: + # one should specify the "sys_prob" and "auto_prob_style" params + # via set_sys_prob() function. The sys_probs this function uses is + # defined as a private variable, self.sys_probs, initialized in __init__(). + # This is to optimize the (vain) efforts in evaluating sys_probs every batch. """ Get a batch of data from the data systems @@ -297,29 +321,14 @@ def get_batch (self, The index of system from which the batch is get. If sys_idx is not None, `sys_probs` and `auto_prob_style` are ignored If sys_idx is None, automatically determine the system according to `sys_probs` or `auto_prob_style`, see the following. - sys_probs: list of float - The probabilitis of systems to get the batch. - Summation of positive elements of this list should be no greater than 1. - Element of this list can be negative, the probability of the corresponding system is determined automatically by the number of batches in the system. - auto_prob_style: str - Determine the probability of systems automatically. The method is assigned by this key and can be - - "prob_uniform" : the probability all the systems are equal, namely 1.0/self.get_nsystems() - - "prob_sys_size" : the probability of a system is proportional to the number of batches in the system - - "prob_sys_size;stt_idx:end_idx:weight;stt_idx:end_idx:weight;..." : - the list of systems is devided into blocks. A block is specified by `stt_idx:end_idx:weight`, - where `stt_idx` is the starting index of the system, `end_idx` is then ending (not including) index of the system, - the probabilities of the systems in this block sums up to `weight`, and the relatively probabilities within this block is proportional - to the number of batches in the system. """ - sys_probs = self.sys_probs - auto_prob_style = self.auto_prob if not hasattr(self, 'default_mesh') : self._make_default_mesh() if sys_idx is not None : self.pick_idx = sys_idx else : - prob = self._get_sys_probs(sys_probs, auto_prob_style) - self.pick_idx = np.random.choice(np.arange(self.nsystems), p = prob) + # prob = self._get_sys_probs(sys_probs, auto_prob_style) + self.pick_idx = np.random.choice(np.arange(self.nsystems), p=self.sys_probs) b_data = self.data_systems[self.pick_idx].get_batch(self.batch_size[self.pick_idx]) b_data["natoms_vec"] = self.natoms_vec[self.pick_idx] b_data["default_mesh"] = self.default_mesh[self.pick_idx] @@ -328,8 +337,7 @@ def get_batch (self, # ! altered by Marián Rynik def get_test (self, sys_idx : int = None, - n_test : int = -1 - ) : + n_test : int = -1) : # depreciated """ Get test data from the the data systems. From b1bc4fb398efc4158d0b07a073174e95add6b323 Mon Sep 17 00:00:00 2001 From: ziyao Date: Thu, 15 Apr 2021 17:08:42 +0800 Subject: [PATCH 353/562] minor bug fixed; data cfg scheme altered. --- deepmd/utils/argcheck.py | 143 +++++++++++++++++++++++++++++---------- 1 file changed, 107 insertions(+), 36 deletions(-) diff --git a/deepmd/utils/argcheck.py b/deepmd/utils/argcheck.py index 28cbf8f2c0..8447b064f6 100644 --- a/deepmd/utils/argcheck.py +++ b/deepmd/utils/argcheck.py @@ -1,7 +1,8 @@ from dargs import dargs, Argument, Variant from deepmd.common import ACTIVATION_FN_DICT, PRECISION_DICT -def list_to_doc (xx): + +def list_to_doc(xx): items = [] for ii in xx: if len(items) == 0: @@ -12,10 +13,11 @@ def list_to_doc (xx): return ''.join(items) -def make_link(content, ref_key) : +def make_link(content, ref_key): return f'`{content} <{ref_key}_>`_' if not dargs.RAW_ANCHOR else f'`{content} <#{ref_key}>`_' +# --- Descriptor configurations: --- # def descrpt_local_frame_args (): doc_sel_a = 'A list of integers. The length of the list should be the same as the number of atom types in the system. `sel_a[i]` gives the selected number of type-i neighbors. The full relative coordinates of the neighbors are used by the descriptor.' doc_sel_r = 'A list of integers. The length of the list should be the same as the number of atom types in the system. `sel_r[i]` gives the selected number of type-i neighbors. Only relative distance of the neighbors are used by the descriptor. sel_a[i] + sel_r[i] is recommended to be larger than the maximally possible number of type-i neighbors in the cut-off radius.' @@ -182,6 +184,7 @@ def descrpt_variant_type_args(): ], doc = doc_descrpt_type) +# --- Fitting net configurations: --- # def fitting_ener(): doc_numb_fparam = 'The dimension of the frame parameter. If set to >0, file `fparam.npy` should be included to provided the input fparams.' doc_numb_aparam = 'The dimension of the atomic parameter. If set to >0, file `aparam.npy` should be included to provided the input aparams.' @@ -270,6 +273,8 @@ def fitting_variant_type_args(): default_tag = 'ener', doc = doc_descrpt_type) + +# --- Modifier configurations: --- # def modifier_dipole_charge(): doc_model_name = "The name of the frozen dipole model file." doc_model_charge_map = f"The charge of the WFCC. The list length should be the same as the {make_link('sel_type', 'model/fitting_net[dipole]/sel_type')}. " @@ -285,6 +290,7 @@ def modifier_dipole_charge(): Argument("ewald_h", float, optional = True, default = 1.0, doc = doc_ewald_h), ] + def modifier_variant_type_args(): doc_modifier_type = "The type of modifier. See explanation below.\n\n\ -`dipole_charge`: Use WFCC to model the electronic structure of the system. Correct the long-range interaction" @@ -324,6 +330,7 @@ def model_args (): return ca +# --- Learning rate configurations: --- # def learning_rate_exp(): doc_start_lr = 'The learning rate the start of the training.' doc_stop_lr = 'The desired learning rate at the end of the training.' @@ -354,12 +361,15 @@ def learning_rate_args(): doc = doc_lr) +# --- Loss configurations: --- # def start_pref(item): return f'The prefactor of {item} loss at the start of the training. Should be larger than or equal to 0. If set to none-zero value, the {item} label should be provided by file {item}.npy in each data system. If both start_pref_{item} and limit_pref_{item} are set to 0, then the {item} will be ignored.' + def limit_pref(item): return f'The prefactor of {item} loss at the limit of the training, Should be larger than or equal to 0. i.e. the training step goes to infinity.' + def loss_ener(): doc_start_pref_e = start_pref('energy') doc_limit_pref_e = limit_pref('energy') @@ -368,7 +378,7 @@ def loss_ener(): doc_start_pref_v = start_pref('virial') doc_limit_pref_v = limit_pref('virial') doc_start_pref_ae = start_pref('atom_ener') - doc_start_pref_ae = limit_pref('atom_ener') + doc_limit_pref_ae = limit_pref('atom_ener') doc_relative_f = 'If provided, relative force error will be used in the loss. The difference of force will be normalized by the magnitude of the force in the label with a shift given by `relative_f`, i.e. DF_i / ( || F || + relative_f ) with DF denoting the difference between prediction and label and || F || denoting the L2 norm of the label.' return [ Argument("start_pref_e", [float,int], optional = True, default = 0.02, doc = doc_start_pref_e), @@ -377,8 +387,8 @@ def loss_ener(): Argument("limit_pref_f", [float,int], optional = True, default = 1.00, doc = doc_limit_pref_f), Argument("start_pref_v", [float,int], optional = True, default = 0.00, doc = doc_start_pref_v), Argument("limit_pref_v", [float,int], optional = True, default = 0.00, doc = doc_limit_pref_v), - Argument("start_pref_ae", [float,int], optional = True, default = 0.00, doc = doc_start_pref_v), - Argument("limit_pref_ae", [float,int], optional = True, default = 0.00, doc = doc_limit_pref_v), + Argument("start_pref_ae", [float,int], optional = True, default = 0.00, doc = doc_start_pref_ae), + Argument("limit_pref_ae", [float,int], optional = True, default = 0.00, doc = doc_limit_pref_ae), Argument("relative_f", [float,None], optional = True, doc = doc_relative_f) ] @@ -392,6 +402,7 @@ def loss_variant_type_args(): default_tag = 'ener', doc = doc_loss) + def loss_args(): doc_loss = 'The definition of loss function. The type of the loss depends on the type of the fitting. For fitting type `ener`, the prefactors before energy, force, virial and atomic energy losses may be provided. For fitting type `dipole`, `polar` and `global_polar`, the loss may be an empty `dict` or unset.' ca = Argument('loss', dict, [], @@ -400,16 +411,80 @@ def loss_args(): doc = doc_loss) return ca -def training_args(): - link_sys = make_link("systems", "training/systems") - doc_systems = 'The data systems. This key can be provided with a listthat specifies the systems, or be provided with a string by which the prefix of all systems are given and the list of the systems is automatically generated.' + +# --- Training configurations: --- # +def training_data_args(): # ! added by Ziyao: new specification style for data systems. + link_sys = make_link("systems", "training/training_data/systems") + doc_systems = 'The data systems for training. ' \ + 'This key can be provided with a list that specifies the systems, or be provided with a string ' \ + 'by which the prefix of all systems are given and the list of the systems is automatically generated.' doc_set_prefix = f'The prefix of the sets in the {link_sys}.' - doc_stop_batch = 'Number of training batch. Each training uses one batch of data.' doc_batch_size = f'This key can be \n\n\ - list: the length of which is the same as the {link_sys}. The batch size of each system is given by the elements of the list.\n\n\ - int: all {link_sys} use the same batch size.\n\n\ - string "auto": automatically determines the batch size so that the batch_size times the number of atoms in the system is no less than 32.\n\n\ - string "auto:N": automatically determines the batch size so that the batch_size times the number of atoms in the system is no less than N.' + doc_auto_prob_style = 'Determine the probability of systems automatically. The method is assigned by this key and can be\n\n\ +- "prob_uniform" : the probability all the systems are equal, namely 1.0/self.get_nsystems()\n\n\ +- "prob_sys_size" : the probability of a system is proportional to the number of batches in the system\n\n\ +- "prob_sys_size;stt_idx:end_idx:weight;stt_idx:end_idx:weight;..." : the list of systems is devided into blocks. A block is specified by `stt_idx:end_idx:weight`, where `stt_idx` is the starting index of the system, `end_idx` is then ending (not including) index of the system, the probabilities of the systems in this block sums up to `weight`, and the relatively probabilities within this block is proportional to the number of batches in the system.' + doc_sys_probs = "A list of float if specified. " \ + "Should be of the same length as `systems`, " \ + "specifying the probability of each system." + + + args = [ + Argument("systems", [list, str], optional=False, default=".", doc=doc_systems), + Argument("set_prefix", str, optional=True, default='set', doc=doc_set_prefix), + Argument("batch_size", [list, int, str], optional=True, default='auto', doc=doc_batch_size), + Argument("auto_prob", str, optional=True, default="prob_sys_size", + doc=doc_auto_prob_style, alias=["auto_prob_style",]), + Argument("sys_probs", list, optional=True, default=None, doc=doc_sys_probs, alias=["sys_weights"]), + ] + + doc_training_data = "Configurations of training data." + return Argument("training_data", dict, optional=False, + sub_fields=args, sub_variants=[], doc=doc_training_data) + + +def validation_data_args(): # ! added by Ziyao: new specification style for data systems. + link_sys = make_link("systems", "training/validation_data/systems") + doc_systems = 'The data systems for validation. ' \ + 'This key can be provided with a list that specifies the systems, or be provided with a string ' \ + 'by which the prefix of all systems are given and the list of the systems is automatically generated.' + doc_set_prefix = f'The prefix of the sets in the {link_sys}.' + doc_batch_size = f'This key can be \n\n\ +- list: the length of which is the same as the {link_sys}. The batch size of each system is given by the elements of the list.\n\n\ +- int: all {link_sys} use the same batch size.\n\n\ +- string "auto": automatically determines the batch size so that the batch_size times the number of atoms in the system is no less than 32.\n\n\ +- string "auto:N": automatically determines the batch size so that the batch_size times the number of atoms in the system is no less than N.' + doc_auto_prob_style = 'Determine the probability of systems automatically. The method is assigned by this key and can be\n\n\ +- "prob_uniform" : the probability all the systems are equal, namely 1.0/self.get_nsystems()\n\n\ +- "prob_sys_size" : the probability of a system is proportional to the number of batches in the system\n\n\ +- "prob_sys_size;stt_idx:end_idx:weight;stt_idx:end_idx:weight;..." : the list of systems is devided into blocks. A block is specified by `stt_idx:end_idx:weight`, where `stt_idx` is the starting index of the system, `end_idx` is then ending (not including) index of the system, the probabilities of the systems in this block sums up to `weight`, and the relatively probabilities within this block is proportional to the number of batches in the system.' + doc_sys_probs = "A list of float if specified. " \ + "Should be of the same length as `systems`, " \ + "specifying the probability of each system." + doc_numb_btch = "An integer that specifies the number of systems to be sampled for each validation period." + + args = [ + Argument("systems", [list, str], optional=False, default=".", doc=doc_systems), + Argument("set_prefix", str, optional=True, default='set', doc=doc_set_prefix), + Argument("batch_size", [list, int, str], optional=True, default='auto', doc=doc_batch_size), + Argument("auto_prob", str, optional=True, default="prob_sys_size", + doc=doc_auto_prob_style, alias=["auto_prob_style", ]), + Argument("sys_probs", list, optional=True, default=None, doc=doc_sys_probs, alias=["sys_weights"]), + Argument("numb_btch", int, optional=True, default=1, doc=doc_numb_btch, alias=["numb_batch", ]) + ] + + doc_validation_data = "Configurations of validation data. Similar to that of training data, " \ + "except that a `numb_btch` argument may be configured" + return Argument("validation_data", dict, optional=True, default=None, + sub_fields=args, sub_variants=[], doc=doc_validation_data) + + +def training_args(): # ! modified by Ziyao: data configuration isolated. + doc_numb_steps = 'Number of training batch. Each training uses one batch of data.' doc_seed = 'The random seed for getting frames from the training data set.' doc_disp_file = 'The file for printing learning curve.' doc_disp_freq = 'The frequency of printing learning curve.' @@ -420,36 +495,31 @@ def training_args(): doc_time_training = 'Timing durining training.' doc_profiling = 'Profiling during training.' doc_profiling_file = 'Output file for profiling.' - doc_train_auto_prob_style = 'Determine the probability of systems automatically. The method is assigned by this key and can be\n\n\ -- "prob_uniform" : the probability all the systems are equal, namely 1.0/self.get_nsystems()\n\n\ -- "prob_sys_size" : the probability of a system is proportional to the number of batches in the system\n\n\ -- "prob_sys_size;stt_idx:end_idx:weight;stt_idx:end_idx:weight;..." : the list of systems is devided into blocks. A block is specified by `stt_idx:end_idx:weight`, where `stt_idx` is the starting index of the system, `end_idx` is then ending (not including) index of the system, the probabilities of the systems in this block sums up to `weight`, and the relatively probabilities within this block is proportional to the number of batches in the system.' - doc_train_sys_probs = "A list of float, should be of the same length as `train_systems`, specifying the probability of each system." doc_tensorboard = 'Enable tensorboard' doc_tensorboard_log_dir = 'The log directory of tensorboard outputs' + arg_training_data = training_data_args() + arg_validation_data = validation_data_args() + args = [ - Argument("systems", [list,str], optional = False, doc = doc_systems, alias = ["trn_systems"]), - Argument("set_prefix", str, optional = True, default = 'set', doc = doc_set_prefix), - Argument("auto_prob", str, optional = True, default = "prob_sys_size", doc = doc_train_auto_prob_style, alias = ["trn_auto_prob", "auto_prob_style"]), - Argument("sys_probs", list, optional = True, default = None, doc = doc_train_sys_probs, alias = ["trn_sys_probs"]), - Argument("batch_size", [list,int,str], optional = True, default = 'auto', doc = doc_batch_size, alias = ["trn_batch_size"]), - Argument("numb_steps", int, optional = False, doc = doc_stop_batch, alias = ["stop_batch"]), - Argument("seed", [int,None], optional = True, doc = doc_seed), - Argument("disp_file", str, optional = True, default = 'lcueve.out', doc = doc_disp_file), - Argument("disp_freq", int, optional = True, default = 1000, doc = doc_disp_freq), - Argument("numb_test", [list,int,str], optional = True, default = 1, doc = doc_numb_test), - Argument("save_freq", int, optional = True, default = 1000, doc = doc_save_freq), - Argument("save_ckpt", str, optional = True, default = 'model.ckpt', doc = doc_save_ckpt), - Argument("disp_training", bool, optional = True, default = True, doc = doc_disp_training), - Argument("time_training", bool, optional = True, default = True, doc = doc_time_training), - Argument("profiling", bool, optional = True, default = False, doc = doc_profiling), - Argument("profiling_file", str, optional = True, default = 'timeline.json', doc = doc_profiling_file), - Argument("tensorboard", bool, optional = True, default = False, doc = doc_tensorboard), - Argument("tensorboard_log_dir", str, optional = True, default = 'log', doc = doc_tensorboard_log_dir), + arg_training_data, + arg_validation_data, + Argument("numb_steps", int, optional=False, doc=doc_numb_steps, alias=["stop_batch"]), + Argument("seed", [int,None], optional=True, doc=doc_seed), + Argument("disp_file", str, optional=True, default='lcueve.out', doc=doc_disp_file), + Argument("disp_freq", int, optional=True, default=1000, doc=doc_disp_freq), + Argument("numb_test", [list,int,str], optional=True, default=1, doc=doc_numb_test), + Argument("save_freq", int, optional=True, default=1000, doc=doc_save_freq), + Argument("save_ckpt", str, optional=True, default='model.ckpt', doc=doc_save_ckpt), + Argument("disp_training", bool, optional=True, default=True, doc=doc_disp_training), + Argument("time_training", bool, optional=True, default=True, doc=doc_time_training), + Argument("profiling", bool, optional=True, default=False, doc=doc_profiling), + Argument("profiling_file", str, optional=True, default='timeline.json', doc=doc_profiling_file), + Argument("tensorboard", bool, optional=True, default=False, doc=doc_tensorboard), + Argument("tensorboard_log_dir", str, optional=True, default='log', doc=doc_tensorboard_log_dir), ] - doc_training = 'The training options' + doc_training = 'The training options.' return Argument("training", dict, args, [], doc = doc_training) @@ -481,6 +551,7 @@ def gen_doc(*, make_anchor=True, make_link=True, **kwargs): return "\n\n".join(ptr) + def normalize(data): ma = model_args() lra = learning_rate_args() @@ -488,12 +559,12 @@ def normalize(data): ta = training_args() base = Argument("base", dict, [ma, lra, la, ta]) - data = base.normalize_value(data, trim_pattern = "_*") - base.check_value(data, strict = True) + data = base.normalize_value(data, trim_pattern="_*") + base.check_value(data, strict=True) return data if __name__ == '__main__': gen_doc() - + From c6fe57b12c4202ac679222004a8ae7c52bfeb970 Mon Sep 17 00:00:00 2001 From: ziyao Date: Thu, 15 Apr 2021 17:10:05 +0800 Subject: [PATCH 354/562] roll back to incorp. normalization. --- deepmd/entrypoints/train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deepmd/entrypoints/train.py b/deepmd/entrypoints/train.py index 17a732e52a..1eb2941ab0 100755 --- a/deepmd/entrypoints/train.py +++ b/deepmd/entrypoints/train.py @@ -171,7 +171,7 @@ def train( if "model" not in jdata.keys(): jdata = convert_input_v0_v1(jdata, warning=True, dump="input_v1_compat.json") - # jdata = normalize(jdata) + jdata = normalize(jdata) with open(output, "w") as fp: json.dump(jdata, fp, indent=4) From ab83ab0fa1d1da9675125dcdd73fa1a2e272753f Mon Sep 17 00:00:00 2001 From: ziyao Date: Thu, 15 Apr 2021 17:27:03 +0800 Subject: [PATCH 355/562] stress dargs.RAW_ANCHOR --- deepmd/utils/argcheck.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deepmd/utils/argcheck.py b/deepmd/utils/argcheck.py index 8447b064f6..c36829ed32 100644 --- a/deepmd/utils/argcheck.py +++ b/deepmd/utils/argcheck.py @@ -14,7 +14,7 @@ def list_to_doc(xx): def make_link(content, ref_key): - return f'`{content} <{ref_key}_>`_' if not dargs.RAW_ANCHOR else f'`{content} <#{ref_key}>`_' + return f'`{content} <{ref_key}_>`_' # if not dargs.RAW_ANCHOR else f'`{content} <#{ref_key}>`_' # --- Descriptor configurations: --- # From ac6013e44694378ada2a6ccec60ca0edab5097aa Mon Sep 17 00:00:00 2001 From: ziyao Date: Thu, 15 Apr 2021 17:34:41 +0800 Subject: [PATCH 356/562] minor bug fixed --- deepmd/utils/data_system.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/deepmd/utils/data_system.py b/deepmd/utils/data_system.py index 5ad98a6463..cea8903e04 100644 --- a/deepmd/utils/data_system.py +++ b/deepmd/utils/data_system.py @@ -118,9 +118,6 @@ def __init__ (self, type_map_list.append(self.data_systems[ii].get_type_map()) self.type_map = self._check_type_map_consistency(type_map_list) - self.sys_probs = None - self.set_sys_probs(sys_probs, auto_prob_style) - # ! altered by Marián Rynik # test size # now test size can be set as a percentage of systems data or test size @@ -148,6 +145,10 @@ def __init__ (self, self.prob_nbatches = [ float(i) for i in self.nbatches] / np.sum(self.nbatches) self.pick_idx = 0 + # derive system probabilities + self.sys_probs = None + self.set_sys_probs(sys_probs, auto_prob_style) + # check batch and test size for ii in range(self.nsystems) : chk_ret = self.data_systems[ii].check_batch_size(self.batch_size[ii]) From 9d99823f1fe0b4a971f0bfe884d83af1e22999d9 Mon Sep 17 00:00:00 2001 From: ziyao Date: Thu, 15 Apr 2021 17:38:35 +0800 Subject: [PATCH 357/562] minor bug fixed --- deepmd/utils/data_system.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/deepmd/utils/data_system.py b/deepmd/utils/data_system.py index cea8903e04..728568c1da 100644 --- a/deepmd/utils/data_system.py +++ b/deepmd/utils/data_system.py @@ -421,7 +421,6 @@ def _format_name_length(self, name, width) : return name def print_summary(self) : - prob = self._get_sys_probs(self.sys_probs, self.auto_prob) # width 65 sys_width = 42 log.info("---Summary of DataSystem--------------------------------------------------------------") @@ -436,7 +435,7 @@ def print_summary(self) : self.batch_size[ii], self.nbatches[ii], self.test_size[ii], - prob[ii], + self.sys_probs[ii], "T" if self.data_systems[ii].pbc else "F" ) ) log.info("--------------------------------------------------------------------------------------") From 97b91fa2f829b56f721b372596c5cff933bbf111 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Thu, 15 Apr 2021 17:43:01 +0800 Subject: [PATCH 358/562] update requirement of dargs --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index f57f40b611..0bbdf12005 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ numpy scipy pyyaml -dargs >= 0.2.1 +dargs >= 0.2.2 tqdm typing_extensions From 202ec7342402fef94304d63ba0ed33766ffd5141 Mon Sep 17 00:00:00 2001 From: ziyao Date: Thu, 15 Apr 2021 17:44:58 +0800 Subject: [PATCH 359/562] dargs version corrected. --- deepmd/utils/argcheck.py | 3 ++- requirements.txt | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/deepmd/utils/argcheck.py b/deepmd/utils/argcheck.py index c36829ed32..6d8ea5ccbc 100644 --- a/deepmd/utils/argcheck.py +++ b/deepmd/utils/argcheck.py @@ -14,7 +14,8 @@ def list_to_doc(xx): def make_link(content, ref_key): - return f'`{content} <{ref_key}_>`_' # if not dargs.RAW_ANCHOR else f'`{content} <#{ref_key}>`_' + return f'`{content} <{ref_key}_>`_' if not dargs.RAW_ANCHOR \ + else f'`{content} <#{ref_key}>`_' # --- Descriptor configurations: --- # diff --git a/requirements.txt b/requirements.txt index f57f40b611..0bbdf12005 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ numpy scipy pyyaml -dargs >= 0.2.1 +dargs >= 0.2.2 tqdm typing_extensions From fcd475c068b940acd4a83e6391fd93a45e542090 Mon Sep 17 00:00:00 2001 From: ziyao Date: Thu, 15 Apr 2021 18:30:32 +0800 Subject: [PATCH 360/562] default prec. changed to high --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index e77b1b78a7..5f7f2fa8bc 100644 --- a/setup.py +++ b/setup.py @@ -101,7 +101,7 @@ f"-DTENSORFLOW_ROOT:STRING={tf_install_dir}", "-DBUILD_PY_IF:BOOL=TRUE", "-DBUILD_CPP_IF:BOOL=FALSE", - "-DFLOAT_PREC:STRING=low", + "-DFLOAT_PREC:STRING=high", ], cmake_source_dir="source", cmake_minimum_required_version="3.0", From a3d85cb50063439a292fa398e66500f239a4f952 Mon Sep 17 00:00:00 2001 From: ziyao Date: Thu, 15 Apr 2021 20:09:37 +0800 Subject: [PATCH 361/562] none validation supported; get_feed_dict optimized. --- deepmd/train/trainer.py | 70 ++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/deepmd/train/trainer.py b/deepmd/train/trainer.py index de7718d891..7997988c5e 100644 --- a/deepmd/train/trainer.py +++ b/deepmd/train/trainer.py @@ -449,8 +449,8 @@ def _init_sess_distrib(self): def train (self, train_data, valid_data=None) : - if valid_data is None: # no validation set specified. - valid_data = train_data # using training set as validation set. + # if valid_data is None: # no validation set specified. + # valid_data = train_data # using training set as validation set. stop_batch = self.stop_batch if self.run_opt.is_distrib : @@ -492,11 +492,14 @@ def train (self, train_data, valid_data=None) : train_time = 0 while cur_batch < stop_batch : - train_feed_dict, train_natoms = self.get_feed_dict(train_data, is_training=True) - if self.display_in_training and is_first_step : + + # first round validation: + if self.display_in_training and is_first_step: self.valid_on_the_fly(fp, train_data, valid_data, print_header=True) is_first_step = False - if self.timing_in_training : tic = time.time() + + if self.timing_in_training: tic = time.time() + train_feed_dict = self.get_feed_dict(train_data.get_batch(), is_training=True) # use tensorboard to visualize the training of deepmd-kit # it will takes some extra execution time to generate the tensorboard data if self.tensorboard : @@ -506,17 +509,19 @@ def train (self, train_data, valid_data=None) : else : self.sess.run([self.train_op], feed_dict=train_feed_dict, options=prf_options, run_metadata=prf_run_metadata) - if self.timing_in_training : toc = time.time() - if self.timing_in_training : train_time += toc - tic + if self.timing_in_training: toc = time.time() + if self.timing_in_training: train_time += toc - tic cur_batch = self.sess.run(self.global_step) self.cur_batch = cur_batch - if self.display_in_training and (cur_batch % self.disp_freq == 0) : - tic = time.time() + # on-the-fly validation + if self.display_in_training and (cur_batch % self.disp_freq == 0): + if self.timing_in_training: + tic = time.time() self.valid_on_the_fly(fp, train_data, valid_data) - toc = time.time() - test_time = toc - tic - if self.timing_in_training : + if self.timing_in_training: + toc = time.time() + test_time = toc - tic log.info("batch %7d training time %.2f s, testing time %.2f s" % (cur_batch, train_time, test_time)) train_time = 0 @@ -532,8 +537,7 @@ def train (self, train_data, valid_data=None) : with open(self.profiling_file, 'w') as f: f.write(chrome_trace) - def get_feed_dict (self, data, is_training) : - batch = data.get_batch() + def get_feed_dict(self, batch, is_training): feed_dict = {} for kk in batch.keys(): if kk == 'find_type' or kk == 'type': @@ -547,9 +551,9 @@ def get_feed_dict (self, data, is_training) : for ii in ['natoms_vec', 'default_mesh']: feed_dict[self.place_holders[ii]] = batch[ii] feed_dict[self.place_holders['is_training']] = is_training - return feed_dict, batch['natoms_vec'] + return feed_dict - def get_global_step (self) : + def get_global_step(self): return self.sess.run(self.global_step) # def print_head (self) : # depreciated @@ -572,16 +576,21 @@ def valid_on_the_fly(self, cur_batch = self.cur_batch current_lr = self.sess.run(self.learning_rate) if print_header: - self.print_header(fp, valid_results) + self.print_header(fp, train_results, valid_results) self.print_on_training(fp, train_results, valid_results, cur_batch, current_lr) @staticmethod - def print_header(fp, results): + def print_header(fp, train_results, valid_results): print_str = '' print_str += "# %5s" % 'batch' - prop_fmt = ' %11s %11s' - for k in results.keys(): - print_str += prop_fmt % (k + '_val', k + '_trn') + if valid_results is not None: + prop_fmt = ' %11s %11s' + for k in train_results.keys(): + print_str += prop_fmt % (k + '_val', k + '_trn') + else: + prop_fmt = ' %11s' + for k in train_results.keys(): + print_str += prop_fmt % (k + '_trn') print_str += ' %8s\n' % 'lr' fp.write(print_str) fp.flush() @@ -590,18 +599,27 @@ def print_header(fp, results): def print_on_training(fp, train_results, valid_results, cur_batch, cur_lr): print_str = '' print_str += "%7d" % cur_batch - prop_fmt = " %11.2e %11.2e" - for k in valid_results.keys(): - # assert k in train_results.keys() - print_str += prop_fmt % (valid_results[k], train_results[k]) + if valid_results is not None: + prop_fmt = " %11.2e %11.2e" + for k in valid_results.keys(): + # assert k in train_results.keys() + print_str += prop_fmt % (valid_results[k], train_results[k]) + else: + prop_fmt = " %11.2e" + for k in train_results.keys(): + print_str += prop_fmt % (train_results[k]) print_str += " %8.1e\n" % cur_lr fp.write(print_str) fp.flush() def get_evaluation_results(self, data, numb_batch): + if data is None: + return None sum_results = None for i in range(numb_batch): - feed_dict, natoms = self.get_feed_dict(data, is_training=False) + batch = data.get_batch() + natoms = batch["natoms_vec"] + feed_dict = self.get_feed_dict(batch, is_training=False) results = self.loss.eval(self.sess, feed_dict, natoms) if sum_results is None: sum_results = results From 3925ada7d2f32a1ddb5c2fbbf3a9835855f07822 Mon Sep 17 00:00:00 2001 From: ziyao Date: Thu, 15 Apr 2021 20:22:54 +0800 Subject: [PATCH 362/562] get_evaluation_rst altered to derive atomic avg. --- deepmd/train/trainer.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/deepmd/train/trainer.py b/deepmd/train/trainer.py index 7997988c5e..efde63106e 100644 --- a/deepmd/train/trainer.py +++ b/deepmd/train/trainer.py @@ -615,16 +615,16 @@ def print_on_training(fp, train_results, valid_results, cur_batch, cur_lr): def get_evaluation_results(self, data, numb_batch): if data is None: return None - sum_results = None + sum_natoms = 0 # total #atoms + sum_results = {} # sum of losses on all atoms for i in range(numb_batch): batch = data.get_batch() - natoms = batch["natoms_vec"] + natoms = int(batch["natoms_vec"][0]) feed_dict = self.get_feed_dict(batch, is_training=False) results = self.loss.eval(self.sess, feed_dict, natoms) - if sum_results is None: - sum_results = results - else: - for k, v in results: - sum_results[k] += v - avg_results = {k: v / numb_batch for k, v in sum_results.items()} + + sum_natoms += natoms + for k, v in results: + sum_results[k] = sum_results.get(k, 0.) + v * natoms + avg_results = {k: v / sum_natoms for k, v in sum_results.items()} return avg_results \ No newline at end of file From 0ee7f84bd6bc8b7f403827745a23130cca01214f Mon Sep 17 00:00:00 2001 From: ziyao Date: Thu, 15 Apr 2021 20:31:31 +0800 Subject: [PATCH 363/562] atomic avg. derived in a compromised way. --- deepmd/loss/ener.py | 3 ++- deepmd/loss/tensor.py | 2 +- deepmd/train/trainer.py | 12 +++++------- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/deepmd/loss/ener.py b/deepmd/loss/ener.py index ea54494273..f4979e9b1a 100644 --- a/deepmd/loss/ener.py +++ b/deepmd/loss/ener.py @@ -137,7 +137,7 @@ def eval(self, sess, feed_dict, natoms): self.l2_more['l2_pref_force_loss'] ] error, error_e, error_f, error_v, error_ae, error_pf = sess.run(run_data, feed_dict=feed_dict) - results = {"rmse": np.sqrt(error)} + results = {"natoms": natoms[0], "rmse": np.sqrt(error)} if self.has_e: results["rmse_e"] = np.sqrt(error_e) / natoms[0] if self.has_ae: @@ -299,6 +299,7 @@ def eval(self, sess, feed_dict, natoms): ] error, error_e, error_ed = sess.run(run_data, feed_dict=feed_dict) results = { + 'natoms': natoms[0], 'rmse': np.sqrt(error), 'rmse_e': np.sqrt(error_e) / natoms[0], 'rmse_ed': np.sqrt(error_ed) diff --git a/deepmd/loss/tensor.py b/deepmd/loss/tensor.py index 7652e9cfcf..1a97881c3a 100644 --- a/deepmd/loss/tensor.py +++ b/deepmd/loss/tensor.py @@ -141,7 +141,7 @@ def eval(self, sess, feed_dict, natoms): run_data = [self.l2_l, self.l2_more['local_loss'], self.l2_more['global_loss']] error, error_lc, error_gl = sess.run(run_data, feed_dict=feed_dict) - results = {"rmse": np.sqrt(error)} + results = {"natoms": atoms, "rmse": np.sqrt(error)} if self.local_weight > 0.0: results["rmse_lc"] = np.sqrt(error_lc) if self.global_weight > 0.0: diff --git a/deepmd/train/trainer.py b/deepmd/train/trainer.py index efde63106e..6912346525 100644 --- a/deepmd/train/trainer.py +++ b/deepmd/train/trainer.py @@ -613,18 +613,16 @@ def print_on_training(fp, train_results, valid_results, cur_batch, cur_lr): fp.flush() def get_evaluation_results(self, data, numb_batch): - if data is None: - return None - sum_natoms = 0 # total #atoms + if data is None: return None + sum_results = {} # sum of losses on all atoms for i in range(numb_batch): batch = data.get_batch() - natoms = int(batch["natoms_vec"][0]) + natoms = batch["natoms_vec"] feed_dict = self.get_feed_dict(batch, is_training=False) results = self.loss.eval(self.sess, feed_dict, natoms) - sum_natoms += natoms for k, v in results: - sum_results[k] = sum_results.get(k, 0.) + v * natoms - avg_results = {k: v / sum_natoms for k, v in sum_results.items()} + sum_results[k] = sum_results.get(k, 0.) + v * results["natoms"] + avg_results = {k: v / sum_results["natoms"] for k, v in sum_results.items() if not k == "natoms"} return avg_results \ No newline at end of file From 80c725f31db159270517beb3c920fad826f5ba59 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 16 Apr 2021 10:37:47 +0800 Subject: [PATCH 364/562] seperate impl of averging errors across systems --- deepmd/entrypoints/test.py | 81 +++++++++++++------------------------- deepmd/utils/weight_avg.py | 34 ++++++++++++++++ 2 files changed, 62 insertions(+), 53 deletions(-) create mode 100644 deepmd/utils/weight_avg.py diff --git a/deepmd/entrypoints/test.py b/deepmd/entrypoints/test.py index 62687866a8..052559f9bb 100644 --- a/deepmd/entrypoints/test.py +++ b/deepmd/entrypoints/test.py @@ -1,12 +1,13 @@ """Test trained DeePMD model.""" import logging from pathlib import Path -from typing import TYPE_CHECKING, List, Optional, Tuple +from typing import TYPE_CHECKING, List, Dict, Optional, Tuple import numpy as np from deepmd import DeepPotential from deepmd.common import expand_sys_str from deepmd.utils.data import DeepmdData +from deepmd.utils.weight_avg import weighted_average if TYPE_CHECKING: from deepmd.infer import DeepDipole, DeepPolar, DeepPot, DeepWFC @@ -77,7 +78,7 @@ def test( data = DeepmdData(system, set_prefix, shuffle_test=shuffle_test, type_map=tmap) if dp.model_type == "ener": - err, siz = test_ener( + err = test_ener( dp, data, system, @@ -87,18 +88,15 @@ def test( append_detail=(cc != 0), ) elif dp.model_type == "dipole": - err, siz = test_dipole(dp, data, numb_test, detail_file, atomic) + err = test_dipole(dp, data, numb_test, detail_file, atomic) elif dp.model_type == "polar": - err, siz = test_polar(dp, data, numb_test, detail_file, global_polar=False) + err = test_polar(dp, data, numb_test, detail_file, global_polar=False) elif dp.model_type == "global_polar": - err, siz = test_polar(dp, data, numb_test, detail_file, global_polar=True) - elif dp.model_type == "wfc": - err, siz = test_wfc(dp, data, numb_test, detail_file) + err = test_polar(dp, data, numb_test, detail_file, global_polar=True) log.info("# ----------------------------------------------- ") err_coll.append(err) - siz_coll.append(siz) - avg_err = weighted_average(err_coll, siz_coll) + avg_err = weighted_average(err_coll) if len(all_sys) != len(err_coll): log.warning("Not all systems are tested! Check if the systems are valid") @@ -135,39 +133,6 @@ def l2err(diff: np.ndarray) -> np.ndarray: return np.sqrt(np.average(diff * diff)) -def weighted_average( - err_coll: List[List[np.ndarray]], siz_coll: List[List[int]] -) -> np.ndarray: - """Compute wighted average of prediction errors for model. - - Parameters - ---------- - err_coll : List[List[np.ndarray]] - each item in list represents erros for one model - siz_coll : List[List[int]] - weight for each model errors - - Returns - ------- - np.ndarray - weighted averages - """ - assert len(err_coll) == len(siz_coll) - - nitems = len(err_coll[0]) - sum_err = np.zeros(nitems) - sum_siz = np.zeros(nitems) - for sys_error, sys_size in zip(err_coll, siz_coll): - for ii in range(nitems): - ee = sys_error[ii] - ss = sys_size[ii] - sum_err[ii] += ee * ee * ss - sum_siz[ii] += ss - for ii in range(nitems): - sum_err[ii] = np.sqrt(sum_err[ii] / sum_siz[ii]) - return sum_err - - def save_txt_file( fname: Path, data: np.ndarray, header: str = "", append: bool = False ): @@ -344,10 +309,14 @@ def test_ener( "pred_vyy pred_vyz pred_vzx pred_vzy pred_vzz", append=append_detail, ) - return [l2ea, l2f, l2va], [energy.size, force.size, virial.size] + return { + "l2ea" : (l2ea, energy.size), + "l2f" : (l2f, force.size), + "l2va" : (l2va, virial.size), + } -def print_ener_sys_avg(avg: np.ndarray): +def print_ener_sys_avg(avg: Dict[str,float]): """Print errors summary for energy type potential. Parameters @@ -355,9 +324,9 @@ def print_ener_sys_avg(avg: np.ndarray): avg : np.ndarray array with summaries """ - log.info(f"Energy RMSE/Natoms : {avg[0]:e} eV") - log.info(f"Force RMSE : {avg[1]:e} eV/A") - log.info(f"Virial RMSE/Natoms : {avg[2]:e} eV") + log.info(f"Energy RMSE/Natoms : {avg['l2ea']:e} eV") + log.info(f"Force RMSE : {avg['l2f']:e} eV/A") + log.info(f"Virial RMSE/Natoms : {avg['l2va']:e} eV") def run_test(dp: "DeepTensor", test_data: dict, numb_test: int): @@ -436,7 +405,9 @@ def test_wfc( pe, header="ref_wfc(12 dofs) predicted_wfc(12 dofs)", ) - return [l2f], [wfc.size] + return { + 'l2' : (l2f, wfc.size) + } def print_wfc_sys_avg(avg): @@ -447,7 +418,7 @@ def print_wfc_sys_avg(avg): avg : np.ndarray array with summaries """ - log.info(f"WFC RMSE : {avg[0]:e} eV/A") + log.info(f"WFC RMSE : {avg['l2']:e} eV/A") def test_polar( @@ -531,7 +502,9 @@ def test_polar( "data_pzy data_pzz pred_pxx pred_pxy pred_pxz pred_pyx pred_pyy pred_pyz " "pred_pzx pred_pzy pred_pzz", ) - return [l2f], [polar.size] + return { + "l2" : (l2f, polar.size) + } def print_polar_sys_avg(avg): @@ -542,7 +515,7 @@ def print_polar_sys_avg(avg): avg : np.ndarray array with summaries """ - log.info(f"Polarizability RMSE : {avg[0]:e} eV/A") + log.info(f"Polarizability RMSE : {avg['l2']:e} eV/A") def test_dipole( @@ -607,7 +580,9 @@ def test_dipole( pe, header="data_x data_y data_z pred_x pred_y pred_z", ) - return [l2f], [dipole.size] + return { + 'l2' : (l2f, dipole.size) + } def print_dipole_sys_avg(avg): @@ -618,4 +593,4 @@ def print_dipole_sys_avg(avg): avg : np.ndarray array with summaries """ - log.info(f"Dipole RMSE : {avg[0]:e} eV/A") + log.info(f"Dipole RMSE : {avg['l2']:e} eV/A") diff --git a/deepmd/utils/weight_avg.py b/deepmd/utils/weight_avg.py new file mode 100644 index 0000000000..aec5026ae4 --- /dev/null +++ b/deepmd/utils/weight_avg.py @@ -0,0 +1,34 @@ +from typing import TYPE_CHECKING, List, Dict, Optional, Tuple +import numpy as np + + +def weighted_average( + errors: List[Dict[str, Tuple[float, float]]] +) -> Dict: + """Compute wighted average of prediction errors for model. + + Parameters + ---------- + errors : List[Dict[str, Tuple[float, float]]] + List: the error of systems + Dict: the error of quantities, name given by the key + Tuple: (error, weight) + + Returns + ------- + Dict + weighted averages + """ + sum_err = {} + sum_siz = {} + for err in errors: + for kk, (ee, ss) in err.items(): + if kk in sum_err: + sum_err[kk] += ee * ee * ss + sum_siz[kk] += ss + else : + sum_err[kk] = ee * ee * ss + sum_siz[kk] = ss + for kk in sum_err.keys(): + sum_err[kk] = np.sqrt(sum_err[kk] / sum_siz[kk]) + return sum_err From a8f1c68d12cfa655055d30e0a6d6ad35725d31b3 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 16 Apr 2021 15:47:18 +0800 Subject: [PATCH 365/562] change l2 error to rmse --- deepmd/entrypoints/test.py | 74 +++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/deepmd/entrypoints/test.py b/deepmd/entrypoints/test.py index 052559f9bb..134994aed1 100644 --- a/deepmd/entrypoints/test.py +++ b/deepmd/entrypoints/test.py @@ -117,8 +117,8 @@ def test( log.info("# ----------------------------------------------- ") -def l2err(diff: np.ndarray) -> np.ndarray: - """Calculate average l2 norm error. +def rmse(diff: np.ndarray) -> np.ndarray: + """Calculate average root mean square error. Parameters ---------- @@ -245,25 +245,25 @@ def test_ener( ae = ae.reshape([numb_test, -1]) av = av.reshape([numb_test, -1]) - l2e = l2err(energy - test_data["energy"][:numb_test].reshape([-1, 1])) - l2f = l2err(force - test_data["force"][:numb_test]) - l2v = l2err(virial - test_data["virial"][:numb_test]) - l2ea = l2e / natoms - l2va = l2v / natoms + rmse_e = rmse(energy - test_data["energy"][:numb_test].reshape([-1, 1])) + rmse_f = rmse(force - test_data["force"][:numb_test]) + rmse_v = rmse(virial - test_data["virial"][:numb_test]) + rmse_ea = rmse_e / natoms + rmse_va = rmse_v / natoms if has_atom_ener: - l2ae = l2err( + rmse_ae = rmse( test_data["atom_ener"][:numb_test].reshape([-1]) - ae.reshape([-1]) ) # print ("# energies: %s" % energy) log.info(f"# number of test data : {numb_test:d} ") - log.info(f"Energy RMSE : {l2e:e} eV") - log.info(f"Energy RMSE/Natoms : {l2ea:e} eV") - log.info(f"Force RMSE : {l2f:e} eV/A") - log.info(f"Virial RMSE : {l2v:e} eV") - log.info(f"Virial RMSE/Natoms : {l2va:e} eV") + log.info(f"Energy RMSE : {rmse_e:e} eV") + log.info(f"Energy RMSE/Natoms : {rmse_ea:e} eV") + log.info(f"Force RMSE : {rmse_f:e} eV/A") + log.info(f"Virial RMSE : {rmse_v:e} eV") + log.info(f"Virial RMSE/Natoms : {rmse_va:e} eV") if has_atom_ener: - log.info(f"Atomic ener RMSE : {l2ae:e} eV") + log.info(f"Atomic ener RMSE : {rmse_ae:e} eV") if detail_file is not None: detail_path = Path(detail_file) @@ -310,9 +310,9 @@ def test_ener( append=append_detail, ) return { - "l2ea" : (l2ea, energy.size), - "l2f" : (l2f, force.size), - "l2va" : (l2va, virial.size), + "rmse_ea" : (rmse_ea, energy.size), + "rmse_f" : (rmse_f, force.size), + "rmse_va" : (rmse_va, virial.size), } @@ -324,9 +324,9 @@ def print_ener_sys_avg(avg: Dict[str,float]): avg : np.ndarray array with summaries """ - log.info(f"Energy RMSE/Natoms : {avg['l2ea']:e} eV") - log.info(f"Force RMSE : {avg['l2f']:e} eV/A") - log.info(f"Virial RMSE/Natoms : {avg['l2va']:e} eV") + log.info(f"Energy RMSE/Natoms : {avg['rmse_ea']:e} eV") + log.info(f"Force RMSE : {avg['rmse_f']:e} eV/A") + log.info(f"Virial RMSE/Natoms : {avg['rmse_va']:e} eV") def run_test(dp: "DeepTensor", test_data: dict, numb_test: int): @@ -386,10 +386,10 @@ def test_wfc( ) test_data = data.get_test() wfc, numb_test, _ = run_test(dp, test_data, numb_test) - l2f = l2err(wfc - test_data["wfc"][:numb_test]) + rmse_f = rmse(wfc - test_data["wfc"][:numb_test]) log.info("# number of test data : {numb_test:d} ") - log.info("WFC RMSE : {l2f:e} eV/A") + log.info("WFC RMSE : {rmse_f:e} eV/A") if detail_file is not None: detail_path = Path(detail_file) @@ -406,7 +406,7 @@ def test_wfc( header="ref_wfc(12 dofs) predicted_wfc(12 dofs)", ) return { - 'l2' : (l2f, wfc.size) + 'rmse' : (rmse_f, wfc.size) } @@ -418,7 +418,7 @@ def print_wfc_sys_avg(avg): avg : np.ndarray array with summaries """ - log.info(f"WFC RMSE : {avg['l2']:e} eV/A") + log.info(f"WFC RMSE : {avg['rmse']:e} eV/A") def test_polar( @@ -475,15 +475,15 @@ def test_polar( for ii in sel_type: sel_natoms += sum(atype == ii) - l2f = l2err(polar - test_data["polarizability"][:numb_test]) - l2fs = l2f / np.sqrt(sel_natoms) - l2fa = l2f / sel_natoms + rmse_f = rmse(polar - test_data["polarizability"][:numb_test]) + rmse_fs = rmse_f / np.sqrt(sel_natoms) + rmse_fa = rmse_f / sel_natoms log.info(f"# number of test data : {numb_test:d} ") - log.info(f"Polarizability RMSE : {l2f:e} eV/A") + log.info(f"Polarizability RMSE : {rmse_f:e} eV/A") if global_polar: - log.info(f"Polarizability RMSE/sqrtN : {l2fs:e} eV/A") - log.info(f"Polarizability RMSE/N : {l2fa:e} eV/A") + log.info(f"Polarizability RMSE/sqrtN : {rmse_fs:e} eV/A") + log.info(f"Polarizability RMSE/N : {rmse_fa:e} eV/A") if detail_file is not None: detail_path = Path(detail_file) @@ -503,7 +503,7 @@ def test_polar( "pred_pzx pred_pzy pred_pzz", ) return { - "l2" : (l2f, polar.size) + "rmse_" : (rmse_f, polar.size) } @@ -515,7 +515,7 @@ def print_polar_sys_avg(avg): avg : np.ndarray array with summaries """ - log.info(f"Polarizability RMSE : {avg['l2']:e} eV/A") + log.info(f"Polarizability RMSE : {avg['rmse']:e} eV/A") def test_dipole( @@ -557,13 +557,13 @@ def test_dipole( atoms = dipole.shape[1] dipole = np.sum(dipole,axis=1) - l2f = l2err(dipole - test_data["dipole"][:numb_test]) + rmse_f = rmse(dipole - test_data["dipole"][:numb_test]) if has_atom_dipole == False: - l2f = l2f / atoms + rmse_f = rmse_f / atoms log.info(f"# number of test data : {numb_test:d}") - log.info(f"Dipole RMSE : {l2f:e} eV/A") + log.info(f"Dipole RMSE : {rmse_f:e} eV/A") if detail_file is not None: detail_path = Path(detail_file) @@ -581,7 +581,7 @@ def test_dipole( header="data_x data_y data_z pred_x pred_y pred_z", ) return { - 'l2' : (l2f, dipole.size) + 'rmse' : (rmse_f, dipole.size) } @@ -593,4 +593,4 @@ def print_dipole_sys_avg(avg): avg : np.ndarray array with summaries """ - log.info(f"Dipole RMSE : {avg['l2']:e} eV/A") + log.info(f"Dipole RMSE : {avg['rmse']:e} eV/A") From 21867881991627108e4c7e91cd3f181461e4f74d Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 16 Apr 2021 19:09:14 +0800 Subject: [PATCH 366/562] fix bug of returned key --- deepmd/entrypoints/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deepmd/entrypoints/test.py b/deepmd/entrypoints/test.py index 134994aed1..218d2974fe 100644 --- a/deepmd/entrypoints/test.py +++ b/deepmd/entrypoints/test.py @@ -503,7 +503,7 @@ def test_polar( "pred_pzx pred_pzy pred_pzz", ) return { - "rmse_" : (rmse_f, polar.size) + "rmse" : (rmse_f, polar.size) } From cfc677a905afac550235712abb3569c89a6bc8da Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 16 Apr 2021 20:15:11 +0800 Subject: [PATCH 367/562] bug fixings: 1, when valid data is not given; 2, bug related to iter over a dict. Not using ClassArg in trainer anymore --- deepmd/entrypoints/train.py | 4 ++-- deepmd/train/trainer.py | 31 +++++++------------------------ 2 files changed, 9 insertions(+), 26 deletions(-) diff --git a/deepmd/entrypoints/train.py b/deepmd/entrypoints/train.py index 1eb2941ab0..89a1de530d 100755 --- a/deepmd/entrypoints/train.py +++ b/deepmd/entrypoints/train.py @@ -250,7 +250,7 @@ def _do_work(jdata: Dict[str, Any], run_opt: RunOptions): # init data train_data = get_data(jdata["training"]["training_data"], rcut, ipt_type_map, modifier) train_data.print_summary() - if "validation_data" in jdata["training"]: + if jdata["training"]["validation_data"] is not None: valid_data = get_data(jdata["training"]["validation_data"], rcut, ipt_type_map, modifier) valid_data.print_summary() else: @@ -309,4 +309,4 @@ def get_modifier(modi_data=None): raise RuntimeError("unknown modifier type " + str(modi_data["type"])) else: modifier = None - return modifier \ No newline at end of file + return modifier diff --git a/deepmd/train/trainer.py b/deepmd/train/trainer.py index 6912346525..dfab8fbbba 100644 --- a/deepmd/train/trainer.py +++ b/deepmd/train/trainer.py @@ -235,31 +235,13 @@ def _init_param(self, jdata): raise RuntimeError('get unknown fitting type when building loss function') # training - training_param = j_must_have(jdata, 'training') - - # ! first .add() altered by Marián Rynik - tr_args = ClassArg()\ - .add('disp_file', str, default = 'lcurve.out')\ - .add('disp_freq', int, default = 100)\ - .add('save_freq', int, default = 1000)\ - .add('save_ckpt', str, default = 'model.ckpt')\ - .add('display_in_training', bool, default = True)\ - .add('timing_in_training', bool, default = True)\ - .add('profiling', bool, default = False)\ - .add('profiling_file',str, default = 'timeline.json')\ - .add('tensorboard', bool, default = False)\ - .add('tensorboard_log_dir',str, default = 'log') - # .add('sys_probs', list )\ - # .add('auto_prob', str, default = "prob_sys_size") - tr_data = tr_args.parse(training_param) - # not needed - # self.numb_test = tr_data['numb_test'] + tr_data = jdata['training'] self.disp_file = tr_data['disp_file'] self.disp_freq = tr_data['disp_freq'] self.save_freq = tr_data['save_freq'] self.save_ckpt = tr_data['save_ckpt'] - self.display_in_training = tr_data['display_in_training'] - self.timing_in_training = tr_data['timing_in_training'] + self.display_in_training = tr_data['disp_training'] + self.timing_in_training = tr_data['time_training'] self.profiling = tr_data['profiling'] self.profiling_file = tr_data['profiling_file'] self.tensorboard = tr_data['tensorboard'] @@ -272,11 +254,12 @@ def _init_param(self, jdata): else : self.numb_fparam = 0 - if "validation_data" in tr_data.keys(): # if validation set specified + if tr_data["validation_data"] is not None: self.valid_numb_batch = tr_data["validation_data"].get("numb_btch", 1) else: self.valid_numb_batch = 1 + def build (self, data, stop_batch = 0) : @@ -622,7 +605,7 @@ def get_evaluation_results(self, data, numb_batch): feed_dict = self.get_feed_dict(batch, is_training=False) results = self.loss.eval(self.sess, feed_dict, natoms) - for k, v in results: + for k, v in results.items(): sum_results[k] = sum_results.get(k, 0.) + v * results["natoms"] avg_results = {k: v / sum_results["natoms"] for k, v in sum_results.items() if not k == "natoms"} - return avg_results \ No newline at end of file + return avg_results From 634a006ca1711bce04d457a07620dc3a9b9ebe53 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Fri, 16 Apr 2021 22:58:17 +0800 Subject: [PATCH 368/562] add default values for trainer settings, in case we do not have argcheck normalization --- deepmd/train/trainer.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/deepmd/train/trainer.py b/deepmd/train/trainer.py index dfab8fbbba..91a7b3668f 100644 --- a/deepmd/train/trainer.py +++ b/deepmd/train/trainer.py @@ -236,16 +236,16 @@ def _init_param(self, jdata): # training tr_data = jdata['training'] - self.disp_file = tr_data['disp_file'] - self.disp_freq = tr_data['disp_freq'] - self.save_freq = tr_data['save_freq'] - self.save_ckpt = tr_data['save_ckpt'] - self.display_in_training = tr_data['disp_training'] - self.timing_in_training = tr_data['time_training'] - self.profiling = tr_data['profiling'] - self.profiling_file = tr_data['profiling_file'] - self.tensorboard = tr_data['tensorboard'] - self.tensorboard_log_dir = tr_data['tensorboard_log_dir'] + self.disp_file = tr_data.get('disp_file', 'lcurve.out') + self.disp_freq = tr_data.get('disp_freq', 1000) + self.save_freq = tr_data.get('save_freq', 1000) + self.save_ckpt = tr_data.get('save_ckpt', 'model.ckpt') + self.display_in_training = tr_data.get('disp_training', True) + self.timing_in_training = tr_data.get('time_training', True) + self.profiling = tr_data.get('profiling', False) + self.profiling_file = tr_data.get('profiling_file', 'timeline.json') + self.tensorboard = tr_data.get('tensorboard', False) + self.tensorboard_log_dir = tr_data.get('tensorboard_log_dir', 'log') # self.sys_probs = tr_data['sys_probs'] # self.auto_prob_style = tr_data['auto_prob'] self.useBN = False @@ -254,7 +254,7 @@ def _init_param(self, jdata): else : self.numb_fparam = 0 - if tr_data["validation_data"] is not None: + if tr_data.get("validation_data", None) is not None: self.valid_numb_batch = tr_data["validation_data"].get("numb_btch", 1) else: self.valid_numb_batch = 1 From 90f744bdff9cc1af250e443efd74e5dae8351c73 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 17 Apr 2021 16:36:46 +0800 Subject: [PATCH 369/562] print data summary with notation on the data systems --- deepmd/entrypoints/train.py | 4 ++-- deepmd/utils/data_system.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deepmd/entrypoints/train.py b/deepmd/entrypoints/train.py index 89a1de530d..31ee881d83 100755 --- a/deepmd/entrypoints/train.py +++ b/deepmd/entrypoints/train.py @@ -249,10 +249,10 @@ def _do_work(jdata: Dict[str, Any], run_opt: RunOptions): # init data train_data = get_data(jdata["training"]["training_data"], rcut, ipt_type_map, modifier) - train_data.print_summary() + train_data.print_summary("training") if jdata["training"]["validation_data"] is not None: valid_data = get_data(jdata["training"]["validation_data"], rcut, ipt_type_map, modifier) - valid_data.print_summary() + valid_data.print_summary("validation") else: valid_data = None diff --git a/deepmd/utils/data_system.py b/deepmd/utils/data_system.py index 728568c1da..4cdb9fb50f 100644 --- a/deepmd/utils/data_system.py +++ b/deepmd/utils/data_system.py @@ -420,10 +420,10 @@ def _format_name_length(self, name, width) : name = '-- ' + name return name - def print_summary(self) : + def print_summary(self, name) : # width 65 sys_width = 42 - log.info("---Summary of DataSystem--------------------------------------------------------------") + log.info(f"---Summary of DataSystem: {name:13s}-----------------------------------------------") log.info("found %d system(s):" % self.nsystems) log.info(("%s " % self._format_name_length('system', sys_width)) + ("%6s %6s %6s %6s %5s %3s" % ('natoms', 'bch_sz', 'n_bch', "n_test", 'prob', 'pbc'))) From fec85d48e79125bed797a691d571cf11a932e587 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 17 Apr 2021 20:39:49 +0800 Subject: [PATCH 370/562] printing the training error with exactly the batch used to train the model --- deepmd/entrypoints/train.py | 2 +- deepmd/train/trainer.py | 36 ++++++++++++++++++++++-------------- deepmd/utils/data_system.py | 5 ++--- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/deepmd/entrypoints/train.py b/deepmd/entrypoints/train.py index 31ee881d83..49fa3dd6c4 100755 --- a/deepmd/entrypoints/train.py +++ b/deepmd/entrypoints/train.py @@ -250,7 +250,7 @@ def _do_work(jdata: Dict[str, Any], run_opt: RunOptions): # init data train_data = get_data(jdata["training"]["training_data"], rcut, ipt_type_map, modifier) train_data.print_summary("training") - if jdata["training"]["validation_data"] is not None: + if jdata["training"].get("validation_data", None) is not None: valid_data = get_data(jdata["training"]["validation_data"], rcut, ipt_type_map, modifier) valid_data.print_summary("validation") else: diff --git a/deepmd/train/trainer.py b/deepmd/train/trainer.py index 91a7b3668f..a2510a4f49 100644 --- a/deepmd/train/trainer.py +++ b/deepmd/train/trainer.py @@ -258,7 +258,7 @@ def _init_param(self, jdata): self.valid_numb_batch = tr_data["validation_data"].get("numb_btch", 1) else: self.valid_numb_batch = 1 - + def build (self, data, @@ -477,12 +477,14 @@ def train (self, train_data, valid_data=None) : while cur_batch < stop_batch : # first round validation: + train_batch = train_data.get_batch() if self.display_in_training and is_first_step: - self.valid_on_the_fly(fp, train_data, valid_data, print_header=True) + valid_batch = [valid_data.get_batch() for ii in range(self.valid_numb_batch)] if valid_data is not None else None + self.valid_on_the_fly(fp, [train_batch], valid_batch, print_header=True) is_first_step = False if self.timing_in_training: tic = time.time() - train_feed_dict = self.get_feed_dict(train_data.get_batch(), is_training=True) + train_feed_dict = self.get_feed_dict(train_batch, is_training=True) # use tensorboard to visualize the training of deepmd-kit # it will takes some extra execution time to generate the tensorboard data if self.tensorboard : @@ -501,7 +503,8 @@ def train (self, train_data, valid_data=None) : if self.display_in_training and (cur_batch % self.disp_freq == 0): if self.timing_in_training: tic = time.time() - self.valid_on_the_fly(fp, train_data, valid_data) + valid_batch = [valid_data.get_batch() for ii in range(self.valid_numb_batch)] if valid_data is not None else None + self.valid_on_the_fly(fp, [train_batch], valid_batch) if self.timing_in_training: toc = time.time() test_time = toc - tic @@ -550,11 +553,11 @@ def get_global_step(self): def valid_on_the_fly(self, fp, - train_data, - valid_data, + train_batch, + valid_batch, print_header=False): - train_results = self.get_evaluation_results(train_data, self.valid_numb_batch) - valid_results = self.get_evaluation_results(valid_data, self.valid_numb_batch) + train_results = self.get_evaluation_results(train_batch) + valid_results = self.get_evaluation_results(valid_batch) cur_batch = self.cur_batch current_lr = self.sess.run(self.learning_rate) @@ -595,17 +598,22 @@ def print_on_training(fp, train_results, valid_results, cur_batch, cur_lr): fp.write(print_str) fp.flush() - def get_evaluation_results(self, data, numb_batch): - if data is None: return None + def get_evaluation_results(self, batch_list): + if batch_list is None: return None + numb_batch = len(batch_list) sum_results = {} # sum of losses on all atoms + sum_natoms = 0 for i in range(numb_batch): - batch = data.get_batch() + batch = batch_list[i] natoms = batch["natoms_vec"] feed_dict = self.get_feed_dict(batch, is_training=False) results = self.loss.eval(self.sess, feed_dict, natoms) - + for k, v in results.items(): - sum_results[k] = sum_results.get(k, 0.) + v * results["natoms"] - avg_results = {k: v / sum_results["natoms"] for k, v in sum_results.items() if not k == "natoms"} + if k == "natoms": + sum_natoms += v + else: + sum_results[k] = sum_results.get(k, 0.) + v * results["natoms"] + avg_results = {k: v / sum_natoms for k, v in sum_results.items() if not k == "natoms"} return avg_results diff --git a/deepmd/utils/data_system.py b/deepmd/utils/data_system.py index 4cdb9fb50f..8b84319eb2 100644 --- a/deepmd/utils/data_system.py +++ b/deepmd/utils/data_system.py @@ -426,15 +426,14 @@ def print_summary(self, name) : log.info(f"---Summary of DataSystem: {name:13s}-----------------------------------------------") log.info("found %d system(s):" % self.nsystems) log.info(("%s " % self._format_name_length('system', sys_width)) + - ("%6s %6s %6s %6s %5s %3s" % ('natoms', 'bch_sz', 'n_bch', "n_test", 'prob', 'pbc'))) + ("%6s %6s %6s %5s %3s" % ('natoms', 'bch_sz', 'n_bch', 'prob', 'pbc'))) for ii in range(self.nsystems) : - log.info("%s %6d %6d %6d %6d %5.3f %3s" % + log.info("%s %6d %6d %6d %5.3f %3s" % (self._format_name_length(self.system_dirs[ii], sys_width), self.natoms[ii], # TODO batch size * nbatches = number of structures self.batch_size[ii], self.nbatches[ii], - self.test_size[ii], self.sys_probs[ii], "T" if self.data_systems[ii].pbc else "F" ) ) From a1d21b9735843af571b4fafd9e44a8ef0b1a4d41 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 17 Apr 2021 23:01:40 +0800 Subject: [PATCH 371/562] fix 2 spacing issues --- deepmd/train/trainer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deepmd/train/trainer.py b/deepmd/train/trainer.py index a2510a4f49..6b04d45d23 100644 --- a/deepmd/train/trainer.py +++ b/deepmd/train/trainer.py @@ -258,7 +258,7 @@ def _init_param(self, jdata): self.valid_numb_batch = tr_data["validation_data"].get("numb_btch", 1) else: self.valid_numb_batch = 1 - + def build (self, data, @@ -609,7 +609,7 @@ def get_evaluation_results(self, batch_list): natoms = batch["natoms_vec"] feed_dict = self.get_feed_dict(batch, is_training=False) results = self.loss.eval(self.sess, feed_dict, natoms) - + for k, v in results.items(): if k == "natoms": sum_natoms += v From 8fc9bed592b790a201c92658ad3d376e2c669a2e Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 17 Apr 2021 23:19:56 +0800 Subject: [PATCH 372/562] more understandable variable names --- deepmd/train/trainer.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/deepmd/train/trainer.py b/deepmd/train/trainer.py index 6b04d45d23..5327094a16 100644 --- a/deepmd/train/trainer.py +++ b/deepmd/train/trainer.py @@ -479,8 +479,8 @@ def train (self, train_data, valid_data=None) : # first round validation: train_batch = train_data.get_batch() if self.display_in_training and is_first_step: - valid_batch = [valid_data.get_batch() for ii in range(self.valid_numb_batch)] if valid_data is not None else None - self.valid_on_the_fly(fp, [train_batch], valid_batch, print_header=True) + valid_batches = [valid_data.get_batch() for ii in range(self.valid_numb_batch)] if valid_data is not None else None + self.valid_on_the_fly(fp, [train_batch], valid_batches, print_header=True) is_first_step = False if self.timing_in_training: tic = time.time() @@ -503,8 +503,8 @@ def train (self, train_data, valid_data=None) : if self.display_in_training and (cur_batch % self.disp_freq == 0): if self.timing_in_training: tic = time.time() - valid_batch = [valid_data.get_batch() for ii in range(self.valid_numb_batch)] if valid_data is not None else None - self.valid_on_the_fly(fp, [train_batch], valid_batch) + valid_batches = [valid_data.get_batch() for ii in range(self.valid_numb_batch)] if valid_data is not None else None + self.valid_on_the_fly(fp, [train_batch], valid_batches) if self.timing_in_training: toc = time.time() test_time = toc - tic @@ -553,11 +553,11 @@ def get_global_step(self): def valid_on_the_fly(self, fp, - train_batch, - valid_batch, + train_batches, + valid_batches, print_header=False): - train_results = self.get_evaluation_results(train_batch) - valid_results = self.get_evaluation_results(valid_batch) + train_results = self.get_evaluation_results(train_batches) + valid_results = self.get_evaluation_results(valid_batches) cur_batch = self.cur_batch current_lr = self.sess.run(self.learning_rate) From dbe79960df55e1534ad25037d77875d0236f621a Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 19 Apr 2021 10:45:10 +0800 Subject: [PATCH 373/562] fix bug in se_t, add unittest --- deepmd/descriptor/se_a_t.py | 4 +- source/tests/test_model_se_t.py | 116 ++++++++++++++++++++++++++++++++ source/tests/water_se_t.json | 53 +++++++++++++++ 3 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 source/tests/test_model_se_t.py create mode 100644 source/tests/water_se_t.json diff --git a/deepmd/descriptor/se_a_t.py b/deepmd/descriptor/se_a_t.py index 2515126690..2dbea05b5a 100644 --- a/deepmd/descriptor/se_a_t.py +++ b/deepmd/descriptor/se_a_t.py @@ -95,7 +95,7 @@ def __init__ (self, self.place_holders['natoms_vec'] = tf.placeholder(tf.int32, [self.ntypes+2], name=name_pfx+'t_natoms') self.place_holders['default_mesh'] = tf.placeholder(tf.int32, [None], name=name_pfx+'t_mesh') self.stat_descrpt, descrpt_deriv, rij, nlist \ - = op_module.descrpt_se_a(self.place_holders['coord'], + = op_module.prod_env_mat_a(self.place_holders['coord'], self.place_holders['type'], self.place_holders['natoms_vec'], self.place_holders['box'], @@ -282,7 +282,7 @@ def build (self, atype = tf.reshape (atype_, [-1, natoms[1]]) self.descrpt, self.descrpt_deriv, self.rij, self.nlist \ - = op_module.descrpt_se_a (coord, + = op_module.prod_env_mat_a (coord, atype, natoms, box, diff --git a/source/tests/test_model_se_t.py b/source/tests/test_model_se_t.py new file mode 100644 index 0000000000..c6818846f7 --- /dev/null +++ b/source/tests/test_model_se_t.py @@ -0,0 +1,116 @@ +import dpdata,os,sys,unittest +import numpy as np +from deepmd.env import tf +from common import Data,gen_data, j_loader + +from deepmd.utils.data_system import DataSystem +from deepmd.descriptor import DescrptSeAT +from deepmd.fit import EnerFitting +from deepmd.model import EnerModel +from deepmd.common import j_must_have + +GLOBAL_ENER_FLOAT_PRECISION = tf.float64 +GLOBAL_TF_FLOAT_PRECISION = tf.float64 +GLOBAL_NP_FLOAT_PRECISION = np.float64 + +class TestModel(unittest.TestCase): + def setUp(self) : + gen_data() + + def test_model(self): + jfile = 'water_se_t.json' + jdata = j_loader(jfile) + + systems = j_must_have(jdata, 'systems') + set_pfx = j_must_have(jdata, 'set_prefix') + batch_size = j_must_have(jdata, 'batch_size') + test_size = j_must_have(jdata, 'numb_test') + batch_size = 1 + test_size = 1 + stop_batch = j_must_have(jdata, 'stop_batch') + rcut = j_must_have (jdata['model']['descriptor'], 'rcut') + + data = DataSystem(systems, set_pfx, batch_size, test_size, rcut, run_opt = None) + + test_data = data.get_test () + numb_test = 1 + + jdata['model']['descriptor'].pop('type', None) + descrpt = DescrptSeAT(**jdata['model']['descriptor']) + jdata['model']['fitting_net']['descrpt'] = descrpt + fitting = EnerFitting(**jdata['model']['fitting_net']) + model = EnerModel(descrpt, fitting) + + input_data = {'coord' : [test_data['coord']], + 'box': [test_data['box']], + 'type': [test_data['type']], + 'natoms_vec' : [test_data['natoms_vec']], + 'default_mesh' : [test_data['default_mesh']] + } + model._compute_input_stat(input_data) + model.descrpt.bias_atom_e = data.compute_energy_shift() + + t_prop_c = tf.placeholder(tf.float32, [5], name='t_prop_c') + t_energy = tf.placeholder(GLOBAL_ENER_FLOAT_PRECISION, [None], name='t_energy') + t_force = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_force') + t_virial = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_virial') + t_atom_ener = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='t_atom_ener') + t_coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name='i_coord') + t_type = tf.placeholder(tf.int32, [None], name='i_type') + t_natoms = tf.placeholder(tf.int32, [model.ntypes+2], name='i_natoms') + t_box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, 9], name='i_box') + t_mesh = tf.placeholder(tf.int32, [None], name='i_mesh') + is_training = tf.placeholder(tf.bool) + t_fparam = None + + model_pred\ + = model.build (t_coord, + t_type, + t_natoms, + t_box, + t_mesh, + t_fparam, + suffix = "se_r", + reuse = False) + energy = model_pred['energy'] + force = model_pred['force'] + virial = model_pred['virial'] + atom_ener = model_pred['atom_ener'] + + feed_dict_test = {t_prop_c: test_data['prop_c'], + t_energy: test_data['energy'] [:numb_test], + t_force: np.reshape(test_data['force'] [:numb_test, :], [-1]), + t_virial: np.reshape(test_data['virial'] [:numb_test, :], [-1]), + t_atom_ener: np.reshape(test_data['atom_ener'][:numb_test, :], [-1]), + t_coord: np.reshape(test_data['coord'] [:numb_test, :], [-1]), + t_box: test_data['box'] [:numb_test, :], + t_type: np.reshape(test_data['type'] [:numb_test, :], [-1]), + t_natoms: test_data['natoms_vec'], + t_mesh: test_data['default_mesh'], + is_training: False} + + sess = tf.Session() + sess.run(tf.global_variables_initializer()) + [e, f, v] = sess.run([energy, force, virial], + feed_dict = feed_dict_test) + + e = e.reshape([-1]) + f = f.reshape([-1]) + v = v.reshape([-1]) + np.savetxt('e.out', e.reshape([1, -1])) + np.savetxt('f.out', f.reshape([1, -1]), delimiter = ',') + np.savetxt('v.out', v.reshape([1, -1]), delimiter = ',') + refe = [4.826771866004193612e+01] + reff = [5.355088169393570574e+00,5.606772412401632266e+00,2.703270748296462966e-01,5.381408138049708967e+00,5.261355614357515975e+00,-4.079549918988090162e-01,-5.182324474551911919e+00,3.695481388907447262e-01,-5.238474288082559799e-02,1.665564584447352670e-01,-5.955401876564963892e+00,-2.217626865156164251e-01,-5.967343479332643419e+00,9.073821102416884665e-02,3.703103995504785639e-01,2.466151879965444438e-01,-5.373012500109097367e+00,4.146494691512622732e-02] + refv = [-1.336768232407933077e+01,4.818050125305787801e-01,3.589284283410607568e-01,4.818050125305786691e-01,-1.225345559839458964e+01,-1.701405121682751653e-01,3.589284283410607568e-01,-1.701405121682752486e-01,-3.428455515842296353e-02] + refe = np.reshape(refe, [-1]) + reff = np.reshape(reff, [-1]) + refv = np.reshape(refv, [-1]) + + places = 6 + for ii in range(e.size) : + self.assertAlmostEqual(e[ii], refe[ii], places = places) + for ii in range(f.size) : + self.assertAlmostEqual(f[ii], reff[ii], places = places) + for ii in range(v.size) : + self.assertAlmostEqual(v[ii], refv[ii], places = places) diff --git a/source/tests/water_se_t.json b/source/tests/water_se_t.json new file mode 100644 index 0000000000..99b2571091 --- /dev/null +++ b/source/tests/water_se_t.json @@ -0,0 +1,53 @@ +{ + "_comment": " model parameters", + "model" : { + "descriptor" : { + "type": "se_3be", + "sel": [40, 80], + "rcut_smth": 0.50, + "rcut": 6.00, + "neuron": [2, 4, 8], + "resnet_dt": false, + "seed": 1 + }, + "fitting_net" : { + "neuron": [240, 240, 240], + "resnet_dt": true, + "seed": 1 + } + }, + + "_comment": " traing controls", + "systems": ["system"], + "set_prefix": "set", + "stop_batch": 1000000, + "batch_size": 1, + "start_lr": 0.005, + "decay_steps": 5000, + "decay_rate": 0.95, + + "start_pref_e": 0.02, + "limit_pref_e": 1, + "start_pref_f": 1000, + "limit_pref_f": 1, + "start_pref_v": 0, + "limit_pref_v": 0, + + "seed": 1, + + "_comment": " display and restart", + "_comment": " frequencies counted in batch", + "disp_file": "lcurve.out", + "disp_freq": 100, + "numb_test": 1, + "save_freq": 1000, + "save_ckpt": "model.ckpt", + "load_ckpt": "model.ckpt", + "disp_training": true, + "time_training": true, + "profiling": false, + "profiling_file": "timeline.json", + + "_comment": "that's all" +} + From 5df5fafabd5f931b78b19621c520d8f23eaa4a04 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 19 Apr 2021 10:45:39 +0800 Subject: [PATCH 374/562] fix bug in lcurve.out output --- deepmd/train/trainer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deepmd/train/trainer.py b/deepmd/train/trainer.py index 5327094a16..c832b01fc8 100644 --- a/deepmd/train/trainer.py +++ b/deepmd/train/trainer.py @@ -568,7 +568,7 @@ def valid_on_the_fly(self, @staticmethod def print_header(fp, train_results, valid_results): print_str = '' - print_str += "# %5s" % 'batch' + print_str += "# %5s" % 'step' if valid_results is not None: prop_fmt = ' %11s %11s' for k in train_results.keys(): From cfde37b2b134d9672cfa5aeab306c90f9ce3f3e8 Mon Sep 17 00:00:00 2001 From: ZiyaoLi Date: Mon, 19 Apr 2021 15:13:13 +0800 Subject: [PATCH 375/562] clean compat v1 -> v2 implemented --- deepmd/entrypoints/train.py | 5 +-- deepmd/utils/compat.py | 87 +++++++++++++++++++++++++++---------- 2 files changed, 66 insertions(+), 26 deletions(-) diff --git a/deepmd/entrypoints/train.py b/deepmd/entrypoints/train.py index 49fa3dd6c4..a99ce6eae8 100755 --- a/deepmd/entrypoints/train.py +++ b/deepmd/entrypoints/train.py @@ -15,7 +15,7 @@ from deepmd.train.run_options import BUILD, CITATION, WELCOME, RunOptions from deepmd.train.trainer import DPTrainer from deepmd.utils.argcheck import normalize -from deepmd.utils.compat import convert_input_v0_v1 +from deepmd.utils.compat import updata_deepmd_input from deepmd.utils.data_system import DeepmdDataSystem if TYPE_CHECKING: @@ -168,8 +168,7 @@ def train( # load json database jdata = j_loader(INPUT) - if "model" not in jdata.keys(): - jdata = convert_input_v0_v1(jdata, warning=True, dump="input_v1_compat.json") + jdata = updata_deepmd_input(jdata, warning=True, dump="input_v2_compat.json") jdata = normalize(jdata) with open(output, "w") as fp: diff --git a/deepmd/utils/compat.py b/deepmd/utils/compat.py index 782f973f69..861a00439c 100644 --- a/deepmd/utils/compat.py +++ b/deepmd/utils/compat.py @@ -12,7 +12,6 @@ def convert_input_v0_v1( jdata: Dict[str, Any], warning: bool = True, dump: Optional[Union[str, Path]] = None ) -> Dict[str, Any]: """Convert input from v0 format to v1. - Parameters ---------- jdata : Dict[str, Any] @@ -21,12 +20,12 @@ def convert_input_v0_v1( whether to show deprecation warning, by default True dump : Optional[Union[str, Path]], optional whether to dump converted file, by default None - Returns ------- Dict[str, Any] converted output """ + output = {} if "with_distrib" in jdata: output["with_distrib"] = jdata["with_distrib"] @@ -35,18 +34,16 @@ def convert_input_v0_v1( output["loss"] = _loss(jdata) output["training"] = _training(jdata) if warning: - _warnning_input_v0_v1(dump) + _warning_input_v0_v1(dump) if dump is not None: with open(dump, "w") as fp: json.dump(output, fp, indent=4) return output -def _warnning_input_v0_v1(fname: Optional[Union[str, Path]]): - msg = ( - "It seems that you are using a deepmd-kit input of version 0.x.x, " - "which is deprecated. we have converted the input to >1.0.0 compatible" - ) +def _warning_input_v0_v1(fname: Optional[Union[str, Path]]): + msg = "It seems that you are using a deepmd-kit input of version 0.x.x, " \ + "which is deprecated. we have converted the input to >2.0.0 compatible" if fname is not None: msg += f", and output it to file {fname}" warnings.warn(msg) @@ -54,14 +51,12 @@ def _warnning_input_v0_v1(fname: Optional[Union[str, Path]]): def _model(jdata: Dict[str, Any], smooth: bool) -> Dict[str, Dict[str, Any]]: """Convert data to v1 input for non-smooth model. - Parameters ---------- jdata : Dict[str, Any] parsed input json/yaml data smooth : bool whether to use smooth or non-smooth descriptor version - Returns ------- Dict[str, Dict[str, Any]] @@ -78,12 +73,10 @@ def _model(jdata: Dict[str, Any], smooth: bool) -> Dict[str, Dict[str, Any]]: def _nonsmth_descriptor(jdata: Dict[str, Any]) -> Dict[str, Any]: """Convert data to v1 input for non-smooth descriptor. - Parameters ---------- jdata : Dict[str, Any] parsed input json/yaml data - Returns ------- Dict[str, Any] @@ -97,12 +90,10 @@ def _nonsmth_descriptor(jdata: Dict[str, Any]) -> Dict[str, Any]: def _smth_descriptor(jdata: Dict[str, Any]) -> Dict[str, Any]: """Convert data to v1 input for smooth descriptor. - Parameters ---------- jdata : Dict[str, Any] parsed input json/yaml data - Returns ------- Dict[str, Any] @@ -127,12 +118,10 @@ def _smth_descriptor(jdata: Dict[str, Any]) -> Dict[str, Any]: def _fitting_net(jdata: Dict[str, Any]) -> Dict[str, Any]: """Convert data to v1 input for fitting net. - Parameters ---------- jdata : Dict[str, Any] parsed input json/yaml data - Returns ------- Dict[str, Any] @@ -154,12 +143,10 @@ def _fitting_net(jdata: Dict[str, Any]) -> Dict[str, Any]: def _learning_rate(jdata: Dict[str, Any]) -> Dict[str, Any]: """Convert data to v1 input for learning rate section. - Parameters ---------- jdata : Dict[str, Any] parsed input json/yaml data - Returns ------- Dict[str, Any] @@ -173,12 +160,10 @@ def _learning_rate(jdata: Dict[str, Any]) -> Dict[str, Any]: def _loss(jdata: Dict[str, Any]) -> Dict[str, Any]: """Convert data to v1 input for loss function. - Parameters ---------- jdata : Dict[str, Any] parsed input json/yaml data - Returns ------- Dict[str, Any] @@ -206,12 +191,10 @@ def _loss(jdata: Dict[str, Any]) -> Dict[str, Any]: def _training(jdata: Dict[str, Any]) -> Dict[str, Any]: """Convert data to v1 input for training. - Parameters ---------- jdata : Dict[str, Any] parsed input json/yaml data - Returns ------- Dict[str, Any] @@ -241,7 +224,6 @@ def _training(jdata: Dict[str, Any]) -> Dict[str, Any]: def _jcopy(src: Dict[str, Any], dst: Dict[str, Any], keys: Sequence[str]): """Copy specified keys from one dict to another. - Parameters ---------- src : Dict[str, Any] @@ -255,3 +237,62 @@ def _jcopy(src: Dict[str, Any], dst: Dict[str, Any], keys: Sequence[str]): """ for k in keys: dst[k] = src[k] + + +def convert_input_v1_v2(jdata: Dict[str, Any], + warning: bool = True, + dump: Optional[Union[str, Path]] = None) -> Dict[str, Any]: + + tr_cfg = jdata["training"] + tr_data_keys = { + "systems", + "set_prefix", + "batch_size", + "sys_prob", + "auto_prob", + # alias included + "sys_weights", + "auto_prob_style" + } + + tr_data_cfg = {k: v for k, v in tr_cfg.items() if k in tr_data_keys} + new_tr_cfg = {k: v for k, v in tr_cfg.items() if k not in tr_data_keys} + new_tr_cfg["training_data"] = tr_data_cfg + + jdata["training"] = new_tr_cfg + + if warning: + _warning_input_v1_v2(dump) + if dump is not None: + with open(dump, "w") as fp: + json.dump(jdata, fp, indent=4) + + return jdata + + +def _warning_input_v1_v2(fname: Optional[Union[str, Path]]): + msg = "It seems that you are using a deepmd-kit input of version 1.x.x, " \ + "which is deprecated. we have converted the input to >2.0.0 compatible" + if fname is not None: + msg += f", and output it to file {fname}" + warnings.warn(msg) + + +def updata_deepmd_input(jdata: Dict[str, Any], + warning: bool = True, + dump: Optional[Union[str, Path]] = None) -> Dict[str, Any]: + def is_deepmd_v0_input(jdata): + return "model" not in jdata.keys() + + def is_deepmd_v1_input(jdata): + return "systems" in j_must_have(jdata, "training").keys() + + if is_deepmd_v0_input(jdata): + jdata = convert_input_v0_v1(jdata, warning, None) + jdata = convert_input_v1_v2(jdata, False, dump) + elif is_deepmd_v1_input(jdata): + jdata = convert_input_v1_v2(jdata, warning, dump) + else: + pass + + return jdata From b6211c24333d24861933f3cbf576ddb46d497e6c Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 19 Apr 2021 15:29:21 +0800 Subject: [PATCH 376/562] change name : se_a_t -> se_t --- deepmd/descriptor/__init__.py | 16 ++++++++-------- deepmd/descriptor/hybrid.py | 14 +++++++------- deepmd/descriptor/{se_a_t.py => se_t.py} | 2 +- deepmd/train/trainer.py | 6 +++--- deepmd/utils/argcheck.py | 8 ++++---- 5 files changed, 23 insertions(+), 23 deletions(-) rename deepmd/descriptor/{se_a_t.py => se_t.py} (99%) diff --git a/deepmd/descriptor/__init__.py b/deepmd/descriptor/__init__.py index b08ca170f1..7c3d910091 100644 --- a/deepmd/descriptor/__init__.py +++ b/deepmd/descriptor/__init__.py @@ -1,9 +1,9 @@ -from .hybrid import DescrptHybrid -from .se_a import DescrptSeA -from .se_r import DescrptSeR -from .se_ar import DescrptSeAR -from .se_a_t import DescrptSeAT -from .se_a_ebd import DescrptSeAEbd -from .se_a_ef import DescrptSeAEf -from .se_a_ef import DescrptSeAEfLower +from .hybrid import DescrptHybrid +from .se_a import DescrptSeA +from .se_r import DescrptSeR +from .se_ar import DescrptSeAR +from .se_t import DescrptSeT +from .se_a_ebd import DescrptSeAEbd +from .se_a_ef import DescrptSeAEf +from .se_a_ef import DescrptSeAEfLower from .loc_frame import DescrptLocFrame diff --git a/deepmd/descriptor/hybrid.py b/deepmd/descriptor/hybrid.py index 0b9a5bb508..a0748591e5 100644 --- a/deepmd/descriptor/hybrid.py +++ b/deepmd/descriptor/hybrid.py @@ -8,16 +8,16 @@ from deepmd.env import GLOBAL_NP_FLOAT_PRECISION # from deepmd.descriptor import DescrptLocFrame # from deepmd.descriptor import DescrptSeA -# from deepmd.descriptor import DescrptSeAT +# from deepmd.descriptor import DescrptSeT # from deepmd.descriptor import DescrptSeAEbd # from deepmd.descriptor import DescrptSeAEf # from deepmd.descriptor import DescrptSeR -from .se_a import DescrptSeA -from .se_r import DescrptSeR -from .se_ar import DescrptSeAR -from .se_a_t import DescrptSeAT -from .se_a_ebd import DescrptSeAEbd -from .se_a_ef import DescrptSeAEf +from .se_a import DescrptSeA +from .se_r import DescrptSeR +from .se_ar import DescrptSeAR +from .se_t import DescrptSeT +from .se_a_ebd import DescrptSeAEbd +from .se_a_ef import DescrptSeAEf from .loc_frame import DescrptLocFrame class DescrptHybrid (): diff --git a/deepmd/descriptor/se_a_t.py b/deepmd/descriptor/se_t.py similarity index 99% rename from deepmd/descriptor/se_a_t.py rename to deepmd/descriptor/se_t.py index 2dbea05b5a..f680d83db6 100644 --- a/deepmd/descriptor/se_a_t.py +++ b/deepmd/descriptor/se_t.py @@ -10,7 +10,7 @@ from deepmd.env import default_tf_session_config from deepmd.utils.network import embedding_net -class DescrptSeAT (): +class DescrptSeT (): @docstring_parameter(list_to_doc(ACTIVATION_FN_DICT.keys()), list_to_doc(PRECISION_DICT.keys())) def __init__ (self, rcut: float, diff --git a/deepmd/train/trainer.py b/deepmd/train/trainer.py index c832b01fc8..eb88aca92e 100644 --- a/deepmd/train/trainer.py +++ b/deepmd/train/trainer.py @@ -11,7 +11,7 @@ from deepmd.fit import EnerFitting, WFCFitting, PolarFittingLocFrame, PolarFittingSeA, GlobalPolarFittingSeA, DipoleFittingSeA from deepmd.descriptor import DescrptLocFrame from deepmd.descriptor import DescrptSeA -from deepmd.descriptor import DescrptSeAT +from deepmd.descriptor import DescrptSeT from deepmd.descriptor import DescrptSeAEbd from deepmd.descriptor import DescrptSeAEf from deepmd.descriptor import DescrptSeR @@ -57,8 +57,8 @@ def _generate_descrpt_from_param_dict(descrpt_param): descrpt = DescrptLocFrame(**descrpt_param) elif descrpt_type == 'se_a' : descrpt = DescrptSeA(**descrpt_param) - elif descrpt_type == 'se_a_3be' or descrpt_type == 'se_at' : - descrpt = DescrptSeAT(**descrpt_param) + elif descrpt_type == 'se_a_3be' or descrpt_type == 'se_at' or descrpt_type == 'se_t' : + descrpt = DescrptSeT(**descrpt_param) elif descrpt_type == 'se_a_tpe' or descrpt_type == 'se_a_ebd' : descrpt = DescrptSeAEbd(**descrpt_param) elif descrpt_type == 'se_a_ef' : diff --git a/deepmd/utils/argcheck.py b/deepmd/utils/argcheck.py index 6d8ea5ccbc..dca1508a03 100644 --- a/deepmd/utils/argcheck.py +++ b/deepmd/utils/argcheck.py @@ -71,7 +71,7 @@ def descrpt_se_a_args(): ] -def descrpt_se_a_3be_args(): +def descrpt_se_t_args(): doc_sel = 'A list of integers. The length of the list should be the same as the number of atom types in the system. `sel[i]` gives the selected number of type-i neighbors. `sel[i]` is recommended to be larger than the maximally possible number of type-i neighbors in the cut-off radius.' doc_rcut = 'The cut-off radius.' doc_rcut_smth = 'Where to start smoothing. For example the 1/r term is smoothed from `rcut` to `rcut_smth`' @@ -164,14 +164,14 @@ def descrpt_variant_type_args(): link_lf = make_link('loc_frame', 'model/descriptor[loc_frame]') link_se_a = make_link('se_a', 'model/descriptor[se_a]') link_se_r = make_link('se_r', 'model/descriptor[se_r]') - link_se_a_3be = make_link('se_a_3be', 'model/descriptor[se_a_3be]') + link_se_t = make_link('se_t', 'model/descriptor[se_t]') link_se_a_tpe = make_link('se_a_tpe', 'model/descriptor[se_a_tpe]') link_hybrid = make_link('hybrid', 'model/descriptor[hybrid]') doc_descrpt_type = f'The type of the descritpor. See explanation below. \n\n\ - `loc_frame`: Defines a local frame at each atom, and the compute the descriptor as local coordinates under this frame.\n\n\ - `se_a`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor.\n\n\ - `se_r`: Used by the smooth edition of Deep Potential. Only the distance between atoms is used to construct the descriptor.\n\n\ -- `se_a_3be`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Three-body embedding will be used by this descriptor.\n\n\ +- `se_t`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Three-body embedding will be used by this descriptor.\n\n\ - `se_a_tpe`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Type embedding will be used by this descriptor.\n\n\ - `hybrid`: Concatenate of a list of descriptors as a new descriptor.' @@ -179,7 +179,7 @@ def descrpt_variant_type_args(): Argument("loc_frame", dict, descrpt_local_frame_args()), Argument("se_a", dict, descrpt_se_a_args()), Argument("se_r", dict, descrpt_se_r_args()), - Argument("se_a_3be", dict, descrpt_se_a_3be_args(), alias = ['se_at']), + Argument("se_t", dict, descrpt_se_t_args(), alias = ['se_at', 'se_a_3be']), Argument("se_a_tpe", dict, descrpt_se_a_tpe_args(), alias = ['se_a_ebd']), Argument("hybrid", dict, descrpt_hybrid_args()), ], doc = doc_descrpt_type) From a56ae4f5b00def39aa1ad07ddae4a2bbfb3d37fa Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 19 Apr 2021 15:41:13 +0800 Subject: [PATCH 377/562] fix bug in ut --- source/tests/test_model_se_t.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/tests/test_model_se_t.py b/source/tests/test_model_se_t.py index c6818846f7..3708e1e5e7 100644 --- a/source/tests/test_model_se_t.py +++ b/source/tests/test_model_se_t.py @@ -4,7 +4,7 @@ from common import Data,gen_data, j_loader from deepmd.utils.data_system import DataSystem -from deepmd.descriptor import DescrptSeAT +from deepmd.descriptor import DescrptSeT from deepmd.fit import EnerFitting from deepmd.model import EnerModel from deepmd.common import j_must_have @@ -36,7 +36,7 @@ def test_model(self): numb_test = 1 jdata['model']['descriptor'].pop('type', None) - descrpt = DescrptSeAT(**jdata['model']['descriptor']) + descrpt = DescrptSeT(**jdata['model']['descriptor']) jdata['model']['fitting_net']['descrpt'] = descrpt fitting = EnerFitting(**jdata['model']['fitting_net']) model = EnerModel(descrpt, fitting) From bb71df30eeba7d8e0e920e7d1fba7f0df3a77dab Mon Sep 17 00:00:00 2001 From: ZiyaoLi Date: Mon, 19 Apr 2021 15:42:47 +0800 Subject: [PATCH 378/562] compat v1 -> v2 unittest implemented --- source/tests/compat_inputs/water_v2.json | 51 ++++++++++++++++++++++++ source/tests/test_compat_input.py | 10 ++++- 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 source/tests/compat_inputs/water_v2.json diff --git a/source/tests/compat_inputs/water_v2.json b/source/tests/compat_inputs/water_v2.json new file mode 100644 index 0000000000..ec405a5e4f --- /dev/null +++ b/source/tests/compat_inputs/water_v2.json @@ -0,0 +1,51 @@ +{ + "with_distrib": false, + "model":{ + "descriptor": { + "type": "loc_frame", + "sel_a": [16, 32], + "sel_r": [30, 60], + "rcut": 6.00, + "axis_rule": [0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0] + }, + "fitting_net": { + "neuron": [240, 120, 60, 30, 10], + "resnet_dt": true, + "seed": 1 + } + }, + + "learning_rate" :{ + "type": "exp", + "decay_steps": 5000, + "decay_rate": 0.95, + "start_lr": 0.001 + }, + + "loss" : { + "start_pref_e": 0.02, + "limit_pref_e": 8, + "start_pref_f": 1000, + "limit_pref_f": 1, + "start_pref_v": 0, + "limit_pref_v": 0 + }, + + "training": { + "training_data": { + "systems": ["../data/"], + "batch_size": [4] + }, + "set_prefix": "set", + "stop_batch": 1000000, + "seed": 1, + "disp_file": "lcurve.out", + "disp_freq": 100, + "numb_test": 10, + "save_freq": 1000, + "save_ckpt": "model.ckpt", + "disp_training":true, + "time_training":true + } +} + diff --git a/source/tests/test_compat_input.py b/source/tests/test_compat_input.py index dbdfc555d4..f1ac1924a9 100644 --- a/source/tests/test_compat_input.py +++ b/source/tests/test_compat_input.py @@ -2,8 +2,8 @@ import numpy as np import unittest -from deepmd.utils.compat import convert_input_v0_v1 -from common import j_loader +from deepmd.utils.compat import convert_input_v0_v1, convert_input_v1_v2 +from deepmd.common import j_loader class TestConvertInput (unittest.TestCase) : def test_convert_smth(self): @@ -18,6 +18,12 @@ def test_convert_nonsmth(self): jdata = convert_input_v0_v1(jdata0, warning = False, dump = None) self.assertEqual(jdata, jdata1) + def test_convert_v1_v2(self): + jdata0 = j_loader(os.path.join('compat_inputs', 'water_v1.json')) + jdata1 = j_loader(os.path.join('compat_inputs', 'water_v2.json')) + jdata = convert_input_v1_v2(jdata0, warning = False, dump = None) + self.assertEqual(jdata, jdata1) + def test_json_yaml_equal(self): inputs = ("water_v1", "water_se_a_v1") From 5600b446dce09b71fb1b878928ce3e1a237d5000 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 19 Apr 2021 15:54:10 +0800 Subject: [PATCH 379/562] fix bug in ut: duplicated graph name --- source/tests/test_model_se_t.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/tests/test_model_se_t.py b/source/tests/test_model_se_t.py index 3708e1e5e7..60ae54736b 100644 --- a/source/tests/test_model_se_t.py +++ b/source/tests/test_model_se_t.py @@ -70,7 +70,7 @@ def test_model(self): t_box, t_mesh, t_fparam, - suffix = "se_r", + suffix = "se_t", reuse = False) energy = model_pred['energy'] force = model_pred['force'] From 2b99eb51985cc3bec6466a24d10ecc973fc50b1f Mon Sep 17 00:00:00 2001 From: ZiyaoLi Date: Mon, 19 Apr 2021 16:04:00 +0800 Subject: [PATCH 380/562] test bug fixed --- source/tests/compat_inputs/water_v2.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/tests/compat_inputs/water_v2.json b/source/tests/compat_inputs/water_v2.json index ec405a5e4f..e49add4467 100644 --- a/source/tests/compat_inputs/water_v2.json +++ b/source/tests/compat_inputs/water_v2.json @@ -34,9 +34,9 @@ "training": { "training_data": { "systems": ["../data/"], + "set_prefix": "set", "batch_size": [4] }, - "set_prefix": "set", "stop_batch": 1000000, "seed": 1, "disp_file": "lcurve.out", From 96d14c18a3761aa5d8aa4b7d74bc4d3b4ebccd7a Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 19 Apr 2021 16:19:17 +0800 Subject: [PATCH 381/562] change names of descriptors, old names are still compatible --- deepmd/train/trainer.py | 8 ++++---- deepmd/utils/argcheck.py | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/deepmd/train/trainer.py b/deepmd/train/trainer.py index eb88aca92e..52d8e97cf8 100644 --- a/deepmd/train/trainer.py +++ b/deepmd/train/trainer.py @@ -55,16 +55,16 @@ def _generate_descrpt_from_param_dict(descrpt_param): descrpt_param.pop(kk, None) if descrpt_type == 'loc_frame': descrpt = DescrptLocFrame(**descrpt_param) - elif descrpt_type == 'se_a' : + elif descrpt_type == 'se_e2_a' or descrpt_type == 'se_a' : descrpt = DescrptSeA(**descrpt_param) - elif descrpt_type == 'se_a_3be' or descrpt_type == 'se_at' or descrpt_type == 'se_t' : + elif descrpt_type == 'se_e2_r' or descrpt_type == 'se_r' : + descrpt = DescrptSeR(**descrpt_param) + elif descrpt_type == 'se_e3' or descrpt_type == 'se_at' or descrpt_type == 'se_a_3be' : descrpt = DescrptSeT(**descrpt_param) elif descrpt_type == 'se_a_tpe' or descrpt_type == 'se_a_ebd' : descrpt = DescrptSeAEbd(**descrpt_param) elif descrpt_type == 'se_a_ef' : descrpt = DescrptSeAEf(**descrpt_param) - elif descrpt_type == 'se_r' : - descrpt = DescrptSeR(**descrpt_param) elif descrpt_type == 'se_ar' : descrpt = DescrptSeAR(descrpt_param) else : diff --git a/deepmd/utils/argcheck.py b/deepmd/utils/argcheck.py index dca1508a03..1e82ecc3d7 100644 --- a/deepmd/utils/argcheck.py +++ b/deepmd/utils/argcheck.py @@ -177,9 +177,9 @@ def descrpt_variant_type_args(): return Variant("type", [ Argument("loc_frame", dict, descrpt_local_frame_args()), - Argument("se_a", dict, descrpt_se_a_args()), - Argument("se_r", dict, descrpt_se_r_args()), - Argument("se_t", dict, descrpt_se_t_args(), alias = ['se_at', 'se_a_3be']), + Argument("se_e2_a", dict, descrpt_se_a_args(), alias = ['se_a']), + Argument("se_e2_r", dict, descrpt_se_r_args(), alias = ['se_r']), + Argument("se_e3", dict, descrpt_se_t_args(), alias = ['se_at', 'se_a_3be', 'se_t']), Argument("se_a_tpe", dict, descrpt_se_a_tpe_args(), alias = ['se_a_ebd']), Argument("hybrid", dict, descrpt_hybrid_args()), ], doc = doc_descrpt_type) From 840338c5bf39f621d0fff8784e4dab5f84dcc32d Mon Sep 17 00:00:00 2001 From: ZiyaoLi Date: Mon, 19 Apr 2021 16:52:05 +0800 Subject: [PATCH 382/562] import fixed --- source/tests/test_compat_input.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/tests/test_compat_input.py b/source/tests/test_compat_input.py index f1ac1924a9..1933725ac7 100644 --- a/source/tests/test_compat_input.py +++ b/source/tests/test_compat_input.py @@ -3,7 +3,7 @@ import unittest from deepmd.utils.compat import convert_input_v0_v1, convert_input_v1_v2 -from deepmd.common import j_loader +from common import j_loader class TestConvertInput (unittest.TestCase) : def test_convert_smth(self): From de6427382b11c9ff79d3a6d4bd06a23445033266 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 19 Apr 2021 18:04:52 +0800 Subject: [PATCH 383/562] normalized the list items of descriptor `hybrid` --- deepmd/utils/argcheck.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/deepmd/utils/argcheck.py b/deepmd/utils/argcheck.py index 1e82ecc3d7..121079bead 100644 --- a/deepmd/utils/argcheck.py +++ b/deepmd/utils/argcheck.py @@ -553,7 +553,21 @@ def gen_doc(*, make_anchor=True, make_link=True, **kwargs): return "\n\n".join(ptr) +def normalize_hybrid_list(hy_list): + new_list = [] + base = Argument("base", dict, [], [descrpt_variant_type_args()], doc = "") + for ii in range(len(hy_list)): + data = base.normalize_value(hy_list[ii], trim_pattern="_*") + base.check_value(data, strict=True) + new_list.append(data) + return new_list + + def normalize(data): + if "hybrid" == data["model"]["descriptor"]["type"]: + data["model"]["descriptor"]["list"] \ + = normalize_hybrid_list(data["model"]["descriptor"]["list"]) + ma = model_args() lra = learning_rate_args() la = loss_args() From 8ab68293c2534b4a4226a1def912980e459a1b01 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 19 Apr 2021 21:22:31 +0800 Subject: [PATCH 384/562] update doc: changed name of descriptors. with updated dargs --- deepmd/utils/argcheck.py | 12 +- doc/train-input-auto.rst | 836 ++++++++++++++++++++------------------- 2 files changed, 434 insertions(+), 414 deletions(-) diff --git a/deepmd/utils/argcheck.py b/deepmd/utils/argcheck.py index 121079bead..1e151b7a1e 100644 --- a/deepmd/utils/argcheck.py +++ b/deepmd/utils/argcheck.py @@ -162,16 +162,16 @@ def descrpt_hybrid_args(): def descrpt_variant_type_args(): link_lf = make_link('loc_frame', 'model/descriptor[loc_frame]') - link_se_a = make_link('se_a', 'model/descriptor[se_a]') - link_se_r = make_link('se_r', 'model/descriptor[se_r]') - link_se_t = make_link('se_t', 'model/descriptor[se_t]') + link_se_e2_a = make_link('se_e2_a', 'model/descriptor[se_e2_a]') + link_se_e2_r = make_link('se_e2_r', 'model/descriptor[se_e2_r]') + link_se_e3 = make_link('se_e3', 'model/descriptor[se_e3]') link_se_a_tpe = make_link('se_a_tpe', 'model/descriptor[se_a_tpe]') link_hybrid = make_link('hybrid', 'model/descriptor[hybrid]') doc_descrpt_type = f'The type of the descritpor. See explanation below. \n\n\ - `loc_frame`: Defines a local frame at each atom, and the compute the descriptor as local coordinates under this frame.\n\n\ -- `se_a`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor.\n\n\ -- `se_r`: Used by the smooth edition of Deep Potential. Only the distance between atoms is used to construct the descriptor.\n\n\ -- `se_t`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Three-body embedding will be used by this descriptor.\n\n\ +- `se_e2_a`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor.\n\n\ +- `se_e2_r`: Used by the smooth edition of Deep Potential. Only the distance between atoms is used to construct the descriptor.\n\n\ +- `se_e3`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Three-body embedding will be used by this descriptor.\n\n\ - `se_a_tpe`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Type embedding will be used by this descriptor.\n\n\ - `hybrid`: Concatenate of a list of descriptors as a new descriptor.' diff --git a/doc/train-input-auto.rst b/doc/train-input-auto.rst index 6da37d5264..edfb634654 100644 --- a/doc/train-input-auto.rst +++ b/doc/train-input-auto.rst @@ -1,76 +1,67 @@ -.. raw:: html +.. _`model`: - model: | type: ``dict`` | argument path: ``model`` - .. raw:: html + .. _`model/type_map`: - type_map: | type: ``list``, optional | argument path: ``model/type_map`` A list of strings. Give the name to each type of atoms. - .. raw:: html + .. _`model/data_stat_nbatch`: - data_stat_nbatch: | type: ``int``, optional, default: ``10`` | argument path: ``model/data_stat_nbatch`` The model determines the normalization from the statistics of the data. This key specifies the number of `frames` in each `system` used for statistics. - .. raw:: html + .. _`model/data_stat_protect`: - data_stat_protect: | type: ``float``, optional, default: ``0.01`` | argument path: ``model/data_stat_protect`` Protect parameter for atomic energy regression. - .. raw:: html + .. _`model/use_srtab`: - use_srtab: | type: ``str``, optional | argument path: ``model/use_srtab`` The table for the short-range pairwise interaction added on top of DP. The table is a text data file with (N_t + 1) * N_t / 2 + 1 columes. The first colume is the distance between atoms. The second to the last columes are energies for pairs of certain types. For example we have two atom types, 0 and 1. The columes from 2nd to 4th are for 0-0, 0-1 and 1-1 correspondingly. - .. raw:: html + .. _`model/smin_alpha`: - smin_alpha: | type: ``float``, optional | argument path: ``model/smin_alpha`` The short-range tabulated interaction will be swithed according to the distance of the nearest neighbor. This distance is calculated by softmin. This parameter is the decaying parameter in the softmin. It is only required when `use_srtab` is provided. - .. raw:: html + .. _`model/sw_rmin`: - sw_rmin: | type: ``float``, optional | argument path: ``model/sw_rmin`` The lower boundary of the interpolation between short-range tabulated interaction and DP. It is only required when `use_srtab` is provided. - .. raw:: html + .. _`model/sw_rmax`: - sw_rmax: | type: ``float``, optional | argument path: ``model/sw_rmax`` The upper boundary of the interpolation between short-range tabulated interaction and DP. It is only required when `use_srtab` is provided. - .. raw:: html + .. _`model/descriptor`: - descriptor: | type: ``dict`` | argument path: ``model/descriptor`` @@ -80,65 +71,74 @@ model: Depending on the value of *type*, different sub args are accepted. - .. raw:: html + .. _`model/descriptor/type`: - type: | type: ``str`` (flag key) | argument path: ``model/descriptor/type`` + | possible choices: |code:model/descriptor[loc_frame]|_, |code:model/descriptor[se_e2_a]|_, |code:model/descriptor[se_e2_r]|_, |code:model/descriptor[se_e3]|_, |code:model/descriptor[se_a_tpe]|_, |code:model/descriptor[hybrid]|_ - The type of the descritpor. Valid types are `loc_frame <#model/descriptor[loc_frame]>`__, `se_a <#model/descriptor[se_a]>`__, `se_r <#model/descriptor[se_r]>`__, `se_a_3be <#model/descriptor[se_a_3be]>`__, `se_a_tpe <#model/descriptor[se_a_tpe]>`__, `hybrid <#model/descriptor[hybrid]>`__. + The type of the descritpor. See explanation below. - `loc_frame`: Defines a local frame at each atom, and the compute the descriptor as local coordinates under this frame. - - `se_a`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. + - `se_e2_a`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. - - `se_r`: Used by the smooth edition of Deep Potential. Only the distance between atoms is used to construct the descriptor. + - `se_e2_r`: Used by the smooth edition of Deep Potential. Only the distance between atoms is used to construct the descriptor. - - `se_a_3be`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Three-body embedding will be used by this descriptor. + - `se_e3`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Three-body embedding will be used by this descriptor. - `se_a_tpe`: Used by the smooth edition of Deep Potential. The full relative coordinates are used to construct the descriptor. Type embedding will be used by this descriptor. - `hybrid`: Concatenate of a list of descriptors as a new descriptor. - - `se_ar`: A hybrid of `se_a` and `se_r`. Typically `se_a` has a smaller cut-off while the `se_r` has a larger cut-off. Deprecated, use `hybrid` instead. + .. |code:model/descriptor[loc_frame]| replace:: ``loc_frame`` + .. _`code:model/descriptor[loc_frame]`: `model/descriptor[loc_frame]`_ + .. |code:model/descriptor[se_e2_a]| replace:: ``se_e2_a`` + .. _`code:model/descriptor[se_e2_a]`: `model/descriptor[se_e2_a]`_ + .. |code:model/descriptor[se_e2_r]| replace:: ``se_e2_r`` + .. _`code:model/descriptor[se_e2_r]`: `model/descriptor[se_e2_r]`_ + .. |code:model/descriptor[se_e3]| replace:: ``se_e3`` + .. _`code:model/descriptor[se_e3]`: `model/descriptor[se_e3]`_ + .. |code:model/descriptor[se_a_tpe]| replace:: ``se_a_tpe`` + .. _`code:model/descriptor[se_a_tpe]`: `model/descriptor[se_a_tpe]`_ + .. |code:model/descriptor[hybrid]| replace:: ``hybrid`` + .. _`code:model/descriptor[hybrid]`: `model/descriptor[hybrid]`_ + .. |flag:model/descriptor/type| replace:: *type* + .. _`flag:model/descriptor/type`: `model/descriptor/type`_ - .. raw:: html - - When *type* is set to ``loc_frame``: + .. _`model/descriptor[loc_frame]`: - .. raw:: html + When |flag:model/descriptor/type|_ is set to ``loc_frame``: + + .. _`model/descriptor[loc_frame]/sel_a`: - sel_a: | type: ``list`` | argument path: ``model/descriptor[loc_frame]/sel_a`` A list of integers. The length of the list should be the same as the number of atom types in the system. `sel_a[i]` gives the selected number of type-i neighbors. The full relative coordinates of the neighbors are used by the descriptor. - .. raw:: html + .. _`model/descriptor[loc_frame]/sel_r`: - sel_r: | type: ``list`` | argument path: ``model/descriptor[loc_frame]/sel_r`` A list of integers. The length of the list should be the same as the number of atom types in the system. `sel_r[i]` gives the selected number of type-i neighbors. Only relative distance of the neighbors are used by the descriptor. sel_a[i] + sel_r[i] is recommended to be larger than the maximally possible number of type-i neighbors in the cut-off radius. - .. raw:: html + .. _`model/descriptor[loc_frame]/rcut`: - rcut: | type: ``float``, optional, default: ``6.0`` | argument path: ``model/descriptor[loc_frame]/rcut`` The cut-off radius. The default value is 6.0 - .. raw:: html + .. _`model/descriptor[loc_frame]/axis_rule`: - axis_rule: | type: ``list`` | argument path: ``model/descriptor[loc_frame]/axis_rule`` @@ -158,482 +158,427 @@ model: - axis_rule[i*6+5]: class of the atom defining the second axis of type-i atom. 0 for neighbors with full coordinates and 1 for neighbors only with relative distance. - .. raw:: html + .. _`model/descriptor[se_e2_a]`: - - When *type* is set to ``se_a``: + When |flag:model/descriptor/type|_ is set to ``se_e2_a`` (or its alias ``se_a``): - .. raw:: html + .. _`model/descriptor[se_e2_a]/sel`: - sel: | type: ``list`` - | argument path: ``model/descriptor[se_a]/sel`` + | argument path: ``model/descriptor[se_e2_a]/sel`` A list of integers. The length of the list should be the same as the number of atom types in the system. `sel[i]` gives the selected number of type-i neighbors. `sel[i]` is recommended to be larger than the maximally possible number of type-i neighbors in the cut-off radius. - .. raw:: html + .. _`model/descriptor[se_e2_a]/rcut`: - rcut: | type: ``float``, optional, default: ``6.0`` - | argument path: ``model/descriptor[se_a]/rcut`` + | argument path: ``model/descriptor[se_e2_a]/rcut`` The cut-off radius. - .. raw:: html + .. _`model/descriptor[se_e2_a]/rcut_smth`: - rcut_smth: | type: ``float``, optional, default: ``0.5`` - | argument path: ``model/descriptor[se_a]/rcut_smth`` + | argument path: ``model/descriptor[se_e2_a]/rcut_smth`` Where to start smoothing. For example the 1/r term is smoothed from `rcut` to `rcut_smth` - .. raw:: html + .. _`model/descriptor[se_e2_a]/neuron`: - neuron: | type: ``list``, optional, default: ``[10, 20, 40]`` - | argument path: ``model/descriptor[se_a]/neuron`` + | argument path: ``model/descriptor[se_e2_a]/neuron`` Number of neurons in each hidden layers of the embedding net. When two layers are of the same size or one layer is twice as large as the previous layer, a skip connection is built. - .. raw:: html + .. _`model/descriptor[se_e2_a]/axis_neuron`: - axis_neuron: | type: ``int``, optional, default: ``4`` - | argument path: ``model/descriptor[se_a]/axis_neuron`` + | argument path: ``model/descriptor[se_e2_a]/axis_neuron`` Size of the submatrix of G (embedding matrix). - .. raw:: html + .. _`model/descriptor[se_e2_a]/activation_function`: - activation_function: | type: ``str``, optional, default: ``tanh`` - | argument path: ``model/descriptor[se_a]/activation_function`` + | argument path: ``model/descriptor[se_e2_a]/activation_function`` The activation function in the embedding net. Supported activation functions are "relu", "relu6", "softplus", "sigmoid", "tanh", "gelu". - .. raw:: html + .. _`model/descriptor[se_e2_a]/resnet_dt`: - resnet_dt: | type: ``bool``, optional, default: ``False`` - | argument path: ``model/descriptor[se_a]/resnet_dt`` + | argument path: ``model/descriptor[se_e2_a]/resnet_dt`` Whether to use a "Timestep" in the skip connection - .. raw:: html + .. _`model/descriptor[se_e2_a]/type_one_side`: - type_one_side: | type: ``bool``, optional, default: ``False`` - | argument path: ``model/descriptor[se_a]/type_one_side`` + | argument path: ``model/descriptor[se_e2_a]/type_one_side`` Try to build N_types embedding nets. Otherwise, building N_types^2 embedding nets - .. raw:: html + .. _`model/descriptor[se_e2_a]/precision`: - precision: | type: ``str``, optional, default: ``float64`` - | argument path: ``model/descriptor[se_a]/precision`` + | argument path: ``model/descriptor[se_e2_a]/precision`` The precision of the embedding net parameters, supported options are "default", "float16", "float32", "float64". - .. raw:: html + .. _`model/descriptor[se_e2_a]/trainable`: - trainable: | type: ``bool``, optional, default: ``True`` - | argument path: ``model/descriptor[se_a]/trainable`` + | argument path: ``model/descriptor[se_e2_a]/trainable`` If the parameters in the embedding net is trainable - .. raw:: html + .. _`model/descriptor[se_e2_a]/seed`: - seed: | type: ``int`` | ``NoneType``, optional - | argument path: ``model/descriptor[se_a]/seed`` + | argument path: ``model/descriptor[se_e2_a]/seed`` Random seed for parameter initialization - .. raw:: html + .. _`model/descriptor[se_e2_a]/exclude_types`: - exclude_types: | type: ``list``, optional, default: ``[]`` - | argument path: ``model/descriptor[se_a]/exclude_types`` + | argument path: ``model/descriptor[se_e2_a]/exclude_types`` The Excluded types - .. raw:: html + .. _`model/descriptor[se_e2_a]/set_davg_zero`: - set_davg_zero: | type: ``bool``, optional, default: ``False`` - | argument path: ``model/descriptor[se_a]/set_davg_zero`` + | argument path: ``model/descriptor[se_e2_a]/set_davg_zero`` Set the normalization average to zero. This option should be set when `atom_ener` in the energy fitting is used - .. raw:: html + .. _`model/descriptor[se_e2_r]`: - - When *type* is set to ``se_r``: + When |flag:model/descriptor/type|_ is set to ``se_e2_r`` (or its alias ``se_r``): - .. raw:: html + .. _`model/descriptor[se_e2_r]/sel`: - sel: | type: ``list`` - | argument path: ``model/descriptor[se_r]/sel`` + | argument path: ``model/descriptor[se_e2_r]/sel`` A list of integers. The length of the list should be the same as the number of atom types in the system. `sel[i]` gives the selected number of type-i neighbors. `sel[i]` is recommended to be larger than the maximally possible number of type-i neighbors in the cut-off radius. - .. raw:: html + .. _`model/descriptor[se_e2_r]/rcut`: - rcut: | type: ``float``, optional, default: ``6.0`` - | argument path: ``model/descriptor[se_r]/rcut`` + | argument path: ``model/descriptor[se_e2_r]/rcut`` The cut-off radius. - .. raw:: html + .. _`model/descriptor[se_e2_r]/rcut_smth`: - rcut_smth: | type: ``float``, optional, default: ``0.5`` - | argument path: ``model/descriptor[se_r]/rcut_smth`` + | argument path: ``model/descriptor[se_e2_r]/rcut_smth`` Where to start smoothing. For example the 1/r term is smoothed from `rcut` to `rcut_smth` - .. raw:: html + .. _`model/descriptor[se_e2_r]/neuron`: - neuron: | type: ``list``, optional, default: ``[10, 20, 40]`` - | argument path: ``model/descriptor[se_r]/neuron`` + | argument path: ``model/descriptor[se_e2_r]/neuron`` Number of neurons in each hidden layers of the embedding net. When two layers are of the same size or one layer is twice as large as the previous layer, a skip connection is built. - .. raw:: html + .. _`model/descriptor[se_e2_r]/activation_function`: - activation_function: | type: ``str``, optional, default: ``tanh`` - | argument path: ``model/descriptor[se_r]/activation_function`` + | argument path: ``model/descriptor[se_e2_r]/activation_function`` The activation function in the embedding net. Supported activation functions are "relu", "relu6", "softplus", "sigmoid", "tanh", "gelu". - .. raw:: html + .. _`model/descriptor[se_e2_r]/resnet_dt`: - resnet_dt: | type: ``bool``, optional, default: ``False`` - | argument path: ``model/descriptor[se_r]/resnet_dt`` + | argument path: ``model/descriptor[se_e2_r]/resnet_dt`` Whether to use a "Timestep" in the skip connection - .. raw:: html + .. _`model/descriptor[se_e2_r]/type_one_side`: - type_one_side: | type: ``bool``, optional, default: ``False`` - | argument path: ``model/descriptor[se_r]/type_one_side`` + | argument path: ``model/descriptor[se_e2_r]/type_one_side`` Try to build N_types embedding nets. Otherwise, building N_types^2 embedding nets - .. raw:: html + .. _`model/descriptor[se_e2_r]/precision`: - precision: | type: ``str``, optional, default: ``float64`` - | argument path: ``model/descriptor[se_r]/precision`` + | argument path: ``model/descriptor[se_e2_r]/precision`` The precision of the embedding net parameters, supported options are "default", "float16", "float32", "float64". - .. raw:: html + .. _`model/descriptor[se_e2_r]/trainable`: - trainable: | type: ``bool``, optional, default: ``True`` - | argument path: ``model/descriptor[se_r]/trainable`` + | argument path: ``model/descriptor[se_e2_r]/trainable`` If the parameters in the embedding net is trainable - .. raw:: html + .. _`model/descriptor[se_e2_r]/seed`: - seed: | type: ``int`` | ``NoneType``, optional - | argument path: ``model/descriptor[se_r]/seed`` + | argument path: ``model/descriptor[se_e2_r]/seed`` Random seed for parameter initialization - .. raw:: html + .. _`model/descriptor[se_e2_r]/exclude_types`: - exclude_types: | type: ``list``, optional, default: ``[]`` - | argument path: ``model/descriptor[se_r]/exclude_types`` + | argument path: ``model/descriptor[se_e2_r]/exclude_types`` The Excluded types - .. raw:: html + .. _`model/descriptor[se_e2_r]/set_davg_zero`: - set_davg_zero: | type: ``bool``, optional, default: ``False`` - | argument path: ``model/descriptor[se_r]/set_davg_zero`` + | argument path: ``model/descriptor[se_e2_r]/set_davg_zero`` Set the normalization average to zero. This option should be set when `atom_ener` in the energy fitting is used - .. raw:: html + .. _`model/descriptor[se_e3]`: - - When *type* is set to ``se_a_3be``: + When |flag:model/descriptor/type|_ is set to ``se_e3`` (or its aliases ``se_at``, ``se_a_3be``, ``se_t``): - .. raw:: html + .. _`model/descriptor[se_e3]/sel`: - sel: | type: ``list`` - | argument path: ``model/descriptor[se_a_3be]/sel`` + | argument path: ``model/descriptor[se_e3]/sel`` A list of integers. The length of the list should be the same as the number of atom types in the system. `sel[i]` gives the selected number of type-i neighbors. `sel[i]` is recommended to be larger than the maximally possible number of type-i neighbors in the cut-off radius. - .. raw:: html + .. _`model/descriptor[se_e3]/rcut`: - rcut: | type: ``float``, optional, default: ``6.0`` - | argument path: ``model/descriptor[se_a_3be]/rcut`` + | argument path: ``model/descriptor[se_e3]/rcut`` The cut-off radius. - .. raw:: html + .. _`model/descriptor[se_e3]/rcut_smth`: - rcut_smth: | type: ``float``, optional, default: ``0.5`` - | argument path: ``model/descriptor[se_a_3be]/rcut_smth`` + | argument path: ``model/descriptor[se_e3]/rcut_smth`` Where to start smoothing. For example the 1/r term is smoothed from `rcut` to `rcut_smth` - .. raw:: html + .. _`model/descriptor[se_e3]/neuron`: - neuron: | type: ``list``, optional, default: ``[10, 20, 40]`` - | argument path: ``model/descriptor[se_a_3be]/neuron`` + | argument path: ``model/descriptor[se_e3]/neuron`` Number of neurons in each hidden layers of the embedding net. When two layers are of the same size or one layer is twice as large as the previous layer, a skip connection is built. - .. raw:: html + .. _`model/descriptor[se_e3]/activation_function`: - activation_function: | type: ``str``, optional, default: ``tanh`` - | argument path: ``model/descriptor[se_a_3be]/activation_function`` + | argument path: ``model/descriptor[se_e3]/activation_function`` The activation function in the embedding net. Supported activation functions are "relu", "relu6", "softplus", "sigmoid", "tanh", "gelu". - .. raw:: html + .. _`model/descriptor[se_e3]/resnet_dt`: - resnet_dt: | type: ``bool``, optional, default: ``False`` - | argument path: ``model/descriptor[se_a_3be]/resnet_dt`` + | argument path: ``model/descriptor[se_e3]/resnet_dt`` Whether to use a "Timestep" in the skip connection - .. raw:: html + .. _`model/descriptor[se_e3]/precision`: - precision: | type: ``str``, optional, default: ``float64`` - | argument path: ``model/descriptor[se_a_3be]/precision`` + | argument path: ``model/descriptor[se_e3]/precision`` The precision of the embedding net parameters, supported options are "default", "float16", "float32", "float64". - .. raw:: html + .. _`model/descriptor[se_e3]/trainable`: - trainable: | type: ``bool``, optional, default: ``True`` - | argument path: ``model/descriptor[se_a_3be]/trainable`` + | argument path: ``model/descriptor[se_e3]/trainable`` If the parameters in the embedding net is trainable - .. raw:: html + .. _`model/descriptor[se_e3]/seed`: - seed: | type: ``int`` | ``NoneType``, optional - | argument path: ``model/descriptor[se_a_3be]/seed`` + | argument path: ``model/descriptor[se_e3]/seed`` Random seed for parameter initialization - .. raw:: html + .. _`model/descriptor[se_e3]/set_davg_zero`: - set_davg_zero: | type: ``bool``, optional, default: ``False`` - | argument path: ``model/descriptor[se_a_3be]/set_davg_zero`` + | argument path: ``model/descriptor[se_e3]/set_davg_zero`` Set the normalization average to zero. This option should be set when `atom_ener` in the energy fitting is used - .. raw:: html + .. _`model/descriptor[se_a_tpe]`: - - When *type* is set to ``se_a_tpe``: + When |flag:model/descriptor/type|_ is set to ``se_a_tpe`` (or its alias ``se_a_ebd``): - .. raw:: html + .. _`model/descriptor[se_a_tpe]/sel`: - sel: | type: ``list`` | argument path: ``model/descriptor[se_a_tpe]/sel`` A list of integers. The length of the list should be the same as the number of atom types in the system. `sel[i]` gives the selected number of type-i neighbors. `sel[i]` is recommended to be larger than the maximally possible number of type-i neighbors in the cut-off radius. - .. raw:: html + .. _`model/descriptor[se_a_tpe]/rcut`: - rcut: | type: ``float``, optional, default: ``6.0`` | argument path: ``model/descriptor[se_a_tpe]/rcut`` The cut-off radius. - .. raw:: html + .. _`model/descriptor[se_a_tpe]/rcut_smth`: - rcut_smth: | type: ``float``, optional, default: ``0.5`` | argument path: ``model/descriptor[se_a_tpe]/rcut_smth`` Where to start smoothing. For example the 1/r term is smoothed from `rcut` to `rcut_smth` - .. raw:: html + .. _`model/descriptor[se_a_tpe]/neuron`: - neuron: | type: ``list``, optional, default: ``[10, 20, 40]`` | argument path: ``model/descriptor[se_a_tpe]/neuron`` Number of neurons in each hidden layers of the embedding net. When two layers are of the same size or one layer is twice as large as the previous layer, a skip connection is built. - .. raw:: html + .. _`model/descriptor[se_a_tpe]/axis_neuron`: - axis_neuron: | type: ``int``, optional, default: ``4`` | argument path: ``model/descriptor[se_a_tpe]/axis_neuron`` Size of the submatrix of G (embedding matrix). - .. raw:: html + .. _`model/descriptor[se_a_tpe]/activation_function`: - activation_function: | type: ``str``, optional, default: ``tanh`` | argument path: ``model/descriptor[se_a_tpe]/activation_function`` The activation function in the embedding net. Supported activation functions are "relu", "relu6", "softplus", "sigmoid", "tanh", "gelu". - .. raw:: html + .. _`model/descriptor[se_a_tpe]/resnet_dt`: - resnet_dt: | type: ``bool``, optional, default: ``False`` | argument path: ``model/descriptor[se_a_tpe]/resnet_dt`` Whether to use a "Timestep" in the skip connection - .. raw:: html + .. _`model/descriptor[se_a_tpe]/type_one_side`: - type_one_side: | type: ``bool``, optional, default: ``False`` | argument path: ``model/descriptor[se_a_tpe]/type_one_side`` Try to build N_types embedding nets. Otherwise, building N_types^2 embedding nets - .. raw:: html + .. _`model/descriptor[se_a_tpe]/precision`: - precision: | type: ``str``, optional, default: ``float64`` | argument path: ``model/descriptor[se_a_tpe]/precision`` The precision of the embedding net parameters, supported options are "default", "float16", "float32", "float64". - .. raw:: html + .. _`model/descriptor[se_a_tpe]/trainable`: - trainable: | type: ``bool``, optional, default: ``True`` | argument path: ``model/descriptor[se_a_tpe]/trainable`` If the parameters in the embedding net is trainable - .. raw:: html + .. _`model/descriptor[se_a_tpe]/seed`: - seed: | type: ``int`` | ``NoneType``, optional | argument path: ``model/descriptor[se_a_tpe]/seed`` Random seed for parameter initialization - .. raw:: html + .. _`model/descriptor[se_a_tpe]/exclude_types`: - exclude_types: | type: ``list``, optional, default: ``[]`` | argument path: ``model/descriptor[se_a_tpe]/exclude_types`` The Excluded types - .. raw:: html + .. _`model/descriptor[se_a_tpe]/set_davg_zero`: - set_davg_zero: | type: ``bool``, optional, default: ``False`` | argument path: ``model/descriptor[se_a_tpe]/set_davg_zero`` Set the normalization average to zero. This option should be set when `atom_ener` in the energy fitting is used - .. raw:: html + .. _`model/descriptor[se_a_tpe]/type_nchanl`: - type_nchanl: | type: ``int``, optional, default: ``4`` | argument path: ``model/descriptor[se_a_tpe]/type_nchanl`` number of channels for type embedding - .. raw:: html + .. _`model/descriptor[se_a_tpe]/type_nlayer`: - type_nlayer: | type: ``int``, optional, default: ``2`` | argument path: ``model/descriptor[se_a_tpe]/type_nlayer`` number of hidden layers of type embedding net - .. raw:: html + .. _`model/descriptor[se_a_tpe]/numb_aparam`: - numb_aparam: | type: ``int``, optional, default: ``0`` | argument path: ``model/descriptor[se_a_tpe]/numb_aparam`` @@ -641,47 +586,20 @@ model: dimension of atomic parameter. if set to a value > 0, the atomic parameters are embedded. - .. raw:: html + .. _`model/descriptor[hybrid]`: - - When *type* is set to ``hybrid``: + When |flag:model/descriptor/type|_ is set to ``hybrid``: - .. raw:: html + .. _`model/descriptor[hybrid]/list`: - list: | type: ``list`` | argument path: ``model/descriptor[hybrid]/list`` A list of descriptor definitions + .. _`model/fitting_net`: - .. raw:: html - - - When *type* is set to ``se_ar``: - - .. raw:: html - - - a: - | type: ``dict`` - | argument path: ``model/descriptor[se_ar]/a`` - - The parameters of descriptor `se_a <#model/descriptor[se_a]>`__ - - .. raw:: html - - - r: - | type: ``dict`` - | argument path: ``model/descriptor[se_ar]/r`` - - The parameters of descriptor `se_r <#model/descriptor[se_r]>`__ - - .. raw:: html - - fitting_net: | type: ``dict`` | argument path: ``model/fitting_net`` @@ -691,14 +609,14 @@ model: Depending on the value of *type*, different sub args are accepted. - .. raw:: html + .. _`model/fitting_net/type`: - type: | type: ``str`` (flag key), default: ``ener`` | argument path: ``model/fitting_net/type`` + | possible choices: |code:model/fitting_net[ener]|_, |code:model/fitting_net[dipole]|_, |code:model/fitting_net[polar]|_, |code:model/fitting_net[global_polar]|_ - The type of the fitting. Valid types are `ener`, `dipole`, `polar` and `global_polar`. + The type of the fitting. See explanation below. - `ener`: Fit an energy model (potential energy surface). @@ -708,69 +626,73 @@ model: - `global_polar`: Fit a polarizability model. Polarizability labels should be provided by `polarizability.npy` in each data system. The file has number of frames lines and 9 columns. + .. |code:model/fitting_net[ener]| replace:: ``ener`` + .. _`code:model/fitting_net[ener]`: `model/fitting_net[ener]`_ + .. |code:model/fitting_net[dipole]| replace:: ``dipole`` + .. _`code:model/fitting_net[dipole]`: `model/fitting_net[dipole]`_ + .. |code:model/fitting_net[polar]| replace:: ``polar`` + .. _`code:model/fitting_net[polar]`: `model/fitting_net[polar]`_ + .. |code:model/fitting_net[global_polar]| replace:: ``global_polar`` + .. _`code:model/fitting_net[global_polar]`: `model/fitting_net[global_polar]`_ + + .. |flag:model/fitting_net/type| replace:: *type* + .. _`flag:model/fitting_net/type`: `model/fitting_net/type`_ - .. raw:: html - - When *type* is set to ``ener``: + .. _`model/fitting_net[ener]`: - .. raw:: html + When |flag:model/fitting_net/type|_ is set to ``ener``: + + .. _`model/fitting_net[ener]/numb_fparam`: - numb_fparam: | type: ``int``, optional, default: ``0`` | argument path: ``model/fitting_net[ener]/numb_fparam`` The dimension of the frame parameter. If set to >0, file `fparam.npy` should be included to provided the input fparams. - .. raw:: html + .. _`model/fitting_net[ener]/numb_aparam`: - numb_aparam: | type: ``int``, optional, default: ``0`` | argument path: ``model/fitting_net[ener]/numb_aparam`` The dimension of the atomic parameter. If set to >0, file `aparam.npy` should be included to provided the input aparams. - .. raw:: html + .. _`model/fitting_net[ener]/neuron`: - neuron: | type: ``list``, optional, default: ``[120, 120, 120]`` | argument path: ``model/fitting_net[ener]/neuron`` The number of neurons in each hidden layers of the fitting net. When two hidden layers are of the same size, a skip connection is built. - .. raw:: html + .. _`model/fitting_net[ener]/activation_function`: - activation_function: | type: ``str``, optional, default: ``tanh`` | argument path: ``model/fitting_net[ener]/activation_function`` The activation function in the fitting net. Supported activation functions are "relu", "relu6", "softplus", "sigmoid", "tanh", "gelu". - .. raw:: html + .. _`model/fitting_net[ener]/precision`: - precision: | type: ``str``, optional, default: ``float64`` | argument path: ``model/fitting_net[ener]/precision`` The precision of the fitting net parameters, supported options are "default", "float16", "float32", "float64". - .. raw:: html + .. _`model/fitting_net[ener]/resnet_dt`: - resnet_dt: | type: ``bool``, optional, default: ``True`` | argument path: ``model/fitting_net[ener]/resnet_dt`` Whether to use a "Timestep" in the skip connection - .. raw:: html + .. _`model/fitting_net[ener]/trainable`: - trainable: | type: ``bool`` | ``list``, optional, default: ``True`` | argument path: ``model/fitting_net[ener]/trainable`` @@ -781,27 +703,24 @@ model: - list of bool: Specifies if each layer is trainable. Since the fitting net is composed by hidden layers followed by a output layer, the length of tihs list should be equal to len(`neuron`)+1. - .. raw:: html + .. _`model/fitting_net[ener]/rcond`: - rcond: | type: ``float``, optional, default: ``0.001`` | argument path: ``model/fitting_net[ener]/rcond`` The condition number used to determine the inital energy shift for each type of atoms. - .. raw:: html + .. _`model/fitting_net[ener]/seed`: - seed: | type: ``int`` | ``NoneType``, optional | argument path: ``model/fitting_net[ener]/seed`` Random seed for parameter initialization of the fitting net - .. raw:: html + .. _`model/fitting_net[ener]/atom_ener`: - atom_ener: | type: ``list``, optional, default: ``[]`` | argument path: ``model/fitting_net[ener]/atom_ener`` @@ -809,59 +728,52 @@ model: Specify the atomic energy in vacuum for each type - .. raw:: html + .. _`model/fitting_net[dipole]`: - - When *type* is set to ``dipole``: + When |flag:model/fitting_net/type|_ is set to ``dipole``: - .. raw:: html + .. _`model/fitting_net[dipole]/neuron`: - neuron: | type: ``list``, optional, default: ``[120, 120, 120]`` | argument path: ``model/fitting_net[dipole]/neuron`` The number of neurons in each hidden layers of the fitting net. When two hidden layers are of the same size, a skip connection is built. - .. raw:: html + .. _`model/fitting_net[dipole]/activation_function`: - activation_function: | type: ``str``, optional, default: ``tanh`` | argument path: ``model/fitting_net[dipole]/activation_function`` The activation function in the fitting net. Supported activation functions are "relu", "relu6", "softplus", "sigmoid", "tanh", "gelu". - .. raw:: html + .. _`model/fitting_net[dipole]/resnet_dt`: - resnet_dt: | type: ``bool``, optional, default: ``True`` | argument path: ``model/fitting_net[dipole]/resnet_dt`` Whether to use a "Timestep" in the skip connection - .. raw:: html + .. _`model/fitting_net[dipole]/precision`: - precision: | type: ``str``, optional, default: ``float64`` | argument path: ``model/fitting_net[dipole]/precision`` The precision of the fitting net parameters, supported options are "default", "float16", "float32", "float64". - .. raw:: html + .. _`model/fitting_net[dipole]/sel_type`: - sel_type: | type: ``int`` | ``NoneType`` | ``list``, optional | argument path: ``model/fitting_net[dipole]/sel_type`` The atom types for which the atomic dipole will be provided. If not set, all types will be selected. - .. raw:: html + .. _`model/fitting_net[dipole]/seed`: - seed: | type: ``int`` | ``NoneType``, optional | argument path: ``model/fitting_net[dipole]/seed`` @@ -869,86 +781,76 @@ model: Random seed for parameter initialization of the fitting net - .. raw:: html + .. _`model/fitting_net[polar]`: - - When *type* is set to ``polar``: + When |flag:model/fitting_net/type|_ is set to ``polar``: - .. raw:: html + .. _`model/fitting_net[polar]/neuron`: - neuron: | type: ``list``, optional, default: ``[120, 120, 120]`` | argument path: ``model/fitting_net[polar]/neuron`` The number of neurons in each hidden layers of the fitting net. When two hidden layers are of the same size, a skip connection is built. - .. raw:: html + .. _`model/fitting_net[polar]/activation_function`: - activation_function: | type: ``str``, optional, default: ``tanh`` | argument path: ``model/fitting_net[polar]/activation_function`` The activation function in the fitting net. Supported activation functions are "relu", "relu6", "softplus", "sigmoid", "tanh", "gelu". - .. raw:: html + .. _`model/fitting_net[polar]/resnet_dt`: - resnet_dt: | type: ``bool``, optional, default: ``True`` | argument path: ``model/fitting_net[polar]/resnet_dt`` Whether to use a "Timestep" in the skip connection - .. raw:: html + .. _`model/fitting_net[polar]/precision`: - precision: | type: ``str``, optional, default: ``float64`` | argument path: ``model/fitting_net[polar]/precision`` The precision of the fitting net parameters, supported options are "default", "float16", "float32", "float64". - .. raw:: html + .. _`model/fitting_net[polar]/fit_diag`: - fit_diag: | type: ``bool``, optional, default: ``True`` | argument path: ``model/fitting_net[polar]/fit_diag`` Fit the diagonal part of the rotational invariant polarizability matrix, which will be converted to normal polarizability matrix by contracting with the rotation matrix. - .. raw:: html + .. _`model/fitting_net[polar]/scale`: - scale: | type: ``float`` | ``list``, optional, default: ``1.0`` | argument path: ``model/fitting_net[polar]/scale`` The output of the fitting net (polarizability matrix) will be scaled by ``scale`` - .. raw:: html + .. _`model/fitting_net[polar]/diag_shift`: - diag_shift: | type: ``float`` | ``list``, optional, default: ``0.0`` | argument path: ``model/fitting_net[polar]/diag_shift`` The diagonal part of the polarizability matrix will be shifted by ``diag_shift``. The shift operation is carried out after ``scale``. - .. raw:: html + .. _`model/fitting_net[polar]/sel_type`: - sel_type: | type: ``int`` | ``NoneType`` | ``list``, optional | argument path: ``model/fitting_net[polar]/sel_type`` The atom types for which the atomic polarizability will be provided. If not set, all types will be selected. - .. raw:: html + .. _`model/fitting_net[polar]/seed`: - seed: | type: ``int`` | ``NoneType``, optional | argument path: ``model/fitting_net[polar]/seed`` @@ -956,96 +858,158 @@ model: Random seed for parameter initialization of the fitting net - .. raw:: html + .. _`model/fitting_net[global_polar]`: - - When *type* is set to ``global_polar``: + When |flag:model/fitting_net/type|_ is set to ``global_polar``: - .. raw:: html + .. _`model/fitting_net[global_polar]/neuron`: - neuron: | type: ``list``, optional, default: ``[120, 120, 120]`` | argument path: ``model/fitting_net[global_polar]/neuron`` The number of neurons in each hidden layers of the fitting net. When two hidden layers are of the same size, a skip connection is built. - .. raw:: html + .. _`model/fitting_net[global_polar]/activation_function`: - activation_function: | type: ``str``, optional, default: ``tanh`` | argument path: ``model/fitting_net[global_polar]/activation_function`` The activation function in the fitting net. Supported activation functions are "relu", "relu6", "softplus", "sigmoid", "tanh", "gelu". - .. raw:: html + .. _`model/fitting_net[global_polar]/resnet_dt`: - resnet_dt: | type: ``bool``, optional, default: ``True`` | argument path: ``model/fitting_net[global_polar]/resnet_dt`` Whether to use a "Timestep" in the skip connection - .. raw:: html + .. _`model/fitting_net[global_polar]/precision`: - precision: | type: ``str``, optional, default: ``float64`` | argument path: ``model/fitting_net[global_polar]/precision`` The precision of the fitting net parameters, supported options are "default", "float16", "float32", "float64". - .. raw:: html + .. _`model/fitting_net[global_polar]/fit_diag`: - fit_diag: | type: ``bool``, optional, default: ``True`` | argument path: ``model/fitting_net[global_polar]/fit_diag`` Fit the diagonal part of the rotational invariant polarizability matrix, which will be converted to normal polarizability matrix by contracting with the rotation matrix. - .. raw:: html + .. _`model/fitting_net[global_polar]/scale`: - scale: | type: ``float`` | ``list``, optional, default: ``1.0`` | argument path: ``model/fitting_net[global_polar]/scale`` The output of the fitting net (polarizability matrix) will be scaled by ``scale`` - .. raw:: html + .. _`model/fitting_net[global_polar]/diag_shift`: - diag_shift: | type: ``float`` | ``list``, optional, default: ``0.0`` | argument path: ``model/fitting_net[global_polar]/diag_shift`` The diagonal part of the polarizability matrix will be shifted by ``diag_shift``. The shift operation is carried out after ``scale``. - .. raw:: html + .. _`model/fitting_net[global_polar]/sel_type`: - sel_type: | type: ``int`` | ``NoneType`` | ``list``, optional | argument path: ``model/fitting_net[global_polar]/sel_type`` The atom types for which the atomic polarizability will be provided. If not set, all types will be selected. - .. raw:: html + .. _`model/fitting_net[global_polar]/seed`: - seed: | type: ``int`` | ``NoneType``, optional | argument path: ``model/fitting_net[global_polar]/seed`` Random seed for parameter initialization of the fitting net + .. _`model/modifier`: + + modifier: + | type: ``dict``, optional + | argument path: ``model/modifier`` + + The modifier of model output. + + + Depending on the value of *type*, different sub args are accepted. + + .. _`model/modifier/type`: + + type: + | type: ``str`` (flag key) + | argument path: ``model/modifier/type`` + | possible choices: |code:model/modifier[dipole_charge]|_ + + The type of modifier. See explanation below. + + -`dipole_charge`: Use WFCC to model the electronic structure of the system. Correct the long-range interaction + + .. |code:model/modifier[dipole_charge]| replace:: ``dipole_charge`` + .. _`code:model/modifier[dipole_charge]`: `model/modifier[dipole_charge]`_ + + .. |flag:model/modifier/type| replace:: *type* + .. _`flag:model/modifier/type`: `model/modifier/type`_ + + + .. _`model/modifier[dipole_charge]`: + + When |flag:model/modifier/type|_ is set to ``dipole_charge``: + + .. _`model/modifier[dipole_charge]/model_name`: + + model_name: + | type: ``str`` + | argument path: ``model/modifier[dipole_charge]/model_name`` + + The name of the frozen dipole model file. + + .. _`model/modifier[dipole_charge]/model_charge_map`: + + model_charge_map: + | type: ``list`` + | argument path: ``model/modifier[dipole_charge]/model_charge_map`` + + The charge of the WFCC. The list length should be the same as the `sel_type `_. + + .. _`model/modifier[dipole_charge]/sys_charge_map`: + + sys_charge_map: + | type: ``list`` + | argument path: ``model/modifier[dipole_charge]/sys_charge_map`` + + The charge of real atoms. The list length should be the same as the `type_map `_ + + .. _`model/modifier[dipole_charge]/ewald_beta`: + + ewald_beta: + | type: ``float``, optional, default: ``0.4`` + | argument path: ``model/modifier[dipole_charge]/ewald_beta`` + + The splitting parameter of Ewald sum. Unit is A^-1 -.. raw:: html + .. _`model/modifier[dipole_charge]/ewald_h`: + + ewald_h: + | type: ``float``, optional, default: ``1.0`` + | argument path: ``model/modifier[dipole_charge]/ewald_h`` + + The grid spacing of the FFT grid. Unit is A + + +.. _`loss`: - loss: | type: ``dict``, optional | argument path: ``loss`` @@ -1055,97 +1019,93 @@ loss: Depending on the value of *type*, different sub args are accepted. - .. raw:: html + .. _`loss/type`: - type: | type: ``str`` (flag key), default: ``ener`` | argument path: ``loss/type`` + | possible choices: |code:loss[ener]|_ - The type of the loss. For fitting type `ener`, the loss type should be set to `ener` or left unset. For tensorial fitting types `dipole`, `polar` and `global_polar`, the type should be left unset. + The type of the loss. \. + .. |code:loss[ener]| replace:: ``ener`` + .. _`code:loss[ener]`: `loss[ener]`_ + + .. |flag:loss/type| replace:: *type* + .. _`flag:loss/type`: `loss/type`_ + - .. raw:: html + .. _`loss[ener]`: - - When *type* is set to ``ener``: + When |flag:loss/type|_ is set to ``ener``: - .. raw:: html + .. _`loss[ener]/start_pref_e`: - start_pref_e: | type: ``float`` | ``int``, optional, default: ``0.02`` | argument path: ``loss[ener]/start_pref_e`` The prefactor of energy loss at the start of the training. Should be larger than or equal to 0. If set to none-zero value, the energy label should be provided by file energy.npy in each data system. If both start_pref_energy and limit_pref_energy are set to 0, then the energy will be ignored. - .. raw:: html + .. _`loss[ener]/limit_pref_e`: - limit_pref_e: | type: ``float`` | ``int``, optional, default: ``1.0`` | argument path: ``loss[ener]/limit_pref_e`` The prefactor of energy loss at the limit of the training, Should be larger than or equal to 0. i.e. the training step goes to infinity. - .. raw:: html + .. _`loss[ener]/start_pref_f`: - start_pref_f: | type: ``float`` | ``int``, optional, default: ``1000`` | argument path: ``loss[ener]/start_pref_f`` The prefactor of force loss at the start of the training. Should be larger than or equal to 0. If set to none-zero value, the force label should be provided by file force.npy in each data system. If both start_pref_force and limit_pref_force are set to 0, then the force will be ignored. - .. raw:: html + .. _`loss[ener]/limit_pref_f`: - limit_pref_f: | type: ``float`` | ``int``, optional, default: ``1.0`` | argument path: ``loss[ener]/limit_pref_f`` The prefactor of force loss at the limit of the training, Should be larger than or equal to 0. i.e. the training step goes to infinity. - .. raw:: html + .. _`loss[ener]/start_pref_v`: - start_pref_v: | type: ``float`` | ``int``, optional, default: ``0.0`` | argument path: ``loss[ener]/start_pref_v`` The prefactor of virial loss at the start of the training. Should be larger than or equal to 0. If set to none-zero value, the virial label should be provided by file virial.npy in each data system. If both start_pref_virial and limit_pref_virial are set to 0, then the virial will be ignored. - .. raw:: html + .. _`loss[ener]/limit_pref_v`: - limit_pref_v: | type: ``float`` | ``int``, optional, default: ``0.0`` | argument path: ``loss[ener]/limit_pref_v`` The prefactor of virial loss at the limit of the training, Should be larger than or equal to 0. i.e. the training step goes to infinity. - .. raw:: html + .. _`loss[ener]/start_pref_ae`: - start_pref_ae: | type: ``float`` | ``int``, optional, default: ``0.0`` | argument path: ``loss[ener]/start_pref_ae`` - The prefactor of virial loss at the start of the training. Should be larger than or equal to 0. If set to none-zero value, the virial label should be provided by file virial.npy in each data system. If both start_pref_virial and limit_pref_virial are set to 0, then the virial will be ignored. + The prefactor of atom_ener loss at the start of the training. Should be larger than or equal to 0. If set to none-zero value, the atom_ener label should be provided by file atom_ener.npy in each data system. If both start_pref_atom_ener and limit_pref_atom_ener are set to 0, then the atom_ener will be ignored. - .. raw:: html + .. _`loss[ener]/limit_pref_ae`: - limit_pref_ae: | type: ``float`` | ``int``, optional, default: ``0.0`` | argument path: ``loss[ener]/limit_pref_ae`` - The prefactor of virial loss at the limit of the training, Should be larger than or equal to 0. i.e. the training step goes to infinity. + The prefactor of atom_ener loss at the limit of the training, Should be larger than or equal to 0. i.e. the training step goes to infinity. - .. raw:: html + .. _`loss[ener]/relative_f`: - relative_f: | type: ``float`` | ``NoneType``, optional | argument path: ``loss[ener]/relative_f`` @@ -1153,9 +1113,8 @@ loss: If provided, relative force error will be used in the loss. The difference of force will be normalized by the magnitude of the force in the label with a shift given by `relative_f`, i.e. DF_i / ( || F || + relative_f ) with DF denoting the difference between prediction and label and || F || denoting the L2 norm of the label. -.. raw:: html +.. _`learning_rate`: - learning_rate: | type: ``dict`` | argument path: ``learning_rate`` @@ -1165,42 +1124,44 @@ learning_rate: Depending on the value of *type*, different sub args are accepted. - .. raw:: html + .. _`learning_rate/type`: - type: | type: ``str`` (flag key), default: ``exp`` | argument path: ``learning_rate/type`` + | possible choices: |code:learning_rate[exp]|_ + + The type of the learning rate. - The type of the learning rate. Current type `exp`, the exponentially decaying learning rate is supported. + .. |code:learning_rate[exp]| replace:: ``exp`` + .. _`code:learning_rate[exp]`: `learning_rate[exp]`_ + .. |flag:learning_rate/type| replace:: *type* + .. _`flag:learning_rate/type`: `learning_rate/type`_ - .. raw:: html - - When *type* is set to ``exp``: + .. _`learning_rate[exp]`: - .. raw:: html + When |flag:learning_rate/type|_ is set to ``exp``: + + .. _`learning_rate[exp]/start_lr`: - start_lr: | type: ``float``, optional, default: ``0.001`` | argument path: ``learning_rate[exp]/start_lr`` The learning rate the start of the training. - .. raw:: html + .. _`learning_rate[exp]/stop_lr`: - stop_lr: | type: ``float``, optional, default: ``1e-08`` | argument path: ``learning_rate[exp]/stop_lr`` The desired learning rate at the end of the training. - .. raw:: html + .. _`learning_rate[exp]/decay_steps`: - decay_steps: | type: ``int``, optional, default: ``5000`` | argument path: ``learning_rate[exp]/decay_steps`` @@ -1208,185 +1169,244 @@ learning_rate: The learning rate is decaying every this number of training steps. -.. raw:: html +.. _`training`: - training: | type: ``dict`` | argument path: ``training`` - The training options + The training options. + + .. _`training/training_data`: + + training_data: + | type: ``dict`` + | argument path: ``training/training_data`` + + Configurations of training data. + + .. _`training/training_data/systems`: + + systems: + | type: ``list`` | ``str`` + | argument path: ``training/training_data/systems`` + + The data systems for training. This key can be provided with a list that specifies the systems, or be provided with a string by which the prefix of all systems are given and the list of the systems is automatically generated. + + .. _`training/training_data/set_prefix`: + + set_prefix: + | type: ``str``, optional, default: ``set`` + | argument path: ``training/training_data/set_prefix`` + + The prefix of the sets in the `systems `_. + + .. _`training/training_data/batch_size`: + + batch_size: + | type: ``int`` | ``list`` | ``str``, optional, default: ``auto`` + | argument path: ``training/training_data/batch_size`` + + This key can be + + - list: the length of which is the same as the `systems `_. The batch size of each system is given by the elements of the list. + + - int: all `systems `_ use the same batch size. + + - string "auto": automatically determines the batch size so that the batch_size times the number of atoms in the system is no less than 32. + + - string "auto:N": automatically determines the batch size so that the batch_size times the number of atoms in the system is no less than N. + + .. _`training/training_data/auto_prob`: + + auto_prob: + | type: ``str``, optional, default: ``prob_sys_size``, alias: *auto_prob_style* + | argument path: ``training/training_data/auto_prob`` + + Determine the probability of systems automatically. The method is assigned by this key and can be + + - "prob_uniform" : the probability all the systems are equal, namely 1.0/self.get_nsystems() + + - "prob_sys_size" : the probability of a system is proportional to the number of batches in the system + + - "prob_sys_size;stt_idx:end_idx:weight;stt_idx:end_idx:weight;..." : the list of systems is devided into blocks. A block is specified by `stt_idx:end_idx:weight`, where `stt_idx` is the starting index of the system, `end_idx` is then ending (not including) index of the system, the probabilities of the systems in this block sums up to `weight`, and the relatively probabilities within this block is proportional to the number of batches in the system. + + .. _`training/training_data/sys_probs`: + + sys_probs: + | type: ``NoneType`` | ``list``, optional, default: ``None``, alias: *sys_weights* + | argument path: ``training/training_data/sys_probs`` + + A list of float if specified. Should be of the same length as `systems`, specifying the probability of each system. + + .. _`training/validation_data`: + + validation_data: + | type: ``NoneType`` | ``dict``, optional, default: ``None`` + | argument path: ``training/validation_data`` + + Configurations of validation data. Similar to that of training data, except that a `numb_btch` argument may be configured + + .. _`training/validation_data/systems`: + + systems: + | type: ``list`` | ``str`` + | argument path: ``training/validation_data/systems`` + + The data systems for validation. This key can be provided with a list that specifies the systems, or be provided with a string by which the prefix of all systems are given and the list of the systems is automatically generated. - .. raw:: html + .. _`training/validation_data/set_prefix`: - - systems: - | type: ``list`` | ``str`` - | argument path: ``training/systems`` + set_prefix: + | type: ``str``, optional, default: ``set`` + | argument path: ``training/validation_data/set_prefix`` - The data systems. This key can be provided with a listthat specifies the systems, or be provided with a string by which the prefix of all systems are given and the list of the systems is automatically generated. + The prefix of the sets in the `systems `_. - .. raw:: html + .. _`training/validation_data/batch_size`: - - set_prefix: - | type: ``str``, optional, default: ``set`` - | argument path: ``training/set_prefix`` + batch_size: + | type: ``int`` | ``list`` | ``str``, optional, default: ``auto`` + | argument path: ``training/validation_data/batch_size`` - The prefix of the sets in the `systems <#training/systems>`__. + This key can be - .. raw:: html + - list: the length of which is the same as the `systems `_. The batch size of each system is given by the elements of the list. - - auto_prob: - | type: ``str``, optional, default: ``prob_sys_size`` - | argument path: ``training/auto_prob`` + - int: all `systems `_ use the same batch size. - Determine the probability of systems automatically. The method is assigned by this key and can be + - string "auto": automatically determines the batch size so that the batch_size times the number of atoms in the system is no less than 32. - - "prob_uniform" : the probability all the systems are equal, namely 1.0/self.get_nsystems() + - string "auto:N": automatically determines the batch size so that the batch_size times the number of atoms in the system is no less than N. - - "prob_sys_size" : the probability of a system is proportional to the number of batches in the system + .. _`training/validation_data/auto_prob`: - - "prob_sys_size;stt_idx:end_idx:weight;stt_idx:end_idx:weight;..." : the list of systems is devided into blocks. A block is specified by `stt_idx:end_idx:weight`, where `stt_idx` is the starting index of the system, `end_idx` is then ending (not including) index of the system, the probabilities of the systems in this block sums up to `weight`, and the relatively probabilities within this block is proportional to the number of batches in the system. + auto_prob: + | type: ``str``, optional, default: ``prob_sys_size``, alias: *auto_prob_style* + | argument path: ``training/validation_data/auto_prob`` - .. raw:: html + Determine the probability of systems automatically. The method is assigned by this key and can be - - sys_probs: - | type: ``NoneType`` | ``list``, optional, default: ``None`` - | argument path: ``training/sys_probs`` + - "prob_uniform" : the probability all the systems are equal, namely 1.0/self.get_nsystems() - A list of float, should be of the same length as `train_systems`, specifying the probability of each system. + - "prob_sys_size" : the probability of a system is proportional to the number of batches in the system - .. raw:: html + - "prob_sys_size;stt_idx:end_idx:weight;stt_idx:end_idx:weight;..." : the list of systems is devided into blocks. A block is specified by `stt_idx:end_idx:weight`, where `stt_idx` is the starting index of the system, `end_idx` is then ending (not including) index of the system, the probabilities of the systems in this block sums up to `weight`, and the relatively probabilities within this block is proportional to the number of batches in the system. - - batch_size: - | type: ``int`` | ``list`` | ``str``, optional, default: ``auto`` - | argument path: ``training/batch_size`` + .. _`training/validation_data/sys_probs`: - This key can be + sys_probs: + | type: ``NoneType`` | ``list``, optional, default: ``None``, alias: *sys_weights* + | argument path: ``training/validation_data/sys_probs`` - - list: the length of which is the same as the `systems <#training/systems>`__. The batch size of each system is given by the elements of the list. + A list of float if specified. Should be of the same length as `systems`, specifying the probability of each system. - - int: all `systems <#training/systems>`__ use the same batch size. + .. _`training/validation_data/numb_btch`: - - string "auto": automatically determines the batch size so that the batch_size times the number of atoms in the system is no less than 32. + numb_btch: + | type: ``int``, optional, default: ``1``, alias: *numb_batch* + | argument path: ``training/validation_data/numb_btch`` - - string "auto:N": automatically determines the batch size so that the batch_size times the number of atoms in the system is no less than N. + An integer that specifies the number of systems to be sampled for each validation period. - .. raw:: html + .. _`training/numb_steps`: - numb_steps: - | type: ``int`` + | type: ``int``, alias: *stop_batch* | argument path: ``training/numb_steps`` Number of training batch. Each training uses one batch of data. - .. raw:: html + .. _`training/seed`: - seed: | type: ``int`` | ``NoneType``, optional | argument path: ``training/seed`` The random seed for getting frames from the training data set. - .. raw:: html + .. _`training/disp_file`: - disp_file: | type: ``str``, optional, default: ``lcueve.out`` | argument path: ``training/disp_file`` The file for printing learning curve. - .. raw:: html + .. _`training/disp_freq`: - disp_freq: | type: ``int``, optional, default: ``1000`` | argument path: ``training/disp_freq`` The frequency of printing learning curve. - .. raw:: html + .. _`training/numb_test`: - numb_test: | type: ``int`` | ``list`` | ``str``, optional, default: ``1`` | argument path: ``training/numb_test`` Number of frames used for the test during training. - .. raw:: html + .. _`training/save_freq`: - save_freq: | type: ``int``, optional, default: ``1000`` | argument path: ``training/save_freq`` The frequency of saving check point. - .. raw:: html + .. _`training/save_ckpt`: - save_ckpt: | type: ``str``, optional, default: ``model.ckpt`` | argument path: ``training/save_ckpt`` The file name of saving check point. - .. raw:: html + .. _`training/disp_training`: - disp_training: | type: ``bool``, optional, default: ``True`` | argument path: ``training/disp_training`` Displaying verbose information during training. - .. raw:: html + .. _`training/time_training`: - time_training: | type: ``bool``, optional, default: ``True`` | argument path: ``training/time_training`` Timing durining training. - .. raw:: html + .. _`training/profiling`: - profiling: | type: ``bool``, optional, default: ``False`` | argument path: ``training/profiling`` Profiling during training. - .. raw:: html + .. _`training/profiling_file`: - profiling_file: | type: ``str``, optional, default: ``timeline.json`` | argument path: ``training/profiling_file`` Output file for profiling. - .. raw:: html + .. _`training/tensorboard`: - tensorboard: | type: ``bool``, optional, default: ``False`` | argument path: ``training/tensorboard`` Enable tensorboard - .. raw:: html + .. _`training/tensorboard_log_dir`: - tensorboard_log_dir: | type: ``str``, optional, default: ``log`` | argument path: ``training/tensorboard_log_dir`` From 1a7010505957c453a8bae299ae549ebf9a65b7f4 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 20 Apr 2021 11:44:03 +0800 Subject: [PATCH 385/562] update the doc and examples --- doc/data-conv.md | 41 + doc/train-hybrid.md | 25 + doc/train-se-e2-a.md | 223 ++ doc/train-se-e2-r.md | 23 + doc/train-se-e3.md | 23 + doc/use-deepmd-kit.md | 147 +- examples/data_conv/OUTCAR | 2491 +++++++++++++++++ examples/fparam/train/input.json | 5 +- examples/fparam/train/input_aparam.json | 5 +- .../water/data/{ => data_0}/set.000/box.npy | Bin 3680 -> 3008 bytes examples/water/data/data_0/set.000/coord.npy | Bin 0 -> 184448 bytes examples/water/data/data_0/set.000/energy.npy | Bin 0 -> 448 bytes examples/water/data/data_0/set.000/force.npy | Bin 0 -> 184448 bytes examples/water/data/data_0/type.raw | 192 ++ examples/water/data/data_0/type_map.raw | 2 + .../data/{set.001 => data_1/set.000}/box.npy | Bin 3680 -> 3008 bytes examples/water/data/data_1/set.000/coord.npy | Bin 0 -> 184448 bytes examples/water/data/data_1/set.000/energy.npy | Bin 0 -> 448 bytes examples/water/data/data_1/set.000/force.npy | Bin 0 -> 184448 bytes .../data/{set.002 => data_1/set.001}/box.npy | Bin 3680 -> 3008 bytes examples/water/data/data_1/set.001/coord.npy | Bin 0 -> 184448 bytes examples/water/data/data_1/set.001/energy.npy | Bin 0 -> 448 bytes examples/water/data/data_1/set.001/force.npy | Bin 0 -> 184448 bytes examples/water/data/data_1/type.raw | 192 ++ examples/water/data/data_1/type_map.raw | 2 + .../data/{set.003 => data_2/set.000}/box.npy | Bin 3680 -> 3008 bytes examples/water/data/data_2/set.000/coord.npy | Bin 0 -> 184448 bytes examples/water/data/data_2/set.000/energy.npy | Bin 0 -> 448 bytes examples/water/data/data_2/set.000/force.npy | Bin 0 -> 184448 bytes examples/water/data/data_2/type.raw | 192 ++ examples/water/data/data_2/type_map.raw | 2 + examples/water/data/data_3/set.000/box.npy | Bin 0 -> 3008 bytes examples/water/data/data_3/set.000/coord.npy | Bin 0 -> 184448 bytes examples/water/data/data_3/set.000/energy.npy | Bin 0 -> 448 bytes examples/water/data/data_3/set.000/force.npy | Bin 0 -> 184448 bytes examples/water/data/data_3/type.raw | 192 ++ examples/water/data/data_3/type_map.raw | 2 + examples/water/data/set.000/coord.npy | Bin 230480 -> 0 bytes examples/water/data/set.000/energy.npy | Bin 480 -> 0 bytes examples/water/data/set.000/force.npy | Bin 230480 -> 0 bytes examples/water/data/set.001/coord.npy | Bin 230480 -> 0 bytes examples/water/data/set.001/energy.npy | Bin 480 -> 0 bytes examples/water/data/set.001/force.npy | Bin 230480 -> 0 bytes examples/water/data/set.002/coord.npy | Bin 230480 -> 0 bytes examples/water/data/set.002/energy.npy | Bin 480 -> 0 bytes examples/water/data/set.002/force.npy | Bin 230480 -> 0 bytes examples/water/data/set.003/coord.npy | Bin 230480 -> 0 bytes examples/water/data/set.003/energy.npy | Bin 480 -> 0 bytes examples/water/data/set.003/force.npy | Bin 230480 -> 0 bytes examples/water/data/type.raw | 1 - examples/water/hybrid/input.json | 81 + examples/water/se_e2_a/input.json | 66 + .../water_se_r.json => se_e2_r/input.json} | 31 +- .../water_se_a.json => se_e3/input.json} | 34 +- examples/water/train/.gitignore | 4 - examples/water/train/polar_se_a.json | 60 - examples/water/train/water.json | 70 - examples/water/train/water_se_a.yaml | 68 - examples/water/train/water_se_ar.json | 83 - examples/water/train/water_srtab_example.json | 72 - 60 files changed, 3815 insertions(+), 514 deletions(-) create mode 100644 doc/data-conv.md create mode 100644 doc/train-hybrid.md create mode 100644 doc/train-se-e2-a.md create mode 100644 doc/train-se-e2-r.md create mode 100644 doc/train-se-e3.md create mode 100644 examples/data_conv/OUTCAR rename examples/water/data/{ => data_0}/set.000/box.npy (78%) create mode 100644 examples/water/data/data_0/set.000/coord.npy create mode 100644 examples/water/data/data_0/set.000/energy.npy create mode 100644 examples/water/data/data_0/set.000/force.npy create mode 100644 examples/water/data/data_0/type.raw create mode 100644 examples/water/data/data_0/type_map.raw rename examples/water/data/{set.001 => data_1/set.000}/box.npy (78%) create mode 100644 examples/water/data/data_1/set.000/coord.npy create mode 100644 examples/water/data/data_1/set.000/energy.npy create mode 100644 examples/water/data/data_1/set.000/force.npy rename examples/water/data/{set.002 => data_1/set.001}/box.npy (78%) create mode 100644 examples/water/data/data_1/set.001/coord.npy create mode 100644 examples/water/data/data_1/set.001/energy.npy create mode 100644 examples/water/data/data_1/set.001/force.npy create mode 100644 examples/water/data/data_1/type.raw create mode 100644 examples/water/data/data_1/type_map.raw rename examples/water/data/{set.003 => data_2/set.000}/box.npy (78%) create mode 100644 examples/water/data/data_2/set.000/coord.npy create mode 100644 examples/water/data/data_2/set.000/energy.npy create mode 100644 examples/water/data/data_2/set.000/force.npy create mode 100644 examples/water/data/data_2/type.raw create mode 100644 examples/water/data/data_2/type_map.raw create mode 100644 examples/water/data/data_3/set.000/box.npy create mode 100644 examples/water/data/data_3/set.000/coord.npy create mode 100644 examples/water/data/data_3/set.000/energy.npy create mode 100644 examples/water/data/data_3/set.000/force.npy create mode 100644 examples/water/data/data_3/type.raw create mode 100644 examples/water/data/data_3/type_map.raw delete mode 100644 examples/water/data/set.000/coord.npy delete mode 100644 examples/water/data/set.000/energy.npy delete mode 100644 examples/water/data/set.000/force.npy delete mode 100644 examples/water/data/set.001/coord.npy delete mode 100644 examples/water/data/set.001/energy.npy delete mode 100644 examples/water/data/set.001/force.npy delete mode 100644 examples/water/data/set.002/coord.npy delete mode 100644 examples/water/data/set.002/energy.npy delete mode 100644 examples/water/data/set.002/force.npy delete mode 100644 examples/water/data/set.003/coord.npy delete mode 100644 examples/water/data/set.003/energy.npy delete mode 100644 examples/water/data/set.003/force.npy delete mode 100644 examples/water/data/type.raw create mode 100644 examples/water/hybrid/input.json create mode 100644 examples/water/se_e2_a/input.json rename examples/water/{train/water_se_r.json => se_e2_r/input.json} (69%) rename examples/water/{train/water_se_a.json => se_e3/input.json} (66%) delete mode 100644 examples/water/train/.gitignore delete mode 100644 examples/water/train/polar_se_a.json delete mode 100644 examples/water/train/water.json delete mode 100644 examples/water/train/water_se_a.yaml delete mode 100644 examples/water/train/water_se_ar.json delete mode 100644 examples/water/train/water_srtab_example.json diff --git a/doc/data-conv.md b/doc/data-conv.md new file mode 100644 index 0000000000..1dd1f5a2cb --- /dev/null +++ b/doc/data-conv.md @@ -0,0 +1,41 @@ +# Data + + +In this example we will convert the DFT labeled data stored in VASP `OUTCAR` format into the data format used by DeePMD-kit. The example `OUTCAR` can be found in the directory. +```bash +$deepmd_source_dir/examples/data_conv +``` + + +## Definition + +The DeePMD-kit organize data in **`systems`**. Each `system` is composed by a number of **`frames`**. One may roughly view a `frame` as a snap short on an MD trajectory, but it does not necessary come from an MD simulation. A `frame` records the coordinates and types of atoms, cell vectors if the periodic boundary condition is assumed, energy, atomic forces and virial. It is noted that the `frames` in one `system` share the same number of atoms with the same type. + + + +## Data conversion + +It is conveninent to use [dpdata](https://github.com/deepmodeling/dpdata) to convert data generated by DFT packages to the data format used by DeePMD-kit. + +To install one can execute +```bash +pip install dpdata +``` + +An example of converting data [VASP](https://www.vasp.at/) data in `OUTCAR` format to DeePMD-kit data can be found at +``` +$deepmd_source_dir/examples/data_conv +``` + +Switch to that directory, then one can convert data by using the following python script +```python +import dpdata +dsys = dpdata.LabeledSystem('OUTCAR') +dsys.to('deepmd/npy', 'deepmd_data', set_size = dsys.get_nframes()) +``` + +`get_nframes()` method gets the number of frames in the `OUTCAR`, and the argument `set_size` enforces that the set size is equal to the number of frames in the system, viz. only one `set` is created in the `system`. + +The data in DeePMD-kit format is stored in the folder `deepmd_data`. + +A list of all [supported data format](https://github.com/deepmodeling/dpdata#load-data) and more nice features of `dpdata` can be found at the [official website](https://github.com/deepmodeling/dpdata). diff --git a/doc/train-hybrid.md b/doc/train-hybrid.md new file mode 100644 index 0000000000..8c2097caa8 --- /dev/null +++ b/doc/train-hybrid.md @@ -0,0 +1,25 @@ +# Train a Deep Potential model using descriptor `"hybrid"` + +This descriptor hybridize multiple descriptors to form a new descriptor. For example we have a list of descriptor denoted by D_1, D_2, ..., D_N, the hybrid descriptor this the concatenation of the list, i.e. D = (D_1, D_2, ..., D_N). + +To use the descriptor in DeePMD-kit, one firstly set the `type` to `"hybrid"`, then provide the definitions of the descriptors by the items in the `list`, +```json= + "descriptor" :{ + "type": "hybrid", + "list" : [ + { + "type" : "se_e2_a", + ... + }, + { + "type" : "se_e2_r", + ... + } + ] + }, +``` + +A complete training input script of this example can be found in the directory +```bash +$deepmd_source_dir/examples/water/hybrid/input.json +``` diff --git a/doc/train-se-e2-a.md b/doc/train-se-e2-a.md new file mode 100644 index 0000000000..03bf33295d --- /dev/null +++ b/doc/train-se-e2-a.md @@ -0,0 +1,223 @@ +# Train a Deep Potential model using descriptor `"se_e2_a"` + +The notation of `se_e2_a` is short for the Deep Potential Smooth Edition (DeepPot-SE) constructed from all information (both angular and radial) of atomic configurations. The `e2` stands for the embedding with two-atoms information. This descriptor was described in detail in [the DeepPot-SE paper](https://arxiv.org/abs/1805.09003). + +In this example we will train a DeepPot-SE model for a water system. A complete training input script of this example can be find in the directory. +```bash +$deepmd_source_dir/examples/water/se_e2_a/input.json +``` +With the training input script, data (please read the [warning](#warning)) are also provided in the example directory. One may train the model with the DeePMD-kit from the directory. + +The contents of the example: +- [The training input](#the-training-input-script) +- [Train a Deep Potential model](#train-a-deep-potential-model) +- [Warning](#warning) + +## The training input script + +A working training script using descriptor `se_e2_a` is provided as `input.json` in the same directory as this README. + +The `input.json` is divided in several sections, `model`, `learning_rate`, `loss` and `training`. + +For more information, one can find the [a full documentation](https://deepmd.readthedocs.io/en/master/train-input.html) on the training input script. + +### Model +The `model` defines how the model is constructed, for example +```json= + "model": { + "type_map": ["O", "H"], + "descriptor" :{ + ... + }, + "fitting_net" : { + ... + } + } +``` +We are looking for a model for water, so we have two types of atoms. The atom types are recorded as integers. In this example, we denote `0` for oxygen and `1` for hydrogen. A mapping from the atom type to their names is provided by `type_map`. + +The model has two subsections `descritpor` and `fitting_net`, which defines the descriptor and the fitting net, respectively. The `type_map` is optional, which provides the element names (but not necessarily to be the element name) of the corresponding atom types. + +#### Descriptor +The construction of the descriptor is given by section `descriptor`. An example of the descriptor is provided as follows +```json= + "descriptor" :{ + "type": "se_e2_a", + "rcut_smth": 0.50, + "rcut": 6.00, + "sel": [46, 92], + "neuron": [25, 50, 100], + "axis_neuron": 16, + "resnet_dt": false, + "seed": 1 + } +``` +* The `type` of the descriptor is set to `"se_e2_a"`. +* `rcut` is the cut-off radius for neighbor searching, and the `rcut_smth` gives where the smoothing starts. +* `sel` gives the maximum possible number of neighbors in the cut-off radius. It is a list, the length of which is the same as the number of atom types in the system, and `sel[i]` denote the maximum possible number of neighbors with type `i`. +* The `neuron` specifies the size of the embedding net. From left to right the members denote the sizes of each hidden layer from input end to the output end, respectively. If the outer layer is of twice size as the inner layer, then the inner layer is copied and concatenated, then a [ResNet architecture](https://arxiv.org/abs/1512.03385) is built between them. +* The `axis_neuron` specifies the size of submatrix of the embedding matrix, the axis matrix as explained in the [DeepPot-SE paper](https://arxiv.org/abs/1805.09003) +* If the option `resnet_dt` is set `true`, then a timestep is used in the ResNet. +* `seed` gives the random seed that is used to generate random numbers when initializing the model parameters. + + +#### Fitting +The construction of the fitting net is give by section `fitting_net` +```json= + "fitting_net" : { + "neuron": [240, 240, 240], + "resnet_dt": true, + "seed": 1 + }, +``` +* `neuron` specifies the size of the fitting net. If two neighboring layers are of the same size, then a [ResNet architecture](https://arxiv.org/abs/1512.03385) is built between them. +* If the option `resnet_dt` is set `true`, then a timestep is used in the ResNet. +* `seed` gives the random seed that is used to generate random numbers when initializing the model parameters. + +### Learning rate + +The `learning_rate` section in `input.json` is given as follows +```json= + "learning_rate" :{ + "type": "exp", + "start_lr": 0.001, + "stop_lr": 3.51e-8, + "decay_steps": 5000, + "_comment": "that's all" + } +``` +* `start_lr` gives the learning rate at the beginning of the training. +* `stop_lr` gives the learning rate at the end of the training. It should be small enough to ensure that the network parameters satisfactorily converge. +* During the training, the learning rate decays exponentially from `start_lr` to `stop_lr` following the formula. + ``` + lr(t) = start_lr * decay_rate ^ ( t / decay_steps ) + ``` + where `t` is the training step. +        +### Loss + +The loss function of DeePMD-kit is given by +``` +loss = pref_e * loss_e + pref_f * loss_f + pref_v * loss_v +``` +where `loss_e`, `loss_f` and `loss_v` denote the loss in energy, force and virial, respectively. `pref_e`, `pref_f` and `pref_v` give the prefactors of the energy, force and virial losses. The prefectors may not be a constant, rather it changes linearly with the learning rate. Taking the force prefactor for example, at training step `t`, it is given by +```math +pref_f(t) = start_pref_f * ( lr(t) / start_lr ) + limit_pref_f * ( 1 - lr(t) / start_lr ) +``` +where `lr(t)` denotes the learning rate at step `t`. `start_pref_f` and `limit_pref_f` specifies the `pref_f` at the start of the training and at the limit of `t -> inf`. + +The `loss` section in the `input.json` is +```json= + "loss" : { + "start_pref_e": 0.02, + "limit_pref_e": 1, + "start_pref_f": 1000, + "limit_pref_f": 1, + "start_pref_v": 0, + "limit_pref_v": 0 + } +``` +The options `start_pref_e`, `limit_pref_e`, `start_pref_f`, `limit_pref_f`, `start_pref_v` and `limit_pref_v` determine the start and limit prefactors of energy, force and virial, respectively. + +If one does not want to train with virial, then he/she may set the virial prefactors `start_pref_v` and `limit_pref_v` to 0. +    +### Training parameters + +Other training parameters are given in the `training` section. +```json= + "training": { + "training_data": { + "systems": ["../data_water/data_0/", "../data_water/data_1/", "../data_water/data_2/"], + "batch_size": "auto" + }, + "validation_data":{ + "systems": ["../data_water/data_3"], + "batch_size": 1, + "numb_btch": 3 + }, + + "numb_step": 1000000, + "seed": 1, + "disp_file": "lcurve.out", + "disp_freq": 100, + "save_freq": 1000 + } +``` +The sections `"training_data"` and `"validation_data"` give the training dataset and validation dataset, respectively. Taking the training dataset for example, the keys are explained below: +* `systems` provide paths of the training data systems. DeePMD-kit allows you to provide multiple systems. This key can be a `list` or a `str`. + * `list`: `systems` gives the training data systems. + * `str`: `systems` should be a valid path. DeePMD-kit will recursively search all data systems in this path. +* At each training step, DeePMD-kit randomly pick `batch_size` frame(s) from one of the systems. The probability of using a system is by default in proportion to the number of batches in the system. More optional are available for automatically determining the probability of using systems. One can set the key `auto_prob` to + * `"prob_uniform"` all systems are used with the same probability. + * `"prob_sys_size"` the probability of using a system is in proportional to its size (number of frames). + * `"prob_sys_size; sidx_0:eidx_0:w_0; sidx_1:eidx_1:w_1;..."` the `list` of systems are divided into blocks. The block `i` has systems ranging from `sidx_i` to `eidx_i`. The probability of using a system from block `i` is in proportional to `w_i`. Within one block, the probability of using a system is in proportional to its size. +* An example of using `"auto_prob"` is given as below. The probability of using `systems[2]` is 0.4, and the sum of the probabilities of using `systems[0]` and `systems[1]` is 0.6. If the number of frames in `systems[1]` is twice as `system[0]`, then the probability of using `system[1]` is 0.4 and that of `system[0]` is 0.2. +```json= + "training_data": { + "systems": ["../data_water/data_0/", "../data_water/data_1/", "../data_water/data_2/"], + "auto_prob": "prob_sys_size; 0:2:0.6; 2:3:0.4", + "batch_size": "auto" + } +``` +* The probability of using systems can also be specified explicitly with key `"sys_prob"` that is a list having the length of the number of systems. For example +```json= + "training_data": { + "systems": ["../data_water/data_0/", "../data_water/data_1/", "../data_water/data_2/"], + "sys_prob": [0.5, 0.3, 0.2], + "batch_size": "auto:32" + } +``` +* The key `batch_size` specifies the number of frames used to train or validate the model in a training step. It can be set to + * `list`: the length of which is the same as the `systems`. The batch size of each system is given by the elements of the list. + * `int`: all systems use the same batch size. + * `"auto"`: the same as `"auto:32"`, see `"auto:N"` + * `"auto:N"`: automatically determines the batch size so that the `batch_size` times the number of atoms in the system is no less than `N`. +* The key `numb_batch` in `validate_data` gives the number of batches of model validation. Note that the batches may not be from the same system + +Other keys in the `training` section are explained below: +* `numb_step` The number of training steps. +* `seed` The random seed for getting frames from the training data set. +* `disp_file` The file for printing learning curve. +* `disp_freq` The frequency of printing learning curve. Set in the unit of training steps +* `save_freq` The frequency of saving check point. + + +## Train a Deep Potential model +When the input script is prepared, one may start training by +```bash= +dp train input.json +``` +By default, the verbosity level of the DeePMD-kit is `INFO`, one may see a lot of important information on the code and environment showing on the screen. Among them two pieces of information regarding data systems worth special notice. +```bash= +DEEPMD INFO ---Summary of DataSystem: training ----------------------------------------------- +DEEPMD INFO found 3 system(s): +DEEPMD INFO system natoms bch_sz n_bch prob pbc +DEEPMD INFO ../data_water/data_0/ 192 1 80 0.250 T +DEEPMD INFO ../data_water/data_1/ 192 1 160 0.500 T +DEEPMD INFO ../data_water/data_2/ 192 1 80 0.250 T +DEEPMD INFO -------------------------------------------------------------------------------------- +DEEPMD INFO ---Summary of DataSystem: validation ----------------------------------------------- +DEEPMD INFO found 1 system(s): +DEEPMD INFO system natoms bch_sz n_bch prob pbc +DEEPMD INFO ../data_water/data_3 192 1 80 1.000 T +DEEPMD INFO -------------------------------------------------------------------------------------- +``` +The DeePMD-kit prints detailed informaiton on the training and validation data sets. The data sets are defined by `"training_data"` and `"validation_data"` defined in the `"training"` section of the input script. The training data set is composed by three data systems, while the validation data set is composed by one data system. The number of atoms, batch size, number of batches in the system and the probability of using the system are all shown on the screen. The last column presents if the periodic boundary condition is assumed for the system. + +During the training, the error of the model is tested every `disp_freq` training steps with the batch used to train the model and with `numb_btch` batches from the validating data. The training error and validation error are printed correspondingly in the file `disp_file`. The batch size can be set in the input script by the key `batch_size` in the corresponding sections for training and validation data set. An example of the output +```bash= +# step rmse_val rmse_trn rmse_e_val rmse_e_trn rmse_f_val rmse_f_trn lr + 0 3.33e+01 3.41e+01 1.03e+01 1.03e+01 8.39e-01 8.72e-01 1.0e-03 + 100 2.57e+01 2.56e+01 1.87e+00 1.88e+00 8.03e-01 8.02e-01 1.0e-03 + 200 2.45e+01 2.56e+01 2.26e-01 2.21e-01 7.73e-01 8.10e-01 1.0e-03 + 300 1.62e+01 1.66e+01 5.01e-02 4.46e-02 5.11e-01 5.26e-01 1.0e-03 + 400 1.36e+01 1.32e+01 1.07e-02 2.07e-03 4.29e-01 4.19e-01 1.0e-03 + 500 1.07e+01 1.05e+01 2.45e-03 4.11e-03 3.38e-01 3.31e-01 1.0e-03 +``` +The file contains 8 columns, form right to left, are the training step, the validation loss, training loss, root mean square (RMS) validation error of energy, RMS training error of energy, RMS validation error of force, RMS training error of force and the learning rate. The RMS error (RMSE) of the energy is normalized by number of atoms in the system. + +## Warning +It is warned that the example water data (in folder `examples/water/data`) is of very limited amount, is provided only for testing purpose, and should not be used to train a productive model. + + + diff --git a/doc/train-se-e2-r.md b/doc/train-se-e2-r.md new file mode 100644 index 0000000000..af456f1eaf --- /dev/null +++ b/doc/train-se-e2-r.md @@ -0,0 +1,23 @@ +# Train a Deep Potential model using descriptor `"se_e2_r"` + +The notation of `se_e2_r` is short for the Deep Potential Smooth Edition (DeepPot-SE) constructed from the radial information of atomic configurations. The `e2` stands for the embedding with two-atom information. + +A complete training input script of this example can be found in the directory +```bash +$deepmd_source_dir/examples/water/se_e2_r/input.json +``` + +The training input script is very similar to that of [`se_e2_a`](train-se-e2-a.md#the-training-input-script). The only difference lies in the `descriptor` section +```json= + "descriptor": { + "type": "se_e2_r", + "sel": [46, 92], + "rcut_smth": 0.50, + "rcut": 6.00, + "neuron": [5, 10, 20], + "resnet_dt": false, + "seed": 1, + "_comment": " that's all" + }, +``` +The type of the descriptor is set by the key `"type"`. diff --git a/doc/train-se-e3.md b/doc/train-se-e3.md new file mode 100644 index 0000000000..e854c34231 --- /dev/null +++ b/doc/train-se-e3.md @@ -0,0 +1,23 @@ +# Train a Deep Potential model using descriptor `"se_e3"` + +The notation of `se_e3` is short for the Deep Potential Smooth Edition (DeepPot-SE) constructed from all information (both angular and radial) of atomic configurations. The embedding takes angles between two neighboring atoms as input (denoted by `e3`). + +A complete training input script of this example can be found in the directory +```bash +$deepmd_source_dir/examples/water/se_e3/input.json +``` + +The training input script is very similar to that of [`se_e2_a`](train-se-e2-a.md#the-training-input-script). The only difference lies in the `descriptor` section +```json= + "descriptor": { + "type": "se_e3", + "sel": [40, 80], + "rcut_smth": 0.50, + "rcut": 6.00, + "neuron": [2, 4, 8], + "resnet_dt": false, + "seed": 1, + "_comment": " that's all" + }, +``` +The type of the descriptor is set by the key `"type"`. diff --git a/doc/use-deepmd-kit.md b/doc/use-deepmd-kit.md index e456137578..4f77972127 100644 --- a/doc/use-deepmd-kit.md +++ b/doc/use-deepmd-kit.md @@ -1,8 +1,6 @@ - [Use DeePMD-kit](#use-deepmd-kit) - [Prepare data](#prepare-data) - [Train a model](#train-a-model) - - [The DeePMD model](#the-deepmd-model) - - [The DeepPot-SE model](#the-deeppot-se-model) - [Freeze a model](#freeze-a-model) - [Test a model](#test-a-model) - [Compress a model](#compress-a-model) @@ -50,6 +48,13 @@ $ cat type.raw 0 1 ``` +Sometimes one needs to map the integer types to atom name. The mapping can be given by the file `type_map.raw`. For example +```bash +$ cat type_map.raw +O H +``` +The type `0` is named by `"O"` and the type `1` is named by `"H"`. + The second format is the data sets of `numpy` binary data that are directly used by the training program. User can use the script `$deepmd_source_dir/data/raw/raw_to_set.sh` to convert the prepared raw files to data sets. For example, if we have a raw file that contains 6000 frames, ```bash $ ls @@ -64,135 +69,40 @@ making set 2 ... $ ls box.raw coord.raw energy.raw force.raw set.000 set.001 set.002 type.raw virial.raw ``` -It generates three sets `set.000`, `set.001` and `set.002`, with each set contains 2000 frames. The last set (`set.002`) is used as testing set, while the rest sets (`set.000` and `set.001`) are used as training sets. One do not need to take care of the binary data files in each of the `set.*` directories. The path containing `set.*` and `type.raw` is called a *system*. - -## Train a model +It generates three sets `set.000`, `set.001` and `set.002`, with each set contains 2000 frames. One do not need to take care of the binary data files in each of the `set.*` directories. The path containing `set.*` and `type.raw` is called a *system*. -### Write the input script +### Data preparation with dpdata -The method of training is explained in our [DeePMD][2] and [DeepPot-SE][3] papers. With the source code we provide a small training dataset taken from 400 frames generated by NVT ab-initio water MD trajectory with 300 frames for training and 100 for testing. [An example training parameter file](./examples/water/train/water_se_a.json) is provided. One can try with the training by -```bash -$ cd $deepmd_source_dir/examples/water/train/ -$ dp train water_se_a.json -``` -where `water_se_a.json` is the `json` format parameter file that controls the training. It is also possible to use `yaml` format file with the same keys as json (see `water_se_a.yaml` example). You can use script `json2yaml.py` in `data/json/` dir to convert your json files to yaml. The components of the `water.json` contains four parts, `model`, `learning_rate`, `loss` and `training`. +One can use the a convenient tool `dpdata` to convert data directly from the output of first priciple packages to the DeePMD-kit format. One may follow the [example](data-conv.md) of using `dpdata` to find out how to use it. -The `model` section specify how the deep potential model is built. An example of the smooth-edition is provided as follows -```json - "model": { - "type_map": ["O", "H"], - "descriptor" :{ - "type": "se_a", - "rcut_smth": 5.80, - "rcut": 6.00, - "sel": [46, 92], - "neuron": [25, 50, 100], - "axis_neuron": 16, - "resnet_dt": false, - "seed": 1, - "_comment": " that's all" - }, - "fitting_net" : { - "neuron": [240, 240, 240], - "resnet_dt": true, - "seed": 1, - "_comment": " that's all" - }, - "_comment": " that's all" - } -``` -The **`type_map`** is optional, which provide the element names (but not restricted to) for corresponding atom types. - -The construction of the descriptor is given by option **`descriptor`**. The **`type`** of the descriptor is set to `"se_a"`, which means smooth-edition, angular infomation. The **`rcut`** is the cut-off radius for neighbor searching, and the **`rcut_smth`** gives where the smoothing starts. **`sel`** gives the maximum possible number of neighbors in the cut-off radius. It is a list, the length of which is the same as the number of atom types in the system, and `sel[i]` denote the maximum possible number of neighbors with type `i`. The **`neuron`** specifies the size of the embedding net. From left to right the members denote the sizes of each hidden layers from input end to the output end, respectively. The **`axis_neuron`** specifies the size of submatrix of the embedding matrix, the axis matrix as explained in the [DeepPot-SE paper][3]. If the outer layer is of twice size as the inner layer, then the inner layer is copied and concatenated, then a [ResNet architecture](https://arxiv.org/abs/1512.03385) is build between them. If the option **`resnet_dt`** is set `true`, then a timestep is used in the ResNet. **`seed`** gives the random seed that is used to generate random numbers when initializing the model parameters. - -The construction of the fitting net is give by **`fitting_net`**. The key **`neuron`** specifies the size of the fitting net. If two neighboring layers are of the same size, then a [ResNet architecture](https://arxiv.org/abs/1512.03385) is build between them. If the option **`resnet_dt`** is set `true`, then a timestep is used in the ResNet. **`seed`** gives the random seed that is used to generate random numbers when initializing the model parameters. +## Train a model -An example of the `learning_rate` is given as follows -```json - "learning_rate" :{ - "type": "exp", - "start_lr": 0.005, - "decay_steps": 5000, - "decay_rate": 0.95, - "_comment": "that's all" - } -``` -The option **`start_lr`**, **`decay_rate`** and **`decay_steps`** specify how the learning rate changes. For example, the `t`th batch will be trained with learning rate: -```math -lr(t) = start_lr * decay_rate ^ ( t / decay_steps ) -``` +### Write the input script -An example of the `loss` is -```json - "loss" : { - "start_pref_e": 0.02, - "limit_pref_e": 1, - "start_pref_f": 1000, - "limit_pref_f": 1, - "start_pref_v": 0, - "limit_pref_v": 0, - "_comment": " that's all" - } -``` -The options **`start_pref_e`**, **`limit_pref_e`**, **`start_pref_f`**, **`limit_pref_f`**, **`start_pref_v`** and **`limit_pref_v`** determine how the prefactors of energy error, force error and virial error changes in the loss function (see the appendix of the [DeePMD paper][2] for details). Taking the prefactor of force error for example, the prefactor at batch `t` is -```math -w_f(t) = start_pref_f * ( lr(t) / start_lr ) + limit_pref_f * ( 1 - lr(t) / start_lr ) -``` -Since we do not have virial data, the virial prefactors `start_pref_v` and `limit_pref_v` are set to 0. +A model has two parts, a descriptor that maps atomic configuration to a set of symmetry invariant features, and a fitting net that takes descriptor as input and predicts the atomic contribution to the target physical property. -An example of `training` is -```json - "training" : { - "systems": ["../data1/", "../data2/"], - "set_prefix": "set", - "stop_batch": 1000000, - "_comment": " batch_size can be supplied with, e.g. 1, or auto (string) or [10, 20]", - "batch_size": 1, - - "seed": 1, - - "_comment": " display and restart", - "_comment": " frequencies counted in batch", - "disp_file": "lcurve.out", - "disp_freq": 100, - "_comment": " numb_test can be supplied with, e.g. 1, or XX% (string) or [10, 20]", - "numb_test": 10, - "save_freq": 1000, - "save_ckpt": "model.ckpt", - "load_ckpt": "model.ckpt", - "disp_training":true, - "time_training":true, - "profiling": false, - "profiling_file":"timeline.json", - "_comment": "that's all" - } -``` -The option **`systems`** provide location of the systems (path to `set.*` and `type.raw`). It is a vector, thus DeePMD-kit allows you to provide multiple systems. DeePMD-kit will train the model with the systems in the vector one by one in a cyclic manner. **It is warned that the example water data (in folder `examples/data/water`) is of very limited amount, is provided only for testing purpose, and should not be used to train a productive model.** +DeePMD-kit implements the following descriptors: +1. [`se_e2_a`](train-se-e2-a.md#descriptor): DeepPot-SE constructed from all information (both angular and radial) of atomic configurations. The embedding takes the distance between atoms as input. +2. [`se_e2_r`](train-se-e2-r.md): DeepPot-SE constructed from radial information of atomic configurations. The embedding takes the distance between atoms as input. +3. [`se_e3`](train-se-e3.md): DeepPot-SE constructed from all information (both angular and radial) of atomic configurations. The embedding takes angles between two neighboring atoms as input. +4. `loc_frame`: Defines a local frame at each atom, and the compute the descriptor as local coordinates under this frame. +5. [`hybrid`](train-hybrid.md): Concate a list of descriptors to form a new descriptor. -The option **`batch_size`** specifies the number of frames in each batch. It can be set to `"auto"` to enable a automatic batch size or it can be input as a list setting batch size individually for each system. -The option **`stop_batch`** specifies the total number of batches will be used in the training. +The fitting of the following physical properties are supported +1. [`ener`](train-se-e2-a.md#fitting) Fitting the energy of the system. The force (derivative with atom positions) and the virial (derivative with the box tensor) can also be trained. See [the example](train-se-e2-a.md#loss). +2. `dipole` The dipole moment. +3. `polar` The polarizability. -The option **`numb_test`** specifies the number of tests that will be used for each system. If it is an integer each system will be tested with the same number of tests. It can be set to percentage `"XX%"` to use XX% of frames of each system for its testing or it can be input as a list setting numer of tests individually for each system (the order should correspond to ordering of the systems key in json). ### Training The training can be invoked by ```bash -$ dp train water_se_a.json -``` - -During the training, the error of the model is tested every **`disp_freq`** batches with **`numb_test`** frames from the last set in the **`systems`** directory on the fly, and the results are output to **`disp_file`**. A typical `disp_file` looks like -```bash -# batch l2_tst l2_trn l2_e_tst l2_e_trn l2_f_tst l2_f_trn lr - 0 2.67e+01 2.57e+01 2.21e-01 2.22e-01 8.44e-01 8.12e-01 1.0e-03 - 100 6.14e+00 5.40e+00 3.01e-01 2.99e-01 1.93e-01 1.70e-01 1.0e-03 - 200 5.02e+00 4.49e+00 1.53e-01 1.53e-01 1.58e-01 1.42e-01 1.0e-03 - 300 4.36e+00 3.71e+00 7.32e-02 7.27e-02 1.38e-01 1.17e-01 1.0e-03 - 400 4.04e+00 3.29e+00 3.16e-02 3.22e-02 1.28e-01 1.04e-01 1.0e-03 +$ dp train input.json ``` -The first column displays the number of batches. The second and third columns display the loss function evaluated by `numb_test` frames randomly chosen from the test set and that evaluated by the current training batch, respectively. The fourth and fifth columns display the RMS energy error (normalized by number of atoms) evaluated by `numb_test` frames randomly chosen from the test set and that evaluated by the current training batch, respectively. The sixth and seventh columns display the RMS force error (component-wise) evaluated by `numb_test` frames randomly chosen from the test set and that evaluated by the current training batch, respectively. The last column displays the current learning rate. +where `input.json` is the name of the input script. See [the example](train-se-e2-a.md#train-a-deep-potential-model) for more details. -Checkpoints will be written to files with prefix **`save_ckpt`** every **`save_freq`** batches. If **`restart`** is set to `true`, then the training will start from the checkpoint named **`load_ckpt`**, rather than from scratch. +During the training, checkpoints will be written to files with prefix `save_ckpt` every `save_freq` training steps. Several command line options can be passed to `dp train`, which can be checked with ```bash @@ -209,9 +119,8 @@ optional arguments: Initialize a model by the provided checkpoint --restart RESTART Restart the training from the provided checkpoint ``` -The keys `intra_op_parallelism_threads` and `inter_op_parallelism_threads` are Tensorflow configurations for multithreading, which are explained [here](https://www.tensorflow.org/performance/performance_guide#optimizing_for_cpu). Skipping `-t` and `OMP_NUM_THREADS` leads to the default setting of these keys in the Tensorflow. -**`--init-model model.ckpt`**, for example, initializes the model training with an existing model that is stored in the checkpoint `model.ckpt`, the network architectures should match. +**`--init-model model.ckpt`**, initializes the model training with an existing model that is stored in the checkpoint `model.ckpt`, the network architectures should match. **`--restart model.ckpt`**, continues the training from the checkpoint `model.ckpt`. @@ -332,7 +241,7 @@ The model compression method requires that the version of DeePMD-kit used in ori ## Model inference One may use the python interface of DeePMD-kit for model inference, an example is given as follows ```python -from deepmd import DeepPot +from deepmd.infer import DeepPot import numpy as np dp = DeepPot('graph.pb') coord = np.array([[1,0,0], [0,0,1.5], [1,0,3]]).reshape([1, -1]) diff --git a/examples/data_conv/OUTCAR b/examples/data_conv/OUTCAR new file mode 100644 index 0000000000..a1d06ea578 --- /dev/null +++ b/examples/data_conv/OUTCAR @@ -0,0 +1,2491 @@ + vasp.5.4.4.18Apr17-6-g9f103f2a35 (build Jan 29 2020 12:26:58) complex + + executed on LinuxIFC date 2020.05.07 01:33:18 + running on 16 total cores + distrk: each k-point on 16 cores, 1 groups + distr: one band on NCORES_PER_BAND= 1 cores, 16 groups + + +-------------------------------------------------------------------------------------------------------- + + + INCAR: + POTCAR: PAW_PBE O_h 06Feb2004 + POTCAR: PAW_PBE H_h 06Feb2004 + + ----------------------------------------------------------------------------- +| | +| W W AA RRRRR N N II N N GGGG !!! | +| W W A A R R NN N II NN N G G !!! | +| W W A A R R N N N II N N N G !!! | +| W WW W AAAAAA RRRRR N N N II N N N G GGG ! | +| WW WW A A R R N NN II N NN G G | +| W W A A R R N N II N N GGGG !!! | +| | +| For optimal performance we recommend to set | +| NCORE= 4 - approx SQRT( number of cores) | +| NCORE specifies how many cores store one orbital (NPAR=cpu/NCORE). | +| This setting can greatly improve the performance of VASP for DFT. | +| The default, NCORE=1 might be grossly inefficient | +| on modern multi-core architectures or massively parallel machines. | +| Do your own testing !!!! | +| Unfortunately you need to use the default for GW and RPA calculations. | +| (for HF NCORE is supported but not extensively tested yet) | +| | + ----------------------------------------------------------------------------- + + POTCAR: PAW_PBE O_h 06Feb2004 + VRHFIN =O: s2p4 + LEXCH = PE + EATOM = 432.3788 eV, 31.7789 Ry + + TITEL = PAW_PBE O_h 06Feb2004 + LULTRA = F use ultrasoft PP ? + IUNSCR = 1 unscreen: 0-lin 1-nonlin 2-no + RPACOR = 0.800 partial core radius + POMASS = 16.000; ZVAL = 6.000 mass and valenz + RCORE = 1.100 outmost cutoff radius + RWIGS = 1.400; RWIGS = 0.741 wigner-seitz radius (au A) + ENMAX = 700.000; ENMIN = 500.000 eV + ICORE = 2 local potential + LCOR = T correct aug charges + LPAW = T paw PP + EAUG = 888.804 + DEXC = 0.000 + RMAX = 1.128 core radius for proj-oper + RAUG = 1.300 factor for augmentation sphere + RDEP = 1.125 radius for radial grids + RDEPT = 1.088 core radius for aug-charge + + Atomic configuration + 4 entries + n l j E occ. + 1 0 0.50 -514.6923 2.0000 + 2 0 0.50 -23.9615 2.0000 + 2 1 0.50 -9.0305 4.0000 + 3 2 1.50 -9.5241 0.0000 + Description + l E TYP RCUT TYP RCUT + 0 -23.9615319 23 1.100 + 0 -25.3221145 23 1.100 + 1 -9.0304911 23 1.100 + 1 -5.4802209 23 1.100 + 2 -9.5240782 7 1.100 + local pseudopotential read in + partial core-charges read in + partial kinetic energy density read in + atomic valenz-charges read in + non local Contribution for L= 0 read in + real space projection operators read in + non local Contribution for L= 0 read in + real space projection operators read in + non local Contribution for L= 1 read in + real space projection operators read in + non local Contribution for L= 1 read in + real space projection operators read in + PAW grid and wavefunctions read in + + number of l-projection operators is LMAX = 4 + number of lm-projection operators is LMMAX = 8 + + POTCAR: PAW_PBE H_h 06Feb2004 + VRHFIN =H: ultrasoft test + LEXCH = PE + EATOM = 12.4884 eV, 0.9179 Ry + + TITEL = PAW_PBE H_h 06Feb2004 + LULTRA = F use ultrasoft PP ? + IUNSCR = 0 unscreen: 0-lin 1-nonlin 2-no + RPACOR = 0.000 partial core radius + POMASS = 1.000; ZVAL = 1.000 mass and valenz + RCORE = 0.800 outmost cutoff radius + RWIGS = 0.700; RWIGS = 0.370 wigner-seitz radius (au A) + ENMAX = 700.000; ENMIN = 350.000 eV + RCLOC = 0.701 cutoff for local pot + LCOR = T correct aug charges + LPAW = T paw PP + EAUG = 1000.000 + RMAX = 0.819 core radius for proj-oper + RAUG = 1.000 factor for augmentation sphere + RDEP = 0.817 radius for radial grids + RDEPT = 0.817 core radius for aug-charge + + Atomic configuration + 2 entries + n l j E occ. + 1 0 0.50 -6.4927 1.0000 + 2 1 0.50 -3.4015 0.0000 + Description + l E TYP RCUT TYP RCUT + 0 -6.4927493 23 0.800 + 0 6.8029130 23 0.800 + 1 -6.8029130 23 0.800 + local pseudopotential read in + atomic valenz-charges read in + non local Contribution for L= 0 read in + real space projection operators read in + non local Contribution for L= 0 read in + real space projection operators read in + non local Contribution for L= 1 read in + real space projection operators read in + PAW grid and wavefunctions read in + + number of l-projection operators is LMAX = 3 + number of lm-projection operators is LMMAX = 5 + + PAW_PBE O_h 06Feb2004 : + energy of atom 1 EATOM= -432.3788 + kinetic energy error for atom= 0.0035 (will be added to EATOM!!) + PAW_PBE H_h 06Feb2004 : + energy of atom 2 EATOM= -12.4884 + kinetic energy error for atom= 0.0001 (will be added to EATOM!!) + + + POSCAR: O2 H4 + positions in cartesian coordinates + No initial velocities read in + exchange correlation table for LEXCH = 8 + RHO(1)= 0.500 N(1) = 2000 + RHO(2)= 100.500 N(2) = 4000 + + + +-------------------------------------------------------------------------------------------------------- + + + ion position nearest neighbor table + 1 0.121 0.105 0.117- 4 1.01 3 1.03 + 2 0.879 0.105 0.117- 6 1.02 5 1.02 + 3 0.132 0.170 0.116- 1 1.03 + 4 0.088 0.111 0.118- 1 1.01 + 5 0.870 0.066 0.171- 2 1.02 + 6 0.870 0.066 0.064- 2 1.02 + + +IMPORTANT INFORMATION: All symmetrisations will be switched off! +NOSYMM: (Re-)initialisation of all symmetry stuff for point group C_1. + + + + +Automatic generation of k-mesh. + generate k-points for: 1 1 1 +Space group operators: + irot det(A) alpha n_x n_y n_z tau_x tau_y tau_z + 1 1.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 + + Subroutine IBZKPT returns following result: + =========================================== + + Found 1 irreducible k-points: + + Following reciprocal coordinates: + Coordinates Weight + 0.000000 0.000000 0.000000 1.000000 + + Following cartesian coordinates: + Coordinates Weight + 0.000000 0.000000 0.000000 1.000000 + + + Subroutine IBZKPT_HF returns following result: + ============================================== + + Found 1 k-points in 1st BZ + the following 1 k-points will be used (e.g. in the exchange kernel) + Following reciprocal coordinates: # in IRBZ + 0.000000 0.000000 0.000000 1.00000000 1 t-inv F + + +-------------------------------------------------------------------------------------------------------- + + + + + Dimension of arrays: + k-points NKPTS = 1 k-points in BZ NKDIM = 1 number of bands NBANDS= 16 + number of dos NEDOS = 301 number of ions NIONS = 6 + non local maximal LDIM = 4 non local SUM 2l+1 LMDIM = 8 + total plane-waves NPLWV = ****** + max r-space proj IRMAX = 1 max aug-charges IRDMAX= 15493 + dimension x,y,z NGX = 384 NGY = 192 NGZ = 192 + dimension x,y,z NGXF= 768 NGYF= 384 NGZF= 384 + support grid NGXF= 768 NGYF= 384 NGZF= 384 + ions per type = 2 4 + NGX,Y,Z is equivalent to a cutoff of 21.28, 21.28, 21.28 a.u. + NGXF,Y,Z is equivalent to a cutoff of 42.56, 42.56, 42.56 a.u. + + SYSTEM = unknown system + POSCAR = O2 H4 + + Startparameter for this run: + NWRITE = 2 write-flag & timer + PREC = a normal or accurate (medium, high low for compatibility) + ISTART = 0 job : 0-new 1-cont 2-samecut + ICHARG = 2 charge: 1-file 2-atom 10-const + ISPIN = 1 spin polarized calculation? + LNONCOLLINEAR = F non collinear calculations + LSORBIT = F spin-orbit coupling + INIWAV = 1 electr: 0-lowe 1-rand 2-diag + LASPH = F aspherical Exc in radial PAW + METAGGA= F non-selfconsistent MetaGGA calc. + + Electronic Relaxation 1 + ENCUT = 1500.0 eV 110.25 Ry 10.50 a.u. 94.74 47.37 47.37*2*pi/ulx,y,z + ENINI = 1500.0 initial cutoff + ENAUG = 1000.0 eV augmentation charge cutoff + NELM = 60; NELMIN= 4; NELMDL= -5 # of ELM steps + EDIFF = 0.1E-07 stopping-criterion for ELM + LREAL = F real-space projection + NLSPLINE = F spline interpolate recip. space projectors + LCOMPAT= F compatible to vasp.4.4 + GGA_COMPAT = T GGA compatible to vasp.4.4-vasp.4.6 + LMAXPAW = -100 max onsite density + LMAXMIX = 2 max onsite mixed and CHGCAR + VOSKOWN= 0 Vosko Wilk Nusair interpolation + ROPT = 0.00000 0.00000 + Ionic relaxation + EDIFFG = 0.1E-06 stopping-criterion for IOM + NSW = 0 number of steps for IOM + NBLOCK = 1; KBLOCK = 1 inner block; outer block + IBRION = -1 ionic relax: 0-MD 1-quasi-New 2-CG + NFREE = 0 steps in history (QN), initial steepest desc. (CG) + ISIF = 2 stress and relaxation + IWAVPR = 10 prediction: 0-non 1-charg 2-wave 3-comb + ISYM = 0 0-nonsym 1-usesym 2-fastsym + LCORR = T Harris-Foulkes like correction to forces + + POTIM = 0.5000 time-step for ionic-motion + TEIN = 0.0 initial temperature + TEBEG = 0.0; TEEND = 0.0 temperature during run + SMASS = -3.00 Nose mass-parameter (am) + estimated Nose-frequenzy (Omega) = 0.10E-29 period in steps =****** mass= -0.206E-25a.u. + SCALEE = 1.0000 scale energy and forces + NPACO = 256; APACO = 16.0 distance and # of slots for P.C. + PSTRESS= 0.0 pullay stress + + Mass of Ions in am + POMASS = 16.00 1.00 + Ionic Valenz + ZVAL = 6.00 1.00 + Atomic Wigner-Seitz radii + RWIGS = -1.00 -1.00 + virtual crystal weights + VCA = 1.00 1.00 + NELECT = 16.0000 total number of electrons + NUPDOWN= -1.0000 fix difference up-down + + DOS related values: + EMIN = 10.00; EMAX =-10.00 energy-range for DOS + EFERMI = 0.00 + ISMEAR = 0; SIGMA = 0.05 broadening in eV -4-tet -1-fermi 0-gaus + + Electronic relaxation 2 (details) + IALGO = 68 algorithm + LDIAG = T sub-space diagonalisation (order eigenvalues) + LSUBROT= F optimize rotation matrix (better conditioning) + TURBO = 0 0=normal 1=particle mesh + IRESTART = 0 0=no restart 2=restart with 2 vectors + NREBOOT = 0 no. of reboots + NMIN = 0 reboot dimension + EREF = 0.00 reference energy to select bands + IMIX = 4 mixing-type and parameters + AMIX = 0.40; BMIX = 1.00 + AMIX_MAG = 1.60; BMIX_MAG = 1.00 + AMIN = 0.10 + WC = 100.; INIMIX= 1; MIXPRE= 1; MAXMIX= -45 + + Intra band minimization: + WEIMIN = 0.0000 energy-eigenvalue tresh-hold + EBREAK = 0.16E-09 absolut break condition + DEPER = 0.30 relativ break condition + + TIME = 0.40 timestep for ELM + + volume/ion in A,a.u. = 1125.00 7591.87 + Fermi-wavevector in a.u.,A,eV,Ry = 0.218280 0.412489 0.648264 0.047646 + Thomas-Fermi vector in A = 0.996232 + + Write flags + LWAVE = F write WAVECAR + LDOWNSAMPLE = F k-point downsampling of WAVECAR + LCHARG = F write CHGCAR + LVTOT = F write LOCPOT, total local potential + LVHAR = F write LOCPOT, Hartree potential only + LELF = F write electronic localiz. function (ELF) + LORBIT = 0 0 simple, 1 ext, 2 COOP (PROOUT), +10 PAW based schemes + + + Dipole corrections + LMONO = F monopole corrections only (constant potential shift) + LDIPOL = F correct potential (dipole corrections) + IDIPOL = 0 1-x, 2-y, 3-z, 4-all directions + EPSILON= 1.0000000 bulk dielectric constant + + Exchange correlation treatment: + GGA = -- GGA type + LEXCH = 8 internal setting for exchange type + VOSKOWN= 0 Vosko Wilk Nusair interpolation + LHFCALC = F Hartree Fock is set to + LHFONE = F Hartree Fock one center treatment + AEXX = 0.0000 exact exchange contribution + + Linear response parameters + LEPSILON= F determine dielectric tensor + LRPA = F only Hartree local field effects (RPA) + LNABLA = F use nabla operator in PAW spheres + LVEL = F velocity operator in full k-point grid + LINTERFAST= F fast interpolation + KINTER = 0 interpolate to denser k-point grid + CSHIFT =0.1000 complex shift for real part using Kramers Kronig + OMEGAMAX= -1.0 maximum frequency + DEG_THRESHOLD= 0.2000000E-02 threshold for treating states as degnerate + RTIME = -0.100 relaxation time in fs + (WPLASMAI= 0.000 imaginary part of plasma frequency in eV, 0.658/RTIME) + DFIELD = 0.0000000 0.0000000 0.0000000 field for delta impulse in time + + Orbital magnetization related: + ORBITALMAG= F switch on orbital magnetization + LCHIMAG = F perturbation theory with respect to B field + DQ = 0.001000 dq finite difference perturbation B field + LLRAUG = F two centre corrections for induced B field + + + +-------------------------------------------------------------------------------------------------------- + + + Static calculation + charge density and potential will be updated during run + non-spin polarized calculation + RMM-DIIS sequential band-by-band and + variant of blocked Davidson during initial phase + perform sub-space diagonalisation + before iterative eigenvector-optimisation + modified Broyden-mixing scheme, WC = 100.0 + initial mixing is a Kerker type mixing with AMIX = 0.4000 and BMIX = 1.0000 + Hartree-type preconditioning will be used + using additional bands 8 + reciprocal scheme for non local part + use partial core corrections + calculate Harris-corrections to forces + (improved forces if not selfconsistent) + use gradient corrections + use of overlap-Matrix (Vanderbilt PP) + Gauss-broadening in eV SIGMA = 0.05 + + +-------------------------------------------------------------------------------------------------------- + + + energy-cutoff : 1500.00 + volume of cell : 6750.00 + direct lattice vectors reciprocal lattice vectors + 30.000000000 0.000000000 0.000000000 0.033333333 0.000000000 0.000000000 + 0.000000000 15.000000000 0.000000000 0.000000000 0.066666667 0.000000000 + 0.000000000 0.000000000 15.000000000 0.000000000 0.000000000 0.066666667 + + length of vectors + 30.000000000 15.000000000 15.000000000 0.033333333 0.066666667 0.066666667 + + + + k-points in units of 2pi/SCALE and weight: read from INCAR + 0.00000000 0.00000000 0.00000000 1.000 + + k-points in reciprocal lattice and weights: read from INCAR + 0.00000000 0.00000000 0.00000000 1.000 + + position of ions in fractional coordinates (direct lattice) + 0.12126746 0.10473971 0.11733333 + 0.87873254 0.10473971 0.11733333 + 0.13194264 0.17027479 0.11626154 + 0.08787106 0.11115189 0.11766219 + 0.86972453 0.06627868 0.17073627 + 0.86985000 0.06605326 0.06404818 + + position of ions in cartesian coordinates (Angst): + 3.63802389 1.57109570 1.76000001 + 26.36197611 1.57109570 1.76000001 + 3.95827906 2.55412181 1.74392306 + 2.63613168 1.66727831 1.76493284 + 26.09173582 0.99418024 2.56104402 + 26.09549990 0.99079897 0.96072265 + + + +-------------------------------------------------------------------------------------------------------- + + + k-point 1 : 0.0000 0.0000 0.0000 plane waves: 889965 + + maximum and minimum number of plane-waves per node : 889965 889965 + + maximum number of plane-waves: 889965 + maximum index in each direction: + IXMAX= 94 IYMAX= 47 IZMAX= 47 + IXMIN= -94 IYMIN= -47 IZMIN= -47 + + + serial 3D FFT for wavefunctions + parallel 3D FFT for charge: + minimum data exchange during FFTs selected (reduces bandwidth) + + + total amount of memory used by VASP MPI-rank0 1504469. kBytes +======================================================================= + + base : 30000. kBytes + nonl-proj : 199352. kBytes + fftplans : 295613. kBytes + grid : 965246. kBytes + one-center: 18. kBytes + wavefun : 14240. kBytes + + INWAV: cpu time 0.0000: real time 0.0000 + Broyden mixing: mesh for mixing (old mesh) + NGX =189 NGY = 95 NGZ = 95 + (NGX =768 NGY =384 NGZ =384) + gives a total of ****** points + + initial charge density was supplied: + charge density of overlapping atoms calculated + number of electron 16.0000000 magnetization + keeping initial charge density in first step + + +-------------------------------------------------------------------------------------------------------- + + + Maximum index for augmentation-charges 886 (set IRDMAX) + + +-------------------------------------------------------------------------------------------------------- + + + First call to EWALD: gamma= 0.094 + Maximum number of real-space cells 2x 3x 3 + Maximum number of reciprocal cells 4x 2x 2 + + FEWALD: cpu time 0.0022: real time 0.0022 + + +--------------------------------------- Iteration 1( 1) --------------------------------------- + + + POTLOK: cpu time 7.8125: real time 7.8318 + SETDIJ: cpu time 0.0016: real time 0.0017 + EDDAV: cpu time 7.6793: real time 7.6982 + DOS: cpu time 0.0012: real time 0.0013 + -------------------------------------------- + LOOP: cpu time 15.4947: real time 15.5330 + + eigenvalue-minimisations : 48 + total energy-change (2. order) : 0.1514268E+03 (-0.4031052E+03) + number of electron 16.0000000 magnetization + augmentation part 16.0000000 magnetization + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -972.38151982 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 60.59470546 + PAW double counting = 697.41634940 -699.85762974 + entropy T*S EENTRO = -0.00002531 + eigenvalues EBANDS = -96.53607144 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = 151.42675751 eV + + energy without entropy = 151.42678283 energy(sigma->0) = 151.42677017 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 2) --------------------------------------- + + + EDDAV: cpu time 9.5427: real time 9.5657 + DOS: cpu time 0.0011: real time 0.0011 + -------------------------------------------- + LOOP: cpu time 9.5438: real time 9.5667 + + eigenvalue-minimisations : 64 + total energy-change (2. order) :-0.1039947E+03 (-0.1039945E+03) + number of electron 16.0000000 magnetization + augmentation part 16.0000000 magnetization + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -972.38151982 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 60.59470546 + PAW double counting = 697.41634940 -699.85762974 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -200.53075803 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = 47.43209623 eV + + energy without entropy = 47.43209623 energy(sigma->0) = 47.43209623 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 3) --------------------------------------- + + + EDDAV: cpu time 7.6121: real time 7.6304 + DOS: cpu time 0.0009: real time 0.0009 + -------------------------------------------- + LOOP: cpu time 7.6130: real time 7.6314 + + eigenvalue-minimisations : 48 + total energy-change (2. order) :-0.7308666E+02 (-0.7308666E+02) + number of electron 16.0000000 magnetization + augmentation part 16.0000000 magnetization + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -972.38151982 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 60.59470546 + PAW double counting = 697.41634940 -699.85762974 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -273.61741821 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -25.65456395 eV + + energy without entropy = -25.65456395 energy(sigma->0) = -25.65456395 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 4) --------------------------------------- + + + EDDAV: cpu time 5.6924: real time 5.7061 + DOS: cpu time 0.0010: real time 0.0010 + -------------------------------------------- + LOOP: cpu time 5.6934: real time 5.7071 + + eigenvalue-minimisations : 32 + total energy-change (2. order) :-0.6216357E+01 (-0.6216357E+01) + number of electron 16.0000000 magnetization + augmentation part 16.0000000 magnetization + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -972.38151982 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 60.59470546 + PAW double counting = 697.41634940 -699.85762974 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -279.83377498 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -31.87092072 eV + + energy without entropy = -31.87092072 energy(sigma->0) = -31.87092072 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 5) --------------------------------------- + + + EDDAV: cpu time 9.5565: real time 9.5798 + DOS: cpu time 0.0009: real time 0.0009 + CHARGE: cpu time 1.7681: real time 1.7724 + MIXING: cpu time 0.1715: real time 0.1721 + -------------------------------------------- + LOOP: cpu time 11.4970: real time 11.5251 + + eigenvalue-minimisations : 64 + total energy-change (2. order) :-0.1289698E+00 (-0.1289698E+00) + number of electron 16.0000000 magnetization + augmentation part 0.2051310 magnetization + + Broyden mixing: + rms(total) = 0.18249E+01 rms(broyden)= 0.18249E+01 + rms(prec ) = 0.18540E+01 + weight for this iteration 100.00 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -972.38151982 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 60.59470546 + PAW double counting = 697.41634940 -699.85762974 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -279.96274475 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -31.99989048 eV + + energy without entropy = -31.99989048 energy(sigma->0) = -31.99989048 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 6) --------------------------------------- + + + POTLOK: cpu time 7.6238: real time 7.6421 + SETDIJ: cpu time 0.0014: real time 0.0014 + EDDIAG: cpu time 1.4681: real time 1.4721 + RMM-DIIS: cpu time 10.8174: real time 10.8434 + ORTHCH: cpu time 0.0504: real time 0.0506 + DOS: cpu time 0.0003: real time 0.0003 + CHARGE: cpu time 1.7771: real time 1.7815 + MIXING: cpu time 0.1561: real time 0.1565 + -------------------------------------------- + LOOP: cpu time 21.8947: real time 21.9479 + + eigenvalue-minimisations : 48 + total energy-change (2. order) : 0.3401693E+01 (-0.1284952E+01) + number of electron 16.0000000 magnetization + augmentation part 0.1254852 magnetization + + Broyden mixing: + rms(total) = 0.18033E+01 rms(broyden)= 0.18033E+01 + rms(prec ) = 0.18063E+01 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 0.4926 + 0.4926 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1018.21992079 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.07085790 + PAW double counting = 1513.45144763 -1516.49098254 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -232.60054874 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.59819759 eV + + energy without entropy = -28.59819759 energy(sigma->0) = -28.59819759 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 7) --------------------------------------- + + + POTLOK: cpu time 7.6784: real time 7.6969 + SETDIJ: cpu time 0.0013: real time 0.0013 + EDDIAG: cpu time 1.4491: real time 1.4526 + RMM-DIIS: cpu time 11.7565: real time 11.7847 + ORTHCH: cpu time 0.0517: real time 0.0518 + DOS: cpu time 0.0005: real time 0.0005 + CHARGE: cpu time 1.7699: real time 1.7742 + MIXING: cpu time 0.1616: real time 0.1620 + -------------------------------------------- + LOOP: cpu time 22.8690: real time 22.9239 + + eigenvalue-minimisations : 54 + total energy-change (2. order) : 0.4794357E-01 (-0.1172557E+00) + number of electron 16.0000000 magnetization + augmentation part 0.1054543 magnetization + + Broyden mixing: + rms(total) = 0.15927E+01 rms(broyden)= 0.15927E+01 + rms(prec ) = 0.15947E+01 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 1.8963 + 1.7150 2.0777 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1023.40193777 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.35110808 + PAW double counting = 2211.92332504 -2214.95865315 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -227.65504518 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.55025402 eV + + energy without entropy = -28.55025402 energy(sigma->0) = -28.55025402 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 8) --------------------------------------- + + + POTLOK: cpu time 7.6686: real time 7.6873 + SETDIJ: cpu time 0.0013: real time 0.0013 + EDDIAG: cpu time 1.4660: real time 1.4696 + RMM-DIIS: cpu time 10.5114: real time 10.5366 + ORTHCH: cpu time 0.0525: real time 0.0526 + DOS: cpu time 0.0005: real time 0.0005 + CHARGE: cpu time 1.7796: real time 1.7838 + MIXING: cpu time 0.1670: real time 0.1674 + -------------------------------------------- + LOOP: cpu time 21.6468: real time 21.6989 + + eigenvalue-minimisations : 46 + total energy-change (2. order) :-0.8265731E+00 (-0.6778624E+00) + number of electron 16.0000000 magnetization + augmentation part 0.1566603 magnetization + + Broyden mixing: + rms(total) = 0.11958E+01 rms(broyden)= 0.11958E+01 + rms(prec ) = 0.12069E+01 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 1.3893 + 2.2500 0.9590 0.9590 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1009.44372392 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 62.60721834 + PAW double counting = 6839.84251395 -6842.35630999 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -242.21747444 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -29.37682711 eV + + energy without entropy = -29.37682711 energy(sigma->0) = -29.37682711 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 9) --------------------------------------- + + + POTLOK: cpu time 7.6537: real time 7.6720 + SETDIJ: cpu time 0.0015: real time 0.0015 + EDDIAG: cpu time 1.4659: real time 1.4695 + RMM-DIIS: cpu time 10.7640: real time 10.7901 + ORTHCH: cpu time 0.0521: real time 0.0522 + DOS: cpu time 0.0004: real time 0.0004 + CHARGE: cpu time 1.7702: real time 1.7744 + MIXING: cpu time 0.1729: real time 0.1733 + -------------------------------------------- + LOOP: cpu time 21.8807: real time 21.9334 + + eigenvalue-minimisations : 48 + total energy-change (2. order) : 0.1056462E+01 (-0.2351360E+00) + number of electron 16.0000000 magnetization + augmentation part 0.1272037 magnetization + + Broyden mixing: + rms(total) = 0.41679E+00 rms(broyden)= 0.41679E+00 + rms(prec ) = 0.41912E+00 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 1.0796 + 2.1632 0.8623 0.8623 0.4304 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1029.98144592 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.71854898 + PAW double counting = 5755.03792464 -5757.88626392 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -221.40007737 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.32036463 eV + + energy without entropy = -28.32036463 energy(sigma->0) = -28.32036463 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 10) --------------------------------------- + + + POTLOK: cpu time 7.6539: real time 7.6722 + SETDIJ: cpu time 0.0014: real time 0.0014 + EDDIAG: cpu time 1.4730: real time 1.4765 + RMM-DIIS: cpu time 11.7614: real time 11.7896 + ORTHCH: cpu time 0.0515: real time 0.0517 + DOS: cpu time 0.0006: real time 0.0006 + CHARGE: cpu time 1.7441: real time 1.7485 + MIXING: cpu time 0.1927: real time 0.1932 + -------------------------------------------- + LOOP: cpu time 22.8786: real time 22.9336 + + eigenvalue-minimisations : 54 + total energy-change (2. order) :-0.4627474E-02 (-0.1961741E-01) + number of electron 16.0000000 magnetization + augmentation part 0.1175680 magnetization + + Broyden mixing: + rms(total) = 0.20948E+00 rms(broyden)= 0.20948E+00 + rms(prec ) = 0.21117E+00 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 1.5721 + 2.5467 2.5467 0.9597 0.9037 0.9037 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1030.92096977 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.76203534 + PAW double counting = 5508.64806262 -5511.51065269 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -220.49441655 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.32499210 eV + + energy without entropy = -28.32499210 energy(sigma->0) = -28.32499210 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 11) --------------------------------------- + + + POTLOK: cpu time 7.6712: real time 7.6896 + SETDIJ: cpu time 0.0015: real time 0.0015 + EDDIAG: cpu time 1.4703: real time 1.4739 + RMM-DIIS: cpu time 9.8039: real time 9.8275 + ORTHCH: cpu time 0.0520: real time 0.0521 + DOS: cpu time 0.0002: real time 0.0002 + CHARGE: cpu time 1.7654: real time 1.7697 + MIXING: cpu time 0.1879: real time 0.1884 + -------------------------------------------- + LOOP: cpu time 20.9526: real time 21.0029 + + eigenvalue-minimisations : 41 + total energy-change (2. order) :-0.3396011E-02 (-0.9357442E-03) + number of electron 16.0000000 magnetization + augmentation part 0.1175273 magnetization + + Broyden mixing: + rms(total) = 0.11910E+00 rms(broyden)= 0.11910E+00 + rms(prec ) = 0.12111E+00 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 1.5111 + 3.0289 2.4604 0.9665 0.9665 0.8220 0.8220 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1032.86725081 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.82823010 + PAW double counting = 5147.75592617 -5150.60791184 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -218.62833069 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.32838812 eV + + energy without entropy = -28.32838812 energy(sigma->0) = -28.32838812 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 12) --------------------------------------- + + + POTLOK: cpu time 7.6888: real time 7.7072 + SETDIJ: cpu time 0.0013: real time 0.0013 + EDDIAG: cpu time 1.4671: real time 1.4708 + RMM-DIIS: cpu time 10.3582: real time 10.3831 + ORTHCH: cpu time 0.0524: real time 0.0526 + DOS: cpu time 0.0003: real time 0.0003 + CHARGE: cpu time 1.7742: real time 1.7785 + MIXING: cpu time 0.2026: real time 0.2031 + -------------------------------------------- + LOOP: cpu time 21.5450: real time 21.5969 + + eigenvalue-minimisations : 45 + total energy-change (2. order) : 0.7972297E-02 (-0.1200521E-01) + number of electron 16.0000000 magnetization + augmentation part 0.1108344 magnetization + + Broyden mixing: + rms(total) = 0.58878E-01 rms(broyden)= 0.58878E-01 + rms(prec ) = 0.59345E-01 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 1.3822 + 2.6900 2.6900 0.7998 0.7998 0.9841 0.9841 0.7273 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.90921949 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 64.02860913 + PAW double counting = 4915.61293416 -4918.51259087 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.73109770 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.32041582 eV + + energy without entropy = -28.32041582 energy(sigma->0) = -28.32041582 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 13) --------------------------------------- + + + POTLOK: cpu time 7.6648: real time 7.6832 + SETDIJ: cpu time 0.0019: real time 0.0019 + EDDIAG: cpu time 1.4664: real time 1.4699 + RMM-DIIS: cpu time 11.5862: real time 11.6143 + ORTHCH: cpu time 0.0527: real time 0.0529 + DOS: cpu time 0.0001: real time 0.0001 + CHARGE: cpu time 1.7671: real time 1.7714 + MIXING: cpu time 0.2045: real time 0.2050 + -------------------------------------------- + LOOP: cpu time 22.7438: real time 22.7987 + + eigenvalue-minimisations : 53 + total energy-change (2. order) :-0.2817125E-02 (-0.1004256E-02) + number of electron 16.0000000 magnetization + augmentation part 0.1090245 magnetization + + Broyden mixing: + rms(total) = 0.73025E-01 rms(broyden)= 0.73025E-01 + rms(prec ) = 0.73534E-01 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 1.3706 + 2.7187 2.7187 1.0074 1.0074 0.9318 0.9318 0.8245 0.8245 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.87309953 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 64.02200107 + PAW double counting = 4944.92878187 -4947.82742169 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.76444362 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.32323294 eV + + energy without entropy = -28.32323294 energy(sigma->0) = -28.32323294 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 14) --------------------------------------- + + + POTLOK: cpu time 7.6617: real time 7.6801 + SETDIJ: cpu time 0.0014: real time 0.0014 + EDDIAG: cpu time 1.4692: real time 1.4728 + RMM-DIIS: cpu time 9.6490: real time 9.6722 + ORTHCH: cpu time 0.0540: real time 0.0542 + DOS: cpu time 0.0001: real time 0.0001 + CHARGE: cpu time 1.7674: real time 1.7716 + MIXING: cpu time 0.2142: real time 0.2147 + -------------------------------------------- + LOOP: cpu time 20.8171: real time 20.8671 + + eigenvalue-minimisations : 39 + total energy-change (2. order) :-0.7901685E-02 (-0.3680976E-03) + number of electron 16.0000000 magnetization + augmentation part 0.1080283 magnetization + + Broyden mixing: + rms(total) = 0.78044E-01 rms(broyden)= 0.78044E-01 + rms(prec ) = 0.78650E-01 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 1.6193 + 4.0671 2.8747 2.3411 0.8187 0.8187 0.9415 0.9415 0.8853 0.8853 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1037.67973570 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 64.04496757 + PAW double counting = 4970.24891255 -4973.15304060 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -213.98318741 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.33113463 eV + + energy without entropy = -28.33113463 energy(sigma->0) = -28.33113463 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 15) --------------------------------------- + + + POTLOK: cpu time 7.6808: real time 7.6994 + SETDIJ: cpu time 0.0013: real time 0.0013 + EDDIAG: cpu time 1.4674: real time 1.4709 + RMM-DIIS: cpu time 9.1159: real time 9.1378 + ORTHCH: cpu time 0.0514: real time 0.0515 + DOS: cpu time 0.0004: real time 0.0004 + CHARGE: cpu time 1.7721: real time 1.7764 + MIXING: cpu time 0.2379: real time 0.2384 + -------------------------------------------- + LOOP: cpu time 20.3271: real time 20.3761 + + eigenvalue-minimisations : 34 + total energy-change (2. order) :-0.2715443E-02 (-0.3426902E-03) + number of electron 16.0000000 magnetization + augmentation part 0.1089825 magnetization + + Broyden mixing: + rms(total) = 0.30925E-01 rms(broyden)= 0.30925E-01 + rms(prec ) = 0.31421E-01 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 1.5644 + 4.2821 2.5925 2.5925 0.8362 0.8362 0.9712 0.9712 0.8473 0.8571 0.8571 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1037.33486562 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 64.01093561 + PAW double counting = 5060.21957511 -5063.11318511 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.30725901 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.33385007 eV + + energy without entropy = -28.33385007 energy(sigma->0) = -28.33385007 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 16) --------------------------------------- + + + POTLOK: cpu time 7.6492: real time 7.6675 + SETDIJ: cpu time 0.0015: real time 0.0015 + EDDIAG: cpu time 1.4678: real time 1.4713 + RMM-DIIS: cpu time 11.0973: real time 11.1242 + ORTHCH: cpu time 0.0528: real time 0.0529 + DOS: cpu time 0.0002: real time 0.0002 + CHARGE: cpu time 1.7628: real time 1.7670 + MIXING: cpu time 0.2388: real time 0.2393 + -------------------------------------------- + LOOP: cpu time 22.2703: real time 22.3240 + + eigenvalue-minimisations : 50 + total energy-change (2. order) :-0.7488643E-03 (-0.1972646E-03) + number of electron 16.0000000 magnetization + augmentation part 0.1098972 magnetization + + Broyden mixing: + rms(total) = 0.12681E-01 rms(broyden)= 0.12681E-01 + rms(prec ) = 0.13084E-01 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 1.5914 + 4.3342 2.7215 2.7215 1.4116 1.4116 0.8397 0.8397 0.8249 0.8249 0.7876 + 0.7876 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1037.10399816 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.99572517 + PAW double counting = 5069.76820872 -5072.65677801 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.52870560 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.33459894 eV + + energy without entropy = -28.33459894 energy(sigma->0) = -28.33459894 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 17) --------------------------------------- + + + POTLOK: cpu time 7.6641: real time 7.6825 + SETDIJ: cpu time 0.0014: real time 0.0014 + EDDIAG: cpu time 1.4715: real time 1.4751 + RMM-DIIS: cpu time 7.9624: real time 7.9815 + ORTHCH: cpu time 0.0537: real time 0.0538 + DOS: cpu time 0.0004: real time 0.0004 + CHARGE: cpu time 1.7672: real time 1.7714 + MIXING: cpu time 0.2523: real time 0.2529 + -------------------------------------------- + LOOP: cpu time 19.1729: real time 19.2189 + + eigenvalue-minimisations : 33 + total energy-change (2. order) :-0.3167343E-02 (-0.4434230E-03) + number of electron 16.0000000 magnetization + augmentation part 0.1110904 magnetization + + Broyden mixing: + rms(total) = 0.24794E-01 rms(broyden)= 0.24794E-01 + rms(prec ) = 0.24910E-01 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 1.6945 + 4.9876 3.0147 3.0147 1.8999 1.4618 0.8327 0.8327 0.8981 0.8981 0.7709 + 0.8611 0.8611 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.58120773 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.95954289 + PAW double counting = 5113.03990271 -5115.91860269 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -215.02835040 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.33776628 eV + + energy without entropy = -28.33776628 energy(sigma->0) = -28.33776628 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 18) --------------------------------------- + + + POTLOK: cpu time 7.6628: real time 7.6815 + SETDIJ: cpu time 0.0013: real time 0.0013 + EDDIAG: cpu time 1.4745: real time 1.4780 + RMM-DIIS: cpu time 9.8757: real time 9.8993 + ORTHCH: cpu time 0.0530: real time 0.0531 + DOS: cpu time 0.0002: real time 0.0002 + CHARGE: cpu time 1.7758: real time 1.7801 + MIXING: cpu time 0.2661: real time 0.2667 + -------------------------------------------- + LOOP: cpu time 21.1093: real time 21.1603 + + eigenvalue-minimisations : 41 + total energy-change (2. order) :-0.1578669E-02 (-0.9871864E-04) + number of electron 16.0000000 magnetization + augmentation part 0.1117241 magnetization + + Broyden mixing: + rms(total) = 0.28035E-01 rms(broyden)= 0.28035E-01 + rms(prec ) = 0.28269E-01 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 1.8059 + 6.1918 3.3052 2.8921 2.1130 1.3960 1.3960 0.8338 0.8338 1.0096 0.9241 + 0.9241 0.8285 0.8285 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.46619351 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.94830038 + PAW double counting = 5096.98295366 -5099.85999531 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -215.13535913 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.33934495 eV + + energy without entropy = -28.33934495 energy(sigma->0) = -28.33934495 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 19) --------------------------------------- + + + POTLOK: cpu time 7.6500: real time 7.6684 + SETDIJ: cpu time 0.0017: real time 0.0017 + EDDIAG: cpu time 1.4812: real time 1.4848 + RMM-DIIS: cpu time 9.8993: real time 9.9234 + ORTHCH: cpu time 0.0517: real time 0.0519 + DOS: cpu time 0.0005: real time 0.0005 + CHARGE: cpu time 1.7687: real time 1.7729 + MIXING: cpu time 0.2779: real time 0.2786 + -------------------------------------------- + LOOP: cpu time 21.1310: real time 21.1820 + + eigenvalue-minimisations : 41 + total energy-change (2. order) :-0.5446741E-03 (-0.1128610E-03) + number of electron 16.0000000 magnetization + augmentation part 0.1110888 magnetization + + Broyden mixing: + rms(total) = 0.10695E-01 rms(broyden)= 0.10695E-01 + rms(prec ) = 0.10782E-01 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 1.8664 + 7.3530 3.4623 2.6970 2.5457 1.5606 1.5606 0.8316 0.8316 0.9289 0.9289 + 0.9315 0.9315 0.7834 0.7834 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.83546504 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.96566088 + PAW double counting = 5074.45231031 -5077.33465365 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.77869108 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.33988962 eV + + energy without entropy = -28.33988962 energy(sigma->0) = -28.33988962 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 20) --------------------------------------- + + + POTLOK: cpu time 7.6816: real time 7.7000 + SETDIJ: cpu time 0.0013: real time 0.0013 + EDDIAG: cpu time 1.4711: real time 1.4747 + RMM-DIIS: cpu time 10.7993: real time 10.8255 + ORTHCH: cpu time 0.0525: real time 0.0526 + DOS: cpu time 0.0005: real time 0.0005 + CHARGE: cpu time 1.7435: real time 1.7477 + MIXING: cpu time 0.2951: real time 0.2958 + -------------------------------------------- + LOOP: cpu time 22.0448: real time 22.0980 + + eigenvalue-minimisations : 48 + total energy-change (2. order) :-0.3896540E-03 (-0.4392959E-04) + number of electron 16.0000000 magnetization + augmentation part 0.1106257 magnetization + + Broyden mixing: + rms(total) = 0.91288E-03 rms(broyden)= 0.91284E-03 + rms(prec ) = 0.97027E-03 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 1.8433 + 7.5249 3.5720 2.6232 2.6232 1.7286 1.7286 0.8324 0.8324 0.9641 0.9641 + 0.9609 0.9609 0.8030 0.8030 0.7279 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.94886690 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.97098990 + PAW double counting = 5061.91304487 -5064.79697399 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.66942211 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.34027928 eV + + energy without entropy = -28.34027928 energy(sigma->0) = -28.34027928 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 21) --------------------------------------- + + + POTLOK: cpu time 7.6440: real time 7.6623 + SETDIJ: cpu time 0.0016: real time 0.0016 + EDDIAG: cpu time 1.4817: real time 1.4853 + RMM-DIIS: cpu time 9.6796: real time 9.7029 + ORTHCH: cpu time 0.0510: real time 0.0511 + DOS: cpu time 0.0002: real time 0.0002 + CHARGE: cpu time 1.7590: real time 1.7632 + MIXING: cpu time 0.3120: real time 0.3127 + -------------------------------------------- + LOOP: cpu time 20.9290: real time 20.9793 + + eigenvalue-minimisations : 40 + total energy-change (2. order) :-0.2304305E-03 (-0.1690825E-05) + number of electron 16.0000000 magnetization + augmentation part 0.1106527 magnetization + + Broyden mixing: + rms(total) = 0.11007E-02 rms(broyden)= 0.11007E-02 + rms(prec ) = 0.11423E-02 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 1.9766 + 8.1563 3.5608 3.5608 3.0999 2.2672 1.5556 1.5556 0.8324 0.8324 0.9398 + 0.9398 1.0940 0.7925 0.7925 0.8567 0.7884 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.92222360 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.96938540 + PAW double counting = 5062.03953197 -5064.92302841 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.69512401 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.34050971 eV + + energy without entropy = -28.34050971 energy(sigma->0) = -28.34050971 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 22) --------------------------------------- + + + POTLOK: cpu time 7.6715: real time 7.6903 + SETDIJ: cpu time 0.0013: real time 0.0013 + EDDIAG: cpu time 1.4612: real time 1.4647 + RMM-DIIS: cpu time 9.5592: real time 9.5821 + ORTHCH: cpu time 0.0527: real time 0.0528 + DOS: cpu time 0.0006: real time 0.0006 + CHARGE: cpu time 1.7689: real time 1.7731 + MIXING: cpu time 0.3289: real time 0.3296 + -------------------------------------------- + LOOP: cpu time 20.8442: real time 20.8945 + + eigenvalue-minimisations : 39 + total energy-change (2. order) :-0.1835709E-03 (-0.4515843E-05) + number of electron 16.0000000 magnetization + augmentation part 0.1105401 magnetization + + Broyden mixing: + rms(total) = 0.23291E-02 rms(broyden)= 0.23291E-02 + rms(prec ) = 0.23404E-02 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 1.9358 + 8.5288 4.1348 2.8889 2.8889 2.2825 1.6181 1.6181 0.8326 0.8326 1.2001 + 0.9319 0.9319 0.9169 0.8578 0.8578 0.7936 0.7936 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.99415945 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.97309131 + PAW double counting = 5061.88628724 -5064.77078764 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.62607370 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.34069328 eV + + energy without entropy = -28.34069328 energy(sigma->0) = -28.34069328 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 23) --------------------------------------- + + + POTLOK: cpu time 7.6847: real time 7.7031 + SETDIJ: cpu time 0.0015: real time 0.0015 + EDDIAG: cpu time 1.4751: real time 1.4786 + RMM-DIIS: cpu time 10.9934: real time 11.0202 + ORTHCH: cpu time 0.0524: real time 0.0525 + DOS: cpu time 0.0006: real time 0.0006 + CHARGE: cpu time 1.7744: real time 1.7787 + MIXING: cpu time 0.3422: real time 0.3431 + -------------------------------------------- + LOOP: cpu time 22.3243: real time 22.3783 + + eigenvalue-minimisations : 49 + total energy-change (2. order) :-0.6534761E-04 (-0.2114694E-05) + number of electron 16.0000000 magnetization + augmentation part 0.1104497 magnetization + + Broyden mixing: + rms(total) = 0.30474E-02 rms(broyden)= 0.30474E-02 + rms(prec ) = 0.30786E-02 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 1.9913 + 8.8375 4.8274 2.6647 2.6647 2.4899 2.4899 1.5568 1.5568 0.8326 0.8326 + 0.9301 0.9301 1.0541 0.9548 0.8349 0.8349 0.7758 0.7758 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1037.01437174 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.97414565 + PAW double counting = 5063.01440221 -5065.89921135 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.60667235 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.34075863 eV + + energy without entropy = -28.34075863 energy(sigma->0) = -28.34075863 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 24) --------------------------------------- + + + POTLOK: cpu time 7.6941: real time 7.7125 + SETDIJ: cpu time 0.0016: real time 0.0016 + EDDIAG: cpu time 1.4770: real time 1.4805 + RMM-DIIS: cpu time 9.3615: real time 9.3840 + ORTHCH: cpu time 0.0525: real time 0.0527 + DOS: cpu time 0.0005: real time 0.0005 + CHARGE: cpu time 1.7790: real time 1.7833 + MIXING: cpu time 0.3601: real time 0.3609 + -------------------------------------------- + LOOP: cpu time 20.7263: real time 20.7760 + + eigenvalue-minimisations : 37 + total energy-change (2. order) :-0.3766322E-04 (-0.1162993E-05) + number of electron 16.0000000 magnetization + augmentation part 0.1105096 magnetization + + Broyden mixing: + rms(total) = 0.14979E-02 rms(broyden)= 0.14979E-02 + rms(prec ) = 0.15134E-02 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 2.0035 + 9.1899 5.1470 3.1409 2.5758 2.5758 2.0364 2.0364 1.3098 1.3098 0.8325 + 0.8325 0.9235 0.9235 0.9698 0.9698 0.8381 0.8381 0.8086 0.8086 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.97627491 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.97205780 + PAW double counting = 5064.76746833 -5067.65178680 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.64320966 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.34079629 eV + + energy without entropy = -28.34079629 energy(sigma->0) = -28.34079629 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 25) --------------------------------------- + + + POTLOK: cpu time 7.6689: real time 7.6876 + SETDIJ: cpu time 0.0014: real time 0.0014 + EDDIAG: cpu time 1.4631: real time 1.4667 + RMM-DIIS: cpu time 10.8421: real time 10.8681 + ORTHCH: cpu time 0.0524: real time 0.0525 + DOS: cpu time 0.0005: real time 0.0005 + CHARGE: cpu time 1.7725: real time 1.7767 + MIXING: cpu time 0.3848: real time 0.3857 + -------------------------------------------- + LOOP: cpu time 22.1857: real time 22.2391 + + eigenvalue-minimisations : 48 + total energy-change (2. order) :-0.1596734E-04 (-0.6312087E-06) + number of electron 16.0000000 magnetization + augmentation part 0.1105646 magnetization + + Broyden mixing: + rms(total) = 0.44451E-03 rms(broyden)= 0.44451E-03 + rms(prec ) = 0.45027E-03 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 2.0446 + 9.2331 5.5481 3.0483 3.0483 2.5706 2.3725 2.3725 1.4898 1.4898 0.8326 + 0.8326 0.9257 0.9257 1.0221 1.0221 0.8965 0.7977 0.7977 0.8331 0.8331 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.96043559 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.97118114 + PAW double counting = 5065.35881755 -5068.24291531 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.65840899 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.34081226 eV + + energy without entropy = -28.34081226 energy(sigma->0) = -28.34081226 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 26) --------------------------------------- + + + POTLOK: cpu time 7.6901: real time 7.7085 + SETDIJ: cpu time 0.0013: real time 0.0013 + EDDIAG: cpu time 1.4703: real time 1.4742 + RMM-DIIS: cpu time 10.1219: real time 10.1462 + ORTHCH: cpu time 0.0525: real time 0.0527 + DOS: cpu time 0.0004: real time 0.0004 + CHARGE: cpu time 1.7717: real time 1.7760 + MIXING: cpu time 0.3987: real time 0.3997 + -------------------------------------------- + LOOP: cpu time 21.5069: real time 21.5588 + + eigenvalue-minimisations : 43 + total energy-change (2. order) :-0.1249405E-04 (-0.1004617E-06) + number of electron 16.0000000 magnetization + augmentation part 0.1105830 magnetization + + Broyden mixing: + rms(total) = 0.17005E-03 rms(broyden)= 0.17005E-03 + rms(prec ) = 0.17141E-03 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 2.0330 + 9.3115 5.9022 3.2871 2.8646 2.8646 2.2565 2.2565 1.6593 1.6593 0.8326 + 0.8326 0.9109 0.9109 1.0371 1.0371 0.8212 0.8212 0.8490 0.8490 0.8850 + 0.8459 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.95277230 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.97074023 + PAW double counting = 5066.04516731 -5068.92918969 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.66571925 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.34082475 eV + + energy without entropy = -28.34082475 energy(sigma->0) = -28.34082475 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 27) --------------------------------------- + + + POTLOK: cpu time 7.7511: real time 7.7698 + SETDIJ: cpu time 0.0014: real time 0.0014 + EDDIAG: cpu time 1.4775: real time 1.4810 + RMM-DIIS: cpu time 9.9866: real time 10.0108 + ORTHCH: cpu time 0.0521: real time 0.0523 + DOS: cpu time 0.0003: real time 0.0003 + CHARGE: cpu time 2.0870: real time 2.0920 + MIXING: cpu time 0.4892: real time 0.4904 + -------------------------------------------- + LOOP: cpu time 21.8452: real time 21.8980 + + eigenvalue-minimisations : 42 + total energy-change (2. order) :-0.4542188E-05 (-0.6904532E-07) + number of electron 16.0000000 magnetization + augmentation part 0.1105978 magnetization + + Broyden mixing: + rms(total) = 0.39214E-03 rms(broyden)= 0.39214E-03 + rms(prec ) = 0.39467E-03 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 2.0403 + 9.3674 6.0689 3.7670 2.8401 2.8401 2.5393 2.5393 1.6557 1.6557 0.8326 + 0.8326 0.9238 0.9238 1.0668 0.9729 0.9729 0.9112 0.9112 0.8440 0.8440 + 0.7892 0.7892 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.94457693 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.97027781 + PAW double counting = 5066.03676746 -5068.92068946 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.67355713 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.34082929 eV + + energy without entropy = -28.34082929 energy(sigma->0) = -28.34082929 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 28) --------------------------------------- + + + POTLOK: cpu time 8.9558: real time 8.9829 + SETDIJ: cpu time 0.0017: real time 0.0018 + EDDIAG: cpu time 1.7457: real time 1.7499 + RMM-DIIS: cpu time 12.4906: real time 12.5207 + ORTHCH: cpu time 0.0531: real time 0.0532 + DOS: cpu time 0.0003: real time 0.0003 + CHARGE: cpu time 2.2062: real time 2.2119 + MIXING: cpu time 0.5461: real time 0.5474 + -------------------------------------------- + LOOP: cpu time 25.9997: real time 26.0681 + + eigenvalue-minimisations : 42 + total energy-change (2. order) :-0.2690320E-05 (-0.5570044E-08) + number of electron 16.0000000 magnetization + augmentation part 0.1105992 magnetization + + Broyden mixing: + rms(total) = 0.26696E-03 rms(broyden)= 0.26696E-03 + rms(prec ) = 0.27060E-03 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 2.0422 + 9.4431 6.4254 4.3745 2.9914 2.9914 2.5250 1.8991 1.8991 1.5419 1.5419 + 0.8326 0.8326 0.9185 0.9185 1.0226 1.0226 0.9525 0.9525 0.8024 0.8024 + 0.8202 0.8202 0.6410 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.94511102 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.97030255 + PAW double counting = 5065.65718800 -5068.54111932 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.67304114 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.34083198 eV + + energy without entropy = -28.34083198 energy(sigma->0) = -28.34083198 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 29) --------------------------------------- + + + POTLOK: cpu time 9.3987: real time 9.4269 + SETDIJ: cpu time 0.0015: real time 0.0015 + EDDIAG: cpu time 1.7531: real time 1.7573 + RMM-DIIS: cpu time 10.9870: real time 11.0143 + ORTHCH: cpu time 0.0532: real time 0.0533 + DOS: cpu time 0.0004: real time 0.0004 + CHARGE: cpu time 2.1558: real time 2.1611 + MIXING: cpu time 0.5771: real time 0.5785 + -------------------------------------------- + LOOP: cpu time 24.9266: real time 24.9931 + + eigenvalue-minimisations : 34 + total energy-change (2. order) :-0.9984269E-06 (-0.1780315E-08) + number of electron 16.0000000 magnetization + augmentation part 0.1105978 magnetization + + Broyden mixing: + rms(total) = 0.19719E-03 rms(broyden)= 0.19719E-03 + rms(prec ) = 0.20075E-03 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 2.0237 + 9.4686 6.5653 4.5536 2.9419 2.9419 2.6868 2.2582 1.6878 1.6878 1.3519 + 0.8326 0.8326 0.9069 0.9069 0.9566 0.9566 1.0217 1.0217 0.9058 0.9058 + 0.8140 0.8140 0.7751 0.7751 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.94637307 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.97036793 + PAW double counting = 5065.52770425 -5068.41165017 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.67183088 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.34083298 eV + + energy without entropy = -28.34083298 energy(sigma->0) = -28.34083298 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 30) --------------------------------------- + + + POTLOK: cpu time 8.9642: real time 8.9860 + SETDIJ: cpu time 0.0015: real time 0.0015 + EDDIAG: cpu time 1.6174: real time 1.6224 + RMM-DIIS: cpu time 11.7490: real time 11.7779 + ORTHCH: cpu time 0.0619: real time 0.0621 + DOS: cpu time 0.0006: real time 0.0006 + CHARGE: cpu time 2.1670: real time 2.1736 + MIXING: cpu time 0.6128: real time 0.6143 + -------------------------------------------- + LOOP: cpu time 25.1744: real time 25.2383 + + eigenvalue-minimisations : 42 + total energy-change (2. order) :-0.4557878E-06 (-0.6069651E-08) + number of electron 16.0000000 magnetization + augmentation part 0.1105934 magnetization + + Broyden mixing: + rms(total) = 0.14046E-03 rms(broyden)= 0.14046E-03 + rms(prec ) = 0.14236E-03 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 2.0432 + 9.4786 6.8086 4.8374 2.9755 2.9755 2.5612 2.2733 2.2733 1.6314 1.6314 + 1.2040 1.2040 0.8326 0.8326 0.9236 0.9236 0.9498 0.9498 0.9065 0.8808 + 0.8808 0.8134 0.8134 0.7591 0.7591 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.94860821 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.97048719 + PAW double counting = 5065.57246986 -5068.45644144 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.66968978 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.34083344 eV + + energy without entropy = -28.34083344 energy(sigma->0) = -28.34083344 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 31) --------------------------------------- + + + POTLOK: cpu time 9.0231: real time 9.0447 + SETDIJ: cpu time 0.0023: real time 0.0023 + EDDIAG: cpu time 1.8458: real time 1.8510 + RMM-DIIS: cpu time 11.3205: real time 11.3497 + ORTHCH: cpu time 0.0655: real time 0.0656 + DOS: cpu time 0.0004: real time 0.0004 + CHARGE: cpu time 2.1578: real time 2.1631 + MIXING: cpu time 0.6525: real time 0.6540 + -------------------------------------------- + LOOP: cpu time 25.0678: real time 25.1309 + + eigenvalue-minimisations : 39 + total energy-change (2. order) :-0.5099819E-06 (-0.5763795E-08) + number of electron 16.0000000 magnetization + augmentation part 0.1105892 magnetization + + Broyden mixing: + rms(total) = 0.49855E-04 rms(broyden)= 0.49855E-04 + rms(prec ) = 0.50730E-04 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 2.0610 + 9.5062 7.0952 4.9171 2.8109 2.8109 3.0317 2.5806 2.5806 1.6558 1.6558 + 1.2909 1.2909 0.8326 0.8326 0.9175 0.9175 1.0173 1.0173 0.9439 0.9439 + 0.8921 0.8921 0.8001 0.8001 0.7761 0.7761 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.95083535 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.97060732 + PAW double counting = 5065.51832384 -5068.40231851 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.66756020 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.34083395 eV + + energy without entropy = -28.34083395 energy(sigma->0) = -28.34083395 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 32) --------------------------------------- + + + POTLOK: cpu time 9.4370: real time 9.4610 + SETDIJ: cpu time 0.0014: real time 0.0014 + EDDIAG: cpu time 1.7846: real time 1.7890 + RMM-DIIS: cpu time 10.2647: real time 10.2908 + ORTHCH: cpu time 0.0572: real time 0.0574 + DOS: cpu time 0.0003: real time 0.0003 + CHARGE: cpu time 2.2263: real time 2.2382 + MIXING: cpu time 0.6502: real time 0.6518 + -------------------------------------------- + LOOP: cpu time 24.4217: real time 24.4897 + + eigenvalue-minimisations : 34 + total energy-change (2. order) :-0.3252635E-06 (-0.1585956E-08) + number of electron 16.0000000 magnetization + augmentation part 0.1105879 magnetization + + Broyden mixing: + rms(total) = 0.20063E-04 rms(broyden)= 0.20063E-04 + rms(prec ) = 0.20440E-04 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 1.9955 + 9.5104 7.0833 4.9415 2.8746 2.8746 2.9148 2.5976 2.5976 1.6371 1.6371 + 1.1962 1.1962 0.8326 0.8326 0.9142 0.9142 0.9920 0.9920 0.9590 0.9590 + 0.9058 0.8575 0.7923 0.7923 0.7626 0.7626 0.5478 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.95185260 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.97066329 + PAW double counting = 5065.53060872 -5068.41461353 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.66658910 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.34083427 eV + + energy without entropy = -28.34083427 energy(sigma->0) = -28.34083427 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 33) --------------------------------------- + + + POTLOK: cpu time 9.2407: real time 9.2630 + SETDIJ: cpu time 0.0017: real time 0.0017 + EDDIAG: cpu time 1.4769: real time 1.4817 + RMM-DIIS: cpu time 11.3022: real time 11.3307 + ORTHCH: cpu time 0.0631: real time 0.0632 + DOS: cpu time 0.0005: real time 0.0005 + CHARGE: cpu time 2.3118: real time 2.3174 + MIXING: cpu time 0.6911: real time 0.6929 + -------------------------------------------- + LOOP: cpu time 25.0881: real time 25.1512 + + eigenvalue-minimisations : 38 + total energy-change (2. order) :-0.6773371E-07 (-0.1062542E-08) + number of electron 16.0000000 magnetization + augmentation part 0.1105866 magnetization + + Broyden mixing: + rms(total) = 0.91623E-05 rms(broyden)= 0.91622E-05 + rms(prec ) = 0.93300E-05 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 2.0350 + 9.5609 7.3253 5.2812 3.4093 3.0686 3.0686 2.5176 2.5176 1.6549 1.6549 + 1.3593 1.3593 0.8326 0.8326 1.1378 1.1378 0.9187 0.9187 0.9231 0.9231 + 0.9599 0.9599 0.8044 0.8044 0.8670 0.7837 0.7837 0.6135 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.95231133 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.97068818 + PAW double counting = 5065.53250092 -5068.41651070 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.66615036 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.34083434 eV + + energy without entropy = -28.34083434 energy(sigma->0) = -28.34083434 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 34) --------------------------------------- + + + POTLOK: cpu time 8.9953: real time 9.0236 + SETDIJ: cpu time 0.0013: real time 0.0013 + EDDIAG: cpu time 1.7498: real time 1.7541 + RMM-DIIS: cpu time 10.2017: real time 10.2275 + ORTHCH: cpu time 0.0697: real time 0.0699 + DOS: cpu time 0.0010: real time 0.0010 + CHARGE: cpu time 2.3582: real time 2.3639 + MIXING: cpu time 0.7483: real time 0.7500 + -------------------------------------------- + LOOP: cpu time 24.1252: real time 24.1912 + + eigenvalue-minimisations : 30 + total energy-change (2. order) :-0.1850694E-06 (-0.1083993E-08) + number of electron 16.0000000 magnetization + augmentation part 0.1105855 magnetization + + Broyden mixing: + rms(total) = 0.24782E-04 rms(broyden)= 0.24782E-04 + rms(prec ) = 0.25063E-04 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 2.0617 + 9.6214 7.6279 5.7723 3.9386 3.0939 3.0939 2.4466 2.3085 2.3085 1.6327 + 1.6327 1.2031 1.2031 0.8326 0.8326 0.9145 0.9145 0.9829 0.9829 1.0725 + 1.0725 0.8797 0.8439 0.8439 0.7937 0.7937 0.7513 0.7513 0.6430 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.95290231 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.97072072 + PAW double counting = 5065.51687695 -5068.40089356 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.66558527 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.34083452 eV + + energy without entropy = -28.34083452 energy(sigma->0) = -28.34083452 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 35) --------------------------------------- + + + POTLOK: cpu time 8.6297: real time 8.6582 + SETDIJ: cpu time 0.0016: real time 0.0016 + EDDIAG: cpu time 1.6518: real time 1.6558 + RMM-DIIS: cpu time 10.4320: real time 10.4580 + ORTHCH: cpu time 0.0607: real time 0.0608 + DOS: cpu time 0.0006: real time 0.0006 + CHARGE: cpu time 1.9045: real time 1.9091 + MIXING: cpu time 0.6194: real time 0.6209 + -------------------------------------------- + LOOP: cpu time 23.3002: real time 23.3650 + + eigenvalue-minimisations : 30 + total energy-change (2. order) :-0.1145991E-06 (-0.9243699E-09) + number of electron 16.0000000 magnetization + augmentation part 0.1105845 magnetization + + Broyden mixing: + rms(total) = 0.45365E-04 rms(broyden)= 0.45365E-04 + rms(prec ) = 0.45860E-04 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 2.0554 + 9.6712 7.9403 5.8112 4.2777 3.1164 3.1164 2.4899 2.2563 2.2563 1.7099 + 1.7099 1.1221 1.1221 0.8326 0.8326 1.0892 1.0892 0.9200 0.9200 1.0619 + 0.9253 0.9253 0.8041 0.8041 0.8891 0.8891 0.8492 0.8492 0.6905 0.6905 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.95334531 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.97074540 + PAW double counting = 5065.50118967 -5068.38521272 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.66516064 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.34083464 eV + + energy without entropy = -28.34083464 energy(sigma->0) = -28.34083464 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 36) --------------------------------------- + + + POTLOK: cpu time 8.5828: real time 8.6041 + SETDIJ: cpu time 0.0014: real time 0.0014 + EDDIAG: cpu time 1.6693: real time 1.6733 + RMM-DIIS: cpu time 10.6530: real time 10.6839 + ORTHCH: cpu time 0.0590: real time 0.0592 + DOS: cpu time 0.0007: real time 0.0007 + CHARGE: cpu time 1.8482: real time 1.8527 + MIXING: cpu time 0.6495: real time 0.6511 + -------------------------------------------- + LOOP: cpu time 23.4638: real time 23.5263 + + eigenvalue-minimisations : 32 + total energy-change (2. order) :-0.3223522E-07 (-0.2489422E-09) + number of electron 16.0000000 magnetization + augmentation part 0.1105843 magnetization + + Broyden mixing: + rms(total) = 0.32658E-04 rms(broyden)= 0.32658E-04 + rms(prec ) = 0.33131E-04 + weight for this iteration 100.00 + + eigenvalues of (default mixing * dielectric matrix) + average eigenvalue GAMMA= 1.9959 + 9.6676 7.9536 5.7782 4.2761 3.1497 3.1497 2.4817 2.3720 1.8707 1.8707 + 1.6817 1.1331 1.1331 0.8326 0.8326 1.0821 1.0821 0.9215 0.9215 1.1164 + 0.9019 0.9019 0.8046 0.8046 0.9055 0.9055 0.8548 0.8548 0.2562 0.6878 + 0.6878 + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.95291144 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.97072221 + PAW double counting = 5065.51919258 -5068.40321087 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.66557610 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.34083467 eV + + energy without entropy = -28.34083467 energy(sigma->0) = -28.34083467 + + +-------------------------------------------------------------------------------------------------------- + + + + +--------------------------------------- Iteration 1( 37) --------------------------------------- + + + POTLOK: cpu time 8.5484: real time 8.5704 + SETDIJ: cpu time 0.0016: real time 0.0016 + EDDIAG: cpu time 1.6819: real time 1.6859 + RMM-DIIS: cpu time 11.5559: real time 11.5900 + ORTHCH: cpu time 0.0610: real time 0.0611 + DOS: cpu time 0.0006: real time 0.0006 + -------------------------------------------- + LOOP: cpu time 21.8493: real time 21.9095 + + eigenvalue-minimisations : 35 + total energy-change (2. order) :-0.5719812E-08 (-0.5881873E-10) + number of electron 16.0000000 magnetization + augmentation part 0.1105843 magnetization + + Free energy of the ion-electron system (eV) + --------------------------------------------------- + alpha Z PSCENC = 0.09670462 + Ewald energy TEWEN = 247.39057564 + -Hartree energ DENC = -1036.95274706 + -exchange EXHF = 0.00000000 + -V(xc)+E(xc) XCENC = 63.97071319 + PAW double counting = 5065.51950922 -5068.40352550 + entropy T*S EENTRO = -0.00000000 + eigenvalues EBANDS = -214.66573348 + atomic energy EATOM = 914.70366869 + Solvation Ediel_sol = 0.00000000 + --------------------------------------------------- + free energy TOTEN = -28.34083468 eV + + energy without entropy = -28.34083468 energy(sigma->0) = -28.34083468 + + +-------------------------------------------------------------------------------------------------------- + + + + + average (electrostatic) potential at core + the test charge radii are 0.5955 0.4325 + (the norm of the test charge is 1.0000) + 1-119.5768 2-119.7330 3 -46.9125 4 -47.1157 5 -47.1365 + 6 -47.1399 + + + + E-fermi : -6.7437 XC(G=0): -0.1760 alpha+bet : -0.0402 + + + k-point 1 : 0.0000 0.0000 0.0000 + band No. band energies occupation + 1 -24.7993 2.00000 + 2 -24.6817 2.00000 + 3 -12.6088 2.00000 + 4 -12.4638 2.00000 + 5 -9.3687 2.00000 + 6 -9.2323 2.00000 + 7 -7.1633 2.00000 + 8 -7.0149 2.00000 + 9 -1.2206 0.00000 + 10 -1.0215 0.00000 + 11 0.0535 0.00000 + 12 0.2161 0.00000 + 13 0.2366 0.00000 + 14 0.2520 0.00000 + 15 0.3607 0.00000 + 16 0.5197 0.00000 + + +-------------------------------------------------------------------------------------------------------- + + + soft charge-density along one line, spin component 1 + 0 1 2 3 4 5 6 7 8 9 + total charge-density along one line + + pseudopotential strength for first ion, spin component: 1 + 26.736 32.699 0.059 -0.001 -0.040 0.078 -0.001 -0.053 + 32.699 39.992 0.072 -0.001 -0.049 0.095 -0.001 -0.064 + 0.059 0.072 -9.436 0.001 -0.010 -12.552 0.001 -0.013 + -0.001 -0.001 0.001 -9.391 0.000 0.001 -12.491 0.001 + -0.040 -0.049 -0.010 0.000 -9.444 -0.013 0.001 -12.563 + 0.078 0.095 -12.552 0.001 -0.013 -16.684 0.001 -0.017 + -0.001 -0.001 0.001 -12.491 0.001 0.001 -16.602 0.001 + -0.053 -0.064 -0.013 0.001 -12.563 -0.017 0.001 -16.699 + total augmentation occupancy for first ion, spin component: 1 + 16.309 -14.437 -9.031 0.089 6.355 4.024 -0.039 -2.880 +-14.437 13.923 7.645 -0.075 -5.410 -3.600 0.035 2.589 + -9.031 7.645 8.123 -0.065 0.954 -3.668 0.042 -0.623 + 0.089 -0.075 -0.065 3.991 -0.047 0.042 -1.006 0.031 + 6.355 -5.410 0.954 -0.047 9.349 -0.624 0.031 -4.435 + 4.024 -3.600 -3.668 0.042 -0.624 1.693 -0.023 0.350 + -0.039 0.035 0.042 -1.006 0.031 -0.023 0.254 -0.017 + -2.880 2.589 -0.623 0.031 -4.435 0.350 -0.017 2.124 + + +------------------------ aborting loop because EDIFF is reached ---------------------------------------- + + + CHARGE: cpu time 2.3607: real time 2.3666 + FORLOC: cpu time 0.3467: real time 0.3476 + FORNL : cpu time 0.4188: real time 0.4200 + STRESS: cpu time 6.8955: real time 6.9122 + FORCOR: cpu time 8.2739: real time 8.2938 + FORHAR: cpu time 2.4135: real time 2.4198 + MIXING: cpu time 0.8330: real time 0.8350 + OFIELD: cpu time 0.0001: real time 0.0001 + + FORCE on cell =-STRESS in cart. coord. units (eV): + Direction XX YY ZZ XY YZ ZX + -------------------------------------------------------------------------------------- + Alpha Z 0.09670 0.09670 0.09670 + Ewald 44.43709 111.97467 90.97875 48.57095 -1.05568 -1.20702 + Hartree 312.66211 364.44836 359.83992 10.84590 -0.21030 -0.23663 + E(xc) -72.99191 -72.83952 -72.99285 0.22421 -0.00560 -0.00579 + Local -643.16263 -754.02351 -737.27158 -44.88721 0.91799 1.06557 + n-local -42.68001 -41.36498 -42.37574 2.48098 -0.05873 -0.06449 + augment 1.32366 1.05934 1.33191 -0.32385 0.00853 0.00826 + Kinetic 398.16527 386.91763 397.59899 -18.18450 0.44415 0.47116 + Fock 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 + ------------------------------------------------------------------------------------- + Total -2.14971 -3.73130 -2.79389 -1.27352 0.04036 0.03106 + in kB -0.51025 -0.88566 -0.66316 -0.30228 0.00958 0.00737 + external pressure = -0.69 kB Pullay stress = 0.00 kB + + + VOLUME and BASIS-vectors are now : + ----------------------------------------------------------------------------- + energy-cutoff : 1500.00 + volume of cell : 6750.00 + direct lattice vectors reciprocal lattice vectors + 30.000000000 0.000000000 0.000000000 0.033333333 0.000000000 0.000000000 + 0.000000000 15.000000000 0.000000000 0.000000000 0.066666667 0.000000000 + 0.000000000 0.000000000 15.000000000 0.000000000 0.000000000 0.066666667 + + length of vectors + 30.000000000 15.000000000 15.000000000 0.033333333 0.066666667 0.066666667 + + + FORCES acting on ions + electron-ion (+dipol) ewald-force non-local-force convergence-correction + ----------------------------------------------------------------------------------------------- + -.468E+02 0.442E+02 -.434E+00 0.746E+02 -.847E+02 0.837E+00 -.285E+02 0.429E+02 -.435E+00 0.128E-03 -.208E-03 0.192E-05 + -.741E+01 -.487E+02 0.190E-01 0.279E+02 0.930E+02 -.552E-01 -.216E+02 -.467E+02 0.512E-01 0.918E-04 0.193E-03 -.298E-06 + -.305E+02 -.762E+02 0.127E+01 0.320E+02 0.800E+02 -.133E+01 -.228E+01 -.620E+01 0.103E+00 -.133E-04 -.819E-04 0.125E-05 + 0.808E+02 -.472E+01 -.462E+00 -.865E+02 0.507E+01 0.494E+00 0.728E+01 -.451E+00 -.394E-01 0.816E-04 -.217E-04 -.209E-06 + 0.230E+02 0.440E+02 -.664E+02 -.242E+02 -.465E+02 0.702E+02 0.173E+01 0.369E+01 -.552E+01 0.231E-04 0.490E-04 -.494E-04 + 0.227E+02 0.443E+02 0.663E+02 -.239E+02 -.469E+02 -.701E+02 0.171E+01 0.372E+01 0.552E+01 0.229E-04 0.492E-04 0.493E-04 + ----------------------------------------------------------------------------------------------- + 0.417E+02 0.301E+01 0.320E+00 0.000E+00 0.213E-13 -.142E-13 -.417E+02 -.301E+01 -.320E+00 0.334E-03 -.211E-04 0.257E-05 + + + POSITION TOTAL-FORCE (eV/Angst) + ----------------------------------------------------------------------------------- + 3.63802 1.57110 1.76000 -0.719072 2.472756 -0.030872 + 26.36198 1.57110 1.76000 -1.075376 -2.334989 0.015085 + 3.95828 2.55412 1.74392 -0.810143 -2.365156 0.038942 + 2.63613 1.66728 1.76493 1.525263 -0.107359 -0.008087 + 26.09174 0.99418 2.56104 0.545647 1.167904 -1.728483 + 26.09550 0.99080 0.96072 0.533680 1.166843 1.713414 + ----------------------------------------------------------------------------------- + total drift: 0.000060 -0.000041 -0.000020 + + +-------------------------------------------------------------------------------------------------------- + + + + FREE ENERGIE OF THE ION-ELECTRON SYSTEM (eV) + --------------------------------------------------- + free energy TOTEN = -28.34083468 eV + + energy without entropy= -28.34083468 energy(sigma->0) = -28.34083468 + + + +-------------------------------------------------------------------------------------------------------- + + + POTLOK: cpu time 9.0386: real time 9.0662 + + +-------------------------------------------------------------------------------------------------------- + + + LOOP+: cpu time 859.2600: real time 861.4263 + 4ORBIT: cpu time 0.0000: real time 0.0000 + + total amount of memory used by VASP MPI-rank0 1504469. kBytes +======================================================================= + + base : 30000. kBytes + nonl-proj : 199352. kBytes + fftplans : 295613. kBytes + grid : 965246. kBytes + one-center: 18. kBytes + wavefun : 14240. kBytes + + + + General timing and accounting informations for this job: + ======================================================== + + Total CPU time used (sec): 877.816 + User time (sec): 847.517 + System time (sec): 30.300 + Elapsed time (sec): 880.605 + + Maximum memory used (kb): 3453896. + Average memory used (kb): 0. + + Minor page faults: 702128 + Major page faults: 7 + Voluntary context switches: 10645 diff --git a/examples/fparam/train/input.json b/examples/fparam/train/input.json index c57afdfb7f..3e401aa7d2 100644 --- a/examples/fparam/train/input.json +++ b/examples/fparam/train/input.json @@ -31,8 +31,8 @@ "learning_rate" : { "start_lr": 0.001, - "decay_steps": 5000, - "decay_rate": 0.95 + "stop_lr": 1e-8, + "decay_steps": 5000 }, "_comment": " traing controls", @@ -51,7 +51,6 @@ "numb_test": 10, "save_freq": 1000, "save_ckpt": "model.ckpt", - "load_ckpt": "model.ckpt", "disp_training":true, "time_training":true, "profiling": false, diff --git a/examples/fparam/train/input_aparam.json b/examples/fparam/train/input_aparam.json index 86be27ef29..05eae62216 100644 --- a/examples/fparam/train/input_aparam.json +++ b/examples/fparam/train/input_aparam.json @@ -31,8 +31,8 @@ "learning_rate" : { "start_lr": 0.001, - "decay_steps": 5000, - "decay_rate": 0.95 + "stop_lr": 3e-8, + "decay_steps": 5000 }, "_comment": " traing controls", @@ -51,7 +51,6 @@ "numb_test": 10, "save_freq": 1000, "save_ckpt": "model.ckpt", - "load_ckpt": "model.ckpt", "disp_training":true, "time_training":true, "profiling": false, diff --git a/examples/water/data/set.000/box.npy b/examples/water/data/data_0/set.000/box.npy similarity index 78% rename from examples/water/data/set.000/box.npy rename to examples/water/data/data_0/set.000/box.npy index 276172016ae9c5f48b3799b2f263abb5e10c1f36..6ad2de625b40040a2d13248dd8b197a0f885bdc0 100644 GIT binary patch delta 80 pcmaDLb3mMPvR|lgKqMnW*+fngD+>c11xrmGg<1tt!A5saZUD5n4$}Yt delta 37 tcmX>g{y>IvvR|lgKqMoB+eA(iE<*zY9R*8G9fjJB<(}M|1sE?d0RYOk3PJz? diff --git a/examples/water/data/data_0/set.000/coord.npy b/examples/water/data/data_0/set.000/coord.npy new file mode 100644 index 0000000000000000000000000000000000000000..8bd448b1254784551c11c2c238af183a8dc0a4f3 GIT binary patch literal 184448 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

8_D17ES@Pzxp;`@_~) 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

)*OElAOC#W~T87Hl|+ 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%0Aa1S;y~x!3JuS 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

E`A>seQw}y3QWG>*%j~)z< zc#kpcuJ!bs$6V2|eBQpphQe;O@+rs78RM`XT?v~}bx)rVXhzGHmLe!~1of%xL!-i0 z^t#$oUY|W3ikU*MM}82Mq%4NiNhOkr_oGG!C$bv)lB+cqWAeCZ2p-B@KjC|X0I7f*zLf(j*Zf)hq{#>C*~!>^-P4Onp8ANTam1;J+AoqlZAUO%qv$?I@@2~pP|or%89tf zF)#Sc!R`27t|4xodIygE*87_G&D-ZC43U%2QB(u{B2X8SiO!R43mukYV{VqDM5}jP;hg#_pZlq*BrXP3# zRdp>g+|`WYt>e*cwTatk4E zg8Zpr8{^(EU&P`SY9wLji(UJ`Nj8Jomu~C~+Hg&k z%KzJgo!cu#6SWBAS@wGMFe&;fUCg@B-?>RI)C9GX3!<0<1Nf}^FZk52mMaZP!2#!X zEYV%dy`OuG`*~_IrO3X+g*WW)f4+c|W!y{djUt`~iqQX^2$4tUq2HS+^kmcn7+=+- zuXB5lJxI)*IG+xkZdd-}Qb)3HR)O8bw^(#1m~qFWJ82>k;nPvSutC z?SaqpG%5YCGv#aF!Prc7vTi;Dr|_w0TCYcKjRtg}Gms8#-O6n*&Vb*bUyQ}##apEf zuDG@)ih>S5!J5EOOq=-!r}LLXSvM2&mlz2`-d6l#=cc=zjA!unG2fEPdc!;C^AZ6P zv~y+}e5BkN7iuCkzH}6R@A!(yX;QQ@BZ_;rq7Z=}y09~@g_kH;PoXsuw7ZaHLseY3 zU9IM{MbLs&=~hhf(xsu#XTcy^gZyTOk}2bV>ULJ3*zkPC4~-7AT%0AG`@lM>R)Z)+ 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 literal 0 HcmV?d00001 diff --git a/examples/water/data/data_0/set.000/force.npy b/examples/water/data/data_0/set.000/force.npy new file mode 100644 index 0000000000000000000000000000000000000000..10b2ab83a233e3e9cd9d3ce05cda586295edadf4 GIT binary patch literal 184448 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

Jbo~0y36oal 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

C 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 E0s8k~cK`qY literal 0 HcmV?d00001 diff --git a/examples/water/data/data_1/set.000/energy.npy b/examples/water/data/data_1/set.000/energy.npy new file mode 100644 index 0000000000000000000000000000000000000000..9fa747389b89ac522b533332e0ca8a14ba37f42e GIT binary patch literal 448 zcmbV`ze_?<7=~>uY6~h{E)krZzes literal 0 HcmV?d00001 diff --git a/examples/water/data/data_1/set.000/force.npy b/examples/water/data/data_1/set.000/force.npy new file mode 100644 index 0000000000000000000000000000000000000000..dd8fccb45dac1f0d0be4bc95aaebc154962c165b GIT binary patch literal 184448 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
      (AV#2=Y}Z!w_p!#i9~L6vx9w+ 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 literal 0 HcmV?d00001 diff --git a/examples/water/data/set.002/box.npy b/examples/water/data/data_1/set.001/box.npy similarity index 78% rename from examples/water/data/set.002/box.npy rename to examples/water/data/data_1/set.001/box.npy index 276172016ae9c5f48b3799b2f263abb5e10c1f36..6ad2de625b40040a2d13248dd8b197a0f885bdc0 100644 GIT binary patch delta 80 pcmaDLb3mMPvR|lgKqMnW*+fngD+>c11xrmGg<1tt!A5saZUD5n4$}Yt delta 37 tcmX>g{y>IvvR|lgKqMoB+eA(iE<*zY9R*8G9fjJB<(}M|1sE?d0RYOk3PJz? diff --git a/examples/water/data/data_1/set.001/coord.npy b/examples/water/data/data_1/set.001/coord.npy new file mode 100644 index 0000000000000000000000000000000000000000..476bbec5d72fd6d899f131110acccdfa76cf8162 GIT binary patch literal 184448 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 a{co4dV{}>WbnyjwhW?cK7O(LB5dHvd5*UU6 literal 0 HcmV?d00001 diff --git a/examples/water/data/data_1/set.001/force.npy b/examples/water/data/data_1/set.001/force.npy new file mode 100644 index 0000000000000000000000000000000000000000..431e38ccf37f6492fa29a450625afae31f8b2fc1 GIT binary patch literal 184448 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±EWOE=PB6nbfgyv3GVtAJJE+y_ zghGS+tWQdg9S*9*(s#1>xUz=dQEWv9<%V2>xG+z%nN2O{W7(eEKQMaN7F3H{2@_Qm z@Y#eNH2M5l{M=?w%yB$(Y<|SnRK6mSVFVq}JS6&1o=h!?ANearXHkmx!`IKQu_yf} z@nqFKx@RBHssj}9Rd*fxJv$YSJ`u->mXRd)#sxLv<*8X_lo!=a^}{~TFRZxO5F4EOML7o&SlW(l z@crCg3U;Yy!G*(Md3!9|^m`D-xsOMKOJgx)iX^S9x(II7^F`+I4m2z#o?qDR&-xGg zF_F;KQmJdlpo$j)5YC{l84O>fpJ;%eo{t@_RfjcP&b>JM2U^=&BKY86OU^C}5 ziDt*iVcVRE%unB)_m6R}ER+pIQRi`5xqnYZneG+lUed_T>No`FyyDoN4`aCcer3p- z5P>%HJh{d{o3TfK4^$;xq19G;Y@U9k}nUikmNAYnWxg+*#nF{9ahA! z_9kQo)d}j}_4H_A7~3;_T$RN;7ZxwSjGji?fW_QoycE3#Pq$XUozV*@>Q4^rcUnRJ zMJK|SVTk#OHDs5R%dQ_AMO~@?*!cGcY3>ght9I1^enVXt?w@&<{-v8EuQ8MwGbJ$n zw<|`ae?xs-Bs+V z^DUu|stTDy_T!sw3lz^5M-!hU(Pd$FPU*%^f2*1m%SIKbE3fvHN6Gkt~W#%R| zupmGjwOWnn-~I%wEv&#VC+tYmErcbg+Hu3ZRPiHAVBI%fvhAVAu;gS-rPyFY3{KI& zy`Ms{$>s-?t(c4%UEZizfwxmzqn+Y|>JpPpd#~1>Q{N{x9xd ziICaP(#76}Gc0DDJic2oi@t78z)R<(tNi0`541I!<@BG@Sf89sg4ggJqSs1UKUaknelKEq`OgYHFmo znwi%8&2u&IV3t08n<0niM+Kw94^{dku{C9 zYXN`xktaKNH5$sspB!5yu`HQVcl9v0RC9W?FA9GAXAc+O?C1K}R+zH*G4Jz211EfP z`}PKk_UxzG6Qlj`JfR z3S7XB{Z7aWbC&AN`M4z34s}~{*r6*^sk;6crHt=^B=qEe6q)@47MGdO_NNy>Y0GYG5=(?)}C^eUZjiK>{YAysR>c;PF1Lp*$fvPpXy< zDg zLb4W*>C^&!ij!>yRSS1=J~9uFTg<0xHD%n>cUQ=N;0z|Toxv*qGP=6WoMzkSG5fDF z?1W1$jt%QYwaNEs!rD!!`+6Ou_0-VOy2&i4?jNIWS*qCt^!x4B%Db+T{Fk07bY^q_ z$&O2+@PhM1^Dbay{$LiDXG8UAu5_hpv*_D|Gi>06JoOhUv)6+j< zu#OYyeNAR3BdlrW(Ma4QcZmg#m9dhWU%?#9M$oNdJsi2#0;F1>Fg7R)6Q*m@!%d^v zm)*IPpKppaJN4-1d>`strwc)aWoXV~V$QbH$y@}ETh{Xhaa_I30Vv}LO~%} zC>e2#GUps+ot`ZsLz6~WRBOviBy>W;Pz6-m6v$Lv>L6ri8611;$ULvxBD<0fe;1T7 z<&5i4v$lb=zp4*Y>vLGc-7{=%^K8y*-6l9Pc`94|(T{80kOQrUl-Us7C|-BA9jF@F z!quixaKvQw~R zEH@VL>V*er)VEUB8sj0_;%AK)m$+c#rX}=VTaOmnon!Vn!_m!fIi((EATjkPk6Q<^ z_S%V{+O9~Sxkb3YQJTKy342+U9Cq7z1sA_&4}KpdWUzfyG4OZ;%NgDPxvOt7#Y5BJ zT8IOjiCV*}96LcVA5XE+O^I|^V;kJLnZzPP9$+Y`vWUwv7Nsr3Ezlr8 zi$L_VI0p%81MsxFf*U#SFX-LLhuz0t!jAnjXv3Guc-?KFGJVr{f!!0&e+-&#G0f!w zdlLE4GBD>Jl=S-0oY={%=GIAA5NAm%`7!9jKV!02v~X*D2C?yn$yi;D$zIsWxh;GS zdXY-x^Wqyz4c}5}=$;1ENpD26dZ(f3rxtqh>nZzlCx>m+>=tHUzpz_!5PcAMNh4p3 zWZF3z_&j?DZTz(ghHSbj_$9-k!e$9xpR*kme@F`5w|TtH-$eG`moY4%ZYgc**Cl;5 zDYP(^Vk;em-P6`2YWSUk^CLb(i%JlGK%Vi1gMTn%(>e6~gbcQ{yTE$0Snl$gYpCS& zfw#LMjTWv!@U!$FG~83f$xm1ERtK~(G585eov6YTbbWrt4y-MPhCLgokx=LKoY-sdjgQ|6;5K0kWmj`LQc~zGrRiD)FyDJ zym#%#o(+wxDq#zYqrv>k+aYX|d=Q3QDCYA=%tyUC4Nz1SGKGs~;?l}ewzndNqhS*$ zahP6}&XqQN9pGM-^f-t~EM3HDToS`orfslbtR78{pG_vW^H@W>(78Qi4i-n3bA5d- zxJI;qmn*1Y5_>1I(40}&bYLgt9{&qtq!lVX4i<2)Fqm1~m8Ml&Q^34vG`-m;yj6Td z@YRmL>~Q2=8123UwtlLhnW6;n+>SV~;T*b*sKiqylc`xkrE1fFB0iZdO&=aTt&|SE z%-X*Hq*uPb$icIm#5AKpqwX$^4a>maIr^|_^G3E#bez80IMY}=l@L$oQroB+sH;;?<62sEl+Rz+ypV^#FVVjQJ zU@yGuNi=^bPMlo`F0W70r2B3xKl(YTpKC-#ldDt^wHmF%8d!6W0$ts$!P*mz*v9S$ z++x>asvq-}zPt!V>AgSU;fIm9=(iQhJ*wlq&bGmN%>vFdRts8g4-zdii)1UMFJo_i z0^ECTh%fjn`0aT=TX-)P9Bj3rBesD_Xt_a~sV7OAq|xN4dHBM*6Nkiob;hCFDa+< z!;gy2e4PiWTcpU~c0cSdHe}n{ggoPv2#nU6h-*Ct(F(gSmQNKY;v-LAGJZA!*KAQF zFQIeN-?fqk?eAfG`{T%RTLv9HcaS$=OUYi|h8;RPgT(K+!ImM?^hmLgm9PHHU!Gxt z4*rE~z4lQYwe1=Q)epgBmk+i2kD~E&hvN(@N9O{JLD87K>IQ4+kXVRQiXSj+g!Y}V^r0ad%9HzO3HE1Kp@IoEhQ=GL+D|h#@Dnj z$J&)a%->T3Ha)lrt_}wTC(90YH%A?rv@I7SS|#E_C-QDTm3VEN=eR=eF)EgJ;n#I7 zY-X?U{$FH6`Mnp|sup+h5YL1WA^*T`)EIm#c&uKJYUcch4aJT3A2DAYf6nGYI=;;v zL>op9Mdyc;Dq6Pouw0oFl{u61V2zIvNXowhX|*>naG8hJhweZsJ~&l#Evc7Oi#q2l zg#I?cIjypSJ$>jwZIch9qVz>*2*?B%qkmv}^*MBmFJt9vQo!|oCSHuRgkGrN^XQJ^>}ts`<~Bz|D9TK}rV()88O9 z)Nxyh_c`L9aG%(dwM*b~#zbnob^@+Blt63qFMhYjC(fg^flC@Q2v>z};#%w!=wn9% zoVxRgo$Po{@i!+Qc7*?#J%|2YJcXeHXJGl#FkGuY3bg+AvG0;iZ1ccX ziuZ758&9o;N46(O`uPDg6e~nA&k)S*OXZCwq;ifvQ?c&$a4^nMCCALmaK3slu5Qz& z3>|44-(rim`%Y5#Pfc1q!X6E#wLv3SXnWl6!3mw8=?0$7D7qLf+ z;y29#W3OQ}nQ8sqjqk!N$l;PCzIxuu8Nda8 zMXkUsp}S1PPqBJ9w-B9TZjs{$E815_Xgwj82Cu%y;>M3fU)|}#-c*OGOEy!UaQ2V= zy%Qaxp5w%^&)LJ=6s~UP5#H(34ww{F040W&koHK8zJ8rqd0^L4d^)3+sVq@u@4h*s zva=-?O^_3%q(2a4EtIC!MTM}e`!3ognWJT(p=h5{BySWDi({HLgM7|gF1;g%{d)Y6 z87EX#NZ)tj04PPP6Spv2E*l!Uflo1ny!l> zILC+3C!G@L7vAk2!SFr2k5QDD#Q!LLJ&sO_XOxAk`#jMetxaBJCP83e>yI- zGr>y-N?7h(BQ|pAW;nk-o39A)WSewX)9I;GAo9vB_Mxty^S;)>J2cmEzg&`GLTMg5 zJZ3a>Efj;M4X5#ebtpvs?%{8Gc+!GL?V@VCMo7PwK%PrA@XPs6_-3Z?_ENruchiR9 ziHfCoBlNV8Gq{VAQsVr$l^5XOTvfWbW;sNhO=V{k#ktVnVs^#dlu7&D5zV+INxlZ= ztZCx`xWDUH<-+1G(j zdEzv5Srohd)02u}9~F)fIxABa@QJUZA@@rjxCq(jt*^_$*W3fn7EdIfB@*m}{VZ;{ zxxg{$^2G_2JDJ3_GTwGXO+~ohCU|n)AN4gpvIA}k_#sw|G|MYs8l^;|U zG-PDePLCyU)q4PCXT*@%203Eh>rv+0X(9U=LycuZK6l@p39|Ey%|$ zTp~O@G1$u7GMG8rRj^@!vZVBD1!nx7Ob&O#F|}B+N^zSH-t(IXVx^6&uEZWDzqX?) zqm!SY-%KDB=L=T2~6gq z)1O(rm z^Ey6!j1#O70`RzAfGxNj_e)FAtmbJ?t_0BYb zZC^CD3=?MD%DV)vUm2{i-wt0~dtg;`EiWY_qKku6VDqeCV*0Yw?6w{?Hr1wV;uIJU+7eNw?PA!9HspjC2U4g$oie%q)TZT5yq%Egwq-_3iwT!L2aeE{TN? zKF3QmzGGu^dYQ(sbj;puPdTmMDC$!&e)XLIN81u8yL%75FWd?)srQ&qOCGmII2#HS zW5BbZ4YoRz;MGB&$bGjyt@v7l`%8c0Liz`@WDf8~ZSz=#>{g){F`oXM8X_>*&SQJZ zFBX_TjMV3AfmU%a{`L>#mp6)Abt=5(Tb#WnA@>~Sl2ZEkj!zmWnBp@zH~s~eM<3n9CuZkb}Hd=xhu5(aR(bK zEBF+jK4Fa}XIRw-1Ddr#nLbGTq42$%{?FE?Fr7Fk+QgXKtYSPjNgRisxlYNFM!4hM zEO^A}(e54L>}#GrT82tf{(E!K`L&g~*PF884zm2ZHOKj{Huu=UZ%s7zz)752`5oNa zBydQ!Bn^8TioN28xLYOexYhnRO))Sgy}%%>8LlJhn{W~827hFClU-=zr~$enzm6s8 zSF(V-v+&V)I@c`o31Y?4$z-sQDG1ulZ_2m}+@E@OF~boArXKeqSb|TUqsv4>XKA~2 zJa4*sKW+DQp(fK0%=?2iUGjbh&xSt4PdjtTUN;Z*=H`gHs!izVJ}oAoLGaJLb!B4Ff|U;Egt_4*Va8n# zT`rBh+Ng0LRaM1KAFc<9t$_KP&ha~UeuOGr1(q2&h`{oqFjsMBdH)4*Mh<~6*nTAc zNiC7r)*lVw(&MoqCyi~DTLE@krE#C0H#6?kWz}}c&>FFfWn{K6tF=X3eMc$k>{g~D z$)ici^avJZzh&~feu9Mt;{98_l?5sql)k+byi?sl@^c__*w+hh-VxaO`w4x-FqrRG z&4=!A276%+cu?vdub6X~{aG;&Z00J^li~j$<7ks;%UT&W%23GenHsTpuR&ISSIoq1 z607N&`Qgf8@p3r(+Ix7cRm!sJVrg@&A}R{b@7e2bQTmr)`g=?ouYQlOOdmFjl;#)l z2}b(Bk5`5_-#Ymj4QKJS>JoYw9$3CqSsT0iFY<>w?I<$v1Dl#?gr-N=iKZ!Mu^-7y z^z@~`LAO}P(r<*aOv5cK(qRg|Uf@Q)UQ3Xs-Vl0^-c`Q4ovl27#!H;7%?{+64i2#jURjRo4?STG-gUffL>D+YPD0`$*bNC;_NAvDN>;RC z=!4l5^=}f>j4Gnn|Kw4X+iQy zoRM%A4&PSAR}+u1J;Stl7awi>c&m`fL=LKQ=vjtlXWzkbIcC(#6@U zt_wc2`SjuCMhbuB#pd4@*!kWbY^Bi-^vLN|L{rHqAVoz@+DmfuQHx zaW<;5MX}MOE7{B68EK1VZi(PK#)+ORSj{H{2tKa?3+T8dL7_oMAk93U@z?aY{br?X zcy|s9>iz=@=1%0kjnJZ|(Am6?JdspHJk_MM^S>kHsPp?e?*Cqr=U2qpkb!r++>Fg! zp_B*@*0*vVGIQC}sIz!`+f~>rHu40vou1_{G68RG)E;zI~3N-3zLj zLhMiI+OPpOt99`fV$LLHJpshmpT_3yIo$tQ6G?}Of7>^d-SLvDs+8#BI}-2ElGW#6 zz)KwcPh@ko`3-DYs5pF@tU=!*?I3K16m6=P#P^f+am(r!&Ul;@KDd3K+dj5~lvl=) zth5|@qRdUZx4HIW{YX50j=jmO zM^!Pkyg+J9j)izP5&ImWjh=(b_*)$_=%L;pu6f)&jNfBmrF|ikmRTHuV$&;?kAut5 zs7#ZrVuxV=@Ey=Dx`RU`gNFl5G zIg5Vhc;Jx%71rwJNxMUA&|M-+=)TI)z=d!Yr7Fgn)C(bWwi<;A{Gw5{^0?HrX6D!2 zJPc`Q0)vN%7&zn-Mup{D2H#F+6{qt^b?`VG`c4~vV-UaV*&`PMd z5u*R}eW)&U71>&T;(819N%_}M3|BD4Blll3ZoCt_F5gPdcO#&4{8m1+z=mENI!LGA zJK>A3f>*RFoBE|=NPYQkAt$~`@aUezQJ~Di#s=W=@jUilvJ~ajxYC^FUo@mTjeF{x zg4R#eY2U#}_PkoBD(t=r#oGmAU8Fx;={f}Ds)#8ABQbJG0aKd$nw_-y$aRg)W%aF+ z%-J#l3;yI_uvr{DzOjlG-_WvJ;L`&gjU%k&8?@->jXG}cYr#ibR)mt-r${wX76;Fm zOy#53QIn?ys(uY%W)~!^)+Q>VNyrV_qV|BZ{^g6RQ~G$fJ1?;7PX?z^a|;xlzq4ao zj=+{RBWT%!Ec!cB$gnv?v)-$!H1l8vMV;?vPxfDd>y~bqU0cZ9E}wuI>p50Cen?gO zx-?WQ9>ipXGa%@S0&4Vp!;0O_xZdG8PM##N5>8LU;6L}_aP}Y?cQBiDiYj2@acS}{ zyG+VwU082jI*l10O&-b{+5OG|wrZX~EgiUvg>qJ~#Vv@I8jq~{5ITmYE*-|7-8Y2fxM!JTt+LS2h=?L9Q~ed;3PN zqGK?M`|@mSi99WG3TL9f_n6(AZ34H(iYBgFMVqFXu#$@c=cRl#nCRDvTx^%ZPrW;A zxc_uGUDU}Q)sDvnvuas~`!qJzCyX2izvmz60p62|u9S4EC9#2_I6Cwq=Vo#N#-2Wk z-C}EL-v}?-vnU+*nH)y{lZNnqj56Ny=myz{`z-WW5?>au3b)T_5xU!nuxQa+IMU^h zPksnJ{e9IeaBCJczxpJaQ9U0Fht{%|-#yT`U6QU<+rTs-&ocdX4gG0&!yYdQCW8m1 zAosAGYdb#(v$jRx-#mf!>U@IjDR{$1Dy|a+7t7-Oss!4(>NsT1^JG0jHZVR!9KRO! zuvVcDwnse!Wa_3tjGh*49(D@X-8H~NHO}l@_gFNzWr7+$>R1~hxO@+V!!DmnG+7dd zD;$IwsB0i=X>unn_%T1@-z*q&P77leWHX%hf_zEx%#+05 zij$#yVLHWR*08dHDJXYf8@s=~jEy+!UHRgxI2*ZLmR%Q|D5{GySo4FkWZ35miVyBE z45(!@hMr}6bvLu&9XrV=We}eF7zmPr=hv%{$innCyto_3)?D<5j3K^wdQ}nq6mr%| zdSh7YmZ$7W*JxZ6tV=4hx5LqRCJJ>~MQN*3A?0lf9|nV%xlsyR*1VR@9Wfl2#7q%p zL#B{9rxToq8)MoGWn9sxz<;}DK}_(v?%Vz!&4?E=BSFpVV7DW#3uxzJk7}XfqdDw= zvj_PG*zt0fsnC-dOo<+=XzlYR;AtlIgls^wmq*#_iT|O>-|;xQBo(tWeBj2aL8N4) z#&Cu?IwwAaMVc3A^`>T6eJ2`*SX{va4%gw;?dkmYelx+-ev26yo?-o7uh`)^1zgdp z7i`1b(4<6$iZm&aQmJ?EL!t~N(T8NrOy-DCX{JbX zijYc3sYIQ3?^NcwLdK9Wna2>{`>$W8)mmruJkQ?ueO)sWsnkZmuU9Q$<2qehczG|5 zUijF#)=dqEHvginuBYJVsNwwhM6uvzdYCv5QE3ptnN$(K|=fL(#LVou&L zG^uZe%zw3Dd8RLx^^akfmH`|!CIYu@4&x(LOVDt;KKTuMFU*?YAZ0umWPV-wc~b-E z>eoOHg~5-XQZU+bB#u~JM!H)&3uzK_?Nn47PanD$77VzEVR4txYv38@Wkp}aT0N;N zrMw^B{5*jxzQ2Y7N&@H2H-tQib-vF>M?4waiE}$f!WHQw*N+-Q1I(|$l_1G4-E*3d zCFb+*g;nCW+5(6j+o|e$#bmlSyN!?hig9jQ5=I&q|4{zIB6+`$D>%5kyjan(z1*EZNy*{r?Z=`NNUqg`5Nx?I2 z2F~6(5U&nMz>mpFsCLhY>Q5P>h0=VAt(5rO=PYR6snc{v)f}Nz8P0F(Ez@22no|aL z5HhDpbG4V6qV13}ej9(C-QGQBlTELkH)>rKE>1Aur0p9;``tR2JfWSuN5+crdwao^ zhR*D`yaT>D6^mDX%)(5s>tbD`BerdOC4R|}N#C<=c(C(UEVG*jujZ);9~5`UdqRq+ zt|sHd1rzCa_$4|OHjAGf`5=DTHWhyxYV*5LPnezO1=cRTkh=B7zma>nWdB_p^{Yy- zF#>KnW0|okr9g~@5No6t*|gRl79!cQBh_oHydAsUr{#&vu#tTW2Y^k^DSF=*+ZlUKkq|B z@FwSL%Tnm8d=l)rvWUI3)6uh7#Q(l4aMcboP8+e8sPPo9_?wF_B);C;Z;ptsUqDo7 z2O;>vc__Txho^Um0rej0RmQukVcJVSF1((C%V#N|yUk17sJoE$M$8c`&cxHCLy^)h z!kDI|PN#XQ%X#yE9$@N{!+qtE@KISq=H|Aal_wZcFASyd>7(&pYay9+iNx6*dvh1v zRMD}EM%C`@`+Ow1guRcpqt)$P>e;G;ug*$un}TBATDk+~7@4!e>BB^7#Z zeS1zwpMOn0*`z^OtCqopQYznbG_c;RHsF> z>Vi8h?P$asEq9A*7DvTf3+KU*4I^Nlo4G8w+zK@fMe(>tjtW*sPsO=1--4>=^|Z|IJ+J5oE`w$4!A% z{_A>q>ln`wQ(*r%Ay=ge>46&k;Z~3r0uaIQEpJB?~7j#c) z0b^tL(Ae+#e5-}COpUy^Y&saL0o-8)q-U^T1GNIOEpRjOM5x+^z;(YJrlyqS*DgM*v zQinF$S#1D57l1Oi{DE69ABk5rm-CCRr%3rgNAlWPw3 z_+ILr=?twEZg*TSoHp|joXwTVH(uIVr$u7;<}2d4d+(sfOeKyANTLVo3b;7wKdx2Z z#0w|xp|yH*Kwo=23_BLWS=Zwv|NKhS&RZY`J?ulC73cY*nic!@vJq}nisIRvtjw3qC$X+_0iPX)Oj?ck6?CDCNgE>7R^ zmu&9EiEj<`CGPh`?ktSp4;v&WaD@77Dr*eb(JLs(2E@jSLsZ(!j zE<7KATcpm6@zhpP^Nt2(c=`(Ve-6W)!*OIS@je%IT7<8(3`G0%TjbH!7iZs2r_^^< zG-dB7I&m$VFGgIa-%`eJyS6TB*BIiUEsN3n(>*dW$fEGcS`|rQx1r&N9W?(`sObFp zgfJ)Um9S~dQlvK;^z(c}^jz7yk(1jc6v^B^N6*?BsDk(#EXQ3@gb1`f%I|}tm68ElKD1WS0B8`3am_MUj zEO~VUOQXK>BLBH)QMQCuE^VTpE4^q+Cv!L^`It2s4tCp@{oE3 zXM=`!5WV;pic`MYQ`M7E)MJ(h8TC7aacMDVBYOsS-2`rr`h%ZO8%aLBncyEB4JXUq z(}C$xWIA@5a3^`7bhmKj$*m#>Fq&Iuvggcoh)pPlenEHX7U$%HGJRUA=O!5 zAg5F31?%N%9QiB>0($hvsMBZ3&M8hX{Pvlu|M;-9kHDdg34H2!4)sfkpvG7AbkV|A z_BSR3C+{*Kr>ld68HPhe8&w0S5UjEG`cZM8&RyzsOUl##G~l3~t9i{Kf1LhLA6Hhr zrcu}RC^pO+G+TQ>lTR0@>}Nr*mMCFx%P!tC!e7XEt{|qZGr`bP2iZyL3U*sEiY6#5 zhQe*y=y&zCV6D4I9IdlcJeakB_9b4UeVPlYpmvR5+jAg|Qrab6S$PtdjyVc~;cy)0 z70*vM-V@gy2}PcpO6QcSsbE_oB>rbiy}y>yev`=@cqD>6q<2Bv#17ngx=}D5lPqr* z_tLVE<1{|+Fx4)+bb!Tn43!>g03vP_o)cz5_5=gsx0bjolpKd-UEWw8aU z{oo*{9#gG)v-lyrtm=q2HN5HYjB%_LyBH!Zn$hlPnm8&j3j@`4s+LVrameBeh zevj~g&E;RHPkSh&$+B7Pp(6e$xlKKChDuz(eBS8jgfdwM_AN208sjf;Q7;ty3!};R z{3(7u@+?R6@sUlEoC(io6hj~7IcPucDqpskOSzu@v?Dx)b#ADT>&;_SvtL_q_!R?2 z>r~PDm^ChOUBbI&+{85hDoOXFe}Fq>0)yrSm+>hfGwCQlWJIYWQ!Jht0dj{{8o`?DkQ}y_zmK4|#{N zbL#Mjj`W6VE?~W1uc6|%9onxLTjeoq7TWYQr-KRBv@QP`*txsXPQ&@2&{3O`GkeGl z{tcx-qcFTML#HY*U5SN{it_U(86(CH63Q>F#Ad@{dcQIeQ#OQh?*p4Lt>Z1Oak`0i zn+0~y&c%^GJ94*kS76K2W={AQ2NRSw@W{Va&LOpGRd?TZ#`&G=`Nt%G)*0bm)z{{= zFsiF9JnA`w$9unX_L^9NC#60l4lIys?D8f3W@(=?OiA!D@*%K01A5=nC2veIJ+|*D z&g$G1#Jg*FPR&Rlxo-utkrr#2o>XYk(Mg@2!0#IftV@teB>pV2a|I`TOg z_ons5SK4WCY>z7cyyC@CS1xhM{c3)0W6XJ_GTuC<49tDP*fV4%b;#MlBcXLz1 zql2(Abu?@#R~H}ZdE*JK+4OsH685bu!QDfR`0#>M^x!CA`?2-BD<+?X9fvr?A(Hp} zv}TtsvH0lm2l}ktwd#v`B;Q@Qh?hRJ7yk3>g$p9P<3WR=aK1(X>sp5phIb@0njt(d zZxi<{Zl=cPG2pi_hX2<52M#v`=N-+e*ktw;iX+3wssA_*JEF>e24AGTu|4>|LFaK< zRuDb=dlrTqx=uY8H-nJeMn}^7@qLSMDZ@M-JE>iSr>_I?zi*Pe@ED+R!?3F9`!guR zE{uPDOQBueA41736-d2(5KMRdgcl1PLFrX*iD&$tT1+KoW{A48OmQfuO}_>|e8c7U zcN=5Z@DkRza|~z2J&=5jMyR-Z4KD242P(ayuw&*@Y~7g82d>=5-7;G?w;qR{6CctQ z6-Bw`XKyOJc?TR~JUDPvz1&Xi8opn82ZLvt@=qbKP3V`Pa&4ur4{m}oAE!i|4 zmR#4`wDpAnH;>Z9O}kI>nU;B2Kc_cNH2MW4m+lBFT6ASUE6$OHk0I~(>@VtObVLog zE6ujpfv;Z%VQOzzX--!q__8exYOjKE%g3OPc?VFN-W!hp?ZrvOb*S+=24^gsg>G)A z#9@z~(HD*N?BW#-7q_Nhfqw}+nsXCgCtf1eZcnIU>@tb7a+xpc$wgs`qp)_HCIx2p z1FKUR^w>Ftib9Mqsh@+GFxrC4&Pt=P zHNE)MpHIS0PUV;m3Nr1{v#8!9f!<&AW=)|xhK2UUN$P6oKRAN4_KFn$FVXp@M+Jq7 z%@BGsivnw}h<#!rG5@e0T{*AJ_O^5Q+vFIW*I`5 zn4u<4bq|j~_NbNQxbQt>p8GCwj#S|HzWbtjj3+%3N8(9!=7XtggSUGPKFA-rE_jL-j=iYpE3X~UjbvgCeVtokzn zp4C>`p;dL<^E9sOG!QkX{h>>r$MaL4m(=xY zJ%@R8<1O`@__pp~X})ru%D2v>;iZOo)e1c`Y^|j}cNvKS>i8o0ZGW?U%7yS~GohohRCa1jE4B zBWY&yS)uO0Z%97oKpj$Q<%{C#z)`0^T{<|A(vzG(d07x>O=~CV3nOk>8$tt8*Yk+? zGjP514%p~<7KX_(d60G-q?P@Jk!?MAVeuK~>NC4ZRhrSc26n;6_2KaRWPkjcYmX9G zU08os0lFz(!VZ3(&ff>PW3ZI3x_xs6xE7e>wfb5Lczux7i&fEQ-)Xq5-wqt^&I)zb zY&qkaeAe?1ly4z(Hr!>x>%RMo6+Ro}30Kwl^piwsUus8uF<+cjatliKOyTptE%E8K zOkSObXyc`e6~{kN>1?1b( zht100qUX3YT$r=~k2yF%1uVtE2h5%0e=VbLOQl(oTOo9r=_M{187IA4o=P4abvSS+ zfR)Ps@nWmFa4&lv+79w3&AhJs?Q>Vb&}bh2{MahK>TJMwN4ygsq(j90!Lh<|&IqtYXLap`AMNbOrDd09Ki>LWVK7Vlh6 z{l+y4d23{Na8rRaGc>|;+6P!`*+PD^3snddmq0RWuHCWF_&mQ{HxxHqz3(*mn6sGA;n`2ZK3rjin$Y&u#{CFhypAp1*rfK}XyNIJMS;;1) zLY31mwW{=@TJUY?henD$WL;f43O_=3bIf!Ds*l)+vwgpaB@LRG=q0(?pQU2VXa`)r z;WW+Zc}uSFv>28t+@-xb%{+94Jx6VIgOrSyRJN&_tel4NyzN%7{zNl>9~3Ws`;^OT zZh9iQByfJ|2xz!ez;DF4Qg34&=v!(yP=#q~H7aj|{%3eT7 z_gCPuVm8h@{S>+n`~_}Gv!MOZCA!~#F#I;`4O4l6aL9(ClS6ktzE&NQbG7L1^IMcM zXeY$?Glp}PO2X9MALXkbXwts5H4v=S0T!Kj3#Iid#9`ZJa96kj^Zuq%2Q}3yl{!PP z{WOgY_htyIV|{t5@;H39{+;ky*u)mcJBwS*9zv(91sFUBpz}Ljc(;85=B;}H4}&`M zroO#tS)w}L3b3K`gKm=D22*GY*TGwr<0-GP8|)gJ&51*FA>;T{==l4S^Von&!J+Us zTpN5<>@w#71*r)5=Uyr$Kgfc;j=JnFtA|^z*1Yg!uIT>P8=i*lf>rl2;q|Q5FfH8& zZ~U>wu`3_I>D_+xUI=htPblX^w>ukH~YYTdx6t{Ly)*pPsw-};G8ql#dQ&w63lWq*EgJsBI@cHrf*O5Q&z49`hk zR=xZ=ASnJ4KCEGSy(67+ho2SCZ#9$sTaqjee6XKv8jh3O$ymPN>V}s0Dq*GmH+cMD zFjYn!pZu8J?@UxFMZ(CYUn)k25^5O{?lG6`MJ`AavwqHjklXpgq;Euc_Pfu`u zvO}6*l7b{~Em8AX<-R>Za zc5{N!J!*u~8<-X!{yx+nJq{DUYx9~<^%yO2Ia_iT z;D%xPJjKmfK4OtRjqfxKPT!p(C`|N|IG!&t=a3FR)Xjl+KGSHbmq?wvJfh8#llR4o zz7*a41+042i@ch3>4Uo*of&!*Il_J@b~?L(m(IBWK4xS2N+94<;k@&< znwMe^o5OTH^*B8kdV>}k4WM-0ZdG$9X;uBWd7FlXOHJ_pK0Iyi3vL(UIY@OST)L}* zUF%Y4ijE3<-#aU>t|`Wn@%xbGD&lANKG-7fD8sTl@FDItn>^^jJ(s0$t$8x$$Ex$O z@kb^9+Acg=_lM?hpT$=FY(eXDAE9|^7TCVkWs{m>%FE7RYjc^Dxi*0N>wKIS1SOK! z{q7XIWHXhe!DEtPw^iPOPEEUS>FA zrYhzv_QS7F{CJXDXZ~vYg=(MFJAV#*0rT3-geluXS(@LI-2r9#kS#)&i38c|o2NXa zTM(4QZiY+VpHM-&l1-ZxWzO~&B+ghA-?AUg9UL3UwNnhgTRf9~20MYN#{lksJD#0V zwh3Cvo^Y+lZZuon0q3mlgY#~*bJo9bcx|VQO5-DO%{CJ%`MZNk?6Y{?-h5%Db-J+s z_E;gXu2$Y2Ig*qgFXyuEA$a5JPFi=>jQ{NH4=KeDg=1Nd$!gSQ!QxRC{yt@b`}+ma ze%*uc$si1JRc3*0=Q=W&xEyc9eUmT$5{;C1kY-jzijTY!Ao^n|sMkD)m)*UnFx*dc z)slF0!vo?aI0k{_7XlkfK2C{8@2LvNN9pz?zpoUA?s zKgW8CH~MuI6UUjcwr_Xb8N8Gy?|8xmF3VwDEpgh-L{_m`jJ*%c#XXm#-#NDedx*nP zUb>8bzfq-rQYOnE)G_y4$EuRFbT<2xiOO##QcJG`d_yUSdYIHX`MT^t59Mh*Z(QH1 zz4OONzVpx0{@fCtTjo+mY%X=4IEVeh>{;<_9z4Aii%Spf!s2VYIZrnimet**+lqJC zQYit?r*)SZ%a*dX$#YuwOzP!5-NhG2KcU(r;Kx1gK)u=#4Ax&PlsV{9{<#EDXz=Fv zb%9(f^~jx^Q}Dr2V|)g_nb8;+3k0pkt5>D<|J4)rP+8D9toV+Yj?yzive3X?V{ ziHxTgqeoQ@`?r!iM1R9AdPyh-rSr+PGx7UMeH?ETgTIgNAf?d~6H>>_dHUvFw5M+Z zXRWoM>gUg4MbsJYxbKdXz0hN)cgcc!Xe3=YFiGC`sv&d8kBlK30ng~yWbC*jo^?&k4KIIbFxgEy$l<~OOJ#_%9Wf7&R1 zE7rl)Cqm#?WN%EITp+%Z*Tb0tcg)^XMlol@Y3PwG8hf-(;#3^suIt`#hw@7BA72dl z^QWV{+8rJG9}pf)I024l-Q>oW$*g;=Kfm2)$X+F@`I-4{hz~Zx+FOP2P1l?+9-9E( z9{thqT3=zt`*5g>bK_A78@bgr3NQT5gSGv`g@0P6_$PTHIQ%yod{=l<%FEfjXOsh{ z#=Fu`rA0Jp{tY3gzrUEM*$qNk+#xFH2^n8q1tZE2OKvt($KiKvXa1t>LC3F(5c)EWP8%A6-)U_jCFX^*?a4|` znEZlbeL|>bsV@XwjuYfdRe6P-l*J3a3$t8Q_>|!%=nkF27D^LCNzdcZdY$+S7-yI`j>mb%}oqdk6_SjAqFd-68^GWjF6U#Mf{OGEfa z_d}HvL)E!ba?lj?k+asGLbl7&ATLELc$MJ?zpAIv$A%_2cfALW)Kr0twlX+;dM8@% zjE2T9Q~1z7b5?U#!^f*#>BO05WP3Iq)XWtswfhU~@n#o&a&v>G8KHD?wtOqrj6J8SbHvEVf{Neq_Fj}PLWb;+b#RZK4y&4Ch!MsXgi@~1VLVt}+m zOi-3i(L8W7cC1fAGd3oobk!@dKM z^`yMs4zn2NeY*niM8H-awMzP4u6B?-kMA%r-kGZw6|>#`44yM65CZQk!J#QN5IOHR z6)A3}Cn`Sj?==ddI4DKj8+`;aFISCdzMKlqcOuYB{R};fJukdp|4rPNJf0FC=)lCn zyH5X&FQL^ZCX!Ov5Zd1F5!I_)0_)B5vHbc-(sJ}c_mJDbgVdpHwG!to$bz@)hI2t& zF>PKkiboW8rAdolJKsK}$vdBX6O8>5#AQyc5Y^@=T-OW3q@IQN;GQQs9oG{AY!?Z0 zZZE*WCHnkE@_Hy97>YvsIvAm>&tta7IoWK>;9>=R#5>BU?{bhfe6(Pf>wr2jZajX8 z9rOuorf+_41=smy;^|MnVVvVJ*5hk*a?uMBChJ3_p$UuU{IU0<{`~z>DF?-L0J&c- zgvnY2W0Oc)Y;jS{&RYgw!}MXnI|DqJ2h_{+gw(k#;B|wS@}R#GlX~GBn6zm*_WmT` zrmPXXA%mP|-q1t+yJL8kLp0>P&qMWFL!1|B^#-%}Lh!#{MQZuw5NuTLocuzG6Z%<_ zrHd(U+#gAiKdrF;`(fhIVN>|3og%Lo@fe>bbs>XG576G|EXS|CKyze1TsT;ZAM9t| zFn9+ZU9$?ueo~frqT#6DAUd6`I3YwACJiWt{|tCf>*lxa9D{d!wC zGDekimf3?=Sr44@%>z;;KZE15p`a0Q4VSDK&K-ChcAj)xOqy!TQ#bX*nnoG^4f+TE z%^R>_RW&@+O5^VVIXq17q~wvGkK1}gu+xr%v^GQ&Yt85KFIyuTd!&r=F154fi|@{l zUM+^`Vh!vWKOf`X-Q?%Kqh#4}N?11o&~VvTF|to8&$GG>`?s8?dt>gv=O-6nw*3HF zkTeFnNF36U$EAE`R!{ul=0~PHo2|`kxa;O3XuGGuJwq&cb?@#FHa(3t|K7=w*QE2> zrwHt(>_Ma4<7}<6g*NZn4Tha{D725{3^Bb39T!}Y&H*!O%5eg%8{cT`AWxzG{T5hh zDa~ZXAcTmJzrNUzX4T#R2WdkK2y{=%0RQXXPi z50>&-sJbDM&0^%#^`|<_8#V#W8cM}aw>n@d1z>lbk!&21#EBDTv)Pbvv^dqD_eKSx zRn`MK|3d10Cxp_IKMrV>6T{^XrEK?AeM&j+f(GLc@uwSGsj$Kpk1Axc{C0<`AD6Wu zOCHAjD2=^Nr9q%)3eV_tg?t~|Lz|+r?A6*Lx~lwCNQ^m23(c<5$gCE09_5J|C8l`k z?J52?q=t`qG0N?{B))EURB0Us|MZWM!`UA+GG-`v*2nVlPj}(1$rj=4wiIY}IS6Do zfy+l;asC!(BQZ1%@VFN$PO??Y!~s4bXYL1eV2e(@pjxwq?m3mP*D`fXd>6u7lu}?w zMZPe1hqqII>o%#Yp2A(OKZmtV!|Bb|0@&HLBZkk}1*#F_aBT2@aCFBEycGI}LcDXu zhgNTCLGew@YtQGTaT>DyOBUlcpWg6wzaGbI>P#9F!l6yelxLjp;@oY3J&#U4LysKa z@lnlF;;v>d9;ufm<+UD*4hx4sp8H?9_Lbw#Wlo>P;Rp8cmh!9O!jnmYiLo*EOf`^&z5cXOSD)8^KLc4W#$eY~?ciw8&H420z5;chgAY%7!korg(5Gb{`Mf#~qt6=P ztq#}3l5Zh&T}{f<9&y1pYX`yMk3;D~^%Jpa^9i_ka(` z9!ePCiT8C=rJ3Sp9PPA6jP`4U=xxb7>_NN;oxjk3J-fp(EhjYaRFJqBE8xel16;eJ zLCAe}6atPYQw=wf!-568Gi^BerY_~khjZv!$~qb|Hv*a-IAKo1U8tQeu|OMppxyd+ z@U~TrBOX|=Z?HXU1UpiFz5{%k-U+faJ3+LI1-?%mO-KFWvCGmB`q|`9;snX1^YN@u z5a!4O3kPBEp?+fMfo!32@n(q~GDPT+RE;Bzb$I2t+Y;CBs*u=o6z%R757W%_(R}G) zQnnh1Pm<>fcP9AbOb+F4=9_SmOp*5oxWOtLRrIx7&8zAMi`}i#NyFO;t*UF~E;qYY zz1ZHDQV&}3qIOTZYodhhClb-Y%uej;RsyD{<0XFHNIsaekIq}Rfolh8UcN7dt5w#`_wAQuDyV- ztE~CNxPkmWb1EK@Iz#WT^y5$4)WNvNSjn@#k+e2U!P6k^4u0yO(#J%CeVXvsZy|kF zO64mTo8ZU$d*X!A!(q2Vn)vdQFPs@4PWCk}+&L?r&pwL96aCz(wtP+pea9m-#;Kj6 zuOmi0%7Xwe8_H^S$EBO}AScsJcoX4GKW3hSMN4(5CH0)}>U9QucP_w%mPc`(NjTXJ z)`wi5GcZ1v#XCdB!{GQ%xWDM9D4lB*w)GvYX=a)~9l5O`DWc7CCFv zRxx_zd*S}*M|48i>g@kmg_aBp0IQgb*rery3F1OhAJYMsZC#2-#~On?e=JX2GF3Qr zFFQ)Ph?ZND6p&)pDAAtI0-)Ys{M(AjmD`snz!6LjC=4G8uh42q9Blm88-M2o!Qlm)ggArM7?ooW7B=Y|n(&cF z-Tp+4Ro_7SM}KJ3YZS6?F5)ex<2iC+ELBhIg89ZZIIl+^%#hMO_+%h>ge(;z%e){w z*$Tb1GT`^)4UpH_mvvjD{Eh8Hn(idA%5HmO%f%9CHNFOSj$5#&!Z_ODDml0f6R@tR zh8A~u4A*pG1cTj*m@0GN*Cv*{xIy9t!B{a;?W34sm`OH&ZenU>179`jOReWZ*w)+& z62>lM5bdwAq>6u(`Jlh`ks7?qJIe-OS8 zkM*>`G`qi2=gN=f=8D)bbC9s3Knbf~bmA-Tl&eA=+rT}iQA8pST52J zPCN(dx4vT5#!^nyPsVs<-Kv~aXEJ`&7rR*)vfo=nTx_Hbjn_M%ug+D`Z*(oMTa|-d z^Vh-c{1(3yl3E8q_nc$Yy){VOG|r#DU+qYv;;MO}Q=!o6 zS;GTbcf*abf5`7SIUo9Y0kkW^AYP?{1~f{Y4Zd8d_-hxh_sQixGo9GC-~(;RDu>M> zk?=^`Gd-Ge77P!k($o)|d0W@Pyy4<^a6D}XxBdmvzYYmBTw)a6s`H}tdeepV=hoBE z@!LS}ssZYkU#HE>r_+rd3ps4=D2YoyhsVYhpz5tQ>bY?QmGNn6GFXEZMk5%LU%-#p z$>`MnNr;`2Op7xdFlcx`?6NJNyO)My+Vvw&s~xr2Xo4BlZMTG{yVT^_QWm;oi6>Z1 zn9KG?(L8m|4{_zDI5yv)#ip;X!=NZ5+;4qO6g_T`h2+e9JuesnHW+eqZ9aWG)ChW& zd+~If1$wrSc)fQ8TW>y3xi_BD?#4R$Ho60^_%~i`D@%u`UFGyW_cHyx=pbbD)7D#5wQe^yXPS|UI2il~&y_fJMNs?bvv|n98d5Fn*{|?2 zSwzLd$8{gbEnpg|d+3jd+HHbdQ-U*_3+aoCjj+Y62U;u6hMw1Z!LrFN!ddUv!n4ok z=>3iaXp7j#$~`47@xKx5w72baOjWB`Z7iVu;O)3`MsHfZ^@~_|s4ITTmVBWVD@Ch> zn-X*UE4{luhy$tv1+&^EeCkLX&Q{cg#(+0GZD|LzS6{(*O`nLjb32MpvL&Zj_i>=R zt+T8-a0z+I;)N~)4htGbTE$;9T<9;IYx)fl632T2E&UxY#tt8eqdfLNq>FU7o422? zg|&eENGRzqsfKL3D6+V(haWuqa8O|ly;|mqUbQK7O7R)YIa@1gzAeWbV>Q|ua}!d= zmdT9%^FTa2DR%obROU3=hJNG^D0Q_Q7#16L{xOKleLQ_7S8@GhiZeAAs zO!K)~^45I)wwY!~yx_s+b;66HRnS*0oLqKHp(y+z%JSxLl4&tms=3l(=btdP{{Z?j zIY=l<8cbuq=D_uQW8SdIly=PKMsDsl`+NXS&!ku@C{(`Rj#FY;CyUzh3`${+IUqd&% z`EVy{ueaw2%lou<jWwkIJ&rjsitLu~8YZmV4L+TYf<>OXPW5wxi;s=T zMByBHrPhmm8oRTDdMPC56jSBjEb)SoEB92@cly8XERavYh@eMiqDMY?30$i{Czl7nLdWz8B-AA{#nUSttfUeUzu z)zP?k@&+EBlZvuis<`TTfBf+HtoY!QDvs;8R#=|+k$xX6gPK)$q+Mbky6}0sV7JXf zzOPR!6@1)|=_={u;k$|^rF+x5pgdl+ZX?~;vKxng?uJV~=Yji)AtX1r0KHF5#AOws z*s6Mz#cNj5`8wI@T9-We`OXEx)1VkO<4MHaj zyR6CL85wi{6Y+0KGq`NNjgGe>cwz6+Tz+{7d$l`LyOtLpHi@Q*I+5aJ?+cKer&ATs z_=LNk)8vUyH?v`hDHoP%u-4+96gZ%iG9Gz~&iZ|D(cn#VWquy~yIhB6kxRIJ;ZfKy zEDf~JX^YpR>R?x|H*|RNRm$1+lJbrAqQb~KLfM%lVaoM1(d79liqi6cOC=}ZM6abJ z{&+@U8%4tx9>7xbAh4NPid~l;hkn)PF(R%6EHPU6Y<@)Ob8iZT`MeibzQ}MMy=Etj zdel*RXHEj!r^c+}Uny$zU&IsFiezCNjqb*`#RFRh;r_41Z1H9p@K=UMMVrvC$(IL> zb%o7qZzHUn&J~+Q7}as7^fz>qZRzC%Ula!6>9Nt+G;aqsKJ^yHUlhg275?0JU@dnWKBN6DQsp%G)B3;WV!uTxmTTdykY0#)Gd=nx7+1=uuBg>h?&Ts!F!L#^`QP zDVTj6D)VjXix;fUbIcrlsr&r^(p($pLG&@cvE(Wr>WDnlq=n|KSK(D*Z7}(!H`HdR z(_6z4up*=z2AeI#vAG}6)Ful9y%F(k|R()m5W%W25QR*>HvNyQ0M@Wu>d=yy1-!v2XVE4ww4 z!i?!SuIULbDvIYg-5+#0Sz?LZXn=$qQ<GnL%F5)o^ zde?yuw0Gu#P3ffk!9{X0UZjkG16+M01^oVNrEy7W{KKYJob>WA>6&(zxo3J)o8^62 znk%DYl7oEx>Z#nDM_~1#O8#$ZBbVGh%u&z6aM8qk?CCFc%kR9Q(0$1u{meT03g{hQ zMEj-vNLFb)-UxmOP0E&4+t&O*@$*fJc;FA-yN$W;jORj=??9ZM_?L^81#tD~P+Hb~ z6HUsQgC_Y4ga~C7Zl3f9JwLhOc`q;8bN(7UUU`sKp6I|P;ZKSB%|?^0d2Du|4zBrL z!l{8Bu`>O)^iCX2Yul$nWRipU)20=SzgzH+=*2v3zz(*RICk$65AU`ro= z;mZwOb(+f zMOC!s>t!)U`pij(x6{L{(Gd5{m~;O1rT6#e^Ba$u9J1vQHh!KA`t8lanxb6DtcjWOsJ1XVgc$s=O5K`c7qMK_4@(x6`=~&*;B`Td7H z4Jqf)>!CMH9^O%0e%%qYP8s9HlF`CCTRm7er;zr$9)N3$%IV;45B?N)fc}JC=O>d~ zrH+|Mz5b@*kuybP_);4O%{RvVa}p$v`&fScDN|I7xGM~m`dJgnq5J#F?%#XRQ^|+-dN3{`j((ezlvEc3TAmNfEVYEB*PP*GcYr&kZ|X@t~mf za>{CVfV_phs`90K+4~AJ-2P??r2eZEb0UjiX0HgbTYqzWCL4ld2B_jShad2>b^n(-w(KjKd@+$0AKDLUiBs@fzcyOX znv0*GeuVAOBQRrC5jAA~rf~+#`AwNKCIvsHK8w6D=G`d@3~`36rZJ=+yNic~cEJgL z%W?RV2L2G#9ja3%2wUF15z6N|!b@3_Fxce>6yzR+lph_apJpg{+K=b?YmLaqHxV`~ z@1k+-k=$VAiif@^bJeB@9Py_aUTi%N3I**{H+`R=GB1VhdnA$XOs2qT1hLtlp?69j zR(2i*FNa*9A&35gDBFmx*GJ$3i_prCdRuAW)Cf8{EDoWz9|f(;*40#Ubl!Pj5hE1HxGxXTXIxf6#We7!Q;XX3(vQorH?@qIo;z7 ze;d7;gGcqif$7O;U#}#K^H!Bb&&ejIq~VlSA43DrpMZ}n3S;_=1@qO;Y3! z_6~z_@n<`J->)zJH^WHY;5~?vwQmT@OJl`p4I9yUk3yC0T?Kp=tV7cRljR%xbl@+A z$>1MZBDPM`=27+%Kl*kMKd4ot(nU>t{=-c;wl^6);X6-Ixx$Y^Ur>GXc8r~W8cq96 zz&$EzVEWV#Ed12@bJ7|}oLNRD79lXr+JM}R&XToX1{F8tI^VnJgk2xF^3a&+ILWA= za3MDweGhrks0Y$s#Pcwmk5!Zf7N3LWF=Kc##=)1cBplJl8w{Oh;Jm}VXhGK`Iv@Uz z&UH+7ez!!0E8+rZgVZxA{dh`T5ZM#*|Ky4D4C5eq$V@C!lV*zbWu&>rivMMGtU4`I zr*OA07&HR= zVH1?wsfq(DO?l?vv#50SIrvn^Ko=1h^Sn1SQv%#a{!u@X^jOG%oH4cJ|Vi zO-)=T_E}s4$B!;!dE6}ua_!2aYUMDi{SzrS+hhH$A-FGWlC$ro4S1qcHQ1V(P@ra! zuxI5Xv_F$Y85J?qX{-xcG=GKvIXdsSoZdH%w}+O9L}`#RQXwPHxvqzZ$SjIfMnd); z8SOo^qmqguEv2Q-eLXTGQIQc*nO`GGBI|cvzkmJL%Q?@vulxFZ-tXO}niTK8m-H&H zR&U>>kMHjF@%sV~iCj0G7D>GfM6)Ay%x8)<%1Z*7oWMBzCViha_L?p3lnx66K}m^|1FcE3yNQ> zD~F9kQyYJ_T<$0Dut!&1vTQOO(*}%8`~%rV^-Q7~LDEy=sQiU1F0||~`8hd-L>tr4 zyR(2+7(ZmUTTWCTHt2yYm$9fHcNcH!*$6-KR1D@M+mmQQdU{2+W zpkw<4j9n0mp7l2DthpUZ9X&~$nHCQDKAd_()kuyMXy|ucde*QWjpfUDo6Dm~@#-AR zAASINkKL4)WJkH#LnXo10n~X%1*c4Tiz-Q>Rmyth{3}TzD_Iyz_rrwyzX*Yk^wb2q zHCKa%!G4go49E7J9SoG7($SStlE>+q;@8r&mW^J+-b;d6Ka&Y` zxVnp3TfRZ#XoY2HC*{4Fe0`ltP#ykji&w!3={qf5yUG{!!F7ii`S-_*G%&J0x zmMh9js#fj73!fGFv2B^qx!RArP#KA3Dj|Gk|EcKnxtY}@>|;-l`BlrNZvgMXzWf8R zB96Zm2(CKW)L#3TeG<+rMlXC>&Fif=#(WknmlSfP;Yn;N|A2ECqXD9I)==N|jAzH> zm^U|x)EZ91hsB>+SH^Af(yfHTGF=w1<|n_##)DVys1*f1Erms)`ysk}IX^(;%Mx~# zu|`k5%l^BfXvet@PJ385Te$hM=+OHV<`xo;b6*PC&2>SncKt!YGhv0k3jR>J-JJDG zWbov`AM{||d4Y-aoQ)ed1wYygET$Y0=vRDUd0+m6u06LX;L?9g@ofwgO4P+x4mCK> zYY>RL=AoCY3;uU66ekUj#2!B#Qd1LngtZHyda*gYdl-lH=k)MJ&v-ijBLHG0B1qrh z!5U^{!MX|)HaRhm-)(8YyvH5@&E@gP{Kqkmhy8?}lQR4HwTy4QEr-{)YoT>zDf{|& z5sfe%Og}I9lSb7Ps&V$`N=AHy11BzWtt$d)=E+L-U8g@W#p{r*tU#Z?Wx|rf59o1^ z5v_VPlq((}&DT1<1liIoTz12V#r`|T7nZ1y$REL9VFD&h;mA}|!itlH%(l)_SU#nc zE8RQ{J4%P6@4S9+#H_Gt_a+^#!QLJm8>85|URPH0_))c*l^$iOg$r5K*|1&tJYL9c z#QWO*qD>mjFz(4DbgmGyD8pTF?@)m#$~6|^ZcAflOb;8`e1{E+b>`Q+&8)ulF@-jT zreRU-c$}4Of$>=l6t{8`CvEOWcYD-vc1ozIu5K>Ix#x50;ZLCdy2~Ogv*fncE927@ zk6WSkA~hDBP%^l&`=c4h`jgEs&-&Lu$E<%e?5CoE7Bm2*dcI!EoWE;N_~k z1dSa%@ML2f6x7DBh5QU!)oDYaikD$1?K2b8)%Zu zWH--La5IgQ*`&X7>15?1#;(@DXGth)EBM9=J07!N+TNf!eE?omvEss_uE1H>JLJ{1 z5DM;d};lfn1bXYkDNBkQ=~ zY^iS|T=aS`3hUg)lKci^(4Vj1qI?DJWzB|lu{U9$eGD#c&SeWDuF;|qnbcKX%9Xzf zBn2je2a>O_8>9ch=;?~^zDs!TkE&6{{Z?N7R&ce_*74Pu0^he|>s3B8#F2f9oI?I9 zobg~zAD9*Hfh)GfJ-$2{{fW_30#IXxS%eTnBamKDSPDG#}!R&lVW*n*CqRUjFU z^VM%>o@EK0+gY9E7~FBT4KC=|vWB{Kq^P=w)`W(`0d-S6=D3*sP%VKlT|Ka|(BpTs z^~0oz3sK(vBUd0QpuacrsxB4ZdB!SW@E@96V|i%8xT6wdtK? zxBEL+_&2NCR+tG4i+18b867sa=OW+k8N&i~m+(suNO3zm-f&Cgms7+{DI7PrM{vU# zQ(cP+?TegB|IN)}llv9$zuZ+w>DW##cB&a?ehOj0wr1KeCxQK(-VCEX64=Avr%Cxl z0Jip};d3Wr9Jyo}STxO|eudZA*Ujm`Cdt!zS9`YTWCZ6TDyEpifh1i#iMzQog@s&` zrAf!tq2s2o_r7$38O+#9O)bh?esKc-F{psGZq31Cw;S2>Mh#x-dKNP|KZ!1sgg7gwCM}{Tb#&@hxsROOy|tALX$-?gw}D$`(2$-H1th^x>;VE|V@C z1rK7^V9big@aFO!PA_*QS`YCmRU4?buQt3~2896?%MML?K z)Vg8=)+H~Z7aIp~N30X+UUDRfyDPBYvvHVse=PG|p^F#vqanA_5htE?W5=3(@t2GQ zNM{7?kQg%sK9ha(odkVen$)CI$ab$^#2d&RgZ|wc_z>$bsy<;seLISw^zbdVWKJ8s z9vF@TEdycP+R4=co_>OZ$56;oI$# zyL?^Mh!`un@QtJA1C+^s;a%arNr`Gi92&0eVA`*RVD2$rl35>9dE5t zq6;k^?eeN;}QkD*OJMdOpzmV|AAyscAuFfNwGW9KUnUG(Rk8$ zHMy4sV9CoATKi=J4bPV0yUo>U>4r7Ty1`h`zTk7rk6vmpU) z@=v#E!q+Qjp?>BS(o@_^^%l?hOG2OdWRL@sC<%7}Qbi=?{(zpfMsTNsW!Vhx7i@D@ z62vNvhpfOeB=@8Zs#B#TcBy~Z?;a_1EfT>KCoxLRO2kLU$|3z$1(~W$gXc>+IUk!7 ztfj(*E`>y5T3i|pXk#vYrPUpm{;-CjbE#ZK=v_u0WxG8KxpnUr2;D^? zTcq(;)Z#QQ@w1Yo&^BMfxzYE{*5}XwN zf#l(q%~|z6B)d>kM#0^X-~R+Q-gt`h&lHMW8itbU;`t(r%}H##r3kwYJcYjbVOTrk zGbolhuT6bY`tj>)Eq= z@3}1>SMZKMN8$F&S8)0f59adMIUU*2?2`KrxSTKzPmIuJ!(U4vB)pMdt#b!rb+5pH zkFvPu&TCH8qk!u@Js3>X!mIA)(6L2LlJR||s2&e=p;b?5@Gj_LX!o zelxEs9nD;ihVzZ{SF)0W%US&+VSoSeIQ<(l3uDLVpzOi|6c*onN=*Z|IX{ZMx3uI^ z91VpmnTU1ww)3@#8}ME+Rol<-V?7#1{PuwZarG=Q{+`+bqvABtQ~nKKYy67qRjy(( zdG@SrrkTk5Ste^R^u%;We{_)O;66zj{x13e7OtPTHEpY~N-Y(OMhBx-xiXogE#jZb z{$R_iq6ClLHiDfJ(b)$wtZv^hoDuF%JHo@+NWQYV)j5-fe;7~J|F-j4&mThGK3@tR z6w4;JsnZ*?L!7Ny7H8BISe-gf5wBgnk5B)kF{aT6*NnW`C~lC%OKd7oLH$AV!=>s? zYl11$+Jr&*d|2wSnFXw_f#MI0Z|Wxx-=bde(jA7hxUUGN2bF`%2wixs;|z*_q-mQ@ zFgB`=CY2;Z6rH%qW|=usN3c5v8MxBbU60wkL)LKkhB=!OvJVQS!YHRC0PactqYjtj zSR~SioFEEfxXv(lA@bmvmlb-x$#plw%!2byx9J-B-ed&iS>KCE?kqg@q zm&aaCFT@R9ZR~e?1h#K|zhgF9~_TwMH!r7ClY^6E<2m;!q-^d);8FF*imn7E< zJ)W^6NoT*n+WlI_CYh(;mr)V0B)u1Y8usyWwOd5WjamM?D$HGDATrHE{jH4^Xf)|k$kj*}!t<&b z_%Mnr-fD_lulqAsfi?M`_%75hyn)xdSHY~m$#igKFtPR*+|32ap!KJaov^dt{{$VYhWp(>7Ck;B%%z6o_R?Z9#qhY1Ueq1I?1$-lDVy3gIE zckK^o)l5e=S$ZN)+;p4u{L^Ipoj$Y4XVP6z$y#|G&I=BY$zj{m`%u1eA>vtE z`r!8g<6m8cz3HK3m9mYiy4Q)a9^P;^S{{#eUt-p#73{NK2z{3wOR*wn>c9IaS8{45 zc+K9$^R7Z)HcpNe-%PKc@P5e) zQS5pbwk=GLX1H0xYy|~O>RkaJ(dP7n{O=}LEjqxMRegp7rQXo0ynxUe_^XgoE2V9{Q&e}xUxNvMTn%n2Y z^t=tExN!yO#WZql2QsiZARA1*FOg}*4p{$W1v5<4r;w*R_=~M-{E}F6d?azF9iOfs z2rP;*w}NR_Y#6(DKp&6J;b`e{S^88kjC!}6Ca!WBj#>STn{ldy&fNG|ZB*XHY}B^F zYR9RlEZGZjKGKxmsQ}lX+ps(JVZd=UT;JR8RVf379%NAn{J;oA?C& zZit6bY%iSski;c)OcRnGX4XfieFBSn8T`h<`ZWFD71;ByA6{rEqYJ11h@8!yu?Zu^ z%y&jSOBka=?U!s}T}c*PDUXHs`hxRwog=@=VH|H{x&qcEm@;3^llOMM0An9+qcxxQ zi)J;q{69aBUl!AiPcvv#To1o~rc?D?{bs&S>p4GRXfb|^d4eY=pJgTS4Z`p1U~c3F zRZdwk6dsiy1~UZ{v^;1`Apsiztm?TBpJoGg4PZ{S>a;6^?`yO}j z(?YgYP7QSBT%yWEYyIRf^16hLd-0e1q+mq3>s0alc3adQV9BPtXtG1OW2;@?yyp%c zisQ#rg|iozU2(yF1?WFqj7nQ((A9Zote5KZP~|C0_$UUx$ChBjq9m61x|Lflu#<8Y zSHhIy9Ez-WWFzSt4tSqOtl&30Hd;lz`qnWj`SOt~$p}Gxqa}Ff_i&iDd@g(a)>Clu zo@Ha#?V!+~2kCpL6Me=~F#n;B{zIJE_F-8#Z>TvJnYsv%9QFXtRT)$EO3~VO2UeP! zNr?j6(&76cIPmZmKxjTKfjh^o=5!MNVVwWu{c~{2DXSy$5yc5?IK> zFg9taIk)A!Dr)}CVl`X!S=V-Rs11?BJI?wjFZ>q7m~$BLZwg?zq2Swdq{Z(H`Kr}_ z*-pnREHc3y%q(6Djz9z0r(M7deZ&+SCfvJfS>VpO>%lJXZneeuGH7fB(X4Y;7<9G} zt{zmv7mp)YKMCQLzfoB6`XGdO2>!LgAnv!^Y$j?FvMOR#@$z39DF5g*Gqr!jYg`|T zxAdcNP0=IzYd3=$Ef$KN{AVbdF#a-&_b3DT8Uy~>)1&N_eSeIYsEF6+%VOG16CA(n zHV&)2$^|tDIo6sGNd4gm9Ydnn)eDwv+Nh0Gr<4aBLHXe3@Q95sdqUf8WkSmJ3bdXg zh5r>n2dKsP@bgz23og8=Zy*e#wmXT!U zouL`b2v^KCCBpz~()KGtPeWZ!^S&Kz{C1iZzn9|{UUS7Fec|7AVlgtL1jff{aSB|2 z(SJ#gxTvk|yi2h*{87=urAKej`u$I!#9=DNE*;OM?aG7xOI>Mc^26%Brsp*El@~-e3xnSA4E6!W@eoY}(G3ApI|qN!#^fr>?(Z&-Z<&P3WVcr{HA71JNA1DQ|lu;Tj= z+S$?sr&|^9ZjTHLG>^fGFGgY*be>wDm9WR73t8w!L%eaR54tiI;kIq(xB*_5m_y)B zv6uMJ4#2CY8HZ*SLxvH%whsNTnI_!9v>cP6t9Ck(;5 zM4C#qqF9*!Zgfb$D*Qi;7rBQ_M$0eG6m!Y~z2@uTOYybo|LqOHgn`=`qB2?g0LgVm zLG6|n3VZDZ8$Vs;m;;dK^}6bTX#%5Uu_kWc9xL!pv`NzTf!p;ukdup6!2tQGWPhfJ zwtoK$U%q~0?|Rh5>LdTbEw2+OmKWF(oBFZdSv}kjpPT&HH@QrGt+H44DMrzaXow9?!^8X`oPnvR&b@F7_Ba!ry}i0wsLza z$)B}`!M)$1DfKfOrUP_~>xR4mK|)?tEK;{O#p}jb0rtIxLETc5h{`9%f+0=`6Z^ zN(NVH$1sWCZ1Q^-!3qW@Gp%jKtieX;qox&B2Rr@8w8(|sZZbn>>*07hSq@!%!m)lw zF(rTLhKWhTSi`0LQ2%2vww};J^(WR~aPk5OJbvEFZ7i#33Z(jV$8lom9#pIi!+F=@ zM8f<@RvE|nVxJ?}VAsLP?7oUt%cBJzlPQ9^45$>Slh(-~u7A=O`h2aG+|$0&)83KL zEJRvmu#hj5aiF0AuW0|#9n^Efi8`HfVD1+WoOHkxzn5*NmJhLLG^msHHAtrz0M47&vD_7y67s3f2`wl57|=m z{`dT{+M(4cH^%cjj;#mzZZA{|RDdB<{_xLV&*iq|xUoJa-3#+( zJcfmb5#z>vO8Y#QOotld;W5DEl!?HhadA=70{rXHjeS2u(I}@54ahs$EX0UULFG%4n1Buu_vw*M zG=^x+#EAK!^rdl-c+pC4$3c4ZPO$!R8Vd$$OGdc-t2S!V zBzm?N=l$0V|EyC;!I!YpJc1tV(4bGRtgyyVS-d(#8OOZ0q}(I=U=@?jRh5pULhC`` z7W*4KPdf;6!auhCkd@dh6g(Z_N0yDU60us@cc@S@#|PB39!A;(j?@Ij{*WiB?5 zw}BIL@7d07^pw)PFa5-o^G>msi_~dSD@SZYYOUac*#Qx-7}3`>-o6J5XO$iYPD?%so>fXZ9ZUZtyN_yw(FR z?#i*#T85Nf9?F{gI}m63ifevQEV{fq8f3B`dXL_pU>P3#9Y+s=lpatG0s|WnFDE4 zZbAM9{B$OO^t1eFx}GhY8@Cs<&9*}RY#q41rm9LRKB2m@@+3R=qK;esdlT+|x`T{! z{J>W6GOo<3BqyeU#~+npQh+)p#J5$y@ioIwsgp^?QX22XPNXu$Z_Lu%7c@sMrzegA z=LB7`QBgwI4JM$9S{8&j>hMatrqbW?G?-QL8CH#(g$Mq4VN%!<%uaVk_q9LR*4u(V zeas9hbpOq5x;zQCH??r@Omqd$nH5tAb%D?0^V!7vE;KD}0N%Wo2bqa}Y+AoIuI`*A zsk7t!@8vPzVe^#@u~DP>2k)>;VXI-2WE*EUHVXfH|C~*fz0cIfcYxu?LE?WOhlo2a z^#{znM7P7EAz!u=nzyXt@178x0ge&u)l31(C2&Es=X~ZqPH*IloV$6+>_YzgiqHJW z!xe1g<15ghu1MmJ1n?fN%|IcC-*r|MJQR0>>B>`VyIQm8?kX)N7kQe6eVauQO1I%a z%W2Me@(zj%3})eXYpAYB_%>*#gZs@OoFr$@#`X$5{bh%!pTc2g5NA`x0vKN~+K(y+ zY{T4JEAd>_Y5uj~Md)pe!RehJKtA|5U7OQ{dUuoP$L591wa^<%4ld!k5A;=kIXa9D z>5u}Km^)BB=K@+Eoq^gPa@mkbDOUPr2QGWq19{6*+27?iK>n8-v`ID6<(3#KP%(p5 z(8JOl?!mU`r8K@hn0E@#7M|tGYPH9uy!#A4DB9G8I}@J5(zStjal8=*Za7Elg}m&j ziD{G*;{iqj3+eRAJEDL%XIk#iEmE}V$1S%S05{F`Nba!*#-Ed>j+`{O(#9b1h#3>F zEXBS0`@zW8m7C`Bfj4TDMay4OxK}KA9#>m~`uF!D6Q;+tt8K;ml~Y-t<~``1*8&TV zil}CuFAm%nOP`ON!>ymX;h?TQnpdr)B&l9zt)2=lEmOyF1zd(VF9jsd^RANld! zwQR)&c^I=fm;IUYm|ZUo$9>B_u~}1Bv53{1Q9Rwh+W1ZjUDcG3mN4I@xJWanq7>GA z)SIoy%7U*)3q<=Lo6tltknFL=xK?c_I)`#hYkC$;TI37qnMTx@$PoL=`dg~FQnzcYU+e|8du1}qKQkE!Wc_ksUc?IErk>+!%w%A(Q#zy#{KSf983TzR+pb#0j=$?*m{we48Lt;hWfv_7S&5|bG-tm#M0TY6~m@$@?o^_!fres zI|5He30*+>O4cyh3?UM}&NK6;46tSOw9bvmMN zjW4FQ8VmWB9&lft3!ZOJu!+k$*gehN_)TsF1@ya$l}AFL)})wZAJ@>@7iVz#{RvdD z--%SNp26sWR`^imJEzDh@KFDYbTHKhY^R zxC>?b-@-S&MWpy5)_PidJQr6fhsGmz)5M97*^=wTZ=4Z^5-X8~x4|;ky(s)}g!&3(n<%lXsBdaBiY6!hOW;h8@DU{Wip`>Cdz@ z)Y;%(H#Wa-I`-eSj=vY(z=~UX*+xq*NiK!OXPs41UcD=C`cvLNb@YPT|E@vKk=d33p?n0s|{|kv?0}|(c+y7%`p4x9Ey>w0vD%m%w~ZY&3;S6 zvWd2wOS`h@X0-y%xTr2M-cpF)yAGiFr$E+~_C)9rU8Fq?DZEbPbgKd>B`XU+obRZznE*aDEfw+46HeL#QR$L#BeeQ06Z%D=zVOefQV2;a$)@mWVK z@*Pi)@?3 zAC8ql7nq~Kr(Ugk0jxC-va;rX{M3U#A$_D1_T@%!R*gq6`Nn5XcUmHuO$*?T7!#{+ zQpb7GF~D5k!{pRC_|pF=_ciVtndHnw+V`%DwYO^N~xvrt3u~z8E*n}tY zzDW@b^VKQzMH^fF@eO-y5C}>JC&{e;Jve?jhfCGo4^D*vY|umDZ`yj2)&5W<)yMhl z-n6x_{+9s@-|q<0_ag0BBmVI5j3Ix3dZg9L9?gh1l{CAP+MgJN*}i4-XBSn zu_=wDHxFlDe^#N|zz3pW*-Xk5m}qlWUBHdYJkfX44%~gG0bd>3ga>~ofQqFRX?-r{ z3+e`8>GxPxRxHmH=4`;K?^B5BuYqDsMRXP~#U&r!@CW4|z|!0_e#(k4x}vAat@S0C z927#CGlt_%T^&hBYoDmgu7dMvp3kaT2t zj{IEuT_4UaTfKthrUy8x*`8^sJ>qSzY4F<9YlMEPEZ%a_!IMD-(A%v|2UIdxOjt7g zxn(TkmJ4T5zjV>keK(oSqJ6Ob+AkP)MwJpxgjwYGEgZ4+Al{S%^j|#;n!=($0Dv*C zmRBq@T0~u~4Y+xjGIkc}@&Rich>xF4JN|XCDb*a=j{D7O%Fcq~zO8K35jEU8bw1fS zCr)?zwI5Z}jPa|7tR%twC%@CD1K!NZWQSZ@_z~S_;HX4Ha`oUGbbM(;Od9$wH&s9-3RVh;k*a|jJ&s~=WeZ3N z?xI_cqo&LI=~3(B2pV(j7;=H(+{+0Dbnov%ip%$*{ekPrV}h38c(I^V+LL2Y{e2=gVZAvxzMqXf8N{nstN`t$R3TP-&snOw6X-eXUAdBo_DZo$YH8@ZOHf3-C-IBYUoDS4_K4Ei@4LB?Dh9y z&^l%awCo~*d!v@qh2+m+l z$tN`hHuhvH-B*7BFE;x##kM=p5HgsF^$R%vqoH(}jivP7OYGHKYqmAHnC1PL57&xz zkcRt4u01J)UH^Fy-NE>D@``dEbEDqL(cm)Ek9P9x23G53;qk*nQu_U>^U zduuutW!?VrpdPOYG6ufk}GaGsrGoP+CSZE);IO-wjb##X%9 zM3Fgdn9y~f8>$pZaW_v^-&*X+#$0g%vzZ0x@@68dah-t*f`?^H#A%dTI1LnyYx$U? zTluIkN0KrR15YfVFXcX%|LqW!&wR-`zZl@rE5cs!{t4<_egs>VKI3YBr}M7ccd~cx zO6*3i;8IObU|zS%D799b6ge5plSyL7=GxJY$V~dz@{=nxnFrA`{&Dw%y=lS4*WCT{ z%Q@*O2UzQMQwogt!>IuSsP6s?hP9@g$DADg!GV2jpUp^eSoI%!(8@FA&@@=TVGQby zn2yJ6EAh@63(-i$9~5%Xsao#z7;ai#18A8HC0RO)SNj_Y+~+{<=c#5sBsT$Hnxv9Z zs17X=*j~{Ymyowirt`wLRAJ|Bo<(k^LZ4sQxTb(c%u*zy19tTI?`Cjr3&yL7t?Z*u zDy`tdS>z>ErgZH-jIQ)yYA5RT&j7VSKAaWBq|c5n^b78z>HbF^Bg8B zWU|P2n&QR1Uiee?GXJe;GVNp{T&tl*VKxEGZ_^l*m&$-|4c%SQsSX$lw=255gvO{_8TCaX-3 zrvFkViuKd(3wieGn4bCyV!ckn?#yaf+p>z&dRWg*irT}j7TG}0@bhfT$fdl>*#=Q- z{Zr=rWhZ--x|KDRNYSt)L$Wsaq}$j1gnPX0EIaIG^)|~0dN_SKZJd=2Jui2|%#WQ^ z9zTYK3QXN#GZ)hOYJuuo%sH(9Gj_o=8a7+B^I!U+z~ym1l$JJEPOWx>|E$0B`$~!J zkLcjXhQH(=O_hQ2E<0N0v(v>M2SxmbM^XM!BC;kraE97tw zas7mxks+Quf0%hYhml(Oa6IrP8g57jQ&@R2TlQi!3w|tvTkiEjN~8m>a=Hx{_hw*# zjRu6+{bjY1w;+m|#Z0aarAWU_#yL5$4XVeOw}%q;ZSCPL=c)$$`irKyeE57@aN1iha0V~HNt-+T;qdir&@+1m)5f#narY>*c{W{itbx9a z6Oi&NgWj*Qgw5x!a`uyXRw3e*-e2bND#yIa_q?yy)cF2(I2R z5XO%f!P&QJO5R4#q?hlDglBp?s>oGyo6JghkM6;EY0x+fA2XJ+!!<~(x(?EHl;C3I zC1&>86B$| zjptg?sRfs4U5T~mS-NWKs6RM!U{ z#;2z&DDYeuOAr_$)zTA?83LUB_KY2vUIIbSy6DG$VO6eC7jWdevE-Ato^Cv!$z|2v zVWv`x@QdS3h%DX-r>FKYBmG>MX+H)E3$l4HZdvtHX>&*_?G$m*tC{IWGYVSymp?vn z537H=k7+y!0@(-^d@^Ggh_8GUo}&cHm#Jf_Kfl5L&M%z!zI>HK;V?So_Xw^}pUDz; z^}zTI_u0$FtCVo)9g}-Do3y`laR-GwYG!#K$(zrEpO?b0d42;IQh%7G2zi?i1=@5i zUzra5-A|nbj z#mjPG=j2sbdexR2GU69&?UrMYGb2PY-ihq)(kP}biRFCM?LppuA!^0dh+a1uvQu_e zSa;|#8dd$QvU_uxacRwj3X0<_@P>s3rq~y;Qy*v2gDN4%dN~4x=YXl)(8uu$ z8o86EhPhXHUcN@_f$M1QlRpFUs2+59gQb-@sn!JaN;00{$OTR^`)3F zo@%7|yGk7DY`cW9k@;w+5rSVw?_mj7e5hYh2zxIu{gu~Wr{>9D*}2{C_*>D5u8SFzzTyPwxiOSj!)Z?&ZHKmJ;ZeFH|*It4{ zO*@WMS_RsE#ZdQgI!!IjM?Je1e6+(_yyuu7t;-1leuN=Q+Y^ajhTcNUjZO#<#@;#a zL|@Yx?3bJlZXeym?p2oJwDe@s$#=ly3(9=CAev5^8sBtpf6*{Io6ic<|o zVpQYep~B2Tnn%b1z#o`4GJRUq|QRkJbPFaigp< zvx-7VRzgW}pZBGd5-ll}Xi(D7o`gb3DXWweh3b=JMRcF*x{ZoUa#jZQQ(6qMWPvaf zf35U{z0_(X1Q!c;(9z-0fou$FIk;OQx;d*)i8y!mq`2`4T|s!e%r- z>&8A!ox_&@l%~i1k29Fk!Crse$wFsXLQnK*mei#$_I{Pec5h6fXy1O4r#B9YEO$KM z{63yx;#vxY|7@m7CS;r%rn}ge4TFGQ$;6fITpP4BfF(j3<(aC@mo|pgf(|E z-^_=6s>*7{A~rywPdDj&o&vSPUFx&(U3UK3HoWw#UC0X&bBj5~9T^?U}&5M`qMKW^!r7z%pJcJuS}$u1?ByC= zYBuTzT5L^Vu zY2}Px%%-MYnAc7u!zUBjl^ykLf@u*2uU7;mftQoU74xAN4~hNVg>!eKo>8&8=mtw{&p-`VS?U(xt3$&@T#cRt49^o1s~0KfHPW z0gTqmI+;F7DlcxY!NPOKFn^?k)ym33TiMlX6N{5s%V%qbjb-e<`gw8S!hO7qXt=oQ zuLzE34r6+sU*Wt(32c6ZHY__RVR|j#H0kB$^}S%lSprVT&4>*fAe~ARrF}iFv+86WtwJGjMd#k@!Yf9tV2o!p@t`6 z`XfEb#h0;kaih=HN~$H3C6g@R8noTe-o$lDdH1Ld8z6uxZb z|Nl-!7E%<$)R_If1l-a2gMSvbn!W{IF0(yWfm=fA&dTl0lkK_?ousxf>b4OKRal}u37Z)2H}LqSGjEyQz5+mo!Gy625b|( z<(viPSIXLJeDZ)ZOjoj-l`WT|0W^ma)C4m9oH(l1o67iMC*Z*Jc=5J9Rj_GBBt7y^ zqIltq8vJgYWXYC4@YQV#tv=LEw&Qox?79HbZLb3r=WsCTXyXiC3umlF6Cn0ykHd}J za@<_J7~;O)`~&{%B+Pxg1QbdKXI-(G=i!vIX|*h>)`eIa7lY?9KMOU@b|;z1`(`%CS53$wKf|_rFL}F}JK^d!A9l{Mlwa0TPxdB} z^dUHwy1p-`=5kwR%?%U%nwkq6-^_vPmqR2IW*%g#m*(PC)1}<$K2H{OM3dz2nes2U zrGt3OUiL6Gnk0L|#D6Z&q6w`r7@vBY$(NVH`KoftI_=4=I;o5$%BB$CsL9QEpeOlB z;B?$HhYXy;IoFG=>{QEX(Ra5Vw*T8i;hQaVE(8~(V^G*f* zn|tAjV;x!94}|}umxJB;Veq27lw^Xgv41NT($p!*5ct85)TMh+$Z=8OhtvP_I?}!O z1(@inE^y1Vh0MSq7Bo&1F7z1kxli-3@YgnaH%p42>1WKAZd3uw2bHWv&7M+373ib3 z5~U18Z27{uu+4HZT~E!&Sg)z#kB1VNDC{`8WQ0+~lq;;)1=!s!n^^ABNOq}j1bsFO5e~+2#TUVy+C{3Cfr5GNrDv|Uqhu9Qr_F-ulTpfBI z(*JXYbJ<_mq{0ZUCi@lohJ0d^=RD;i=_dclMTKozcRcP$NSDx~%)jBNW0d`SOj z_AVooZL3s*mJ{mGanlYWe50_tY#lol;7;l<6wt`Bi~DFd6$2;yVhv-%ux$&+>dL(N zoPi&?^hkBc6msp;_8;Semv5w8`+AWonvhofe%fOLf-~tRNd4X>-dS@MF3xBrw?P-7 zPk$TuT$#Yqo)3qD#MAiq%oMcn&gW#@G$HY!2I-!TWEXwi*cI@@d9TM(d}2HH+>7JZ z-Yw?7IrM{qOmB*=4`(m6MnKQ(SGeih9c!Ery=0?{nHA!e~7oBb1dr6QGH@foEc7$V~NzuZS|*~al~ zie;7PfBdSRP*qY$lLd!yCUEu2Qj%IN2P5|V#D9Ur6FhYgT*1>r!&VYq%k2Ir1#WLqCfLv!* ztW;vc2W{v~5x^AGyk(8TBf|_PnE*Wm<&%v^(s3W<8^F4#vzggcQAX z(DW;w`im!n)LnH{D0;$jt-D1Nd|#q%^ksp4{)C^gd>XxpTLd=N{?POKK5s0SL|4Dd zq2(tD8Vpf~W%*-J$a{-p{U?at>@%kl~@Lo2|Wg|Q1v>4y_4xm-y#r%J_OxV{2^03!c z$gZep(7gC9e6a6v^bnj8Jtncx-k=J(XB$!ZTLP~lpTZfojAXNa-ew0@-C?6W|A0#lh-X6lA6TXj2+h?M6 zs2O(MO5|4P526EGvoY>dEvzmumE_Je0GY+7@%5Ee1S5)YnBxJwyMI4xIernN*KH%a z1Q{TMn-uIGPd5fBI;HN~O;uxrXQTQVduvk5U-Am3>V++Q$kh}uS>T8oS|M=UkHc|O z3G6rV%w0Z;eQ>FTU6Y(4EJcpJrCQkLABktegbrWIL3DdiPW8$^9kfQ}knyZU_&B45 zN0{u}1usflw(HvI*kIf~{1$zD*}}O;nK?DZS|R=Yg*mql zvL)Gqv#Hb;WONPjPrz(SuOG^@1`jS>F&~;Po8UUZpJe~X9risFLu|kx@V_nemxY{4 z>*sOs@4JO$?qfO0iTGk%c<>249omAP-gPYF(h$kPBY*K!a17;SUM45&U~*9oR{Mqjr+MbeTjbGhS*G0s-7gexh_nMfdm$_5Gnr3KUEXJ#m zgYa_AOvy$<)uQp~_sL&lh zS<)#FV`~Z))9j=KZtCAol(gN3O=eP(10Az5e%v@>Chjl_9so|-D@jp$%N?!iPt~3s2u~r4$WNcZ(a7@RhLf<%E1F`yP1Q1 zIMXp)%9X_`I{lg!0ipw$l=`Bbo3Zy8Xd0e}SFHhbM{6rg4D2QOj8?91gpju$^`4!2 z^jmZ)`7Qo6abT}!TEeuHdT!@~TJA`9GHXAV4(mk1Sv_JiHAOg)a&jd%difDtwp-|r zqY|hFSkcA#PGra~;&DX>R##)kY|j6~1!c$4*J2Sa^7)KuH$Gxg{|I>P7|9f?Pf%sz zTI|^D0HWFIY{5HgxI1_f^*i*2IsP;S11^zt115v@+h^!fpzY)s*379^8*}b2JZNs` zHfjiK;PZ7>(8EzXxOIkyaZ6Do7ZX6@l~L8KWA8q6&y;2rrpsZc@H+D_PiJbjL7ett zPfqlG2J&mCLF&X2keoRh@)XJh=E{ z6XD5aCtRs&%Cz2k)1kwi7+3j&UD&dpEs=SPW9omiVW#ICb%R#mP^sl?;8S_BO9XaJ zEebaqR#9o*F|Mic0QLWw24Pn!;Lk~K))*l$D^z5GS^RWdIdl*`9D9V#yLO3BIUfZw zlQsyPplasoy@zD(B+{SYI2vO;0Jm$#AnizDK?4%F9AW;mF8KqV`56cCYwj_vU7B1? zo(_DNexFU6w+=@c6tW@t!y*5ig7{%`4tDpL!ZpVXfvJ_r&Zi9%b!s1?8v@I;z*Uhd z+XGo9g`&DzIGQwXr-*M~WE+)Z&6ZMTk&a|G!>6CAKf1 z2?>))L!8L6ohOobS}TsN&t;8cQs|H>2e*F?hLhYTjLIp)AAA72^8PV3l`V$sd)HBb zp5VBd%JA&%4DosWBJrC16)fUIF0|9hp)fr#o09e=?e`O zS*OUEG`6GCo=|Li`2h6K+^3Wj4KSEw3!U|4+~=X*q!e#J3TM-K>r6o*r=di)^*4Ff z)=y>Kp3Qjf&_Y~lZwHg(M+rIZjUacUmPHErh`cIdD>B=0g$J?xlAEl9j&l{Fa&%i$ z$7zhzg)~J5Wus$3QDGe%EZGXPDQS7NEw|Dg>l#_x*xsF?nUtNU{YtK6*q-?3;F zo5r!P2`p^xOuDmZ7s!f|Dg5;+&QeR7cFMSQ_CiCc};2S>V z+k-XDv25Opt(@O56C7$Q0prtyp#MTKI&aBF&$8v%Ub7tsJyd0r>Yt;Y|8#QwH`5tW}3JOSIhb~(SUQsWyA3oG+ zX^pf*`mhUV-CfC+O`ZqKS}K_Bn=uqW!3rApN8+rvS^Pr}3p&#xIMH%S*!+G`{E{n6 z=%JAd%?dlhrdrNm=yqGw`bi2*`VC?Ga?W#Z+DmYhs~-KYH+;&}nkF0O?S99SC{Z-*fpEfsisF=MDX=A=W){u51 z;x7*qoV9r>?s9kK?_9SRUp6|!{d*X3?YmnAzc)OO#xAb}rR-CjTd^)J)3c@h7dKO6 zlagrIq9?FTa4Guh4xquib6MLr4OrjD3l8!!UgqK_)E!j9RbJ1=rvsnzoeehR-0WQ$iV4uJtN54iP<2as3JacX`pCAm6jKW5Ci3bPnTH&Y*QpTBH@K{xKfCAYCK zykRHR8RnDe)8kO!VnhC^L1;5pp5E-PV+~VM@jsK%kQB867R|JUyLN>%eG0+K$q$j% zY=O)H38eU92pmb{=@8|yHCNYC%bOw$8hM*io*(8HE(oO;paOixD0=eu8XL8`82wx| z==F;#%(FQT8FS9S4WZ|Cry~QK{=~uO8Nv?bv5CaayA#(mYEsk2XfkOYN$LfQNY79S zG$$S82CPqn8#fgpJlq@#E_d*&on1j(u>%UmMndqD!7#kDo_*b3#?{X0FL|_OCEc^@ zBNbgamU&HrU$$4FgXR-9e32_2KNmw^13f8Xq>zbBG!wc+$%1cP4;IF4rr-P4i`HZ( z3G9>sPWjuyVAgLXno;qVrkJ~df7eW^k)JMjum^+2Au*fsx`bSIx{6@+zhVrl`8At{4L^z7&lSP&W1cj=B84q>uA~oMf`qEkb1a&8ki;-Ul8G3o;7$sS<;9XbnZyd$yFFPp9`N@D(v^`L9t0hz;$fLYd%T1uS2 zc}Zltx$*2*fIP2xRf^jc-^N)SwZR>`dj+1?6FM?s6$KiOgY~f=aQob$ETTOPRullvfe_OAF}h{VewWdNuY~Z01z5{K$0I2mF9VG(FUug2J6?x@JAd z4j&BfFE;RcnrC>g$jiLdK~q{^K7$OrM`PB|vvBs0(BoCUfY)T#;YiUgGK;>$>RjIm zeA|P(=f@oWyx>6|b4f7rDA|yPfjjt*{Zk&7$LQydKAgBBjCC%lbE4r7=bCZpsSdbwiIH>>nK=P;zX+*U15j0 zu#avDft2kcv9!1mKA+vrJ$N-3_HMn;rmerjg{|Ais`awCpVyLb(eZYCG}4AtJ?d~> zz&@t5C4}Zh@1|>e0D`@GMfX<>1ZVw?XxTah%0{L0s_6^C;`~4=JidU7&kMpE20OVN zLo-r&+aKb36zPwW3RSxf@?HMc2xagZbA_$;s$)+kK4b612Py8nE!|$Q0slSv%g$!+6Y>Z;P%}h>n;ss? zykGxeC$?B%>@p4Vagm0y2@3q!Q9ID+RWezh8UdT^)WNLoH2VDtXYYfQplW+EONjmq zVKLh&@X9^r`sNKgwXqYcHUU2{c_4XS8Ohu)ALNcG_2*{0ePdQ@=fI91&zar=72cyS zUu^Ve4Ij8Mk`8A_@?*NDl5^n&E>F#Yt+O+LZ=X`dh0j;h*dsaUQLh6>n(smFuTP-) z#gS$NAD&X;oiRC@gp`)T+BlC=Zh4=^4K?1JsLZ^giAH;VqORHnf!h=l2u=cX2Kab zKTm<(u2o}a!=>Sl_jsx)%wRd$76Ln_nVAf5fodCL@F)=Oz=8cJ?x6?Wdzu3i{-rTh z>rTcz6`c$p48giUWUuBJz@x6)OwBxkJDhcaHO?;Q@*G>eX25fcT)0y7l=*sIga>=W*}ki@!8N1~6U~{}aqubB5#HYv zu$6PU9?k8@PGfU^baA~;BhY*6VmP2+gNvR|;ZmL*rSTVQ#cv;|I*q+j4bQgU!(Ck> zRLM=lUzwlr_TCU26R;7OlNwl`+(cgfhSXo#lG6TjL4!l8!)JRZvSyQ$+yrSA8Z+2{n)Xb` zj;{C2&vpUq_1caJ$I{XN#&>>Flrb4&2Ed3Kys=9KjiTjoq`)DqD7wtO&f3OKuc>1O z_PMm!@hJ40@Q7vc^GRmJWZ(w(Cu4baG8+|5>5>SPKI95!cdRI+FB@bF_oCI)FBthD znx4Mb1j<%^bU9y` z{S1@kS&+c`b;^ORxl5t{htm)^=n$nG?}g;hIvA8U5cS?)p?Yy1W$iporNKLCe?|&> z^z9Oxct@Ak4-aB*r6a|SCWGkP?kh0Pb~C7@t$_tblPS(ai;P@T$=RR+pPANR*@tB` zx66jqKUPq=Bod~tm_mw6_LKE~O?0drOpb=fs7Uw|#Sgs+14?9^Vx~%i%(LC#y>uR| zmp8+X@4nz1b{FMoBCnLB;1p{wq8k0L^g2vR@>$jotUiwBPSwYQ)Hpk+(!C>O3|5os z{Ypr$Zeqm+&$u@e$DnH2Fxs;DHW(kWBAFAZ5YRgU_Lw{HJAMnmJBv)OBZ+4OYnc^)Ijg6T$(M+ z*QZyef_Q-xNdkXyE%773=X0W{=2JGfC%xv_q!v_IxD=XuzM`A2D(vOI^DhT=(!C}B zVDqPJ4EpXuXGed)LAS?3a7P80?ns8GQ}&XbK6St= zMHM%4)3orIEq9Daid? z1<%%4!o!P(w13?Kk~yvf_8I!rJoF40+76`guJYpdjst1rmif$c#x3r4+YT(LnZ@o- z7!Cppf;!q}QAlJy3pXofrk7V@vQsr^Rg9y~N&hfBdk!<-uOacBDLC%(r%|BaR5Hsy zh@JP6X$02spW<%P2*Kg`L^p!v--`h_oXF}gdH?@BzBaksL3}`wdi-@@TwXp`x^gc* zZph>g4>YFjV}3GOAHh)&whJoqk8&Zm)8E8A|EZ(Xt#T)a+!aAczth+mqSxlG@ zwS^N|yM+RCTC$Mxh1|l5!2iJ}xz$DaCtm zMb)OD`|%C^=pG2Ow^mc}?o;6!)a}!Ng%F?tXB?|LR<-Dyf@_&@wVgDLs zkXouEx$)v8Qw~7 zVhlSm&>V6XokpMGn_=^J!QFIf4!+*JlWB~c#Bp6w{J4U1Fk;7Fx;0t@P9#lbQXxk; z?+JtG-#RD0cGm#fo8!QojvV9q%kL%cmJ!hX{XWy1E)ToDdQe+X0xPx3vz%aIw^!o@V>Hxo?J)(ygeqQR zp%s5B!-M_~%qO|?``FKAt6*HiR*-U zTPf0}ubzCD)NhnIBQQiWw((Zdso*oAKX?yoWR3yfx&K;I;8|&c_~hoZj%&oz1Xsiw zM&lB2Nznl=a{h6)FMJejy*PvBh_5rlhUu8OvIpn;yPePA4I**x`yx!5znryfw4wQb zXVAy}%W=V43qI*s8~f{H14SLRY{?c+*gtRyoS$%;GgtM8y`QtFI;)Hm_M|WXXYezG z-sT}i7nD72h>Ii>H?puLj2{JS@EX|j7e4*YP7`=RZFPZG1}+DB>X^Bu`6d72jP1n0t<8Ot%T+NITH2*vUakwsKvjRc2hIBan?*cERxP z*L!jOu}Yk=*#$k^!!dMVBDL6f7c^;`BwQcsY|M)>r*h=<2(PzCDzOH49cV zV_7|?r}y^K%on%m?NXj47}deK-A6d-i54tzh%D)EDrDn}ZF%`wE*P#LbhXt?pexgw zwcQ&6`k!Pa^{2F`V7(JO^by|OV;}LuesyBssS^SZb+%~dM_JfhbsN>Iiio}Z%m&w2 zg6xHV;}+*OMx2x-0VXt3ohYtSj89pe}CftChMg6 zQ_smPB$55vla1q}qG->-VX(&i0lTqh6MK1HlT|w@z&blkFbm0Go!Wkso)HWI!{^h= zf0yW9%ycr*jw3Bj2MoIfZoii=9qQUjGxvVu2KwuQ{NHG}9D9n&o#Vkx_69zB5e(Yj zW0_@Z8ET%^WHohufZKk;iBp$I?$K}3tZL^qrl*reOd#7fauAiA0J?X+fPyum!1r1b zd|PP?-#<%elb;wZckO^f?zXVDFrCJ4KMl^!dq`u{Ah75+7iXRFgP(twLR6Ruj=Q^& z6z|o-sfyhcUnnreHE*${=_jGxwvdLLl#xvBIK(bLF@ptt*KpU4qZCvTj^C6rLFZ}< zl&rYK%^s@=F`-L2!;U2o^lB~{tk6c68=6d%_ydgFKG5n3?qqq?fqpIf3#Z>3Nlu(g zWG1z*X!^XrWY<{F-h6HnUHE%|nJpGP6?c=__&MreD7^q4FXmA$#DUtXteH=A9CWSO zK+V3foQ14E8LrZ$qc4rI=lxk2mt$qoBOk572gY~B}Latzr159&1MV=HM~ zpGgTBL!4Ubv#FnPIe$3EnPyD!W0|U15WY+sBAQYucUubn=Rb(vC(GjZJ86&*J(pRP zxY45uj+r+-;9k#p$=sXg(PpV`4Az)T)wTcOyOOiQtV5V5myD)inQ^#UDVCcpJSzns zRfHYXQOut`3*tHw*}Q(~WcTS7?AI@66GvG?%wZ*NV`&UEEs_TR@N(RN&oR|fmNErC z;h-F0K6~a2I0V>`@z!vdI!<7@HF{yh+D#;xJdRejj-**baxk{*3LdphLL-qq%FK|a zei|0A!M6sY)x4nAcp!uf|0B~(m*!S@Vb01~HX{lVq z1NT?qh7J0l$=?(Y=Bsi19vK?rD`a1Ne5l9S8$0*7vago0IK-_V=*PZcvUdj4{`0?L`TD*i{0 zZ(W7XqC$4xYB1=u?gPhv$8h)f0xnrw4|;>tKt6mpDJCjX^qIl5LfkyAI_g&$@|$I0gog<7;(fFlsFHO zi~L<&KE;!QQtmMED_6LlC(KNR9B=-RKP<_|9tL=1vX{>WNtRmvVjd%2iN>FgVOJN< zM|*iia=jacNf(at8~RzHuJtPxBkWIG_y1GLw$LwOzCROgV;uK5R}nAV_{=_S z%ptAO^RHDTy~7~c^=My|fNdv#b2BT&%zua~{dG(bx=K6IGx-ebx^{)E$1kNrX@_B- z|9kOnnNF^(%>j+W%URu?>zH&Un(SSKozvgT{Nj~!K>Ah%<`24o$8Ytch4+48Slo5) z*OHUMS+j~a3M~Phu|WODje(qX&)}j=DufCwez8sSXVHD`!rwRXF%N>OW0HQ5b*I3i~qYignUna#8^=a*HC|fJQDkX zZHp3mk4(Vcwzt@yCi9=Fj%?BQdD+cu`I{L3yzfCfXvx$ ztjlgINq2<7pbQxhoy``het(Dy&JAZ$iZY=6VH<91mdE+M*Rd9Ja!mFWBu2M zG+QGBdUyWdj3=t%SF=9+apWcV3OkFq-~g!Y$$(|OrqEV!2h&bP;;X^t?Bowq(!N%V zrB@#?m-|}OAf*ERz1+lYA3tLEhA?@Xg$LDSS>r{wy&Y(i`7_wm6wUQJ5e>3!t6+H@2WvuJ^D+y|*kDBk zdKWQ+->}mbzeQ@ZcOLoTA9v3|(C$WYc37d1?evEd-%*^l+ZebJBf~d@ZJ`=9RUEJ> z39qhw4AX1;S$dM-gp^XD180TYXZR;N+cutX(NpHr?f8RS5n>k7F_>zz*pC2 z+(6sMY*TPNXCm}O_HP_536?1)qZ3*1TuFb8{Qj@r$u9hw1CZWnn6-j;S zb;=7~$qu#MLN6&rifNFd@%c-jd-OkW+xLJ@w>yAi%L3jcJb^B%oZ}uYI{+c&W8v$! z@mOT8P0Q?x`MVR`DBW{A9jk7^WAs#rSLECZ)QI@?_9{HlL1AaFGY=gN@Ox!X%jYOFxqrpH>y8jI8PZ>})WeN@R$PGg zmp4(}!hmwGX*lVYTTxD~s9gTbL-0D+tPM(upsc%vxbpB3d#g$q#*ItW!c3N?%Nxyil=wYz> z;(cywF~YU_Yp8o-BzA7?N3H)F;KB8Moan5;3VeE)UaERHC4Y&6dt)M*!R#{jap!5+ zxkZ{&yQGKOKh{9M&^&gQ3&M|&)-zNT9H$TdvIg-l+_dp4d%rIg^9N+GpqmrXNZ*pa zkM4j|lck-`wAhpQc`0*c3*dg&b=Ev9fm2+4ovknG#lwM~uyoW^xVbltzKjw$t|=Fo z)~4AU$qVPhYGujwzgA!y{FA#jDhUq+E5gnL$5}wsNJ^4DMEOsZNOs6ZY}lW|CZCq3 z5dY;^5z)eGa*y(6CXLMLbO1`1NP+AWb67I-4gYD9Joi>=Gn*g3hJGlyv*lM3*iGMq zOi$|wtM`?~n7q{(a{eCm%K7m2X?nOuwiXJ~jxpQZGWN613WDxhORmmn0n5LqQ7mzT z%g*y)W7QoR(|rl1sKr9?GGF-f?FN0*OovfFwuu{Wr?KZV4|9bluX9J!vRU|xB)(@& zIp6)hof~U#7c0iS2cw__(drA zewj3$o&;0PemHHgG}->WfrGrNc%8NrxI5Sp8^1hZJEJUNpWp%irEdkv^=dw3nZ3n(4Wr=Jr*qsp`S;vwo+FZtqzHfEHC$|m zJ{bcgHCsiJ@9O;}A#Ww@T}S{sDmMwVC&#kl$wl0WTsbIdx2E?@MWFA#XZr0a{Lc<= zagpq43^jej4cu}7wO9V*)VHL;sr4uDhcJ7Muv<(o=RKn?!+QMXc!xg4UuExy#luoJ zcbKuYRTQ4F5O;nT5bPvmCgYjM8N!4TB$YiLa*MarM94`+OIyf9?coiasRk z8$}ugom}gN$@EYCEt8(;!n^#7q0nIAEYCpZk^3%(TZ<;uHtM^@d*jMn7x5Zp#y)JXXl;LK}I%cHtcmkk6@merESf@^P(UGjy)jq|uRiEa$*+uH@lS z_B_H08{rtQ<~$* zgVO`)w^Is4$M$!cGFKlIYHr|y$}4Qqbsenjd(FCRgxyxc8Iq~LNMANyL*qTt^z~I8 zSGM^yzf$H8R^)%<^83bP#rgo~*U*T|&$e*A((<73u$70Ohw;>B6L`Ddi&EqI(OG+C z3hH5Wq*a0^=B;MKuTB!!H*2ugelpw|AIFY<^oB~OqwK=8elWbt3}=6^Cyk>1I8FT@ zZ{sl>Z@rtu$5x8)@Cs|nx)%?tt!voR&7(o#V<~qau9s=AF-F6ULs4YsO@wncadZoZqesPVxkH5yY?bCxq<0R@D TKMnKVrLpfT9>Biq6D9u#IKT_t literal 0 HcmV?d00001 diff --git a/examples/water/data/data_1/type.raw b/examples/water/data/data_1/type.raw new file mode 100644 index 0000000000..97e8fdfcf8 --- /dev/null +++ b/examples/water/data/data_1/type.raw @@ -0,0 +1,192 @@ +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 diff --git a/examples/water/data/data_1/type_map.raw b/examples/water/data/data_1/type_map.raw new file mode 100644 index 0000000000..e900768b1d --- /dev/null +++ b/examples/water/data/data_1/type_map.raw @@ -0,0 +1,2 @@ +O +H diff --git a/examples/water/data/set.003/box.npy b/examples/water/data/data_2/set.000/box.npy similarity index 78% rename from examples/water/data/set.003/box.npy rename to examples/water/data/data_2/set.000/box.npy index 276172016ae9c5f48b3799b2f263abb5e10c1f36..6ad2de625b40040a2d13248dd8b197a0f885bdc0 100644 GIT binary patch delta 80 pcmaDLb3mMPvR|lgKqMnW*+fngD+>c11xrmGg<1tt!A5saZUD5n4$}Yt delta 37 tcmX>g{y>IvvR|lgKqMoB+eA(iE<*zY9R*8G9fjJB<(}M|1sE?d0RYOk3PJz? diff --git a/examples/water/data/data_2/set.000/coord.npy b/examples/water/data/data_2/set.000/coord.npy new file mode 100644 index 0000000000000000000000000000000000000000..b50cf2b802a65557b1ed00b7fabe38c95636f7f6 GIT binary patch literal 184448 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
    1. 7NR@r_S^? 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 literal 0 HcmV?d00001 diff --git a/examples/water/data/data_2/set.000/energy.npy b/examples/water/data/data_2/set.000/energy.npy new file mode 100644 index 0000000000000000000000000000000000000000..52287bab346e53b61a990409d828a0bafdf86aea GIT binary patch literal 448 zcmbV{F-t;G7>0FFByegdqTnLIDY#iggk{hmGz3b44S^CDy&@4Q_eKP2NYNHVduB~~@DmRb_J zCQ=#e$TAN1GFH+Y_8Z25ZPMFmBWp6x1QzsJT`Oq+|BQHgO4j>I`oEMc;~|)XQz+60 z$b0hrL&^0|CC9j{GFRwZ%oEH5yv@Ey*67@jZvN*cT^(QHeHU{D{{vhU6jA^H literal 0 HcmV?d00001 diff --git a/examples/water/data/data_2/set.000/force.npy b/examples/water/data/data_2/set.000/force.npy new file mode 100644 index 0000000000000000000000000000000000000000..f1ad439e4542c346307acaf13fe96da7f7784000 GIT binary patch literal 184448 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≪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%0A#Q@mkkizN`27U-(50`$kYVrH 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�(Y@f_>L0XCV;4>T=`M_(*(4S# zCP3l%8^V9R3aI&IPqNF^2X*s<^flED6JOsDI>zeov<4fljc0yW_0s9l+y2l?94Yh- zIYBJ>Ds+Z5LZ`6;esVQoU)7b=+rXR8AD=J2m>x|Z!*rB|pZ8*MsTm=`C_Q1%}&$9eEP0-CmnyLKM zfIqpr#W6pF zt+;kn0ffF(<^G*?uuHWiKU~y~@2_})d$X3{hkP%r$sQo(w55v{e*eUuu3`95@=K08 zmrkdZb;zs2xXdqiJS8kN3XMizob%4O+|6O05ZKZPIk}TDLg_MO`FG*J z6T0)~h(*|K%~ks9ZvgG@h}8CJ80)V*0Yk63;VQ?|Sli8ndV5q-cVji~|65 z%cXR?gC+Sch=wCgI-u$QQSmM0p5PeQm3$XwqV4!jxKLpt7ToI#aCR!r4vbZJo!BTG z?hr|zwFh$D)3L%m(;2wJd@(wQbjC+K0H>}hhk@!3$X5DJ`rbVXQ*&~0)5eQ@=7gv4 b&MKUje>noCsq0~*vKHCg%qvrw*9-m+vO>aZ literal 0 HcmV?d00001 diff --git a/examples/water/data/data_0/type.raw b/examples/water/data/data_0/type.raw new file mode 100644 index 0000000000..97e8fdfcf8 --- /dev/null +++ b/examples/water/data/data_0/type.raw @@ -0,0 +1,192 @@ +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 diff --git a/examples/water/data/data_0/type_map.raw b/examples/water/data/data_0/type_map.raw new file mode 100644 index 0000000000..e900768b1d --- /dev/null +++ b/examples/water/data/data_0/type_map.raw @@ -0,0 +1,2 @@ +O +H diff --git a/examples/water/data/set.001/box.npy b/examples/water/data/data_1/set.000/box.npy similarity index 78% rename from examples/water/data/set.001/box.npy rename to examples/water/data/data_1/set.000/box.npy index 276172016ae9c5f48b3799b2f263abb5e10c1f36..6ad2de625b40040a2d13248dd8b197a0f885bdc0 100644 GIT binary patch delta 80 pcmaDLb3mMPvR|lgKqMnW*+fngD+>c11xrmGg<1tt!A5saZUD5n4$}Yt delta 37 tcmX>g{y>IvvR|lgKqMoB+eA(iE<*zY9R*8G9fjJB<(}M|1sE?d0RYOk3PJz? diff --git a/examples/water/data/data_1/set.000/coord.npy b/examples/water/data/data_1/set.000/coord.npy new file mode 100644 index 0000000000000000000000000000000000000000..49042a04a25ad5af6229df72acfcaed133a6b6ea GIT binary patch literal 184448 zcmbT7_di$v`^W9Q$=)*~DSR%D`zEIxEoq{%yqJ` zF|?SwEHNo@#?ts@iL>YY@A{+}i&xGOTwghV#_~CW|D(s*+ZZ~#x>(v6t~dPu{bUZV z8o(MaVXX5zfJ)!*Xp}#J1h>(Y9HT)Kw4X8R0S;v95l?Gwk0oQhNmy#O5f>fJ$*_Jp zhBCF;#ntPn&uJ{(W#1xpAO*+Q-@)iWXD+=ql>Qvr4>{f{IzDg-7902|8Kp}u`=#j9 zG7i<*%?xi)nO0m@rD^^7h%IqMfV~8rDU+akh8C=alM_ztjHD%Vq$t*A8hmO!n4Zqb z+~?2#@t(@^OI#+aFt)r)nESmaZNm+eLNS47BN#FQS&tMY{o29R@? zH}^;72&%e8nO@0nyl9(1@?!VkT8u4C))S)PT0M*;ufueSeD=#mO^SP&fSPSmB%R_- z)oc2peMpr`PcSrg>@>`L7fDBZIM{krVZz-;EVD3#nCWEFPZy?^OV`kKO%kvBo1rsZ zo@x`zxxmT4@H^g}lRRLF{=EAzp81+_NYSTJ2~O18^#rY=+VtQ2CQ#x+4O#Vl^nqOKSFk#{8*zpaM3h>m1L zZj`58TSaI>fGlTxOPur-oVjU60~pdbg5yO$k}~rn?GyLdUr9Id?wU0H$CGAzwrP-a zn;b2Viso*qY@mtR-_g_c7BLHNFpV1v*c}ljFjcvLVOv$Y*=dGXYKzIKA%$kDN|WE` zO4xOMW)DxvMXp~F7t(FQ9Gu`mLVqQgq!Yp9eQXy7K5U_{nmk-J+|Bb+;L+&bv+RB9gyrg3Y?hlvFMO7O%h$j`v8^zD{RSfj#x%6Q z25XqHOeiy%d6c@J={o$DDHAuK!M&o?;d_fIe7Fx(ElLU&l{nDsObNeaXos~N#OJw^ z*rX_W|K5Yn+*yQmFZM#`-59#@DieN&6X?EC2AzMwP`T|tNPH=T+R+>EFqP-lyHBU( z{^fY@pG?6LmvKSkIsO~1Nj|HFaIuPyEFV>5i71lp0U2_S%%c+llF09nBvHLD=*WN9 zJZx`|wZ>6&wN8}Gj%>qX_l1msraEOzILRs{NZ`P)ZHW2!p8sBTAB0}$Qw#3!Ry~O( zjhW+VjqMQ9);rR4jZ%Krw@}(3r^z*RUO-=L7Oy_gnpb$zi!yfApm>f4+4+i*|B11X ze>V}MVk6j*S{3R(>W{RYf3QO}kQ9H2P^6R=z0}ZWH?;Xfad8|CrB~uY^I;6kJcVq} z7QuT=x0p$<>crGH zg$y-~riBLeP@0hoSD6>w-qRUS`6fbiQJ#eL9RbUyYWDc|wb z7}LRexI6{jQl@)C0ld=B`t<3&Bwb|s za`ftn9caZ`5;>htxdEzl=J`$teYE4YEy%>Wg`2p))_Kg-0vDPtcb?H2J&lgetAO&| zJlgOg1|HKR`Mpa@*(vY(*nq=du{>`lt82R-t+w8@=ju6_9Co9tG5ORpI*S}W?&Zdm zheFL(m_m4kwB9<37FfvwkCnO$R@A-Z`g z{a!W>$98GpSAQyMCBHy4(T*1WXo1S28b(jal(AAypy-LUOh~ykrPe*b>1VafGwmwO zYY`^Sc@IXu>Cx0!Av}LSV{GUgBTiApb1xN_%BuG;P|B&%1qUy;ZM_XKirim(vs&K=iF|NepAah z^lrkE-AkBvBexJo#w4~J%rpOk%<<+Rno%r8CF`_^yr=Okm&DLx(L~N*(|L5+O<_Lf z@%RpkF*LAtFGd3G$(jEfxA$IR8kLGLwDAW&4eHdi*$N@Y6v^F~p_W7cA!xfK?H)au z?%JCO?iEhyZ5{BD*oNpIHxXW_31#{5wC?0z4Bu#jo{SSFkG+FMThu5>^B_0tfEZob zZ%$=TByiaEDqeIJFskRY=+b-_df)X^aAq1&&rl8Ko$kQ7AEs0is7=xP#?T^(0iM*a z%V=AqM0WN2Sgje|Onb~c3gkY(-TyJ~Nu(ydpiPj<+mHK(y!L_@r9TDRjOHXpx4|Jxo^-1!*i<1yI(Ar{F6zzU9<;0^ zg$7{?zWg1rKUE-^$|JXL!SLN*i;7tqbTcmj@)`4}*mxbK#K_akma91Yppn(PRfaR` z)3{qV>zLH-M9GGwMai6}YC!_}qK`DvM$0j@!s*yc(f6 z%AQQlamZU|O$WXflkxL4q`hAIeaPg@_ta!d#0JM>AWLX;9)S{cc8reypilD;S!kk(|w=z9x6s7&evoP*jGir7Svtzn_Xhq~6bcU>>>OU8- zr{X&1YARByt_;vnGLiP7jycoj$?ZC$&6m_N%!NlZ{Tuan(qMw2D&_B)6gS8M94K7s1@QSkk74Nz;O zitfVw=>^yjU`PgL&QvOr#|W9WGGpAU@G4Z5E|-<^C+?d}COjFGB{m?f=n3wpLyLCPeE~-l8eL|9om;YiHbW72x7k1pUeS9eTtcA+cYeW)xtCEKQ^=dYZD#Y*0#^ikl|ZvZnF3YE zKyk|)>XBYR3w=fDjr$!~T@B;a#S8km@&<0jEL*IYXhD8{8Ze{<^wd8Dp>G${cYzj> zd;6F7WfL$rS#mJxypmW=QFmgve%t9%)qO(evi1bZ^{oF67~MP`(%? zvun_&REO(D5#*&KM54E)D1VPE$sSoi1;?^5_K^p*wCqETf+kLDg&?kcB7Ilg$XEv) zVp+#@3~XwL*-agaZ)k$1*$HNT-$Z6osW4+3z7$h>`Z3$wki_?HU`{P6K$81QWE!@? z@c9_JX!aiYUx%5|6(*!KD~#U8kD+?GeKdG;ozw%G8JS|&n$nj597y~CTN132Dzk!gRgPs<+UvT<957{j)5OtS9c zAF?k%b&M(Pdhn5P`Z|q{y$_<-C;ISS@cwttwqxsj1L*j_@BCu}PZ)!UHs5=o>L3t4>i0`r&|0-%L=uRGFQhZ%M8`+fnsSj;a?7LU`OCOXt_W#R1)SsNQ)S&O7hmS5G%Sei7lG^gEGChz_f{ zGKY6k@do^|BA{%pM^BT?Xw|?~?7VJ6(qpQ?=Z>JS+nRcM5TI>15K7<55-pG-gCuiZ-Q+)65kuyksH4dyD#r8QpT+ut*wRHyJ=s z_%rxD_GZ?to6W1b69X&BdKBj=5t8LldODFlw#*~1Fa@&BKZmFXqRi-J-O#+alI!zO z!cey<#XoIf4ED~WwhJ5ay>~g~FSLUHfFCbBAe!ge{FMEhAwf@uHnYyQ=dt3YIgQeI zjUItEXo=WJ>Y6iY$eQCGF)NT$C`CSDnKV}Q78;v^Xl=z8d{X!ec8WTUa7pA)n}_>j zCy~gF8t5izVX#gIKjuvod;?dRnx^~wORnp%ediNIt6NcO5DUo;75vmvW)v`il%2yN zw&o9tA4}1EmwCMYu8m+PyhO;n^LP`kPO|x;lqAsKo%0 zmW4d2{yc&QF|(Mq?T&QqqZ-9Nw#L|;*|fn=FjF1Aj^A@W^S^B`K*G0)C^Hu^bYCMK85|@m1zPRSD@Z79hy-_r0)G6?71u0Q+Eb2 zM*SFLdJ4zCU(PBWI9emlG->{wdA8h(3RjOpD9Ih)_pZnN1LG;~Pzlfc!ftj0%AnZVhFo!N zvUWI(=65;FlL~+OJaZ|dyJ;&%b&TNpz!3Hn3*qsMZJ?KOv@H8DD$A_s`4S6CynKQw z^&dmMkxR)b+m3dY24dyeqxdMHN}jf>(e&^m|A<}=iEW!ebL1Yud;eCMwUggF`I6d@e!LV`K5EK%gf_`*C8?D_H$xbs(?=AHF*C|CS$tSC1)a9xr9w z;>wvnU4E1jDoh5et;jdehOJo}LWiw`xTwBb_%|mrXKgZ=JJx~ZTU>+}dd{>aWdtGK zCQvn7jve|3oArm)>B{P8_yo#Q-o7bR_p2A*1T%3`?L?Yqo{31kXsS0mgfBnp(38}H zgNZUwJ2#Q)9*L7^N;~HIIl$@D1^lScpx(yATut8~t}GYkhQk^P7 z>`CnJQ*w zLan@(Szuv6(r$ZDUAqPH?jo1oKUt5K8CtadxCo`JmFB+B_=1Js^|+lOkD&Nh3I#KK zX=e~a1zqRZXPQ?ad|r{px?kjf2~Z=aIm(pG3*gi*ucvzk-x0lL0NO4;m=nIH>_QC% z%pP?Q&!VNNPRkviLg!P`&>EU|Sb}cnpGDD2VNPm&A(pi7;B2~=FmeX&MEkNC1xG)6 z*t#7KA{)u+vJ}vv$n+1o(Wr@!JzJia{q zw9lcGzElTY>Z2i_T#Orkf8x(vBjTqOV$ZSXy!jWR8Jc>Od99_3B3lD0CrPUIeax&> zDuhUg5+!t%;NHt|G{e!12EC+lvDKLzcg-Us#*LO0uZI7EdMMA*CXpvQVc;4-%M5bJ zGi(Z3Ird@du1c7AT!hhlNly1|4E1JSz+=-D)OYwG9(vu!C4D(6kN6H=avScPeZ_2P z)2D>r(sV{>J8f4L#pIwtY`-K$Zu>ts`&c>R^v5_l_C}o2uWZE{@5zkZI~`KmFwB;Q z*?Bbi(iF0}C^@@Cy* zlJ-jRw*2%Xp2|UV^mviS1aVT@J|5j>;h3ya&>VGBiVm&tL7bT|Y3+`r<2iruX1yjY z(=cXdQrpGm)msp zK9WE5vMW@i(ADt{vn$48`%fiu`)x$~N1np}p9VReVo_edALc%SS#IWN8o%0&_63~a zcL@ntguglY9k-{DuqZl`ki+ySUBi=^9gK7D7?M>!3B_d_aOKt~?#t0!45=!R^?EsK zRoKfu@BaYfBidYX{55E_xZ(qU3a!6qPf`raT9~y%X0axD_gvsjk#V~qWoe?1qa-DQW(Zt|~(-h|ehTK-Fc zZu$1pmkwRs1Cf@oRInwFDu1Wbut6nP=ra=!9{s_8OL8gjo}jNDV<={QB|L5#Q2xg! zkm%n;d%jM>JjGEoiOs}}tcQ$sr3mtMC(%1cRm|8ajOC5nu=Sx3ojqhnTfSDK%6JX4 z*zgN+$VFa{I9cx5ijB)n>C`Dx;%^A1tD!D5cE@^B zuy&#yiT*h6a2!(II#hMo3;!;-km3C_YH^rC{TBU@ShWmpHplV&z6Y1q>P;1o&f`e( za@y#36Pus$ks~KZw6Vra?j4LCk9jy}78N2p9Evubi4 zUZv4w5S4dtQ2m9s@Oi$3H3HPfwoyC6&p`&>CO_yf;P~pDFD_}EU!0keBVXW#P z&)!9kVn))Dzqbeh(?4?oju|lcXGYE+WN6`S6K;ea!ZApRGoCwu{MbKCc}O@7*Lcy+ zN>z^3FW^YFDv7<^#jgIRN35nEMH9=Mn*SSRp zt?Eitf4v;)I^}pB6G7jOJwV?PZPNU82a|%=QbDI9awZy5?aWQk(sskNWjq`eu+5Fz z1?+#W1e6z^!^5^8=>BI+^7VVcB>dyAKN3N_tZ-)VN(h$z)u)n0BBT~^hpCRr#rxGl zbmjJ01jL!pH9?PBkb07FTB}dJHZ$n>GgC4T4#EA&+c15z3OSXApnmFX_E}#drSNp< z?$usA`Y{bV%&((K@jrIif>?@?titccB#Kb4$NfcZ$QDtjH>cI;k6|6&3JD{pQjKgD ztCO{@Gc5Nh;Fp^zEhv770kv3G>rX6t0*I3ArAf?fKHM|4FmQ4{R~dhhKW+XlW=G^% ztiEyEv*p4W3^t6Vr@~r{kdgzUYKWc|zrdDKArenzo3m$l(SNCC+%lKVsOV2-f@)fs z;5>i&z9$LO1q^=O{l8E;_lQ}r#}uLZT5Pbn1C^aE$IG$uw6)2HRtX&k99#*4=g|4^ z7?yhb62H41r>)bFedIbk&jF008%=ZjiIFpHm>$)H?`4mCkD0DM8;p%iCIop}ub&s1r3(ouwbzJp#ZV|o#0PU~q4PwCASCU|i>45}1p z?w%v;`D3%_`#dYurJTj$xqq3MFQX}Y@lNb3-;NsbAufCCCX{YfrL+uDI=jSbFK(r4QD63E)_j5l8Py2W#|yK$wv8#I_4YS5 zPHshj_&r`;`iSSiktKM2wGEGTMM%#^214r+Xlwdvy7W<$YWAN2WzA(>ejbC(jg_2J zoDi#;!lPwA?Mx&2(xnglbMQeg+$vk2U@jIb6s(Ke`Xix(ECXH+vAf(TeKi zg{bO_E@jAP(^f8vlvB&NMx8JWBr4M1J^%Ak_&9WU3eA-Jf{pp&bhPMmgeuf4!sCHI{sCX#V?$y`BG5ue?XFq4uOHN!$@F{%ALg`{z> zaj-;zBx)4s_;^7dbazB{oeFi>$6on zRiL3#h~(;n>DjYO;3qm!O`1O!^|uU5Tfzk1$04v=x4|;90S`vzW8rCgTHV}(!;ic1 zV$WeLH)SDuMZg~iF0=Df1by1~0vqzlgPA1$5wH5DVYj{s8E>?t8P3g^=&VV?ZHKY> z*GW_c+EDzU9c^j|qlLNR`1;=!s6=X0qd-#($Vb!l6H>@cYet2E7HpQeQm#)Oww}nu z^^JX8SZN8O1YXL%4jJObNN{O7PtcP&hqEzkK%;94GM|MIdVMHv&sR2i;bW*@9z`$f zBKYSy1=?pPL>Ufaxn$er^zX4K1*%;|mcUyya?j(}e9K2UzY8z=g-NsOKc>=V86CCV zK;Ly_NNHq0$~9)PH;eL7IT*)X+0owkNKv2(b|~NqKakED?SQcDYV!Z|p1CWb&zvr6 z=0Eel%UWbU0?zMe15Q4{Hc4k%|F$2uc-FLZUIq={%_h^m2e{THUeGTQqVH-&)Fse- z6B`1l`ouFl8T%FacLe_QlN`F^eij<_4y5UwjcFA<%(YDdeIhZQUIYeU?D%xv-HXl0 z?~(PkWu$W?1 zMhWKFOITzT%q|nnLh6ahl>cNDMbt0F!b)kJIpW0q)7RoXC|t{wi|@hGYzh9O)9nbo z>rDLAqaM}8DgyoxKubzLV(a98Xmk^06wL!^;NUdw>6IcZ7AEFroC<6oM9?9djriPT zOUVm9pu#nu+0qe@)t*7@KN~x`cPR_nY6^7e_C#uy6=($sFY?N?AbsINR3uHHf&zh` zo#lm-Z?3_hCLG2JwsdfbIQ^Q>N5B4MtW~PO4X+`Le$mJFD;twsm==loR58kvA7fIF zCC)^$X%|z1@m(w2jNfGp!Js>tKR8RdG#aq22J#dXN3%1%6ijR=oD+@t%2xll`82=Bv6UUab3w z*S`$NcIO)2%ccI1zS#oh)H{%iwj=q~AK~!bm^m%1Kw?WL&|U>KN|xRUo!gC=5&0Y& zYuDlXLV3=?ZyMz|3sFl(KhmZdL9;mxcirU}^-gap+_(puWERpg{cFf9>4sO)2;Mcz zkp9cl;9CmLt0xY0fBiVxBpw7SLI3X@(jy&}8cdq(z<#=ujtzt6G~M$x4pr6SP~v4~ zo`6x$bh*K({$0wOX(>c;wW?@eaSA2;pJ2vcXKGiqFfX;jXvNik2zVn!15tLo$YNLe z;jE6Jzx|B5pjT=l54-xkX;)M?cG&1qj-e)X{8fj@%uL7}jpE&`pGa|z2~ZXK4>ey& zFypo1!*WMz_8v#qpJ$`?t{kO0)?*q!9$^F3s9BT)zN#rH1=PT-X$TEx1$8IejD9(N zn4R%q|H)6F_?6n+vT7B?HSsYN@`h>YF`-e9?P;MKhv=lyl=rj-Me!3LcgT#iGVLhI zVh3;GW)WuXzRi$6J`DG5?R+oWNyKd9Gc)5JBRyt19Hmw1;?5$Z@nSHr;4X{35qRdI zLtXo|s5nBF`<13ZcFQiZmg7HToYr1=#ZICl^$a|Yh0(F8;W)T?3At--gL?OFX4j%6H1~iAS2#3) zP19yD4c9NC=&&v2tWcyQ-U9FY^JX$HnM9#CQ@JCDo?vT+z?+@(n33zdg0FXtsV2Px zC593-)%g$PtmCMoJ`6wYjA*v`ZbZMCh_h+uaGmc*Dt{EwHqW2G@$MRoPI`-o92p8# z??su75)PjK&MP#PXP-2wplqZCqYF&wO8IquS!60!K5jtdo_A=?i zr&4o2+PcVu^4IQ!Xj&<_fOagsl7YuL*3?)XMIr{W0yZ#+{Y_Kxpeqq2PP>_^$AR?C zumBC=Npzv66$%!EpgZre;FlD=_TG=Zf8?;*#EQbdSkd-HsZ^5`%G6A=rhQY7q4mXm zewSt`8k|Q{b=y5SoZcbm6YA)>WlY~4Wsveuk9n3YNA2_fV+vGTk*oXH|Bs z2)wpF&uzZG7Jtxl^Be93p2d*fb;jx2Vb{Tr{f`!O zX|NeK7tKkB%fo`h)3Kq#mK>+K(=7qBoqKm8eT|6xglLzIfX_6X!Z763Gqh$qL`aR3myo9yjnWlAnP~@No z>Ab$e-WK!}O&7ttD0E?Dx8H(M#uJR1}nqG3Vqhoi9WWCR)HZ$_{E zLi&9%1FO4T7`u`yjE>AV*6rChd=63cP`q#lb2g8sqk0OIRbomf{$!GStp_E`#B=$! zUvcD#8igh;pr~=T@L18Fb}xB`=QCw!!Ycu@X=izs&F?#&lvD!S8 zme`nJ`YI_#sCg5fKY9RvL3ZP@W2oKdO`st!8%EOK z*TS^H?lmIo#F6*a7iIie&GX|09A2>&X(O}f^20ayUEPKMzDZM-z{6HKQ;YZs@l0@( z6J4%#A^+z(=y@v0*yXEHSN%Tl8AH$gNePe)bQH|zKak{n47sP?G6S=}vb`2I%$!&~ zR!C?B^%BF(#i_-39x{xo3AqffelPRt-gH{2_8(fVi_uuUbY`t1$ZzK(#Z)Lp zJbjX%INldtYIl*NtwzmG&CH%vk!bU70sHM9HP3m@h*rf$HEt|ING$52A1T{^8Uj zVX}JpkC)-;Okbx1t#3{+c?k?6l6_Rr`Q%H`nXk@TO`PqmlHPv%iRA3p`>r&h*0wo-l$X}R`bphuqm{rtlJZ`vVN+205A3sxcA&4AvW4#e%v z_7s0Ljw%YINXxkwKFxi6eL+TLh3{g{b9W-NpW2YsEo&_8jG#&dM=1PQOcH{u%7cnf zX0zQ4ikqmwO}ipQgPLW$N9J|tQyfEoHKiz#uSc?n^J%u6AAJp4!%gbBg|t#>s%}2U z^xfq{d6PYfKly>z*OaL#{2ypm3{5JGK$)ZoS-#tcz$-3-Y)Lh$r+blW{y(N4EgsPu zXF|*1F8+4vkW}9QvRkB)QM`!>62HT*kZ53bjpwjZTa(V;@nn2s)3Knh6>o=zaAd@Z zCdGfp$_8<~oh45>b`dmVsWJU!OL3oeVEwFz7~i!QL5XANFh7K%R?1Lw zuS3w`H%zv+53McA24|H@JJXx6dq9Xr37BAUunuiGwGTF~eN3k3Xj(3AN>e_pBhQ=| zW}&$q3BSIN%eO8!TTS1C#&tHdDZLlD{TtDK(-gbMo727Z^~@P-Z)PM_mQK!k&0KT7 z0k!qAwAk$*Q`A0<)-Cm-I;($}E6BkZh0WmwwY$;X_Bg0lykmArZo`Mv=~%Pck5;?A z#?_0WxaJ0pNDuOjRskyV@ddq}1 z?<<1HdVhQrWM)lOPe4+TqgA?J0WtYEnE&Gq_&TRCrCA(BHpf}9g`T7so5lJCn80An zQ7E|u;OZSMa*cMRrcdP)A!h-4k>Dmb>dtC zA4Bw^Ko@&VqRzbW8CST|{VR&$o2WjQPs#;*Pp=M* zf3S(p94CtP_Tq#e-@y(+EjRnkq%|g&VV}gKIa7qGb&C=mvwekxBXcPBr30RQHlX!c z2e4AGcVY3l2?N6u$m*vWHXT^V1Zj^!oK7p;UmMYb;$8M590M^GAS!7Qr(Yqc<(L4>7OIG z){%yt_8P=n5>4y6gh;LBC&o^7#>DaQn4l}hRMZ5J$=Wj1&z(mNo7<5%y$|m8DuVf4 zz?@RcFnfn9vuL{u$=$alv&HuKrX$GihiK4Xb0az@dGTLNi^5fJ7y2&X6ARlb@zUiz z)6Ge7#$g4`#hYZy|qng+0dO zaWhEP`#yI58BcmyW9esc4q~sWQ1RB&*wLJg_MvPT2)xT@z9w{~wG}0sTM^ND2Y$b= zBe5b1o#yLVeu+KtE*g_@X(^+UdI>$2f?UU-JbhQ0NF@dhST0~gr^?Ua{sS-6UsMxh zTLi52Oe6_H$;`HE*(lF{gWPwccr$!{^7mCFk%*=U^#>LpSYDMBw`_+>;z~%5m*lK? zX;`9cNVEKuX}735SExFQr1yGrdA1@nxVloni-YL$^Da{qeznvABdXgwVHI}mkWMit=uNA5(Su@XGE@MmRNW8lc(brcjPf1_~Vz0n+vL${_cOwl?G+5 z+UgxzWDWSz*DfO|)`_6N6uxL7$86^?G4wminN7@+G(nDMk{xAT z{SE&#QJNAUCfFAVqq4zqkl1fWjsh>p<1N7=b0742d2~`cm-(o9+w+2Z4(w+O@UWt5F6j*6mQRR-(OjTHuLH!Sk@EIB>iJF~S;DQ!hjx6SEj| zBSA)?d@il;HzxOSTjBKNEZQ1HNSJp3a-}NVsjMV2%~q%AocHL-ngji!a!fu|#xLB$ z(DcxJ#K)&otzId-a{IAtp%{G`R--A(m!P%o0&^_Hf>x;-QEHhdDo?#*)>~< ztaGcFQM-d_=kAwC6A~elrgYDRZa!o?B4DjAr0~I90?)l?;Cyiy4K6&2|7vxpR85** zq{w6Vc_0*g&+_}&v9wuGCwoi!5Rej0zkdpPxttxHl6Rsik2<*ZI8xV#^SJtXHIkEB zvGVc`EDE)uu%F-2)LaY2u#2?_SWDLW}$v7UL1;s*b)QU ze$AC;2z;jDFjLYya2U6Bx8k?10iD@AhIY(Z$wc?fWIFEcN7ZFv+9jO9$0LxI`zI#i zvcUh^BFi=vI!pL{M|C2sswWljc4-+I%RMCYi;EYwo0KXCo`B$vyJJW<2Ag>+0EokwgUgKCt12kkbm+P{3kDqoRb#hDXr-# zr8bTUOE`q5DJPnre5}GjuTj*0XAcvW5<-df6R2G16+WGmqu)o2*y+sygd9s|{m=

4Cg%lYErG7|_riO8KX;vZIH+b64F>m8P@K;(--_>&E zU2Z&DgWNPP`#Kw4Vg8K3QyD%0FLaQVn~60o2C{HsF7R%3-~IZju4@VWh7RYU5GV6t z3;Zcq=azl{;MAW2>if zt|4#@$!O)lPPp<5&JDT#$-3r)!Cuw;{y2j{%-Vh^Am59{fqu=liv~ecdE(nTGAyDY ztl4_6earEFbChvY_oP6h7WCAS#t0eLQcBDBtyhDvChfXvo_sb<(2G-9Bzpt6a#**0%X{INP zU}zlEu_qP$jK=>pABwa3lc`fIXRy&d1)?ar@l0tnc%Hd&*>T|Cf*drC%??hglwiuaK35%Nc_Is*9=@7jG?FIQWA&7_!&GJ^i z=RlW9`5T6>@olB*XlLaG=cuET`15q+pvOx0cj_)H{Ru}bOMOJesq?5t)P7=qIH#3V z3B3ra1AS}vFI-q;6cqo$1ph{XYrlT-e^RFvK>zl#sN^V@{gfWi7Yq?kbV(l25c9fA zNDE!q)OVAu4o4lW)>|D0M_A4s@91>dC0y1zBev42mm%~He78ibc-G!H!u>bS^bdwm zt?^x013`5z_`|5pdf;te2i4xD6W=7Y8C$l|w2=rc$X9G0|X&bOXV` zk-^&;X6+{gOKYbD)*xT=yugG*yZHh2UkUS4Dp{CbCp2?vwpk~SY zOlRJhM?^70ZK4|-WLcr_60dDK>yFWYO6$V8lz13SBE;GS>~1T@?yWvw4+4Cos#e0! zM(;#bL(?9A$MB9jPAE5hwkTZu*aR))OJglH728a z(UfC?U4oT7$APWRi6PHjUW4Tkl{bG4_nH&Ew>Dp-;BV$tHU@@r&e{3iJ=yS8q0F>? z9^>|(+D9sbRDy+!-)-9GsvAv}9Tn>3+8bIH5sQ6PxDCcEIG(;lm+Zz8{IxML*9c$s zGR*sZ@`j-h{46Heo1r@mp~LHKm!-s0z$=KBs-b;g$5V2~|XuuB1+2J`+p*ZYpV9fcJOvhogsm z87Ac#BjmUJ4ZffS-P5+lO*;5<(Zv}{mx#i#V!X>xU=@pD6o8);67CPploeIQMhpvO z2FEFB0Dt?kVF~`Z3ze2^*CcD>o0yC-m`Xfa2FB}3AhRbn4%n%I zo$B6AP^8xAQyl&R0I6eC(G%4o@K8?g>tfM~UH2NNIZ3U`!;NPRgEcx)z1TIRtkr6Z zPoA|exqL2>WFGNmeT~}l0hn9kLD71Y0gnx|9te@G-uHYhE?sSkD6UW+ihRrAY+i<| z@VTs_1pj|oZxa(JIG}Y=+rRC{=RYIBHR-dfY_I3DL8mqth_8GR(nnX{U8=EA2CUv$ z9Y-9w0H#*(ySq~RsHR(`cUl~&eFqTEV{8wFFo+WTcBX%k#d=Cu7|8Zc=z)FLKsVTL zP6r1}pEEpGX(WehYQqj`N;y(UHw7v{+lBb2orb>29QRou{KSaqFQa&^pR`OXX^a%D z*JRKTq=_;lO`3!YjwKGlkm8ZthWZdGa$ghVDpik`pLos+Il7?~rds&{&T)5sNOR8G zT{5mjga#0uJ)vC-c6YOpg0h~HN1U?iw?DBC8uEH?&8NG499UOlSw09$b^O#onFh4U znD)>MMlD$39_Wp`$?`)P(xZ%+G}RVqLaLZZGKDflR(by3A6F9*WmiHEO_rTB9&Q{1 z>dfua!%mjDyF~Kq+{aUT9^qdOQ&6m_C)%*Wgz86|+GY7{)Qr3yJ0!Fq%JRs4hwK5Ik>D!6G@8l(&kJ%Q%{*@|YrzeI1wiIoE z1FLQkyyuopMj(dEug9*UrzrP3kHy2?U?K&@)R0J&$e$|STpSD3hNnB;4*Dl_&D8iX z=t3{8O{Xl{%ZBHghSBM=X<9$7WT!yLnWE+rJ75WQMOgwUTvW)Im)>+LU9JIx$Mjy# zr$nOyLD2A#6sx8^7~8;sBx%yVaoqHH=u}gAJZ-(>fC0jr*2}JU~zFi%!Z(82lA{+@*abLpzZk9{xKyrw8)v0F7 zC+kt-g{Dv-{ey*RO$;1Mhp&dfnr$Aea9T@CEvK5ckKMN>{n|eck-`kxbEF`so;3GA z$GE+k=ntx*qdm2@Uj2EYd!Z70n+yt!z$3hs)hSV#jaz}F-1)dE)#{WfwCv1Lc-4qr zrVc#y%0J-^C*ouk#FyFnwX|TynXP!4e%wDj`nwIYac27@%99fZF(eLXtp)g{#9Qf# z+$iPcM8i9Ghr@5);`#Rhz)E5J=>Z$@stGS96HeoG-bb#r4VZkY?t%WWd4qb|gVy(FS3itSw;}=66{3B` z)J>@1Oq2n^WP-=kNI#MLsxBB30t)mz(4BH{awYrG-afD8SxL`MGck^-q#ziJ3`SAc zgp4QFH8NGL>ct7KGMq7}dJ4EvSi>D2_IAIvT#;Nm2s1XULSOIA9Q4UC%^_>LjIWG7 zOM#Ei!gCGL<-|rET8ihF8@*IoPjz9m2am13mC*;q4T{*Jzj5@4ou_DiKsGcuOI zsQy_f)&+v<}H*FJt~wd{KCZ$y>HvHotq zoO==!H{};%rXC(7D)Ba|n{`^{ObPd zr=A6i=hzqBb{iFY=CJ;BC3Iy;zDq$?O=LC)styuzj?`q&DAPg7CnxFEdgJ^}ym3a~ z#TE^Be#VW_T{3NW%(!-g0jzcHshP)v6jzL}Vbp z$jZ`)hoZ{8=~OESQC2H;(z#)E=eSqJ)eQnPe9=*8lmi1SKGfWwR8g&z28)XahCRQD z@3R6Enxd_K$a*X&pNnO@!#E1dhFTm2&Wj1jhM?0>%-AM(kJ(R#m}fP zx;M-LMYLYY<+^F$aAikh`Io_vgFedmrV~)b{5zJHCJECiUMMY=cBra{;2W2~JElB| zxwF<>4+8B}nlZzxz~f86R&A{{2ZSprhoLw4GTkxOU9Xt_yhGB174s+BQKy$(v=R?( z^U&yObX~lmgLLRAC5E`IL7i{jH*6~ODM0K~*|boOOA?_M5S78&Ta#ElckmLnp|zj` zCcas7&Jvlbq7b-&<|e<}m}Pz2BPPra6=Qb8CUBFizF6^I=y#GP>-8%Sa>oM2G!dXU zyRdTq-mhQ2$lvLf7?(uWE_xEZ!=xSHo;kwlZ#S6drmdbebVwi^GN$dirwpOe*oIHr zA*Kk5OV^WsYP|fB@hRG_4UVhNa4u{5QbB`B(GNH2?0IcKzpY$ZwEzX}C_wymFr7k3 zcyJakYgql%ZEEw&vZ5f9?55em)a~sT|8QLI`!s?}cNNd)5<;=*dl0gr?*{#fnC^fMAN5x6V#kv6AqEX{r&V4*AT&%sR;GG0cj?NMW;9`v!X>HbYuR#XcH3Cn?oRg|yUK3m>R}A%cJ2_mpkw#=t z4(rMm5fv08(0V+65cx+M`C!VskgUw5Ip+R|S{u|X5l4z9VTi5Q z(XrXb?`tpb7%fz3SzM&F>Jq+mui@j9#lHH?rbC~vmjRC6-Xo&op7ZJTm^9EYs|-*G ziLE1k-AS(T@EWSr4HHi4hMt^t&YVnB77a&(cG|A$H6__ghj7GFV}v(bL|+-TyRfrW zaXGk>cO&`((F0FVF^I7y#1?VWN5FnQanSvNOhD6_MOQeX(g@UlnV}1WP(c_xGyir|>-M1D^YqyX9I2O4Fnt$BW4mlHr#>(p2 z$nd|R=rt(6akB5$vHBtI&cc1Fu@6X@?b4Ah@2#tSZwB(GU~gF~5SPZ5iEq|%YIKWG zvS|Xg+p)$Mb08+finH)_A7bz%oWb1eU0f7|{*=3Iu!C{$4fA!Kbn^KfSD+62^B#%= zTiyCG^tFa(zJZbj-p-oz7`FwIsmBSN%V__Ky0ImKSPER9RlwKyb)XP+xY>8} z8G4P^*X^_Jk9>y1`WVm3NX$(=Ep2*vPrhYqr!u9p65-1_Ldh{)Xdsd;>^D|qZ)rN< zqYOw6$@YdKs84C?Sv{F`ZDQj)tNJ=kRNqlqQzmM0+Qu*>FAH%oj~z9Ud@nuEczRwa zNP(kjb}MKf-}Vp`be`1JM?!Yqe~kHwiGZLnv4)t;;AZ1OmPVu)@$Fq!DS+iV+%8MS zZ^9cjho=i*lbT(8Z$B!f(?w2s9$++w9uCuz@S#pAw#m&Nk| z8v=oNdSnyhqd=0*#tA+UDUgDHH`eDEj{@N-p`w&dioTrb zXhRCisZ~xfPI2gq5H_KXU1yU4PawEYZ1MCGs`fWhNsg}&^OQ=%5lQ`DMv{6ZPxu-l z)#$85nh3}x%u=_>+WT>)PI@Fq#6>wr#}Vbo^fw>FfOdKYa5A#n1=Mmer}g5TQ6*n|PWf1qIV?PZ?VNEX-@{_VV%P0*H~=o7QP<(IZg zfc<5L6b_7D`pW=#5|g3L_yqqv&JYjKY!q>s&oy#*16cg6NZ3PXgJ&9j)i6rqyMvd$ zkS)Yk{JQS+Ob~8g%p42YqTml>ZzK~w;z}_iXrTQv`4m~oc+a6O31A}#);*}1**X>=UcAK6)p|#R9sJH+Zzterk z(Wy&bqUWKbYmLkpEeRt|0dFNS&`rCUtmk={aX}y=stRKMDe`3VA^ya-uik0Djs*GC zm|EWr#wc8Reasbkf$Wm3SDqUvJ^X{QFEIIdkoT*C)9+q%c={boc|EuVBV9V~nI?B# z4M=ehvxSVAvVpQgH11ci@a6h7-vBE`GBpqtfQ-=;7$@q=4t(Y`BHlhUU_>I1d9G6= zrA{SYO$-i8xW8somA)7+`i_5gJD0r_?PJ_UkBOJ!@hLTs9K&T0^{XD7FOf5D@fvQ! zQP^yx8j-K*FW7i^@*$J{M{vn+||N2NX+a}PYnRfm`2HyMldT0V8nb%9%IAj z_pIMBv{?K0Z$sVz70O4{K8GP>=JpK^@tV7)oFcT|akE5%n9Cb#(15IC!Ed_%b+&(D zDvRo1KlRm5wS|=1{|?i=s-yuPNk%WkzUcba1AJLEO|PNB-U%Eh@54*(j5WpWitf^B zEC3S!pOBcfR}*-Z_BYY=)Pd{11Bn-eNBJvFm;>JGE!8Ufy06sB3*eb*NMgkV=igdW zuKk{2T1m0TOtlukLZT}d+A7v7RC%m_a;Yt$wBvwz)rCM!a_|S5HN(r0tKzPpq4oBc zo^~Y%5loqiil8Q;snKy?{Bj`hJGsaa9!|q#C~(lBl!OJ4q;bvGyped>Qycxb)0zAp zNr{bAbEw#K_KDg=v^9R|IKkVw(&JJnt!&y%iJPc1SES|dMhgoIJK2tU4!W{!1^p3Q zf|{{27pE7WMtL-U@nUR8&s|X^%U10u{DoMwqkhO0PMhG-9NkkuEsV4dun7q_0 zj(fSOHGv-pg14ZMsTvff4?jwinx-WE$F%+17at)U*|uTC9xs4nkY`H@N3#N{Zn@(3 zTmde{?AzIndQzzjXY}|$hUpP~1%cZX5YWK%s3$G3RY1BU;)t_-oHxPCYQi`R{{d8b z1f80X)&*bkl&v3%>0qB26i4c)zDn-Fn2;4u7F`$8TSK{Bugc=Tg0X=B#rB_)W+F~D zQ@p?ZyiN?70;VPEcX$05GR-7!xH|gE!+QXVf@06liHxeUSJWKuc&EI)G|@I4KdbIM z-($JE%6xyzF^yJIdbF6xxO`9!F@mqshN^oH5^EUF3b{b9OGqyzN>iw**EI4Nz#NDu4Cb30MwVl&@vxS)k>2xrCrMQi8sy^mk(1Bx3<5f$JoG z30RYq_V`h^(#GQ)JdMYh(euSzv6Ll&^6_Stm!WzZzRGpl7JoHW<)&-flyQtO<3h)b zMYdT!=ny+?D_a-Do$nDO0R=Y44R$rgH(lTxIkpMg{|0xR4Kx=2$jaB}%#MFj`qom) z-m%_a6cF|MA~J$6wh)y>zglnK4YsgOTgo~hz1I3J>zUOrTFx5X3(~TLz6pNWBc%G2 zk+$bIwHA4_~l%SuH99bXw{Ohn*b3eB?~uf{dc};J>QwHSIIcz@md2MV7d*wa^W_~ zmX@pF65h!5;8XM~QJk^A61Kg{RA4EJE5OU_&#u7W)|-&uNCn*Y>l0sL%%*0G-Wvr* zjB6bQLTWj^#UA;IvUOuSD-Im~Pn+&}S9>E$_e6L2 zdBW@&AGmB^2Ka`5&M(^-4AdA|l4 z+t-zjBmb~8C8DegW&urhEIQu=qO6pL~BwT{KKYrk!vdhcveUf6-5SJ~x`3FYvH zE~A3Wr)+KBuO1jb4mT(yD2*;M|FGmD6N1I;=4y+J6wRgcY=)+N_(dY8RD7rw&6irt zqMZDyPJq~fsf;nIjH*s(6U?r9m=^8+`4)LkD+{hcV%q zL6G7Tl5WaQPFz*28(uC)O}#+k>2FjN4!=kpK4ri2x_k-->LuFLT!q1Ncb!~@-*$Co zR51pJGZko$jipH+?iiUOOOJ*9 z6@aZyV0d|E6L=W9%8*hqX8RI*Yu#_sB&?MfuIV3QVZgB=K#lI$`e?w#|8ysgGt2`v zC**Sk*7?pE(%c`Q7z?@NVwLLiMLU(TE;}6>U4GT3RuAjvymz}5a0w^fYhmQqdicMg z2Tt06RUb;7q(TlZ+y8=G*02;{$r4RWTURyR5EjrcUMQEXHEt_CPmuzH;u@G|qLHN< zVlK*;(9@!WJ&}?1C4un9w`3Uk^r4X}V55)@O39z{W=PnlgO>XV3=}5n>wK%GKIzV` z3Ebau^En!=^_8kj>GzLNEl8wY%PICMJSOv#Nm55Y@GHOoBv}ZFL*_QhYeJpBo4IE@ zC~@*ho;`Auy&3CHlB)XmzbKSlF9^YF9~~NcIZPOdoJZz8Be^J&9T&%Of;$-(&3=Ce zpkT*kuGaXrSjoI$@z*bD&Mkxzx1gXoDRa|fiUOBPYXpyIBJu>;LG9apwONNprMXz5s*2-X zF<`ZxRX&iaT~WZSe&x*XxpUOz@b8@;Pkip)!`5Fe`&pUf1azYGhpTK;wF z$T_GvTD>+U{jSmTmWZ zo@3q+Wk?Ra59<#UKi&ti$wOYWr=W@I@r~QP=iknt*mLpN5PgW6VJeryZlK^C872M<-oEu zseFk(7=$B5EK-DMA(%LZ$eSFbZ-&Xar88r|_(d{{Y0(t*``z zd6489fecLRv-bT)HP~Dn5J5Sj#~&dA2*;X_TBPj^U-euPs1e5mYL6Cahr@d56?X!M zbIO0Y^NexdXN-Gg6FP$XA;DDAv*lc5V@=F0+qt{7r%WB)64nYGj)b_=UHmi`gNsMz ze+rD%6*p|W&9>ysYN^6ONf%X(GzlY^1}ls6Qengf_`?wj-8jZA+)%8tzAs1281d7Z z>lnlvMf=VMFG~ETKJKVh*29__{zUa4&vB|#jXE^^xebK}(ZJY^_VXb@aZ|wPAYSX` zu!+1tW|x=TNY+h2*Q9UPE|B-x%l*x``#Tj59n-g1qm8VLm|{BOa2uUa9>`6ON>~N* z3nO35)tlbex1x<-X%p)!Ggi;TdVC6TzEiJVtiih9dp^1Y2RuYNCX3=<&hazI<-8eFQrP#>mB3J8JTsWFBu zt%xgbLvQqCD|WJ=Ri_I!Cg-JADfKDFSDT%R2390=S&Q!#)3?d>VexacaiA1RQLD=c3#`v_gCKaTn~RT8XMYYI+e4cEoGK&g6&h$-x) z9N>D`d1&#s3$8__P+$|P?!z0GXsvNN5x(tsoA~M&UG^bRp<3ZI#_9P_-@h0FAzxIc zKO6t=;>1P*HXL&Gm&Utw`6R7QE1Q4hEcM4H8n0<-5F;k#x$!V5#F(mdY=p1L?D1-C z)sXy+FCNCDZ;aH*^lE~K3y|+Yj+yP@8$G6bkSM@dVGcE=GKdF$i)g$NfPKp&Kiyy* z*_P6uEbmJBv$MjLf<#QM4ycG^zltgYr@@x|jU+>PSgyZKu4ORz)Z6DxW-st_t+LD0 zE?swB<*@5_?DCgc!qz$y8DVFc`X{L14b^gEQMh-{M*o@O^z~fpv*5OOdysh@t*;-0 zS$HP}up7%y=Tr+RsFcy00$$MSY?=@%+eb--Z>D;NDaB>Cx>qIXw(7gz9l#z)z}HG* z*V;yI9{)fdPW~7(>ZzRt8Bdcg-@P!0xvI-{4^pS;AJu$izs$H*2IjOho8r6U*TbRw z=tS3qfXpqOnHI;L#0Pt>fYtCU3$0v&;08<;-9V)Xr|x3AmnU|Bj~|GTURwy*G3TFE7;gNc_w1fzTD-#Ek?*)8NWJ+?cGX_MUxJ2RXCvz$e z!swH)ABXx=+92J!FgW}GP>Qj~rJA#RZZNo$@O52jrJv;+zoa2lxZ!SioZOYtB__1w zL~O>v?#EeMfglpeZxz0iAo5E5sPU4IA8H*FR#&oRX;HV{DO+@(HF$h4JEutSX;IJx ztJR-}F97*L#@>5;`z@qA?=jDwQKJwD6$Mrb zWf@>A5Wn4u6;PYlEdyyx=^ZR?5}Ij!47ai^-c$ zHi;1&@X8enaJZ(Q6cmPl@kQBoZ>DtZ7qW-Sh<3$RQ`qu=I<6mRG0k*L7d9&+vO6sp z()u3;8xgHFz$+AJM3eO*ocE;en?~xE&g7gXlZ^+NE7mpYrgc`a)bo?27|b;u`G(&}({2IekgA1pTQ55dv<#ilPp9g+) zj&n|#Xe#lMI#kM>0jW~2YO*#i%iCmYT({?ERoq4xCPh~`)!$_ZcyXeCr~D+(9_p>7 z5UDb0Dp|ye#?e7(_R~AAr@?2w!Va*tvJ@yn()B~>`Ve2!F@|k(@Z4W1KvRG$X&PFX z5vhhpsrgi{siZ8&nz7PUtM)uSBwe6Uj-{sSiD8igxUwz%x77RR9bXk}lO7DeX{c21 z-(M^hL%6wq0c}H!?};G^@Au}F)$!%Pz@oJb>xqIJE4^q|vIfbPJHj)>2BS-tDnK_W zC`23N%5bG}M}PCCMR1ro^^113={NOiL5mF_F{H;@dHFrAJ<% zrIkMBOK^X=8IxV{ASf0+kDG>^QjbIMR-2vj3SmmJ)rG96Fi5`CbF&#ywNcrgQtG}F zNJbb1g9@P4m|@s+IjR@rxS)31w4k2TDAg8t?Ti(-Oou#SKrBU}h4+md6H8Ou*mFN1 zu%03f-DXHpi9)mTp?R#hL5j0#^bh)%0h zq1^)9vi{Wb&Wr&8jF1?_&{nx(%k?P6L44`jHa-|`+2r0-)Yj5rfGl(DHtEa#gGTbU z8DuwZs_*f|pj%qa@e52s6ph%w&+ebk)})|4F-X>m-L(Dxfd;qnQiU0s9WgW1*Nhbz zj_fnnqPX^eHa9V?nPFz@1%EzX?aDPbg50h>F&W%}&Y2!5q?H}*j_P&+7G)>p;|&fQ zi&x$IJeLa&Dxj$Q6`ze+@}|V)```ETKHKy4`g)z)dEnfC z`)-!_4}`J_UrC#rAU*>`4CGmjIXMD^;A{V~u2mHZYclJ1yAn(skITdiQpHl>PDz#% ze8!z2M#R)rB#%}~gzGJKF?B}A1{jM64s%-58oGdwmqc5j?PR+*(LS!;BHR-n5`PTF z8qh+|khKS?(uXfb-5k5qAo$_B_odyynwpivH*CN-NGwr34kV!j+NNOFxJ>cP-iUC1#WI+rxWVhJN73tzgQXG5XJs(Ds9~L zuFyL;z&-l;1H)zu>7OyZwKM&wD=Gv7iSUIfI+Ypeu+RWeu2l(lsto)5p}~Cbkv(>s3KcO!CPW3VfZHDN&PA?V#YTMq(W+lDZ-a5u zOLAK@tNinGc9CpUqRPf!l|#>?)OEr7Q@xq{zU+Y%CjM!A9rfeTlG1ZQQ(L}l3|=On zUKyjcjD__N&kV{<(>oc+HdA%YL?Vwf*A#^0#Ds(xdEiaReZ z$%aC6_g&`7rXyxK^K(D~c5ijYL5Eh2n?ZmcE{1QX(${n6PCNaD@wOtB+Arnxh5NH+ zVVeJ(pN%fG_(YCn16es9bNh;@R#R#i_AP|+fB~l=xi{Nf2P7;1-2AN|I8rg{G{KEn z9D016>wq`ZmuY+w26&Im=*zZAi9_%{NQ=@k2xk)GiiTD9EFRi>E{rTAOc1$Ye>k*xP43AZn$1jYZ&F!P2H4z zb%5ty*f;lQ@eT$)M#cHv-0{mURbvQiux7nba%UPV4Aee0a3?$6P6tPbd0)?ZS_VB91yBca# zH5X@$KQAQg7FW{tG?u06S9KiXtN#C905fEAOBrc9~kkeTW=ahMRiNl29E@O{fEslP(1%l2xgKZI2!a{{n39NQZiVEqv4QL z;iSCIXZo^JhypivN0JU;?U&>v0&|iRai-fwBn#*1A??oo&B8C|PDS(u8p0s_{R^Ks z4-oC;CiuQU=o_7nt^}DjS!1ny6l5VTOB-%WjY8|1cfa$mgz1-{$97%!rfqCvWltb?Sf3?uD7D4=YvS>Ju*u3&4XY?e1DKq&7O>>oD!ujrLQ`M_1 zaRE}(AStRR@IxxagMXd=`{Yn%gy2T7-D`T9(0 z&!2?_yt6vFKwhVcvbFe-%Z7VMtmJE}r_>VZQ-g?6u8!y^OCMfhdR!_unjb&=Byn(d zvlSyTQ>qNq0i(1EYg}#NI*f?`!X`y$jcFQpmsxu`R+HbEyc68?ygC^L7qLp34K)k8 zwky4t-dKz>-3TrHlJW9X_if7n-2gJgAj%3k_Eqpo_Wc??mPoxrCf%04$=oy;Rn8dZ zw7;-i0qLiv zOUs?`fl47e-Ui#xjkjiut>#9ussc0>2sf500T-#$@nZdyx;DFqOd}7qwJXLav%g}k z<4PsReO4>@NyAVK0@PbkE2ipA@6jMa)#ns=DsWzr8qO+}C2+gPOO{?;oZ03>1e!;uLxH%qF zbXD5EU;CPf{i%0%*T53`9Jd(pWjzZe7vlv1srn!K?3-?dS(2?7$wvED!=}$CHEGf& zvR~TvUwqJjZc$FpMR{Hr=33&QAg)U)v9JwHulnCu;$+_Tx7khxCk>+zDw+s0_j)FU zhK8Fao=ryeDC)`_*+6DS6Y`C2$J}X|A0K!EO%DB)ww!^a%SuN8nb@pu366v;Er`2y z?Li%#2y=4;-T^!gjA^-EuzXi_c2h!Kh*J;FuT+$Mfvk3X_@}S$3~$96VXa|d&`(uc zZ>-bJCCL6KxB)m1Tdly|m$zG)9hHy$BF8x;-u}z?qpb=Fxjv?k2ZvAakAt)}Lf*Zqg<>#GEiuohl zO{xX}1yaqMlW+_rFB<6)J@<51R;BhS8L|j{r*WaWGf-7s=P#61@edl(D;U!zKxqx; zMkAHkwR*3XsQR>xuRB?divV<%Y(uAbefyGXua(t_uQAnzmOsZ(8YC;{+;YA1iOVl5NxVQ z5QZL`E{>GU%w(d6_ypi9w@20a67$&qCB)jPlnHl}Gcc{V53bfK&}n+H7W7iha%W#K zAi_@%J#TUCz*4uXe`iCf81vwsly0pqX0CR7A8)eT`L4165vnbKl6Edw6DU~U3f>!M zQx{-H9s+RqboCdy;Gc%Xr9FA?(o}R0+N$K{S*h&)F@%7v>}pO6e#F$mO)6MH!)l~L zp<1RcCY7MO^9{P6s{NIDh(-4%;o_TYkO4}5aBdeQiM;Nf5}p|J(ws_$f~_-W>=5As z!C+bd8`PG!>7cWmj4kT9UBqMe0gXV+x0LoDk?K0>byQ3}(5}2@Yh=#OnvkkHj*ORz zzdmCC>#dn4cb&B_`HMU~`@$FUuV`)XKEBk9oLnjnBU;WRMZ?2R{#8kYK-O$dtO zy?e`vulg-SVnYn>f5jJFaTscOs1AxdoYdD-B~M03nhoY>-eQKEQ;k0$Wq)q%nMvJ_ z*iB0aKyY*uKx_4efEhqhL{ndF&YWgjl1u**6xlOeSg$F6Gy!*A5Oe8Lqhjl-MZ(CJ z@{{w>cYRDIJn&Z({!*T3LJXUYWJYyl_s=_Qe>2_t&flp>LKzf8_C`$#Yr%v zFw|dOZlO2?yw>!O8@cnoUHELG=Dmx45)u$h3|7&RxtLL@Qp0l^&hEV9*cMt(!*_RwGj~mW@ee zxv;*?G&igTR3I?jB}dKL zWi8y99@Qaaj=cOKB}kSZGlead{z|@qBs?&&Y^mt)$BwAWBVQ2gK$&D$Fw{~lP$C6Y zB4HKeej>P~)NT1U;Rjo41rFIf!;@hpqJFL|A_q~fUMN#0v9Y*`RGaHuEHfLsik3D} zCS9X#4{?XG-O-;H@JxN51pBlaMaC^|e4`WoAT1PeHctk5ehfJC14gbH9$Z8t8i^h!#h1TjBHdRceX4rlT9( z9}>|VY=GJnU!p4H0HaI=x$4cETVwU8^4G=i3%~5chC$=Bn8_r9kYpQU48pPeZ>C_m zOsPs`sB$uZ0iPD9*pLMN0u4x(I@GY@^kVeI2&_TuNxqBbz#Tw#DUM%f9 zuiHe^I*HwdZd*eBhp$P$u=ZL+AP~MBLsj~(!cZFD!x65Pqq`mEWZRzb$KoUd3nx?v zhGXJxKg_%}Ztzi4eCVM(#+_0}1uq~x=!f{nAxR9>7u=$A21iMqH2l>8&;+EpDJrt^V3aLFiWZ zpoTuWQtUhQ7xu8=U9hTKXplgsJe`JWAU&6Gx$;jY593ILf*6&mg3KJUsxeF!w>&xB zIl7TlVy#jebh@s>SfZ-qS#yih8_qOL8aqV$hTt!EB)u-E0PiRkg}M+0b3jgdnrPFf z?pCK!ag)Fg5WI{6E6>NsB}~6zlJzlWd|=T9Du(@@*v5CLB&7>b@cJ%0-VI``Q@>sh zqgMdW$Z{JeKFx}{Tv8eGhqEZ5;3^P(uKm`_?4@G#tXxEx^CjK`JwETb`vAzk(Q(=O zjwWsSP-vOFT5Ywx$K$W{@x-_Q&7|25+TCC4gUpmEoyI8$Bs0x zpLP<{shBCLT46CZG^O}QREuw&wuc{K8%KVGEfAlUYCPI|Hk3q7KaeVZA?xbuKQH{1 z(|p`tVG9w!?9roQ0g5s~XlI28mz947Yqi_K`3+d?VpQ;YY*ir}DdqjrDQrEWfR-GA z`j$=6N1*G;BsDN>sA|*g4M1I4lw0Lp@jnN!Ce;{j6pj~8c@__-b0)BI{@+2?zJ`-U zq-<3>%CeR|?nBLgWcC=}wJ>IQ?fkxw0kQy1*n8mvvZ?Ywm zFk_wZnBWkQCSsveN%_5q(73pzZeiN$>mf8W=5S0T^i|0nN2dJoS{>mpI&X*k#}u=_+Ga8SYOFu=jTknH zCn?yggIU~c`~8p7t-@|jmXz~j^L@tY{^v3+b)A_&t0j(H*BCc=cl1x zZhaZKj2+ATCb}N&7WA^CN|EwwYekdM3vd2Qny|Kg`)!DGSC}3b(^lk3w-p#sn|&oR zqNvlKd#gfNdcYkhE{`|lIX?O;!i3+|te#e#M zR;{zn)(ZkQaW ze>#2yjNWeF3DcV=S3yj`Kave`=Mcm#fPS2C7TzP53@-q42F<-^t%;=AGCTV{5XuxPfU0K!|~K0?=qxUCXzWl221bzI{3z z(==I;W|rup5i68Gd!Xc0MSxJB3-5~Mj!)qO=a`t)(Oh{OIHkR*E7a$#j&^mEHl5|b zEra(-cEPI=a*FZ!MnJmkt;qObtv@Ydgf_XKXwy0fF2g%zogcXx>KO+2O{N;zhKM{( z1@^V2)qp_c>5f{PUDWFl1?qYQ36DzYHm~}PB0ieBG%4+9+tJt(7~*+gH7u^@vdn}7 zUoPr6Y(?O;?uR&jq9>gAC2Go&g!qXb3Z8X61#&d9T)jQ?^e#=6hA6?<_Gsf84#k82 zX#_v-&+T;!DBaD>6ZRo-KRdoX;N;+d5%fr5neYecf5HSjrv*TYJ`6AQD;Rs@GL@ul zuUO}Wh<+Y_2BZ3Jzl+&_>z|#UN9w$%-NZ_NgB5)u?>r;^BxlQ!`#%^JGyI^_Oq=?t zRMPS6qlYyMjtYa1bj}U@Q)%PkTTjq zbe0}Xx1PBJ^J%gOX%A+N82OCLt&@pg#Je{ZZeY|(&fK;j&7&QOUZvHA5+K5p#RV1+ zzN8=omXeAT!L^R8C0$>s;0q~Y4C`B|SF>Pj`|mTc>stY9%p9YSod)A5k4KjcPl@_b zf~CV?dM^l8Z}-(o;aFj;mPQ543ncrn|90Ax&AWtE%pJiQg9^`jQH!XA1at(n0CoX9 zaq4`VaA~9VKc=kE6?R;;Muyrcc9} zMIqhob7qY&o`AKGdSi)wc}!6QOcX6p$SLSTF%4z2i$NcZHJY9PxgPbqCi?QBrtX zR6$C!Bs{kR>fqy0j#1d_{`QBj9B#b-hw5terZNG;=Jri>@ERwCY!iLnf84(4xNt0a z1*G+W8$b1HZ`XXBnolntGWBn|0LQnRYF^cz&OLfiMV^;FS?}&b*ZQW{){q~!K7Ukm z%tuF%esG|1ybnd7{#83%{onP7Duk&Y2`mQ#Wsp63IT8;j)lxyD;uto2x&uaC?Nz2= z?Et0mhbTo!VqYKvYam!#-0xk9;L7GN6{?B?F3`5mRXa()uNN^cn|C6?w;oc6gywHb zcxs3nfRq@LV`lC5$+%&;v272EM635Aw&7fD2!S@GLH=oT@IXlH*IPg>Zfh3dI^xCw zK!rIeH_RZpc`cgra{q2V+^YpGV&R5vqePW|(yi&)K<+{)Fq7l6S=qmxI)67z;X^RP z&ABdFn0(#ZSp6Zd<^JVzH0reaTh&_1T$%jlMyd4LgbzfO30L>wk;zgK?auFE3Y6QI zmo{oVyH+SexSySusmx%g!hsH6N%wnP{v+k`s;gZ}Vqg?ng)=CtEuVWX)n+y$KeQ{? zvfbFl`;g%vQ=@h~3-wa2oSzd2dzcz*fwxihRsTFjt#|wt1AjDP!@&s!PX~=lYUjiD zeXda7sKfzPBr6G^b*WiI%YSEGKWC!>?xLTNF6Wb(L)slDh(>ZI6>)x7^lywp1qyI0 zyjT9h-`$tz>`X-L-HUWuojE*54M&Ah1 z3*`8stQ#~1!P^>i`LB_Rk66g4ij(WpfE{4i0wA!GHr0NDG|~$E006H5=0C79SKQ&F z6V+li`8~5;WOoUZ4CzJ_iQ?d!;0pPUYJ4i3WG!4)@DmOrX#3617Hw&VbQfnzn#h0g zGuf8-eZPuTX+Xc`9}<1K`s@VKXcNnpypnlj>@!CJ{kvv3)>p(jys-IfY~t@Vk^+xz z%0Hj26~-?dLbXi)R*`3bVJ{1_AEA~b>0{P7CEw=Zii$rLJ0!EWVdnZ^c{z2M2_LT^B9nV{&ZLN0l#@Q zyo8lx!GZs@Pb-T2dEV0lgf88Nf<@hg>v>WTh0S{!+;UXa9qH>cefoHe>!pnIh4#Pf z3V>4)en#?rqWpw3BX9|@#5UphkJK{Iz$mY&2gOcWS?*?fFKhQrp01n!OkG>ukPM7c zUk&?6U2{jr>o1703F_UfyPRh~)ipFI+K2`e2j3OXM@yuLK&t|D>mGSl{?Ds^uM-f)>Z!}_sKHGrF1;}?SAfk zg5UMNwvgRV_!7DKif~SrUJ~GrO*f|w#yk2ldh2H+ELoD)E49q3lvoLmu%vnTt&~Kw zWaZ-5`PaUOn5*mDpUgy|;u8iH#rEb7ym?)f;!KD^T#VE*D_+ z*$Yu$PV}eZF5$}^+Yc{ip;JYkSu+qR<4+Bbq2B%F59L2Ky|{55;4v|gzH+2}WK8bt zQuj!RLYm-~zHz4=fSrpX4w2IrdXMnL%I}&Y8f(V6Zdtak=x zt92Y`n<=KX`b;CEk<-G-gnylIMCQ@R7EPvjs}fE0fJ!~YdL}4ru-W|w%6MO~AFG|^ zVkPWk?@yGqju)Xka_nfYiz{u=d@hza%0{`+5V0|o`4Zn!Q809szyb3 z;X5w3fAZQp>}ik%wj$i5ruOvT8+)ln?CJC)!?EDdDUVhp3m9X~EdKq62z|CR5pbAF zbd{CaQ}_e>uPS=O_5?rlAN=eAVD80fCIuCDEWZU zKE%PHpG2$ZS4~bCR0stpR1lBwTf1<)ov6h%N|N2gx_t}Ck(6qHMube^Ks*G?`n0a8+r4wd+QqdC!5N~_1L99 zYOdgokfO4p1i|F<*Bo6Fd}#G4MU{dYBwB6IRtWQ>#@fot#AehwI*TU_o(n@K0A5i= z5Fs%vEX+(WHm)5PbbD+pAgaA$AsXI2VGfgOg0(%m#Uvlx!?zsR-}^|6$>c zpQ=UF0h4x}%P>Y|uPah&ne9=!16!tSJ$fz1%}JJJ?Y_`QK}D(0#uOH3Ni?LT zxxQQmGcGn2&=8Z;!5M-kLrj`cMe>MHSEvHWoIB2qRxE3Vo*I#P_NBqqGIj3j+D_2R z2^)qWlhRI|s1YG#2-%ICZ>GGBiHQ*x$O#`$W0f4(<@!_I>QPWepjF^B(!Y^!tq_UDY97Gfl_TE)f=1FJx6mM9lo% z!ZT%o?nS7Eizrv6kg1&CJV)##&EyBGW1I8VZTB)>Ho$`&aVcR=P&k*7;PCLs)YlhD z8g$lN0bq|*5&m6z^)ak&p6U#Gxsc`))LI3W3(;+KZ%Tvwo99Oq<`)kza@v>aXUE5f_+i5wNoAFxbfm;hP~D*&J$wlKyUC3}2{_gxB%ABX?u4w8?fVedr^ME=fmv z$i;NV0e@>8&9CyMs+iFFotm@7-Ark{B&r+b_M8e3(2UWU;{IEu1T&^3UIc1`^#7ZzD% zLU$|K|6JmnmyTIDfQFy7h%NKA!i$fY^gH#=SP6~JpAx2c{4%w;`DUtvUAb1|AjL1i z`Lrih53##RK-yoK>D1XW7b8H~ERo1s(Rs(b2`KZW-mCM7KAAiKaj*_~ls!P|gwyq0 z#&YUB^61LVrC||opCmHd0C6NQ?1az=MKX*(V1Tb_pejg=#Ti=yXzZVq-F5bnyQAJ6 z@FsNEJSHfaKh)?GD-TRPLdvc|_PJ@Ty&e7)d?0mF{yr-d$TVt!_ybd8ZvOKn>F1C3 zy2!&2E?gmhr~bSIn$%a+DD|~s#gFwiCq8aI__dbR+v$%7nB{g{4U^AVHeY3$uxlcQ z52u{)9;FoCCcft5;i=oC3-%Y2TMk7xidN-L2lJ=c%F89b_CNv&Tz)q|tN1ON9_P)= zgQD^u%KU!!gaO`}STsqR3taOg%J|M*onkzthr;{Fy`k&)S=PlCaWl(7yMeQZkkgc^ zkw@v<9HsLBixg{i0}7pYkPYCY`oLZ4oc{R@Q}uChfbTcc!1^)LpXM_sj-8A*<(Nt3 z-Z0lL?#)&VdR$I(%If&iZ>7b*G$8Cl77aZ4VJa&tjmIE^6997XVEpZ+e>^0&bWF*>O$%2 z>ej8YHEpG)ngse&@3OX>YpEYfPgR0kY?+Rpm77jkjw%N=s#mls|J?6Oz6hO0*piSR zK{k~qRU=pKnK1*ng=+laRS7RnXKR?3UM|k@b*dED-wZK4-|8;=Ki~35!?wJD9or9U z#`{r%E{8m1WOwK`OeUUkqoEF(@TzN;6k%NSrIDv8VP{AevH+IULQ8&! zbV?Gd;zE+NFtSMEf zyp_{Tf*k~3i<^3QTKlWIbxj8%?e&;8a@7mP0~AkGX2@Wx?pY1dl=N2zr}Xygoo$ux zzXE4%x8Ma-=Pb`h>)6)($Q}XFffVl7mvTan!q+d?nh%L4CMW3`bj8NLQn&bYbbBow z=9osEv%L*|od=G4d_Y*xj^yuUu(lU!o5BBT^T%Om&CRLGiO*#GF0Z(+uC*m-_(g;} zpCQ%J@WwoV%n`;28#twKm5HR6dYF(o5oLH1HoPi`iFBlbHdLFhDWx(($RE;KClO=;e5gUiBI$Edp}`3_SJfZ{XicVSlI+F z!zj)_t{C{tvD1v4_Z7hvJU13s!9Hy-_`@PiV8QEMH}R~q_iGtupn(v1}b zCjIGQAinUu2F-9)sxg0W@K^rYSENKWoy^Q^25?Q!1H<2@E8wZ$k2A`PA*7DGvL3;H zi`=}M9=D;(z)reQlpJvBov6xn*SHfrE=!!~v*Zr1+wZdfe%Ve*W){?}k>Igzk;?4g zHp{MZN@tM<{a#aF-6F$Jw* z0(X4M>PW8(mY2y4@QFwKDMAqJe!!e2trBy4-1#_`RHODGx$|w*#CG4mv30r!G%(6T zQ)1?atkKYRLfpmjzl*lOr{b1m<>WLS%DZ-}du|G41WEwlQ7i&9dxH===3p)lRTy=eh0jQABPod|w~jyFXtEKG&f>4H#p_pBcQO z9xWlr_d?4N@jJ?kmg7YBk$-v2D0R14o<(HdOLN>z5<}th;PZnj1vTphBHZgoT5x4J zbvI-@3oY6TSZ={KRi+NX+q^CXgtyNiWUY#|N(@sx0J zsUHyUO}L|@Z)(9R@*$Ml)RQ|t|sA}YePsSGe2a2;Zr0e#&_7u6zTNa?L>er-6NA<{uNREow-WC0C z$}4M;E!q{GBN>>|ZEl|{U0X2hH0h0PahS0R#bMP=bG}cFyt<`Mtx4e0y++9v>3W(Y zffv#ou;N*8M*iFQiZwG2J(T8zaRBUxk%0x{8anjNTTMEcijA;!+e~iJ@va;2&&?yn zHWiOM{Os0~PrC5cEQP`gjL|)KEEZ>Wx}d0jBTUoVzuuyvu(a*BwAL?syL_NI;e6^JI%D zs5^_OM!(M8_nfxsL^~q`D~%!M!;$lMPXnfoIi27?&VU~f$~i*FqygKKdTfIw3L#gl zTmD!guPeY;c?$~*B*8AH=#ip05%7S!&$md%_o{&Kw~;$jmJj6riJ9fZsZp2@_?&C9EQo?dNE z|EO+5B8pL9$wmaf zH_6t?{#Hg?+O$wBTCxh>&X~3qjcjdot3!SG;|5z7pQ*)x>%JJN(Ula6S3f`UnQiQJa zxq3Xd&b}DB-Vp_Vg{SCc7Q?3P$-o-yjBWZKi*G7GmlXW@Hy~wX*!B*mcuk?4XY)-q z5Jq)obtMe*(EixIHpRb!C@cKrL%{=GZmu_{!y%CRETVj}`1E&Nk?(bdwuXlJwUMir zx|`edMnhBa2Ab&end{r$a`2v4nXv*E&WJ5|=Bcdn*}2__rH4bCI1A+39A-Rd6SZy} zg_WV^?_c=l$5sy&-Cu^pGOf;qTiay+TmH&Gnie&Xf@*s0WwD1?dZ3x{Zd;(Z&Dn|g zv>1XGqPa9MmAWr`X0b)79PpF{I%qn$A_FpANDdYk}IX~y%V!l4wOPCph{ ziMiEL(%<8v*W|dQ4@Bhq>BxiF)wO20M>S+PoM)FB08363uUEC9aKSzs)hqh_@A!_} za<$FH#Gqfk@9>=ndi(*dgJ_^jd|E#JjqWo0@tjsVJ_)NNBLvwx*-+^)&Cl`kq2_gN z@u=Kc5BXa9-0I?=R|@RCNBcK!Ek*D_(dC-XkMttCQEJw;kB9!ngll73;}(8@v2%k? zgha|V6OX?AfqN>PlA$x`t}(LRwZ1z~y>Zxx0t=A{Q0Nr!M)Q&kb!i!VI)Rt~qRhUJ zA1PgPO$~Qn+x|w)WuO6eKcCkww~%TnC(LfCeVY}O+P^o_O#p0RFtlmiBHQ5Ctt86$ z25u4`dCdtbzH`KkecsJuKfNH96s50jn&9-9C>?tt?*^QGK)9H zLqwgaUvP=-5I!}6juo7*TS|-a&aobaBZL9;4+$}l5pBt@4h@SIKSR{lOPc=XC$XbX zmg)jDKTQ#l_pmLcR_W-+70b(IquXa||I zt=Nh-%u&uy-2q?MtY@znMca*cB!&M;p8VP1$w33-&nt7Z$7~$Hn|)Z8MX*`j7QeLf zDF`6$&FQV*P{{SQZ)%EUjDPCmC6BzYQs?uZiM?4@=^U5u$6@F^B%hG+5Q_F&twdMu zbJ2ykX?y$tIh*1}kpVW1exmMX#b~Je9Xt|Vn{VTmoV3{!PQP(SZc(|Jp$PhT!*%m7 zO#S?4u3$KEU#&(q3Avi7R;@Ahx)5mJ^zzay@us6;y5F!eEmZv8ZUl4yJ`L*nvUb@D z>irzuYlvdzGZ!pTF3$Ogs~)q{d)*8{%kmfw@zOkUu>BQg1*mzRqQTGUkodJVCfV8T zW`z&R3c)?M2^pw7DtOLd)o_HrXHt={e~pgXdCQTn)|?%K4uuxDRPz&pl}q+=u>$YI zvi&31Ys=&VCH@DhmQ35=o6oCHKIZFfb1Ahe{_X^!o{BH-$Sb=I=qzMxKotJha(J|P zxV;~kSKA2t$^*B~A1Dk|O(;%h4peR?f*EIbh#YSlWUY-L}*auVdnbZrWay6>#=;uz|W`5*c<%} zgS-Q*z|4ybHIa)weHIba$@dQOmPa(`wfsPqWaE_bZ!Ej~)8W*5=1D((d}mlpin(}C z`$27luW%u$v^;Hq&4_*Kons)Q5#703bAOrt>3yU(9vT=7g+w71wwk8Z#R4Z5H=~zG zbuBWs{bR@ARaxsqIQd3nOK#-|;F@)x4Te3BI~RVQ*ZMbQ-gil>y=l}V21vN@VKx0JuR6$xSy!%|U{4>!oYd(j`M>Jr9c##=bYsQv)7J@OjzA0+#8pH=^~G%IM*|Ci zCT2$w5x~)0sI#72>%siW3eqGUBgHS>wVWa3`xRA^ifEQRCJ$%lS&mA%^A>v%@bmEp zmx8x%Ir{3;>$^tlb>^L)U8jXV5H}6(*xPwdhtja9?puXu{6vTTWG1;AID1qwpM4uU#QEc-VNSRSf1|uB zli2Y+>AUi`>mLB>l8!X>Xi!_A*G4>d$GVmQ*4Abl^eQ5bmnJ_CcN^}~MpIMGsuQ?C zgo99qiV791o1A>V?Ddq}+<}~#Uu2CQsTozCA-p+Ke*1J>(?M=F^NJ z8sU10Ji_xYad%GG-GzvLrWg?$rKXZnHBtB|pX~zjfRhG<4~1vKla~wm zBT)B=B(At+*WTA-Yg+b~VdDX$VBM5Nu0N7_gNBwXo)nqz-o(E-t@o!2Cv&M+q9=b- zLwzP*J$p;MgEqF<(xWWZ1e$-o{GC@KGs?m8H-0fi_hs&CIAu9`_ydn>Dq3sIcRqua z9f*C3?7mq}7pc-xO+^HAN5)Fcy$|kXhBM3Tae?$Jq&!HSV9yF={I?-#<^ie4 z>nM4mWk*$r)CX9mrZqDBvmNeUQya9yP97%@v06`Smq`7Tz?gO&)t;rl6QTzOm&@^I z_+TgnW{InuKsnUArat%tD*_KQ^{s6wV*O(;{=ldO--(5mF)#e#v>qs1Qn;e~r?g1ar!(jMLHgTMGl*9Ulmn^iM0o;4#`YmTH9g=svA%2G{tRN| z;($?TKhnR99_VWt=90u*1xU~OWF6C|1U?$AvD4%)NF7`5t4Xmn*r|3wM0zlkEmBBz zg&Xfi^MQhKYc1y?3ye^zb&;Dsb}Ih!e7q>k9PWijr#SHj?RTAjgVcwX$q zah;A&|A54{L&KS3W5I9ZBYkaq2KEFYZ)Dq)?+Oj|cOoFCmTjP;MAhrvU0rpyz%E)Q zF9;7F*Pg3|k1=|8nqaF0-Hey4yJ#a}tlfFJePE`TT94*CuG~*PsAq&sjE!;p`Hm+# zs`E$xd32V1rx_wXM%FSeczu|l95uxrffS{;bzy(%+5U$~K6RXPt4Qhiud5qR z8R*Iy?3wh750;p8_*w`Y)!zZF`vua6MP=I>W`2FzA?|feVA#}g@XHRprSMuLL%v_@ z&1x+Qn0o}bPK$-els)Q|OfcfbpZ%hk5_L`}Bm9Dr*ckX8K$}P|NxawTb@CLoD)EHh;7NfZ_3O&ns5BW>kt|zNq_rVO$kC7!; zS3gEzX@M{ef8jdfRy7A|lkmkJz0kuT?v-ExygKY?Y{p}ThP-yD30D=ZYkS#JF z?*qkm7WMGPQt68{o2lYvNml=q@E=BLePwf^UCwhg_{x8B#|gTAF*3kV{=p5?o`*7{KR{KLIiF2iNM!QGi;?-{J zNoi(rcT%-TOD1#`CTk{Q(vTMfL5&=tRwK}VZ&Dy~5UT^8T5JmrBqg6@RAXnbap31Dt?x9_NT4(9R@i~c zaTJ%D(7>e-uU^Ro8~)VFJzI*3zHET&N8me>i;{++in9lem0-)jPdm5JnEtP50TU>3 z!6LIFYulXv;?Br2qaAYmUOF^NX6C4;+HSbP^P5W06$f19NR`_>WYz3=fPcorPwpY> zwWar&{PA6_Fcs#Jld7BL3X&lk22=y79v`H-=?pF&t!7XY;-|m8a;yBzYLFc++>*FD zPor1-P_&NV*1j2~q<&M+5%X-&vOxGWYKtOn+t%rmGFqpSsDj3QCEFa(U_>{<1W-i?qiCs-uEPJfW_eF z!h8t*m#C%zWD{QFzU?k83@9F>l(pIr3^2pRnKB~<52kNMzPvqz+La3guW137eI$sg zeSdR>kM3}>O1o7;ZU=h^ia66`1qzr{^W?EgHWJhcO{b3oR$-)ck$gW=rD4#+TwwRV zd3zgcib+8nQR&X`T15aM*X=pKTt`W=EP9mazpQs~w|hSCqJ8alVhgWropvdjReiE= z2ox-;`MDN0SC3&(RedQT^510rQj^`W`>;%Z8*q6gAT-;EBPxn>aU_N3ZWll(Nw#4g zSfQ~s4xEU#5)sN`7_gKr5o6l$tEgLD{pobgD;g&v{tHHBNPzHK>$rfOcO3j^u7h!e z_LdPt%z^oKZ(x>OGXK7RF$I^`os_q3!n4 zLnLY45sbZk~_QmJEbcGd~QUNN}I_zsOg(bfSx@17=>)}HSPJ=ge4 zYWU@9#zGS#`oOrzeGLREihV)v*bZ?U%Blq5H2x;gw3dyW8$$jk`gwKfY~}sYltJ_? z2>JN*Z&htgGBBB+KRxxt*_z*)`}{dpM;*2b7GN76e?F~oV{`pKZsFyzPz>q#+GP;h zf@wAW2U%AqDt<5@Jv}crWa+^cPTSl5o~QJ%Gyjr+&$p0Q55}KLT*4$5*XUQfXSxQx zaQPZ#Q@tPWCDF^^D~gT(gYWg0rUs@3J8Ntu8y`5eoO!D=1lb#9f|wC$8u2jW${Tfn z?I1v@4;+;xxgcAYad5o3XhS(`9b+H6$cWvdw#J0W`u7@22&(us z$(*WKirrWcF|~Jk=Ys59j8@q1V4PvjBcpO@C+zF(Fncozz$%%Zxae$RqK`vDnq>~= zllUw&}SFk%tWz3=_`HL3^o=<*F(OMEDc(j0%yG+r-u%19SL4~!gP`4m-sRwu*4>ZO&5*7kK7r>Y^P*}{ zJ|aZZr0^5ie;gpFr7ehfa z6R@&tfn13)f;T~SbJ4#zJFC$*lh%?GbHWJuB5K52n0(4|iHmS_z80&^HvDX3 zgK$)lI|$$HKHNr=sJwt@`={laO*ISVBRVX;zKfmdu%cL5tNq;&|M@B0+L#Dij|s-z zBWPf_UW3)P3LWw-osq`BA|9?b%RaBhevh3jQ z?(XjH?u0;a3m$^Iy9IX!_Ygez;O@%cq`bYcQ#0V>w!=MnOQLOYf{Z$ULVpIno_#fHGqX zdBqP~DeYpV$gsaa97ik3uM#$m@L%~cv*EPr+>gZc+4$a(a!B1i`UvVPiS({DpM+mx zf)A^SB}{yZ85bKCPyUMGpV{}_?8w51B~WI|!+bkCv0-4mf5SauxKw$wcL_d}J7idrIl1_9lc=hQ z{k;Es9d}EUAW4!wa_M_eb!?fJ);qD9J?^V~v(P^_zZ8D^wx2NMpRV}U{;O}3mz^Hs zT<@71w-uc~-7dbga}tyMVd}+T8*6oHe2m~~QL}Zqc*`k72}ZQlx|J@x z-Ds>WV?6jIOrXP5#&A4L8Iqnf zoJz45roBooK1<~AKn8cYvJkdN49tcNI(fcvJKj1DLN}sryyu?o z1FOBR_MPz8+VO&L@Ey)theHs9I)loPsdYWGx6ZZKhkKT6H%8atcznG7%^tVw-n(@8 zwLllt8EbT(+b+@2HAfB`8MC->S&gZk`}E`gc>%NrZb1lKID1-Yio;Cex$g3SzsA?C z|8a87$@&FbZS#dWX57RFT$Bp1;0a1OTE1cnm>V-Vqs|Ww)O7jvnFw?3w^hFxQ6sGV z<2*P}hwLpCuZXE3gtbDSTP{)hB9b|?l`VRuLQWYzrpxd$tZB*H)s^6fq7DG*(++OL~I1Z%6WH&;;9Of1aW0m>q zOIhvf4gAp+C6eZKFP70vLX~D)3kJ?U(O=bEwXKy%_08WqhA-_Q1KbDw^7+3o<%?{& z|JR1a2$S9rc&ljBOQp00&ilY@zqqTBB+H3A?j)x*ciZvU0JC~tUcPJdd*4bcIPVAu z`x0CP40W+Zff1K}`9lTl^1Wld-nVVSO^F3mQZM)SQ@4Mhz2ke=oCYm+Txii;)BgW_ zrF=ciNQ8l(Jf2B5-l;qKZPW2P?x%3@C!%7{voV`PG}EODo^Fkvu3D*s+NJIdEm zzajtgb!7pUU!x#A_>FlY2q$b0fCF>h23#TN9*E(;`Ew!NZ3wKL(q9_-xtlvLt9@!c zS&ZjaH0dE@m`%_@?@^NQ8i-PSkeL{0$AHVXgoz`5#k zLgSkLAzEXrp-~@=smk^18}02LV9cYz4Ub|dq`6S`6)IUYj?~$E;p@Kr}d1^28Z5IMt4h#w~E`R)>)4xPhi75H!CW-0(FsVRs zH4wPTh;h$R3JhhEG^pjlg8Z>JNCI+ck^hlXE-pLDN6uWUP6^A9rt^niu&|B^MC%Cq zR*1{p{-P|Xyd(lB2bCGe0j=)12oZrUjaO~w^C$wwj+ zuAXE;1z?27Us%|OXztx)x&sA$}gxh&B{z8=m^;a?Wpu!Yw38Y)rN@l^ST!|9acU#wjV3B{{xvZc5 zeB1j&U!xTiei@z)xEte+ZwR#h5c6?>G+)%piM?0_lQ)Kwnk!T-XELv14lm&|W5GjU zm6E@QYD!AVGg22MJ$w{vTz2#Z7~OP{Y1A+VDGMi2UQP)oBxFFd_XJYtgqu*AjSVkY zt5p4kYi!jQc{qPrXr3~BsII>dog>j>IcA=pU$&aE%JI7w=;(5&k)a-~{R~ME={RCz zKHmzqC1(Y>^$4Z$eug~Fce7LkZPnc9-zVW+^rHG-dfD3SC>g&hnimCJMSR3BH`+!_ zJaj|(OkDcym>ukreT0f^g3Ky_nYkQt@x**W^sjUQ&kA!3X~^W>tMTuVx?P=%zB^cX zoB}IRwO(B3kT$klhtHGxV>n`Ob7J-zZx>{-XI7aM^Wx<}noxgWHBdB*gBaT$$Uf{XV{!oYIM?|A)2E`C6&9|#xWpU+`n7(a4lvrJ?ho| zNGCPiJlHLw$jcUQ7#6+tcTvjpc6snRZv*cFP(|f7KhxH-8D!pRyMR~M26&SEo(kFK zo&Ho!QNALdlvK90Mjdock%0=2NG?T9Ll8xaD4}z^RQmcG4^s>9aNIe;r1kT4uCs>{ z9kWYQ^fy4yQZB*_CnC=o{^0S{tt6nlFL;RhcqV(O-l*Yd+VxUu@Qhk1#8}vLjP7ab zS!SvYcXr>g%Oq#pOsr$*byF>yiVtDH>h*?)4^VM>m2=qc!F!;}@cU)xn0sX)h`G;n zQSziavdh7ih)(5lEi%X_haE)votA8>uTRKl{OcYp3?wBWmmv*h{rpx&!x#Q+>G(z? z`E2R%`Su!a@kC{snLwI*)*K6+v6v@ za|2G^6Sdvoh`wC{a)0e}Ts95Imab(Fzuq>fY&OjT#;(9z>%Z>a*|Qn0FwQwPVGF&@ z*JMjYT}&N`B1~`pGoM4djn>z6yw0!w#}oQU=7o|nl=+9lqB1Mkx)W#27Z`6O`JoDA zjIEVl(G`0u$w7ll<1-=Lh2?y4>5rYiMhu-jiUb68e9=0cEyjia<^0U~_Z#_oGVK~f z@WjLVRk5%70Rx^-SS=;3On7iV&TO*4W1a7{3RkACtli^@P`(+Y;5~&E#pv~s>+?IZRl`Ek>_nV4P(r49*0}0_ho6~gl^_b_o3#Y}887B&l z7OG~VJ}v{^oR;zGEXHWThXL;lTmk|X3ItVEETzpJRXu+VmfapyKR;Z5Wd8ZX;LPNl zdy>m-yI9R@*uOKSNwCG(9B%{qZ&?--%JXc^ioZ>~<|=Nv_q&}Fh~Kre z4S{OD$eraI!vh2=$$mPEGRHHa_PGE1H-&u4ow!Y;~p+Dk}@{Y`$N#@ z{fnZ@A$o!PdF+m}T9XzM(g%I~5J#&jq2=T~s$iD}AHPD2WC1Z8N|-N1P=yPMYl%IO znvXu%Q&f2AyAm#tKV+B!bo-7LvO9*6{2mD}p-f;>Xnr!Z^N zgzmXK)rKxr3&?hLA4DLn5e<*%29w~et5btPc)QsaqH3_+0$5%AC@z7t;@5X!x~*F` z{JiRKF29W#rF(ehr{h$@T%dXHJ*5c)$I1U>(=1{!8&fxviQP@hin@_<_-}5UDlq?8;4S zS0iv`driCUwS!6KV$o?x__lL-2by8^3{y5%;d7DRyLnpY3V%;)kw zV6dE8E;qTmWM&jDQt(RAC1}+;TD{I-_A1oOzPo+v*-}~0L)~A*_{it`I!6?Uwk((W z+QTwjvOb;xiJ|~V5*73f`+E#lHS38_0(gXKcse8N>9U4ce(Lry1b{N;{3Qve+K0d9 zbi+2-&``}`?}2GCeXlHvh~Bm)s(NhnvE@$|i+_<%BH!gl^=XG!jpep?_0V}gvfmhK%#oOKzY0HM3S5D_O=fzLc=2~>-Uy*)Yi;5K{jL~VEMXPlZ zY2TVWtTuBPwBvwT(8?Ej z^7{d_G#lL>ZG@ccc45n-) zSy5j`gdiqlWx;KQ)Micclp&L<=pt%J7jrInv=d=ZGzUtcoco87wZ4PqPS?TL_w;z2 zIv-ZsBNF0}1`T>?h?eqE^lp)6ulT?HWxkY^jolq#DTB(B#8f-`J=(9uiw~F#6`{%) zjx~#H;E?0m$xy3vV%=LW3zN~#%}E0SH%vN%z}B-orWgk(1~xcfp>3~UgfCxjRaGdx z9JC8$Zu#EgCJS*ev4tfrr!y6l#mllUC2n;w*Gp-I-(WF?N89B^(0D6XFDh)_e>7y# z7zZJ$o_s&452l?h7(6c(HvKP?1lYg zJ?HEY)b{1vb)B_)8q z7b3h=+pj2j$+eRqY`##A8?eCjlQeJ6m1Y-dA%;%bJ6+~PB(@UIQAy3iiBN0^h<07cl#4(PRZ zM%~?B)&{P>u+lf$?A)LQV*&AyzD&;@J3WXnnrlEDuSn6PX3GW@Inu#yzi4Slh(m9f zo=rxL;O{QBKZs#*(wL&!ixm^M;VXwHKjr2b$QHGhk%6#$ei+qy-h^@Xkvj6T3(C}c zIVn5mIINxqYK-}hb}aGwm@#qUh1O>G~jZhCSBlW?6FrXK%ZZBsRtIpzBnS`#&49=mVnqd4>p z{cn-mhQnxhloHC zDXrs(FcPWzxE#_(#A=y@-HcotS4XO554EW1hT>wAbu|r*4NIneqC53`_j!KMY!|6R zM1^V%$A6b9zCWQ-8KO1g#$YSV+> z`l3;RSKzS*XC6&5feT%mWsH1%IZ2n#TQ7{OM zY0v<641*R=uvrp8a}7Mr83wUL=i54U=O-w^EB|l+d3A#IPF)7?3_z@LLnO2B@5;&R zH1Ql`57!lDhSlFYTU0s>WxME%2^l6MI>#aCl8df~;ps2xEVro?60?$8<5ZET;kdOi zC#Yje+l)??ghX{4wsw7<^sBjj^tDJj28m^bCD~hq6ox=iveSgJyi=@-4Uq1S+pnXA4&s&h zMR$wyi~f>Fm)!aZc5zl_7Gq!oC&j5%vnQu&#GS`q)tcLO^IVNAMEh)lO__wo8TiMU=IF7TrZI()0@D<;;yrHwAUv_BiN(sUJx8X zwsbn4PR%(E-BuX^;f&HUCd@gWhEV7}IKnv(KSr`DLLviDyfheVVB?7uVq7#{6J1ou zdW(}}(oddv1FWC;yaHm1^iDm9w!0htf{y6174f$YAqQM@SUoTe{8T%X zxKIOTd^k(mgh9SEL#%KGl&XG?J^3(GIJpq7ytm9VBb_c8RA@=z8$x!oo1$*52{0yD z?jB$V>z}0wxHyk~oV%pZ4TBwO%K6iF*IWyHK;-VUJM6$VVR$aSqoz@cF>+=PLaxLh zkEX>$TVnLdhOv~Ub|q#Vil8uP+LWW#{imiF&LIjc24wO17nF=BwvQ5^z-yl6x%0=P z=btGx!Y^9Vxfk+}F-?RYkND0ym+(JRluxvOq=s#h1lg%WUi7#{Afc{FC1_s>ao1B; zB4#aYtV==1Ipxt{P`3=W)51FK*F#+o65pJzf0~3G0!-!CNlq1+H62&MwoTr^{txBv zKXtk$O!&B^lM%%OPkvlO(PyjZJqPS|Qx&0^v#91iZf) z26EuJk-Q*iR!TR_=eV)?&m2OMmtEAG&&yp3$1C}#zISurjXA`*0d1Q`o_VrDGMla+ z>`rb=#5{fsn`aiW)IK5#sB$w<`y4j}>BsWlhz0Bzfh$%^$6q)je5cR`>)o-qJuW=6 z8Iin9oKP&gBqWJ`oN#*{j^w$%Tuto(#Mv<$8!T+%}B;rZw`d5Qd- z_<`OxWJ){eJ^k3{l%qfaN@r*GOzu#|t4bIQB+5*7F6ddfsD|=>FB6{d&49?h%}^YX zXo}(}eiOqH;XV=^IogFNdLrrNq#JX;ent5%R}qOrZMg7CTZ;DRt1(t%oRr3!$BZ{a zc_y4pb&V&PQXb7hh^H#1Q()BYiyUqlweoIC7uK26_sXOd$gx475G2xXgc3q{$3(46 zj#!2N*3vn5!q0(v_cwW4)&Krb9yCx00Rx%3S~W&IeWI%T2yJ(qe=sMI!6w9Wgp##YiSToTZ-BT%K zc*qYiB-`FXc{z=03aJsZSFPAN`z5`8fpne;ww;SxbX*|vKl@SfyJY3D)R#k61vy#} zz!-2)phC;)BpY%vuRg8{Sy94X@crUdfxxcM?YliBLy>*)zm%JAT(xD9e!`Q%kw27K z89_@K7@LBeCe*cD;(P387YAhSf`d2!kdfV--avvO+!qY9~65FV!@Ktw#FHFYCyR{Qx)sA=&K;s|BkZXsu^=yDlnS?2xS zlw<@lC)VYF3i$gB?Hcg2o+_lYai+_a971O=IdEXvzpF7Zb{*QYLS~x2LbB|uqQf9s zaKyS)2bb@_xMQJLR1{>LpAO0|Or78v7w*w+J3#jY-Z&u_Fjfv9Hlu1Y*=ZPNZRn}s zF|_JbTNn@D;2YFRq{CWmNcI=(7gQ1v1$#Df(1zVT{;lzt)FpMtKZ0XYI51`Bz@2Zs zS!_VA2(HY2?(g!g2rgu|tHDyvIi>itDzho1S9_!qG*&3h{c zdOsr>IUAwf0e8S*p%W8W<~03k{yxIZeaZ-`Jj2*Y!#(FtUArws+nlCy0$pu4*KMJj z`q>dI^H*Ne80NoDzxJeM8%TdSa(YAj*n|r~hy)%XF<10s-n~1gCfWxX97mcZMKc*r z34tm-ik^-bvH0xGX%DG1V;Z$B3n(ksTQ)_I6w2UF9dt5n`Gha93}AzP{yNmzY_5IY zDTPsvb&6(t_T_T!lC_zB5jE>V9F8s&!+nF?v?0 zBZkVefyNvbrjq+HIsGD3&MLdP5h(7etgy#FRV)X)AXt@73O}g5_Oxs(qpn*Phx5JH zUY%}^1*cF`S{EGWv1A9ARf~VM^e$KiU+}b1GT?6w(x-)htAuajc!vWsZtGVOaRc{H zOjdT^0!LEe<#D)?hRP{fkKt1l0<)Pe^)!Bz&`VXkxIss;*)kZx-TE+hdw1_u2K;T$ zVa5Pt0O-Z$Izj&4jijlVuCE9? zgdj1#5P%x06K0N(QNV|gPq!G8XGPaN$U(}|?&qV57h|L`2)uZ(CesqU~b3%eM=eF&F0^rGsd zu{C2cLO(qUNX!6?zg2iIp0BshcF*D;bY2gM+R=8s>mv0}wqK?Az3ZT{c-cy=0gro_ z4xk9)i+h~#<)(~p4k!ab%BA9Mtf2dj4@VigxU8&PR-NS@&)F#mF{_NP#Y#q{28E@M7GYd6nl-=~}Z)0R7KQ>P=^MSU=Y}RnI zgP%N+G1UGlN0q;1uS_TPxH0Cw(x4cTY7VN^$C%GhrDl zeV&aqceP=XLJE%n(O)6lVw52=W|rG=x@!ldfaOnM%V3s=SzSLE283mOVr1G2NNJf$ z+X#!4wIBxUkaFgWN`4HcJ-?NwyG~|(_?t&~y%sgV>oWZrT$=G4V+7D7cOAy= zP5B&5Lm0cm;`k;?(8Z=+4$93Fee3@KLq1Tm9?L=TNu>8&1HNrhnyWvtAG-RjEj3a* ze_Cj6C<{%i1UL=R<5s<~7irh~!&Zj9=5RniPv!H(}Ka+PE$|_@;i}5K( z*W28Ceedhpu#@7F8^e3oW(@@890yy-;V%Xn``{-29^W0fNb5d3IVS^p_yFBwG`ANP zz@K1!Du6(!Ay6D#{kPx3$$`+LV?nunkFLPYvK@Rd!(`do$0bp7_)I>Fx;QbkOWp%N ziP3F)^kXMj?#GU=Z+|1ynF=F0g$*8w(*{>l00+_7^ee916>_IA`>rpXOlsb6Tb$W< za;%RFj`S)mX!M7)^EK7^P$-{gp_A!l)B2chu)=ou_vhsr0&uB^wA-Hqdlrdo*6hrm z%8~=+7PrdkT~BS0_R+=dk`BlWtdc5$MeffyeSqsNbxVE%k`z6g_57b zOX*EX)}Sn`_T3F@)l7$jsvh#q+uIl$ekGHOo*LW@^94@m#PX6Y(rf`VTZz~Egg-Oe zF6JQfq{^Mfq^$9_s5PevW+v=jgO(m-yh(xlLsH*}rq{ii)xGCqy4Vbj7WqmuD*!_^ zpOAGfpUlpbITQgPhw}YITF~S(O1h6aFNt&7RvONFWN{FZOLa#aLlqLfB$u8S6y~{^WP@nSYe${(TgKz=o2v#C8G!E zX-)zdSVA~vE0zZ>5!SZ7?XWlxRdY!UDw7P_U-i19+fWT2eCTulOyZ4&Sh^djbwZKK ziT99=ZqvNb7kxkUe_{i2_8XoBrG}259RZpP+lXMv7A8B6L4^da@i67}c0SrngHXiA z7EX6`!UNw|O{OU+pL$B1OiG|N!V4hcbKUTF!Cp~uAllRXfe@T3g@**>F_}aF z@Wx)3-wy|==?YZBR zUp+-8r1UE-g5hGb0@+n$<-~)f);|=~8O5a7SU2tbGsM3x>M(Lk1`W26veTiGrG1fE z^f7+t;@VhKxTv_O-z3P2Y;o5EHC^MlW?N$-!-v1JY!8zXz_1%lCJw1IFQ+xrV;{bi z62TLG6(pPFoAb*vs@upIbrRGUVUCfXp3=k6In_nt=Q_f;8V-+{Xd8{uec)FSGA6Q4 zmFdLeA-Ki{y?9Mbw#8zE{_=7rNa=80`B$@Hz8d+grf&*qs;Gp`fcmt}2?r+9KkD}D zYuN`;3yGTrG**LdiTA&teXM6-EQq;Y1dMe(0Jq?K5t2h6->Am6jJPqpe!)NswA`67 zagj5+1$k1xzv5Fo=uE(MnMQAAa&IFe)cQl5;z)sBT2A_hx&*ci$Nxj|FQ9(xu^mbX zzx;#<+QeDY=}|$H@vNQ>{)pS=tfp!!uvuz|?yQQ#t7}l+BFdL9JBmLRM0WYp1lgS? ziI^HKu0vS2-D>!tt%*SZ9R%w(J|~F0;RF+l1>7}@e>$A(`eR=Y0?3Hx=Li^M&d;-X`=)u2brwdcHTiKSxDrTdJ=8AfdX%@cx&fF}V zZi|aFOgtnPNPaVP{Y8%1KxsSYStlEAzH>V{a~N(mYHGCs(zGsCKIe2 zYgVvn5f%b|io=Psa2MIG_?o@eRsb*i8KO%LFK8OPewG?Z!;_*5!M0)6ZbruyT@Bs` z7r9g9%o)lV$b?VG%msr|SnFuNR7a!gqV?V^$CTIea1})l33fRs{r0+qIvp>1x#T7D z27faKRzM4+ekRs1A_(Yi9xWQ;iz9Hxaz}jJFr_oACw5$%w}|CY^+rp4g+x?xTiOGA@H~G{m!9*3{0V(0x{F|bpXGBN5=8|rU=BnZaLyA zpSM12ssdqRm-*d7_Y)t!wGAyN9yiPUtq_sldx&yZ0B8XQzaK)m5jd-XdwMKk+ zM7K_pLr9%E`?xZLsHH2ZCB#=*@~?&7SQgZmv^*GvY4KOVI&}(|%RG7r1}F2vc8C1@ z)~c|C{C?e#TbV$Mrlwm>*&aq)VrP7uWXdB=U(`B#4A9W(y zOPKseD<*f!?*?9YQpC6XKDYU8Oed>@IX0$drsohs=ht(uVdO{{Nb^$bWXl(tiHg)k z4#$q4TfBeGRvWZfuA0MfboI?ZPn8MFfQ&(fg^$hpf2cQRdz9kPUju#tvm5^zyPqsv z+Jd;Dg^sRns|{6s37-bzy3_gT3yZA#wW0nvmXT)+P=qtfVVjN9BN!R_NSje2U|1&h zI8F8=ShwUYK?rNC3W+w5X<3E1d0ohT!y@f{=c9oY)8GMDh^fRx+e0If+~^Q=K959`ue(Dp(V#^I<<{{N9W^|C6>s0bnQ*i1 z_!sL*o(l2?)?>%Dsj#bm8OEjxv`Y3U|8XTCdo77uU4%{nxfIm(DZg+ZIwx{>kH(go z_7pk~S3wPZX8bcd;-~)&Gt?;iWfJ3l`a`?RidIepGH`67-_2QsL)oW}LKzuiD|&sr zqhSu%6R<90%OD|lFjfC%eiGzvirbwS=o`7}y?*_IRP z;;(I|tJYG+1e?jP`Rk8+?J1xG$w<7%7kWAGS}}<4k~RCo2BhjRWj_MUQT#lw$^`_Z z&EpXG1cDLVTRRR$FzTQGc_7XtMShJOhZ8(f{Vpu;p^*&-V7!z*Gi$K7L>~C8Qo4)Vi&iV*0*(Yg49pT1w-0>}(7&{IZARmZ4 zBy{NJ1~%*C{ZR*NKHsz!L-SRhohSU>AAT}4K|5C5zO|LVQQg}+$#di&IKqL6;Z-!jsoJS%-J=I`J|`rXC};U=goTqa z{;npJ^(*ruCoTWB6PeF=*guq7pI`$Go5Tlro7Sn!af8kJZ`xn@^Fk4_(YK%UliwtN z@h7vR8Fn7f;qh}(YJhs@9^})IUhe0qv2;}(}BCxAy<( zC)WxIt!;EXjf@*v2&p@GVqGWdM?bt~1^GX!4&uUUPG!lK*Dhi&B5M4YPg1Kbp6j4< z{;k6wXsBD=T&wIE`%n~Hou6P%8wC%nOhCE2eQd+s6Fy=uMkgc9Y*O0+B7Hujh*W&Q zJX}1NEYf}FL&CuOaPFBn*^Lrl@kX(iVR2-Kt^S0^R9faynp?!Vf9ew>!b3v*7W*RH z{=beNy8C(#u6RdW@7tSt7AC*k{;5HT;akg8kZX5Z7?)erX7iC>PN+OM7rm6khG zUL)cy;3dILhNM7UjjJbCl}}qtOFeD;Iur*8v;Ls*+QFEWoWJLLp4PS-Yhs6oW@Y;j zbr}g%IjxoOj$WcC69u*5wK4hFv|i+7xWl{hZTAxtNb`76w49lJM8j1`2bhbh2nfYH@xZk~#?u5exFwvEeA;QrcU+ba5+X#t?bRc%SLo zr{2+IK$`7&SC1PZXlxt4g8o_1kX5q5E%7eL-|+!7=U5 z5}C++z7tZmr`+i1ZS;EuvjOEc>&NzY#8@JGW6yL z;{K{2&K!)X6}OB|pR;=Ya;PKR}P1t4%JxZrXVOa^hVD$3$H zwv7UbZ=T>*yKUGxUJI?hIH!MezBfj#${v2_^KApme4-~90(73?bwN~WbD1S=$}ZUb{1mj)sgeV`8Gb`}rQEGTLVbqwWaykjwNC=1 z3i}#(B4NTjXjAmeYT2t+5bO)^qgaJZ?6o@@Kpqe9gztW`%B|#{UfFqHqu={^F(^lFvAj@iq644z?YqhY4rJ$I|6N4{v zYp2yU2IJW3U#eBXF0FI!p9j6B=rAcg4<@DBRR-&8ZS6=B+b`9muE3VVE(LpdavgFq z{4CxY+Mi*<3cFp>g>MUVjM?N|?m}i9g!Zt#f&3_Oz59@r(6xJKy+|zChAMA{5I&XqEJsOk<99_`01+xw(rd=^~P$8Mw7naX>PpY%7 zvaAp8sdc)Y_K8axu>oE{TIbFA#+7e4ZhnqT2{u1bp?!m&>vPvsh&$MS;C;Tni>$YgevA)<`U+23J!r%KP+i1mKj2HZC6B8om-aBF3>hp^={! z0Ugji|5=MFv_0zf0v;w~2bUZM`DPsP-e98mJ8YhjYfHTuN}$;*#~TFGY@k8*ucM z9!m8a=9>Wf_w_le@rn%t*G+EVL~8xe#Rq^0DOuuHU6Z_ z30B)ow1t~Wr4?W?a*+nnj^{jiGBOA2-044q!ZCz zmm8dTxkv|9kS&<_XXEObT2Mg$>otfK;H&OF^GPsKCCt7PcbcqEw9J0awZ4Ho9J;P< z92@^yRPxP+e@Z$oQZ)2qvi&tCS^b)Z62gzwqbB{0!0i4$kNYD8DcviSCPcPQk4mB8 z#%ucr9Ng4JSI`goSnUz3wo z_=#UsX}L%Ao)3vY=J!uQ;lF{)xbLQ*<7pbYpQ9aGKdr@r)Xsv<88QyW>I3O)TZPIR z$2xIKY(54_9<(fw9|__4A^xzU7W6iL70y?j)8$j?585dd3=~9h?7scrhY-YU|C!;8 z#po&o&>Y18rQeVozylBSKBbxg#o6WG(}Qr(0qhb}g%yP@-*62qlKan(GWa&T)R`gD zk-I zAtV;)33H0nPIYn{xH%i>jzDp`#a>A&kGXJ!mAxZ&!-qJvo&C#6S)DI$g{sm%1{}A` zFO&d~6<9-&=yEbjU?Q?qY zo+7|Y`%9leTJXV$Vptk4k|mxQ4Z$SLFrEvp6q@BEw%SbrXpSwlp8|4dRR8B8o=5G77 z8)O5<1HFYEI`oOBA0N5xyAFX2WGLu1Fvu%|iV^?15O$DJ)Rs|NSSK+{CJw|0?|Bp$ zcZf;_IJ8E&dCC$R+H-TgccDOZW3rXeL*7DTR2uZ~!5q-Oc0!O&;UI3|MuZu2oBIb^NMdt0=KZCxr#Ykbsy){OFA)=OT3U#R(n zJvT?MM^9P{C$EWBFgct>KUAiLy=fYTUx&r5y_2L{)*u;N4p*p4lJ;3ZRuTgP_-LaV zs=iCY&pTnKmSh-=d(Db(C$WP+N0Ki_ZP;0oe{5M!14JB1N5)Sp8)eVD`PPvaG3(>W z9ml-6JNf(}?^q$qhiEw{OZ)5! zDkZ&Q;Rh!+6ijIN`FXK-^DZQPi|ZTGND+l7acDv}ah{*F48bGNVe`WjDM1<4h->i} zj=h60xXCYi%tG_INxO>Uab6NXkfqsvfhBzi6}qEu^Y!uql@SfHfAekS^ykf^SzZ&8SEVs1VE%okrh8X$h+>$w zD_6k8P|@}EUd>5(Zq_&`%BlcYa85u9(=fHurNl26Rlk=cO0$y2JtjOSdS` z5Y()fg2CiLB$t`45EYVDMfEf;W$PqrI0`0e3vEs%WbOP;BdZK#ws0E$xtVlV>KF21 z{=4#Od=M{?HH)E$|2UrR0=U6a&_7|6Pg`o9z4k#((SZWAnn&;bPb+01OgP>Vou*b8 z4IeiyelWFNNrz^qD>w%<5@ntj{}Ps~0!Ll?N=&wwDmLx)jI~4=KQZTY<^srWVrDUs z)J+Lg$FITja%^##rD$)26NL4}kZ7U(XCV%NKq>OD7&V+Azj3x4yA(B(<=63^J&{j~ zLEAJLOvZ04cAPavqE?+EItB}npjZT)mU!WfV0e}~Ok(^MVw~j_#yr$ z9t;Xq0-)S!r~)er0s@Z5-C%PlyV5ttOyiG9NNa#LLj9na>^bow&gKv7Y6Saff9pj? zFE3t$F8?+T86#N*@3=Kio1TY2>>~toY6i9(G+L(0LV*{Fy0#*jBx=`{v+F|@u%82~ z^kHfAPw>+#mzI37xVu;LA2MO%NI||NmIMa$KkJ*=oEqI!&y~qv5>4?E6CiwYSDy!k zHOR5jOKbQtQMes686E4PKTk$`%+glr|3XV&k_7H*%PL-Sr6UNYC2WKDkSC|Q)8o4( zqCC5HNJcM&639Z4EgKpI$y~x4Xzlx#NFQA&H@mpd*l)7qdU)kt_eb zFvqFgz$8-teQDTo+VhiCx-7wsD!YF)=;2&F_l|bmo@eU1O3eD>{c8C8*if}Cnoj4z zLCwHR+%*m+UA)NZA(crlCdEMm5i1X+CbZ$ARj2=~0R@s-jrNp$Qy2dtOe#tYoIDE) z^lYYb>BO4>%t9h<=np_B>!sIqT~PnJO6ZGbl8uSK??0;0gXneC3mM#H%x`r>X$PHE zJb^WZ{|hYtk3wUDN1dTX2aLKQi_!uJ8*qJMacT z#>LwCr=0{>8f%7_3t~?s7do`<{9q}ynd^D6&FXrvB|i%%?22d307Fl?GgGDkgZPG$i~#p3X9?j$jSa2e;tv1a}hLB|vb3 zySux)ySqcMpa*w%2=4CW;2hj#xqJ8Szxh2+chB@!^;U7vwnak)Q2$-xFe`(BR6gcO zChyDsNxm0y4xjuFZTNAqw_z&S*^)p21tR$L@mS~`1#VpM=bgPSiV7a;#?Niw9LoEK zwvfehk0??@xHN9hC(gE*lY8khYH(%eJR8(703BT~Y0VHZza)i56NzzCv?Z@KC}UU% zHxfI4q4}7-%qO>t0Uxk+KnrnSL=qS{z7yeH3A037ERL9oGETS;{a8g2p!eWwyo`~_ z!J31`=%!kBcl;NV289oJC{Kzq8AZJQoYfYvbv$w97@tXfhWBu&x1Gf?GRz;OnRGay zkCfNINnyz|!W@^`?j1FVe2{J&H?D81VRi!VflNN?&|R>vS&s(sKqtdX;G5=md2#58 zYzm=~N0d?TTesvBzOx!ZsIrv+g>$W$j*XJer8Bb7 z(qn>v?Q?YjEbaDl0Zg#Y3|yl~yC9sBf3W5b!ZK7~!{Na*ioved{- zhau{c>o_gq7F?TJ+WIfS-tM4+M+ozyi}USF{oH4@(VO%NZo$bDa81$EG(#PMNyaCc zc*q*VPeT-fIOu=w(Bo-h&F70bqf=fiC}C$9QT%DjK1_}6;d-5X8Wg@ttJ*EA+ zECd4wnTopeM&Ki5zM@T`6aw~1=?3DTs7p5n9VHH6pP-DVOk}fQ{cXwtu|lk1$l`a7 z(|qOr>r%^dSe#_o1>8NO6RoxM|9OMU!eDpwm9kKK6hGt z>#+Nls5FuaM`DNRB(c8`h{+2*8aF_#Eu%iyR=GMzn1Rv?{RSh2|4{2)W-O3 z`%fNN(}D);WiiMerd&5c$AN`Su$u7&VLf zs@MM__;lq5bR6C82Z7%)coet8X|J_1!V=rgra-8i6bo=U!e$`$d0{0ZCOALt|NuQl<685hA0Ox2QV37qYh}8ZnPg&hC2} zm{JZ0td6EAhSeYj^Q4#gd0+6cQ!&vCxtidYxDaSJ5j?{0F4vAL35 z;%j)CdK(Sydv|Wtr0n8{J@V8QHBQLqcypQLD#&_X2tR(*SEhM(etXUY?aWk}r0KiI zusKL_V@o`)4v+U0&-Rorw;~6H?0HJ ze1UCcTCOZ7UeKO@it|%htEA}}V|%xg#JzkipN(SroNYG?{_(+8;&uww;k{(v(=GN+ z76ua3Ol&b)Nxo$MS495Hj%H?8SD(ee5}SKA*XZ=`)6F@!C|n9`ogr?SKptC0Bc18^ z`W9{Bf}M$#;-AyJ)T2+K=eIp^}=#AL|N^vZ`BY20s)U!PI)j~~DPF4SXrW!bqKwnZ!m#mWE=LptN08y$rH zJlG9&$mC)qIu4`h^XT#>KJS0?^Z5be)-0`m=pg%#eA7-c%x%xj(c3JANrx z1rf`(=k++*jbpm%dV>%l_j&6wRGO5umLvPJvsJ#ESKv%43Z4e$h9u#!lF<4zg~Sos zmyu{YVnlq}+TY#?=g|3_H|d+r4-oM6NbxM0xuB~JdCd(i*(>of%mlj5T#(+6ZB-#W z2m@Y3?!Y@l9N6zq{1@mCvRWx8R&?DhuEb<0Z2(#RFS|;LHH=v3mD8k?eAMKb7lznalft4 z-2}1pB=ULbUG-T;iRzE%CieUR1N64It$?xML~|gfb_j+k1Vtq}iwT#vI748{*7D_# zq0W2GA;hz2{@JpPX6HdM(K{;4aje^o`zKZw@gct=IgN+}`pV=rvD1FgRILg&Ng>U0 z`w%FU;`Wd~0efh09rGXR4&~sPpu-(!x@ECIgOIFQWBK%rd$3zO1?5e~KR`cqYa{+8 zF>XrGZFTO_7?b%95rKmDI^Mw3XbN7ST2GgcO;~Uj*|N+(jX%QPH*dbMCYbYTHken6 zLEh8*dWZk)zY&9Z<3&^6<~OXn3U5y=XmI`Vr!arazOQz6pz1ytjLLg!z|0-+=;{eV zIjBNdUN}s zk6kh7L6I(nL;s{hZvtlSQ*oJ-n$pPYqUZUeh2FvT^7|Bd_7lNgThiBDbirpwNaNf5 zuESdQhUs4R-R4bCJE+(_kv#fs5)a~L(^J~%S~|-=hz8)rMb106(nUN6_6`rDx5XV0?j`hj?DBZN zYtYUu`*)#%gvFVKT9e9(x{no~pyrqipv+UzbS zeiC;~Sc#NJZv}^Q6%197(E_Sq87;&ANN&FgF5e+hCzGiEzm2;XmONu6@!$NH{|pUM zsv%wtBSLZCk2iHq)vFMPU8@7dL0U-q6r+@?$*jE#6-~sdim78#-%hhsaDqc)d2GZn zAq{SSMpH{0Twy~)(_!=`UlEyMF8k=6?*m;+45X-R8)NP;CzQm(*)!^Vbyx=G|55Z2ztpL|Ec4){)e{#Cj_vW8l_ds*j_P6QCfjYFb%l;s{4=(Sc9yU)Z)EAS$``p8S0us-BW3j6p?WoR5;AfTvA?eb|mq_nR)! zP}9+&+H#~bNqkQ8!4u6ylJa!sL{<0+n}*%|4alTq+Jjl0Tdh@rmWcuDWCD&d6H;*> zT0wFa8YXktFf%+~N`Ae*LXvEk+m|x>m1_DRt;^fBxt}LOl-V)X_aJzjhHhJk%|;GP zA&(i&o!^DhoCfk3;j-(_ZorAlW%BFAxBH&Qy+>0l;Pflr^G@qSunU(N>u~UgDOSQD zZQSzms4!jdpKqq5W-x#|0G?@}DGVJmmu!*?+098U5gaRW`@;T@Qn*kq`wL`gr{Q33 zUpex2PsF7TnuOKMZyzz?V#7_?2zlkb?yT_40_7y(V%C=w38Oz zm`tYNz5yj7wN#Lgai&#Nd^3zazXYyev%`fh-WY&vH0tGygOXi+=FTR0p4b00j0tTI zWKFovn}m%y#lFJ!x2U!}cN{aY97Kkq1h8^(*cntC?T!0uZiLocLr5+w9oAw5^E)3* z!IO*d+^R;o%m;a+B8j{W?5dGd!>6EN@`QN+k;nBV2bw@N=`S(%uWaf3K^y4gU3)Z< z1x*`o`c$1A4xZ2Jn|j9YUQKsM)GRoNe2`>(`U}rAPl5NID>sMFaTRVamcHe%RwaR-!+nOy(!2k^@&2aZhjNOTYLe)z<;QUa*1MTKddBAdIf`P)_uc=DZtTh&2Xa+??|lTFI? zeIjK?7dloe=O|E)7-xL~9@BZM&H2wf+@DeRREQTv{6O6kQktaB;KP`aXrTVm*MW7` z_a}`GL!%w_G&-&-h?!b1VTV(zN}3b(@{-6}C)P>TG%)I6a>vFUSGDyYDn?w3aloq% z*9AN^grm1qyzAuqcjP?)rT0~e0LnjUT@nkWl*x>b_�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 literal 0 HcmV?d00001 diff --git a/media/images/l2_force_loss.png b/media/images/l2_force_loss.png new file mode 100644 index 0000000000000000000000000000000000000000..7d6fb37e49cc97d3052f68a6a18ba39995919811 GIT binary patch literal 181164 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 literal 0 HcmV?d00001 diff --git a/media/images/l2_loss.png b/media/images/l2_loss.png new file mode 100644 index 0000000000000000000000000000000000000000..abeb79818edd4c86b3a5776503bb0493826d7d24 GIT binary patch literal 139425 zcmeFZWmuG5+cr!pii9AbbR#V-jUob)5`wg}v~&+67hM7Z(%s!1N_V$(=P-27cg}U+ z&$qol9)|7v_5FF-He`e~>s;$t$FU!^uL)3;m&AHZ{1^!d2}@e)oe~lfh7b}Gswu_; z;5YPLrZPxKPb9yJiz`Zti&HAvS{r}0FhW9-3W!pBsIJ^in53yBZ3!+up4-ZWjyr$%+ab=K( zsKiP8h@fb=lHx)QDSCl;;)096POuaP7G9V8zIJIypeh)Upj)*m)ruR8zXe6FfMnh@ z=@0n{TX2W72z-p?DwqvvVC489>s=!mK|q94D$)jNM~M<{d#Re?FaL2i-PoP~;lz_y zRF3!ue+(#jyG!r^PZUwD_QZO*s(#Z7Qxd zL@2hWc;vQ*n%$>xshJAT_Tk0CPydL~F%E+<>ThPGZ8NxBYcA3pW+Z)8@7e-LD#97@ zqM);HNhyE6^U1v^m7Xr^dKc1IASUvQy-JaGz2mEmL+VR@jn;DSLFIPqC*Oh;|H!{s zecIF6j=fHe>noXK*U9#njxo-?RQ~H1^)%ys=C7XLJIJ#iAEp0vHTUmdm5`3Bb+)0> z`eEiNB(L%7M?on5V9#2Jyke&}k+*sa@{$+&vl1gPBPEgltXrJhBKwIH?IQAvF66h1 zdBaZzq?ALX7P%h%^b)1QL%A4gcr~7b`|Qol236tZ*5fkObcwtdE{hy(=#&puTNfUW zvvmKcRyn{hYl9sO_?51=W|3ZHhhp)R5{Kyjh{@zKl@6x##ZM0if5-6m8BPZ(RQ>#k zPe1Be>&?UT8#4uG*-c6zN-a8jJS%y^!5EJi9L!+k#3Atv`i%l>yN*4od_HpDhi^Q) zLb$#uF9y23QLqp~yFB&P2&K0*I$f}XvHDr(6_uvfd{hj4O80a5{6^NcY9Xe8HM z_(Nc#Ahpic_kGjZ;6>I5%2cPjbpUJIsa|$T`qYbEq=_f$Q(p?u1;fZxmQz)ar78m- zG}7fQcY6yhgU(mJx-&5|I+@$-I9_FtGe09_K9g*TrA}nS-|&C@*`nqM^Rw0?P@7G( zU%cSo%BY2>C%h+dxtAi8edW3im<31}aU!o?*(~O>ty3epVWWsOo~UjNp;vpCBPHmx zs&xg9320qVwy^)ic2Ae}LN7rMeMNz@h>G&&r9V>o8zHF&TY7i}Wf(;!FMd5R{_c|U zM8(TUk0<8=Neg`m*7ajYZ(|!IQgnvj{5DUu(5siWw@?P(usdU3K1HLVvi}GCi!$1u zZ27x0rKi*@Ja8LzfRsQ)z$zu)J8<7SLP~I+ITGQS@g>M@skRJMM>xfzc_Mn|KwE3&ovMVcNeHOyMShn*h}bY?G? zL))Esny{?@gssFtubkO$eZ&}kJ=MZMMq~RzO6B(|MDcwNtp(LCO@f!TGSL!ixRfCt znSaxPr7Xibo(V1y{^V09yf9orf1CghTDMR|d{V3BPF+_bANFG%8#x=J_O3z@wJ`!8~T-YvGj!h3O@?39%n9I4gxU z)iRSTbuObZYjo@MSkd)Ctwx$MZr=K(8DzIk z#AYa`Dd(0;ZhV&yW0RQFiAnDrO)S(*uh%`Rvq~lxAJk^oDHgLXop)^Ha#c8yzC68r zdWmwQbR&1!c}&6i$`{MKb&-qk6)%_ktGXxt53nC-d24w;_SVIk!E(hq!D@V>j1`1s z{sf2Ek&`1!II_3Tgw1H*SjWJVo0CtUwrdn1Fqvv^0N&IN( zf25PTZ6l2%>$7Td%eT}=zh>>oDf~Kp!u6c+b+BlG`_%rI>OMs-lk#`vFO1{+2I5a* zHGfIQ%JfghQE)*@^)&v`Sk)*fdu=#u*X~LynUKXruu+$O`Qc~Pf|UXtX0Ciw zW}or*`HuOX<_~wC?OaR<7D8qeEw3%gEI&kZZ4FkvXuG;r$K zPi*w|h`R|p?LSo@3nr_U)%nDVq>Dj0M7uC zmLd@aQE9J0Oz6@-OSi3btvkNDPMNi3+Cf?*T97ckP=7KG(7PjlA{t9c<6te3!?7-Q zt9h#ntN1yq`kneP$7IO-_H9q=v^V7A%D48&{TEyOo#pLEnK3~zL*|W>Sk}I0&mk0z zvkjtG=a*gX#2$4XmL6Ol<{rgYFV5-CSx*J`6b^8Xl2<@2FmW#hu`ezAUd<@ls7EN( z4@Jndq?8F3xWMc)t7a&Y`VQYNsoq%eQO(B_!v?N6EBD!yLoC z>BV;aweD8J)lLl*fRAp^jldRw$}XDlVZyc+1jO{cvP;mNAqu@Mo1u;@G3ylU&Hi zpV3bl4xuFcRueULTUlGn$I(xe-kWtq2RA{VuBe4U;ueKdE&fynVB-fdB*hvEFoH&Y zcMC+iM4lPqagK6Un|Lm_A8k8(eEwT7Q=lW_*X#?^!evsY+a!GONDU*|@S#z0muDRQ z&vMRe&1ckk&rbaLm(8HPe>eYP)j|%JkE+(OR4Nh4Ga z;nC89*$-s3g)7wvX=bSP$6t*$vM~==PwmnK1ulVqz9y zU1t}$io8-#6~$ud)){FUGugT{YBP#3nvC{iS*UtzEzuq5$J|+9q0z3P+O*xj-JL(E z;;L$;F0P%fKKhwJbG&TAaj&d0IZt9-&HRs<<3!vzTb@U?e98XE<Cokr|HEOdPu|L#d^|U;6-61LF zv-Ei6aW+rbum@7RonO7F!ttb#_mI6h&j8IZjAZ8x$|q|!x4GAHDZY9|xz_ERmyYy+ zBrXxFCBG19XcSqmg$vE0;W8;3@0|yqD%C-9$t7D39t9Hdmu#UTyHKPOOx~;7A0($e z>8`df#e{|Z;@+=LCy|@65jQ|_=W(7i@ILe!d)#6&-69671A_6Pm|l4V z{CH#|_1O*yiI5KdjV!H1dw_%_h9v#&jfyk!?%X5yza}1(*U1CnbTR>C(`^qOm$hiE zy;zo*ShtXWI?ldjbkclT-@r=pcrMxslcoM(#4+Y=>cgRthTe}oRmst8lJ)F9D00eW zLu(k4gv)Kx2~*JUw!l593I4cYL0Gs6H|Q&Eh@o`S$`#E0neZ9Rr3uzOHF13`WXa{j ztc8YwODX1sgp6|M3-ALxQ|px4I3@&R{`;qtmz0aYF~Nvt`*)=2Yh+{`tg|lJU-u5h zJy_&HygvAh+zDP@e!gyo^s)%I0w0Rud_a89j)7ss@?tIGt-_r6^!Gj-O~@JRJ{cmT zU@=fGrY@1kKEl8E;V9${5AHt|UwqtyA)Bzie;(cYaAX`E)H{#&-va^GB-Z)}!`ZY( z()iE)LpL;V`}+FYHbl;9yEcwWje4V+@;SJCFx%H#f!Sk+KjHJ(i9Pew8*5PHA*#1$%X|4uv}7j$FeRI==i zCg0jOtn(BH_)&N|zd72Qt?s0_8K!8L(Y+ioH8a48iThjd~;7azyZA7?rL z#?(>dnWCyS!9#-{#xx7fU(KHtO+E{jxpyM&@RquVLVs<0S)l_?P35xD8GgRL)cn#b zQ>6ybZMEh)t+V{*%lvj4_8xS+d-sS0WAR_2> z+?{$#alQC(r4w}B*=uRlbg^!$@%>(_q*RnkDc4xih*~?kIPXzwQX(yCZWgVK7he;$ zYJhf}@0y5eveez2&NAmu@Cb8oJY4`bzkIONIy^dx9|pQ!F*w_w z=#ePwC^HRxq4~U>y`va*Su9z(7`*BqTHSoJS86_4gnqMMw^QVN6u&^4d^wg)ICe9H zbEDX>qYVkn7FuJ(+?G1?Fx5pC7D;WilOz~oAfMfh;Oq? zzWOVL!Vp2j5pgAS6g$XLE!VN&ug%uO_w!z)#CkdOY0Bfvy4FVG?ms`e4Fg++wxksT zXRYcB*QpjR2An$JmZ*QF*0`-2jz*iX-L%b{e7mwXHV~yHy!wh@Zew$;>qW^ZsM869d_OeJa4MXQj@=#JV4W`HdAP~ z`GOCYm5`L|e3GxL{lr{nnm#*9SN-8(N3%lSt8v$o69W4$%Fckq&((ra(Kp z=OMW>WztE334xQMlvVid?hp6H=J`pFvpKb<_W4G)-mQxOkE_$DAh=1})@5fih+Gbb zMIT9DepPVOu$Zgk(K(EW0rUYH@SKE%c~Xsj9vbS@cDgqkB%ynI7!$O!x3j}6;J%1T z;qOQ8np0NG{Xf3+PGc+ir^WZ7P=b&PXVT5CNoOmLs8+%!+ln^p>kexcj`qrY0gp?2 zmy+MVf7`lxF8{$~XCWdJu+K@5$18SUV_wm{UDFK|06WcpPY+T4P>Ks9|Sdb>p7pTHV4`<3dnuY^-e)XE>T< z!y-DnzvyMUXyB?2=*$VER&?8EB7*O<;Nis2{^nk<&GKyOhnL@~H*B)`_5@lDx~gt} z0r&)k02oyCR??6&)`v@@Ga|pZsZQupj&Dvyeoz6fJ1>cZcRmj?WrOxNJlWXlcgvP1 zX~Kk**c9-Dg@vKf)eUr2)(bi;3MiBx1V8@^xMx>?H$-B#CnqKdMNgDP3E;-ky9UH5 zF+E=&-5tmOS2^`kTYS-kt|zQ-K3xMs{|en#({V9!KP^uV>5u1QPv{qjx&Fg`{q|>Q z()od(C@Jh%0amdX+Wi->1BIWx%wfN3w)66r7k_)V7vp$rim&lT1z@r_lqBqJZ!={T zH=fSeHq)L{#q>ta{=_5Fw*ScZVs373tpe?S<4{Z~EV+7nVn;++rCniYW|r5W*&3O2 zoKdq^HQQtPujgUEU1pCyf~_@Q$4u2bS@Y|%LTfsO*@^(wH&f+_nzL!e`nFS8O*oqb z*jSatw9aqP1G?S9{f+3fFB4ZQ(SMJx1er-5*Jsk7b%w3O~HK_atmSrP#63&dkj8wA$O- z{~VQ0E4N##mJ0n|vl1$}+;p`s6H=)~Kh5z)Pml70q%`ebe*XsG6`X_sO%8+|C*LZ& z10j+uR{X9abe*r6U*|ZDD6>ZlU1h%kKMQEKKwXLq9*C)+D#? z;_IH`0_PY%*iAFcNoen@g642P0|Ud#em#VZT(Hz`W5Bu3fV@2I7M@rD!GDdjVf+4E zz4C8D8LXeAmEmai$0sN4Ny2Vv)zwb9>)ZGHpU2=R>t@Aa7vadL`uAh5$>Yb}hMeE_ zDkmpggV6UP^n6y$GbbksHEAwv?{~S(L^-o$0MxEz~F|dl_ov!p#Xwem>A`FK{(kVJrd<5; z^m+Te*^JoDV+`k<1rr0~dx!qth5lcO-m7^3|LbUC&`;(fR4@>RoC8?-c~n+FK)}o_ z`{{ist*!vxDXO;;_G1rYT}+i7t_c7_9)?hIVPerk8qtxOpjSuHL^Y76tL3%;dcMj1x(8pE5`d$aT6NXp({4a2X4#e!8oH_w?+_wI1{4V7^xU{tN zwd1b3#Y_dGEP4CESIB@VRMFcpeL#FM5Al?~7d?WPkABf!S{63-BerlxLBU zhzPl$(|$0JL0rbCym*@PaS#0Hd!F;bJj=p3v~`Vmw(%G(0IitFZgs1Awv1hEL#$Uad086o}b?**O`eAUM+Qx?JKG?J9N3{-~4#nBaKL+|K}-=QQEY( z-{gLJ7>bpBC}Sj0Wucp=L5AQ2!O=uO1^tj683~YUj2JBIIQI<={&bx6INM^XF*6nd z&C^f@x&!7SPWktC2e4RyvVST?ayLHZPyq^=AiL#6=4T>AtKxZzdr(3j`~Xmimbc&? zw&^&g>yF=%xz|duRY^^mdE3K`{uX=r#NI!;4DO_B*@ ztS=Cy%Qo6%bTuMp%S>Xu^?M8tLFLJm1=v!^Nkd;W5?Fw+s}Iv=N^mMBZcn?@SNUR% zvlm^c55rkKR8jcu6^Y?v0vNIEXa4oRm@(xuU@+V}k(F#f3rHu$ZX*+``2i+^)lrt{ z0Nb39nWzD#ek}>EN;(dIzVSL?AJLQIJ^<>YEG!>HC6+Re=4dhfGj8PH?PPK$UKNFe zCSFCGr6EEuv0ganO-ouYp@kZrm#_}TCCNW%}#D&=+>BLf!&}U|6 zl}3AsLL+KyH^lOGi&k25ughZlvQ#4fcIB!xMfbh?)FRF*KZ78P=8gsuw+>ewV;L_o zGR$LphYVweAF!n4Nx9MGN-6v1kX z4+NyIMIw575iB0?$N~UlJ*EZ_-39-b$oX8}SyE5G3agqFg7>DpfJ4!WawR}ArC}(N7O@~ z+zLM9?H-6}DJB_P8ye{HGa!7k1G*V(tk5B(AOTqGhMXQXVMk{FlVl<5qi+U?WPSqF z2U2yC{&B&j9D0VLow!v!Zox)zBWx$BL>naJ>6*4)DL6sE;P2AO?5ZIi5)#= zxuz|2nKUy3Y)ah;ydPRMCLH1Am+yF*-9s)U9Nohn)&0IxX&hmxr=kGR%xI5eLU}JS z8jN5`S112cmy7r6-u#H1nK}-jnLDXwvcO(dFtln7QmBcbg;(;Khe1XWb5w}g7%G6P zR-BVygd^!Y%H-sLTe&T5Vl%SWf{n5*;*Mn#sTGJCq(k;__}>rLzy&0)oWeI6TX*x0 zmk4fDQNqryLQ%zieX?>t%kig;P{4CwA5$C!#qtJ_0DoEaG5J4+P)noZ4i$&`z_deyZ^$3;N__ z#w=dpE2G?P_lnH_FVhIj5IvyX{aeQ9Fxbj4ka2j#l}Q<}zhmWp3TDmS?%tGLGeWQ} zjEXcsi$1w;Psn<;_+s|qI6qH})3L=?uAQDEo8c6esZy3k1QDw6@P0e8+6o1YS4FQg zdVcH%JMp>9+J;Hl=*5LZ@A?r}`5U}m-Z2D|c!}WyoEX#Zex{GmFveoU)Fdwp9jN2O zE(C?1gvhe-Z%O<=~v$>!yph$xqvP`j$&2r|x9SP~nL zw11R>=-bSdu#$@jBRo9AM@&w z2sj+mme}=Xsldd=4RWtPa83(0f3%n{-6=DwH_AThtr|wCMCow$Pz8f=6Oe`%v|M}n z0RfY0F~x$> zXwx~oq~a+N+YKe)nMA}I6XSv}BrE$XE1=DdKvq{YMyl{cAp`K1tMa7U(nnd=f>H5b zFL^X5?>>|kIGv0ilMz^JL48Z)nWfyEfvMpMGEOeokXmqW6Px{Rg%e|jFCa79vJh~z zPGB-kS7p1`_WCSQx-6r$J7u=2yaM;M=?a;Ch?q915){P4;g03MdA87Ymot@YY9niv z)jnIaQMzy)HHA1$^hZp=O%~@d{9|G zOa{<}R!TXVPl4=T?~`u%*BiVd_s5i((_in~vK5eCJ+eEKQtd(%I-0%(5728x(gC)% z*nnwYkr`HzlQ2{TPO5=zYIWbHXRpL*quQYpp95dA7}ElMR7c{{(9A^ zA9Q`t9T@!-e|lP*7AOyLtFj>qnSl^*_h2YkVLT4V9U&;OMaQKCQTW8WgYVeZ=RG^= zjZq1hW`B77L=&9^sDbJGm!MJhhGeEQia!1DAyGP&RW115}1cq%uZqIiurfxJY3(z4B*rD zZ5U4g@K_^;ccAFvvD2l_FX(#uE(qUeg(ZR+-%e7C_M+aTif$oL&C?>|CyS@3y*~Fn zwZQ^-5O&h70hE*+SW7G^BjXlYX_W0QV%<4BoC$torYo1%i}zto2;}Y_7ig{p+Fi6e zb>>(wAjn#VoPjxsA+fO>0Be;JKp%D6Xt(N2Cugb9V!+lRtFJ_Li4Vk{L`O8KVHnzB zqLR~>VfHfBNg)V)xk~`Mf8gny1w_j?@cJIBV6Cus;~MXUX^^c+E*D7LdW+ z=>k(|OOCU@WqxXc*GO98FfB-aVLEpagyuYF-rZK5nf_v-@7jGu78^TDmR7bDuoTc! zfQbDB&LRMUoQklCKNz^CXyAM&tY_K$${5a4MTRDR*9|MI0*~o39oyggz=9>57(ZV( z{r!mNL`EWCXt$_614YD~I4w1V$y5Jvmo#Y~u4Y;$?YMcip`*H@B5z0c+- zXlP89IcBTd0j5jac`VVb3P2UgtYgc$ny9u4i-$pFFngFWJ@>GRLrxvP(MQpbplN*8 z8?2i4@{9OA1pJ#CKHcJ{bP>HDJEifuYuWIaFo-^#i~Qy8VF~2-m5f~A0@>b=aE9NkW^TlA(OSUFwH&W4CMfYuGm~O+lL~)?#MT?vM*?uCA z=dEsyUJZh{n*@eEW`$T&M-;uys_)~(fNm>*&rf$<)+YP^F1FLJYY~+~Y zAYia7--{%p>PQzf?%3N@s*1#VN6~S>5 zi>DY3emW0oK6h@|lo(V%7gP}`GZEeJ(^rOM)xd6BquPUjR$8`!zWdvf*0i@w7!^rk zx>@NBo2P&F*@%uEI}O;TRM?p5P6q@hmaE(pqVob5s!s+z^*|p@cvVFRwR5jiQv*%? zRYDLoqQL9;rhpdQIFb8rTyNsAU%ZPHY8-&a6{>w#mA? zSYjY!tyO79>1Z|mOjsLp!SM{+imfU!cp51Hfa1JuOS9h0o=#&Rqsi?d?3GqiQN@)EubaKFwEqV9+mCh6tsE3N} zJf{7P?e_3$`Okc9%Ri^5Rp^wn1LU8>!=~%n9nGdjd6Kr>XxW1Qiu)-U6~=YTZ)iGf zP2BCUOh1DMK51WMi`)IK%F27qwyJ24wU6`DF zwpc_C)t(FY5-^FuNgpKtfRkfE&7ay7_1f%B3(#AlrVM%zHnD36>i7EGPi+(@`@3=+ZU*5 zFl@sT;xBr&`H-41f9=CMr_wJ;R<$ykcA&q{DpyIR7=xm$ti0yJbG75rP;w;GbO3W& ztIVwz?!ZLL)F%Jn5c?~1SB3X5J)7oH3X`@02T?`Tb+agMR8W0b0*fm9x#wo;sLz?d z&+jMc>FK#ut*w>lE>Qxko5|gs$E$y|Sw8Gd?p(!kDRT%2oDnn4F(mK#FYRkF)>AD+ zPD0cVgE0qtuMT~G)OQO!O5nH4I@gfDonNkOkni%H!v(KGM!Tihd2{spJ-4{UjDe2sIbSv!Wt)iuChHUwLn208yaA7N%3Qr zgn(heCbYDd~L#RIrLApuKE0z}LqjE^H+<~%gIHJbex@)T3_T-28HCI&W8S}PXV z!_N|(v;cCg;c^vFBjhffnqp=Y6;28oUBSF@t(&2Cb2WhF#3v*K8+3+BI4!BCYoPx9 zRQAd8k;PB3L!yz@%7(9_St>2#@8=dgFbbl?4uLC=0JHh}4Vc2UFe>lcfL}|layIpa zlkVYdf_p6ncb?cGq;WJ`LGtj-__tul<+Falr_KkzAJRN>1u_D;`Tt1xB6jrre0Ly) zPcuNt%}*CY$;> z$@DmV%=M?XmKL!}CL=WBx0H`anY8b_ovr`%m6}1xPJHBc!!mGC1 z7k&(ZKtkoTEBEvxD|GXjC;7=n$wo1KcNqJO^itg3T(}a_hOc(xV8q=xG$i?U6ybnZ zDO9@6`CVX8r{GIxdgD?7@M`r~1P%?a_55ySgTULy?RS(HVyqXh{+QRwlly-y(4f4y zvOWCr4g_jGTT^A;R>wipnjZd01#>nC_Hk1}@S!>k~5KB%6z(smh(SDZF|bY}lCpbs zw3p2>XzW6DDI$zDHb87E$H299dgVAyXc!gD&-)qU)us$ZK&ev+yDJw7OtLp%se6-5 z`k^(go$Pu<-&dOARd4^*hc(^S?QXjBQZ8p2=3v8(#1YY=hUiI+NoNv9o5R)aWgMGo zi)lPJfHB^sSx*G!A&~O)iocGxyE@&26GnN+X7$i`l_)Qes4qU~bawAd|A$F~PA@13 zzs6K$H8+#f`^p-n-GC(m1k<*aUNVvK!I}J5$kW5@7qx#gV{|mGYqipgS{okG3SQD7 zL%Ii7qObmj6M|g{r@F{)cyA|dcBF2PwKwkY9MVkzB!L@i^n8fr)h>t^mVJUAuNxVi)ed|oH#WMs> z%ay=%T45qW`-RoDleItSrWnKx1f9*KQL|gc$6vHvx8`e(22gt)uK3SdtpfD2h#d;qIHJml_wTE4I zVL_K;u8#wsgpmsq0%To~(D=qz1(2=#TCZ-9+dlswPCm`24<)5hgLgV{EL%+)oXuMqJamzhX(l{=CT|ab0M) z`XuCNQ2JpFLCS{3IurrF|9}mG#SV4?HvqpAh&G7(g|^A@dC-nq?@X`)y!>m|>kiQQ zAT*>H#H<=)7*WR8xU~nRz_hHZuO}R1{x^PQ+uaKUKFy)MxF<@t(VQ}G@4%+Js!6|m zgbg=Sguy_W@kKfb-~}!^j_@ud{it=PF22wUelC#yPGKtvNxUj!ZWH48jNr`1AKMpI z8PJ?vomMxKq^BD|{}46VP8$K&s1}HmzPt|3D?y_Q;m`6ePMudG#^dW2+pir41N3lpKb zZz5mX*<)dj)PPn^{So3?4_kg)-#oy*CGOyKa< z!D93i^omRS4<$d@sL3H<`(TVUi@Dt>3_k(J3^f1-Cew@s9H-uNy9thG_0;;%&{Uaa zeB~QQfrSE@as-Vm;O4jq1bA!Dt#B8bU@F%mu&eQ! zwNSsFGxa==+K=9}W&FTh>BAh^$U9S|5@VFm3U#gzs6g3L?*{$!$!W(@U?S0sR{2hXXNN4aFyi~+rCFRGSGS1lqdE%5OoBcFIX{2UP4 z6eYMxRzTj8yN;;Q4v+NXo`9p7(EKT1wOYQ$QCVttm2(ErqrB8OB6*IW8J%JT?_2Gr zSK9!*hc_wgqaTwx=9!QmM|En^y3uJhn(t2qX;rj)lxF?~c`lQ&H?z$ja!nFmKItot z0Qwtu%3U>QdK7?3J?{**SNG&2@OJ&&5zGJFySx|^Jq?i#+P)ixZ^;g_L z=Z@%M$ZIYRz7FUpelC=knkxz7-%s+51`&A!i2H`7N(==pPCCW5)6Y=*EO~Be z>9jRlsW+iHzmf1@UPhOf5iLk)!05oof8s!*vasDU!Uioq-OY9pS`A`LRhx{gDbAwYeQZlx5tu(DmrH(LQ1i7zm8=E z)C~-*wh{F{`dc7sjJRtPQ}lo9(F$svfuDdA!nSg@Njvz|)Hm>mtJdP!AsfOa5Ux4w zp&SxZtD9#jk@YO&<40OVEonVfpm_YLJqsTY{Dgc;qvfe-poXNo7DzyG>D<{(HdKyf z)&p`)!wN83!wI>RBYWqq(`0 z{TXO135$~10l79E(B4(6Y8C%pCTNUG>WYbsL&kxBmi%1q^B&o*%oalL`S6F~+RZGb>U$bskt4dVIE2z#cH@g|Hf1tGH=i8y=^5X98 zBBO**mmDfg6B`+=1F{Fx6TaL#_`y=z2=uknwKi5vLvpoN&bfQ+xE1c4L`)cH^5^(v z>%mLaFEM}uyhnwE$!f1WQM)Ps5EcHG0b@^ynN+Y`L6ddm(oyL#afC>1`q_J{P4&wC z9i`~RBsX?S7V2bZXjbPjJK)xw3Xxl{DSrKW7=%LBr*-cG%MvEf?e? zq*4`uh_gFX1MhvDO~>*B?J8QunYk~sV#dR&4vE4eY3U^^;TsYcdiMmu@OBb3R|7C#Ip!b0yG2Se z8=8cD3|MCd$sInjvCw7#ArEK0sjG$AN?3)uJtq?aSAbCkHr15SyR5Hk@a{ut4yO=C=Wb*s(=$Fs)F&fm< zroZQPN)d>d+k>(%*EtN=1fA;S<*Lof}C-JGi8iqIyv^;rZ9`;d__h1E)_ z@Dh9{2Si-VG&Ft$r>NLpEh$G$`%0N)ALY6@I-IAoqEp|EH>OI+SAl$6-jyss2%$#F zKS2%a+lV1@9w)L6Vc%yr=?#d@g?3?)F+X_!6LXS@BNCfaJ^zaumppGwl8kj07dct{ z>g3=_TOfKI*EP8vG)zznOL60E7!0*T-m3_FNe?Iiv02J)}! z%hA6&d!!M`+Gh(7P-IaowPO!$BWPHeinlgjnh2h0YsxbO{2dzp6`LRxbz;0elg(s^ zNXfZ>zRE83dzWIO(<08hKHoFTDU2Cf(na*0+^o?`)IM(_YX%6<@3g(w#VB^k z5s8yuYXIm0XeaOVZc7Pso95z`rY~ZfWH+wUY(+$sJAg=yEiU(N3_Qw>yvXj?^aqB8BXp(Yd z(WczI{E2yc+WKdKD&h$I71$SkvEm?X2nA^NNq|pnPTw($I03Y~J2(FexEJ%vgbL1A z@O|3#⪚_O7cmO0Lz}1?B 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%0DL95fm`7|lO`8R+)P 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 literal 0 HcmV?d00001 diff --git a/media/images/tensorboard-distribution.png b/media/images/tensorboard-distribution.png new file mode 100644 index 0000000000000000000000000000000000000000..1ceede55d2372367bf0699301e8ec4239dd7010f GIT binary patch literal 272198 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∾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 S93)-i=$k3*cbP94d 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