From e101d68d8b338aaca4541ba055c83124c8289919 Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Tue, 11 Aug 2020 12:50:26 +0800 Subject: [PATCH] [Gluon] Add VAE demo (#18758) * add VAE demo * minor changes * change format to md * minor changes * add liscence * Update VAE.md * update vae demo * remove unnecessary files --- example/probability/VAE/VAE.md | 259 +++++++++++++++++++++++++++ example/probability/VAE/VAE_11_0.png | Bin 0 -> 9062 bytes example/probability/VAE/VAE_14_0.png | Bin 0 -> 15863 bytes 3 files changed, 259 insertions(+) create mode 100644 example/probability/VAE/VAE.md create mode 100644 example/probability/VAE/VAE_11_0.png create mode 100644 example/probability/VAE/VAE_14_0.png diff --git a/example/probability/VAE/VAE.md b/example/probability/VAE/VAE.md new file mode 100644 index 000000000000..a334d7012012 --- /dev/null +++ b/example/probability/VAE/VAE.md @@ -0,0 +1,259 @@ + + + + + + + + + + + + + + + + + + +# VAE with Gluon.probability + +In this example, we will demonstrate how you can implement a Variational Auto-encoder(VAE) with Gluon.probability and MXNet's latest NumPy API. + + +```{.python .input} +import numpy as np +import mxnet as mx +from mxnet import autograd, gluon, np, npx +from mxnet.gluon import nn +import mxnet.gluon.probability as mgp +import matplotlib.pyplot as plt + +# Switch numpy-compatible semantics on. +npx.set_np() + +# Set context for model context, here we choose to use GPU. +model_ctx = mx.gpu(0) +``` + +## Dataset + +We will use MNIST here for simplicity purpose. + + +```{.python .input} +def load_data(batch_size): + mnist_train = gluon.data.vision.MNIST(train=True) + mnist_test = gluon.data.vision.MNIST(train=False) + num_worker = 4 + transformer = gluon.data.vision.transforms.ToTensor() + return (gluon.data.DataLoader(mnist_train.transform_first(transformer), + batch_size, shuffle=True, + num_workers=num_worker), + gluon.data.DataLoader(mnist_test.transform_first(transformer), + batch_size, shuffle=False, + num_workers=num_worker)) + +``` + +## Model definition + + +```{.python .input} +class VAE(gluon.HybridBlock): + def __init__(self, n_hidden=256, n_latent=2, n_layers=1, n_output=784, act_type='relu', **kwargs): + r""" + n_hidden : number of hidden units in each layer + n_latent : dimension of the latent space + n_layers : number of layers in the encoder and decoder network + n_output : dimension of the observed data + """ + self.soft_zero = 1e-10 + self.n_latent = n_latent + self.output = None + self.mu = None + super(VAE, self).__init__(**kwargs) + self.encoder = nn.HybridSequential() + for _ in range(n_layers): + self.encoder.add(nn.Dense(n_hidden, activation=act_type)) + self.encoder.add(nn.Dense(n_latent*2, activation=None)) + self.decoder = nn.HybridSequential() + for _ in range(n_layers): + self.decoder.add(nn.Dense(n_hidden, activation=act_type)) + self.decoder.add(nn.Dense(n_output, activation='sigmoid')) + + def encode(self, x): + r""" + Given a batch of x, + return the encoder's output + """ + # [loc_1, ..., loc_n, log(scale_1), ..., log(scale_n)] + h = self.encoder(x) + + # Extract loc and log_scale from the encoder output. + loc_scale = np.split(h, 2, 1) + loc = loc_scale[0] + log_scale = loc_scale[1] + + # Convert log_scale back to scale. + scale = np.exp(log_scale) + + # Return a Normal object. + return mgp.Normal(loc, scale) + + def decode(self, z): + r""" + Given a batch of samples from z, + return the decoder's output + """ + return self.decoder(z) + + def forward(self, x): + r""" + Given a batch of data x, + return the negative of Evidence Lower-bound, + i.e. an objective to minimize. + """ + # prior p(z) + pz = mgp.Normal(0, 1) + + # posterior q(z|x) + qz_x = self.encode(x) + + # Sampling operation qz_x.sample() is automatically reparameterized. + z = qz_x.sample() + + # Reconstruction result + y = self.decode(z) + + # Gluon.probability can help you calculate the analytical kl-divergence + # between two distribution objects. + KL = mgp.kl_divergence(qz_x, pz).sum(1) + + # We assume p(x|z) ~ Bernoulli, therefore we compute the reconstruction + # loss with binary cross entropy. + logloss = np.sum(x * np.log(y + self.soft_zero) + (1 - x) + * np.log(1 - y + self.soft_zero), axis=1) + loss = -logloss + KL + return loss +``` + +## Training + + +```{.python .input} +def train(net, n_epoch, print_period, train_iter, test_iter): + net.initialize(mx.init.Xavier(), ctx=model_ctx) + net.hybridize() + trainer = gluon.Trainer(net.collect_params(), 'adam', + {'learning_rate': .001}) + training_loss = [] + validation_loss = [] + for epoch in range(n_epoch): + epoch_loss = 0 + epoch_val_loss = 0 + + n_batch_train = 0 + for batch in train_iter: + n_batch_train += 1 + data = batch[0].as_in_context(model_ctx).reshape(-1, 28 * 28) + with autograd.record(): + loss = net(data) + loss.backward() + trainer.step(data.shape[0]) + epoch_loss += np.mean(loss) + + n_batch_val = 0 + for batch in test_iter: + n_batch_val += 1 + data = batch[0].as_in_context(model_ctx).reshape(-1, 28 * 28) + loss = net(data) + epoch_val_loss += np.mean(loss) + + epoch_loss /= n_batch_train + epoch_val_loss /= n_batch_val + + training_loss.append(epoch_loss) + validation_loss.append(epoch_val_loss) + + if epoch % max(print_period, 1) == 0: + print('Epoch{}, Training loss {:.2f}, Validation loss {:.2f}'.format( + epoch, float(epoch_loss), float(epoch_val_loss))) +``` + + +```{.python .input} +n_hidden = 128 +n_latent = 40 +n_layers = 3 +n_output = 784 +batch_size = 128 +model_prefix = 'vae_gluon_{}d{}l{}h.params'.format( + n_latent, n_layers, n_hidden) +net = VAE(n_hidden=n_hidden, n_latent=n_latent, n_layers=n_layers, + n_output=n_output) +net.hybridize() +n_epoch = 50 +print_period = n_epoch // 10 +train_set, test_set = load_data(batch_size) +train(net, n_epoch, print_period, train_set, test_set) +``` + + +## Reconstruction visualiztion + +To verify the effictiveness of our model, we first take a look at how well our model can reconstruct the data. + + +```{.python .input} +# Grab a batch from the test set +qz_x = None +for batch in test_set: + data = batch[0].as_in_context(model_ctx).reshape(-1, 28 * 28) + qz_x = net.encode(data) + break +``` + + +```{.python .input} +num_samples = 4 +fig, axes = plt.subplots(nrows=num_samples, ncols=2, figsize=(4, 6), subplot_kw={'xticks': [], 'yticks': []}) +axes[0, 0].set_title('Original image') +axes[0, 1].set_title('reconstruction') +for i in range(num_samples): + axes[i, 0].imshow(data[i].squeeze().reshape(28, 28).asnumpy(), cmap='gray') + axes[i, 1].imshow(net.decode(qz_x.sample())[i].reshape(28, 28).asnumpy(), cmap='gray') +``` + + +![png](./VAE_11_0.png) + + +## Sample generation + +One of the most important difference between Variational Auto-encoder and Auto-encoder is VAE's capabilities of generating new samples. + +To achieve that, one simply needs to feed a random sample from $p(z) \sim \mathcal{N}(0,1)$ to the decoder network. + + +```{.python .input} +def plot_samples(samples, h=5, w=10): + fig, axes = plt.subplots(nrows=h, + ncols=w, + figsize=(int(1.4 * w), int(1.4 * h)), + subplot_kw={'xticks': [], 'yticks': []}) + for i, ax in enumerate(axes.flatten()): + ax.imshow(samples[i], cmap='gray') +``` + + +```{.python .input} +n_samples = 20 +noise = np.random.randn(n_samples, n_latent).as_in_context(model_ctx) +dec_output = net.decode(noise).reshape(-1, 28, 28).asnumpy() +plot_samples(dec_output, 4, 5) +``` + + +![png](./VAE_14_0.png) + diff --git a/example/probability/VAE/VAE_11_0.png b/example/probability/VAE/VAE_11_0.png new file mode 100644 index 0000000000000000000000000000000000000000..455f09e27d3faef02de9fbc0fcc66132ec81c759 GIT binary patch literal 9062 zcmbVydpwhW|Nk{}2@ zU=02o1^|f57GCf-gQ^wq0l@8h{*vhy@GE%Bt;gVFelL9sUjPsk=6plC21D1ui)a0G z&HYR~o&3;tK8}F9ou8MRr=Qzx`vWLPAK%-a9*S@UxZ?2xE`EMqs`B#x|L<^5A7^?(br=ZG)?GWe?`OUW-z|1s;p?kc#iMV+ZEj}S zpA%_CNbbG55EXvc=FIOaryCn}?nQ_SK8EN%K6JSlC#oykg;61Db#%~V9t_bcN@WS<% zX4(#IM;+Q6$e|u81hG91)d_Qbu8m3fl6g(z@;wf!dmWVaIovUwVm_Nt%~Tk-9}dbC ze77@TXXTNItmXJB-{g~x7qlymMrdxYlaJGAOv)#j7>PQLJyLCF5V=`$5m~)*4$LF6 ziqO3dg?yoWk=)M#D9(T+>Tq>N*xE!fMNPH};nMW(3!^tY>s7s$wu7zWTzANbP?#C% zWjJ;SQVXc-rXFO=?ZmWT+B*h_j<@7&Mb28j@k5#pxuDM_&; zDmxWcGwRtJ(zd6*oSHWutVg@Jk0jM@FN4fN7yw0NsEM!6A>_!Mg*}^w&U31ENMBuX zB;BpYbn-=WrE@d5D8dw?_mDeeCTyOBCQXnWsY-PH{oO->XXwd?f_xIOAq3^zc>PIOl4hQ%G{>x8yz&MYBTewVHPY(kGBU4OZ&B$qQYDD9 zaWsdZp@}=N$+OahbK4>QILRX{#eLH0SgtRJ=huR`hPXbpuC0ag)C%rT>SM6U?3&=; zI#v)Z?g$)jef(5Kc&FdV`Iw&O@QG;damWz#>d4u0;5l>}Cn(bNtG1qaGoWc$a5%Pp zK22aCF@PpcYSrGTSD1vJHb6Y7bzcN`Kd=I4Lqw;It3ka>w9 zLF*mDZfSLh-2%)g0v5p*K1(jJSP~R68OZv z5bpejwlV_OcMXSM2;Av)@wvOzmbQKwC6UTLHQtKAm<{EV3P$fmlORjSXZmJ*3$W(K zFE9DF$v}D&7RcQN>laBa4G0k1;5=owJVC+yXdf(zTB!}PFpN3;J?j~lx8;GZ}!oMhXFC@ zON+mY!sUvJ4v($A2+wjsi0Yy*8u{&>4;(!?;_HefUhcQSod_pRV~PpZRXHJWcjgXk z?s#L;Me72qjQry-Z;*~gC;@0LtU_a|ePq64 zxjVh}K07&FMGr@8t$5nZ3>DY?igIZCO4>p%F3}wNL;_*R0BB6Q(U_#@Q#O?RoX72S zM1-I)6C;~1Hmfkq>u@!rUK3s3lv6gNXH=G2 zc{{jBA-7N=S7y$4Skf^hx8zyio&tOd_Qv#$b`?z!I@A%@jNDx^H_TuU$A{_N+XhIXokjEprKKCg0v z8jm@15K4EkAy7xJbM1XvBA6=fdgm&KI8C4|R>o9+s3J zVJT4bgQ@CKm3su{**`2All&W#v=U3AS|6)D{?7GC1hJo)oGvqK6!Ls^cin}7FzCF> zpnGG|a%0lIF1Ho+k;RWi;YIg`By_(%^9jy1j-NgsOxWYFR~W5`#%H-)>Og14nJst9 zke`+oXEr8vM=C6fOvDgnW6o@%sIKVnQ`4%JuvtMbSd0`XAj=`z%5V_v>Iwd)GT2{}# z`J2A}gU|l^1=A!!OMR;9FmBW{C{5KLaG};#;b*9IYGa-_p?ylCcr)>qzsXUwj6dkR zg>%({V6(kg4{x0dC=(PPJaiZj+n zWq_^wl-e5l2~o}wHUzh1e0#Ep{EUMCl&Ls#soM}@UVbMYKhw9f)0bu_HBP^0mVMF3 z=q6<=wbVHVPo{q>M7}(s@?;-pBW3}XA0yhtN&@EX5winTzE#$xw@qrb+hsC><0dHy zE)5Z4K%|65e}hwJI`YZ24zOUJWW!dhBW$ADf12w{9R@94v(O?3Im=r8i7c@D6mU>V zi`i4KN4cIcdkrp8?s%oPqou#RSvS`$p&Sc6?J>|7U*R!m=|*8xvCuQcO(SN7Ljgad z?2Fp3H#S-9xh{3UO#2D$F6v`nv^XwZ1H<*s_5+u=+R_&t$l0k^*;cgsA_jmh2?v1_ zf&*(WW)DGPqp@kXm#4k~Wv;!2eT(bc?g}WKdm}_SSK{*ZkT_;Ij1LG{Y*$9MrQa#@ z9HKS^E&YOMrzp8wwJF`MLCsjw>egMO2x|ggaxT?+b$6txAq$MMFE&t%%-#g>o@3TQ zlGM=f*!~Ys1vwStX~(fHy|W=m8>E^a|6X9B2m~!pjoB0S)z}b28`9~egPpOoafV_c zta!dbJh{N$s*c=N>`qYI5KY9um9>~#pCmDpJZ+QTUYTY@5T&P`vbMh-)}ZZTdZd4$heG&rP=p7Z zMX!HwBt^IkR+r1g>`~;^pXqu(U08z~mCw14xG|w$?frt$1(lNbT!Se}2G2o&6lKqj z{!pjOf132#Or&SqwuhrGTPXR^{Oq$ibA8?6;0hfLG;c;q3S;S$h|?p#7nc?)?06^`6*U#Uc(WQW_ame zu?KZpp4PV0XTBW39t0s6lV!CEVICdaR8&>b1};18okpW`wLS_uBB;wmg%CCv30SAAj*r z+3&&)Z|n>e=~go$ss(Uvk72}14ZtmD-fhJt+JveAFg4V1Mqk`0<6}up^)aMZ6KlY~Rz3OnfzT>;r@HD@!OK{Za6Fsixn~?x( zxd;n+hnnf%KZ_hQ<^@}S;M8#DxqDXRjK|+f4kH)rKIqCyVviTWzL}buj@sWOxIv72 zz2EIQnIZlC?NLt8H}CMVw2P|mM2G*Fh@twUVQ{>-Jg+T-Muv~e z=USQ_<+Sge^60L|#{zXcj<|uqu21!IZNi?nj`8Rcsyg&wlVRLWpF=>el$NTQ8RQ*} zuzWxbcl+WEH*0LF`Y3k&!l^vzSO4yk{yVE|`lttaIbVdTURs(wn0*MYWx+wqcRrJh zw5fwXe-`{t)@yT79)&X-LdpZfEg(WdGo3rr;V6)G#4zoB#SX~8@wQ|@eQoq!w!}e+@+UNfF2wqP8 z7J}~lcFqXdrJwPG@d&BqH8=bLPH-ca2)LJ~zFzKGn#@hDII&x8SzQY838w1z3SaIq zxEJR!SY2iQXd4W8W%eckzcw^9)|v?QV$M|5^xfwd0s08;H~V{Uh3Dpq%U<9B!5C5| z(j9ev@>=HuLGkK^oJ&uEv#Z1RkhHRH17F7)?uE6947&Xa730}}zH!+xC5YwIbM5(Q z$grN)?a^=rUu?6F2?2+)F!=Xm9yEWt(VbemM<40GJcu6hcf`ceGghz6t~NC| z$zrYos{T{lIZmbW#C2i)b}L4l&O}EVvcRI$sj$|y7k(hH>Ld1=rlUs2pCdkYO{5H2 zgVLTlbC|MJCNl}hAqtOs?*r99otz}9&#plNyZj9ySDR77p6bc}*+OXkrK~*T&01gV zM7n|O0~A=-^*6Y6FAVs0`YW*eU${>ZZg=OJx3R6qOngl_^HkVr^`$Y^J4o4__ah?n!<`r zsdJ~q0b)tI;U5rM$mPF79{PmEJlgN0-`_NZq1Qbl9;sLl`!W=~C=?qM(rLX| z+Ut9ee5>GQMIpZ2ow5rj$zE-Oe}83k7(uP}my6xMhvyx57M{(F?b|#|aA-pBJG)O- zYlStlT*i7<1(xM4@t##b)y-BX>0vR*nc{ zjwW_Bu$zK)L{^2PB0{(`Laq@g9<5}} zOKapOvY~|1^(5H7;Hmt)>Li%S6nc1l7ESaWYru;;qn&-V{}fChi~ml_VF1dvjoaAM zyBOUB(!(HpJmz)mdNG=AePH8^7JHVFu|abN_6PlX(U7j}NmUoejD*WXxYxvP!p@F8 zUIUfhg{dCaiFxTk0{R9dxwV%C-bswOPlnjvCgLEko{jDAT4PW=!$v>L;7;5m+;Z2_ zxensuCMeZ<-0hd$5~Dix%0A{=n(DXsjdDPWNUr(0@%6Y&suvfa#a`<~wi(#C&@=f0 zX3Bd3Q27+%9jBGD{m}G@EEByyH?vU4Kegf$z4wfOzSf60t+1HFHL-1Kc5%e$rg(%k zzqXOl6Fm7G1?6qVfpyW()Ok=3ur3%RxKnS84=!-S@BZ5*DSS;(m*3kO{8N$JrR5^^x{H=dwhH`&2^p9$7!M)X1ceC&lVgo zc*0Edo z{J2xhqYbLIPkQoG1J&jRw;Sa!c>n}Nz!>q(vdm>?Y+ax;=df)GnBnJ{k|9f9Ly6-c zuJIWg{+c-yJ(22baD&lW80gihv2x21V`kR=d>+vuIe04t%bLU?b*MHj-;}m*Ff}*I z57I0bS#gdG%MACf^CkIH^m`f_^Tfk^FuxtKLGEAPOW#bx{oRDrlXiFIDB*i z{kwD7Apv`J#+#vLOv}n(Ebx)k=(SL(o651YFRi=&H0G38-M5dsO>VE;836UZHhH>E zGIaHaHW_v-MvGM`N6|ePf?CJ};eEE#Bf-f)R5zqG)ROh)vo}NUW1qoJcC}SgGz{`< zu%-epwD9c67VRbhTDL*R!>UFMsb!#90G!&Ae%LcaKf*J3-`#4CvoAVf z*K_4BbCFrwfiuIMvTdgLI;I@l=nzS1Sf?d>Xzn4pDduD#XY_Xy4>vfS#@1i0PVrpH z_5kNj^bp68EX=BAnr;tW?AUf^g|8x!5bJCqa69?bpPS=!jWc7L=7l3E{_R4Eg0Pd& zyVHV{{0P|4dE)yB;w8QFHM0nUMVN7mRw2Eg9Up z7wwyWO0%N{7k{OKZn}Msq%&vB|FI3ug|6Q?W5*s4e?i>>*QrC(sRx**n>~81%d0*b zs{@!qG`i|p(n4MS_bQDqAoyRdB<)3kNLCajW zphSiO#kkwz=F;;HibgK;IZM^v7fXoQ|LG?TJDi_QUNFLHt zL(M&R&{Fuz)!ST(Rys1Yh8h<9xg%e4R*!GT4c4I1j+iVKc(6HZAHo()aHM)w;Nmz? zU_+!f(9FLCbDq3eZO+m^qm-)`x?axbn4xm+iz*TMEs3Ea205f3!CE9 z>=+a^J3x+SGG?Y*GD3gL#;OWm6hMH6-)e2{({{9@8gGvT{e0#>OTXq10_{#-RFQR^ zY7^#AeDk(yUeGq&+jK#ITYs7C1oN3J=PpV_ZR`<~P8@1j zZ{1Pq)XuelUBdrE!mlrg_<>Fsu<~g>0%v^SldN0-8PMmwVO)r=t}d`2J>U&@(jx-u z^YtQN86!3o^5t8k5BK<>%@iX5^sv8LSVcLayV&CtP-O4Lar7VM$d!c366|4*7ymHF zv9H`33!e{%_1rYH4*2oldd*=A(;{mPgeGVzA${epiTE{FjA+-g)|EdD0dj6XDB=(j zr(Jdc_+2M_6xxH4XO?K>?)a3`x4CjUf|0*A?SAIncAU6PaIqYi3hc%8T4PRpq3RRJ zHPoV-Syk~j$QmV}JI@eZ>_7c|4AoR}^4bs(BD%5U-|10!1Nnnn1 zI{KOyJ6w)LwPo;NetdkOZFf!0d~;F+;L!BI@nr2O{+cxQ7{^?KLjnWY)^BXr2}>aV z%2mVXr};m##bOwb{>%pGWqL9;0zStcY>=ox6UBeOdOX#U;nv(=8(1pWnWDTM2i>MW zE<_B!ladP(w>>@Pc$sm1pgMpp@457>+{Hk%9TZ?7>>Bf@Z?RIlj+bDOZ9t%-%H zbc;^TWNjYj+^os|-6m((G*`w!l&GNPjS;UmRcWi5ZUV(2h}Z?0NK>1@)a8=%e@gm4 z0!B-tKj{pq>$qFqv16JTuOD5T)}!j9&esc4zIX2a^-rGv4p$ue^3OBORz0?~3tGND zV!}`<89t!rJb7la4)a;Bh@9zZV2%3icf>F z96$suB(eZ}3>>$4KhTgK`ujE_6qMW$b7E*6evDa`!r@8IKeJ5VUHbyM!oTvmob>yf zi1&BnES_Q7o{m`Cj4z%D% zssrVdr_i%j05z03<3`Ie)qW~{4cM(`_-P$ zd*Ap+r_SEzq$08XsmJ9hOF&<3pki#$M-M%dw&!PB8`g92rf|09pcujmk`wJw0`_FA z1&lcOY@6ebzzOyZ0tnWJ?V*4+h&omUV6g#p5W3(Da89}A=vX$T;e6CHBk;YB(ob=2 zkKQuGq^{t4o{n`Hq=J&f4w0@NSRzN6$1!e64u8Mtd4dtdyrPbx^=%Bg%gRt%&i=SB zV&w(~A3#qblEO)#K%s=B6*oyhjZ3XTk%9~yYl#P}{J!df=-YMLy}ze{wUnm?ITt3Qq5i8|PJ$o=yk8x``_w%Wov^t$HCUqzH0}2V?Un;EgozSQ(F{=q zO!5r;i$O31@-15ADNjxjH)cGMG!k?>cidt#00zLj^oSZL#mKOB5=wi^Vo4KUKrE66cYWUBAO3-NtOp_+$fbFBvNV0C-u@rI_6AXeauoVlcozFO*`2lK z_H<|)2|gL#+d9Rmu4*K+O=C z)wLLBIP2N3qD`4FXk0SLqg5q!*V;Pu8P$Ubn-H@p6lke>e=n~3O@9~Chef*U{a8&? z$-uHy0Pw{TcyRJfbzXDAShDo1w5}a-Pu1cZ3@|GlYIM^UO)~`Rz8>m^EAf)cqm(rT z%wUJ7M}G(`fH|AcoGe@Lk97~>_eUJmf)OG4DlHa}TwqY} zF6Cej(;y-5>i*d8*rKt%Kf(LwMFgQDVa=kYt0D7^wB=l+4ez;5pHQX{6wAqz)jk?fmr3o5znrO)cMI_05Y5&g9I zekItWt$Rl7QE7Zw(Wp9Xr=**E%F9@{px<<7dNgruJO$adZK;EA(;u~SrJ=^Mk`Kp5<0LmZt2ZRvN-~n@A zbhewhs2O`R5)P~F<%w(Wf+MRdldya>jw#Ws{JTV@dO`VGK&p2UH~QA`1@Fy7U5?tR zoxCsGE}NG+(n46Qmn^rJAusDSt;$THBAszJ@jd(|Txu$CDRJ@=I7&D1>*0YjB|kUi zS3*VfJ?dt7YfhY-u-_BKah6- literal 0 HcmV?d00001 diff --git a/example/probability/VAE/VAE_14_0.png b/example/probability/VAE/VAE_14_0.png new file mode 100644 index 0000000000000000000000000000000000000000..d26173bb56aebfd2bca129c3c88eab7d87eff338 GIT binary patch literal 15863 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%0ADjCmTR<|&A? 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 literal 0 HcmV?d00001