From 37df81940817b676dbcc7dbf09c6a39b3c8ba120 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Thu, 9 Jun 2016 21:04:42 +0000 Subject: [PATCH 01/48] SpatialDropout --- torch2caffe/torch_layers.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/torch2caffe/torch_layers.lua b/torch2caffe/torch_layers.lua index f9a84b5..4775188 100644 --- a/torch2caffe/torch_layers.lua +++ b/torch2caffe/torch_layers.lua @@ -224,6 +224,7 @@ M.CONVERTER = { return layer end}, ['nn.Dropout'] = simple{typename='caffe.Dropout', inplace=true}, + ['nn.SpatialDropout'] = simple{typename='caffe.dropout', inplace=true}, ['nn.View'] = simple{ typename='caffe.Flatten', layer=function(layer) From 4a5aae7d86e006eb2ce0149bfa59fb7576f2bfee Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Thu, 9 Jun 2016 21:47:11 +0000 Subject: [PATCH 02/48] tweaking~ --- torch2caffe/caffe_layers.py | 2 +- torch2caffe/torch_layers.lua | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/torch2caffe/caffe_layers.py b/torch2caffe/caffe_layers.py index ca14bd8..967a861 100644 --- a/torch2caffe/caffe_layers.py +++ b/torch2caffe/caffe_layers.py @@ -186,7 +186,7 @@ def dropout(torch_layer): layer = pb2.LayerParameter() layer.type = "Dropout" layer.dropout_param.dropout_ratio = torch_layer["p"] - assert torch_layer["v2"], "Only handle nn.Dropout v2" + # assert torch_layer["v2"], "Only handle nn.Dropout v2" train_only = pb2.NetStateRule() train_only.phase = pb2.TEST layer.exclude.extend([train_only]) diff --git a/torch2caffe/torch_layers.lua b/torch2caffe/torch_layers.lua index 4775188..e857ebb 100644 --- a/torch2caffe/torch_layers.lua +++ b/torch2caffe/torch_layers.lua @@ -210,7 +210,7 @@ M.CONVERTER = { end return new_layer end}, - ['nn.SpatialConvolution$'] = simple{typename='caffe.SpatialConvolution'}, + ['nn.SpatialConvolution'] = simple{typename='caffe.SpatialConvolution'}, ['nn.SpatialMaxPooling'] = simple{ typename='caffe.Pooling', layer=function(layer) @@ -224,7 +224,7 @@ M.CONVERTER = { return layer end}, ['nn.Dropout'] = simple{typename='caffe.Dropout', inplace=true}, - ['nn.SpatialDropout'] = simple{typename='caffe.dropout', inplace=true}, + ['nn.SpatialDropout'] = simple{typename='caffe.Dropout', inplace=true}, ['nn.View'] = simple{ typename='caffe.Flatten', layer=function(layer) From 1f94e02476aee22dd80fd58bda079e0e60d08afe Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Thu, 9 Jun 2016 21:49:46 +0000 Subject: [PATCH 03/48] for nv-model --- convert_model_for_converter.lua | 107 ++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 convert_model_for_converter.lua diff --git a/convert_model_for_converter.lua b/convert_model_for_converter.lua new file mode 100644 index 0000000..843f0aa --- /dev/null +++ b/convert_model_for_converter.lua @@ -0,0 +1,107 @@ +#!/usr/bin/env th +--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +--! +--! model_test_loss.lua +--! +--! Brief: -- Script to take a trained model file, with all the included +--! training and data parameters, and make it usable by our +--! DrivePX. Major component is to save it as a .txt instead of +--! tensor binary. However, at the time we are also downgrading +--! models since the DrivePX is stuck on CUDNNv3 +--! +--! Author: NVIDIA CORPORATION, +--! www.nvidia.com +--! Created 2016-03-18 by Karol Zieba (kzieba@nvidia.com) +--! +--! Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. +--! +--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + +require 'nn'; +require 'cunn'; +require 'cudnn'; +--require 'LocalNormalization' + +-- Figure out the path of the model and load it +local path = arg[1] +local ext = path:match("^.+(%..+)$") +local model = nil +if ext == '.t7b' then + model = torch.load(path) +elseif ext == '.txt' then + model = torch.load(path, 'ascii') +else + assert(false, "We assume models end in either .t7b or .txt") +end + +-- Just incase we perform any calculations for the future. +torch.setdefaulttensortype(model.parameters.tensor_type) + +-- Batch normalization is implemented in CUDNNv4 differently than in CUDNNv3 so +-- we convert models to the NN implementation recursively and in place. +-- Also nn.SBN has extra table parameters which crash the system so we remove them +function convert_bn(net) + for i = 1, #net.modules do + local c = net:get(i) + local t = torch.type(c) + if c.modules then + convert_bn(c) + elseif t == 'cudnn.SpatialBatchNormalization' then + local m = nn.SpatialBatchNormalization(c.weight:size(1)):cuda() + m.gradBias = c.gradBias + m.gradInput = c.gradInput + m.gradWeight = c.gradWeight + m.output = c.output + if c.running_std == nil then + m.running_var = c.running_var + else -- handle the case of CUDNN 4 and before using 1/std instead of var + m.running_var = c.running_std + m.running_var:pow(-2) + end + m.running_mean = c.running_mean + m.weight = c.weight + m.bias = c.bias + m.train = c.train + m.affine = c.affine + m.save_std = nil + m.save_mean = nil + net.modules[i] = m + elseif t == 'nn.SpatialBatchNormalization' then + c.save_std = nil + c.save_mean = nil + end + end +end +function convert_conv(net) + for i = 1, #net.modules do + local c = net:get(i) + local t = torch.type(c) + if c.modules then + convert_conv(c) + elseif t == 'cudnn.SpatialConvolution' then + local m = nn.SpatialConvolution(c.nInputPlane, c.nOutputPlane, c.kW, c.kH, + c.dW, c.dH, c.padW, c.padH) + m.output = c.output + m.gradInput = c.gradInput + m._type = c._type + m.weight = c.weight + m.gradWeight = c.gradWeight + m.bias = c.bias + m.gradBias = c.gradBias + -- Ignore groups + net.modules[i] = m + end + end +end + + +print(model.net) +convert_bn(model.net) +convert_conv(model.net) +print(model.net) + + +-- Save the model +local out_path = path:sub(1, #path - 4) .. "_clean.t7b" +torch.save(out_path, model.net, 'binary', false) From 188bf9798ac16e5c564312af34fc3654c907e471 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 10 Jun 2016 21:56:01 +0000 Subject: [PATCH 04/48] tweaking~ --- convert_model_for_converter.lua | 107 -------------------------------- torch2caffe/torch_layers.lua | 2 +- 2 files changed, 1 insertion(+), 108 deletions(-) delete mode 100644 convert_model_for_converter.lua diff --git a/convert_model_for_converter.lua b/convert_model_for_converter.lua deleted file mode 100644 index 843f0aa..0000000 --- a/convert_model_for_converter.lua +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env th ---++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ---! ---! model_test_loss.lua ---! ---! Brief: -- Script to take a trained model file, with all the included ---! training and data parameters, and make it usable by our ---! DrivePX. Major component is to save it as a .txt instead of ---! tensor binary. However, at the time we are also downgrading ---! models since the DrivePX is stuck on CUDNNv3 ---! ---! Author: NVIDIA CORPORATION, ---! www.nvidia.com ---! Created 2016-03-18 by Karol Zieba (kzieba@nvidia.com) ---! ---! Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. ---! ---++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - -require 'nn'; -require 'cunn'; -require 'cudnn'; ---require 'LocalNormalization' - --- Figure out the path of the model and load it -local path = arg[1] -local ext = path:match("^.+(%..+)$") -local model = nil -if ext == '.t7b' then - model = torch.load(path) -elseif ext == '.txt' then - model = torch.load(path, 'ascii') -else - assert(false, "We assume models end in either .t7b or .txt") -end - --- Just incase we perform any calculations for the future. -torch.setdefaulttensortype(model.parameters.tensor_type) - --- Batch normalization is implemented in CUDNNv4 differently than in CUDNNv3 so --- we convert models to the NN implementation recursively and in place. --- Also nn.SBN has extra table parameters which crash the system so we remove them -function convert_bn(net) - for i = 1, #net.modules do - local c = net:get(i) - local t = torch.type(c) - if c.modules then - convert_bn(c) - elseif t == 'cudnn.SpatialBatchNormalization' then - local m = nn.SpatialBatchNormalization(c.weight:size(1)):cuda() - m.gradBias = c.gradBias - m.gradInput = c.gradInput - m.gradWeight = c.gradWeight - m.output = c.output - if c.running_std == nil then - m.running_var = c.running_var - else -- handle the case of CUDNN 4 and before using 1/std instead of var - m.running_var = c.running_std - m.running_var:pow(-2) - end - m.running_mean = c.running_mean - m.weight = c.weight - m.bias = c.bias - m.train = c.train - m.affine = c.affine - m.save_std = nil - m.save_mean = nil - net.modules[i] = m - elseif t == 'nn.SpatialBatchNormalization' then - c.save_std = nil - c.save_mean = nil - end - end -end -function convert_conv(net) - for i = 1, #net.modules do - local c = net:get(i) - local t = torch.type(c) - if c.modules then - convert_conv(c) - elseif t == 'cudnn.SpatialConvolution' then - local m = nn.SpatialConvolution(c.nInputPlane, c.nOutputPlane, c.kW, c.kH, - c.dW, c.dH, c.padW, c.padH) - m.output = c.output - m.gradInput = c.gradInput - m._type = c._type - m.weight = c.weight - m.gradWeight = c.gradWeight - m.bias = c.bias - m.gradBias = c.gradBias - -- Ignore groups - net.modules[i] = m - end - end -end - - -print(model.net) -convert_bn(model.net) -convert_conv(model.net) -print(model.net) - - --- Save the model -local out_path = path:sub(1, #path - 4) .. "_clean.t7b" -torch.save(out_path, model.net, 'binary', false) diff --git a/torch2caffe/torch_layers.lua b/torch2caffe/torch_layers.lua index e857ebb..6c20123 100644 --- a/torch2caffe/torch_layers.lua +++ b/torch2caffe/torch_layers.lua @@ -210,7 +210,7 @@ M.CONVERTER = { end return new_layer end}, - ['nn.SpatialConvolution'] = simple{typename='caffe.SpatialConvolution'}, + ['nn.SpatialConvolution$'] = simple{typename='caffe.SpatialConvolution'}, ['nn.SpatialMaxPooling'] = simple{ typename='caffe.Pooling', layer=function(layer) From 9f388189d2461c54c938ec2d6d2688f130e94e0c Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Mon, 13 Jun 2016 20:18:02 +0000 Subject: [PATCH 05/48] tweaking~ --- torch2caffe/__init__.pyc | Bin 0 -> 137 bytes torch2caffe/caffe_builder.pyc | Bin 0 -> 2734 bytes torch2caffe/caffe_layers.py | 8 ++++++++ torch2caffe/caffe_layers.pyc | Bin 0 -> 12362 bytes torch2caffe/lib.lua | 8 +++++--- torch2caffe/lib_py.pyc | Bin 0 -> 7961 bytes torch2caffe/torch_layers.lua | 2 +- 7 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 torch2caffe/__init__.pyc create mode 100644 torch2caffe/caffe_builder.pyc create mode 100644 torch2caffe/caffe_layers.pyc create mode 100644 torch2caffe/lib_py.pyc diff --git a/torch2caffe/__init__.pyc b/torch2caffe/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..346c5b35e1815d0b5320da4be25868812b94a312 GIT binary patch literal 137 zcmZSn%*&;l9vPm@00oRd+5w1*S%5?e14FO|NW@PANHCxg#YR9e{fzwFRQ=MV(!7#V z{j?PO2Tq@M0il F002W^9B=>t literal 0 HcmV?d00001 diff --git a/torch2caffe/caffe_builder.pyc b/torch2caffe/caffe_builder.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f0d29c8f4355da23955191b5607bbe110616fd20 GIT binary patch literal 2734 zcmb_dTW=dx5T5ldi5oXf(py?8ty)!bMB}uP03jhno1~~xh>C3#uvC_{_jtW#y~o*e zHW%dZ65e^_5&i%_g%{rW75o9dnYHUy9)t{Wx1T|IcQyMNf) zcl!}Ea+#ZIZQUSBRnO}5+|_+(&STkBsfPPBas42OY@`!EcEi+9Y!!-Q-{J(bY`-kn;TLFzfQuBa~YQz^^N0rE~VDY;~$C*`LG#cyF<{OLH2%?k7AcI_T z6_RlpCD!X_Nslwj<<}t3l89^M#gSF1ADhEo5mL6O;BS|k=?}yUi7twC_A5<@_Fnx$ z7bUVpLx+Y1n&5wlhDBLRbXlZ}vd~z|CJs$1v@tBxw*@+W z$sOXrWQeYMtz7+g<%?Xo$jt{6wmh!UkzJ-?jV_Vx0@?%zb$Xla? z=ZK5@Jb0u>0%c9#OB*@Ww1r&T@^9WN-43 z5ROmuz>yQd$t_ldMJTB_$A7(<>M~8>_cljk{j)Yritu+Jb;Qnw7?)?poWvbTqDGUN z80H0F<}U4U(z!`(W^!ztBZv{EU%;@H`QqhFQIS9sBBZ?GfYkS&o=UhdZ}us|m# zDz%oI)t-+Pdz)M4nsye(a_FwMR*!^KXPBix9OqI`1)(yQJJ;&5<-GBoO4-;SBSaty zP(l6XAM+03%w}mYs)p1a!9ymvF^48 z{#c0}iXmT&oE%E@JR|#jVurZqDNe&qq$=oDq64n`JSpDn!mp|Grks3QLEg!a%q7B! zO_N1UzETPJM!hYgMU)pBh4T`eX?|^H3@n?oat(8qFSU7>opJ`5dm_IH zKjuUBTc|iSXUVzYEIV8HtrnM^HPEY06~AksHl16L)$m&fS92DeTLnQgE)qALpxJLA za_9mq0L>TyF7Ys;2c{fQ0D_+%Fydhl0c>ajU{sD_z$^?Y&*@P>^ySx6UnQ|FzvTPFr=(_Apz=+VW4LBy_EI9~!rAQM}EJTWFkWtL>T1_v>Sh_aWp>(~pdEQ`ny12nkQ@j$=h@sYD ztmLL7lWx|}$Cq2IuhWrlr9r+>#`vLX>z2g>6as*8B$Y;f9R2WGTIV3m`@B5lWfP0E zZU292DE5!Ds*m~0txV2!=caSN!0U!n=jzGudtRV>o+lIG;kC3`sywgB7ELa6lYyei zIMZCiVtF?5QZ!~|Xz(3POVE7GO6*;3AlGRK?J*8DJ(ts2aFGW8UO$Q literal 0 HcmV?d00001 diff --git a/torch2caffe/caffe_layers.py b/torch2caffe/caffe_layers.py index 967a861..94e9d25 100644 --- a/torch2caffe/caffe_layers.py +++ b/torch2caffe/caffe_layers.py @@ -192,6 +192,13 @@ def dropout(torch_layer): layer.exclude.extend([train_only]) return layer +def power(torch_layer): + layer = pb2.LayerParameter() + layer.type = "Power" + layer.power_param.power = 1 + layer.power_param.scale = 1-torch_layer["p"] + layer.power_param.shift = 0 + return layer def fbthreshold(torch_layer): layer = pb2.LayerParameter() @@ -299,6 +306,7 @@ def build_converter(opts): 'caffe.SpatialConvolution': spatial_convolution, 'caffe.Pooling': pooling, 'caffe.Dropout': dropout, + 'caffe.Power': power, 'caffe.Flatten': ty('Flatten'), 'caffe.FBThreshold': fbthreshold, 'caffe.LSTM': lstm, diff --git a/torch2caffe/caffe_layers.pyc b/torch2caffe/caffe_layers.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9f3c8e0cec9d1412593e52af90560f359fb4f147 GIT binary patch literal 12362 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 literal 0 HcmV?d00001 diff --git a/torch2caffe/lib.lua b/torch2caffe/lib.lua index 495b703..7850d36 100644 --- a/torch2caffe/lib.lua +++ b/torch2caffe/lib.lua @@ -104,7 +104,7 @@ function M.compare(opts, torch_net) torch_outputs = torch_net:forward(torch_inputs) end) if not ok then - print("Got error running forward: %s", err) + print("\n\n\nGot error running forward: %s", err) torch_net:cuda() local torch_inputs = inputs_to_torch_inputs( inputs, 'torch.CudaTensor') @@ -139,12 +139,14 @@ function M.compare(opts, torch_net) local max_absolute_error = (caffe_output - torch_output):abs():max() print("Maximum difference between Caffe and Torch output: %s", max_absolute_error) - if (max_absolute_error > 0.001) then + if 1 then --(max_absolute_error > 0.001) then debug_nets(caffe_net, torch_net) if os.getenv('LUA_DEBUG_ON_ERROR') then require('fb.debugger').enter() end - error("Error in conversion!") + if (max_absolute_error > 0.001) then + error("Error in conversion!") + end end end if os.getenv('LUA_DEBUG_ON_ERROR') then diff --git a/torch2caffe/lib_py.pyc b/torch2caffe/lib_py.pyc new file mode 100644 index 0000000000000000000000000000000000000000..48df49dc1f877d01b9ebb3144c2a15066429199d GIT binary patch literal 7961 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�JdWO*}ypDeqm*e8A?rY;Lgm zh|OI#>udrvQ(h>vKM|)eU$qJ3HNu9$R~6B<{;^J>wTijY(b9bBc!_n1Q`*jz7C)_* O@mHzWknbI-Fa8_mD1}!5 literal 0 HcmV?d00001 diff --git a/torch2caffe/torch_layers.lua b/torch2caffe/torch_layers.lua index 6c20123..fae565c 100644 --- a/torch2caffe/torch_layers.lua +++ b/torch2caffe/torch_layers.lua @@ -224,7 +224,7 @@ M.CONVERTER = { return layer end}, ['nn.Dropout'] = simple{typename='caffe.Dropout', inplace=true}, - ['nn.SpatialDropout'] = simple{typename='caffe.Dropout', inplace=true}, + ['nn.SpatialDropout'] = simple{typename='caffe.Power', inplace=true}, ['nn.View'] = simple{ typename='caffe.Flatten', layer=function(layer) From 8c59d9abf2ec2fed54f948d28c193373a0d36060 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 14 Jun 2016 13:47:10 +0000 Subject: [PATCH 06/48] tweaking~ --- torch2caffe/__init__.pyc | Bin 137 -> 0 bytes torch2caffe/caffe_builder.pyc | Bin 2734 -> 0 bytes torch2caffe/caffe_layers.pyc | Bin 12362 -> 0 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 torch2caffe/__init__.pyc delete mode 100644 torch2caffe/caffe_builder.pyc delete mode 100644 torch2caffe/caffe_layers.pyc diff --git a/torch2caffe/__init__.pyc b/torch2caffe/__init__.pyc deleted file mode 100644 index 346c5b35e1815d0b5320da4be25868812b94a312..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 137 zcmZSn%*&;l9vPm@00oRd+5w1*S%5?e14FO|NW@PANHCxg#YR9e{fzwFRQ=MV(!7#V z{j?PO2Tq@M0il F002W^9B=>t diff --git a/torch2caffe/caffe_builder.pyc b/torch2caffe/caffe_builder.pyc deleted file mode 100644 index f0d29c8f4355da23955191b5607bbe110616fd20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2734 zcmb_dTW=dx5T5ldi5oXf(py?8ty)!bMB}uP03jhno1~~xh>C3#uvC_{_jtW#y~o*e zHW%dZ65e^_5&i%_g%{rW75o9dnYHUy9)t{Wx1T|IcQyMNf) zcl!}Ea+#ZIZQUSBRnO}5+|_+(&STkBsfPPBas42OY@`!EcEi+9Y!!-Q-{J(bY`-kn;TLFzfQuBa~YQz^^N0rE~VDY;~$C*`LG#cyF<{OLH2%?k7AcI_T z6_RlpCD!X_Nslwj<<}t3l89^M#gSF1ADhEo5mL6O;BS|k=?}yUi7twC_A5<@_Fnx$ z7bUVpLx+Y1n&5wlhDBLRbXlZ}vd~z|CJs$1v@tBxw*@+W z$sOXrWQeYMtz7+g<%?Xo$jt{6wmh!UkzJ-?jV_Vx0@?%zb$Xla? z=ZK5@Jb0u>0%c9#OB*@Ww1r&T@^9WN-43 z5ROmuz>yQd$t_ldMJTB_$A7(<>M~8>_cljk{j)Yritu+Jb;Qnw7?)?poWvbTqDGUN z80H0F<}U4U(z!`(W^!ztBZv{EU%;@H`QqhFQIS9sBBZ?GfYkS&o=UhdZ}us|m# zDz%oI)t-+Pdz)M4nsye(a_FwMR*!^KXPBix9OqI`1)(yQJJ;&5<-GBoO4-;SBSaty zP(l6XAM+03%w}mYs)p1a!9ymvF^48 z{#c0}iXmT&oE%E@JR|#jVurZqDNe&qq$=oDq64n`JSpDn!mp|Grks3QLEg!a%q7B! zO_N1UzETPJM!hYgMU)pBh4T`eX?|^H3@n?oat(8qFSU7>opJ`5dm_IH zKjuUBTc|iSXUVzYEIV8HtrnM^HPEY06~AksHl16L)$m&fS92DeTLnQgE)qALpxJLA za_9mq0L>TyF7Ys;2c{fQ0D_+%Fydhl0c>ajU{sD_z$^?Y&*@P>^ySx6UnQ|FzvTPFr=(_Apz=+VW4LBy_EI9~!rAQM}EJTWFkWtL>T1_v>Sh_aWp>(~pdEQ`ny12nkQ@j$=h@sYD ztmLL7lWx|}$Cq2IuhWrlr9r+>#`vLX>z2g>6as*8B$Y;f9R2WGTIV3m`@B5lWfP0E zZU292DE5!Ds*m~0txV2!=caSN!0U!n=jzGudtRV>o+lIG;kC3`sywgB7ELa6lYyei zIMZCiVtF?5QZ!~|Xz(3POVE7GO6*;3AlGRK?J*8DJ(ts2aFGW8UO$Q diff --git a/torch2caffe/caffe_layers.pyc b/torch2caffe/caffe_layers.pyc deleted file mode 100644 index 9f3c8e0cec9d1412593e52af90560f359fb4f147..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12362 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 From 9ef1860e2e601c96e9c5084e15adf108aeecbc65 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 14 Jun 2016 13:47:35 +0000 Subject: [PATCH 07/48] tweaking~ --- torch2caffe/lib_py.pyc | Bin 7961 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 torch2caffe/lib_py.pyc diff --git a/torch2caffe/lib_py.pyc b/torch2caffe/lib_py.pyc deleted file mode 100644 index 48df49dc1f877d01b9ebb3144c2a15066429199d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7961 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�JdWO*}ypDeqm*e8A?rY;Lgm zh|OI#>udrvQ(h>vKM|)eU$qJ3HNu9$R~6B<{;^J>wTijY(b9bBc!_n1Q`*jz7C)_* O@mHzWknbI-Fa8_mD1}!5 From ab1c57156261c60d60130b143ce51f95c34f1303 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 14 Jun 2016 23:26:36 +0000 Subject: [PATCH 08/48] test --- convert.lua | 121 +++++++++++++++++++++++++++++ torch2caffe/caffe_layers.py | 9 ++- torch2caffe/lib_py.py | 5 ++ torch2caffe/torch_layers.lua | 3 +- verify.lua | 143 +++++++++++++++++++++++++++++++++++ 5 files changed, 279 insertions(+), 2 deletions(-) create mode 100644 convert.lua create mode 100644 verify.lua diff --git a/convert.lua b/convert.lua new file mode 100644 index 0000000..e29c33d --- /dev/null +++ b/convert.lua @@ -0,0 +1,121 @@ +#!/usr/bin/env th +--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +--! +--! model_test_loss.lua +--! +--! Brief: -- Script to take a trained model file, with all the included +--! training and data parameters, and make it usable by our +--! DrivePX. Major component is to save it as a .txt instead of +--! tensor binary. However, at the time we are also downgrading +--! models since the DrivePX is stuck on CUDNNv3 +--! +--! Author: NVIDIA CORPORATION, +--! www.nvidia.com +--! Created 2016-03-18 by Karol Zieba (kzieba@nvidia.com) +--! +--! Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. +--! +--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + +require 'nn'; +require 'cunn'; +require 'cudnn'; +local t2c=require 'torch2caffe.lib' +local trans = require 'torch2caffe.transforms' + +--require 'LocalNormalization' +Test={} +g_SLOW="" + +-- Figure out the path of the model and load it +local path = arg[1] +local ext = path:match("^.+(%..+)$") +local model = nil +if ext == '.t7b' then + model = torch.load(path) + model2 = torch.load(path) +elseif ext == '.txt' then + error('wrong model') +else + assert(false, "We assume models end in either .t7b or .txt") +end + + +local function adapt_spatial_dropout(net) + -- does not support recursive sequential(dropout) + --print (model) + for i = 1, #net.modules do + local c = net:get(i) + local t = torch.type(c) + if c.modules then + adapt_spatial_dropout(c) + elseif t == 'nn.SpatialDropout' then + local m = nn.Dropout(c.p, false,true) + local found = false + -- Ignore groups + net.modules[i] = m + for j = i,1,-1 do + local block_type = torch.type(net:get(j)) + if block_type == 'nn.SpatialConvolution' + or block_type == 'nn.Linear' then + --or block_type == 'nn.SpatialBatchNormalization' then + net.modules[j].weight:mul(1 - c.p) + if net.modules[j].bias then + net.modules[j].bias:mul(1 - c.p) + end + found = true + break + end + end + if not found then + error('SpatialDropout module cannot find weight to scale') + end + end + end +end + +local function g_t2c_preprocess(model,opts) + model = cudnn.convert(model, nn) + model=nn.utils.recursiveType(model, 'torch.FloatTensor') + for _, layer in pairs(model:findModules('nn.SpatialBatchNormalization')) do + if 1 then -- layer.save_mean==nil then + layer.save_mean = layer.running_mean + layer.save_std = layer.running_var + layer.save_std:pow(-0.5) + end + --layer.train = true + end + adapt_spatial_dropout(model) + return model +end + +if model.net then + model = model.net + model2 = model2.net +end +--model.net=g_t2c_preprocess(model.net, opts) +--model=nn.utils.recursiveType(model, 'torch.FloatTensor') +model=g_t2c_preprocess(model, opts) + +--torch.setdefaulttensortype('torch.FloatTensor') + +local function check(module, module2,input_dims) + module:apply(function(m) m:evaluate() end) + local opts = { + prototxt='1.prototxt', + caffemodel='1.caffemodel', + inputs={{name="data", input_dims=input_dims}}, + } + t2c.convert(opts, module) + t2c.compare(opts, module2) + return opts +end + + +check(model, model2, {1,3,66,200}) + + +-- Save the model +--local out_path = path:sub(1, #path - 4) .. "_c.t7b" +--torch.save(out_path, model.net) diff --git a/torch2caffe/caffe_layers.py b/torch2caffe/caffe_layers.py index 94e9d25..5f602aa 100644 --- a/torch2caffe/caffe_layers.py +++ b/torch2caffe/caffe_layers.py @@ -186,12 +186,18 @@ def dropout(torch_layer): layer = pb2.LayerParameter() layer.type = "Dropout" layer.dropout_param.dropout_ratio = torch_layer["p"] - # assert torch_layer["v2"], "Only handle nn.Dropout v2" + #assert torch_layer["v2"], "Only handle nn.Dropout v2" train_only = pb2.NetStateRule() train_only.phase = pb2.TEST layer.exclude.extend([train_only]) return layer +def elu(torch_layer): + layer = pb2.LayerParameter() + layer.type = "ELU" + layer.elu_param.alpha = torch_layer["alpha"] + return layer + def power(torch_layer): layer = pb2.LayerParameter() layer.type = "Power" @@ -306,6 +312,7 @@ def build_converter(opts): 'caffe.SpatialConvolution': spatial_convolution, 'caffe.Pooling': pooling, 'caffe.Dropout': dropout, + 'caffe.ELU': elu, 'caffe.Power': power, 'caffe.Flatten': ty('Flatten'), 'caffe.FBThreshold': fbthreshold, diff --git a/torch2caffe/lib_py.py b/torch2caffe/lib_py.py index cff29d4..0f20f8c 100644 --- a/torch2caffe/lib_py.py +++ b/torch2caffe/lib_py.py @@ -141,6 +141,11 @@ def load(opts): assert net, "Net is none?" return net +def load_train(opts): + net = caffe.Net(opts["prototxt"], caffe.TRAIN) + assert net, "Net is none?" + return net + def check_layer_names(opts, expected_names): net = caffe.proto.caffe_pb2.NetParameter() with open(opts["prototxt"]) as f: diff --git a/torch2caffe/torch_layers.lua b/torch2caffe/torch_layers.lua index fae565c..1e8d10d 100644 --- a/torch2caffe/torch_layers.lua +++ b/torch2caffe/torch_layers.lua @@ -224,7 +224,8 @@ M.CONVERTER = { return layer end}, ['nn.Dropout'] = simple{typename='caffe.Dropout', inplace=true}, - ['nn.SpatialDropout'] = simple{typename='caffe.Power', inplace=true}, + ['nn.ELU'] = simple{typename='caffe.ELU', inplace=true}, + ['nn.SpatialDropout'] = simple{typename='caffe.Dropout', inplace=true}, ['nn.View'] = simple{ typename='caffe.Flatten', layer=function(layer) diff --git a/verify.lua b/verify.lua new file mode 100644 index 0000000..4bedee2 --- /dev/null +++ b/verify.lua @@ -0,0 +1,143 @@ +require 'nn' +require 'cunn' +local pl = require 'pl.import_into'() +local py = require 'fb.python' +local torch = require 'torch' +--require 'fbtorch' +-- local logging = require 'fb.util.logging' +local torch_layers = require 'torch2caffe.torch_layers' +local t2c = py.import('torch2caffe.lib_py') + +local function evaluate_caffe(caffe_net, inputs) + local input_kwargs = {} + for i=1,#inputs do + local input_spec = inputs[i] + input_kwargs[input_spec.name] = input_spec.tensor + end + local py_caffe_output = caffe_net.forward(py.kwargs, input_kwargs) + local caffe_output_list = py.reval(t2c.format_output(py_caffe_output)) + local caffe_output_length = py.eval("len(a)", {a=caffe_output_list}) + local caffe_outputs = {} + for i=0,caffe_output_length-1 do + table.insert(caffe_outputs, + torch.FloatTensor( + torch.totable(py.eval(caffe_output_list[i])))) + end + return caffe_outputs +end + + +local function debug_nets(caffe_net, torch_net) + py.reval(t2c.debug_net(caffe_net)) + torch_net:apply( + function(m) + if m.output then + local sizes = {} + local sums = {} + if type(m.output) == 'table' then + for i=1,#m.output do + table.insert(sizes, m.output[i]:size()) + table.insert(sums, torch.sum(m.output[i])) + end + else + sizes = torch.totable(m.output:size()) + sums = torch.sum(m.output) + end + print("Layer %s, %s, Sum: %s", + torch.typename(m), + sizes, + sums) + end + end + ) +end + +local function inputs_to_torch_inputs(inputs, type) + if #inputs == 1 then + return inputs[1].tensor:type(type) + end + local tensors = {} + for i=1,#inputs do + table.insert(tensors, inputs[i].tensor:type(type)) + end + return tensors +end + + +local function test() + local torch_net = torch.load('toy14_1.t7b') + torch_net=torch_net.net + torch_net:apply(function(m) m:evaluate() end) + local opts = {} + opts.prototxt = '1_c.prototxt' + opts.caffemodel = '1_c.caffemodel' + local caffe_net = t2c.load(opts) + --t2c.compare(opts, torch_net) +--end +-- + local inputs={} + local tensor = torch.load('input.txt','ascii') + --local tensor = torch.rand(table.unpack({1,3,66,200})):float() + table.insert(inputs, {name='data', tensor=tensor}) + print ("\n\n\n\nTesting Caffe Model\n\n\n\n") + + local caffe_outputs = evaluate_caffe(caffe_net, inputs) + + + local torch_outputs + -- Some networks only accept CUDA input. + local ok, err = pcall(function() + torch_net:float() + local torch_inputs = inputs_to_torch_inputs( + inputs, 'torch.FloatTensor') + torch_outputs = torch_net:forward(torch_inputs) + end) + if not ok then + error('not ok') + end + + if type(torch_outputs) == "table" then + for i=1,#torch_outputs do + torch_outputs[i] = torch_outputs[i]:float() + end + else + torch_outputs = {torch_outputs:float()} + end + + if #caffe_outputs ~= #torch_outputs then + error("Inconsistent output blobs: Caffe: %s, Torch: %s", + #caffe_outputs, #torch_outputs) + error("Inconsistent output blobs") + end + + for i = 1,#caffe_outputs do + local torch_output = torch_outputs[i] + local caffe_output = caffe_outputs[i] + print("Caffe norm: %s, Torch norm: %s", + torch.norm(caffe_output), torch.norm(torch_output)) + if not caffe_output:isSameSizeAs(torch_output) then + error("Inconsistent output size: Caffe: %s, Torch: %s", + caffe_output:size(), torch_output:size()) + error("Inconsistent output sizes") + end + + local max_absolute_error = (caffe_output - torch_output):abs():max() + print("Maximum difference between Caffe and Torch output: %s", + max_absolute_error) + if 1 then --(max_absolute_error > 0.001) then + debug_nets(caffe_net, torch_net) + if os.getenv('LUA_DEBUG_ON_ERROR') then + require('fb.debugger').enter() + end + if (max_absolute_error > 0.001) then + error("Error in conversion!") + end + end + end + print (caffe_outputs[1]) +-- torch.save('input.txt',tensor,'ascii', false) +-- torch.save('output.txt',caffe_outputs,'ascii',false) +end +-- +test() + From aecfaf9267d17ef8bc4b415ae58b7e0bfea6c365 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 14 Jun 2016 23:27:04 +0000 Subject: [PATCH 09/48] test --- test1.lua | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 test1.lua diff --git a/test1.lua b/test1.lua new file mode 100644 index 0000000..7ffbb87 --- /dev/null +++ b/test1.lua @@ -0,0 +1,86 @@ +require 'fb.luaunit' +local t2c = require 'torch2caffe.lib' +require 'loadcaffe' +require 'nn' +require 'cunn' +require 'cudnn' +--require 'LocalNormalization' + +-- local logging= require 'fb.util.logging' +Test = {} +g_SLOW = "" -- set to "" to run slow tests + +local fwk +if pcall(function() require 'cudnn' end) then + print("Using `cudnn`") + fwk = nn +else + print("Using `nn`") + fwk = nn +end + +local function check(module, input_dims) + module:apply(function(m) m:evaluate() end) + local opts = { + prototxt=os.tmpname(), + caffemodel=os.tmpname(), + inputs={{name="data", input_dims=input_dims}}, + } + t2c.run(opts, module) + return opts +end + +local function check_opts(module, opts) + module:apply(function(m) m:evaluate() end) + opts.prototxt=os.tmpname() + opts.caffemodel=os.tmpname() + t2c.run(opts, module) +end +--[[ +function Test:toy2() + print(model.net) + check(model.net,{1,3,200,66}) +end +--]] +torch.setdefaulttensortype('torch.CudaTensor') +function Test:testToy() + -- Hang Zhang form NVIDIA + local net=nn.Sequential() + local model=nn.Sequential() + model:add(fwk.SpatialConvolution(3,24,5,5,2,2,0,0)) + model:add(fwk.SpatialBatchNormalization(24)) + model:add(nn.ELU()) + model:add(nn.SpatialDropout(0.25)) + model:add(fwk.SpatialConvolution(24,36,5,5,2,2,0,0)) + model:add(fwk.SpatialBatchNormalization(36)) + model:add(nn.ReLU()) + model:add(nn.SpatialDropout(0.25)) + model:add(fwk.SpatialConvolution(36,48,5,5,2,2,0,0)) + model:add(fwk.SpatialBatchNormalization(48)) + model:add(nn.ReLU()) + model:add(nn.SpatialDropout(0.25)) + model:add(fwk.SpatialConvolution(48,64,3,3,1,1,0,0)) + model:add(fwk.SpatialBatchNormalization(64)) + model:add(nn.ReLU()) + model:add(nn.SpatialDropout(0.25)) + model:add(fwk.SpatialConvolution(64,64,3,3,1,1,0,0)) + model:add(fwk.SpatialBatchNormalization(64)) + model:add(nn.ReLU()) + model:add(nn.SpatialDropout(0.25)) + model:add(nn.Reshape(64*18)) + model:add(nn.Linear(64*18,100)) + model:add(nn.ReLU()) + local model_= nn.Sequential() + model_:add(nn.Linear(100,50)) + model_:add(nn.ReLU()) + model_:add(nn.Linear(50,10)) + model_:add(nn.ReLU()) + model_:add(nn.Linear(10,1)) + net:add(model) + net:add(model_) + net=nn.utils.recursiveType(net, 'torch.FloatTensor') + check(net,{1,3,200,66}) + torch.save("pure_toy.t7b",net) +end + +LuaUnit:main() From 9bcc87c91af7e50b1992df7a285d902a244a8d3e Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 14 Jun 2016 23:27:23 +0000 Subject: [PATCH 10/48] test --- torch2caffe/prepnv.lua | 71 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 torch2caffe/prepnv.lua diff --git a/torch2caffe/prepnv.lua b/torch2caffe/prepnv.lua new file mode 100644 index 0000000..549a693 --- /dev/null +++ b/torch2caffe/prepnv.lua @@ -0,0 +1,71 @@ +require 'nn' +require 'cunn' +require 'cudnn' + +local trans = require 'torch2caffe.transforms' + +local function adapt_conv1(layer) + local std = torch.FloatTensor({0.229, 0.224, 0.225}) * 255 + local sz = layer.weight:size() + sz[2] = 1 + layer.weight = layer.weight:cdiv(std:view(1,3,1,1):repeatTensor(sz)) + local tmp = layer.weight:clone() + tmp[{{}, 1, {}, {}}] = layer.weight[{{}, 3, {}, {}}] + tmp[{{}, 3, {}, {}}] = layer.weight[{{}, 1, {}, {}}] + layer.weight = tmp:clone() +end + +local function adapt_spatial_dropout(net) + -- does not support recursive sequential(dropout) + --print (model) + for i = 1, #net.modules do + local c = net:get(i) + local t = torch.type(c) + if c.modules then + adapt_spatial_dropout(c) + elseif t == 'nn.SpatialDropout' then + local m = nn.Dropout(c.p, false,true) + local found = false + -- Ignore groups + net.modules[i] = m + for j = i,1,-1 do + local block_type = torch.type(net:get(j)) + if block_type == 'nn.SpatialConvolution' + or block_type == 'nn.Linear' then + --or block_type == 'nn.SpatialBatchNormalization' then + net.modules[j].weight:mul(1 - c.p) + if net.modules[j].bias then + net.modules[j].bias:mul(1 - c.p) + end + found = true + break + end + end + if not found then + error('SpatialDropout module cannot find weight to scale') + end + end + end +end + + +g_t2c_preprocess = function(model, opts) + if model.net then + model = model.net + end + model = cudnn.convert(model, nn) + model=nn.utils.recursiveType(model, 'torch.FloatTensor') + for _, layer in pairs(model:findModules('nn.SpatialBatchNormalization')) do + if 1 then -- layer.save_mean==nil then + layer.save_mean = layer.running_mean + layer.save_std = layer.running_var + layer.save_std:pow(-0.5) + end + --layer.train = true + end + adapt_spatial_dropout(model) + return model +end + + + From 7712e4c519ec7292a8495b964fbf86fa72bfa786 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 17 Jun 2016 18:07:23 +0000 Subject: [PATCH 11/48] test --- convert.lua | 2 +- torch2caffe/caffe_layers.py | 4 ++-- verify.lua | 25 ++++++++++++++++--------- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/convert.lua b/convert.lua index e29c33d..9806655 100644 --- a/convert.lua +++ b/convert.lua @@ -113,7 +113,7 @@ local function check(module, module2,input_dims) end -check(model, model2, {1,3,66,200}) +check(model, model2, {1,3,64,256}) -- Save the model diff --git a/torch2caffe/caffe_layers.py b/torch2caffe/caffe_layers.py index 5f602aa..30c1cf2 100644 --- a/torch2caffe/caffe_layers.py +++ b/torch2caffe/caffe_layers.py @@ -174,9 +174,9 @@ def pooling(torch_layer): if not torch_layer["ceil_mode"]: # layer.pooling_param.torch_pooling = True - if dH > 1: + if dH > 1 and padH > 0: layer.pooling_param.pad_h = padH - 1 - if dW > 1: + if dW > 1 and padW > 0: layer.pooling_param.pad_w = padW - 1 return layer diff --git a/verify.lua b/verify.lua index 4bedee2..ae40663 100644 --- a/verify.lua +++ b/verify.lua @@ -65,19 +65,21 @@ end local function test() - local torch_net = torch.load('toy14_1.t7b') - torch_net=torch_net.net + local torch_net = torch.load('gienet.t7b') + if torch_net.net then + torch_net=torch_net.net + end torch_net:apply(function(m) m:evaluate() end) + --torch_net=cudnn.convert(torch_net,nn) + --torch_net=nn.utils.recursiveType(model, 'torch.FloatTensor') local opts = {} - opts.prototxt = '1_c.prototxt' - opts.caffemodel = '1_c.caffemodel' + opts.prototxt = '1.prototxt' + opts.caffemodel = '1.caffemodel' local caffe_net = t2c.load(opts) - --t2c.compare(opts, torch_net) ---end -- local inputs={} - local tensor = torch.load('input.txt','ascii') - --local tensor = torch.rand(table.unpack({1,3,66,200})):float() + --local tensor = torch.load('input.txt','ascii') + local tensor = torch.rand(table.unpack({1,3,64,256})):float() table.insert(inputs, {name='data', tensor=tensor}) print ("\n\n\n\nTesting Caffe Model\n\n\n\n") @@ -93,7 +95,12 @@ local function test() torch_outputs = torch_net:forward(torch_inputs) end) if not ok then - error('not ok') + print("\n\n\nGot error running forward: %s", err) + torch_net:cuda() + local torch_inputs = inputs_to_torch_inputs( + inputs, 'torch.CudaTensor') + torch_outputs = torch_net:forward(torch_inputs) + --error('not ok') end if type(torch_outputs) == "table" then From e645528a5b5ad5b491a955341d65b9f4c0d5d43d Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 17 Jun 2016 20:30:30 +0000 Subject: [PATCH 12/48] suport official batchnorm --- convert.lua | 2 +- torch2caffe/caffe_layers.py | 13 +++++++++++++ torch2caffe/torch_layers.lua | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/convert.lua b/convert.lua index 9806655..bc54257 100644 --- a/convert.lua +++ b/convert.lua @@ -79,7 +79,7 @@ local function g_t2c_preprocess(model,opts) model = cudnn.convert(model, nn) model=nn.utils.recursiveType(model, 'torch.FloatTensor') for _, layer in pairs(model:findModules('nn.SpatialBatchNormalization')) do - if 1 then -- layer.save_mean==nil then + if layer.save_mean==nil then layer.save_mean = layer.running_mean layer.save_std = layer.running_var layer.save_std:pow(-0.5) diff --git a/torch2caffe/caffe_layers.py b/torch2caffe/caffe_layers.py index 30c1cf2..bbe33a9 100644 --- a/torch2caffe/caffe_layers.py +++ b/torch2caffe/caffe_layers.py @@ -295,6 +295,18 @@ def bn(torch_layer): return layer +def batchnorm(torch_layer): + layer = pb2.LayerParameter() + layer.type = "BatchNorm" + # Caffe BN doesn't support bias + assert torch_layer["affine"]==0 + layer.batch_norm_param.use_global_stats = 1 + blobs_weight = np.ones(1) + layer.blobs.extend([as_blob(torch_layer["running_mean"]), + as_blob(torch_layer["running_var"]), as_blob(blobs_weight)]) + return layer + + def build_converter(opts): return { 'caffe.Concat': concat, @@ -319,6 +331,7 @@ def build_converter(opts): 'caffe.LSTM': lstm, 'caffe.Eltwise': eltwise, 'caffe.BN': bn, + 'caffe.BatchNorm': batchnorm, } diff --git a/torch2caffe/torch_layers.lua b/torch2caffe/torch_layers.lua index 1e8d10d..0311500 100644 --- a/torch2caffe/torch_layers.lua +++ b/torch2caffe/torch_layers.lua @@ -274,7 +274,7 @@ M.CONVERTER = { false)) end, ['nn.SpatialBatchNormalization'] = simple{ - typename='caffe.BN' + typename='caffe.BatchNorm'--'caffe.BN' }, } From f2c4282ff2b4047253b7947834d3977c01174f7e Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 17 Jun 2016 22:29:10 +0000 Subject: [PATCH 13/48] test --- torch2caffe/prepnv.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/torch2caffe/prepnv.lua b/torch2caffe/prepnv.lua index 549a693..29c9d97 100644 --- a/torch2caffe/prepnv.lua +++ b/torch2caffe/prepnv.lua @@ -56,7 +56,7 @@ g_t2c_preprocess = function(model, opts) model = cudnn.convert(model, nn) model=nn.utils.recursiveType(model, 'torch.FloatTensor') for _, layer in pairs(model:findModules('nn.SpatialBatchNormalization')) do - if 1 then -- layer.save_mean==nil then + if 1 layer.save_mean==nil then layer.save_mean = layer.running_mean layer.save_std = layer.running_var layer.save_std:pow(-0.5) From cecfdd6433feb8fff9579e622923322c8236a0bf Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Mon, 20 Jun 2016 17:42:08 -0400 Subject: [PATCH 14/48] Delete test1.lua --- test1.lua | 86 ------------------------------------------------------- 1 file changed, 86 deletions(-) delete mode 100644 test1.lua diff --git a/test1.lua b/test1.lua deleted file mode 100644 index 7ffbb87..0000000 --- a/test1.lua +++ /dev/null @@ -1,86 +0,0 @@ -require 'fb.luaunit' -local t2c = require 'torch2caffe.lib' -require 'loadcaffe' -require 'nn' -require 'cunn' -require 'cudnn' ---require 'LocalNormalization' - --- local logging= require 'fb.util.logging' -Test = {} -g_SLOW = "" -- set to "" to run slow tests - -local fwk -if pcall(function() require 'cudnn' end) then - print("Using `cudnn`") - fwk = nn -else - print("Using `nn`") - fwk = nn -end - -local function check(module, input_dims) - module:apply(function(m) m:evaluate() end) - local opts = { - prototxt=os.tmpname(), - caffemodel=os.tmpname(), - inputs={{name="data", input_dims=input_dims}}, - } - t2c.run(opts, module) - return opts -end - -local function check_opts(module, opts) - module:apply(function(m) m:evaluate() end) - opts.prototxt=os.tmpname() - opts.caffemodel=os.tmpname() - t2c.run(opts, module) -end ---[[ -function Test:toy2() - print(model.net) - check(model.net,{1,3,200,66}) -end ---]] -torch.setdefaulttensortype('torch.CudaTensor') -function Test:testToy() - -- Hang Zhang form NVIDIA - local net=nn.Sequential() - local model=nn.Sequential() - model:add(fwk.SpatialConvolution(3,24,5,5,2,2,0,0)) - model:add(fwk.SpatialBatchNormalization(24)) - model:add(nn.ELU()) - model:add(nn.SpatialDropout(0.25)) - model:add(fwk.SpatialConvolution(24,36,5,5,2,2,0,0)) - model:add(fwk.SpatialBatchNormalization(36)) - model:add(nn.ReLU()) - model:add(nn.SpatialDropout(0.25)) - model:add(fwk.SpatialConvolution(36,48,5,5,2,2,0,0)) - model:add(fwk.SpatialBatchNormalization(48)) - model:add(nn.ReLU()) - model:add(nn.SpatialDropout(0.25)) - model:add(fwk.SpatialConvolution(48,64,3,3,1,1,0,0)) - model:add(fwk.SpatialBatchNormalization(64)) - model:add(nn.ReLU()) - model:add(nn.SpatialDropout(0.25)) - model:add(fwk.SpatialConvolution(64,64,3,3,1,1,0,0)) - model:add(fwk.SpatialBatchNormalization(64)) - model:add(nn.ReLU()) - model:add(nn.SpatialDropout(0.25)) - model:add(nn.Reshape(64*18)) - model:add(nn.Linear(64*18,100)) - model:add(nn.ReLU()) - local model_= nn.Sequential() - model_:add(nn.Linear(100,50)) - model_:add(nn.ReLU()) - model_:add(nn.Linear(50,10)) - model_:add(nn.ReLU()) - model_:add(nn.Linear(10,1)) - net:add(model) - net:add(model_) - net=nn.utils.recursiveType(net, 'torch.FloatTensor') - check(net,{1,3,200,66}) - torch.save("pure_toy.t7b",net) -end - -LuaUnit:main() From 42fddeef93a0db7d53cd6c6eb82c60336230468a Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Mon, 20 Jun 2016 17:50:01 -0400 Subject: [PATCH 15/48] converter --- conversions/conversions.py | 370 ------------------------------------ doc/caffenet.png | Bin 54500 -> 0 bytes doc/googlenet.png | Bin 67711 -> 0 bytes predictor/Optimize.cpp | 217 --------------------- predictor/Optimize.h | 21 -- predictor/Predictor.cpp | 173 ----------------- predictor/Predictor.h | 70 ------- predictor/PredictorTest.cpp | 117 ------------ 8 files changed, 968 deletions(-) delete mode 100644 conversions/conversions.py delete mode 100644 doc/caffenet.png delete mode 100644 doc/googlenet.png delete mode 100644 predictor/Optimize.cpp delete mode 100644 predictor/Optimize.h delete mode 100644 predictor/Predictor.cpp delete mode 100644 predictor/Predictor.h delete mode 100644 predictor/PredictorTest.cpp diff --git a/conversions/conversions.py b/conversions/conversions.py deleted file mode 100644 index 5c9504f..0000000 --- a/conversions/conversions.py +++ /dev/null @@ -1,370 +0,0 @@ -""" -Copyright (c) 2015-present, Facebook, Inc. -All rights reserved. - -This source code is licensed under the BSD-style license found in the -LICENSE file in the root directory of this source tree. An additional grant -of patent rights can be found in the PATENTS file in the same directory. -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - -import logging -import itertools -import os -import tempfile - -import click -import numpy as np - -import caffe -import caffe.proto.caffe_pb2 as pb2 - -import google.protobuf.text_format - - -log = logging.getLogger(__name__) - -THRESHOLD = 1E-3 - -# TODO - refactor this in to a sequence of (prototxt, caffemodel) -> -# (prototxt, caffemodel) passes. - - -def flatmap(f, items): - return itertools.chain.from_iterable(itertools.imap(f, items)) - - -def load_prototxt(params_file): - params = pb2.NetParameter() - with open(params_file) as f: - google.protobuf.text_format.Merge(f.read(), params) - return params - - -def convert_fc_layer(net, fc_layer): - conv_layer = pb2.LayerParameter() - conv_layer.name = "{}_conv".format(fc_layer.name) - conv_layer.type = "Convolution" - conv_layer.bottom.extend(list(fc_layer.bottom)) - conv_layer.top.extend(list(fc_layer.top)) - # get input - assert len(fc_layer.bottom) == 1 - bottom_name = fc_layer.bottom[0] - bottom_shape = list(net.blobs[bottom_name].shape) - if len(bottom_shape) == 2: - bottom_shape.extend([1, 1]) - - num_output = net.params[fc_layer.name][0].data.shape[0] - assert bottom_shape[-1] == bottom_shape[-2], bottom_shape - conv_layer.convolution_param.kernel_size = bottom_shape[-1] - conv_layer.convolution_param.num_output = num_output - return conv_layer - - -def convert_fc_prototxt(params_file): - params = load_prototxt(params_file) - - def find_layer(name): - (layer,) = [l for l in params.layer if l.name == name] - return layer - - def f(layer): - if layer.type == "Flatten": - new_layer = pb2.LayerParameter() - new_layer.CopyFrom(layer) - new_layer.type = "Reshape" - new_layer.reshape_param.shape.dim.extend([0, 0, 0, 0]) - return new_layer - if layer.type == "InnerProduct": - new_layer = pb2.LayerParameter() - new_layer.CopyFrom(layer) - new_layer.inner_product_param.axis = 1 - return new_layer - return layer - - new_layers = [f(l) for l in params.layer] - new_params = pb2.NetParameter() - new_params.CopyFrom(params) - del new_params.layer[:] - new_params.layer.extend(new_layers) - return new_params - - -def convert_spatial_prototxt(params_file): - net = caffe.Net(str(params_file), caffe.TEST) - params = load_prototxt(params_file) - - def find_layer(name): - (layer,) = [l for l in params.layer if l.name == name] - return layer - - def f(layer): - if layer.type != "InnerProduct": - return [layer] - return [convert_fc_layer(net, layer)] - - new_layers = flatmap(f, params.layer) - new_params = pb2.NetParameter() - new_params.CopyFrom(params) - del new_params.layer[:] - new_params.layer.extend(new_layers) - return new_params - - -def convert_spatial_net(spatial_params_file, spatial_weights_file, - conv_params_file): - spatial_net = caffe.Net( - str(spatial_params_file), str(spatial_weights_file), caffe.TEST) - # Initialize from the SPATIAL layer - conv_net = caffe.Net( - str(conv_params_file), str(spatial_weights_file), caffe.TEST) - spatial_params = load_prototxt(spatial_params_file) - - converted_layer_names = [ - (layer.name, convert_fc_layer(spatial_net, layer).name) - for layer in spatial_params.layer - if layer.type == "InnerProduct" - ] - - for layer_pair in converted_layer_names: - log.info("Converting layer pair: %s", layer_pair) - (spatial_layer_name, conv_layer_name) = layer_pair - spatial_params = spatial_net.params[spatial_layer_name] - conv_params = conv_net.params[conv_layer_name] - - assert len(spatial_params) == len(conv_params) - for spatial_param, conv_param in zip(spatial_params, conv_params): - log.info("Spatial Layer: %s - %s, Conv Layer: %s - %s", - spatial_layer_name, spatial_param.data.shape, - conv_layer_name, conv_param.data.shape) - assert(conv_param.data.size == spatial_param.data.size) - conv_param.data.flat = spatial_param.data.flat - return spatial_net, conv_net - - -def verify_equivalent(fc_net, conv_net): - log.info("Verifying convnets") - input_names = fc_net.inputs - log.info("Running on inputs: %s", input_names) - inputs = { - input_name: np.random.random( - size=tuple(list(fc_net.blobs[input_name].shape))) - for input_name in input_names} - - fc_outputs = fc_net.forward(**inputs) - conv_outputs = conv_net.forward(**inputs) - # Verify convolutional model works - for k, conv_output in conv_outputs.iteritems(): - log.info("%s: %s", k, conv_output.shape) - fc_output = fc_outputs[k] - delta = np.amax(np.abs(conv_output.flatten() - fc_output.flatten())) - log.info("Maximum delta: %s", delta) - if delta < THRESHOLD: - log.info("Delta: %s < threshold: %s", delta, THRESHOLD) - continue - - log.info("Conv output: %s", conv_output.flatten()) - log.info("FC output: %s", fc_output.flatten()) - for ((fcn, fcb), (cnn, cnb)) in zip( - list(fc_net.blobs.iteritems()), - list(conv_net.blobs.iteritems())): - log.info("FCN: %s - %s, CNN: %s - %s", - fcn, fcb.data.shape, cnn, cnb.data.shape) - log.info(np.amax(np.abs(fcb.data.flatten() - cnb.data.flatten()))) - raise Exception("Failed to precisely convert models") - - -@click.group() -def cli(): - pass - - -@cli.command() -@click.option("--conv-prototxt", type=str, required=True) -@click.option("--output-scanning-prototxt", type=str, required=True) -def scanning(conv_prototxt, output_scanning_prototxt): - """ - Add a scanning layer on top of all softmax layers, so we max-pool - the class probabilities over spatial locations. - """ - conv_params = load_prototxt(conv_prototxt) - - def add_scanning(layer): - if layer.type != "Softmax": - return [layer] - scanning_layer = pb2.LayerParameter() - scanning_layer.name = "{}_scanning".format(layer.name) - scanning_layer.bottom.extend(layer.top) - scanning_layer.top.extend([scanning_layer.name]) - scanning_layer.type = "Pooling" - scanning_layer.pooling_param.pool = pb2.PoolingParameter.MAX - scanning_layer.pooling_param.global_pooling = True - return [layer, scanning_layer] - - scanning_layers = flatmap(add_scanning, conv_params.layer) - scanning_params = pb2.NetParameter() - scanning_params.CopyFrom(conv_params) - del scanning_params.layer[:] - scanning_params.layer.extend(scanning_layers) - scanning_prototxt = tempfile.NamedTemporaryFile( - dir=os.path.dirname(output_scanning_prototxt), - delete=False).name - with open(scanning_prototxt, "w") as f: - f.write(google.protobuf.text_format.MessageToString(scanning_params)) - # Verify the net loads with the scanning change. - caffe.Net(str(scanning_prototxt), caffe.TEST) - log.info("Moving: %s to %s", scanning_prototxt, output_scanning_prototxt) - os.rename(scanning_prototxt, output_scanning_prototxt) - - -@cli.command() -@click.option("--fc-prototxt", type=str, required=True) -@click.option("--fc-caffemodel", type=str, required=True) -@click.option("--output-spatial-prototxt", type=str, required=True) -@click.option("--output-spatial-caffemodel", type=str, required=True) -def spatial(fc_prototxt, fc_caffemodel, output_spatial_prototxt, - output_spatial_caffemodel): - """ - Remove `Flatten` layers to preserve the spatial structure - """ - logging.basicConfig(level=logging.INFO) - - spatial_net_params = convert_fc_prototxt(fc_prototxt) - spatial_prototxt = tempfile.NamedTemporaryFile( - dir=os.path.dirname(output_spatial_prototxt), - suffix=".spatial_prototxt", - delete=False).name - with open(spatial_prototxt, "w") as f: - f.write(google.protobuf.text_format.MessageToString( - spatial_net_params)) - log.info("Spatial params: %s", spatial_prototxt) - fc_net = caffe.Net(str(fc_prototxt), str(fc_caffemodel), caffe.TEST) - spatial_net = caffe.Net(str(spatial_prototxt), str(fc_caffemodel), - caffe.TEST) - verify_equivalent(fc_net, spatial_net) - - spatial_caffemodel = tempfile.NamedTemporaryFile( - dir=os.path.dirname(output_spatial_caffemodel), - suffix=".spatial_caffemodel", - delete=False).name - spatial_net.save(str(spatial_caffemodel)) - log.info("Moving: %s to %s", spatial_prototxt, output_spatial_prototxt) - os.rename(spatial_prototxt, output_spatial_prototxt) - log.info("Moving: %s to %s", spatial_caffemodel, output_spatial_caffemodel) - os.rename(spatial_caffemodel, output_spatial_caffemodel) - - -@cli.command() -@click.option("--spatial-prototxt", type=str, required=True) -@click.option("--spatial-caffemodel", type=str, required=True) -@click.option("--output-conv-prototxt", type=str, required=True) -@click.option("--output-conv-caffemodel", type=str, required=True) -def convolutional(spatial_prototxt, spatial_caffemodel, - output_conv_prototxt, output_conv_caffemodel): - """ - Convert all fully connected layers to convolutional layers. - """ - logging.basicConfig(level=logging.INFO) - - conv_net_params = convert_spatial_prototxt(spatial_prototxt) - conv_prototxt = tempfile.NamedTemporaryFile( - dir=os.path.dirname(output_conv_prototxt), - suffix=".conv_prototxt", - delete=False).name - with open(conv_prototxt, "w") as f: - f.write(google.protobuf.text_format.MessageToString(conv_net_params)) - log.info("Conv params: %s", conv_prototxt) - - (spatial_net, conv_net) = convert_spatial_net( - spatial_prototxt, spatial_caffemodel, conv_prototxt) - verify_equivalent(spatial_net, conv_net) - conv_caffemodel = tempfile.NamedTemporaryFile( - dir=os.path.dirname(output_conv_caffemodel), - suffix=".conv_caffemodel", - delete=False).name - conv_net.save(str(conv_caffemodel)) - - log.info("Moving: %s to %s", conv_prototxt, output_conv_prototxt) - os.rename(conv_prototxt, output_conv_prototxt) - log.info("Moving: %s to %s", conv_caffemodel, output_conv_caffemodel) - os.rename(conv_caffemodel, output_conv_caffemodel) - - -@cli.command() -@click.option("--conv-prototxt", type=str, required=True) -@click.option("--scale", type=float, multiple=True) -def scales(conv_prototxt, scale): - """ - Examine the network output dimensions across a series of input scales. - """ - logging.basicConfig(level=logging.INFO) - - net = caffe.Net(str(conv_prototxt), caffe.TEST) - input_names = net.inputs - input_shapes = { - input_name: tuple(net.blobs[input_name].shape) - for input_name in input_names} - - for scalar in scale: - log.info("Running on scale: %s", scalar) - - def perturb(i, n): - # only perturb HxW in NxCxHxW - if i in (2, 3): - return int(n * scalar) - return n - - inputs = { - input_name: np.random.random( - size=tuple( - perturb(i, n) - for (i, n) in enumerate(shape))) - for input_name, shape in input_shapes.iteritems()} - - for input_name, input in inputs.iteritems(): - log.info("Input: %s, shape: %s", input_name, input.shape) - net.blobs[input_name].reshape(*input.shape) - net.reshape() - conv_outputs = net.forward(**inputs) - for output_name, conv_output in conv_outputs.iteritems(): - log.info("%s: %s", output_name, conv_output.shape) - - -@cli.command() -@click.option("--prototxt", required=True) -@click.option("--caffemodel", required=True) -@click.option("--output-prototxt", required=True) -@click.option("--output-caffemodel", required=True) -@click.pass_context -def vision(ctx, prototxt, caffemodel, output_prototxt, output_caffemodel): - spatial_prototxt = tempfile.NamedTemporaryFile( - suffix=".spatial_prototxt", delete=False).name - spatial_caffemodel = tempfile.NamedTemporaryFile( - suffix=".spatial_caffemodel", delete=False).name - ctx.invoke(spatial, - fc_prototxt=prototxt, - fc_caffemodel=caffemodel, - output_spatial_prototxt=spatial_prototxt, - output_spatial_caffemodel=spatial_caffemodel) - conv_prototxt = tempfile.NamedTemporaryFile( - suffix=".conv_prototxt", delete=False).name - conv_caffemodel = tempfile.NamedTemporaryFile( - dir=os.path.dirname(output_caffemodel), - suffix=".conv_prototxt", delete=False).name - ctx.invoke(convolutional, - spatial_prototxt=spatial_prototxt, - spatial_caffemodel=spatial_caffemodel, - output_conv_prototxt=conv_prototxt, - output_conv_caffemodel=conv_caffemodel) - - ctx.invoke(scanning, - conv_prototxt=conv_prototxt, - output_scanning_prototxt=output_prototxt) - log.info("Moving: %s to %s", conv_caffemodel, output_caffemodel) - os.rename(conv_caffemodel, output_caffemodel) - -if __name__ == "__main__": - cli() diff --git a/doc/caffenet.png b/doc/caffenet.png deleted file mode 100644 index 5a80e5269f63013450bb40fba84fee9a6b6774f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54500 zcmeHw2{e?^-~SNV!iZ8?3#lxlWGUNdp=6m>q)?J%-}hxGDn%P2dxfHqHG4_2C;Kv% z#MoxWJ{U9ee-uLE{h#wY=l{O{_i;|=JU!2S?((^x`}uzFckaEha^h~FCXLqF(yb9X zXK3j}pcH$fr4*e5+hx9gR60R+n`=@chO&;cPQTb#->@Rl}Y9w2()_UtXU{-1(*SjOpH#yZ+-oO*D`LfyJ9+DR~9` zt1FD+K1o|s-VvGR|d-r_TfYR>2B!<9NP|TwGmJdH|5lf8=j@y=_AA_cjn<%F2SC=_CLq27V!poXURzM z?Q^UkDJq6KG-W+Nu zr+(m*uN&JQh=<~5>JO~$x{ptbe)XM!v0gN`U^>J9VtRAHreU@p!k4%liY^aBn_LR7 zKalyM-tDeBJ)(U#{}|6zNKL?v10TH^wT(XQrphJPxsCD53XDU!S#KDh0bVNMDG%9ce&XRHKSZjL&;m3kgE*e_IZN-F~9af#Z&Vn#^GI+tI?`)*gmrQit@zpC4?R8s!`<{)j^tqa-_Iq0rA<)r&pWJ+wL$gxsqP-z{E(l2OBdg+ zYdha_?mb@iQ01E7nSj}QoJZC9*dKBKlpKX_hwJi1A~wB>DU08I^N#v)uG1O^w>?lY zihg~A>7wV>Xp?XBX&X_#lF@NB<$a84%x*{~1IUx&ZO@pl`yaa6t|c9G=av2u)BP8` z0u3az_!{UtCL|J>IX=t(I2PtFZe^1tzhQV=*aLK@-$=cqfUd7p7uS@;>`wVx9s=KJ zcTkCYiSK*})i@zgA;893M(0ASOlQ>PKOmUPxB2d-7?v6eY$esz!&Vel5>^}|kdy~a zM_pApcRxCDlVAL?(B81myLukoJE?Pma3b!6=1Jm9=4;yTC7VNsl-2piN^k$P9@QN^ zIeLCneDuzJulvaRsj69wrJ{jvAIj}+=eAuga z>Sa$&!?yurqZ`aOcz*U-Z?#5RbAAx8K5wmNt=XenR{oXat4mpR5bPl=SV7q1xI02o z=_BH!4)Rs9R%Jq_Ay4rBeRbO!>b{RRvfVJR zk$rI}zWCedHcpqBXm0CY!PHOZD};YJQbMI^sI-%+fI;GTE2oQS>?XIj~8l z$s+_M0tJnmFTd|wrab>Le-{4)E|@e+SZ-L5G?&9npD8X3?fP}vg54%~Q*fSWb=-Ef zZuM3n%8lSqzQky0~XoyZ)2nex0Z#7DjnG$jTBCE^;a)wb1c5wJYryj!}; zdF?JTF0fJav5&5^ZYr+Xu7R!wu0n1+Q~fiqW+bKj~^{0G>2`ox1hgb^K z1l0qc=}HidU!MQ@>Fe0(@%TfhU0$>wcR8N)AfLm4lkc8!Kwv=lb{!sqe3jrk;de0i zo3k-f<#YpdxwnFjow;iIBjR({_Iz>4%DzZrsZ___N^Pao-pXug9XI>lAy%88=;U5b z^3DP zRn`1doPX0+Z0T`pqn?bPdy8JE$9>frf6{j)U&sAC$@fEw4RiI`u#(8eLmjrHH`CSh zv-IxTo-lpb4ZZkO%jQqMezNSCOZSD*01Z{r{#{1-JBda zrJzH+G&0r~`c&ew38wKv65qS-q?`}!Zf=)Du4*ebcQZzFgi0Qe3Nm%gF|LaB>&fV8 zl{zcwCy76Q>s*>?O~-rla&%c*8OM3u^E4SZO)sZU5GAWJ66(3@AGAtj2Ah-9yfeES z)XCv$5vz(0?D>ew`gh}XS6tvYDH#&_wOaZprldaC(p?u;a7i-RV%=L$E!=U1lKBzaJP z+Osho@@;cxGevv%9_#Of;A7DK@Y7y}3Rn8M)OJlm>YO3aR5nkjqta`iO32lHuJ-~u zYPcckDIqru9zVZoAoAe&?aXbTd~0f?LLmYaZl&-%`cCC(_Dysq3b*bIr~&f?I?EHK_GHi*2)Peg!dR+k?WHw?K+w5 ziAQZ%vry)*C`813sl@!jN{0^0GQ8;{w98%vS@G7?ukG8 zjB)2bvHYDCb-K$sWl6fS|d**ej4Zq{*b@)~@bZy>2pPAq5?CXo?9Ng#P;$moGVqy^2qNV6I)>~=a{pG=d$Z9EjNA}%o!-l*< zwfo7*5AHSYv`z2Ad0ZYt?=I3{-U+C5WXG4mKVY4HOLjt%PJSsVDe1vvc8EG)+oo+hV{_V)y|VRQ z!d_=)WJr>-dm;y>sn;1!uIl;|`#cL+jNJk`fW~x~M@3Ibb zcUT>FpfJ+ra!=ObEN?16Bbym}!8Q959tEU=w(eQG)N5N22qX0l?AjpFvLO&OS2>Qa zIeL*5z=*5pZw+4p~2c)2P9HYK^)8;`$!hux08K>9A^s8`GR8?3$YVDx`-26?n1bZ`O%#w^^O_BkYaR$txqhnZaHX#+zMU?^f)7#9phfT4(GKP`cwi23mW{`@mP0|!G9U?^hQFL7Wf0t`hg z`w0{bMS!6QFch)OuU;4*{|`bDVwJhMbBiJnPYOQ@;>${SxSqZ!>c(ol2=(t3K1m%^ zZrJ=mOsKlRGNs~r{*sFNx@_pcG9Q)KT@p+Gt!nEOZUs0=} z>?9?7T=00vQMwAW-)LaRhco$Oje4+DBeznqrwN10Jj#X4fmJsiX1^C~#H(~xeZ1mC zMs+;JcM!7f3(^m~`E=6xS$-6^gGR4{e5l}-WXaXnVr&wLisHUlHvt4eEme>;H*C+S zYGhkqRCH507Actp_kc~}W2IK@3MjAGEzh_<#^}Bs%gou|3s#aZz!md?zHV51i49zz zmV$Z$dhea$vMKi8d7A*sMojL?u9J$&2Z}&2gOyvL%N$%Faw`V`$hp6U(f_W|8f(JS zMM1TLRZBFer;(>^p8|12rl%cMWS(={fJ5nBs<2+R{j1!O-o~=x@|;KBm20fWllBEx z654DF<%?9)|8Oa&H4__@=`o2dEvY%7=ytKDeKgSGl90!Eiv;zAF^e1bZz_JfRfzH~ z8co0}h~jbFb{*ut!SdZl_(O1SdZZ(fL$nt#Gr{kk zDv+^4^aC^9)<>3V{L9S|?`}1b9W^nTIA0S17Qe)eHt1;Y#QrWkpr?DXW zJc$4pox5Jyd7jl>N@MS$+C$aKx`^F2j?T)75%|a7C15)&;)54bYN1a5YNZA33oH z!*2f;#v2!+$l6hnZTXsI@0+(skac?9LaM)shhgktaYKeCQvT*kMRdMQBob)Q z2JdXn`CjStqhgZ(ph+UpNR`!e{qQ3-dAMvso>$CEl@alnaOeWr$8=+m7}mPGHdA)=?DCR9m*U?y@Rjz#B0#>r>uK(bkK`8! z5LnVrzuO?4Uf4x^F$yD(>-AticD+vOV&$Q|FZg2gtwq7542O)_qKxNWaBoUt#}o2M zm2Z!SLRS42t?rFdX`7L`lx{n->WNM72Rm{vh$^^zB$re>3XMk;Orh~*f|=OcTN90B z?Ij}H2_oe&6@tFe_!zJ3P@O`>zo0c^Xv?wDa-a3~5aA(JS7xv?HkmgNizX8+a?jb@ z8&TBW2li83?3~27^q|SZIF!^xuFGh5Obq(DvS(p0)yxq~50ALq;hs}H-vje18C9%% zobW2FZOU@5d7fk1_{Q&gZZMYsHiKNg@{>o%w#OgSOD=+?Z zDmGHd=6ibaX&5H&aAe~~?UPd{R(AJ-n?3Jva%@2$ES@$Nue~G~t}hT3r3>cvM?wGR zgx^FqS6!HH$kY?1$;8FkZ@W5OdhOixR+6y=?Wsmy#EZh) zdD>1B50Zk=@36rmO=A@|E53%%hFt*6V#KV%>}aY>T;8o}mlOI2cLYkc&!R@t6ZC>B`>MfVbsEos)YTSKAN2uKwPg7Q5xNtXM zb5lENKsN%D&_f~?zu@kz=H59R6@|?gn*4MjM0Iz7-VCif!>H@Ge;BBci`|n16 zds;{$sZV1&@*CvFGGC`33GR=OavQa=R6?EdR?lRsi=OgXWx4*g6L3X2=*#kjoVf)6 zX(|sy<9Q~a9xJT*?;0a}slQZO+)(^8W|o@rMHz}e0$03zd=t~!Q$pke!uHmO zf9y1pkwG|zN37tIaCwXi&x6_IX-1ozSp(W}{8bN)zvr}wC!Su}f4qXZ3LtIviecQV zW{ZV#dYZlS4s3Uceq*!!s)27rHG9tw@f^c!31d_7<#Y2wCw2rP5>FLQE~U;EgpOD9 zOUp+DcfWALZwjt?qE}=TMmt{p0j=jx!qYe0X!8s00IZ3cu8%R7n z%HzlQZ6ap0je)Qw?8}PXe1#T(?@^FGoWM_6jul{sUH*V*cO7Id%X3kt9}xf9&Rz#| zowf$T5;8^SUH8rNw{wL?GZL=CG9)p9i#ELrC#W=mn`4*y}H{HBZSP4iclxuG4&p!kN$Ma zUt^Zon@xQdE5!fP21JddL-z~C8g1Dko(=d??J5~k}CJKKZT6T#zn0&8xZ zD}Bw$mkK9W^rKMP%{f`&As_#-<53J)!S4)L4F+cPh1yh;FzizjisNq;oxc-xo+4>y z>&^F*3ju%yi@coba6=$cQATOS`Hz~ANk1m{_*2Jp<-h(!; z|Isz4Imiou;d{H=1hxhkWv5TNE}R7bBs;e|D(amuv}Eo5J=Y6Z?E%;OO zeXIzC=GHsit9R7`4nWUR+a;8?_$}O6y-k6@L|%yDv(?%te|rOglVDEb% z^$+PkbzLpn8|Q(z3rM-&{qmoq97wa}dIHjH$>0NNwnQyKHCqD4e^Ubrsu`$et9vYf za{;Q^k^u~=*%B~7HCsB-0;d3f=1~6|W}TqX{GVtvJIT#CksW2&)J>gwdU`HDMy?$W zQ9b#+*Y~iQB9tzDmoVa`xt47a{mxr;<}3_bO{X@%j|?TKm_C9E-O}2XVsLpYwPfJF zhb?fp%3glV%dw(-ymb}7@`IR)u!?Y-A-p`^MgYCLyBp`$QQdu4L?HvV9Hpg-@eG*f zYw>Xgd~z z0H98QIIBFMkP|Br06DP|5l|;UPJo$WVEPCNA0B}9{l1<6LQ4rvI@Ojexhq(5C z#jnEKY<15oX>@qFIn%tc#Saz~U~$Ri@{36geJ2(n9!}F1;@EjYFxfd%geh2Mzz>e! z7O+KHPB){`T-Qw5mwi-jM?iS7&{}5z4*AWM?T3wv?U?Q-PR4oQlQ7sfaT90j2%}6F ztg1la6{Fn~PeX@aFI56?fXfA4-?hIS?^(zToWsrEwqB}4 z;7Ac|C$6=>_fA3S4V3xNQey?KOEy;i+DMlQoT6gXV<)|${eL#u{eFKFP^RK1xph)i z0EfjyfS@hxz5+p8DnB68mJLO4crMYHLQvBdL}N~%K|`?AH2`ceXg&YXXj?Evx{-UYOxNG6b?=_6oO~dqdmdro*M|X$WI(Fn zx#R}1J$X4sZwc+(9h~XxuN(E=d+1%VkE99bhP942G^GkLE z-#@{b){_W%E||CPqU6sZEW-PyZ=&*NN$HbOISzBjrX!UZ#;GR=`07?YH?%K?G@Z@G zIn^7lY~oaToNgQ!4Ab?9bt4Ar^Edbs(O;AaK&0%=YKebagC!en^sF90B;! zN}ikOb2W66_P&c5QsY5Xv_rmdGPyJdRjV>v>Cj>BfDI>*d)+_lx|fsUX7oJzon5-? z(QI`+wFh`txMY^ifTvcjUf8|pMan*c>z(0oC{UVq{D43xJPPweZ|-9lc!70$Prfex z_wmBW5(Y=Fv=V}&$cn5NduRSa75Mr<1nu|z>o~u|j=+)h-EO%-znp=g%)(eba+ktn z>y{kmC74ts~RGeNMCAM*v@Eam2N2 z6G$=&#`r2plnt?J6zXDiLr+Byn6T&(+a~O@q=$1$T^?l%06lFvO{vf??@u1~=&-=G z%Z+jN2lM#S9Y&IDVuZ?zCY|wzYD%rUYpW73rYbS#{X4CDv2S)hbjh6h%L;oU@XLd@R(4aulAynz$ zG7RyIXUwTYb@WkN>R^{WVu{5#_gAQVJIwo%k*Pn$(q4M(={57XQ%?97@=esp<9LJG z@}lE11G+OF4z23?Zplu4j)j&oaEo8Z_UX`#^Ed?gG0Xc4#b@psS7HUYX-EF>s`~D3 zAG?K*5&)d#VjbqJliB*rY6bIGbZ~M4rMs82<`Z$L6%PQ5)J{LH@Q7rOKPQVu)s|+l z@IDl@Y$JZT%b^+2(w_qBLccQMqkQ`|JD@`$+ok{|qa(pn8i|#QA%_RR>^1mo4Ev=f zWW#?J=cfmlvkziw{&eo*j6^oQkeF&mcu_z^PpadKF>0C@2=)CMY6B2TL#mk{1CwKM z80Pj|RQ_a7bx=q-FBPq-;Bc*r5vH2l<$}qvC}?%#jKsFN$-eeD{KA4bZ@poLM|hjQCS?nXH;e@EZgEXVM~QB`_h^;IEVc^D`*2TGl)7rY`jU=b@^oQT z?EzAOdCg(;-xsfB)k|fob>m}d$>$9XD216|HN5r1+(Z=ZP)MON*&NqA&>)a3MM*5d zcHw5S3D2+@d2n2#OExA5aA`6}53C}w$P6vhmSFSn3=Y8(9=1A~eK&Dism@R}Ty7m5 zwGqU$Y|+ctD6QkBk{7ki(n`}b4@<-IBxc9VbSF)8XzWV9#F=K~&(0H6C(q-&Ij20g zK{>0u4&Ss2_cEZ;hhCNn zPkH~I3^pkud%9xWq6uny%&8`Ub3^lzN?YfJmL3@(&r=nb)g}-C-4=27>sXg8cqnZimmQwd`F-qdfBsn#=(Ov=$<9GTt zhC&}BYLI5a`rg+LFHvYw4Y;D4(}Q3tlt4k6{#!8(=|b{? zp~_9K|8$f+aPEB`>;CPJf0cE~zt9Gyp;6#OXy}p6Ql1yG2$fDH{F65pxz1y+tA@Y) zd3jEe^lu`I>u3%KETZ&}3)eZT^W@y@_PT6o-(1iL{T>TmtzhDAlW=LR%x<`vuZEto1{ zA~rm!(X93<72l-*S36vz%w&Z5uflF1^B>9|(#_}~m7!aSspkiG3@GajNl=NNh$2rB zzZ6~ZZ*mUcDWNK>ep0E>UdnlIs+VimqVCVs8vR&*P<6&@CXhoA zQ#NWjD4x3$0A^AVun9?#oaqXrO1(B;JIpHIP2p9CD{`^FzD;{6vCu?HqgATIF&%|* zzo({^y<}Z|7`D7a36cr7+}1tZdeTJz4Oo zRd)itcBE$ht4;q*Ed~_LEnrQtq=41>8O&`3Kp<`_1OQ|R$dHx4x-M58kRc#L{?{{P zn2bSHnsZV^Z`W{>;diJvH>VuA6RcmvI+Et}?8MIf;vxRY*D9_)?CT%=E*F#tHBhq) zAH~+rpTl3cm6CE|>pk6hpL)U8|23@?rKhc9zw5eT1>siu2&OxE5f;&X5`X()%kFf> zc*5NteUqbT)liGOV}e^!3}zXp0lbb03BH}Vf3A5P3Q@9 zL!0BP_ga1^$kTRr$D>Bk#+BZKam7|?WXGBfr_v25 z6h+QVBo3ZjPM*Ko$Sc5$i2GT&O5|oqOW+}%@XPj=gKMA!)E3NYuFF8Ievug@14xEN zMFq(Kk^v;c90wNdFK8w}GXauex!((#3D8U|DkMk-kPILhK%Zfe1B(}+GJwhek^xkP zMGh=pfXVNfozODc}(%#vidJX&%mMmA0OI< zC|yE?dR$MxO;Skjs-Q29CC|bF>WCK13_5~Glc5gAu1zNO*TyA1nz57~`tU+~d4TWF zTl1Yatg4U63ID9l773&ggoz=S6#JdU#ZmiCBs@4FSG=Zy zg@u=jg@x0Oe+qbl=kTZu3yYY_{OVQp>sPNbtJ~X{np-}=!cu(x?lzu|W<7O`o(4Vv z57~)}@uITs?}jDYE94cipPsqGoZS0b4!7sY3;Y)^G9F(jq6T+Ac@`~~b=QbH`Sa(O zxOA6n-eB!`+Q5*dYhHrLmT-sW-RZ&b$g@}zR(G&vIa0B})F3t5SwwY!n&SO8dsz45 z@GoTLn`JxT#*mYDQ$`D3y0kcQ?bTliQ75_-&y zCm*+--f(wV!@0LheeVGa8$Q-+?wS;h&nz|d8kQHcp9ih`_2OX(ysJKwh|SCy)Y52{ zR4HbU{fuXuo{?#cfvh;YLx=tuiaF-ZyLYFvrKs+WPawuV?ddg6Jb%xvJ%CS}dD&N-s%X?c7@#9Ncx9$lElm#YnC^7F|A}%>0Ds?0p}{^7(U?j89>o&O;vKK4qq|g>Jt$9XzipQ0ebQ zc>&8?_8V>?1;p^pP2M{H9X<+Oa~l#3wvXFqf{B+Y$GG(wT&fI~$$CA?O#>yzRL3F8 z+begTmtAAJht(GRP@ux+^c}NG4xEzxPOmjKDfV?TMsjPi9sGP*e)`GEsA}SEity?u zoNq3ez^0c8eL?(YPt;rS(7QEXl>CNIj*Aqq+_&=g7|nPEng|lKbutbbs8p7+b9o=h z&_!B)6qGF4ooOY5qicBY z)n=QPe^b57qr>TZC4f`AlA`_wZ7h#QB@X~);DC;Z4v7wAFSzfH3Gvf6$kVF@YpdVr zDkb&!jp~$C8cf_P`2@nw)|u%k-__OA?K{D|SEdAFvY~y05UDI!R|)Gl^;nZYD-qI> zy^bZeNr|;nY$H+HW9yNAa^#w*9$RDBoUNV0MIg6+hiXI_*c&fI-+?GWD)X>PO0-_#y zkn0J*a!LLt%=iTHERNSsx5*Qe34S|gcWsc&hz;lYwKK2S*r-O&v)*U2`>PxG zIW>ZJU(jDwJx}wRaYAI3>@3*ue5^Wg!iVq49FLx<$}!wj6QT{2H;YesNTU0gI^Lp{ zF!$7uzes#iTf@xhTv9J6i3wInHSK#6(;)GC!#ZN2&k~HUSYFnC^3Ft9=X^IId_(v% zDcv`jv1?I5f_4rCGAEa5qXMT#UaoYxvK#t~jxuZs@3P1|^=5CyKZhguM3ChbnVKSd zBReI3tpgGQx^JktDe;{u=vDAcfPr~kmov#dSSJlwy+N?d#}Ir1$T95$TIqP*7!CtM{F-Uo~94zItm_aP?WhlK^Ny zj&cF9f@xW!ZupQuy1?!GI}hY9yr4Y)f{Q)kjp`lwlsF-cW{str!*$=k&wZDuR}Gu2 z=Y5y{O8SC_>}LFeLh6~Ww{t4d*Qsvys9U61bq;ij3Y}|uH6^R`X|k=mbgeh`zPE((z2XZ4aeK=_)Me!>)GPF$30XSvH%8xI z$*jy`HE6qWS^u(_omX~Jnkw`;ppx{}gbZe?nN(qzQ$ zxP583zd7-y-k$^B1{PKpW)-G>xX?b+N!#7ozTQLm(7H|Pqj++4>uT$bp8jMf4GVB& z#$sYq$8fUO4U}3UVMj=K{byrmet$Sb8vE%Hbf86*!87CRU7ZIWzWLCK>|;CcD8`KObV27M1A4@zU; z6C;l*i3$~CaM_u$L_|${)@|F+ID`?0mGZVEomClE9gtqkPRrnGa7wa>rR(6SxANDE zEe?`wD6K)i_K(4>=sFw`#ps;koN|!?Vcqou`Q> zmlxC4>`uat@Yd<=fo;BJ8zN>L9K6q@Gp9R=@8fmjk>HBs@DR@7C!SKky?qKqc= zzQ{g4F~+FCs1q4n`2i^IYT*R#Nw-vsIloS*5Hfc)S2jj8^9}NnG_#k-4k}v4G)ItQ04t8>pZ*fsaP6=Wl(UaFU~H=F!Aak1*7YEqrf zddSS(GCjzxJ^#XN2htYJsM^>bak%4N>UIm^E+OR3V?JZPhepXcwtbcUFQsS}^#iz7 z4F}7v*<5dXvzM@^G#`31^Z_@jwDn8Y=jFxKg2{Bb2sx#fjQbP&npd;+v$G0Zd>dXY za;>~8d1sJjscm&-URN1Jm>AU(AH%GylCTVVr>#UAa<^BLor#f8IO zUIyX!?#T9ypN^-C5D^d!we&1DZ%%wU`E_zYR8!=o2=dlbtz64C_!sMj>F>GU>24X` z!u$Hj(jadGEz04D2-bSraC>m55R1xMq+diw1WNaeu6qzJgN2Qgx%5tCwM|~FQ_$^b zb@A*?w#oZ#^=+ECNqz%3Rz69ZY9Q;_4hT|tH+-I+GA$`{TVK*edUO{`9LEV3NR$7HVZDSk~@_bz$92!^*YV&!FrKQwt0dC!C=P|i1>w$i_?O*8`Q zmF|fxR(b}8J`stX2cm2qbdSH%&z7ojUvsU2$8*R>mlBRBY|{`ESb&~Bn^OV&1Oi*d zI}TV_)a*b0pSZ5Uwv2^!BGz0>$5BT`S;EA|iudk)n|lvVe~3 zW>+gqYX=EeY1Y4TNC4>{kNH@c|H|TMAmtZ&V{gWHSzKJ4k6(aKK!69x!QCscX4>Uo<|l zMKb2N)b{4xD{@yO$t95|Rx{Wbaj=aAyJj5IbeId4$rDXx;# zLFYe*+!z<--#tb+JTAN{9$fUY&g@abBcWIP*p{4^qRW@cr(f_Y#(geDh%s1C?+0Md0s5(zj_SVQa2>r|McT4Ax){B0HILX*K1P5Si6&_1Y^<#lIb%Hq z3<~WhYfcO-*-P@Ju0658BYiGV*V|}~?#15Gz@5MrC9o{z+T6S+vG0cJ5sfydDQk1T zS?W-eE@$O6ybbqKIi?#!1PgL50|;xkpliqE#L>{u8o)h92ehU<{!pZ8jd%W-e#_-a zACm(+n(#uZ z?LRILef+^)snQJS)8Lcx?X;eDBkAp?^+2ZRTUziZkudk1@*3AD$Y@!9qNYofx)!`~ zT=MtCGV2rei#hhw-Cyv@9vU&j7LlfFk90DVt>NzB!LN|51#Vn!HmtD5i+Xgw_tF@eDDXpZ+!+B z`?WE;-;e!(wYMe$Okc$y>^KKQl;A?D4eQG3V`%(CP2=7v-(t&O*@W?x6FUI^QFCtN zkxqv2*9-hsn;MyY3O-XG;e2au)ow5~j*z#Y={wQ*ja>W#h^Fv0Lng{1_*y{D{FZ6U z0Ah_}(NhoG4K!J5I0tEQklAmqUN3c+ZqExm?E&Eui=94GheF2;SS#5`y0b0P1x^(a zo3Z{qzEC6Z&C=bodMrPo2RC5z>6b;xpn7TA)p!jaZ7cFZ`fx=!I~?bNC}wkDyQ6(R z#q1fP2qbK`hGLco?j^B7)x|DPX_{!41Bbg$*zS}Hnzh$5ddAfiibg)!$wqjJqG!Wk zZ-7<6Y9^#b3{A{Yas#2;{AJ!l=GQ%5GVIh($Eta6zROHxGVn}sYu5@_dw+?##W?d! z@B4rb8yLcI#|H`ekPLYj!1wpmLl*&oSvq$w+&QR?<&9Q)7cD z>e%HWxa}KFO|f1%S)fVu9(th-Frj}x~cG=UEb!pr3yyhoFo zHav!rs{e=)w1;9@uY10JOXeq}SWwZ6uizxky(RC=_H0?RlEJ*EZa`j+O6kR1Mz~}q z8wxEJwZy{3WDp5&kT-`BZZbV9PKd4{9WUP0wUh~T%=AD}Pzxw>yXtv)3HElZN*$_n z0wuJT(X@@<$+nzl7IWQuWuvwuZ|Zq2B*x+f1lbc2TfR<*a5r1~RH`}KIybk(RL<@P zC>j62=8->&JJcB`2IhJZ-O;fh!Yhg>h)=ezEeKUA{hA%F$|xNn)AzPZ73V9_h17hD zEy07q{U=eb9Oq{9bjrJ_*m{{c>oIu$-RTJeQX*#F**jESO6NX5_;ZM3imEPQY%|!6 zuXY>Xa`F5b9B0CMUf?iQdx(n@%vj%n2y zaNJ!mojVjoin|59n-;co)I3xYC?|CYxlMkgv35Th#`X%3c(osr?R-LR!}+xL5dk#C zj}^=eeffOp#O^6QnzshdtP$zM>67x>>SQ8fZOvO!k`4PG@&x>xv^Xwkx*4vAsqO8t z29GFw4|7yN3=yovBm3n$E4Y#Yy-kdXQ08{Q%6HP9l{I{cmQe6hbeV8k%U|omSZQSM zyh1x7Mm)N^cDz%oOAo#oUd}^gsmd|i=7G4L))c}Ng>Oltu4U7+{KL}zW27ALC(J?- zbR->RQ+*YxIMn2{qOg)o5swt3ZrE*0^yL{Rm z1!7syuQF*ngU=WO-&9TG;By$=Sg!uCC90R|d#w)e>hXvOmt2f4?D#*Xyg) zghG!NFR6xgi$;8Kr{Qgt)8cxCL>c&#BzTZ8@pdzVE{{*NnapY?F+PfkyXjn^!~LPc z6wo~;jUIay$sFg*!ST!sBZQ~bWfCY}^HaPPi zt%L>50=get$MjQA138MwY+G`O9@HKZ;Ga}Mz2Ncfn>38CR(?*b62}OWj_wyQkN;2k z`kD17>VMag0O&_0wK~rOiTG_oM*xuaH@J_)fBW{JKNk$ZHx1mcOdTC$EPn%F9LBBQ z!1C{|{Exc9vw+cTrx0NJFE)ptgen^s+@H^;2PV*wgMVhDJqxZ@I+gQ7CKEf%zkB>~ zOQsWGXBii*EZD)uJvd8Jj{NAAOo&ja<3`a3_a3eJlDK-uH$fTc2_Xu>-2}#6|D$*R zpsJn#kge~%JP}w>Ib4ze`Pq}m!I0IoyPB(ydgY|&W%eC6@B7QH&3SVET66!ZN&O{I zLFlLS5G<$xRh;UWH<)4vMFQJ>(0r?Q*RvmK2d3xM90C;X@WSkYhd z@Q7SptLIIw)6t>zI5NP%u*lN-94$+E_!m+wuJ=p)S~~|+_)tRq88G5k%mK2$7s!9m zf$HK=cIB~IMgI$}{|x!UH9+DN$!ZQn@V5yt4*-Vlo3E;Wn1p|-rDTmu=4Hb-In>$z zGze^!Q3GJ`T-W0~8d*XBS(-CXFaK-u{xjrX(|=@bz5udB1eLT$gOMx;fT7ghef>Yp z93BSr3V^IH&Ryc8!RQ3Q$iRr%-x7}zvqNHx5wk-I0;A0igK=QYFxm`^F`9>LF~(>f zGQnUBH~Ym1H7FZZ=b{Gtd3vkGcVqAbjU|>AWL(Ut<(>w$QCZKUBMt})u90CIq z&^YA7V*(n7z`z7F4*T$!@a!+Y6%(HQg~k8rfJS-NEAfDvDdo9$kQ4nIQ~Mn62z8tl zq2@UbD0HXM*@R(ZGJ66)hzZo(p;V}_EJmZbcuLdIJ2TAvmTL+OwDG~R=X+T!?G1fsHLh##ZyCPE4gLLbWsJ$jcQ4^v> z6=(B`@n-SXj=Te1=U|xSnwhkQJOH-+OBq}mkXrp-PLuf*bw{vmpAn9D*_L|Pz zm`me3@7idQ9<`1Vcu1|Y^D=iu*!Jc9DTw!)M@H>#abU-Jq9J$5ehYm4t>D^@ojxWM z`;4%qXPPo}SE*xpIo@&WYVfCb1HtdaKc!Gp*RgMGd+*twgE^XyHoWjW;RYk!%uGO& zmP#|Y_V~OG`;wGnQ|5Sia-g`0hz4z+pL9LfVR;t|X}e$MIAOx1iau%4WhPZ-FKhsr zn|0jq*q`4skkqqQ<8uN!y|8u?;dWusdwEYfy1HV3qRw}ydVklnXsM^N0ua=Q1mL&Gdhl==AJw&N@;=Egi9k_`$uo^li&myQOMVke7@BdXF@X?=p=s_vYuqI-SCCSBb5e z@LYFW?`#KW;ohn0hS_TG?HfC@aP&u%i$T1LYm{ekmizSLY%^##;6u?>WCp3Q_3*~r zZWw^+{ur#w3v_{|tLknMS`(I-yyQ;d>{?P^BVV+ep48#sy;nHL_NrNWGhuxU2C>>C+`qlwGlaSX6A%EgcuWRSyqLq)S=*TIYeB2@ zZ_RGcWnTTO$J@@My|v!r3{q<`Zz;QGclu&KG3_scJ~iy4ho)pcxb$&5k2j0!Kvu`% zkuaA{SJ(%4)ol%tk5G`5{fDSYqVQm|ro)HKDrnhOa4F?45Ne6QAxI zh!7#w=yv~(Dvd=J=kMt~B(j97Wk^zg;9hMkOpZZExpL*+k;y?1?{?5G!Kn%jXc*^e z(9HQnM0%l~CqO81YluSHHl&qHE-!zN%PpT*X223A+GC!R@Ai4GDBaB-SY}Imb7QFQ z?2UZ~7z*V{w*rtfyD@hEDtk z_u@wTT{j62?t((53Fr7V@IY}M!t)}D;-Lt`A&>HaD3SxaW8@kF=YRL^AQMigB5)4v z+Ff13qqDIB`*!C)-IqV)pd8{IKXohjYv2^X^U7SxqqAKDKB-YqtPl9ri{I2mro#$s z)t~V-zj$=EXTVp1L9gDNJ$kP;>l(0e%1+p!@w=9OcAt!yOcs2TfrVZ0=v`#v=K!=y zl!*z4*v6r#=+C`n<|mIoNL;yLdi4Hw`I#Sw2reiq9dn2P2YUA@OH)A!c1L=`Mg(Yr zloOjAXQ2!K;^J^X-n0Q~$Hj)T)bn~@$gFi*QHcib0#YO7jwNr;-Iv>PlKCY=)(QhT zFB|8b8z4sa_r(xPM7e0-It6PNK?}*uq3G^}(mN+WoS8fiV6d-B>xh1YM`+v!_m&w3 zSEZ3U1&B<#w5`$H2A&>#H5}ZA-7(8{+D0-;zBY(jI%$-eVkR@=lS%BZ&be4vRxd6t z$YmITK8fn+mt?{(dsE8b?K)5aC?PhhnBrIN(nwFFNZ=4?$5BGX#|IS|`z~(?w){9u z>>)jg^iJ7ZP_Z`+f4L~FIGmT5gi#TtI*dH!-QgX?-Kuxzx<6=LQCA$oy(&N*BW(mj z?x1s>=N5^KLWwTu7>g;QB5K)|wi=TnQRYstl@UiNRSSez_zr3)>7r{bFZ!X+RlE)> z*p`F&#&EG7Iy_31!`yMqRag8b(rV}f-6c?>$8JZgVhGo5y(Wt`@n~-uXy0Px06bK~ zL2veLdvc+T=fXJbElCWd4pF33z>*kZr|Z^WVD4Bv;F~eNC=7EQa=mFmhX?ZB^K>73 z&e>j2m=j5w=e@tTKJzg+vF+gmv|ps$$G~*hb33Tf(Lu0xq9)yd8D!jLG!W)~(xo%h ziEqM4*Q`gaX?jkr>7+Bd>*ky&sjg%b=PU2RNd3~#)iQfs4d~P~8%<6V!{8iZyg37u znVB?OQ}f2p>Q2)~fu_aE8xF<%PqIH@chn21WEdeGq#E)I4UNtwR+M=uMSOiQS)00Q z)jiSgL>masbSvRCs-1?rMdL5{mM^#@c^ZB3sU=)9k;p;Itm|gD<-~jz?TKyj@|%M0 zyYW?S6Vl8GgP3w^!P2v3g@%t92kMcpBWqowLN!Mw2YkCa)7I{ZsVgd?Stnx?8RcseVrZ9U`l9 zaa>FqdgXYQ9LE%BIiyenIJyaD{shj1E1d+@vg8P^rxQ)M6xSnIN3MtGTTj#D^pm|u zFHK}uiagXSY~1}Or)FsB+wDtz;Z;LJg{?O<*I$8k?F>oe{LQ;xIvFemoUSOSBmQ+%_Sd_g8Ui>&)(hyR-tF+1UypvLh(`g1 zGs-H+|GRg;)Z;zi2$adRnfuY&_bCN%9Q9>m`LA-n(}~Y`0JVw%><8fg4*`q+6cGFK zE&z9^aIyoQi6OB+i8+S#AGkXh zH|fAFWXAZFKe52j3Jk3{U=s%k46VS>iUT%rkigK2|Esj3d_TtpaoOGg=~dn$6*_3Z zd+`mcxd!PA_bnE^FA3^j#}xuTnLiMF7{WwmdI5hm2_~UW1CC>2$|bls zU2e#hg`f@a)XECEZSwvlDf&2?Hztb?B&bd>=<{q?L~nK6=V63-kgx;&@+A1Vu zH*oaCsyTz=i+R-8-sE!403$wfXzy!E_x;grg59mbkkRJ|2(SJfqjX4dR_;F7b^jz2 zF&;H(U{@Vy8PdCoGzRTFv+*@mgr2A=Fof{iVx>lofonrFsjna>Jj#)GO<*fO#+}u3 zqos_th=DJ2I)O7JLO~y{*Aywx9ObF$IunBo$m`u`%3FS3>n&+%W#tZGQfdy=B>d*n z=@L^QTC$jt(AQF;*IUIAph=Trj^yhucMA(7QPwB@BMn|OXG;U{y_-mL$Jf;S_ghP1`edrEmC9~tXVMH0f1b}5 zsdd5W$}xz=?aJ8@IR~}G9jgc}pnw%Qr|kIftO%v2sl<^<>*Ieq1FXfssSt^kk!eSt zIm5O3!jn~(HM$-RZc{#s9fLoT!7V8&D>X>orYygl9CX5ISF5JLO!Qf7!OLJ1*$vN( zY10i|D6LklTA!6j>=~y%>fT;m(y$DDd=w4!Yf6qR3a#4dIXhlEJu(DcEF8CMyspsd z5p=7FwXB|XsiWXqrt{2cWE*d$!NVty{MD88IL9tW7mzZxXir@kafcS14sP+cqhs{W z+&;t59kF<2kt8AW0$E>kAxL(xkz@E*Bo5wa^Q#mD*=@ND3;Tv!5=Qu_(?1jIhd1Gk4|U(o5qB9n<&a0t{hDT(b-9ZxOvdIT+Kw%!o&pZA(8Y^>U)$Zm;jDNNR)j8kY zoG*=Y-<*Pe#BFIT7?&6+NTu4do^xg$uB<& zBIaqk_MJZ~raS1qKAe=7fy8WhIZ+)sj))Vx%*8`O;((9wPcQ>j>i6Wl!Naf&G z$L)-)jsga(e7Sr{EVwp5TAc1wlLt&hbRI&XW6G21UbG^IiZ}Iwjc-ZclGHca^~x_5 z-mP}oZ^~-zb3woC@MEa|y36g3G_!AJWNAwgW1r3Tzl?hf<>uR0A z9%{Z)fSQP`@*m!AVCjt3^e-?d*k4!kwN?nwDo^#QIx}XsWaQdo1Sd(oTFRvQ(#BZA zYi!uoadPW)y8dMbsP-E6qg1v0>6TbhqrKIzNS~R~QE2hxTv5J3l+P-9-)(e_N;3LK zu9`0@h`1 zzr5>aH+f3beKB@iL|{)}M;f%7KW8;z;kNrA1~+2E*~rCP$MVUX>RL^2Ki^8D=nAdk zZqIl@d0xC*Q1HB)r%BBd6G>bVR|I>tsA-L8M7mYRk{3(DU``(|w~$Sl-Y`sKBeFxu zd^&KhcfsnZQW}lrJfOKfHEYJo-1CW6gd4lNwOtpoYbz6!!u)FUi-xRSmn-n9+CFxm zT4PF^>7*sl(OA&i_}|q0s~M10L$lH>rT4)5vX9H>33DSlR=%A~Y`BZWQ!#RZX0Y)m zf(LoOslBXb3M(aYrAG`kOA|D{1WUal_twW>!2f1-e^4?B9w*h%W; zGolmNP6XdNm}*7&#fq;Pcx4v$yP77S#|!RKj@$f(y#Wa~zUNwXw96f*4QR^r=-Z-4 zYsxc#rlhE#3;nHvJO~Wr0h-ccv83o2O{oZIO8nuhgJQo;B;NuwrNwmDF`DukpaZWh z`yFkl!0A9PUCB)AV>IO%GA+(0qTEMA@ra5{tEb=1>1bS;Ujwli@{+qpL!qAbIIgI> zIqjIMLZ9Q{bUhzAt@LwW;HP2zw=vcQjB%c`;m~j4JjklZ1{h-;8=a$}=)43N9lVRxoPrgZp@hE?itP|K6kMh8tVuBVwNfsCr zv^anQ6SO!WS(u>3FDNiUi=QM53lp^X1qCK(feBh1AaIcQUk5FUp4SLl-o-{6^6Bqx zl2)4RkHq>`Oqt&8x@Z=P?ISDLAIB6VwF?$QW$uk~`-@N?2;P4Zczs(*ePk_OeAE&8PuX9tQVMF_rN5B8o66jfAlgjLw)dg&vIqGLnxL_>$%GR*WZhn^CX#29q&^+}`FA{7Y zLlF0nGiz>Fmys@ZGwd8@^y ze_~#&^T!o*bh#mpU*^RK^y`8QCe*Ay@(Vtag`XT6xW?z3)m)W9?llK-MLS2JH|`q z=~T99G+a2Ej)U@9U*&4b_-I`f>C=Re+B40c%HnamHWHX+^MBq2u%Ta#^MdLb9vFts z4)!N9+TR3D|4f0Gze^`oeJ^zhqS8{>DlqAOl%MaNNco9oz}Po|oK|SwO5e;Zw`?y;ecyRBVAnD*v2dS{lf=*1|xGxAgk2^;9GG-SMOANAn z5@5KN7;7$VL)wyShkCv|1w-c75T!<*%;ke@=#9=ZZ6oiZx7V7!K9I1vP%``tfn%-B ze2Qq%nsabNRE9gb?2a-Lb`hFqW`u8q3S%NFZAcT%i@NEuWM%0m>Ali6mA7PIg4-1t zrd@^HZ$S7miLyiyLG^LQB6oqGTj#mEa$3Rcj8>*F3S_iDlj*zV8q*EY<=vbL4+eIS z2UkWxOhGcMBRaJY$LKU+YjiLM;FhT_G9!@A^xCXjli;GL4ZhT7jDHn6pOIXv#Z`_> ztA%#Z76)HhEv}1Rv1ql*tZH(~VDPfg`)<|NIJe6kcl3$T8%?uRCiOU%sGbE6KAMwN;QMMptU2#u8MPyrxS?~6e%QAyx3|%5|tsdU6tjuvZ|HT zHg81?R~CA>XR+xeWKdQY~4Qc#B&=?6O7VwK5A&FkBT`f^* z^~B$0gGMg~FIK9xujJn$Sdj7-LCM+~J=B$T$_dFUh2{Bgcx};pI~g@`rkds5qn%E~ zi7>vq<@%_Zcl-)-Liy&}^g1$FuhcX^I!a}>U&hmuhc{WZFqPJW80u;rR{9xXLcFr7 zG7iz*?dv1$uYza{{{uuq8bgcCQ>bMZZtvkO4w;rSF&@vthPX0jqmq zI(OI*=8(-a-y{3+`$Wdt*gh4^3%kk|jTQ|yHTEoE<4SDF;L$9!PRw#UPf)oQj`LR{ z5hBgeyw=M&hK4jr`N8&rCM9EK9g$Y~UJZH<#_H7$_O1V&~}6L`pA@&d*N8 zuJB5tmhH^yNZMSTt)rEVwS&_va1Hmx3O5yCWbbVN8LsSATkJ_ktYlC9SXkjUH1^=| zHhNruMu-rf!0w=VMi-);CcJCDXM=*96Ay4p^1`jVg=~3poS_w6wbpC+F~cSW&i6Oe z42{i7t*n>^0|!`v^U>73fY|ooMfAJ7T6r9LgV@wi&X=7=lq+jD2RxWav4iK${v@hmOq}oKW!&P@6qq0D+49K zU$CUn_2}i*-!J+m0fL(9eCx!OQc#QD@;iy2YNI$#h>c@U0rYyZBdM}`PIrxC2@+74 zs8JaQC&E*OQ%j(bDi5})Z^W5GwTl_3)fh>+kkJIuzP=F`J7ZphrIvFY=UgAU6j%AE zomCmqB02*oG?W@WV6R^Xaz?b)ITRsACGirKBokP`B;-jiijs{!sq`0+#4_U0#BC59?eKJQJY5E-pfA>CgYi!GGZw)pq zbE{9StbSteoYDP&?J;Q*8BdzUt`4}ewLs`KV|VNvLo+0U3?<|C42Z-B;_WVXM*wP$ zFO)ejFsy(1^qq#m1h7Rs9pg?C?A-8*+TI>7!j3}p<-A7@T(~=-&!q@`6-1{hy|ZWP z|M0U%(PiiacDkzMHobD3HPij8Nz(mG|I;%mISo_+$f(ZmlN!A<6>6Wk0V&~9*{*Np#faUy^9`Z3oE!|kplN> zMg;T#t!7yoDF3*e64#H9Kf)!VWuE;MWN0!W3sJ{Yb=oj0lL+cYL%Y7i;#ZsF8s?Tu zD-#r%Rqgv@N!C!jM^3klLe!F|BpA#-oz2X#22LJ9O_>VCA4;^Ctw$iOUO7DjKZ1@z z)E)4Xb6OzkbB46uBG>~1zT49Bl61Hq$(XbBPAEKa;hJ;?6mY?HXhFzks1f?zaw2T4 zp~>9lD@+Z=K{LCAlgLX3H*T|*xkav~HuWd%%E8W@9P{?m+AgMm-TY*wk3oT$akAr7!N_;fk!?bHn%9Tc{Pi zcNyDr&T)?0**O!evD4)Sgi-AcT4Ie5zhMOPW=#;8^9@^ zuuhe{-x=2f?+?s;5^$qVsR+pZaUTA%1#f`^S-dHckB+(c@DxB(h$HU5_@ATvcTX=| z2Tsjth;|(@H9!ZU!~im9h3YAfIi2Vu zhtX(<(ZHC_!^RY2IuE0P;b@0>3WlQ{Mgzmq4mo}pXW*C12DnBTXW$SVfJ2P&IuA4l z#_K#B@c3VcH(Gg8X!DfiFdGdUY{ItUvRJwQf@8uUZ@Gc3ur&u4k z9|4XBMDYrphu{ON&o;i9GJE%3$6mroqnBn#he#vhiiVzcCM}7?%z{0;%(rm)rsB&~D28h{R0K%IW zSbC2B?C^2A2Jw+S=LXt z^&=2M`S?^{?U-y7z_*iXZ#yb~7CY?d9f|}QzXe)-`)d9eOpHGObNJj|m-cr(I#hK4 z5UvY8V=sM7Hf1fay7Wy|qTinzI4BIg3AB3iO2*OGXJJ8~1Lq7lznkAZ)REuJ12g{( zpw%078^>k42~7Vrah`w!ZS?zuJP>|TASgWMIxgUH5+J&KA<38g5bD2~JB-l%2W5=V z{de(Vgzi6>{I4|~*roHdeaYUKFV|>-Ls~qX>1j7FA+1pUtnEDY=6Ze;pTNB*T(Ug^Zu#qHE1 zO34^e;|RYEuE_WIX=Jsc^iJku83iUbFRC)V1f%k1z@+ z&1W(ZpSlY#vo6?YaCw@8DD`+Wt`ACtAFZVMd7!L5b79SyehA1~c$T}lSC8z*s0m)B zB-|U(%d$+=Vn7J*J8SVmc4MslikRJ8C_ilg$#7EM7aiUMmHXQS2aEcBbq2MNq1jx2 zQ1Q++CyOkv0co73Oj-+4BwU4JoHNx#+V1nk)7g>c1*d;o#Q|6xtgSJ18r)C+v)ccM zPF&E4t5efLd~p{2VI+W^=yjA&R$(F4R}qhRaYPkP=tJ@~Hhz4c(VlzU3-eEXaf?r{ zb<#Qfc54URj2$F4Jt*w}7?N^&d`oLfKZNI6-?9%vil)D*hqB-;I~fde&(54Bsu1B? zFh5N3fGX+S@6Gz58+P8ZWM!98m2JOEs$%k5rHe0az4-CMEq#h-vF|~i_r-GutYkNY zsbIe|ML<8A0HbB2-HHY#RlN|L)^!f@rf6XC>DIVLD3~}^a>$uNOETT#PV}wc1KLg~ zreLA#{qbm$5+?y{1v&BDUgpM$$aJ*gt=f;QwyjZQBZC$99I@AA?0F(-j}hJ|jUPa% zV+1Fjjwz+h(C@=voXV}^eL%1t`PdzhPBF-;x{iMTZEd?$7Je4!mV6K-lc_rr!Hf$}WvOHuXJ?>#Jodpt= zOxTJptyLR7vo{BasEK*CWJelAp(rkBFrVt0ZZRM+a$CT=YmvjL&;6w#=i;Rdr4`Bc zU`9Oxglo^)`F6|R!2hc$WOZ9xv~q58qjg|T&1Ily{%qmsHQWd%2q3=nVg+J@`QbBPcr2}P#_nM8l@(C$ zpuaQKHtm#UwG!Zw@Q}1bAomA~J9L!36!VWvTiYy7Ziq+^N$VjSdrewgD~M=47JA9B zO|uD<9^=Sed&b79xcw^l<{6o5tgq|*FOX}nvcG;p8M>gzO~69%<$%t)w}lTbYmWsxQmakC&}i z-WsS#eHc2R$2@g*dv~RO$6mL^VLtWZlx#NB-uIla@6A3Rt`r8X+|Q{}xE(#7(Jvbs zSy0~Hy=goQbMs1Da2DMp+P;`N?;ln>%%@+!HmxOBb~);CVG+dlL;pY13!&Xq!V;LQg7C1zhgg~cQWM7c5iw% z&B(X1^&TtMyg1@ow>% z)q|lHeQ$(kT7tH-IomV$^3^^~$GFuK%x}*X-N*~1sIc*xJ~`XsJ;URsnqxRCNgV-# zws`F{%!2kO6jli~(gLGfu4T%_?G1X>c8Km(=O?a_#%2t@?s16Q{|H+NUsu|n{kYBA zXv-jt2Dt!ZO^@U)uk`rID5dA8zaE_=4E+>A!>^-{v&TZwaYjN%tTsG6B{0V1iO<_S-A4|)>&rc=%CX?6E zC$n7Q&QE%YG5M=ea(`?n7Z<-&zNS5l%3-jgnhCF$k2omACWh+*JGq+Mz}%$CiqArU zeZsv+@`31^<^_t^=LhCTlE<9M_m8;Z<-$%_?lQ2g502}nJ=#&g`f+bVs>P)CalRP7 z7Tw8zQIbQ^rhlw2aBLpzls-s!j30Ia`pD#enCJf(HQ@X3Q==6DSJQ; z{z?Gf6k~Vg*>fG|f8nGC9!)jye|(1;SEOxyobUA*oOk)Z;Qadu@a>{j&-e7>oc$Tr zU$d9>3>ysroi>!*Hrvb8axV< zpN-33S43+~QdsdOa|4h=W%<1{gZWFm9f%F!g3=YyX|;`ash^5)PtC8`qWW65mEV(2 z3yxk^J!g$);$=SV_4L|E95!F(OOv3A3y4X?l%0-1AK%-~cP_Vpi%>EB7{XNI?7FFH#`%jCZ%vC(gc57&P5NVK*BHF}=Q+{^2M zPy{#Q`S_N5OouDh_`UU+;dGrlvkAp(QB&XF&AZ8T47yn~nybdhM1|h2k(6dc z`EFD-%r1D=cz<&(6(>UCP3S7bK8h0M3z(kva8yv>T3&WoAb8{Z zoQ5t)Xivn%yfAV;|8>iqz)K=b`x9PzHYp)A0lxEnErI!*j9sTYUT62(oOAv*Z73?>(cM+Pb!3MHD%IAqC+rm#vI0>CGgZMCiwMvWT&oCO%zU zS^KTp-yOGR;-KCqTcz7FInh)2h{!L5mkvQnr%sMp1U(pZyv^2V?HB`>l6P&k;UEQ- zF5~BFr}QO}7R^zC@Q;*DZ>4pNvM8WB@XFDTjE1kucjd$$?` zbu7&0-$pkl7m)cuY7*VIt1lH=*q%pR>n*PDzVH4L=E5>{G0$+$ z{1*av=aVg$^Wc+U#R)nJ(K%g3hZCwXWCXi=XfWYG6c55Q zHyRSJC|9r;9B2(NPXYAp{LuU+{bu(7Tr_AQJG8i@q_wTZ=Y&ax9xm(yKt2|NEE$7@ z9Z$tyMP~Ylo0Us-?p-_+n7p6nY>nN8M01_`t(T4o9574Kz*Sx62lL z*{p+<=`%(n9IPY0HM#!=V^x{-F-kCw0O_Cn|Ca|7k^sk{YT~(d8s8XqU^s7zr)-d-x&X9rgX&I6nlotDG!J>q2Rkp*mSdk)Q+gDlUv&Pr#)Fx(GbU9Meem&o(U9^|ok}u&AgK(?+H{#gh zi#4yBAKlf#gY9bdL&iY5a_*++`42hK|A&>&KsD1=-7mp0g0Ro~Lv{Lv$yZ%aknM7X z6YMhe=~L9?hsif(iuRwep}!FH_Ugy0cP z#X~A(-{AaZo{k)b&QNU8nxGdUT*w(d79S&B6BRfhBge8&CdeV zDa!QiEisI{}SC6u>V5cx0Ylx==!CwTWrh!+}0%+Imre} zUIC7=QwMUdU#rZ&d)P;4QAKRlWy_#nTmR?cM>Gc(_UEZkjI#A?N=TV)kl3}u5pK@r zDE5X4XytJ&#rlQ`S|Ra&N9db%lXIH7;jhMBJvylQcEW7hGbQIK^#gE{~DTIu2l6q*ddX#=z;kAjKEzRCE-uBGbGTiE5QbYiUrwj9^xdi0|Pr&muO}mI~ zLy>dqvX05*mQJ^YqQBp|x3zY*872Yu8!ffPAyA@BaodzL!x)I=7{0o6G05 zfec2RNabtV!hNRz2zPw3jFYxJfX+a=4(&0h3~k{)7Xl!QR_eM*TOL<|Jcd`s+HbTE z!j(w?_M*Ec47d4OQ#z2!(1m;Y*ziUa^JX~|FM-zFmj*VOqrS`Hvku+BnLhQZ^7C(0|TiPP45IRm(+MA(oAwY z{+@P#vU9VN9pHKc7L(g&8Fi4d{HL~Y4e*3eOiXVaZ%oAuCMmvsWbU3STvgwb}d zr>_C-_0E*&HrMns0|BhPd8+MM+W1Hj2Dr;LUrXA)8W0;@2lLFmYqaH2C9%m}(sS?9 z7OsRQz+DirId!z<5tRaP7m3A)pC+9?VGFSb5UzAyo8+@^ckp}QwE^;oOToOPE!=m? zfN=M?m7kz35A)}MJlfi!QnZD8_$0tx{wH8dkZ*b&VPayQiqn7snZB{8r-53xw>1lvt=hS!d|F? zgt3_9BMX4^L$hegzrU z?Xk-V098VKo%JoF_7hOx`*GR-K}@}suYdURcUpf&<{T9r;!#jy5oWCUh{cP1IZH z?Mgf^0dy}guYNNpN^8g^faect)KX|Y14v)Jh7Nwv3Hc%y$zlW*s&d%ycB--bkY zCLN?0p6Q3`qwj-wZxzjjQ)c?CHi)hRZxIvWBf5&r1Qee9pi*}u=lG8`%AB~n|9Zu; zZKyo|knyc=IK2&XLp+bit;=Lqe`fNelbr7V^%(I#Z( z^_y7${Eiyh4maTr@YuC!r`c`JU&1#DNdL}9+oS>7=*zF!&cS8}1}9S^bL^6vW@D+G zJtS&JGQ@D!RSVV8OLF;qJ_Z!n=M&2A`HI@vkyXT2=O^;}45nS%)N*4Dm(GJw%Rea* z9KWEPuzDM8g7#6Q_91=5eW#wOM|kG|={i;n5x;W^7{cnRlOV+*3;Nzd5W9Im@&HFfDvJL*ka^9kA{%l52#vLh}KUy zLsU@J5(HeMEj4O222P9MnknwPBfB9h9`IR#OI-jY$xDat+DXUG^)b~a=y7pzX1|e_ z?eGA^*3t33jjmF4spPJWV_)$8uLIKeK(v6}WvMeN;CLnCLZIIeDQyon9%0-7zduc6 z&`2S8_EjWul4U
$?^o#;X@0aY<(Lrg7Zs+DsL8mVsnm0j{#CV!=X7gEkmRE9VW@5qIyT1qS(%5-fsJBtA&Jq^ z|HkAq?4LP_TdTFw?mucGSwu2vN1Dkz3CUdymCwk`FbMhHguPQhlwOeIr|{*v*)C{P z0VCXiueR9nd2^M`j{!ro-w5BklP-+In)$?fWUj-Q^5REP!v~h`&IxiXhgbP2ioX-X zz8_ZEoE1@8cY|z;ykzewYM;z44sT#s|EC3tS0BJ~)jiCWKb3*61y_S%de=bk)G4l0 zDql>(7Qr7m%>nFLdY%ayovWPPp9Dy||X$H9)3A7qd`K-~A-J0v^B!nPq@n~IRoeObH@ z@q!Kt&}6Ro%I9$?AF&PJcklhA$Kz++MD4P~lPMwDW3EZoi?<-=BXk<3=+HRW@RT_( zv`(RR%_cXRA2Y2v^&ua$KS~IJgHQP{yaya3pjEoh+p0alnBs8E_!{xvdiAP;q^`+l zq#$+yL5cud^CpKs-9QJGDrw7Idmq^fU+oUNlz9lw?qg9Di6PIDQygFmSKq(91p$`6 zyV%XGmEEi?21X3ifL`V{y+WFGP>P1|IUl`dDZ|wKR~0*e(Ty1>I2IGN>yR$t#G|1a zRxs>n#l)*H*~jmn1-PZrBSh$0Ov|6Hj}nxgtaqhi6iRnEx4Yk@VA}0ca~0vosBbC! zYU*_EiEn+BEa)}_1yZSv1cfJ0NisR1#iUDbS$WMgHa=cJCU+#ejZy!IK#N^SD6C42 z_Y|hC5#UD^V?jyCz@W>?+=K~@tYmLejXPaOVxiCHgaRjE1-;I!UKbT%tiDB7U%7=_ zTssG`*HN5=9-TJg3_wSc_)@U*90{W8V;Toc%P_IxrkJ=KJHkQRwmgK>5#OnIT1qPh zvwwOmD}txFy6Z;Q{6(WDNoHkQg>#HLX3Z9-b3$?iFQG?=OjfqqP=@V?5&w)Yx2wG&HZb-b3yQl<*ImWn^&7)5*4U2k0*!!YGsq#;1J07d@GMP5scM?xZQVDux zs>I;zT(QQhRNvdkb-T9hxHE`LH|XWf5T9cunG3v1hYz?s=OUG_z3ynLM@;FHrAfRR za=^zd6{KNu;2RF9Lr(VX;>GF@NK5DJ&C@It6yalD{OU%27SUSM@GQZ6GnsItWyqLY zgosr)DnA%WeND;_(UB3}zZfXDIDbnl&R%~^{>@9y#R>Du$1R9(r4#!oGN~?iv!%O1 zkqf{?D2Fr}`Y}Bd$@PIR^_)?7rO=7<9JNESoumF}elYxaE|#N@V=<5jI|i1`3ei_@ z%&ZLUs>_&&ON8Y&$)Nkyc|7kP#NGZtwYUq4Yw3F}G7WDBO%>jAiN0PAW8f12%yR^( zqKv)tWmyDlq-*2W9CwY3r>;$M{}dtV!Te|dW+RiJ;ZRDs;*<)mgQl)8Y*2hwb=G_A zf|c@JhJG7k#$QP7Y{RWoy_viMYmAfVqdS8c)g5~@CU2vvq?ah=%gLlK1sl%i&~>GQ|nLf^il+(rgtr$ z->d}}unR8C%<^)bgpI#ixjJd3-RP$V=&n1TDMSF)_H1D>7i^Ld6-f#Xi`$smfJynz z)CI~an>zA`s~h8sTfr+K(y56nNxJE?HF-Due3zT39vv_5Q${lySQ`whg!`%{10Bjyeq|xtOU&uT<-%7uPJ2=G3G=x3Qek#_d8?egjONuck$bgGU-_1 zU#^WXbQ@juynouM zad_i4?6-#Zhnr`sJ#f^+yPt8vJy)(btopzaLi6$5%kRzBF7`H$rnfJhQ$t!5I(U4@ zSuinkZ5g5~q1sA3(||3unL)rC3>vKVjSpvU1{|CowZRZiF1f>3_{f}#fvZ^K`O1x9 zE>fFiTsJff2Vus#dFA?>{nJnKnJE63vDL+` z;D|n5v3G~@RzS@<9JtfEO;EDhP>Ir?{3^^riC6=~jjv_zf6Oc$BJv2x#$raZtpb;H zWomaH0+YSXt^nM~EX(JKgJ_F9D8^U=y!uM|poxkbnN(T{M1!KYSIRgZvUd&8&>h6;K9V0Wt4u` zyy_6_Z@>6EheXI62$`J#TE&xvK;!aU^MvFjru>$GDs$dHJD-fO`~_WNvSd9wlD^Be zf0ixt#zKpXkYG%Eg==ArOc3@8>%{pIm|PkBlB`qY8yPN+e$~k{>+7e$oa^kK{5oTh zMtNb;xFc-tu&2Fx{i*{#WIY7XdvIxAd?RVSmFg-Pe{y+Vy~{pZ`4wC-f@}a^SWx%# zRRb`rbOs;vXi-M|VCZeLBO!aii(~35Bd963_|TE;M|Sox3E37n0Si#=kN|u#`PHhi zGa5UPJVC0HzoSGy0(tK-a%IvNewQhCeDqa!b0p*p#-d_1QDHE#F;uudK-Qq zs6k7Phvr|)oEJL!0``7Mrjo5v{Z3wNh{bCeX?_irQxP{&hurzGtGaSE-GNk%MnCa! z`N!%xSf?QGlgJh0E0edG=aGx#%cu;+OGo-gg+*Lz4V9!7$i~ExCxRs-lZ7a)&QEAJTY2tWHGexxdCA&Rl(WMX?jVjm^5nP@uU<>M_+^;SS| zbG^ym4^~f+!+IAA7Nf4;t|Q9CFw}S%N9Eq?k`N&bdw^uc=_L4%8g*g7wS$h8x-U&o zSntF=O}x@lwG_PFjr5d#*vpgDw|VQRuF+xdZdSh0MMCfaze%q{o>oCyd_c z5e7lkgyXG_1C{S{4jk`)K4BjHwC`*TZeVpXbAw}%N3Old*UMGx_H^v9N3M;BP!UL0 zsK+Fidk|RA%UnT^L$ev8%vgtT16ReI2E~1DD5z6UMN`_F(^DmVjyli$>}ngZ$i$~{ zgA<7t@NJpVp+5*cz7D(0cLEVGSDv=yKf%+#vCwxv6l~@z8Y&X)e-cjqL+$l9^WnQ^ zbgpd;uD%|y>J$^BPKz@kjfZyngA>U7d+n6h4f}DJ`6ZqJC^B6~LBISI?M{EhZXl;` zS_SFYCaK)Gng2LN4k@QynDYOb=`YnP8AG#dl&eoybCnOue^%;W9y{;~m@9ZPQTuQUk5>4t$&jGqZe552=WGB#h zx<1Vot?~>2yp|nL?|>t3aeIpaC-;)U zqt183@osgCTx%X$zeO$Ol~+tdTBgbIzGDRHZZ~AA7Rmo)MKkq}@DgwScF;XjcWW-o zj{H>>PgEbrtWWmA29>@yO0Y=#My~r5|4@EcdvK!d1B)~DVi&&Y9a0S<63=xu7qfa@`#{O3U z;BH4c7GI1ix{atnz0$kvQuWp=J_b1&M%7=NMGKS?x@`>cZhIJZj4d%yU%7b+BU9yC zds~C4uZz%?q7_X_zPDsuneg6j-pnVu@|E?s!wI#jie~`c=y$ z(2H?p@P6l$n`^PM<)QovWpU-PFQ>cJN+i3<)lniv6=`p>_F7)t$O5^x`74O4kvoc- zX7BmfrAu{cKX}@dpRAq%#wB7u1V_ zQ-eDO%`5ZrJ9&6<;U8b=3yd016BmOqg-ba16ZB@1{bv!bgAGiWj~Wv1BHvtFaeGS9IOb zSVuW87e&}`uU<0XegBY&oQ6WPj@KWGv-qeJMXHtaJSpJK-!Sd8X6jWD#NAbg_I+e` zIi`d^;(lL{i=W+PMPG#sh&RwkR}uM$%&BF5oKT1X{6}(Rj{R7Z{h;;1-Z}gSH1ZU= zwI?yNNG49cSjxJKsY^Y^$~| zGg;kxXspzWu0#A$;U>9Lj@q?@bWS@+P@E^cJk)PrGMVWC2{wE&?n>tqU@PJ<6Pb8b zkSVCr?4ci-@m4q_KR93!9^=>CeX3?Yne~8LiLcfQ_B@`!)Llf;d37%7W&gSOD2D8D z*)FOlZ|9Rv(lX^;baM(86q9!EvA2-xqg}5VVV!4E?o;Nvv3dhcW259(>!mrq^RfC* z*X@m~=E_kl$pW4@|C=uBH+V+qx@GnoLsv;aRlGxmm0(Myb3*z2NA6rVKTl0m7{7w9 z(mMgkKE=VzMiY0CK%bW|v-sO}L~a?_q_0<8O8m9#>cmy0=3pi{_0;Z8%rO4VR$b-NVXutdGz8Nhpx@>GQYG4tKX|HQp*JuBh!jxlIZ z^i4F@{}6nX$mEBrQGd!w$qoa0Ez2Rx*izpy$#TowQ?|RnhPE5WArnrNH%M@l+dMpZ zoawsP-RO~&r;Da57Ozhd?8y8LTvxM`nr4B(p3$fC48g1(kq6{DZn9Yi?^sAX*q8FL zt;mPBJw0zNZH;r7RH}c|@#?as(uqc?WG&uldmsaZvh4-+M_^Z3F%$$~3bJ09V4YDw zfuoA2gJQ{(knB^sak!c&v!=eND8J4p$5Kdq4vLW&{9;G5q6*b(rCV71W|~EGeyeRN zS;@oM(Wy_SFDS~Y{d%R}(sf1eCw`sHWX7wSM{-tSSYNDA)acz?9MA#2N;t7slBb+x z6xefx|w9X={En)zGdP-N>6zN9N&DRiXhiZJBm<#+b)wSfEq%W~5zlY+$D(2yl; zP5bbf28MXoMeVydjft>8qG92}$7eN$4-(-cum8j7Q;RODk1eMvYy^ds6JvSYeL#jF zBrdMhZ*+hQ60%WqX#MgGrNu6b+4P)o(=J`HkhYQE$y%7aOtnX;#WlN;Hx8Ufr#MWE z(!G-&3+oRIf1x3Gavk#kBBoWa$1Z@0S|00Bq`jsjQsY(;9T`Xz=QAF;+v!gYHan|F2_MD z#VT)0)&%S3Hb@_-wtW(M&ONX_x)5pJ+3{zHE zCs0}A)h0-)y}S+F&u*?ia|gisFq2;K@@?y#bdpSHLEK*6S5p}pj{<~lS9`TK!2k1N z^8D0ul$sMe+e2&-W*RX%IWpGNo^e_wKm}c!Sf_ES+rNZ8A$<2I?xe2|FfRXDLuNtc zggQDR*3*U&ziE{b|;sJzD4ZLKB434!;6}zG+^&IpyZ~nCU!zbR& z7Ph_jNvy8B(2(9|kGxBTuxJVx;`iBya+l@p{^vMD4VYm>)TxVqDi6>(K^J6@)EpG- zpTzdpbUMlmK@#e0#ZiU?@7SWuCMSKIgj{2C4e=o?HZ8f2o`2p@FMzN+cnN%XF9w1O zdG@PUywSS@jG})E5lI$WNhqmjuXY1f>K`z?@a+yw?SF_$V+AqEbtPsW{B*RCR|4?d zYmudg?U#F_Z3ylRI8}a0bViC-R@=O#-=U z+yXM7ZdFT&&mbKVO7K<}t#D(}j&8r|&Mg`XAcrLOF2GlFT^_0eMWvezE6Xl{GY24s z^>7XKp9Kn}lbVVm^2ltS#O72Mu~Y%-Q)!m<6Ls8XJoFh*uUIF{O@q%TRDo53?g9{C zrySIb9hws7^b$I?cWb&G*bAH1CGnffxr=Ksq(IXq&Q=b4P&?jC~;C zz}J}hI;#3SS?dtsSoYWCzTUb2pG)ptY=B`J{pU#dbit>nZgwVV8tB$e1(!e1UxT0` zq)Obi*2I4jk0SauO#&Cu;hzITPQ;k0kfPhT_3B)7OOl)SX7z>40C2VlSQqWwb6zV( zzmZtK)98O}h4o(mcm&H01V16W>eX%*F>))#%w5EH)_*iTVuL4QH65&<6Yba0poo~d zZmRUdgL7qeU_#N|)4iYT9BbJgq7u6z%l*2z%?eKbB;xOeR@p%)t;^pUt*vpt8lWtZ znh`=j8Rm;V%!nS*tN;bGZXMv8-z03VcdxD|?V^J}t1y5j|C-#_4)B-czCi6?sr;{F zZon5ze06m%P>HorpK07-Dx7GR!zTNQ2K)^E@2mkjC_A}skBYz#=&KWC;m0EO9aTy2 zvP%!c_vpv6AL^j_brSPI-~@dl3HuZkyHLahNy0Ysiy4mk;M{CV3@7Ja{(b$R;W#b- zbNJMe!?HrLxMp`90fR|qQx`2u+AsXGDvoYe5x02aXDj+rEO7GoBbp|Rdd0Nf4(RqL zQZpz%NW1W72jUMvqy5b-Y2LF6_z-U(QAwB`G5N8%{1*bhCijh5-8AC=cS!D?SU3UG zvqYg5wrTivVVDM9G04l3VvR3{3;x6#f5CCp%-;6HX(2;SB?FLDR#2*~JmUTH(zoNC z5V`VJ_1Vr3q&N>t%Wb~yv*)*V{l%C|oPQn8S3l&b9~mhzGBWa8o}HWZ zAS}rc<_c7)S&Eu`=ckaqGZtYPl|HohPh{B0kRvs1L?q z;=C$M^XoZSb+|Iig0=&!`0oB*g~)-FR$2l8kZ1;AVr5od@`r@@U-<#q7U1B^vLv0x z7pylQ9)|)4UoZ-!iT3mWy`$@J>9G@`Eo;QeW+N^RqrHtjH6{b -#include - -#include - -#include -#include - -#include "caffe/net.hpp" -#include "caffe/syncedmem.hpp" - -namespace caffe { -namespace fb { - -namespace { - -constexpr int64_t kNotDefined = 0; -constexpr int64_t kNotUsed = -1; -constexpr int64_t kAlwaysLive = 10000; -constexpr int64_t kMinimumCountForSharing = 10000; - -struct LiveRange { - int64_t defined{kNotDefined}, used{kNotUsed}; -}; - -template -using Analysis = std::unordered_map; -template -using OrderedAnalysis = std::vector>; -using SyncedMemoryRange = std::pair; -using Assignment = std::vector; -using Assignments = std::vector; - -template -T& findOrInsert(OrderedAnalysis* analysis, SyncedMemory* needle) { - for (auto& kv : *analysis) { - if (kv.first == needle) { - return kv.second; - } - } - analysis->push_back({needle, T()}); - return analysis->back().second; -} - -OrderedAnalysis analyze(const caffe::Net& net) { - // Build up the liveness analysis by walking the SyncedMemory - // pointers attached the the blobs in the network. - const auto& bottoms = net.bottom_vecs(); - const auto& tops = net.top_vecs(); - OrderedAnalysis analysis; - for (int64_t i = 0; i < bottoms.size(); ++i) { - for (const auto* bottom : bottoms[i]) { - auto& range = findOrInsert(&analysis, bottom->data().get()); - if (range.used == kNotUsed) { - range.used = i; - continue; - } - range.used = std::max(range.used, i); - } - } - for (int64_t i = 0; i < tops.size(); ++i) { - for (const auto* top : tops[i]) { - auto& range = findOrInsert(&analysis, top->data().get()); - if (range.defined == kNotDefined) { - range.defined = i; - continue; - } - range.defined = std::min(range.defined, i); - } - } - for (const auto* input : net.input_blobs()) { - findOrInsert(&analysis, input->data().get()).defined = -kAlwaysLive; - findOrInsert(&analysis, input->data().get()).used = kAlwaysLive; - } - return analysis; -} - -// Is the candidate range compatible with this assignment? -bool isCompatible(const SyncedMemoryRange& candidate, - const Assignment& assignment) { - if (candidate.second.used == kNotUsed || - assignment.back().second.used == kNotUsed) { - return false; - } - if (candidate.first->size() <= kMinimumCountForSharing) { - return false; - } - CHECK_GE(assignment.size(), 1); - return candidate.second.defined > assignment.back().second.used; -}; - -Analysis> blobNames(const caffe::Net& net) { - Analysis> names; - const auto& blobs = net.blobs(); - for (auto i = 0; i < blobs.size(); ++i) { - names[blobs[i]->data().get()].push_back(net.blob_names().at(i)); - } - return names; -} - -// Compute an assignment of blobs to non-overlapping blobs. -Assignments assign(const Net& net, OrderedAnalysis analysis) { - const auto& names = blobNames(net); - std::stable_sort(analysis.begin(), - analysis.end(), - [](const SyncedMemoryRange& a, const SyncedMemoryRange& b) { - return a.second.used < b.second.used; - }); - for (const auto& kv : analysis) { - LOG(INFO) << names.at(kv.first) - << folly::format(": {}->{}", kv.second.defined, kv.second.used); - } - - Assignments assignments; - for (const auto& candidate : analysis) { - auto assigned = false; - for (auto& assignment : assignments) { - if (isCompatible(candidate, assignment)) { - assignment.push_back(candidate); - assigned = true; - break; - } - } - if (assigned) { - continue; - } - assignments.push_back({candidate}); - } - return assignments; -} - -template -void logAssignmentMetrics(const OrderedAnalysis& analysis, - const Assignments& assignments) { - size_t beforeTotalSize = 0; - for (const auto& kv : analysis) { - beforeTotalSize += kv.first->size(); - } - size_t afterTotalSize = 0; - for (const auto& assignment : assignments) { - size_t assignmentMaxSize = 0; - for (const auto& kv : assignment) { - assignmentMaxSize = std::max(assignmentMaxSize, kv.first->size()); - } - LOG(INFO) << "Assignment max size: " << assignmentMaxSize; - afterTotalSize += assignmentMaxSize; - } - LOG(INFO) - << folly::format("Before: {}, After: {}, Compression: {:.2f}%", - beforeTotalSize, - afterTotalSize, - 100.0 * (1.0 - afterTotalSize * 1.0 / beforeTotalSize)); -} - -void applyAssignments(caffe::Net* net, const Assignments& assignments) { - const auto& names = blobNames(*net); - Analysis>> reusedBlobs; - for (const auto& assignment : assignments) { - auto reused = boost::make_shared>(1, 1, 1, 1); - // Instantiate so blob->data() is valid. - reused->cpu_data(); - LOG(INFO) << "Assignment: "; - for (const auto& kv : assignment) { - LOG(INFO) << "Blob: " << names.at(kv.first); - reusedBlobs[kv.first] = reused; - } - } - - using BV = std::vector*>; - using SBV = std::vector>>; - for (auto& blob : const_cast(net->input_blobs())) { - reusedBlobs.at(blob->data().get())->ReshapeLike(*blob); - blob = reusedBlobs.at(blob->data().get()).get(); - } - for (auto& blob : const_cast(net->output_blobs())) { - blob = reusedBlobs.at(blob->data().get()).get(); - } - for (auto& vec : net->top_vecs()) { - for (auto& blob : const_cast(vec)) { - blob = reusedBlobs.at(blob->data().get()).get(); - } - } - for (auto& vec : net->bottom_vecs()) { - for (auto& blob : const_cast(vec)) { - blob = reusedBlobs.at(blob->data().get()).get(); - } - } - for (auto& blob : const_cast(net->blobs())) { - auto reusedBlob = reusedBlobs.at(blob->data().get()); - blob = reusedBlob; - } -} -} - -void optimizeMemory(caffe::Net* net) { - net->Reshape(); - // If the net does sharing (e.g. SplitLayer), run a forward pass to - // get the sharing setup so that it is indentified when we use the - // SyncedMemory addresses as identifiers for def/use ranges. - net->ForwardPrefilled(); - const auto& analysis = analyze(*net); - const auto& assignments = assign(*net, analysis); - logAssignmentMetrics(analysis, assignments); - applyAssignments(net, assignments); -} -} -} diff --git a/predictor/Optimize.h b/predictor/Optimize.h deleted file mode 100644 index e80d54c..0000000 --- a/predictor/Optimize.h +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -#pragma once - -namespace caffe { -template -class Net; -} - -namespace caffe { namespace fb { - -void optimizeMemory(caffe::Net* net); - -} -} diff --git a/predictor/Predictor.cpp b/predictor/Predictor.cpp deleted file mode 100644 index 8e5a03a..0000000 --- a/predictor/Predictor.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -#include "Predictor.h" - -#include "caffe/net.hpp" -#include "caffe/util/io.hpp" -#include "caffe/util/upgrade_proto.hpp" -#include "folly/Memory.h" - -#include -#include -#include - -#include - -#include "Optimize.h" - -namespace caffe { namespace fb { - -namespace { - -template -bool vectorContains(const C& container, const typename C::value_type& value) { - return std::find(container.begin(), container.end(), value) != - container.end(); -} -} - -namespace detail { -void disable_blas_threading() { - // Disable threading for users of this Predictor. - // Ideally, we'd be able to just link against either mkl_lp64_gomp - // or mkl_lp64_seq, but Buck's build system doesn't allow this. - // Instead, just link to _gomp everywhere (including in tp2, etc), - // and for users of this library (people who explicitly instantiate - // Predictor), set mkl_num_threads/omp_num_threads to 1. - // See t8682905 for details. - LOG(INFO) << "Setting BLAS (MKL, OMP) threads to 1"; - mkl_set_num_threads(1); -} -} - -std::unique_ptr Predictor::Predictor::paths( - const std::string& prototxt_path, - const std::string& weights_path, - Optimization optimization) { - auto prototxt = folly::make_unique(); - CHECK(caffe::ReadProtoFromTextFile(prototxt_path.c_str(), prototxt.get())); - CHECK(caffe::UpgradeNetAsNeeded(prototxt_path, prototxt.get())); - - auto weights = folly::make_unique(); - CHECK(caffe::ReadProtoFromBinaryFile(weights_path, weights.get())); - CHECK(caffe::UpgradeNetAsNeeded(weights_path, weights.get())); - // Can't make_unique b/c of private constructor - return std::unique_ptr( - new Predictor(*prototxt, *weights, optimization)); -} - -std::unique_ptr Predictor::Predictor::strings( - const std::string& text_prototxt, - const std::string& binary_weights, - Optimization optimization) { - auto prototxt = folly::make_unique(); - CHECK(google::protobuf::TextFormat::ParseFromString(text_prototxt, - prototxt.get())); - CHECK(caffe::UpgradeNetAsNeeded("", prototxt.get())); - auto weights = folly::make_unique(); - auto input_stream = - folly::make_unique( - binary_weights.data(), binary_weights.size()); - auto stream = folly::make_unique( - input_stream.get()); - // from caffe/util/io.cpp - constexpr auto kProtoReadBytesLimit = - INT_MAX; // Max size of 2 GB minus 1 byte. - stream->SetTotalBytesLimit(kProtoReadBytesLimit, 536870912); - CHECK(weights->ParseFromCodedStream(stream.get())); - CHECK(caffe::UpgradeNetAsNeeded("", weights.get())); - // Can't make_unique b/c of private constructor - return std::unique_ptr( - new Predictor(*prototxt, *weights, optimization)); -} - -Predictor::Predictor(const caffe::NetParameter& param, - const caffe::NetParameter& weights, - Optimization optimization) - : optimization_(optimization) { - detail::disable_blas_threading(); - - // Check that we have some layers - empty strings/files, for - // example, are forgivingly deserialized. - CHECK(param.layer().size()); - CHECK(weights.layer().size()); - param_ = std::make_shared(param); - param_->mutable_state()->set_phase(caffe::TEST); - weights_ = folly::make_unique>(*param_); - weights_->CopyTrainedLayersFrom(weights); -} - -void Predictor::runForward( - const std::vector*>& input_blobs) { - if (!predictors_.get()) { - auto predictor = - folly::make_unique>(*param_); - predictor->ShareTrainedLayersWith(weights_.get()); - if (optimization_ == Optimization::MEMORY) { - optimizeMemory(predictor.get()); - } - predictors_.reset(predictor.release()); - } - auto* predictor = predictors_.get(); - CHECK(predictor); - CHECK_EQ(input_blobs.size(), predictor->input_blobs().size()); - for (auto i = 0; i < input_blobs.size(); ++i) { - auto& input_blob = input_blobs[i]; - CHECK(input_blob); - predictor->input_blobs()[i]->ReshapeLike(*input_blob); - // mutable_cpu_data b/c the interface demands it, but logically const. - predictor->input_blobs()[i]->set_cpu_data(input_blob->mutable_cpu_data()); - } - predictor->Reshape(); - predictor->ForwardPrefilled(); -} - -void Predictor::forward( - const std::vector*>& input_blobs, - const std::vector& output_layer_names, - std::vector*>* output_blobs) { - runForward(input_blobs); - auto* predictor = predictors_.get(); - output_blobs->reserve(output_layer_names.size()); - for (const auto& layer_name: output_layer_names) { - auto& output_blob = predictor->blob_by_name(layer_name); - CHECK(output_blob) << "Misspecified layer_name: " << layer_name; - if (optimization_ == Optimization::MEMORY) { - CHECK(vectorContains(predictor->output_blobs(), output_blob.get())); - } - output_blobs->push_back(output_blob.get()); - } -} - -std::vector*> Predictor::forward( - const std::vector*>& input_blobs, - const std::vector& output_layer_names) { - std::vector*> output_blobs; - output_blobs.reserve(input_blobs.size()); - forward(input_blobs, output_layer_names, &output_blobs); - return output_blobs; -} - -std::unordered_map*> Predictor::forward( - const std::vector*>& input_blobs) { - runForward(input_blobs); - auto* predictor = predictors_.get(); - auto blob_names = predictor->blob_names(); - std::unordered_map*> output_blobs; - for (const auto& blob_name: blob_names) { - auto& output_blob = predictor->blob_by_name(blob_name); - if (optimization_ == Optimization::MEMORY) { - CHECK(vectorContains(predictor->output_blobs(), output_blob.get())); - } - output_blobs[blob_name] = output_blob.get(); - } - return output_blobs; -} -} -} diff --git a/predictor/Predictor.h b/predictor/Predictor.h deleted file mode 100644 index 4c46d3a..0000000 --- a/predictor/Predictor.h +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -#pragma once -#include -#include -#include - -namespace caffe { -template -class Net; -template -class Blob; -class NetParameter; -} - -namespace caffe { -namespace fb { - -class Predictor { - public: - enum Optimization { - NONE, - MEMORY - }; - static std::unique_ptr strings( - const std::string& text_prototxt, - const std::string& binary_weights, - Optimization optimization = Optimization::NONE); - - static std::unique_ptr paths( - const std::string& prototxt_path, - const std::string& weights_path, - Optimization optimization = Optimization::NONE); - - std::vector*> forward( - const std::vector*>& input_blobs, - const std::vector& output_layer_names); - - void forward(const std::vector*>& input_blobs, - const std::vector& output_layer_names, - std::vector*>* output_blobs); - - std::unordered_map*> forward( - const std::vector*>& input_blobs); - - caffe::Net* canonicalNet() const { return weights_.get(); } - - private: - Predictor(const caffe::NetParameter& params, - const caffe::NetParameter& weights, - Optimization optimization = Optimization::NONE); - - void runForward( - const std::vector*>& input_blobs); - - // Shared for forward declaration - std::shared_ptr param_; - std::shared_ptr> weights_; - const Optimization optimization_; - - folly::ThreadLocalPtr> predictors_; -}; -} -} diff --git a/predictor/PredictorTest.cpp b/predictor/PredictorTest.cpp deleted file mode 100644 index 3d3a21a..0000000 --- a/predictor/PredictorTest.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -#include "Predictor.h" -#include "caffe/blob.hpp" -#include "caffe/filler.hpp" - -#include -#include -#include - -namespace caffe { -namespace fb { - -enum class InputTy { - PATHS = 0, - STRINGS = 1, -}; - -struct ModelSpec { - std::string prototxt; - std::string caffemodel; - std::vector inputDims; - std::string outputLayer; - std::vector> outputValues; -}; - -using Param = std::tuple; - -class PredictorTest : public ::testing::TestWithParam {}; - -TEST_P(PredictorTest, ConsistentAcrossThreads) { - const auto &inputTy = std::get<0>(GetParam()); - const auto &optimization = std::get<1>(GetParam()); - const auto &ms = std::get<2>(GetParam()); - Caffe::set_random_seed(1701); - - std::unique_ptr pp; - if (inputTy == InputTy::PATHS) { - pp = Predictor::paths(ms.prototxt, ms.caffemodel, optimization); - } else if (inputTy == InputTy::STRINGS) { - std::string prototxt_str; - folly::readFile(ms.prototxt.c_str(), prototxt_str); - std::string caffemodel_str; - folly::readFile(ms.caffemodel.c_str(), caffemodel_str); - pp = Predictor::strings(prototxt_str, caffemodel_str, optimization); - } - CHECK(pp); - auto &p = *pp; - FillerParameter param; - param.set_min(-1000); - param.set_max(1000); - UniformFiller filler(param); - Blob blob; - blob.Reshape(ms.inputDims); - filler.Fill(&blob); - auto output_blobs = p.forward({&blob}, {ms.outputLayer}); - // Test output blobs in-place. - EXPECT_EQ(1, output_blobs.size()); - output_blobs.clear(); - p.forward({&blob}, {ms.outputLayer}, &output_blobs); - EXPECT_EQ(1, output_blobs.size()); - for (const auto &kv : ms.outputValues) { - EXPECT_FLOAT_EQ(kv.second, output_blobs[0]->cpu_data()[kv.first]); - } - - auto output_blobs2 = p.forward({&blob}); - for (const auto &kv : ms.outputValues) { - EXPECT_FLOAT_EQ(kv.second, - output_blobs2[ms.outputLayer]->cpu_data()[kv.first]); - } - - // True across threads as well. - std::vector ts; - for (auto i = 0; i < 3; ++i) { - ts.emplace_back([&]() { - auto output_blobs = p.forward({&blob}, {ms.outputLayer}); - EXPECT_EQ(1, output_blobs.size()); - for (const auto &kv : ms.outputValues) { - EXPECT_FLOAT_EQ(kv.second, output_blobs[0]->cpu_data()[kv.first]); - } - }); - } - for (auto &t : ts) { - t.join(); - } -} - -INSTANTIATE_TEST_CASE_P( - P, - PredictorTest, - ::testing::Combine( - ::testing::Values(InputTy::PATHS, InputTy::STRINGS), - ::testing::Values(Predictor::Optimization::MEMORY, - Predictor::Optimization::NONE), - ::testing::Values()) - ModelSpec{ - "bvlc_caffenet/deploy.prototxt", - "bvlc_caffenet/bvlc_caffenet.caffemodel", - {1, 3, 227, 227}, - "prob", - {{5, 0.00015368311}}}, - ModelSpec{ - "bvlc_googlenet/deploy.prototxt", - "bvlc_googlenet/bvlc_googlenet.caffemodel", - {1, 3, 227, 227}, - "prob", - {{5, 0.0020543954}}}))); -} -} From fdfe3b3a99578993d6caf9e082d50aad7730878c Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Mon, 20 Jun 2016 17:51:09 -0400 Subject: [PATCH 16/48] coverter --- README.org | 126 ----------------------------------------------------- 1 file changed, 126 deletions(-) delete mode 100644 README.org diff --git a/README.org b/README.org deleted file mode 100644 index abf5604..0000000 --- a/README.org +++ /dev/null @@ -1,126 +0,0 @@ -* =fb-caffe-exts= -=fb-caffe-exts= is a collection of extensions developed at FB while using Caffe -in (mainly) production scenarios. - -** =predictor/= -A simple C++ library that wraps the common pattern of running a =caffe::Net= in -multiple threads while sharing weights. It also provides a slightly more -convenient usage API for the inference case. - -#+BEGIN_SRC c++ - #include "caffe/predictor/Predictor.h" - - // In your setup phase - predictor_ = folly::make_unique(FLAGS_prototxt_path, - FLAGS_weights_path); - - // When calling in a worker thread - static thread_local caffe::Blob input_blob; - input_blob.set_cpu_data(input_data); // avoid the copy. - const auto& output_blobs = predictor_->forward({&input_blob}); - return output_blobs[FLAGS_output_layer_name]; -#+END_SRC - -Of note is the =predictor/Optimize.{h,cpp}=, which optimizes memory -usage by automatically reusing the intermediate activations when this is safe. -This reduces the amount of memory required for intermediate activations by -around 50% for AlexNet-style models, and around 75% for GoogLeNet-style -models. - -We can plot each set of activations in the topological ordering of the network, -with a unique color for each reused activation buffer, with the height of the -blob proportional to the size of the buffer. - -For example, in an AlexNet-like model, the allocation looks like -#+ATTR_HTML: :height 300px -[[./doc/caffenet.png]] - -A corresponding allocation for GoogLeNet looks like -#+ATTR_HTML: :height 300px -[[./doc/googlenet.png]] - - -The idea is essentially linear scan register allocation. We - -- compute a set of "live ranges" for each =caffe::SyncedMemory= (due to sharing, - we can't do this at a =caffe::Blob= level) -- compute a set of live intervals, and schedule each =caffe::SyncedMemory= in a - non-overlapping fashion onto each live interval -- allocate a canonical =caffe::SyncedMemory= buffer for each live interval -- Update the blob internal pointers to point to the canonical buffer - -Depending on the model, the buffer reuse can also lead to some non-trivial -performance improvements at inference time. - -To enable this just pass =Predictor::Optimization::MEMORY= to the =Predictor= -constructor. - -** =torch2caffe/= -A library for converting pre-trained Torch models to the equivalent Caffe models. - -=torch_layers.lua= describes the set of layers that we can automatically -convert, and =test.lua= shows some examples of more complex models being -converted end to end. - -For example, complex CNNs ([[http://arxiv.org/abs/1409.4842][GoogLeNet]], etc), deep LSTMs (created in [[https://github.com/torch/nngraph][nngraph]]), -models with tricky parallel/split connectivity structures ([[http://arxiv.org/abs/1103.0398][Natural Language -Processing (almost) from Scratch]]), etc. - -This can be invoked as - -#+BEGIN_EXAMPLE - ∴ th torch2caffe/torch2caffe.lua --help - --input (default "") Input model file - --preprocessing (default "") Preprocess the model - --prototxt (default "") Output prototxt model file - --caffemodel (default "") Output model weights file - --format (default "lua") Format: lua | luathrift - --input-tensor (default "") (Optional) Predefined input tensor - --verify (default "") (Optional) Verify existing - (number) Input dimensions (e.g. 10N x 3C x 227H x 227W) - -#+END_EXAMPLE - - -This works by - -- (optionally) preprocessing the model provided in =--input=, (folding - BatchNormalization layers into the preceding layer, etc), -- walking the Torch module graph of the model provide in =--input=, -- converting it to the equivalent Caffe module graph, -- copying the weights into the Caffe model, -- Running some test inputs (of size =input_dims...=) through both models and - verifying the outputs are identical. -** =conversions/= -A simple CLI tool for running some simple Caffe network transformations. - -#+BEGIN_EXAMPLE - ∴ python conversions.py vision --help - Usage: conversions.py vision [OPTIONS] - - Options: - --prototxt TEXT [required] - --caffemodel TEXT [required] - --output-prototxt TEXT [required] - --output-caffemodel TEXT [required] - --help Show this message and exit. -#+END_EXAMPLE - -The main usage at the moment is automating the [[https://github.com/BVLC/caffe/blob/master/examples/net_surgery.ipynb][Net Surgery]] notebook. - - -** Building and Installing -As you might expect, this library depends on an up-to-date [[http://caffe.berkeleyvision.org/][BVLC Caffe]] installation. - -The additional dependencies are - -- The C++ libraries require [[https://github.com/facebook/folly][folly]]. -- The Python =conversions= libraries requires [[http://click.pocoo.org/5/][click]]. - -You can drop the C++ components into an existing Caffe installation. We'll -update the repo with an example modification to an existing =Makefile.config= -and a =CMake= based solution. - -** Contact -Feel free to open issues on this repo for requests/bugs, or contact [[mailto:tulloch@fb.com][Andrew -Tulloch]] directly. From 692d57e8055dec432a402390851d92d5380cdbac Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Mon, 20 Jun 2016 18:08:26 -0400 Subject: [PATCH 17/48] Create README.md --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..09a52eb --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +## Torch to Caffe Model Converter +(forked from [Cysu's branch](https://github.com/Cysu/fb-caffe-exts), originally from [fb-caffe-exts](https://github.com/facebook/fb-caffe-exts)) + +### Get Started +0. An easy option for fast using is launch an AWS EC2 g2.x2large instance I created. Choose N.California Sever and search the instance name of FB-Torch2Caffe (ami-03542e63). +0. The package currently only works on Ubuntu 14.04. Please make sure Torch and Caffe (with pycaffe and python layer) are correctly installed. +0. Download the code and install the dependencies + ```bash + git clone https://github.com/zhanghang1989/fb-caffe-exts.git + sudo bash install-dep.sh + ``` + +0. Convert your first model: + ```bash + th convert.lua torch_model.t7b + ``` + +0. Or custormize the conversion: + ```bash + th torch2caffe/torch2caffe.lua --input torch_model.t7b --preprocessing --prepnv.lua --prototxt name.prototxt --caffemodel name.caffemodel --input_dims 1 3 64 256 + ``` + +###. The Layers We Added Support +0. ``ELU`` +0. ``SpatialDropout`` We scale the weights of previous layers by (1-p) to hide the difference between torch and caffe. +0. ``SpatialMaxPooling`` It has slightly different behaviours in Torch and Caffe. Torch uses floor(n/s+1) and Caffe uses floor(n/s). Therefore, only the conversion of even featuremap size is supported. +0. ``SpatialBatchNormalization`` Caffe BatchNorm doesn't have bias. We only support non-affine BN. Alternatively, you can convert it into a customized version of BN as in [Cysu's branch](https://github.com/Cysu/fb-caffe-exts). + +### From 681f2ef69f76289e8b40856ece2ddb73f105a89b Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Mon, 20 Jun 2016 18:08:48 -0400 Subject: [PATCH 18/48] Create install-dep.sh --- install-dep.sh | 143 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 install-dep.sh diff --git a/install-dep.sh b/install-dep.sh new file mode 100644 index 0000000..a62ade2 --- /dev/null +++ b/install-dep.sh @@ -0,0 +1,143 @@ +#!/bin/bash -e +# +# Copyright (c) 2014, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. An additional grant +# of patent rights can be found in the PATENTS file in the same directory. +# + +echo +echo This script will install fblualib and all its dependencies. +echo It has been tested on Ubuntu 13.10 and Ubuntu 14.04, Linux x86_64. +echo + +set -e +set -x + + +if [[ $(arch) != 'x86_64' ]]; then + echo "x86_64 required" >&2 + exit 1 +fi + +issue=$(cat /etc/issue) +extra_packages= +if [[ $issue =~ ^Ubuntu\ 13\.10 ]]; then + : +elif [[ $issue =~ ^Ubuntu\ 14 ]]; then + extra_packages=libiberty-dev +elif [[ $issue =~ ^Ubuntu\ 15\.04 ]]; then + extra_packages=libiberty-dev +elif [[ $issue =~ ^Ubuntu\ 16\.04 ]]; then + extra_packages=libiberty-dev +else + echo "Ubuntu 13.10, 14.* or 15.04 required" >&2 + exit 1 +fi + +dir=$(mktemp --tmpdir -d fblualib-build.XXXXXX) + +echo Working in $dir +echo +cd $dir + +echo Installing required packages +echo +sudo apt-get install -y \ + git \ + curl \ + wget \ + g++ \ + automake \ + autoconf \ + autoconf-archive \ + libtool \ + libboost-all-dev \ + libevent-dev \ + libdouble-conversion-dev \ + libgoogle-glog-dev \ + libgflags-dev \ + liblz4-dev \ + liblzma-dev \ + libsnappy-dev \ + make \ + zlib1g-dev \ + binutils-dev \ + libjemalloc-dev \ + $extra_packages \ + flex \ + bison \ + libkrb5-dev \ + libsasl2-dev \ + libnuma-dev \ + pkg-config \ + libssl-dev \ + libedit-dev \ + libmatio-dev \ + libpython-dev \ + libpython3-dev \ + python-numpy + +echo +echo Cloning repositories +echo +git clone -b v0.35.0 --depth 1 https://github.com/facebook/folly +git clone -b v0.24.0 --depth 1 https://github.com/facebook/fbthrift +git clone -b v1.0 https://github.com/facebook/thpp +git clone -b v1.0 https://github.com/facebook/fblualib + +echo +echo Building folly +echo + +cd $dir/folly/folly +autoreconf -ivf +./configure +make +sudo make install +sudo ldconfig # reload the lib paths after freshly installed folly. fbthrift needs it. + +echo +echo Building fbthrift +echo + +cd $dir/fbthrift/thrift +autoreconf -ivf +./configure +make +sudo make install + +echo +echo 'Installing TH++' +echo + +cd $dir/thpp/thpp +./build.sh + +echo +echo 'Installing FBLuaLib' +echo + +cd $dir/fblualib/fblualib +./build.sh +cd $dir/fblualib/fblualib/python +luarocks make rockspec/fbpython-0.1-1.rockspec + +echo +echo 'Almost done!' +echo + +git clone https://github.com/torch/nn && ( cd nn && git checkout getParamsByDevice && luarocks make rocks/nn-scm-1.rockspec ) + +git clone https://github.com/facebook/fbtorch.git && ( cd fbtorch && luarocks make rocks/fbtorch-scm-1.rockspec ) + +git clone https://github.com/facebook/fbnn.git && ( cd fbnn && luarocks make rocks/fbnn-scm-1.rockspec ) + +git clone https://github.com/facebook/fbcunn.git && ( cd fbcunn && luarocks make rocks/fbcunn-scm-1.rockspec ) + + +echo +echo 'All done!' +echo From 339a6142399b49ce5f3985607380fc895e2a8b6b Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Mon, 20 Jun 2016 18:11:46 -0400 Subject: [PATCH 19/48] Update README.md --- README.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 09a52eb..a1431ae 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,11 @@ sudo bash install-dep.sh ``` +0. Add Environment Variables **IMPORTANT** + ```bash + export "LD_PRELOAD=/path/to/libcaffe.so" + ``` + 0. Convert your first model: ```bash th convert.lua torch_model.t7b @@ -20,10 +25,16 @@ th torch2caffe/torch2caffe.lua --input torch_model.t7b --preprocessing --prepnv.lua --prototxt name.prototxt --caffemodel name.caffemodel --input_dims 1 3 64 256 ``` -###. The Layers We Added Support +### The Layers We Added Support 0. ``ELU`` 0. ``SpatialDropout`` We scale the weights of previous layers by (1-p) to hide the difference between torch and caffe. 0. ``SpatialMaxPooling`` It has slightly different behaviours in Torch and Caffe. Torch uses floor(n/s+1) and Caffe uses floor(n/s). Therefore, only the conversion of even featuremap size is supported. 0. ``SpatialBatchNormalization`` Caffe BatchNorm doesn't have bias. We only support non-affine BN. Alternatively, you can convert it into a customized version of BN as in [Cysu's branch](https://github.com/Cysu/fb-caffe-exts). -### +### Known Issues +0. ``LD_PRELOAD`` crashes your gedit (If you know how to fix it, please update this wiki.) +0. The opencv package that Caffe relies on may cause the error of "libdc1394" failed to initialize, just create a fake device: + ```bash + sudo ln /dev/null /dev/raw1394 + ``` + From cdbf16a9f7625533ef05c38dcbfb64036b1becf2 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Mon, 20 Jun 2016 18:12:08 -0400 Subject: [PATCH 20/48] Delete CONTRIBUTING.md --- CONTRIBUTING.md | 42 ------------------------------------------ 1 file changed, 42 deletions(-) delete mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index e2e8d6d..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,42 +0,0 @@ -# Contributing to `fb-caffe-exts` -We want to make contributing to this project as easy and transparent as -possible. - -## Our Development Process -We sync from an internal codebase, which is the source of truth for this -project. We will apply pull requests to this codebase. - -## Pull Requests -We actively welcome your pull requests. - -1. Fork the repo and create your branch from `master`. -2. If you've added code that should be tested, add tests. -3. If you've changed APIs, update the documentation. -4. Ensure the test suite passes. -5. Make sure your code lints. -6. If you haven't already, complete the Contributor License Agreement ("CLA"). - -## Contributor License Agreement ("CLA") -In order to accept your pull request, we need you to submit a CLA. You only need -to do this once to work on any of Facebook's open source projects. - -Complete your CLA here: - -## Issues -We use GitHub issues to track public bugs. Please ensure your description is -clear and has sufficient instructions to be able to reproduce the issue. - -Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe -disclosure of security bugs. In those cases, please go through the process -outlined on that page and do not file a public issue. - -## Coding Style -* 2 spaces for indentation rather than tabs -* 80 character line length -* Lua files should pass `luacheck` -* Python files should pass `flake8` -* C++ files should be run through `clang-format` - -## License -By contributing to `fb-caffe-exts` you agree that your contributions will be licensed -under its BSD license. From 78c50888248554680a5634e805505cdf21b90abe Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Mon, 20 Jun 2016 18:19:47 -0400 Subject: [PATCH 21/48] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a1431ae..e13df81 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ (forked from [Cysu's branch](https://github.com/Cysu/fb-caffe-exts), originally from [fb-caffe-exts](https://github.com/facebook/fb-caffe-exts)) ### Get Started -0. An easy option for fast using is launch an AWS EC2 g2.x2large instance I created. Choose N.California Sever and search the instance name of FB-Torch2Caffe (ami-03542e63). +0. An easy option for fast using is launch an AWS EC2 g2.2xlarge instance I created. Choose N.California Sever and search the instance name of FB-Torch2Caffe (ami-03542e63). [You can follow the [AWS tutorial](http://cs231n.github.io/aws-tutorial/)] 0. The package currently only works on Ubuntu 14.04. Please make sure Torch and Caffe (with pycaffe and python layer) are correctly installed. 0. Download the code and install the dependencies ```bash @@ -10,9 +10,10 @@ sudo bash install-dep.sh ``` -0. Add Environment Variables **IMPORTANT** +0. Add Environment Variables (Change the path for your own machine) ```bash - export "LD_PRELOAD=/path/to/libcaffe.so" + echo "export LD_PRELOAD=/path/to/libcaffe.so" >>~/.bashrc && source ~/.bashrc + source ~/.bashrc ``` 0. Convert your first model: From 7d965f42d484b5f9e1bda4ba73130a04a075f7e4 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Mon, 20 Jun 2016 18:22:10 -0400 Subject: [PATCH 22/48] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e13df81..de6b066 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ 0. Add Environment Variables (Change the path for your own machine) ```bash - echo "export LD_PRELOAD=/path/to/libcaffe.so" >>~/.bashrc && source ~/.bashrc + echo "export LD_PRELOAD=/path/to/libcaffe.so; export PYTHONPATH=$PYTHONPATH:/path/to/caffe/python/:/path/to/fb-caffe-exts/;" >>~/.bashrc && source ~/.bashrc source ~/.bashrc ``` From 61b7366945a3b05a468296d7ba3b19baa9742a50 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Mon, 20 Jun 2016 18:23:25 -0400 Subject: [PATCH 23/48] Delete prep.lua --- torch2caffe/prep.lua | 67 -------------------------------------------- 1 file changed, 67 deletions(-) delete mode 100644 torch2caffe/prep.lua diff --git a/torch2caffe/prep.lua b/torch2caffe/prep.lua deleted file mode 100644 index e2b0e47..0000000 --- a/torch2caffe/prep.lua +++ /dev/null @@ -1,67 +0,0 @@ -require 'nn' -require 'cunn' -require 'cudnn' - -local trans = require 'torch2caffe.transforms' - -local function adapt_conv1(layer) - local std = torch.FloatTensor({0.229, 0.224, 0.225}) * 255 - local sz = layer.weight:size() - sz[2] = 1 - layer.weight = layer.weight:cdiv(std:view(1,3,1,1):repeatTensor(sz)) - local tmp = layer.weight:clone() - tmp[{{}, 1, {}, {}}] = layer.weight[{{}, 3, {}, {}}] - tmp[{{}, 3, {}, {}}] = layer.weight[{{}, 1, {}, {}}] - layer.weight = tmp:clone() -end - -local function adapt_sequential_dropout(model) - -- does not support recursive sequential(dropout) - for k, block in pairs(model:findModules('nn.SequentialDropout')) do - -- find last conv / bn / linear layer and scale its weight by 1-p - local found = false - for j = #block.modules,1,-1 do - local block_type = torch.type(block.modules[j]) - if block_type == 'nn.SpatialConvolution' - or block_type == 'nn.Linear' - or block_type == 'nn.SpatialBatchNormalization' then - block.modules[j].weight:mul(1 - block.p) - if block.modules[j].bias then - block.modules[j].bias:mul(1 - block.p) - end - found = true - break - end - end - if not found then - error('SequentialDropout module cannot find weight to scale') - end - end -end - -g_t2c_preprocess = function(model, opts) - model = cudnn.convert(model, nn) - --model = trans.fold_batch_normalization_layers(model, opts) - for _, layer in pairs(model:findModules('nn.SpatialConvolution')) do - layer.weight = layer.weight:float() - if layer.bias then - layer.bias = layer.bias:float() - end - end - for _, layer in pairs(model:findModules('nn.Linear')) do - layer.weight = layer.weight:float() - if layer.bias then - layer.bias = layer.bias:float() - end - end - for _, layer in pairs(model:findModules('nn.SpatialBatchNormalization')) do - layer.weight = layer.weight:float() - layer.bias = layer.bias:float() - layer.running_mean = layer.running_mean:float() - layer.running_var = layer.running_var:float() - end - adapt_conv1(model.modules[1]) - adapt_sequential_dropout(model) - return model -end - From 330987a67317f596932892b9f57edce13d47d281 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Mon, 20 Jun 2016 18:23:53 -0400 Subject: [PATCH 24/48] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index de6b066..5e6c951 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ 0. Or custormize the conversion: ```bash - th torch2caffe/torch2caffe.lua --input torch_model.t7b --preprocessing --prepnv.lua --prototxt name.prototxt --caffemodel name.caffemodel --input_dims 1 3 64 256 + th torch2caffe/torch2caffe.lua --input torch_model.t7b --preprocessing prepnv.lua --prototxt name.prototxt --caffemodel name.caffemodel --input_dims 1 3 64 256 ``` ### The Layers We Added Support From 17bc441f5d1b1190d2b73161c066665fad22b4e1 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Mon, 20 Jun 2016 19:02:13 -0400 Subject: [PATCH 25/48] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5e6c951..fab3f28 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ (forked from [Cysu's branch](https://github.com/Cysu/fb-caffe-exts), originally from [fb-caffe-exts](https://github.com/facebook/fb-caffe-exts)) ### Get Started -0. An easy option for fast using is launch an AWS EC2 g2.2xlarge instance I created. Choose N.California Sever and search the instance name of FB-Torch2Caffe (ami-03542e63). [You can follow the [AWS tutorial](http://cs231n.github.io/aws-tutorial/)] +0. An easy option is to launch an AWS EC2 g2.2xlarge instance I created. Choose N.California Sever and search the instance name of FB-Torch2Caffe (ami-03542e63). [You can follow the [AWS tutorial](http://cs231n.github.io/aws-tutorial/)] 0. The package currently only works on Ubuntu 14.04. Please make sure Torch and Caffe (with pycaffe and python layer) are correctly installed. 0. Download the code and install the dependencies ```bash From aa2c50d04f89eb53c3055c8ea0ee83359f6b90e9 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Mon, 20 Jun 2016 20:50:38 -0400 Subject: [PATCH 26/48] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fab3f28..e1a0895 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ (forked from [Cysu's branch](https://github.com/Cysu/fb-caffe-exts), originally from [fb-caffe-exts](https://github.com/facebook/fb-caffe-exts)) ### Get Started -0. An easy option is to launch an AWS EC2 g2.2xlarge instance I created. Choose N.California Sever and search the instance name of FB-Torch2Caffe (ami-03542e63). [You can follow the [AWS tutorial](http://cs231n.github.io/aws-tutorial/)] +0. The easiest option is to launch an AWS EC2 g2.2xlarge instance I created. Choose N.California Sever and search for the instance name of FB-Torch2Caffe (ami-03542e63). [You can follow the [AWS tutorial](http://cs231n.github.io/aws-tutorial/)] 0. The package currently only works on Ubuntu 14.04. Please make sure Torch and Caffe (with pycaffe and python layer) are correctly installed. 0. Download the code and install the dependencies ```bash From 8753dfbe55f4289835f913ffe4633939ab0dff42 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Tue, 5 Jul 2016 18:04:17 -0400 Subject: [PATCH 27/48] Update convert.lua --- convert.lua | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/convert.lua b/convert.lua index bc54257..b5c18d9 100644 --- a/convert.lua +++ b/convert.lua @@ -1,23 +1,3 @@ -#!/usr/bin/env th ---++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ---! ---! model_test_loss.lua ---! ---! Brief: -- Script to take a trained model file, with all the included ---! training and data parameters, and make it usable by our ---! DrivePX. Major component is to save it as a .txt instead of ---! tensor binary. However, at the time we are also downgrading ---! models since the DrivePX is stuck on CUDNNv3 ---! ---! Author: NVIDIA CORPORATION, ---! www.nvidia.com ---! Created 2016-03-18 by Karol Zieba (kzieba@nvidia.com) ---! ---! Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. ---! ---++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - require 'nn'; require 'cunn'; require 'cudnn'; From 160af7c7f6abce992d24785384806b5bec8ea446 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Mon, 11 Jul 2016 13:45:14 -0400 Subject: [PATCH 28/48] Rename install-dep.sh to install-dep-14.04.sh --- install-dep.sh => install-dep-14.04.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename install-dep.sh => install-dep-14.04.sh (100%) diff --git a/install-dep.sh b/install-dep-14.04.sh similarity index 100% rename from install-dep.sh rename to install-dep-14.04.sh From 38c477a9315a423feeda1996af8f6f78abd37682 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Thu, 14 Jul 2016 12:46:55 -0400 Subject: [PATCH 29/48] Create install-dep-16.04.sh --- install-dep-16.04.sh | 150 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 install-dep-16.04.sh diff --git a/install-dep-16.04.sh b/install-dep-16.04.sh new file mode 100644 index 0000000..73ee217 --- /dev/null +++ b/install-dep-16.04.sh @@ -0,0 +1,150 @@ + +echo +echo This script will install fblualib and all its dependencies. +echo It has been tested on Ubuntu 13.10 and Ubuntu 14.04, Linux x86_64. +echo + +set -e +set -x + + +if [[ $(arch) != 'x86_64' ]]; then + echo "x86_64 required" >&2 + exit 1 +fi + +issue=$(cat /etc/issue) +extra_packages= +current=0 +if [[ $issue =~ ^Ubuntu\ 16\.04 ]]; then + extra_packages=libiberty-dev + current=1 +else + echo "Ubuntu 13.10, 14.*, 15.04 or 16.04 required" >&2 + exit 1 +fi + +dir=$(mktemp --tmpdir -d fblualib-build.XXXXXX) + +echo Working in $dir +echo +cd $dir + +echo Installing required packages +echo +sudo apt-get install -y \ + git \ + curl \ + wget \ + g++ \ + automake \ + autoconf \ + autoconf-archive \ + libtool \ + libboost-all-dev \ + libevent-dev \ + libdouble-conversion-dev \ + libgoogle-glog-dev \ + libgflags-dev \ + liblz4-dev \ + liblzma-dev \ + libsnappy-dev \ + make \ + zlib1g-dev \ + binutils-dev \ + libjemalloc-dev \ + $extra_packages \ + flex \ + bison \ + libkrb5-dev \ + libsasl2-dev \ + libnuma-dev \ + pkg-config \ + libssl-dev \ + libedit-dev \ + libmatio-dev \ + libpython-dev \ + libpython3-dev \ + python-numpy + +echo +echo Cloning repositories +echo + + + +git clone --depth 1 https://github.com/facebook/folly +git clone --depth 1 https://github.com/facebook/fbthrift +git clone https://github.com/facebook/thpp +git clone https://github.com/facebook/fblualib +git clone https://github.com/zhanghang1989/fblualib + + + +echo +echo Building folly +echo + +cd $dir/folly/folly +autoreconf -ivf +./configure +make +sudo make install +sudo ldconfig # reload the lib paths after freshly installed folly. fbthrift needs it. + +if [ $current -eq 1 ]; then + echo + echo Wangle + echo + + cd $dir/wangle/wangle + cmake . + make + sudo make install +fi + +echo +echo Building fbthrift +echo + +cd $dir/fbthrift/thrift +autoreconf -ivf +./configure +if [ $current -eq 1 ]; then + pushd lib/cpp2/fatal/internal + ln -s folly_dynamic-inl-pre.h folly_dynamic-inl.h + popd +fi +make +sudo make install + +echo +echo 'Installing TH++' +echo + +cd $dir/thpp/thpp +./build.sh + +echo +echo 'Installing FBLuaLib' +echo + +cd $dir/fblualib/fblualib +./build.sh +cd $dir/fblualib/fblualib/python +luarocks make rockspec/fbpython-0.1-1.rockspec + +echo +echo 'Almost done!' +echo + +git clone https://github.com/torch/nn && ( cd nn && git checkout getParamsByDevice && luarocks make rocks/nn-scm-1.rockspec ) + +git clone https://github.com/facebook/fbtorch.git && ( cd fbtorch && luarocks make rocks/fbtorch-scm-1.rockspec ) + +git clone https://github.com/facebook/fbnn.git && ( cd fbnn && luarocks make rocks/fbnn-scm-1.rockspec ) + + +echo +echo 'All done!' +echo From 0c6e39522d78e12b49588288a6670c72209addef Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Thu, 14 Jul 2016 12:47:39 -0400 Subject: [PATCH 30/48] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e1a0895..cfa6b2e 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ### Get Started 0. The easiest option is to launch an AWS EC2 g2.2xlarge instance I created. Choose N.California Sever and search for the instance name of FB-Torch2Caffe (ami-03542e63). [You can follow the [AWS tutorial](http://cs231n.github.io/aws-tutorial/)] -0. The package currently only works on Ubuntu 14.04. Please make sure Torch and Caffe (with pycaffe and python layer) are correctly installed. +0. Please make sure Torch and Caffe (with pycaffe and python layer) are correctly installed. 0. Download the code and install the dependencies ```bash git clone https://github.com/zhanghang1989/fb-caffe-exts.git From 58e34820efd2a8d350a299ee451e5340876a568a Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Thu, 14 Jul 2016 18:55:20 -0400 Subject: [PATCH 31/48] Update install-dep-16.04.sh --- install-dep-16.04.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/install-dep-16.04.sh b/install-dep-16.04.sh index 73ee217..0111967 100644 --- a/install-dep-16.04.sh +++ b/install-dep-16.04.sh @@ -76,7 +76,6 @@ echo git clone --depth 1 https://github.com/facebook/folly git clone --depth 1 https://github.com/facebook/fbthrift git clone https://github.com/facebook/thpp -git clone https://github.com/facebook/fblualib git clone https://github.com/zhanghang1989/fblualib From 427aed3702cc185c6a1fe5d02ad7630aab06a879 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Fri, 15 Jul 2016 13:36:43 -0400 Subject: [PATCH 32/48] converter --- convert.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/convert.lua b/convert.lua index b5c18d9..497da9b 100644 --- a/convert.lua +++ b/convert.lua @@ -10,6 +10,7 @@ g_SLOW="" -- Figure out the path of the model and load it local path = arg[1] +local basename = paths.basename(path, 't7b') local ext = path:match("^.+(%..+)$") local model = nil if ext == '.t7b' then @@ -83,8 +84,8 @@ model=g_t2c_preprocess(model, opts) local function check(module, module2,input_dims) module:apply(function(m) m:evaluate() end) local opts = { - prototxt='1.prototxt', - caffemodel='1.caffemodel', + prototxt = string.format('%s.prototxt', basename), + caffemodel = string.format('%s.caffemodel', basename), inputs={{name="data", input_dims=input_dims}}, } t2c.convert(opts, module) @@ -93,7 +94,7 @@ local function check(module, module2,input_dims) end -check(model, model2, {1,3,64,256}) +check(model, model2, {1,3,66,200}) -- Save the model From e451ac85a401ec00bbf5f900238560f8e2d4a241 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Fri, 15 Jul 2016 16:14:38 -0400 Subject: [PATCH 33/48] defaults --- convert.lua | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/convert.lua b/convert.lua index 497da9b..cae469c 100644 --- a/convert.lua +++ b/convert.lua @@ -24,8 +24,6 @@ end local function adapt_spatial_dropout(net) - -- does not support recursive sequential(dropout) - --print (model) for i = 1, #net.modules do local c = net:get(i) local t = torch.type(c) @@ -75,11 +73,8 @@ if model.net then model = model.net model2 = model2.net end ---model.net=g_t2c_preprocess(model.net, opts) ---model=nn.utils.recursiveType(model, 'torch.FloatTensor') -model=g_t2c_preprocess(model, opts) ---torch.setdefaulttensortype('torch.FloatTensor') +model=g_t2c_preprocess(model, opts) local function check(module, module2,input_dims) module:apply(function(m) m:evaluate() end) @@ -94,9 +89,5 @@ local function check(module, module2,input_dims) end -check(model, model2, {1,3,66,200}) - +check(model, model2, {1,3,224,224}) --- Save the model ---local out_path = path:sub(1, #path - 4) .. "_c.t7b" ---torch.save(out_path, model.net) From 81d0af1ae559fd88412043ace6b85103f1920dc5 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Fri, 15 Jul 2016 16:31:43 -0400 Subject: [PATCH 34/48] verify --- verify.lua | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/verify.lua b/verify.lua index ae40663..a26170e 100644 --- a/verify.lua +++ b/verify.lua @@ -3,11 +3,20 @@ require 'cunn' local pl = require 'pl.import_into'() local py = require 'fb.python' local torch = require 'torch' ---require 'fbtorch' --- local logging = require 'fb.util.logging' local torch_layers = require 'torch2caffe.torch_layers' local t2c = py.import('torch2caffe.lib_py') +-- Figure out the path of the model and load it +local path = arg[1] +local basename = paths.basename(path, 't7b') +local ext = path:match("^.+(%..+)$") +local model = nil +if ext == '.t7b' or ext == '.t7' then + torch_net = torch.load(path) +else + assert(false, "We assume models end in either .t7b or .t7") +end + local function evaluate_caffe(caffe_net, inputs) local input_kwargs = {} for i=1,#inputs do @@ -65,26 +74,22 @@ end local function test() - local torch_net = torch.load('gienet.t7b') if torch_net.net then torch_net=torch_net.net end torch_net:apply(function(m) m:evaluate() end) - --torch_net=cudnn.convert(torch_net,nn) - --torch_net=nn.utils.recursiveType(model, 'torch.FloatTensor') + local opts = {} - opts.prototxt = '1.prototxt' - opts.caffemodel = '1.caffemodel' + opts.prototxt = string.format('%s.prototxt', basename) + opts.caffemodel = string.format('%s.caffemodel', basename) local caffe_net = t2c.load(opts) -- local inputs={} - --local tensor = torch.load('input.txt','ascii') - local tensor = torch.rand(table.unpack({1,3,64,256})):float() + local tensor = torch.rand(table.unpack({1,3,224,224})):float() table.insert(inputs, {name='data', tensor=tensor}) print ("\n\n\n\nTesting Caffe Model\n\n\n\n") local caffe_outputs = evaluate_caffe(caffe_net, inputs) - local torch_outputs -- Some networks only accept CUDA input. @@ -142,8 +147,6 @@ local function test() end end print (caffe_outputs[1]) --- torch.save('input.txt',tensor,'ascii', false) --- torch.save('output.txt',caffe_outputs,'ascii',false) end -- test() From 60c0104fd12328466073183cbe124ec6f0df4ac3 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Fri, 15 Jul 2016 16:43:18 -0400 Subject: [PATCH 35/48] dependencies --- install-dep-14.04.sh | 23 +++-------------------- install-dep-16.04.sh | 6 +++--- 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/install-dep-14.04.sh b/install-dep-14.04.sh index a62ade2..9675614 100644 --- a/install-dep-14.04.sh +++ b/install-dep-14.04.sh @@ -1,12 +1,3 @@ -#!/bin/bash -e -# -# Copyright (c) 2014, Facebook, Inc. -# All rights reserved. -# -# This source code is licensed under the BSD-style license found in the -# LICENSE file in the root directory of this source tree. An additional grant -# of patent rights can be found in the PATENTS file in the same directory. -# echo echo This script will install fblualib and all its dependencies. @@ -24,16 +15,10 @@ fi issue=$(cat /etc/issue) extra_packages= -if [[ $issue =~ ^Ubuntu\ 13\.10 ]]; then - : -elif [[ $issue =~ ^Ubuntu\ 14 ]]; then - extra_packages=libiberty-dev -elif [[ $issue =~ ^Ubuntu\ 15\.04 ]]; then - extra_packages=libiberty-dev -elif [[ $issue =~ ^Ubuntu\ 16\.04 ]]; then +if [[ $issue =~ ^Ubuntu\ 14\.04 ]]; then extra_packages=libiberty-dev else - echo "Ubuntu 13.10, 14.* or 15.04 required" >&2 + echo "Ubuntu 14.04 required" >&2 exit 1 fi @@ -97,7 +82,7 @@ autoreconf -ivf ./configure make sudo make install -sudo ldconfig # reload the lib paths after freshly installed folly. fbthrift needs it. +sudo ldconfig echo echo Building fbthrift @@ -135,8 +120,6 @@ git clone https://github.com/facebook/fbtorch.git && ( cd fbtorch && luarocks ma git clone https://github.com/facebook/fbnn.git && ( cd fbnn && luarocks make rocks/fbnn-scm-1.rockspec ) -git clone https://github.com/facebook/fbcunn.git && ( cd fbcunn && luarocks make rocks/fbcunn-scm-1.rockspec ) - echo echo 'All done!' diff --git a/install-dep-16.04.sh b/install-dep-16.04.sh index 0111967..899c6ff 100644 --- a/install-dep-16.04.sh +++ b/install-dep-16.04.sh @@ -1,7 +1,7 @@ echo echo This script will install fblualib and all its dependencies. -echo It has been tested on Ubuntu 13.10 and Ubuntu 14.04, Linux x86_64. +echo It has been Ubuntu 16.04, Linux x86_64. echo set -e @@ -20,7 +20,7 @@ if [[ $issue =~ ^Ubuntu\ 16\.04 ]]; then extra_packages=libiberty-dev current=1 else - echo "Ubuntu 13.10, 14.*, 15.04 or 16.04 required" >&2 + echo "Ubuntu 16.04 required" >&2 exit 1 fi @@ -89,7 +89,7 @@ autoreconf -ivf ./configure make sudo make install -sudo ldconfig # reload the lib paths after freshly installed folly. fbthrift needs it. +sudo ldconfig if [ $current -eq 1 ]; then echo From 013fa3944b9cc55656c1ff20e590cec129a9f10e Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Fri, 15 Jul 2016 16:58:01 -0400 Subject: [PATCH 36/48] dependencies --- install-dep-16.04.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) mode change 100644 => 100755 install-dep-16.04.sh diff --git a/install-dep-16.04.sh b/install-dep-16.04.sh old mode 100644 new mode 100755 index 899c6ff..4feaed5 --- a/install-dep-16.04.sh +++ b/install-dep-16.04.sh @@ -72,13 +72,11 @@ echo Cloning repositories echo - git clone --depth 1 https://github.com/facebook/folly git clone --depth 1 https://github.com/facebook/fbthrift git clone https://github.com/facebook/thpp git clone https://github.com/zhanghang1989/fblualib - - +git clone https://github.com/facebook/wangle echo echo Building folly From 39c0760c34962ea75442336a92592d337e57a9b7 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Mon, 8 Aug 2016 22:30:55 -0400 Subject: [PATCH 37/48] avoid stupid changes --- install-dep-16.04.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install-dep-16.04.sh b/install-dep-16.04.sh index 4feaed5..ee11026 100755 --- a/install-dep-16.04.sh +++ b/install-dep-16.04.sh @@ -72,8 +72,8 @@ echo Cloning repositories echo -git clone --depth 1 https://github.com/facebook/folly -git clone --depth 1 https://github.com/facebook/fbthrift +git clone --depth 1 https://github.com/zhanghang1989/folly.git +git clone --depth 1 https://github.com/zhanghang1989/fbthrift git clone https://github.com/facebook/thpp git clone https://github.com/zhanghang1989/fblualib git clone https://github.com/facebook/wangle From f6729dda478534f93c4ccb33ba5d34811cb85eb6 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Tue, 9 Aug 2016 23:59:49 -0400 Subject: [PATCH 38/48] convert all --- convert_all.sh | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100755 convert_all.sh diff --git a/convert_all.sh b/convert_all.sh new file mode 100755 index 0000000..c5a97ed --- /dev/null +++ b/convert_all.sh @@ -0,0 +1,6 @@ +export LD_PRELOAD=$HOME/caffe/.build_release/lib/libcaffe.so; + +for f in *.t7b +do + th convert.lua $f +done From 9c21a04898df662fc971492d2416d484f41a11f6 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Tue, 16 Aug 2016 11:55:43 -0400 Subject: [PATCH 39/48] Update install-dep-16.04.sh --- install-dep-16.04.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/install-dep-16.04.sh b/install-dep-16.04.sh index ee11026..0cc2ab4 100755 --- a/install-dep-16.04.sh +++ b/install-dep-16.04.sh @@ -72,7 +72,7 @@ echo Cloning repositories echo -git clone --depth 1 https://github.com/zhanghang1989/folly.git +git clone --depth 1 https://github.com/zhanghang1989/folly git clone --depth 1 https://github.com/zhanghang1989/fbthrift git clone https://github.com/facebook/thpp git clone https://github.com/zhanghang1989/fblualib @@ -107,11 +107,6 @@ echo cd $dir/fbthrift/thrift autoreconf -ivf ./configure -if [ $current -eq 1 ]; then - pushd lib/cpp2/fatal/internal - ln -s folly_dynamic-inl-pre.h folly_dynamic-inl.h - popd -fi make sudo make install From 998d5d11ef798971b89a951574d38deb0cc47e1f Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Tue, 16 Aug 2016 13:40:12 -0400 Subject: [PATCH 40/48] some script --- .gitignore | 6 ++ clean.sh | 3 + verify2.lua | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 .gitignore create mode 100755 clean.sh create mode 100644 verify2.lua diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b81e1c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +torch2caffe/*.pyc +*.t7b +*.caffemodel +*.prototxt +*.csv + diff --git a/clean.sh b/clean.sh new file mode 100755 index 0000000..a0a8231 --- /dev/null +++ b/clean.sh @@ -0,0 +1,3 @@ +rm *.caffemodel +rm *.prototxt +rm *t7b diff --git a/verify2.lua b/verify2.lua new file mode 100644 index 0000000..efe7216 --- /dev/null +++ b/verify2.lua @@ -0,0 +1,170 @@ +#!/usr/bin/env th +--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +--! +--! model_test_loss.lua +--! +--! Brief: -- Script to take a trained model file, with all the included +--! training and data parameters, and make it usable by our +--! DrivePX. Major component is to save it as a .txt instead of +--! tensor binary. However, at the time we are also downgrading +--! models since the DrivePX is stuck on CUDNNv3 +--! +--! Author: NVIDIA CORPORATION, +--! www.nvidia.com +--! Created 2016-03-18 by Karol Zieba (kzieba@nvidia.com) +--! +--! Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. +--! +--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + +require 'nn'; +require 'cunn'; +require 'cudnn'; +require 'paths'; +require 'image' +csv = require 'csvigo' +local t2c=require 'torch2caffe.lib' +local trans = require 'torch2caffe.transforms' + +--require 'LocalNormalization' +Test={} +g_SLOW="" + +-- Figure out the path of the model and load it +local path = arg[1] +local intenpath = arg[2] +local basename = paths.basename(path, 't7b') +local tenbase = paths.basename(intenpath, 't7b') +local ext = path:match("^.+(%..+)$") +local model = nil +if ext == '.t7b' then + model1 = torch.load(path) +else + assert(false, "We assume models end in either .t7b") +end + + +local function adapt_spatial_dropout(net) + -- does not support recursive sequential(dropout) + --print (model) + for i = 1, #net.modules do + local c = net:get(i) + local t = torch.type(c) + if c.modules then + adapt_spatial_dropout(c) + elseif t == 'nn.SpatialDropout' then + local m = nn.Dropout(c.p, false,true) + local found = false + -- Ignore groups + net.modules[i] = m + for j = i,1,-1 do + local block_type = torch.type(net:get(j)) + if block_type == 'nn.SpatialConvolution' + or block_type == 'nn.Linear' then + --or block_type == 'nn.SpatialBatchNormalization' then + net.modules[j].weight:mul(1 - c.p) + if net.modules[j].bias then + net.modules[j].bias:mul(1 - c.p) + end + found = true + break + end + end + if not found then + error('SpatialDropout module cannot find weight to scale') + end + end + end +end + + +local function g_t2c_preprocess(model,opts) + model = cudnn.convert(model, nn) + model = nn.utils.recursiveType(model, 'torch.FloatTensor') + for _, layer in pairs(model:findModules('nn.SpatialBatchNormalization')) do + if layer.save_mean==nil then + layer.save_mean = layer.running_mean + layer.save_std = layer.running_var + layer.save_std:pow(-0.5) + end + --layer.train = true + end + adapt_spatial_dropout(model) + return model +end + +-- nChannels,nFrames,nGPU,frameInterval,patchHeight,patchWidth,roiWidth,roiVerticalOffset, +-- roiWidthMeters,roiCenterX,baseClamp,supervisor,supervisorNorm + +local n_frames = model1.parameters.nFrames +local n_channels = model1.parameters.nChannels +local nGPU = model1.parameters.n_gpu +local frameInterval = model1.parameters.frame_interval +local patch_height = model1.parameters.patch_height +local patch_width = model1.parameters.patch_width +local roiWidth = model1.parameters.roi_width +local roiVerticalOffset = model1.parameters.roi_vertical_offset +local roiWidthMeters = model1.parameters.roi_width_m +local roiCenterX = model1.parameters.roi_center_x +local baseClamp = string.format('\'%s\'', paths.basename(model1.parameters.base_clamp)) +local supervisor = string.format('\'%s\'', model1.parameters.supervisor[1]) +local supervisorNorm = model1.parameters.supervisor_norms.one_over_r + +csv_string = string.format('nChannels,nFrames,nGPU,frameInterval,patchHeight,patchWidth,roiWidth,roiVerticalOffset,roiWidthMeters,roiCenterX,baseClamp,supervisor,supervisorNorm') + +csvf = csv.File(string.format('%s-model-params.csv', basename), "w") +csvf:write({ +'nChannels', +'nFrames', +'nGPU', +'frameInterval', +'patchHeight', +'patchWidth', +'roiWidth', +'roiVerticalOffset', +'roiWidthMeters', +'roiCenterX', +'baseClamp', +'supervisor', +'supervisorNorm'}) + +csvf:write({ +n_channels, +n_frames, +nGPU, +frameInterval, +patch_height, +patch_width, +roiWidth, +roiVerticalOffset, +roiWidthMeters, +roiCenterX, +baseClamp, +supervisor, +supervisorNorm}) +csvf:close() + +if model1.net then + model1 = model1.net +end + +model1 = g_t2c_preprocess(model1, opts) + +local function check(net, input_dims) + net:apply(function(m) m:evaluate() end) + local opts = { + prototxt = string.format('%s.prototxt', basename), + caffemodel = string.format('%s.caffemodel', basename), + inputs = {{name = "data", input_dims = input_dims, tensor = torch.load(intenpath)[1]:view(1, 1, 66, 200)}}} + t2c.compare(opts, net) + return opts +end + +check(model1, {1, n_frames * n_channels, patch_height, patch_width}) +-- +testpatch = torch.load(intenpath) +testpatch = testpatch[1]:clone() +torch.save(string.format("%s.t7b",tenbase), testpatch) +image.save(string.format("%s.JPEG",tenbase), image.toDisplayTensor(testpatch)) + From 7993aaa7e77e35cc700e81227743be7e5f141e76 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Mon, 22 Aug 2016 10:03:55 -0400 Subject: [PATCH 41/48] Update install-dep-16.04.sh --- install-dep-16.04.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install-dep-16.04.sh b/install-dep-16.04.sh index 0cc2ab4..be9b87b 100755 --- a/install-dep-16.04.sh +++ b/install-dep-16.04.sh @@ -76,7 +76,7 @@ git clone --depth 1 https://github.com/zhanghang1989/folly git clone --depth 1 https://github.com/zhanghang1989/fbthrift git clone https://github.com/facebook/thpp git clone https://github.com/zhanghang1989/fblualib -git clone https://github.com/facebook/wangle +git clone https://github.com/zhanghang1989/wangle echo echo Building folly From f79fae9e4a1d7692eb7db7f866c4253bfdd69961 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Thu, 25 Aug 2016 19:15:09 -0400 Subject: [PATCH 42/48] temporary solution --- convert.lua | 61 +----------- torch2caffe/caffe_layers.py | 2 +- torch2caffe/lib.lua | 14 ++- torch2caffe/prepnv.lua | 129 ++++++++++++++++++------ torch2caffe/torch_layers.lua | 2 +- verify.lua | 187 ++++++++++------------------------- verify2.lua | 170 ------------------------------- 7 files changed, 162 insertions(+), 403 deletions(-) delete mode 100644 verify2.lua diff --git a/convert.lua b/convert.lua index cae469c..25b36c4 100644 --- a/convert.lua +++ b/convert.lua @@ -1,12 +1,8 @@ require 'nn'; require 'cunn'; require 'cudnn'; +require 'torch2caffe/prepnv.lua' local t2c=require 'torch2caffe.lib' -local trans = require 'torch2caffe.transforms' - ---require 'LocalNormalization' -Test={} -g_SLOW="" -- Figure out the path of the model and load it local path = arg[1] @@ -15,65 +11,16 @@ local ext = path:match("^.+(%..+)$") local model = nil if ext == '.t7b' then model = torch.load(path) - model2 = torch.load(path) elseif ext == '.txt' then error('wrong model') else assert(false, "We assume models end in either .t7b or .txt") end - -local function adapt_spatial_dropout(net) - for i = 1, #net.modules do - local c = net:get(i) - local t = torch.type(c) - if c.modules then - adapt_spatial_dropout(c) - elseif t == 'nn.SpatialDropout' then - local m = nn.Dropout(c.p, false,true) - local found = false - -- Ignore groups - net.modules[i] = m - for j = i,1,-1 do - local block_type = torch.type(net:get(j)) - if block_type == 'nn.SpatialConvolution' - or block_type == 'nn.Linear' then - --or block_type == 'nn.SpatialBatchNormalization' then - net.modules[j].weight:mul(1 - c.p) - if net.modules[j].bias then - net.modules[j].bias:mul(1 - c.p) - end - found = true - break - end - end - if not found then - error('SpatialDropout module cannot find weight to scale') - end - end - end -end - -local function g_t2c_preprocess(model,opts) - model = cudnn.convert(model, nn) - model=nn.utils.recursiveType(model, 'torch.FloatTensor') - for _, layer in pairs(model:findModules('nn.SpatialBatchNormalization')) do - if layer.save_mean==nil then - layer.save_mean = layer.running_mean - layer.save_std = layer.running_var - layer.save_std:pow(-0.5) - end - --layer.train = true - end - adapt_spatial_dropout(model) - return model -end - if model.net then - model = model.net - model2 = model2.net + model = model.net end - +model2 = model:clone() model=g_t2c_preprocess(model, opts) local function check(module, module2,input_dims) @@ -89,5 +36,5 @@ local function check(module, module2,input_dims) end -check(model, model2, {1,3,224,224}) +check(model, model2, {1,1,66,200}) diff --git a/torch2caffe/caffe_layers.py b/torch2caffe/caffe_layers.py index bbe33a9..e4baeb8 100644 --- a/torch2caffe/caffe_layers.py +++ b/torch2caffe/caffe_layers.py @@ -84,7 +84,7 @@ def inner_product(torch_layer): num_output = int(torch_layer["num_output"]) weight = torch_layer["weight"] layer.inner_product_param.num_output = num_output - layer.inner_product_param.axis = -1 + # layer.inner_product_param.axis = -1 if "bias" in torch_layer: bias = torch_layer["bias"] layer.blobs.extend([as_blob(weight), as_blob(bias)]) diff --git a/torch2caffe/lib.lua b/torch2caffe/lib.lua index 7850d36..76a5eab 100644 --- a/torch2caffe/lib.lua +++ b/torch2caffe/lib.lua @@ -53,9 +53,7 @@ local function debug_nets(caffe_net, torch_net) sums = torch.sum(m.output) end print("Layer %s, %s, Sum: %s", - torch.typename(m), - sizes, - sums) + torch.typename(m), sizes, sums) end end ) @@ -120,8 +118,8 @@ function M.compare(opts, torch_net) end if #caffe_outputs ~= #torch_outputs then - error("Inconsistent output blobs: Caffe: %s, Torch: %s", - #caffe_outputs, #torch_outputs) + error(string.format("Inconsistent output blobs: Caffe: %s, Torch: %s", + #caffe_outputs, #torch_outputs)) error("Inconsistent output blobs") end @@ -129,10 +127,10 @@ function M.compare(opts, torch_net) local torch_output = torch_outputs[i] local caffe_output = caffe_outputs[i] print("Caffe norm: %s, Torch norm: %s", - torch.norm(caffe_output), torch.norm(torch_output)) + torch.norm(caffe_output), torch.norm(torch_output)) if not caffe_output:isSameSizeAs(torch_output) then - error("Inconsistent output size: Caffe: %s, Torch: %s", - caffe_output:size(), torch_output:size()) + error(string.format("Inconsistent output size: Caffe: %s, Torch: %s", + caffe_output:size(), torch_output:size())) error("Inconsistent output sizes") end diff --git a/torch2caffe/prepnv.lua b/torch2caffe/prepnv.lua index 29c9d97..28dd8bd 100644 --- a/torch2caffe/prepnv.lua +++ b/torch2caffe/prepnv.lua @@ -16,56 +16,125 @@ local function adapt_conv1(layer) end local function adapt_spatial_dropout(net) - -- does not support recursive sequential(dropout) --print (model) - for i = 1, #net.modules do - local c = net:get(i) - local t = torch.type(c) - if c.modules then - adapt_spatial_dropout(c) - elseif t == 'nn.SpatialDropout' then - local m = nn.Dropout(c.p, false,true) - local found = false - -- Ignore groups - net.modules[i] = m - for j = i,1,-1 do - local block_type = torch.type(net:get(j)) - if block_type == 'nn.SpatialConvolution' - or block_type == 'nn.Linear' then - --or block_type == 'nn.SpatialBatchNormalization' then - net.modules[j].weight:mul(1 - c.p) - if net.modules[j].bias then - net.modules[j].bias:mul(1 - c.p) - end - found = true - break - end - end - if not found then - error('SpatialDropout module cannot find weight to scale') - end + for i = 1, #net.modules do + local c = net:get(i) + local t = torch.type(c) + if c == nil then + break + end + if c.modules then + adapt_spatial_dropout(c) + elseif t == 'nn.SpatialDropout' then + local found = false + -- find the previous layer and scale + for j = i,1,-1 do + local block_type = torch.type(net:get(j)) + if block_type == 'nn.SpatialConvolution' + or block_type == 'nn.Linear' then + --or block_type == 'nn.SpatialBatchNormalization' then + net.modules[j].weight:mul(1 - c.p) + if net.modules[j].bias then + net.modules[j].bias:mul(1 - c.p) + end + found = true + break end - end + end + if not found then + error('SpatialDropout module cannot find weight to scale') + end + for j = i, net:size()-1 do + net.modules[j] = net.modules[j + 1] + end + net.modules[net:size()] = nil + end + end end +remove_flatten = function(net) + for i = 1, #net.modules do + local c = net:get(i) + local t = torch.type(c) + if c.modules then + remove_flatten(c) + elseif t == 'nn.Reshape' then + print('Flatten layer is founded!') + for j = i, #net.modules-1 do + net.modules[j] = net.modules[j+1] + end + net.modules[#net.modules] = nil + break + end + end +end g_t2c_preprocess = function(model, opts) + -- convert the model to cpu mode if model.net then model = model.net end model = cudnn.convert(model, nn) model=nn.utils.recursiveType(model, 'torch.FloatTensor') + for _, layer in pairs(model:findModules('nn.SpatialBatchNormalization')) do - if 1 layer.save_mean==nil then + if layer.save_mean==nil then layer.save_mean = layer.running_mean layer.save_std = layer.running_var layer.save_std:pow(-0.5) end --layer.train = true end - adapt_spatial_dropout(model) + --adapt_spatial_dropout(model) + remove_flatten(model) return model end +save_model_params = function(model, basename) + -- saving the model-parameters + local n_frames = model.parameters.nFrames + local n_channels = model.parameters.nChannels + local nGPU = model.parameters.n_gpu + local frameInterval = model.parameters.frame_interval + local patch_height = model.parameters.patch_height + local patch_width = model.parameters.patch_width + local roiWidth = model.parameters.roi_width + local roiVerticalOffset = model.parameters.roi_vertical_offset + local roiWidthMeters = model.parameters.roi_width_m + local roiCenterX = model.parameters.roi_center_x + local targetClamp = string.format('\'%s\'', paths.basename(model.parameters.target_clamp)) + local supervisor = string.format('\'%s\'', model.parameters.supervisor[1]) + local supervisorNorm = model.parameters.supervisor_norms.one_over_r + local csvf = csv.File(string.format('%s-model-params.csv', basename), "w") + csvf:write({ + 'nChannels', + 'nFrames', + 'nGPU', + 'frameInterval', + 'patchHeight', + 'patchWidth', + 'roiWidth', + 'roiVerticalOffset', + 'roiWidthMeters', + 'roiCenterX', + 'baseClamp', + 'supervisor', + 'supervisorNorm'}) + csvf:write({ + n_channels, + n_frames, + nGPU, + frameInterval, + patch_height, + patch_width, + roiWidth, + roiVerticalOffset, + roiWidthMeters, + roiCenterX, + targetClamp, + supervisor, + supervisorNorm}) + csvf:close() +end diff --git a/torch2caffe/torch_layers.lua b/torch2caffe/torch_layers.lua index 0311500..c865bf4 100644 --- a/torch2caffe/torch_layers.lua +++ b/torch2caffe/torch_layers.lua @@ -225,7 +225,7 @@ M.CONVERTER = { end}, ['nn.Dropout'] = simple{typename='caffe.Dropout', inplace=true}, ['nn.ELU'] = simple{typename='caffe.ELU', inplace=true}, - ['nn.SpatialDropout'] = simple{typename='caffe.Dropout', inplace=true}, + ['nn.SpatialDropout'] = simple{typename='caffe.Power', inplace=true}, ['nn.View'] = simple{ typename='caffe.Flatten', layer=function(layer) diff --git a/verify.lua b/verify.lua index a26170e..4a1117d 100644 --- a/verify.lua +++ b/verify.lua @@ -1,153 +1,68 @@ -require 'nn' -require 'cunn' -local pl = require 'pl.import_into'() -local py = require 'fb.python' -local torch = require 'torch' -local torch_layers = require 'torch2caffe.torch_layers' -local t2c = py.import('torch2caffe.lib_py') +require 'nn'; +require 'cunn'; +require 'cudnn'; +require 'paths'; +require 'image' +require 'torch2caffe/prepnv.lua' +local t2c=require 'torch2caffe.lib' + -- Figure out the path of the model and load it local path = arg[1] +local intenpath = arg[2] local basename = paths.basename(path, 't7b') local ext = path:match("^.+(%..+)$") local model = nil -if ext == '.t7b' or ext == '.t7' then - torch_net = torch.load(path) +if ext == '.t7b' then + model1 = torch.load(path) else - assert(false, "We assume models end in either .t7b or .t7") + assert(false, "We assume models end in either .t7b") end -local function evaluate_caffe(caffe_net, inputs) - local input_kwargs = {} - for i=1,#inputs do - local input_spec = inputs[i] - input_kwargs[input_spec.name] = input_spec.tensor - end - local py_caffe_output = caffe_net.forward(py.kwargs, input_kwargs) - local caffe_output_list = py.reval(t2c.format_output(py_caffe_output)) - local caffe_output_length = py.eval("len(a)", {a=caffe_output_list}) - local caffe_outputs = {} - for i=0,caffe_output_length-1 do - table.insert(caffe_outputs, - torch.FloatTensor( - torch.totable(py.eval(caffe_output_list[i])))) - end - return caffe_outputs +if model1.net then + model1 = model1.net end - -local function debug_nets(caffe_net, torch_net) - py.reval(t2c.debug_net(caffe_net)) - torch_net:apply( - function(m) - if m.output then - local sizes = {} - local sums = {} - if type(m.output) == 'table' then - for i=1,#m.output do - table.insert(sizes, m.output[i]:size()) - table.insert(sums, torch.sum(m.output[i])) - end - else - sizes = torch.totable(m.output:size()) - sums = torch.sum(m.output) - end - print("Layer %s, %s, Sum: %s", - torch.typename(m), - sizes, - sums) - end - end - ) +local function check_input(net, input_dims, input_tensor) + net:apply(function(m) m:evaluate() end) + local opts = { + prototxt = string.format('%s.prototxt', basename), + caffemodel = string.format('%s.caffemodel', basename), + inputs = {{ + name = "data", + input_dims = input_dims, + tensor = input_tensor + }} + } + t2c.compare(opts, net) + return opts end -local function inputs_to_torch_inputs(inputs, type) - if #inputs == 1 then - return inputs[1].tensor:type(type) - end - local tensors = {} - for i=1,#inputs do - table.insert(tensors, inputs[i].tensor:type(type)) - end - return tensors +local function check(net, input_dims) + net:apply(function(m) m:evaluate() end) + local opts = { + prototxt = string.format('%s.prototxt', basename), + caffemodel = string.format('%s.caffemodel', basename), + inputs = {{ + name = "data", + input_dims = input_dims, + }} + } + t2c.compare(opts, net) + return opts end - -local function test() - if torch_net.net then - torch_net=torch_net.net - end - torch_net:apply(function(m) m:evaluate() end) - - local opts = {} - opts.prototxt = string.format('%s.prototxt', basename) - opts.caffemodel = string.format('%s.caffemodel', basename) - local caffe_net = t2c.load(opts) --- - local inputs={} - local tensor = torch.rand(table.unpack({1,3,224,224})):float() - table.insert(inputs, {name='data', tensor=tensor}) - print ("\n\n\n\nTesting Caffe Model\n\n\n\n") - - local caffe_outputs = evaluate_caffe(caffe_net, inputs) - - local torch_outputs - -- Some networks only accept CUDA input. - local ok, err = pcall(function() - torch_net:float() - local torch_inputs = inputs_to_torch_inputs( - inputs, 'torch.FloatTensor') - torch_outputs = torch_net:forward(torch_inputs) - end) - if not ok then - print("\n\n\nGot error running forward: %s", err) - torch_net:cuda() - local torch_inputs = inputs_to_torch_inputs( - inputs, 'torch.CudaTensor') - torch_outputs = torch_net:forward(torch_inputs) - --error('not ok') - end - - if type(torch_outputs) == "table" then - for i=1,#torch_outputs do - torch_outputs[i] = torch_outputs[i]:float() - end - else - torch_outputs = {torch_outputs:float()} - end - - if #caffe_outputs ~= #torch_outputs then - error("Inconsistent output blobs: Caffe: %s, Torch: %s", - #caffe_outputs, #torch_outputs) - error("Inconsistent output blobs") - end - - for i = 1,#caffe_outputs do - local torch_output = torch_outputs[i] - local caffe_output = caffe_outputs[i] - print("Caffe norm: %s, Torch norm: %s", - torch.norm(caffe_output), torch.norm(torch_output)) - if not caffe_output:isSameSizeAs(torch_output) then - error("Inconsistent output size: Caffe: %s, Torch: %s", - caffe_output:size(), torch_output:size()) - error("Inconsistent output sizes") - end - - local max_absolute_error = (caffe_output - torch_output):abs():max() - print("Maximum difference between Caffe and Torch output: %s", - max_absolute_error) - if 1 then --(max_absolute_error > 0.001) then - debug_nets(caffe_net, torch_net) - if os.getenv('LUA_DEBUG_ON_ERROR') then - require('fb.debugger').enter() - end - if (max_absolute_error > 0.001) then - error("Error in conversion!") - end - end - end - print (caffe_outputs[1]) +if intenpath ~= nil then + print('Using given input tensor', intenpath) + input = torch.load(intenpath):view(table.unpack(input_dims)) + check_input(model1, {1, n_channels, patch_height, patch_width}, input) + -- + torch.save(string.format("%s.t7b", input), testpatch) + image.save(string.format("%s.JPEG", input), image.toDisplayTensor(testpatch)) +else + print('Creating new tensor') + input = nil + check(model1, {1, 1, 66, 200}) end --- -test() + diff --git a/verify2.lua b/verify2.lua deleted file mode 100644 index efe7216..0000000 --- a/verify2.lua +++ /dev/null @@ -1,170 +0,0 @@ -#!/usr/bin/env th ---++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ---! ---! model_test_loss.lua ---! ---! Brief: -- Script to take a trained model file, with all the included ---! training and data parameters, and make it usable by our ---! DrivePX. Major component is to save it as a .txt instead of ---! tensor binary. However, at the time we are also downgrading ---! models since the DrivePX is stuck on CUDNNv3 ---! ---! Author: NVIDIA CORPORATION, ---! www.nvidia.com ---! Created 2016-03-18 by Karol Zieba (kzieba@nvidia.com) ---! ---! Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. ---! ---++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - -require 'nn'; -require 'cunn'; -require 'cudnn'; -require 'paths'; -require 'image' -csv = require 'csvigo' -local t2c=require 'torch2caffe.lib' -local trans = require 'torch2caffe.transforms' - ---require 'LocalNormalization' -Test={} -g_SLOW="" - --- Figure out the path of the model and load it -local path = arg[1] -local intenpath = arg[2] -local basename = paths.basename(path, 't7b') -local tenbase = paths.basename(intenpath, 't7b') -local ext = path:match("^.+(%..+)$") -local model = nil -if ext == '.t7b' then - model1 = torch.load(path) -else - assert(false, "We assume models end in either .t7b") -end - - -local function adapt_spatial_dropout(net) - -- does not support recursive sequential(dropout) - --print (model) - for i = 1, #net.modules do - local c = net:get(i) - local t = torch.type(c) - if c.modules then - adapt_spatial_dropout(c) - elseif t == 'nn.SpatialDropout' then - local m = nn.Dropout(c.p, false,true) - local found = false - -- Ignore groups - net.modules[i] = m - for j = i,1,-1 do - local block_type = torch.type(net:get(j)) - if block_type == 'nn.SpatialConvolution' - or block_type == 'nn.Linear' then - --or block_type == 'nn.SpatialBatchNormalization' then - net.modules[j].weight:mul(1 - c.p) - if net.modules[j].bias then - net.modules[j].bias:mul(1 - c.p) - end - found = true - break - end - end - if not found then - error('SpatialDropout module cannot find weight to scale') - end - end - end -end - - -local function g_t2c_preprocess(model,opts) - model = cudnn.convert(model, nn) - model = nn.utils.recursiveType(model, 'torch.FloatTensor') - for _, layer in pairs(model:findModules('nn.SpatialBatchNormalization')) do - if layer.save_mean==nil then - layer.save_mean = layer.running_mean - layer.save_std = layer.running_var - layer.save_std:pow(-0.5) - end - --layer.train = true - end - adapt_spatial_dropout(model) - return model -end - --- nChannels,nFrames,nGPU,frameInterval,patchHeight,patchWidth,roiWidth,roiVerticalOffset, --- roiWidthMeters,roiCenterX,baseClamp,supervisor,supervisorNorm - -local n_frames = model1.parameters.nFrames -local n_channels = model1.parameters.nChannels -local nGPU = model1.parameters.n_gpu -local frameInterval = model1.parameters.frame_interval -local patch_height = model1.parameters.patch_height -local patch_width = model1.parameters.patch_width -local roiWidth = model1.parameters.roi_width -local roiVerticalOffset = model1.parameters.roi_vertical_offset -local roiWidthMeters = model1.parameters.roi_width_m -local roiCenterX = model1.parameters.roi_center_x -local baseClamp = string.format('\'%s\'', paths.basename(model1.parameters.base_clamp)) -local supervisor = string.format('\'%s\'', model1.parameters.supervisor[1]) -local supervisorNorm = model1.parameters.supervisor_norms.one_over_r - -csv_string = string.format('nChannels,nFrames,nGPU,frameInterval,patchHeight,patchWidth,roiWidth,roiVerticalOffset,roiWidthMeters,roiCenterX,baseClamp,supervisor,supervisorNorm') - -csvf = csv.File(string.format('%s-model-params.csv', basename), "w") -csvf:write({ -'nChannels', -'nFrames', -'nGPU', -'frameInterval', -'patchHeight', -'patchWidth', -'roiWidth', -'roiVerticalOffset', -'roiWidthMeters', -'roiCenterX', -'baseClamp', -'supervisor', -'supervisorNorm'}) - -csvf:write({ -n_channels, -n_frames, -nGPU, -frameInterval, -patch_height, -patch_width, -roiWidth, -roiVerticalOffset, -roiWidthMeters, -roiCenterX, -baseClamp, -supervisor, -supervisorNorm}) -csvf:close() - -if model1.net then - model1 = model1.net -end - -model1 = g_t2c_preprocess(model1, opts) - -local function check(net, input_dims) - net:apply(function(m) m:evaluate() end) - local opts = { - prototxt = string.format('%s.prototxt', basename), - caffemodel = string.format('%s.caffemodel', basename), - inputs = {{name = "data", input_dims = input_dims, tensor = torch.load(intenpath)[1]:view(1, 1, 66, 200)}}} - t2c.compare(opts, net) - return opts -end - -check(model1, {1, n_frames * n_channels, patch_height, patch_width}) --- -testpatch = torch.load(intenpath) -testpatch = testpatch[1]:clone() -torch.save(string.format("%s.t7b",tenbase), testpatch) -image.save(string.format("%s.JPEG",tenbase), image.toDisplayTensor(testpatch)) - From ad53f387ad04dbd3f9d38103829df94133c38dfa Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Tue, 21 Feb 2017 12:19:50 -0500 Subject: [PATCH 43/48] default size --- convert.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/convert.lua b/convert.lua index 25b36c4..0addd48 100644 --- a/convert.lua +++ b/convert.lua @@ -36,5 +36,5 @@ local function check(module, module2,input_dims) end -check(model, model2, {1,1,66,200}) +check(model, model2, {1,3,224,224}) From 7a8cbf5f32b6087c04ee5c12f2fd0cfa05014cc2 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Tue, 21 Feb 2017 12:21:07 -0500 Subject: [PATCH 44/48] default size --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cfa6b2e..faafab9 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ 0. Or custormize the conversion: ```bash - th torch2caffe/torch2caffe.lua --input torch_model.t7b --preprocessing prepnv.lua --prototxt name.prototxt --caffemodel name.caffemodel --input_dims 1 3 64 256 + th torch2caffe/torch2caffe.lua --input torch_model.t7b --preprocessing prepnv.lua --prototxt name.prototxt --caffemodel name.caffemodel --input_dims 1 3 224 224 ``` ### The Layers We Added Support From 31c7b2199fa8ce04e1659e2f011847a4d5521ef2 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Fri, 28 Apr 2017 08:57:44 -0400 Subject: [PATCH 45/48] stop maintaining --- README.md | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index faafab9..06cd5b5 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,37 @@ -## Torch to Caffe Model Converter +# Torch to Caffe Model Converter (forked from [Cysu's branch](https://github.com/Cysu/fb-caffe-exts), originally from [fb-caffe-exts](https://github.com/facebook/fb-caffe-exts)) + +:x: **I have stopped maintaining this repo. If you still want to use the converter, please use the AWS option:** + +The easiest option is to launch an AWS EC2 g2.2xlarge instance I created. Choose N.California Sever and search for the instance name of FB-Torch2Caffe (ami-03542e63). [You can follow the [AWS tutorial](http://cs231n.github.io/aws-tutorial/)] ### Get Started -0. The easiest option is to launch an AWS EC2 g2.2xlarge instance I created. Choose N.California Sever and search for the instance name of FB-Torch2Caffe (ami-03542e63). [You can follow the [AWS tutorial](http://cs231n.github.io/aws-tutorial/)] 0. Please make sure Torch and Caffe (with pycaffe and python layer) are correctly installed. 0. Download the code and install the dependencies - ```bash - git clone https://github.com/zhanghang1989/fb-caffe-exts.git - sudo bash install-dep.sh - ``` + ```bash + git clone https://github.com/zhanghang1989/fb-caffe-exts.git + sudo bash install-dep.sh + ``` + 0. Add Environment Variables (Change the path for your own machine) - ```bash - echo "export LD_PRELOAD=/path/to/libcaffe.so; export PYTHONPATH=$PYTHONPATH:/path/to/caffe/python/:/path/to/fb-caffe-exts/;" >>~/.bashrc && source ~/.bashrc - source ~/.bashrc - ``` + + ```bash + echo "export LD_PRELOAD=/path/to/libcaffe.so; export PYTHONPATH=$PYTHONPATH:/path/to/caffe/python/:/path/to/fb-caffe-exts/;" >>~/.bashrc && source ~/.bashrc + source ~/.bashrc + ``` 0. Convert your first model: - ```bash - th convert.lua torch_model.t7b - ``` + + ```bash + th convert.lua torch_model.t7b + ``` 0. Or custormize the conversion: - ```bash - th torch2caffe/torch2caffe.lua --input torch_model.t7b --preprocessing prepnv.lua --prototxt name.prototxt --caffemodel name.caffemodel --input_dims 1 3 224 224 - ``` + + ```bash + th torch2caffe/torch2caffe.lua --input torch_model.t7b --preprocessing prepnv.lua --prototxt name.prototxt --caffemodel name.caffemodel --input_dims 1 3 224 224 + ``` ### The Layers We Added Support 0. ``ELU`` From 56a5c2d12c7da7b946d11e57a03575c1c4ccdbcc Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Wed, 3 May 2017 10:36:06 -0400 Subject: [PATCH 46/48] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 06cd5b5..66d38c1 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,9 @@ The easiest option is to launch an AWS EC2 g2.2xlarge instance I created. Choose N.California Sever and search for the instance name of FB-Torch2Caffe (ami-03542e63). [You can follow the [AWS tutorial](http://cs231n.github.io/aws-tutorial/)] ### Get Started + 0. Please make sure Torch and Caffe (with pycaffe and python layer) are correctly installed. -0. Download the code and install the dependencies +0. Download the code and install the dependencies (:x: **If you still would like to set it up on you own workstation, please follow the steps here to install dependencies (https://github.com/facebook/fbcunn/blob/master/INSTALL.md). Good luck!**) ```bash git clone https://github.com/zhanghang1989/fb-caffe-exts.git From 0ee04312a1ac679f82cf5dd23c0b6dcbf5ac95b2 Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Wed, 3 May 2017 10:40:01 -0400 Subject: [PATCH 47/48] stop maintaining --- install-dep-16.04.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/install-dep-16.04.sh b/install-dep-16.04.sh index be9b87b..f05b0ee 100755 --- a/install-dep-16.04.sh +++ b/install-dep-16.04.sh @@ -71,12 +71,11 @@ echo echo Cloning repositories echo - -git clone --depth 1 https://github.com/zhanghang1989/folly -git clone --depth 1 https://github.com/zhanghang1989/fbthrift +git clone --depth 1 https://github.com/facebook/folly +git clone --depth 1 https://github.com/facebook/fbthrift git clone https://github.com/facebook/thpp -git clone https://github.com/zhanghang1989/fblualib -git clone https://github.com/zhanghang1989/wangle +git clone https://github.com/facebook/fblualib +git clone https://github.com/facebook/wangle echo echo Building folly From e6913363f1cb8e2a743cecf7bac33f547c54fdae Mon Sep 17 00:00:00 2001 From: Hang Zhang Date: Sun, 14 May 2017 10:07:19 -0400 Subject: [PATCH 48/48] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 66d38c1..b38b31c 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ The easiest option is to launch an AWS EC2 g2.2xlarge instance I created. Choose ### Get Started 0. Please make sure Torch and Caffe (with pycaffe and python layer) are correctly installed. -0. Download the code and install the dependencies (:x: **If you still would like to set it up on you own workstation, please follow the steps here to install dependencies (https://github.com/facebook/fbcunn/blob/master/INSTALL.md). Good luck!**) +0. Download the code and install the dependencies (:x: **If you still would like to set it up on you own workstation, please follow the steps here to install dependencies ([fbcunn/install](https://github.com/facebook/fbcunn/blob/master/INSTALL.md)). Good luck!**) ```bash git clone https://github.com/zhanghang1989/fb-caffe-exts.git