From 1532c8aeeb6864845b9b9045c9123102a8073730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=A0=95=ED=98=84?= Date: Mon, 18 Feb 2019 15:37:26 +0900 Subject: [PATCH 1/3] #197 : start translate --- ...4 \353\260\224\352\276\270\352\270\260.md" | 49 ++++++++++++++++++ media/197_0.jpg | Bin 0 -> 35742 bytes 2 files changed, 49 insertions(+) create mode 100644 "197_Caffe \353\252\250\353\215\270 Keras \353\252\250\353\215\270\353\241\234 \353\260\224\352\276\270\352\270\260.md" create mode 100644 media/197_0.jpg diff --git "a/197_Caffe \353\252\250\353\215\270 Keras \353\252\250\353\215\270\353\241\234 \353\260\224\352\276\270\352\270\260.md" "b/197_Caffe \353\252\250\353\215\270 Keras \353\252\250\353\215\270\353\241\234 \353\260\224\352\276\270\352\270\260.md" new file mode 100644 index 0000000..be4de39 --- /dev/null +++ "b/197_Caffe \353\252\250\353\215\270 Keras \353\252\250\353\215\270\353\241\234 \353\260\224\352\276\270\352\270\260.md" @@ -0,0 +1,49 @@ +# Caffe 모델 Keras 모델로 바꾸기 + +[원문 링크](https://nicolovaligi.com/converting-deep-learning-model-caffe-keras.html) + + +> 이 문서는 딥러닝 프레임워크인 Caffe로 학습된 모델을 Keras에서 사용하기 위해 Keras 모델로 바꾸는 내용에 대한 튜토리얼입니다. Pre-trained 모델을 사용하는데 도움이 될 것입니다. 설명, 원활한 번역을 위해 원문과 조금 다를 수 있습니다. + +* Keras + +* Caffe 프레임워크 + +* Pre-trained 모델 + +
+ +![197_0.jpg](./media/197_0.jpg) + +
+ +많은 딥러닝 연구자들은 새로운 딥러닝 네트워크와 모델을 개발하기 위해 [**Caffee 프레임워크**](http://caffe.berkeleyvision.org/)를 사용합니다. 내가 그렇게 생각하는 이유는 [**Model Zoo**](https://github.com/albertomontesg/keras-model-zoo)에 있는 pre-trained 모델(학습되어 있는 모델)들 때문입니다. Pre-trained 가중치(weight)를 사용하는 것은 몇 가지의 장점이 있습니다: + +* 데이터를 충분히 구하는 것은 굉장히 어려운 일입니다. +* 모델을 처음부터 학습시키는 것은 오래 걸리고, 소모적입니다. + +However, I really can't get behind Caffe's heavy use of protobufs for network definition (code is data, after all). This lack of flexibility forces everybody to fork the codebase for minor details, like image preprocessing. And you get to write that in C++, of all things. + +그러나, Caffe가 너무 무겁기 때문에 계속 사용하기 어렵고, Caffe의 부족한 유연성 때문에 이미지 처리와 같은 사소한 세부 사항들을 위해 모든 사람들이 코드 베이스에 포크할 수 밖에 없습니다. 그리고 여러분은 C++와 같은 언어를 사용할 수 밖에 없겠죠. + +나는 TensorFlow와 그와 비슷한 친구들의 접근을 훨씬 더 선호하는데, 이러한 프레임워크들은 Python 함수의 힘을 빌려 계산 그래프를 작성할 수 있습니다. 이러한 유연성은 프레임워크 코드 밖에서 스크립트 언어로 작성되었을 때 재사용 가능한 사전 처리 단계로 확장됩니다. 나는 보통 케라스로 일하는 것을 즐깁니다. 왜냐하면 그것은 쉬운 일을 쉽게, 힘든 일을 가능하게 하기 때문입니다. + +In this post I will go through the process of converting a pre-trained Caffe network to a Keras model that can be used for inference and fine tuning on different datasets. You can see the end result here: Keras DilatedNet. I will assume knowledge of Python and Keras. + +이 포스트에서는 pre-trianed Caffe 네트워크를 다른 데이터 셋 대한 학습 및 정밀한 튜닝에 사용할 수 있는 Keras 모델로 전환하는 과정을 살펴볼 것입니다. 최종 결과(코드)는 여기서 확인하세요 : [Keras DilatedNet](https://github.com/nicolov/segmentation_keras). Python과 Keras로 만들어져 있습니다. + +### Picking a model for image segmentation + +최근에, 나는 이미지 세그멘테이션에 대한 최신 기술을 연구해왔고, 이해하고 연구하고 싶은 몇 가지 잠재적인 모델들을 선택해보았고 아래와 같습니다. + +* [**SegNet**](http://mi.eng.cam.ac.uk/projects/segnet/)은 표준 인코더-디코더 네트워크를 사용하며, 또한 흥미로운 Bayesian extension에 대한 내용도 가지고 있습니다.. CamVid로 weight를 학습. + +* [**DirmedNet**](https://github.com/fyu/dilation)은 픽셀 단위 라벨링에 더 좋은 dilated 컨볼루션들을 사용해서 오토인코더 구조를 제거합니다. + +* [**Semantic Segmentation**](https://arxiv.org/pdf/1411.4038.pdf)을 위한 Fully Convolutional Networks는 출력에 대해 fully connected layer를 가진 분류 네트워크와 유사합니다. + +확장된 컨볼루션 덕분에 더 좋은 결과를 얻었고, 매우 깨끗한 Caffe 코드가 제공되기 때문에 두 번째로 말한 네트워크로 진행해보기로 했습니다. + +### Converting the weights + +Caffe는 직렬화 된 프로토콜 버퍼인 * .caffemodel 파일에 가중치를 저장합니다. caffe-tensorflow를 사용하여 이들을 numpy에 쉽게 로드 할 수 있는 HD5 파일로 변환 할 것입니다. 스크립트는 .prototxt (네트워크 정의) 및 .caffemodel 파일을 변환하여 가중치 및 TensorFlow 그래프를 생성합니다. diff --git a/media/197_0.jpg b/media/197_0.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b03c038330c84d020c854f576091e31fc0fc1a8a GIT binary patch literal 35742 zcmcG#by(C*+dsU3N_Thn61#LucPtm-3_92tCUEoFN)WF zU+?ig?{gf#KYqh<>}SrI@A)}rzBA|K{#yLC2EbEMP*wmSAt3>j?*0J3)&Vc%{p@W3 z0A*zk02%-QcmSY4dI&(eLy~v@lz*|p9cDv9`6EZZ!}bvm{$Pze{5#yK`V;@>8wCJJ zK)uri0PuoAynxq#F^HEJ>Gi#qU%!4o_uGO8(so{6ZlXLqE}q;L)~=RNZYx)39zP2= z9uPM#4?tYX&&|Th5$Z)}3AMF%kzoD$wv(04-dciHUqGE#-Axv1XRj3C0o4i6(6tJ1 zv=Xsqm6F5|_Y?JVc5{Y$S2!4ck#0D<8tw2ywiX|_eX~u)YHnt-p$M2 z)#V>LXE$woTRSh$|7iRlOXu+?&u?4k=)~^~zJEqk-NM5WYAvZ?;p7Pw=lTE0?^t<$ zoBl7_|J@XI_5a-rXXpQ#psp^ed1scri-nV%tChDi)Wu6#PEwekS5R6=P((-$EH5J< zEi9`b%gZOIAjB)f3+5LRko{xj|NQ9RqTMAbyLft8xL85&^xc(-+uq(<6eKMV;uR1Q zkrR;?1cBuFgux&I1qB%puPlfc1Qr1QqxWBr{#W1sEj#~PZo1#q>;d(3_4crWO0fR6 z+WNm%OaK2_%}U4f&l~-}P;5Di@9m{O=9tKMhw@)&pwcgpsZ{ks>_Y1z4Yxq8~Uy3xt%@X_hpyI8yW zdj5Hz|F6vdvqkq--u2D9Udr>IzI+$?k2iq2+_?ac-+lep3P2Wsfr^HX_6P$V4IK*; z0}Gb|9~TD)mzIQ#kb;?>m4%6(iIJUK49pG`1~M}7DewzRNXf{`uz{4+l^&~$Ny|w6 zR)U0yg@ucaOM{P3BgMhQA@zS8esu%z(U9y=-lHJl1Ca5NQ1Fp{^#UmGTqDYz%l++C z{|01~2S^Veq248u|4z6I|D@b~Bi*Gw{Iv|gLO}u`Pr2eH^u6C59aKeNk&_3KU@dA_!seip_I7$I(r7I<>-OPoMX4Z^as@f$&?j~ zVkQrjTDVzdfh$Xp_*aDzk|B;*A0`jhmzpX&<{C!eKmx|mmmsTeSFsa|+0N~4OV z4Y6YV%`@jJU7t%&p~0enr{>$me~JE$g8eqT)e2xAmd|XtTi&o&)LpcyGz}H2Z0zrH z((_p>`kJ}EtJYAr-T5{SHb`X_EyXXi-y9zu+Rv(b{kFw+ay)R=T&&Z@)SI!SV1jhV zwi#Dlr^3f`Z&&mTT=lHH95p}6t5g5*;4ddiROXs}*1?N^nSeWPEBWCYbCwNtY9nH$ zu!$a$G&lNe)+_|_6-vEQ;O4XAbDz~|@g(nU- z?e1T8{PDNXS4p3pMSE?jC^_nWes9X0k@Ch7(>mbFLo#V$_AlWhv5Bz-{BqZsiQs?R zK$|rRJTM(ANpv4BU($8Nu1~VzJ37m#kT4w6O;{Ev?95qOm|Oh@FA_JoV$T?B6f+C( z?=Vf)Ru}hl3dq!{sAgB*we<8I*{ZCXkK*T{nr8< z8olk@liT9gm8nk-WR@tbSB<hR#5pzb~wVP4WiPnPh|N^#gijK;x=6-(g)izlJs zg5(>cwlkiX>z2mgo6g7gT!1eBrweod(lPt2%pqGIj4HRo6gxnhxs_zXeFiC^-8c;D zq%y|oow+Q6@?Ll?Vd@(r{$}#GxlpD6$C*#2MqhQ?lt^~24O`DTOuCZCF*7Ue4>X25 zT6q{WB!dHk^=wQJu7IP{pHyrtO3E`QxWA(7RU&TR8v1Gnb(YlpwZp${Gw$pjld3-> zKfi}aSDoS>EjT4QwQQfpMEssW%hfJC1#<}bhW#@Is$I_W%zmn@Qd;`W7Hu^paAO*2 zYG<()6?rU>wqMq6_ps)?bLWCt8YDF3tW=&eiW!ESr*lq2E+nho|5d-^7_R!_4@N3? zot<#I7ymA^K0wq*DJM+>S_2zn-?dLqPC2;Xw{+N*7=O3-$(4IGBdM>}i+p?D$83pQ z=56Jfs)lOMM29OY75`ZuwXclBuHWc-g;}*zb`3KXqf_B$u3U5T!=ros02-SX>y~>= zvGYUx`#nTC3-((d-o_bFqDobW8DW~DP;nfcJDRZkFh*wIySg$Z;oVzVL_w;qPnE*e zBx76|+UyEi5wGVT2sybrqY&||f7bQ3I`PA9`czXy4h7j!7M*L^)*&_{8SC?1HNIJ=yMmq zwDpYjTr8Ug&p&i{N~*bwTMm^ARq+*Ya~apxS0G<;4DcBwsCjxK|DkA9EY} zTeA{Q-=_rc#i%=ryNgs6XO5+_b-6?bD@i zi@z)xRpi|FkUMR0qVOIfT`fqu3#$m7K&B{dGd`3yD`+i$XtqaaiV-YED;Qn#8y9~Q z?KbV#xNWE2oE-0Xm8R^uUj*EbM=s$hiq**i`)JgDloInh7@dd<05v|Tbk|o(oGY$U z2@r5Nr6Ri?5uAIg;CUe#_x>;6f2$pv(5xxwUJAgCTaVGRnQ`STNDhx>kzqHks~MQ` zSpkWp^aXBva{&!q8#PiX7IHuvUrAQZsoD%DjJ@+nn2X*BO1|Jg*Y(Bpc$PW3O+S{{0 zBYE{Ph=(TERx%CX(y~#dg6YRUt!Y$_5!_}a-d?Zr@8J!s)K=W2~**^~+|I36F za@tk(_zx@TSisfaeh!dS9E#i?19mGi6{r)e>YqOe^Gn&bIn)@^Rp2RG{}}1D|Ku>o zMnfX3xJ=O4jC-a@&vv{mB{wIH1^6XGbQk;CI2G#zsRQ)wmQEODttu?etFEVgbm+6X zr~cl%mHR>hut-y}J?=40>NBUDzv3%%7JRA^5@NP$)tW6$yT>UE+A^*9jC$77AG6}F zC+q8-v*vFkpNVBJ)bmx18*X_VcHf8wkm%>=?68Yn!Js$8nLAK#;cZ6)dmL@O z?h$b6n|HwLuY6DXbH)lCnVVGKVlQWEic$2%cALwL=|RV*PubE(&vskt>QD7D>z&GP z*tSIqkMmSkvh|etvYyZ?o{RovfAlP#)#NX(4T=e1di^It%egtAZfw0#S+81C;R2-= zVb(hXzvJI7@X6IynfBAM$<3_q*sPd|KufEH#Y6bXYTK9U%w-J=CksZUBMd#u$x`h{#VTx;{7Z&x3LGl-fBg7Mh!VB#I{Fu%^DTJY5C2G~9YFqtCK~!N zW{yH(l;kz~g7PoR1WA2&B*-3SJE*+g(Zk(X{ja5DTB(8qe zEUpw!!*P$L?N$0#cj9g1B12EK!lHP^`DaaknW!`|gP-2xM`fKl67TDAaZ+ z*P+TTN*TEL8JL;Wh3<8sPh?#$SF>^;k#$c4z%V@dzWWy&bj(Z8{lT=18+|`q!NscJ zFH|M+{!a*({f)G|mZlhm_${C-t7+~ZH$7bn5ejwCu)c~#ghS09=BD-Ggv!-nJHH&KeyH~-9Q$$6ysOdj8}qRdYO5kCEcuW%o+HmHgk z$hWG3f5xQSR5^T1*k*L@Tdr5jhF-+Ee3~izUNx6Fq0Za~2Tv1h^&gJGE&I)eIa7bA zYU6L4N$SKm&d;T#4L>m*?qh1$F`Wj9ej)xGOso0z?~nnoZoeIKzb6LZ%1ZcZy#C9~ zLLV|F)}&|G5>CM(>VMTHBob<&ukbO(fH$Wp=kv7DY-LU+$Ho-0BbLe4;#QLii@g2V z9CUet`K)oEYqx(@;!E?;HiwbN=VpgtTXL7oqp?18VqdXuw5m_<>5vl7&IEezF+gay z>gs-)OH0}#WNBT&JCj0Tx4Z}^LkKIdc%?LDmoj~B#L3xjp=iwFw3vn%4mtK02(TS2 zdl(Xx^UtM$(#G0vZ{0@p><_&lQLx02&x@&Fbc)i!<>aZV-^_lzxF>o@N~7?1$Ob%G znwgq-`bQpUp6OUux|P!%-E!pVXi@AWI5Mtsqc#<6S}tk|o~yhjeeyA}xyjUKxrsrp zM6`mU%^01Ksm2JQebky-!Z>1!66T+4wt}lr+ShBEL1}B<03|5jF)^>bu)F642>V^1 zJ-H_XpqP9r`8!Lz;^Fo$n~TEHk!!SH;W1f$GH#bDnrgFBmfXzr8px?3FC+i^US&a z`kzIDMSJ^?zYY`Nn00=3Kcds}Y$kl@D?DR{d1o6Xsi}PUwg~0wXNyf!iM|#g+-ZK3 zr;%-%nVBeGH<}}+;=V_3V>aq|Prsq>N zW^eWcDj{IJYw;HRNmJFiraikpQq`n}rHPe9PGvjhZRMvbkJ)hVozZox{`3s+s?n9B znRl8&h$%EMD`1&FH{V1P#zReD2-^zWdRL|5-6@3I;~ZXyP!NV z;n<|PIMd$LD$%!@qaSjtw>op;_4#wTMt>;Q|3m*sbz*b@@4omFY8P|&t{i1kJfpK9 zBjrrd(V4pP(yo`wRC}axbcAagZYt`(nAB!tWa!j(-Y{v;Q>bC4>vUGsEO=E)G~!>g z&~EIma=RcI>@?!Cvm{`~XR~;yM~uA)hUvFXWt~aZf2z4B10XjAI$vGhM~r!D^E4m- z!GX_{`1YznDgK5g`*x*62aWY?tXX(X!z|y%_!dW8Eq$h-BQ|XwtAbAT(&VnphVdM% zu`4+S21d@aZ96M@ESkByahu%H4lQ-s#$1VpZ^K{9C4=XNXyR)w_Wm;eds@7jn;Uxc zM~-yzQz$?MZO4}{b&oIMAS2kRUbHR=HoWk}($J(X48e*&H`S4>Zd&G?wp7~kQs(N) zGcf!)gdVLM&Xwf6hpu^0d# zbLEjTdGVVRX=ZT%G5-ewB>BcT!emBH_to5XGQGy_-;i7OH+UvZw{p*(`v#7?n6fxl ztrQejiQH+p-oHq{-I4S z0nMgA9?=G=?y5A%NWK{*S00sP#I;hTxH~c zsM|DxDITdtDn6Zb%YT>dn1z~Ns+s|Een&Fyb6jR|K-x1i0u^qgCEx2ke_?s z%Tc?oM&7)2u3(sc`VtwHxVa0*e?GE-nW$f;~)h(QU2)v7|#NzdQ^Wy1PSqtWsQld9`@NMr|a{T(p^Bgiv? zoDWTuGA4C()otVjM`0&03GvvI_FvU>$nMtlyLu@kSLf&rNOnXysM(N{-@kn%xQ zv_VXCa#hS|OzelL3dTU-Okw1IUKcO@bPE>!2qV|DN9{_VG@ySFwgL0NAU zk-9Mnj#cO$ucJh$9K22mVa1hshwjzK#JLqSFh!B%a8P%XyMK23O<-Q1_*LUzik_Jr zom`ZfPZeJxP&hNd`ftGiMD^QW!|VWXulZ*QfECdIk$Xn~0HAF6X&joxwk?E44LB&O zyvCstdAf1JOoHE(yiXVw2Ae&Ld9WGeD42yacj4bU7Z!m-C2Am73D-i^$gX<;eF;{s z{?Cg7&}HyQB0CnlIOc9r@5)aQTy@GyIRC9e0O~GPN%2Cpw*~mY%V~TtJ2RouT;XQe z({=x3inN4sjHJ-GgbMYChXLvVk4r0=29a$^YV_n1Ippz!R2Urh|I@SnDbknSapD4-&8iD8>fe9;1)#NWaA!w|VDGuAkz=Z*J(7139wvh~EPEZKw*=WRr()yF zovRGQzOgExGF&>3w09n&^mkA1!_@A5Vs}MFUawT|_OUj07=I(E-KFT3zc0=8)()mm zARM($VW+@t^jT>5i&-iQeK3VpifU=kz74|2^0w(Dk(R4k3DzMlSm$+c!Ubb7lhClf zbSaAV=_vZ_URzETd8&X~C`04}mZIhVK4O+@^1N3jcvNXHMcuQZyVP}41U*&IWtvIr zT=ApQb-E!dLe93&MUcS&QWy4#sGKV+BRBieWnQ3m89PCM6OEupH1o2xu?G1=euFI) zGeKX2cL}LO3M!Ca0JU8*+AW&)7|)OGUL!y`CJhtGEoQlr9%vS93Paa&P${x3mXWIT z5OnQNG2JI=d6{ZjC89$fPu$Rgh=E;t4O+;MMb<^2*ux3JvakyuC}o|rrJY=?=MFvF zW+n!1`ke27I=upYMN2W#5H+uj%*WdA47}-;KP?(JxPB*v7}~UUPaKe+9vaUPr#d$p z3uLBd9f}h`L^U<^k8i<2iI$9oi&w!sI$y&LAO8Z-ecJ#|k{IyKh0u6uxVSDw&6_ie z`t8JBE5VH#3-uaZO9qS;WB5`|_RSxs4Xdka)Ky@Ggc^0`|vL@655lNd&vA)e@LXnD}Vml9L* z=1AplgDafm7-U$v(u+7*qI^lJ)jZvU^M!(4b#BDDbDp!NrWYF82udzJq<^PP{|P@m zjfb*yv8d(xdA%>`geN0|gb2_ndiNJVDLhRXm=aH6GT(-OhhhtpFM`9zxy@${tCh1<4#+>~WVa6h;Y!KvFGTyo)O zD)gK?zN6cc76r~Q0vzCT53?IXysV27Fc{vUKJG^FeF1(^K0}r35C(fJhFZ&cSwRor z4KXUh1Tsp??Jjp346K@HMB}lEWEgc9cA0yX;9(i=!m;j+@UUha!84l6PyKuKA%;He zJEM`d-;{!RPWq!udlDT!E>90o_^o+sS4Hd0v&eDLl;+#FtoCGeLUQY6#x}jB>brWY zc_KH$;rn_F*6;SyxwMG#(cqj}I z;IYQVw+9tRae+DMSbRBEw&@WKcdhQYrfp~g98D5aWv6ysyRY{+amsh916@>z&z)Rl z)^CJ1PNWM10ws%@`?4(fG0zVoRG?@}k!<_WZxuTgl&DKjS^&JEji0^r^Kdy~d&6n8 zWf=$pMaAmHtM2s6gO!OQkKj@A%F5IWkXJK9(PHyJhuWU(bHt80dqL|%NNS9&@D;;3?vY$6?^kF@rO)5NIfy^IOH-h@*V`Qfz zmL+Bi+HOdF$KgCG(-TLC^b@k#$bJ5CLn`so=^;n?0=X$&m(8Qdn@_cFB1YEME|fg| z4hvB;lHwFIz7&uE?jsX~+;g7NHi{`7GXnau&i z&_w_}ku}TyupY!n&@|ac2!Fe|z(}9c|HPxMZ^P=D?b^W03$g|TQ}|$NkmO$PkV;{{ zTwIJ2BJ|B?s$kxzhWx}tLd&%dwl^e+3U>JnnRAh9K^+Sy)(SojW>PxWwtmsr}< zm~NNemTUF`459mt0SIxzu)>La5Ea@ov$I^(IgD9%N9;qWS-jHT_-hz1+n6_5Q!F-G zKBX#~9*hPaEOe*GEUWqDst>S7(qpd7lY6QT@8jvf(*;l(1sB~H!pK7Ud{P-H`YQTQ zH>6{+dA^7#0z!swW5bCnKz~7%d6VEQ?QDu^iHpR~V`Y#=fu$yTzg5k{lK@v#a^Zbq z4O6%^{=v12&PO+Xt#J8#71-|ETlM_{SYY}kGq=V2^Bbqt@(U0{gVSh#Gd3iir}(=9 zB#o({P+`;^9IQN@X6-|GQqS49aXzuV#`IjDKqbw4*gmUuXlQ1LJaLtFBqXZ8K`kiB z+WNWQ8SUH6S{nI+uMFoh7jNZg-i=Oj#3XEP`+b*F7XZPJ1mpMX5 z#~{S>Bvx;nqh)E6Y~_t2(()8s21k2Yyy;T-dfn#)yohDfw|kA(73+fHue4<*e!umI(Zb;^!+Z_$UnuNg4*Jfc?hIf?BgqT?LVj*chGB$w z%SAjzke~!-1o8?8SG<5KF6Fg=vPVn7G7s??5r{x(OvmyF%5lx0yUJ z9~rB!&;&C@$faM9xC0G}$)+>cyjGD$AAjsEi;P@q^tqmb@kbM5g$`l!en_hVQNc$! zC^QPr_(?a)r!z4Sp&4EKI8+rsEpqotQelaF(53e(&AL@z+nH7~Q5=7JEJ5KbgZnCK z&$0V}*Da+~d7%U;)4Du~*Hj<>W)xvAkH!)-;rUR~Hrj1m@7w$e)5z~|RGGkjUDj^P z&tB@s+o#%$l5%}R)cEu2n>1$ng9Wv3Q`BnZ@hZm9K9`FTSPPSa|I|qUbRwiQ7WcG? znK60i$nwjk4W}%AgOc3heV0O#TLBt!TQTtVQ{1ciA z?kgEVk*FmQoYZT$mYbbHWtc4u-3%Q%nmJdQbmR~RAlwSToc>4=>n-8v>Zw4xcm=p(b z@z`S}Hp~!#;)y77SzWl9N0&tJ9P7fG*Ws185NmLLOT`o?m1==M4?F~{Jp^wRa6JXf zD`Gus2z(99nqHsW5Ky;Yj20wliMBbMVv1&fJmQ}Ex-6k^HFE1ev%l3h11ovaW*1-B z&z;Dy&j7?@o_QRvjxrgw_t;<~HYzt;y;fmv>zh>d`~8A}(6?%9bsm;ZA13Rt5-)SG zohP_vB8EBmcRe87dS4Waovax)^m&NiHLT<_JUoFL1&W(CC`^%UD7{R4ra}3k4|HS| z1Mv#Tgfuk7_8$<|dt)XJh)T$BeIsoCd8z0%U9`?l{La}>kvuN zf`jqB4bE~?MDx)$JA$5DHbc!_`<=EC1Ugaz@x;v0tR;jNip5jILVQ#$Yxb0(LtwRc zBGk!WI1o2VaglJI5l`(1zr9GjCsY|6kZolbosiYK0es^p^sZE=^ddCXBU=V=yY-Z! zXqcI#vU9|%IAfMpGvc%Fu?`5&iYMdrE;nHR5PBiBg@-APAxRdg7M8H5qyT(of+ ziYQo)O43cQN8KgstK-mJVsG2he*qXa#F`VberJkjFtCa-XslJ5Ng*>EZ6weZ zH_nHhY}1-RmDa0rIVxDBzSwK2fNX$uSmzT*kuVFBbFwnw;GnfHcqg#$(R4@^#01?rtqAa9N}DoMwTG(5n_I)N4jiqe0K=Yn ztiH=C%fy!{C$p-%BwumK7PjNEYtJfYq2hiUL2g0K8m5DGCov7>tD4KQIUSpA+_P|AXLgI*Y>7(tA+ z^D>*^{@MN**{LQ){1e#&NE-iEDm%!^E?h1Wsvp6zN>wX6LFB3-ne-7c*5(`qq4HlG z=yF$YaB=c+R$C!JNRIe@oGofu~#Gg!@^o1~478I+gSamTuClWXr*bGWb z`~BdjN>pLa({o#}I@D}>!+qZCUgX|j&Div$P{*@MFpep)Y8WI~8~~CU=;cl~1vT-~ z4=*>^1q3Y+eNkEIA71abpD8&BNlIvTJzuPSQ^mocPmJ26()r~V;BGO@j1NHiyAu9; zDe3MO5?dGjpbo+x{c4YP zR6YL@qBn>I@ji@IbB8p2)jj%MM-s$NA*pEV;Ek7yU!PL)PS-^jL|V4kvv{2Es>N2% z1J~HVBeZ1~f1BV~!i43~)I6+yPI&zF2I_VCiOCYK5Utop@k#A0-wTAA3JaulH0fSG+SQt5{2Jq; zah&n7tO+k)UPZulHBOGPZ0jp#{5zc>UYIVM>{~H8R%}fcLN#hFnR?}#Qiz2*ktc+h zQFSPMKy$v3&N+EHN*k7>UWC!YXfW;J9l4D8LTBJ~{{ec>7-QtYK z9{+(7nx)q=3lDsqzG_Ikn`#!J=4w|rq_j`@`B8D~ATu78cTwRU;=yag zE4C=I_MnXzP>5DR6}GuFF{y$k-A(UiZZ#B z5lj{h$|Eq`QVU|yD(UZG1Nq6^(O9&z&e7DgEQE4cC(pM-Y6=$hw{70z*XT}zTSdEU z{cMg|)}k?hB$(%9Rs(UX@3Mk2VHiYguWPR3=Nos=0O%sM zN@g5HR;?;IR;#oI;z38T539aJ=xw5)7vr?)&Q5CU&Rm2A)0aIrpkaA)Xu>Wu-hT26 z&@1=McokDx`W2B~T;Eu-oY8}76ki%~`rCYh4uO;E*gy*;B2TCv@k5zoHnc(7m4EsM z@?H3SneXmK-~C1r9zOD8IuHRpua@*vLI#N2pT2?oyKgM2m6-tR*2~m1lS0|uihcn? z1GB_omrF^!mvwy!A8M_w(n!&?ucS^$plGdi1HgQqTb{MaZES2B7KSh!yrR=*{Q8?s zhR{AwS-0Z8FXo-l?(M`-);=6=U2{$zsH%C)z*tO+6^Fs7=-S4mq1(8Y;Ul+_A1sqQjzJ)vqDD6RYH2n)AduTD9B11VS zY_xW21iv3H>9O0WpP@&7OkWzVp}mA-OnUDKSxgC;dvZQ3WUy{>oh)AgI?VIIpx+AE z8x$Fw0SmVtH3;qhmYOtIH^PTkM4peO5xO0XpU|@85e9cp+E{-^L1k!V0~{S-WU<2X z%OR`#HlMUm8-+t2Cku279c?k_Ti}S7#fKit-kpAoVc^Y09u+W>c@zveatW1hW20H} z#Nv?Ur=K8V5^8B{Ev;KcYDL9p5u3wdUx1c)!=VtP5y$~JAFHks>QQCT8Agm%9ZMFA ztqYBMx!FU)FHv;)owzG1j;*w`cHkHi*=iVAnt#1j03MM-4B8&s^*Y(gkiGk9Jgq&6 z$nOS+YOP=6%k<_4agcoyrC`f1AP5D?a)@!BeoPeyp94dMWvoICWfc?{$U2S!k7}cc zbOlYj!FW^AGRaDXkn?n@i|dUf*wY+oqWe~?EW zkh}DPq6x#knik}%a_CTIh5rJ8_FD#3NNcad!-!=9XBMGTTdd;~l;RE)->VwUqVZ+L zqD8?MEc%a%!$<@zQVsiQqsjYd{@j~qu6M!7&~pa)_6ipdfMe9gX}3;2*m5T0*|fQ z7yJMYydUUslQ|~^QwMnc-k4B(34YwIj3?9X(HNWJkrL~Mrt!U!ox}U1AJQHg{ZWR;-pKwVgE+;6KjCeGz zAd@GgrS&|Pq7>(BbtAMtQw>_GumXwddr#O-6hqjFw10o(8B#Z<0;07k!Yj>6@LP^t zI0j%+o0jhj-XDuAb_KWHsuUnbHa|?6>yMqt6JNpP4GUsR3C{2MW44Oie;BByx78TiF=SFV_0O?iqc3mEC^xgzLV7x$y}F!j zh~_H!%t6$U&Ck#)@tK{aJ$-AHWxFs;_=n`Qyw2h|(Exk!y2f*#bla!l%8cB{9U*Boj^{M^Ry3$u2UsdJ={})!bu}I|AwRD%iOXU3Jn3$qeG{n?!!SHlU`wBw&v199 z^NZ(kFts9s*;KzwoAXZWY(#JqpyuOWG~LBEmNio7ruj~>BqU#{!iJpX&#=Ed6GKJU zB#ih4Na$RZ3~NTd3d31OF#epj_`%IBuS*+onjC1N3C6HU_k76S9!*PKOG(yYLDJji zB%FV6vSq{*iJ2CHj4u3~_UUuj&%)pbc-et&1GuE`6=h$|J9S@$J{Pi=JMsqWbpP=d3&N7JI%c zGejf4QpdD2zD8L#Frs)1H7POwp#H14b2=k^5pQ#{j!pTiZa)#EGykgirvnTn=PFP#w5vB~DNzqvp$=yzFk-gz{ z#_%_Mk_yd9dvlu~?xf@I!zmPAZ>=}XI|pRKj*1Pe4J!0S!i##KpoTQ*riW*tw&70) zL-fLFlChnoTF{KRDMhK6x}AyH6Ca2)q<@f<(VKDGOx2@i0s1q4N8O>=KaG1@$6m&} zGk-xU{VIaAyt}(=khjKtnk&)VO#|qYFEh9S>f;Q}ny!#pGcaI(G}ZpWm^Jk6Q#zSm zSu~3h3wtJQnVbfi(6R=q!hT(^h?HHoFfpn(Nj=!dnmb~{(~YEvjdiw~fW+Vmb~?8r z^;e-7`8Ym^?!_HH)!aUz^7R<;559D>W;We3!81<_si<%o44=xvxTdT zlr5LlzJjj|qbU?X3Y$-jcr?PH_=T-VT; z6&buc03*dI4vtVRwI;!STC5=aRvF0?74mdGB`fIu;11>Y(cOc)&)<`~JBI_3hTuK6 zaDNHU*P^TKI-XiT;r-9SofQ3Xd!yplA0F0XBV>$tt|-TEYKzmtpqHJzW-Oa|3QQU@ z6qp6Ftnk5*DV;tv9Y*YvHR%Rm_1R$`ot2fkpW17OIWvChDO9&u)H-ZyN6H(N9n@61 z_M(jkuZlKCF)$DWx>NG3FwDeECJG+G!2%Vu0yA{B2JOzR@DpB5Hc$|UW10}) z^B=b-_{lMtqCVa40d7Xu7-bAKuQ@|7ULyr#WY za)AHc7SW~j4^rPv&P)CHzCeU+cje*68-Emh@L~?p_A;$%zG#>$(Y)I2ZD>A}(WyC2j^nEKltoEsTKydNpb5-rm zS5fA-P1)z+GswY5zW`&T^I2v&c=%@M43{|H3A;hN%i4tOVH4>aFLWwUis+&?~UYcior!@{irorD_P1e><841Cko>*xxR9% z1h+oNh~m(86Xa|(mL2>Ljdh;*SZnH~Gh43tcL%*)XfmXEpy2*|m<-(Sb%L-(c<3#? zpND0p8PWN`)h|FbUj0-Qx7@poUw}-(x=%w`2+elv(wResn@*XegS7L>XA@5nC}blI zcQpF+#;OU;9<)R7k;Pu7vMEOwJQ!I5K_-4ch9pY{qg<_2Sv(lJgjhO*iG)P6@k3Mb z3Mtw0?8z1BL+PyS@XTh1+@n|En+81K-snlw^uU#VL=)@pW1F zl?zz}Ps0&v%vm~Y(fXRvCOp(P#3k>`Sc@7&5A!o8)<&03UVgY4tfxNZe|cN)Bn^6* zDTKE|1T(OBofmSvx%3&ysuTUPMia%G(()%0dk{}iuxqM>-$MEz(}|X)`em&S=fX?o zpzz>z!W$pQ;J64Tr>bW%-L&r)ERNxrcW<|XG}K5|?B|+t7yp`016S22)E2Uj4!j?G zZ^FBd(4Wd!$&y_Py7nBm1B-^FZpj|fo`+*e<6I`6FtCh1V3`=gi7k$zr$Vxd$Ne#x zT*bN;GZkwSy09J1bj55ooY+IUrt{LVHq{?g*~GZapu~(yMFI7aCbB3FpPf}x;Uj-g zIkEBbiHOdu=H8?dz3s+WX}ZK za_Cu%E1z4^UNif5+iuCajjE|kLmzB(+K4-)r5@|ePy-h#jlh!~Dg-^}qE>Q&((2G7OC#rq zjj(kG1sw=2uLn5A{R5UOGU9GAibfwE8ig>Yc?h2b4w_(9a9$?RNqj8|7+%PdBBd+v zAEz4yX>GN4UwUQBRkC1*%gR1prFL;+nCMDzd%P&^kiju~K}u!qmBu1R&R-?QN7j*0 z&RiDXC{B1p{~p04sx@G1pIKfkg4dRf2#Sg+HQ_&ZAb#J%DVD8_;A%rpKRo->7$JlJi3 zGN83n5rXJ4lF+e~uBO77V>-|Se6N0x*4Lc3UUCxfpua>80hXmtHYgX1ICaA)%pN9b z_Nh`OV^5^BBuJYlY{eGWX5)v)t=|;L5%C;NOx@VIBCZvhdA2m`#A^)LBrd1Y$!F!s ziX*a#Rji$f6+)#2Jo6ti=a;&Me9BY*`CO5iccHUL{6PVYBxA^_SNLEE1z)!v7a_82 z9;U8zHjjt%r%;cUK;-(kha&1s?AMP;SaTZY3cqIdkfHK~>>crm=;`!4{}hlx4Z-7d3@ zKYma1G#AkiX-G1u)|k>`&A144<+wDap(J6VzC$eNcUo-vVx7Hgdj88>Y|N<;FuxAN zk$TPs2AcAv35o~dJJ`@mG$~j0D!uxBij-S)g_6B`h3L!Uq-fmt_77S`W7E}$1G63q zM3SAhtmBgN4@B?(7%-17gl>kbOn2bToBF(6yxXWT4&Ktpo$Qhv)~gXn&`Xt1!T4~a zX3t03F>)gc+J_af#J=4eU}z&om44{N50=&1w$|i-_3FX1SJIIqNl4Abb;}L`W~84G zY7vW5gU9`4FVfd+qhQA(Nj-pRA1%XKjd2@(ZdcinqOK5^dd%RywD!Zbc_2|c4|>MU z13Bf8)-AiyYy1>h^{tP5EIct&)Y+8tk3VW0vg) z7>ZxB6u{AE8Cz_^s2zJcU-4V+%BwvNM*H+$LmgDnrHwYP9;a5TM5cLn=aX)XF+>3p zj#-OO#>gg%LpNmf3t*9Hdt`Stf#nj`iFHeAs4Kns(C|@>ke8qUjT9A#pMY&={3G@w zB-hLLc^_#aP#(~L!%M3y(^}K=1DaUK@&>YAydhUh6~M`|d&Qhj;7<-lOh(^i=_m1@ zhY7@@r}kH*W7bA4?Dd37QtgE?WF!kHwa!ID-!#~7q!BX74( z!0Sc}mh$OKv>l;eCVYId%y&UplMmjrHMjbKkgDa#St@)+iNf9Qi4lGhV$w>*E#sK% z^I&q-Zat4eMKIo4NDX`1E<1w_a%tTegL`sK8UvaYv!HvOeac~k2b2&WQ?Amny5PW4cQG7+v5f=Nt9!bRq z`rriSWHOoYOijtA63_DL+-R^e%ml}H0LF+H2P=5(O>a@b$(2c>B}rR5sdn~dnf+tjrq;})ZdC0n?kQKXK1x!h_%)!QF4n8F&Gb9+& zCPQ7M3N$L^2R&50R&pXK8QwYj{*wYhU^M^Jkr)_S0OA(KJN^r6HVkfqOODO0w&+a? z>3ZF+;{QsI>0?5^ofWq{TM&VfZkKl#G#s1d{G#=k(ejyjcSr=>>F^c9+B3&TR|KU( zoCGYQ2;KsoMICZj4;j4PCrZxo5yyk8t$99OdymmodT~*EAK<&tUXXfqf##7w`zTLM zCyLru#t1bZe(HMsL+_V^D$io5vF_f0=%fQS(@QpXe!ClsY z(oF9F`4P`}nUqV5Pi;}95`4On?4|q?rg34D**HuL{c(g^4hm7Wm&}y%v^ExQ#Ays? zSkE?@oLz78YBET;QGdjd&EGl$#p9t~Zc(P_a{L_RkJBYG-tjPiZEModVd;TUFzjIt z4EPHt5~uQ45MNQ|b-X9nVdXpT7+DN|ev<7bn{bM>46pCycO_d?vvP(Ppw`r7QyOqk zQ4H-#X!kIV+88$VKLX5f#YLjxqU5q;bi^!NJh>qlApn!b7&l={?`B4flq)~9r0)!SxEk)K3~9A^+7+2^L}^82-4xoaV2{b4i#xjR)NX>&^(FEe%aCj> zn01XnwF!(1e`NIlxE+*Nx(vD8ld*b)QplY4vJRUvB!X)#xQXzo(UAPh*B@E1SZT{L z`*UF_-}Z8nfcrl%z0gz#9oZ?F>}%Khs5a?7eF37Q4kh?0@{?qQZXe;z)pBL|6IJ1~ zz_$l4TZsqdsAnwP^UHwYu8TlPEMOgG7D3@B&}x=SdmrcW%_qNKVq9qUE)jqgm}$}P%jvUO-2+L+`4o6K+(U` z2*GdH(ttXTM7;RB6cck9T$z`_g+52FGK3YD^9mJRG$^Ihs?*F^Poix}m3BDZd-n@^ z(8EaT^oR4YwVTg%%q3tj%Su!yr|2&aUliyHsnu?zJ~VrtSe8%~vYNh9-3yGk)g|gk zn`)buh7|Ho=5e8qMLDW1LK}DqJ(4UyOm=GC zkd?8R#BsP_RsS1I9m?-qShaM%O_0nOxBe1gskunXvB4~NFaBxiV;N;W8iW6bt+#+` zYw7xjgF6IwcXyZK?p9m^!Ci{BI0SbHg`$N5#oaYHMT!(F4lR`8R;(ZQ-rnc`KF|8H zvT|mx`ORK?_T?BR@;B8?<-j>bmI%fa3 zw35-RO$}@rMP#$IHIgW)f_QD%k%>&1E%}fVArBonk=zHbn6@!Q=}lV09?XFiBmQAi zHrAPjRoYFR;!BuW(Popb;+Bz*;W}mx%r0gI-!|HGxod8H)WjCvP;k_+L@Ajz%8WuM zg6abtboJYe>dt5s9pm@4mKHS~k~J!;ZnV_mY)tym*T}-SM9D`2KBnm$bsB5Q4#_CY z@O~UcL)ekUuA7mcbPQ){Hjv|V6KTsMDiSp+_fvZ?!`C%+EoM?3iL%l=5#_`yWK<#q zF2zDTIsu;t!*3%v&xNWP#0*)==`x%oDw&3Ek<2*!4}|Q?L#$iBoECm+dOM5dVfK(C z-B*tHAu_rf3npcQgf|CQ_FdX34{vGHT8~YF0nb(oZHS5}dH^iXoQ=HVV;iZmDmpRa z%&th7%`sFCD~mYg)vy@x1(~ct8aE%*Y^swI+=|p}JuW?okNGnoTB$OIsCGQ_wrvD_ zc&8jvsC%>>lJZ&ZVb9x-qMSi>+vui8@|t3Ilr&Nz`3}(>n&hySETbbD>y#lv6Y`g| zHd#7*Mf(q~Ae+4RpB#l>z^OyViNsLInp}RCF17a!^Q{uPs^{>^?-h;hdODe`a_R}> zVH3U*?P8(#^&H^jnTgcsnqw9`61v3+E?C0Vv5&OXQL1YgR@|4fgRWNEw$A38aDADZ z-{6*xYq=Yp_dJ2&9o|WP9?ig)LkeHAowUu1`b23JFbHzXB%gSrB&LF@d|LR(nEKVF za$e}uBhio~7J_<;u6ZL#&I5WPogb60HAT7z!$P<}W?9r2QTbyO?&HKq$%NSKx`TH; zarmR-CB@4hO)2Rx+0Q)$@GFjamS$W0Zzz<5qM$P>?c_0iX|CgJx5P`YgwB|6u>?*O zez6RYo1v#&{xqP9YJEdbL-HGNcfMvnsG9gn>COF}ypcPC^7nTdxD2v<13r3eUI_H#}k(}{&H>Uy#ET+uyoaoMkhEcbQb~Y=&cPxGJtV+L#!?W(~ zYuXb_$eqJ8C!_pVGqzCxqL@xseN$oZZOaxfW;OE7VZ59++RVyqA*o1>Mg4pB!ihH*!b zB}x7UX!T`WKG5cfDB*sWdBsoUUww9m(fCMOcSH5DSlA3}Z%ekB`D<#i9tymv;IXNu z!6_4=)>>K9XzQ4od)W6RKSY|vAO{Db-+(mUUb@PbGwl_p7e#sy?f+YDW&q0Q>!tV?q_>M7f^9!sy@<-^;*H|H$aBx)zsem@@F(dE~y3$Zh!@|^s4SQrNmmh04&=^i?%+`hp_8AXud>}cbl7y>NSv>V06 zTUv1ZuJX@`lezcT5<(whlpcv&XNAQN@Ym28*~drSiGmtk<-5nkxT5+D;ey~)+A)XOL-oow7;@j~&woJG^4A1l2u_ zntrWZ^k;a2@sd`{UrNKl4`9f{vb-ug_SbD$vgx~8n+^MR z!q(IO3;BO#|MG5X6~-4YwTc+1idu1AtKqJSiji;r3&@rJxAfPQDCYC6RlCzr2775{ zf(MGqa|8wAR*tgv9}EHm&7acW7r~CvpMcYcJ>F<2B4fma_>D0SD%O7hxbLC=DL)r# zp_5Xk z^7SMl3B94rOKw9}PQ+09an8Kg%}Uq*b`X~#P38IfFK7EZ!$$q7FAmi~5}k;m8@eY* zT+KpBn}1jl{sX4@LoT!k!@#Z|a0G(!&!#x)5h9l9zIWMr{5P2G54marQ}c5W-bz`I zuOBh~yvdlFfv&jouQvX0{*!+JaOvKdop){5@|lT8k?K36NOC!W$JNaLfa(5l=1h?n z`9;&Y>3+W6ba5r+4z1Pr^!OzG-(v9mA-R78wtCc4Loh)m)uhAp!%iG#hc9d?|3~P5 zNzCN0cdV|}yDwNX4;X)x(&_M)435dt{NV-nk2NCz_X{WtjEQMpWO*RUeJ?%7Sl zrmlS}o*3tZ{Z!{t_upWaKO{$@=IQ;bowoclIw^eml*I`2l8(0=DSvAJD4OAqSlUsC zWYNpkY_*|OH{vTlEDDNe-lFNx`~f5VBQwLF#%sGQUK$w2bKq6WLw9|Oq_h36#hf=bV!f5i`$UelQUN7 zDh(Ns>uizeiqrf7|Isr;>OXX)A{s2I&Nt8jh*?{(zY-tL_pOo&o#%hRX@9_T%3UF| z-#=ORVU=W6Dt=MZ>VF@zR`>r8E&#LkmS^RT6mB7YN;2=ybjfg?I{Ey++Q|H;G3f&r zX1~c%B@Y+a*&P?hQ_N8+fDEPY4`=-Me-AgqAFx35$?Wh8u-4N&l2U5BYi0chzBlyzkn{x!>9iv2Jj!6S+@;hK`~t>LdrlS-S37< zVe9<)IY+_2V8B0||B&aH4Bz<_`bC&qIm!`j$L9k=LA%vY|B?EizyH6} z-QZK`1Vd}^$}0=M@bre=U}YLL+l>D=hVp+)&Hab9Fk*`_8UwyeQxZE1|IPyoa$#~* z3-C`R0Pr_wHTh7$-ybf2r_2>QoSqyQlFdx;pr{74ZF)e_*eIXwm)y`{;mG+>$6pq4)=N8he!Co zIp^STfwX^lVaRAdyI}ld4E@V}6SyrCoJ<@Z5X`b}&ifq{ha^ixGjrNTj;R}u5ORwL zY*ZD}J#%qUFC~A)MPMAE5KbTtbRuYp%97xKj&n>uV9+9RaSN!IU?mut45clll=#aH zk!`9)3rN@)KuAs_b?Ub;A}(6es+{p*b1M%*5LwSin$y#|+u40J1tK>he4vX&57y>7 zu3B_mr0$(*S>Q=Y@1R5EW@AxNw!nKP+ZwB!IJ3{m{t8jBW$UOWCN5SlSfivQ(T^HJ z%Q%NTHb45)&z4o!mvzr0k4k4WGNlRXV5rQFoU4_(w>1hXm*pG(I^at%*H9EP{ttFU#X#>7ZsV+e9bBQJ%c zWiT+pxpSH<1V4Uv=8phgDAq;D=A(Lq`Ar75v98`x~td?<_HVgc?Ewx|Fjz7AnT<}ZDDBse(qp2sE#e=-Y zs^`#+;}}RR2qq)H^`_-T3E?p5g~$!gAXHG;Z>mQu1wWIZA;UQ6f(|429;doQCs zV~{KB1K|{>F`=TOQ?oI!3M2y8h6D3!KP1=PyhuFNX<^b$E=(yRi@_iVeleo0G)JQ% z>%xhC!-fbmhe^XEOzSj6dIrH9MPg01&4=&1!F@n}ylA_hsVvD9U)`CrJp3T_2a;gc$J z_*fpO^z%Z(#jKOl@QCG!k)mbM_*ca6Sq6Y|_BO^^7dWlaSm5n7-EDFr0@&uS;FN51 zGY&(8#HpC1vvqbGZS?>(jLFQ0Pc2<98U*N zG*O+$32~u)E7~f;icNUKkB0Gfh(a-!ot(L#;WLO5)kW}N0ZWN`2MsmC!66gFC>(Ea z)+^oC84U|V-Q~RucU)r8))V515m(fQcf2?*Gkh*HAdjQ(O(r(0l)E8>JLl2O1h*_Fxj#&gor!QDPOBV+(cEK1;OIrld zXVf7T%zVmZ5?0e3AiD*|_7_}+)E_9`eokDYJ2$x;=u&BU(8EjlftLbR{vNV9hY#i1 z8)T}VQ4SXTgsQGs_tnOeGP)K^sICsGIF?a&$g0q*>i7cP0Or`GF|1qQgJGQ0`u z1hi=Au6wFU1!>v+&Ua!13TLyzr|KJ-wx9dY+=!UF1XaoziBWF5A=Zi1LGLZ#=J$^tgZfZ$B@Re>rmh<;D#McwQfQ zX{2R%{$3wb|Kr0A+}d+(S=Z#7;E2s-2-oJMlf+-+*s+h~!-{NK8h|yd;^1sVHnbSK z)}?oP-(QdY;v0CuTVuEkj$VevbH=(P2}dsRCSh?b^BFCfto9j?-i&1rk!aqd!qrUzPI2&}0*(LEJF*i(rC3IvnXcgc#Or$4IkzNZr-)Ve9 z`{pn?jFuL-WlwhFpD#9TI<9mV+j;8Vr%8#w%&^gz*^X^NAdxmDEK2mIx5nowAvU49 zh1|L$>a*hp?Ft4hN?^2KF71eQk{r;^2%5jMCYK#+|1l`fX)tj!NtoMZm(J9+*UY}} z&2NBG%U6i;)UL#L5427t{4a2g;cCy1>{yi;x4U#Sson4rlKsnr8tQ9Y1 z?*h{=Lqh6LG!~-iQe}gK%$PaW+2q`$#C+f+bw7qHkXWK|9Y>c6gLJq}WneFut4xX< zlQ-9O#TarA+1SKNzB)a-TDO#fYw;(Eh#=U0XzXNiAG5A!bh&I9+hmRz#?#^?xBkY& z^z1jz33~IgzHj({A#Z5Nn*jsDc zc#dda7Y|F*>AAD(;j~~3mmJp;VcyNF*e+=~;_k*B&0hYGE)o5!UV`-mSkWC}_^JO*7_^ zLCee8>t2pXC;gggw{ekotR5@JxI01m>dHrxnU{hZX_Ny0YCWXlgxtNa+q6LiDeu+p z;*FKZa*MH$?qkY}K{4`rASEo1SS0*M?5Kqob|E z)hfSjnif|))C-Zr&*ZOCZo)Q&roLGv70Pu_xQykFAZ>PRdB@a$EEBVuOTF88p>lDU zSI6Atvw6#7otUzy-le#5;(ciJwF@I*iAds*lk0u|y8JwX3KMO2>$!T?*eSeO;$#r# zFquqRcCd6p(rfn@Y9k9ITM4b5mGn!#9Nab)KO_glT!;=3#nZXOVn`ae_ZkbVzuu`; zh(joYsgB=ftC@0r;7D+1ewC#OGkW$kH0ok^!Kn$jvv||tlkN4{e~{brv+_aXJK6NL zwrNcSsZArzsx%w_kfAOXRVepw_Y`i;v@U{HvjzUr`A(bIbo(u__G|VaaG6LEDr>0e4 zD#7_6G@%u9>6FL4guPG8W2(0EAWp`_6>_G)PP~HJn=9nk5|K~Uhd2I_qVPUYp)09n z>}fU6?nczFSpy84N$rXjCB;V?Du?1*ZaHWSrL`oh@}?u_vMNbhSv$`T7jxyvfb;dz zyY-%8mz>LHr`Fhmcy}|c&cH-X+b-qAZLurNgNmD~jtRytdvZ4~#|f?>UevDlWahMo zFO`?wG;^HmT*gU#2JK%OerX36oapwy@qkzB^{}N~FY$@#tQSe3yuo|L?D|x9O`_C) zyE)eKf`;*FBc?yrrnKuOLB%;Jx1{{pYie1DRDdUGHu>=3HDiNjVz`O93Esozjc-t0 z{_@%foyI7>&sR2#wJ0H&ja$1{Ttaz7H|LLs-mkV3DDvvAXbIaTxzea=KB6I9b-&i1 zJMaZBbj~NfFNk&h<=@!W5uNoTroQIethEpLy=Uufe1DA}XVtG9rd3it$1hBKd5Fi~ zjW8_I!nii7PkvxO#m|eaCh*c&B?zJUxYZ=Q!>?54q+GsCBz?ija6ElR9A=P2MTL;i zSfQ@0>8^dn?A#{* zYFYGAnlGK6Q|;_dNUch|fcy4Yz?E3mXmn^%8;>M9zfVY3tibTKd&t~k`rKONJ)?Cf zbm^VdcT;ynN#nIGr=+igFEAq)7V1{di~}w<&$2ws$;({4SL^9``@6>T)fYY})ZMN3 zet6#zo2|K;P=d(H(?@li65N4{bJgcNfAi5xYuN>L^T+mt)WbT)#IvtS%aimJ?BI=& zi${xLtH+K6%8#Uim(#PKv8htNRA7MQ$_07{P`@(FOxu#q`5y_ZFhscB1i1v0p6ulX z3>))S;gYB^E8J?lGhQRN|7DZ%eA565?nb6(k4?;SiZy)g?|rVZT=M6TRX@eo*QrVE zxZ78+md$W2VlQzdy)q67+obP2AE3zGMLS0M3Ef(FO5b%l7cRCq=lzQf(`d6C;ZYtwYa7Eam3YIn!LAow0xd?#iekm0Tu6Pceh*B;{4H05Ozj8>^VC) zi+Tw79H@jbpk-#O6tN*DuQqL+ua&}{_8YLIVkgR07u0Y=HH?_c;Z7=L^fgdwq_({C zPBd}b*TL4_bh$KQ5KpKGNu#)*Y9}u#tlrYPF^BdmlT_HR$ZGNshLD0maLB&fMj{mGh6; zh$O6|B)>dgz|FQHl4Ttkb=+YGz=aF@UKnEv1Z4EK~Z@uC%co`ejY9)#wdCSoKSFcf|&fe$ct-ilZIh2 z57)Z1%aE7mZ_-+#KQ-vQx(#VgKVmXELw;!vh2DC&JFd}_3KA!YOT`TS8^Ppuf)=?5SEE3#mNF&Q4F29 zPM3Kz0>pz7{IGZ(B3A;|30uyAV{U4pKde3&ZrD%=Z2bmA<#YdfPDI04*u}y9%ahXd zy8Ds%@=~+3^e6$RP6l*rK_a#)MB9?2@kH8)YDggCG@{ZyV<);_h0dWqpTz)-li z-iZgAN!4+g_a&?y6qJIoyV60rULEHR}oT0!=F~n%A*=mTUI-y zQLrDoLy#YCeg@u=?A;vfaz2?qapXIywdOTo^J$u6qi~yYJp}E2-QP3K}YH zVce*#dtI}$)$+hMo$qm$w@YMX{2S00^1Q2L13t&e{*^}R?<`V(9m+iKD*y6Dx0e3P z6}`S6IJN{zz3+-M+M z7?}k9BOrEcBUfx{HQe53sj<4%IF|RT83}v-7%D(KtE-8wtwBsSvvC(l*S9n#oMuvu*)Enuo(MN}~Dd7Bc`#g-{f;piG21Ih@MbR9r;RQgH=O_)z74eXP>hZeH?ARJSx{0SfNtzFu zqGsD?YGHYwBWH%Zm^`k|3Wim-ZBA4y zgb7-QyhFy|3!1m)5<8#loY2X!g1Qki%_`pD&y6S>R)LT`SnnF%$+kxP^!P!PY4aPP z2*#v+U}DXwh#fi245j6|fSaRiMc}HnxX4R2IKw^Xm2X5@2UO0_MCo9Y$D1qBF9dg) zb=Nnqt|=tc`QdyOqyBk}jJTS@Dojy_3eNOA3PJIDS63-i3f05IJv4NTX-1|KFlNL1 z02|1G%91hCCzb@4rQ@1nM9*dFZ|hVhxROe53rF(Chw7^i9>C;HOHy7mJsG8%UVQtx z^C%6}0XhB#6z>y6=IU1PqRwwii)wr?Q&mDYqCKw)O*Hv5V&T!3ndJ=E^mdh^BeOjV zP67lle%o}C46)KHcL?+M%m*LX25~9D+I+eqpPD(*TVb?`yB*-~ygGUe{iNZUnS{}_ zDFb(GcJQXwm=1)b(SWt~SVf)-(o;Ru>M_`?9mX-%QK+P3e8^f#J8-=Kx!bih|N_C(kbG#m~V@{G=HDR$po=BGGDf|7vgi14_jXL&_2Et~Z!M+Iw$3Qp0kg#FN50 zYo<`I@rUuBJ(Dchfp!Ko7R^}j+X`Vf&=jctzR7Bi*T;j(VgiD@UhCh0SUKP51$*s< z7TtIGzX1=49LClrBaM+l1**(XJNHQ@gCgD2%BhSRy*V4e_Xs4T3Oj&)B#&(@zcgoB z3y_V%6u7)vbrt-f8IJs2YL;Qq^y$Smp2e?zOCB~UwkJDRZM`=k>e9qCK4Q1osLRMj zzhDswlMFL{L5i5UP!c_dX`>B|!5zSp8fD4SRfv-r$(pl#v)qU`t7+CD zlknT*QZQqdX{+0%G$6e=S`EMsNoS^9jW$@@5=oBh7Gc^oJh zgwy2}?xQr%SXZ~u#vF2hRv+GkbGsei<92p``B5~I)HBp28rz1Fmqd|KdYvCoH;EBB z4A027pHobk3drmvO|D7oQZfo^$e>ScU>pyawb(7hP~fOI!SX0X+eoJG@nkVy={TU& zjcRvORJ-jAgRd6ZhHLWtkk7?;J@p`U-lC(ebkJK>!;$H|&8tp?5Kfr=a-I)Xn>W?! zE%xFvT#ODK8e!k2xi`cp&sXG01y51M=-9H|9baQZSSpq`$e$paI%Jab{8E(rJA2M0 z9JYmnI|;mRqgSFMJrn?(NJX1RA&zIHXB=9WbJT4*60(@7(jn9`G%a@?2Z8aPBXc z*4`t<`Q<;+IcT5k!LNL)k4^Pv(`UVjv%QTHnN<4)Qxc>`Z1IG`S@T7wC&aZ1zsHQ)6xQaUZd$8_&2is!tO2&_T-T)L5-IJo4cjsRBWT|vR zJ$7JJF#6@xYdbc_n#)a1zx|yrA%f25FMRQnh4~8TT&2#=pXpZ4)(lF8_rc#Of~Ns_ zv8Z9Eq!PaY%1CK-=VwG-#3AKg6ZHA~sO(l!T-vOvgD+0_HU;HEqn-D_o;PD8ax?K8~AMomJUX5vjXxg3-av;TOIQ;K~1>v_% zF7FkZ`JZv7Y}G@elgek;;b#+rrTfo_Ji^W zscyS6au#F20zOjW%+fJU-RwxHM+bKUKO%$Ki|pia+iL%odxNB5>HRRuU zWRup5#X0G-;ThW|l#?(~#u>SY_SQ)|WXc%5ep?YH+7hL$``?xly5c4QUd+}!J!^E*abYYU{8dy<@1#$;cOr<74kFc&=r8>2}- zcvQ=ItH7EL?IkyDhl|!}Vp--%a_JCaM04nDvg~L?tz(6?1HkZ&A;zzXst*C3&eh|E zKP0Kw)Qo_arvX{?F`b=GwZgh(Xrj3$3iTsF;~uaB9VM!qDbhu^~09Jm^!NVco)jTphn~(fPZ^RGRP3A zZ&F{FM3raTSfmDA6WvZDO~gCJJ5PrO{VF%5YQ?j%Q(@)sV~z>I3Wq$TSK+UlTgJ2j zDbj_>2H?k1KiR0BTCMJ?GQDnxz%nGrqG&5F)+P)rM@A9J>UK#~fU1}^%XiJQ@}nk0+sk z6elS+#lFdtn~TxuBcJTl(;SnLW3k8NiGj*Gi8QG<@?}c|x?cweGH*0&x?SDWs_N@& z+m{Cd!8SdNV_8EoXi%S{@VAwBeIz{}IPh&<2&{`;taXkJ;NTyM;p~*Hz~$D$ocs#+ z7;|0y&2?SUcg}ahWYg^A#14%IIk&G zf%ok$aTvacs7edq>kJWI^fk>zQq}!^c)piqA&on;9dI09nC~T-kV8T*DLxI*3CLuo z%0LVv36?;>pV;Li#)J{J_C&^pZU%#R08w!2&O4i`fd1|CdWaT6x1o5<@ zb4kBZ_A#K$1b^b4(utG(-q9waq1JtGFGnsd>pI7+SKP6$V&&@GJz&_QE4~N57}{b^h7BjSBpZxzO#IusBf5VNL6U zWvL76>=V9CP(~+m;y@C@F4{?3*e1}8uJu4K-)|*$hqbLQ!`e7>b*kl>$cM1MPJSNd zJ?WxFb%ZX7yEBC9ENut4 zbx=ov_Q}BY&hkBrTir_4p=GsyqZGso)-{2N{KU8`&^$2IHEe?^%Nl|6m5^1yQ@kyY z;yIz+8Um9=A+a($ZyjfF{_B#DO$2Z-ZT)Vfy$}oV6Tz<4b>gj`#Rm5ktTuvhttN}M zG>$8I8g2s7TlGX(@$i>B`vm!xZ1n^?kRr*7gPcx|t~R@kwQ(7~sWpDzj4fg-#NxdD z?TFGe4+ima1FneVrm*zfqgrujms#@)tl272=x*`{q&&+I6h@&qaAePl)=1qZO{rMw zWDMZ!BMWbRmqK9X><8Zi>Pj0kq=J&uWx7jc?TOHey5nr#-Eo9LQ*ovHzCsAAU?dSl zs)R&&-FJ*pVA;lPUB;AggT*Z&QcpJNj!E>dys%abRNgPoRuFDY=*uGSd6zg$?4;5J z0#3`;8xq2+i8oR<9;Vcu6^r7tOF;;^Gnt)odsi>eugXJ>V1r zPt-B=x>B$*@3pp^rE`6JV0QHSwLft-^eY$U$jEP6_*i`mk;DN}9?K;&; z%e>M{@`A;@O=zDKKvloMRonZ@UY5l~#GGvX@vDUwWV4e3!@^{J+M72S21!Mc)q8}` zvA4Jl*@JA0o~_J+c&PG?^+OYcEY7CStC@Z#URN)SwB%8(lz9Q_0c>FFD~FID$ocQn zVXFi+4^hR1<%i`6@IekovD^VGLfx0rnf6`OdO!FbirvpfcCphbG~_G=~R^A ziosdF)Rg31a!D}?h+JbNTL;VLsQ!{C5|ZShx52Hn^5eAe;OVgG_ro8}S{f`^@hsHC z>fl=x&9On4#_d-Zp8N{B(h=f^0eS^m7(?GdA7*X#jb2eSR1qu$54iA`D|{{=lEx2S z=1O#yIt{h-c^IbH9``=G4#y~w+;}P*hpLPCTOD{fd>iD$+IDg)b%y_y11+zUfPO{D zGQUmi+kkgD&5XYeoACC%3U5i-;+yjKDa35l9X~7r$OSRkBo)z+xW04b+q#gA<&_tKubqYsFdNeHs9L zJuK|RwJxr)Hjqam=rNZmj&avBG4WCbLx^FGvkQJtj5VRtUA<|90DJ$NoI6GQIQt46 zO>8qIhqS9;UN*PX;Qc*9l^+*d>$` zOh@k2tPXZcXJtD-$>Gy~;sQU-cScaw6Z5?3 zIK2Zijz&!Q-AbY(lZ3Sin(#t@F{dS@eiwPuu!t#MLl?fz1hqGxNK9l9ud!;B%`yhD z$sST;i)qE~C%h=HNN5+21*b-4TG=6c2AkCxNp>kXsSL_lSZ8E{NumbCqh4TexMijy z+OS$ThTSB;w9)WpLGUF!Q$9L`b6WN&rKkzaOyT1U3oV+hZ%+bd?$Kk;*!p@*V2AJ! zaU=&OV1VJj_RKa=y9|4EuR^%hH7U9WXnc@2QaOW6NbVkahLm82( ze2}TE<<+5}gd=dDx$N>9b>rWid|s{Z2%83@MMuNnCKb$mCg9sLnsgWW3Bz-y7|FbK zScxoGuuM!`A*(QVv0(29np_nb-!=?c6y2jdz#jVmb`1;s6e4TA-ChlMnYC$p46Y5s zu-W~ffl_eMEXx(cwSP{f^8xzYXl<)bsM)fOumfqRp=<-C0@0UXiT+Y0>>ckI933Mm z&tDmZ!MvCvR+cu+jVnY^+9O`4(#?L8ZMvh1zH8*JNi3881brV!asxj|(iVoU0Xjw1 zozmMCY6@UMMwPpyA;hBCe=J4wL3y3pXc8 zY1908Y+*K)RZY9wQoFEv&YetL#i9VC&M9)m)EbQ>`S)R@c9QM>$o0ml}uTH zqNkB*@j1TPIK0!0&sDU1Q28Y%wiKOf9H{F(fbDPrsXFhGNnzD|#7eu*8_Pz&ja=Z2 zkfPpofg)w0X=WeHaqh=rY`tb2vqqMGw#oxXvN*j+;E2)BEt`U^N7kk@Pr}leMlJ{R zR0#spPnqG4=5ZNsq4rVx4=MV`;}xicyWM$Aeq__W{1ItYz1LL`^W)&n&M!$U2fems zaenyhxCT~aCun-zp)QuAUW#j(bqEd=`iWoyS^l*(Q!9)EJ#%+k=o`{zboO<|V0JoB9XW;lHjE8%WXR;76D=t-wPCJq2>5(&vs7Fpx2x0fDlA7Vxp4Cx=xK3 zz$It>nqvvqFSuO?8*gj^sli!ryo)<(qQ3#J)Ywgg=Wu<*M&sV%HdSOdmc#FBF=S-=j5hdv)S9ntyUQiqX>E zolEHJXFR>!UodJqJwp_e*G&KXdgMG1Sj$y}D_y0!)I5u4(8cJmD^5H7!3H-;FNtLQ z*Rd5-gcTQR9==&`u;h*gz)x|?C>_}-SCfJ zmOMX2g|~HbSdUFm<^1lVR>Y|oTD_lleK&w{N3iFCF5(4lMPXEyv*9X4&cG zlQ<^~P4C1uE@^m5s2yk=zO449oId62gC^FilW2k=%Wo!a?K&Ap9NekjULhM8y6jJ% zS)}m90Rq0=T?*J^HaIOU&M^_$M@ClBA(08|Zibz!nTS}iD49l@@WOvVFZ|$HXiJgK zijsjDfm=Bu^C+(*=|`HR$Hvb~5f3X88`Ck#Rt1@-MiUR+;A%_ntOE^sm=^l)!Gsz1 z5j$-Gm1?vyQTmkxEt?g4Q7e`H5Oh-=1BIVQ7XVevX;MGR_?}^X?d0-I9`?Xc_P+iP z)`M$mNnxMll#iBLfXM6vBS!peA_D%o1eTcAGB3Fd5pZ~A{NoF~^@Kg@RvPSih?XJ~ zW-LZ?)8|u7moXP3LwpYi*%&X%dP6K_+ok9fW?FFJgba<% z*R?}t998NOT8M9Q)O60{A~E_?z_`_U%- zBay#;p&US~y}C&}@H$525=vA;=P@ve&-Pe@ZpN>%pn&^HKA8e$+pS7M2mJ6RyLg)? zzIiMZx;d)tD!QlZlttG{jP%JEZnJib=V*T{kLGjR&ik2VM$cDoV8$1@R)-u-0I~N& z2=gN=X*+S_A{>R3c%#hQIw?{!X>|b)aK*IbL0LC)5s$Uc;VtM0N=22d&{ZUNK{$&I z-r-fszK+Ri*E-xI^)d&;Lu2W~&G2%Rjxznm2)^_j$W9jDUSUvprCG0`8IqwKU*wMp zCr5U!E_G_Od8Y+z5ZoH0`A`kI=l09By!-2+$mT0Wx`~M&6eZvp*^=?$e%A`U?lL+% zM}b!`EEmogr<$n?bpzK#iF4_;&_eIaC}GDnd+X15Y1Mu#^Q1wMNFzKSL%qxh8_Xk< z&L}2+@b%Cvwp$JAI*BM@+Iy^ElEq*bAtVqQV#WqzBJUY-&oB7!wKn|*5Pq-G2_=p` zf5NFPt|&En`;$~ro#!R9&UcPOm<>2{zC~CLh5$co1W%>%CLd_ct|%WX&2!%GK@D`T z1Ak8?>m1?tK$J^)EZmRp+euI@W6r6&QNz%V?@R&@38Pt0Bq!~d<*@{0H)orki7h!l zj7Md7Tqk$TcV_+=__mbUN;tbuMCwFmtU!TTC%iVmC>~llbFYT%JO!6a1twMI@k1IW zky1&IylceD7#QRk-=t?-BXz^4T~S@|52bi#hB36G-i=^BbX03cJfcTZr;gwuR}6n0 zn29(_JYjJA8a2iNZl%ASe8urK5p%w$s83J^vKyE8Pj0fH0T(;;EI}A8YXY&u>&P|D_=%lT9oBbNrMntSo5$l=G zU^3~SP*(0F;nrqbF84`w=;wanZa^4@UO)_z>pnSId+_VYdipK6Fp!_ZPh{Hy;7GOz z)?^?10XECM%w?4{Fi7irt={w2`@4gkg(iwt@6PP=dl+Ca9sM)GHBD5y3fD$AEub71 zRQ|eCJe;T4a4k%`8zuIu`fW5KX8-5)k}>N+ELM#a$YsDjIcxw7iiveLNV3A$dkL#b zprWI)hIz1GaJ}q*?86#ZfG+B`o}ui9M#jVEE~u}ql?Hc7vu7;N6G`YAs6r|yr9Zm3 zA?3VZLnpjW?D@o7`Yp|b_D~xuBHY|dbBV0`eDe_kxmhQI42EWPxC-Le2Bk{8kyL{$X#6PI)SIE!w% z+D9@$fgDzCa2S!EQHA@cv3>C*rz_1B4>z`+o!F-&Ewq4ee4rf3G0859K37G^1pD$m zx$|Y@JX^(i(xQo^&YO~C=@IF?$%ZQTEf=RG!b{D5;PvU}@d%WxvngyRyd>a;)(ITz zA!F#j#eT#aKZtkb$PBQ|@gbS?CoaE0L_QvyB zV%m&(!5L;g&$z+p_$vi@lzteg2m)S)j+!GHk5jsEi@{NQQ^y+)5_;PgFlyzh{ey<*Yj~~!zKTAo9SE4WETV6lW(XqLj_e41vHsvZ8EumgZC4K=;$w31f@nq()G56Rj z3=YYVgK~=6)$G{H^!K*8&hV!Ph)sPqBW=)cP-4>0)VlaT~uS*1ohj@r^2eA!? zme6!?N9`W^GS;~_k!9mGK-i}yrAy|_T&iLGmXjselH98IsgFYA~eGO3RX6|F#e z@BG)`5jCe9ktpKsR5Nw(J>D)_-4CPI*~1#>IPr-QF#Bx$Dql=4U{(w2P@N|b+!7q&0*5gYV4MO&gW zNCBAk=4|GIlXgzy4gD55-GhWoWTd*7B4XB1=smU|c>JFi7K`IT$`q|lc7vgt7 z203RW_087uV9w4Bd-qO`0cQMaG7$w)o`u-R(ioNg0=isEFP7;v8%qy(?^CS!nL>;&;E=#-!ha+iJN;CxGOQ$h+OOG%& zin0>2xFeX6?uZ+j`b7?++JpiY^CE2)ity}w!uo9CsF*7QuhH5`~0@y?+%l{3FoOymx0Vi3WF$Yz-)|UxuwW0etEF z8m~b#L#K3xV)#SOTdNzJw$O{Q%x2Zu31KCSsSQUNP!dTy4^JYm0${*SfN(>lfZm<7 zt*W~2=s|wikB&LxfM|jm@KxQZu+KvwOtCI^S8D5oEc@mD76(EJ(V)CUT(n+m2C)Y` zMJ~P0fJ6U^V|Xbkq*-ClNRVeUl*A{N2YzKh1hOHK23wGU8pBup)W*>^GeA`}{}6X* zS}$%2ToURlLnX^NLBD}SHO&TGCnHK!S{|bZNKlP*Im|hD+)qGE`>o0dy)~$I;H=PH zgy9KjreaeX#nn)Kl}lo_(LfzG1<=EfhAIjJhhZNf@N$Z`L+y%0Z|~GPld$Lrp!Y9c zD}fGtEI)VauEyspHLxo?jU0y5K7F|R4LGET6|F?MxyiWftnN8^F|4nr&+&T9rKAI{ ztaJK?B->S+@tXXVAXnc^_QYjx*T!Dv%H_^%Ex(kF7C%9m2wH%%V-W^|k}P~!SS20$ zFOu6>QnyvF7+hzS32{()3AZ;)b_SCfLf|Ny$~lVnLv9$Wa7DxTa_xhcW8ksj;9+&BWvEMwXROJ0kaRq0k` zd}dq=vK#g$6WSR_7JDNPBj+T&bZj>zR~c<Y@D-lBFW Date: Mon, 18 Feb 2019 16:18:37 +0900 Subject: [PATCH 2/3] #197 : translate finished --- ...4 \353\260\224\352\276\270\352\270\260.md" | 98 +++++++++++++++++-- 1 file changed, 92 insertions(+), 6 deletions(-) diff --git "a/197_Caffe \353\252\250\353\215\270 Keras \353\252\250\353\215\270\353\241\234 \353\260\224\352\276\270\352\270\260.md" "b/197_Caffe \353\252\250\353\215\270 Keras \353\252\250\353\215\270\353\241\234 \353\260\224\352\276\270\352\270\260.md" index be4de39..a909812 100644 --- "a/197_Caffe \353\252\250\353\215\270 Keras \353\252\250\353\215\270\353\241\234 \353\260\224\352\276\270\352\270\260.md" +++ "b/197_Caffe \353\252\250\353\215\270 Keras \353\252\250\353\215\270\353\241\234 \353\260\224\352\276\270\352\270\260.md" @@ -11,6 +11,7 @@ * Pre-trained 모델 +

![197_0.jpg](./media/197_0.jpg) @@ -22,15 +23,13 @@ * 데이터를 충분히 구하는 것은 굉장히 어려운 일입니다. * 모델을 처음부터 학습시키는 것은 오래 걸리고, 소모적입니다. -However, I really can't get behind Caffe's heavy use of protobufs for network definition (code is data, after all). This lack of flexibility forces everybody to fork the codebase for minor details, like image preprocessing. And you get to write that in C++, of all things. - 그러나, Caffe가 너무 무겁기 때문에 계속 사용하기 어렵고, Caffe의 부족한 유연성 때문에 이미지 처리와 같은 사소한 세부 사항들을 위해 모든 사람들이 코드 베이스에 포크할 수 밖에 없습니다. 그리고 여러분은 C++와 같은 언어를 사용할 수 밖에 없겠죠. 나는 TensorFlow와 그와 비슷한 친구들의 접근을 훨씬 더 선호하는데, 이러한 프레임워크들은 Python 함수의 힘을 빌려 계산 그래프를 작성할 수 있습니다. 이러한 유연성은 프레임워크 코드 밖에서 스크립트 언어로 작성되었을 때 재사용 가능한 사전 처리 단계로 확장됩니다. 나는 보통 케라스로 일하는 것을 즐깁니다. 왜냐하면 그것은 쉬운 일을 쉽게, 힘든 일을 가능하게 하기 때문입니다. -In this post I will go through the process of converting a pre-trained Caffe network to a Keras model that can be used for inference and fine tuning on different datasets. You can see the end result here: Keras DilatedNet. I will assume knowledge of Python and Keras. +이 포스트에서는 pre-trianed Caffe 네트워크를 다른 데이터 셋 대한 학습 및 파인 튜닝에 사용할 수 있는 Keras 모델로 전환하는 과정을 살펴볼 것입니다. 최종 결과(코드)는 여기서 확인하세요 : [Keras DilatedNet](https://github.com/nicolov/segmentation_keras). Python과 Keras로 만들어져 있습니다. -이 포스트에서는 pre-trianed Caffe 네트워크를 다른 데이터 셋 대한 학습 및 정밀한 튜닝에 사용할 수 있는 Keras 모델로 전환하는 과정을 살펴볼 것입니다. 최종 결과(코드)는 여기서 확인하세요 : [Keras DilatedNet](https://github.com/nicolov/segmentation_keras). Python과 Keras로 만들어져 있습니다. +
### Picking a model for image segmentation @@ -42,8 +41,95 @@ In this post I will go through the process of converting a pre-trained Caffe net * [**Semantic Segmentation**](https://arxiv.org/pdf/1411.4038.pdf)을 위한 Fully Convolutional Networks는 출력에 대해 fully connected layer를 가진 분류 네트워크와 유사합니다. -확장된 컨볼루션 덕분에 더 좋은 결과를 얻었고, 매우 깨끗한 Caffe 코드가 제공되기 때문에 두 번째로 말한 네트워크로 진행해보기로 했습니다. +*dilated 컨볼루션* 덕분에 더 좋은 결과를 얻었고, 매우 깨끗한 Caffe 코드가 제공되기 때문에 두 번째로 말한 네트워크로 진행해보기로 했습니다. + +
### Converting the weights -Caffe는 직렬화 된 프로토콜 버퍼인 * .caffemodel 파일에 가중치를 저장합니다. caffe-tensorflow를 사용하여 이들을 numpy에 쉽게 로드 할 수 있는 HD5 파일로 변환 할 것입니다. 스크립트는 .prototxt (네트워크 정의) 및 .caffemodel 파일을 변환하여 가중치 및 TensorFlow 그래프를 생성합니다. +Caffe는 직렬화 된 프로토콜 버퍼인 `* .caffemodel` 파일에 가중치를 저장합니다. [*caffe-tensorflow*](https://github.com/ethereon/caffe-tensorflow)를 사용하여 이들을 numpy에 쉽게 로드 할 수 있는 HD5 파일로 변환 할 것입니다. 스크립트는 `.prototxt`(네트워크 정의) 및 `.caffemodel` 파일을 변환하여 가중치 및 TensorFlow 그래프를 생성합니다. + +``` +python convert.py \ + --caffemodel=~/dilation/pretrained/dilation8_pascal_voc.caffemodel \ + --code-output-path=./pascal_voc_tf/dil8_net.py \ + --data-output-path=./pascal_voc_tf/ \ + ~/dilation/models/dilation8_pascal_voc_deploy.prototxt +``` + +가중치는 잘 변환되지만 네트워크는 그렇지 않습니다(몇 가지 중요한 세부 사항이 누락되어 있는 경우로는 작동하지 않을 것입니다). 어쨌든 우리는 Keras를 위해 그것을 직접 해볼 것입니다. + +
+ +### Converting the network definition + +이 단계는 네트워크 정의의 계층별로 암기한 것을 옮기는 작업이 될 것입니다. 나는 VGG16에 대한 Keras의 예와 그에 상응하는 Caffe의 정의를 사용하여 그 과정의 요령을 파악했습니다. + +예를 들어, 이렇게 생긴 Caffe .prototxt를: + +``` +layer { + name: "conv1_2" + type: "Convolution" + bottom: "conv1_1" + top: "conv1_2" + convolution_param { + num_output: 64 + kernel_size: 3 + } +} +layer { + name: "relu1_2" + type: "ReLU" + bottom: "conv1_2" + top: "conv1_2" +} + +``` + +이렇게 생긴 Keras로 동등하게 바꿀 수 있습니다: +> model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_2')) + +이 과정에서 몇 가지 염두해야 할 것이 있습니다: + +* Keras/Tensorflow는 이미지를 (행, 열, 채널) 순서로 저장하고, Caffe는 (채널, 행, 열) 순서로 저장한다는 것입니다. `caffe-tensorflow`는 가중치를 자동으로 수정하지만 사전 처리 단계도 필요합니다. +* Padding은 또 다른 까다로운 세부사항 입니다: 여러분은 중간 단계마다 덤프하여 각 단계에서 모양이 일치하는지 확인할 수 있습니다. +a +이제 정의는 끝났고, 우리는 HD5 파일로 부터 가중치를 로드하는 코드를 추가할 것입니다. 이것을 레이어 마다 쌓게해서 새로운 레이어를 문제없이 맨 위에 추가할 것입니다. + +``` +weights_data = np.load(weights_path).item() +model = get_model() + +for layer in model.layers: + if layer.name in weights_data.keys(): + layer_weights = weights_data[layer.name] + + layer.set_weights((layer_weights['weights'], + layer_weights['biases'])) +``` + +shape이 맞지 않을까봐 걱정하지 마세요, 그럴 경우에 Keras는 에러 메세지를 던져줄 것입니다. + +
+ +### Tips and tricks + +어떤 분류 문제와 마찬가지로, semantic 세그멘테이션은 정규화된 확률을 산출하기 위해 최상단에 Softmax 층이 필요합니다. 이 경우 네트워크에서 이미지의 각 픽셀에 대한 레이블을 생성해야하므로 픽셀 단위로 softmax가 필요합니다. Keras의 softmax 레이어는 4D 배열에서 작동하지 않으므로 미리 픽셀 데이터를 1D 벡터로 재구성해야합니다. Softmax는 마지막 축(채널)에 적용되므로 모양 일반적으로)은 분류하려는 클래스 수에 해당합니다. 다음 코드는 이 작업을 수행합니다. + +``` +curr_width, curr_height, curr_channels = model.layers[-1].output_shape[1:] +model.add(Reshape((curr_width*curr_height, curr_channels))) +model.add(Activation('softmax')) +model.add(Reshape((curr_width, curr_height, curr_channels))) +``` + +문제를 해결하는 동안 네트워크의 중간 레이어들을 확인하는 것이 좋습니다. 우리는 forward pass만 진행하기 때문에 Keras `Sequential` 모델의 일부를 잘라내어 중간 레이어를 볼 수 있습니다. Caffe의 Python wrapper의 경우 `Net` 객체의 `blob`속성을 볼 수 있습니다. + +> np.save(layer_name, net.blobs[layer_name].data) + +
+ +### Next up: training + +나의 [Github](https://github.com/nicolov/segmentation_keras)에 전체 코드를 올렸는데, 오리지널 논문과 샘플 이미지 몇 개를 사용하여 결과를 확인할 수 있습니다. 이제 추론이 작동하므로, 다음 단계는 학습 인프라를 설정하여 서로 다른 데이터셋의 pre-trained 네트워크를 파인 튜닝하는 것입니다. \ No newline at end of file From f115748d982698647761ff9862872834f9b40965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=A0=95=ED=98=84?= Date: Tue, 19 Feb 2019 11:36:31 +0900 Subject: [PATCH 3/3] #197 : add translator --- ...0\353\241\234 \353\260\224\352\276\270\352\270\260.md" | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git "a/197_Caffe \353\252\250\353\215\270 Keras \353\252\250\353\215\270\353\241\234 \353\260\224\352\276\270\352\270\260.md" "b/197_Caffe \353\252\250\353\215\270 Keras \353\252\250\353\215\270\353\241\234 \353\260\224\352\276\270\352\270\260.md" index a909812..440c876 100644 --- "a/197_Caffe \353\252\250\353\215\270 Keras \353\252\250\353\215\270\353\241\234 \353\260\224\352\276\270\352\270\260.md" +++ "b/197_Caffe \353\252\250\353\215\270 Keras \353\252\250\353\215\270\353\241\234 \353\260\224\352\276\270\352\270\260.md" @@ -132,4 +132,10 @@ model.add(Reshape((curr_width, curr_height, curr_channels))) ### Next up: training -나의 [Github](https://github.com/nicolov/segmentation_keras)에 전체 코드를 올렸는데, 오리지널 논문과 샘플 이미지 몇 개를 사용하여 결과를 확인할 수 있습니다. 이제 추론이 작동하므로, 다음 단계는 학습 인프라를 설정하여 서로 다른 데이터셋의 pre-trained 네트워크를 파인 튜닝하는 것입니다. \ No newline at end of file +나의 [Github](https://github.com/nicolov/segmentation_keras)에 전체 코드를 올렸는데, 오리지널 논문과 샘플 이미지 몇 개를 사용하여 결과를 확인할 수 있습니다. 이제 추론이 작동하므로, 다음 단계는 학습 인프라를 설정하여 서로 다른 데이터셋의 pre-trained 네트워크를 파인 튜닝하는 것입니다. + +
+ +> Translator: [박정현](https://github.com/parkjh688) +> +> Translator email : \ No newline at end of file