Buckets:
| import{s as _e,n as ze,o as Ne}from"../chunks/scheduler.36a0863c.js";import{S as Ve,i as Re,g as M,s as n,r as s,A as Qe,h as d,f as t,c as i,j as ke,u as o,x as u,k as Ye,y as xe,a,v as r,d as c,t as p,w as m}from"../chunks/index.9c13489a.js";import{C as y}from"../chunks/CodeBlock.05d8ec32.js";import{H as E,E as Ee}from"../chunks/EditOnGithub.e88f2b7b.js";function Fe(he){let w,S,F,P,J,L,j,ge='La parallelizzazione è emersa come strategia per allenare modelli sempre più grandi su hardware limitato e accelerarne la velocità di allenamento di diversi ordini di magnitudine. In Hugging Face, abbiamo creato la libreria <a href="https://huggingface.co/docs/accelerate" rel="nofollow">🤗 Accelerate</a> per aiutarti ad allenare in modo semplice un modello 🤗 Transformers su qualsiasi tipo di configurazione distribuita, sia che si tratti di più GPU su una sola macchina o di più GPU su più macchine. In questo tutorial, imparerai come personalizzare il training loop nativo di PyTorch per consentire l’addestramento in un ambiente distribuito.',K,T,q,f,$e="Inizia installando 🤗 Accelerate:",D,b,O,U,Ie='Poi importa e crea un oggetto <a href="https://huggingface.co/docs/accelerate/package_reference/accelerator#accelerate.Accelerator" rel="nofollow"><code>Accelerator</code></a>. <code>Accelerator</code> rileverà automaticamente il tuo setup distribuito e inizializzerà tutte le componenti necessarie per l’allenamento. Non dovrai allocare esplicitamente il tuo modello su un device.',ee,h,le,g,te,$,Ce='Il prossimo passo è quello di passare tutti gli oggetti rilevanti per l’allenamento al metodo <a href="https://huggingface.co/docs/accelerate/package_reference/accelerator#accelerate.Accelerator.prepare" rel="nofollow"><code>prepare</code></a>. Questo include i tuoi DataLoaders per l’allenamento e per la valutazione, un modello e un ottimizzatore:',ae,I,ne,C,ie,B,Be='Infine, sostituisci il tipico metodo <code>loss.backward()</code> nel tuo loop di allenamento con il metodo <a href="https://huggingface.co/docs/accelerate/package_reference/accelerator#accelerate.Accelerator.backward" rel="nofollow"><code>backward</code></a> di 🤗 Accelerate:',se,A,oe,Z,Ae="Come puoi vedere nel seguente codice, hai solo bisogno di aggiungere quattro righe in più di codice al tuo training loop per abilitare l’allenamento distribuito!",re,v,ce,W,pe,G,Ze="Una volta che hai aggiunto le righe di codice rilevanti, lancia il tuo allenamento in uno script o in un notebook come Colaboratory.",me,X,Me,k,ve="Se stai eseguendo il tuo allenamento da uno script, esegui il comando seguente per creare e salvare un file di configurazione:",de,Y,ue,_,We="Poi lancia il tuo allenamento con:",we,z,ye,N,Je,V,Ge="La libreria 🤗 Accelerate può anche essere utilizzata in un notebook se stai pianificando di utilizzare le TPU di Colaboratory. Inserisci tutto il codice legato all’allenamento in una funzione, e passala al <code>notebook_launcher</code>:",je,R,Te,Q,Xe='Per maggiori informazioni relative a 🤗 Accelerate e le sue numerose funzionalità, fai riferimento alla <a href="https://huggingface.co/docs/accelerate" rel="nofollow">documentazione</a>.',fe,x,be,H,Ue;return J=new E({props:{title:"Allenamento distribuito con 🤗 Accelerate",local:"allenamento-distribuito-con--accelerate",headingTag:"h1"}}),T=new E({props:{title:"Configurazione",local:"configurazione",headingTag:"h2"}}),b=new y({props:{code:"cGlwJTIwaW5zdGFsbCUyMGFjY2VsZXJhdGU=",highlighted:"pip install accelerate",wrap:!1}}),h=new y({props:{code:"ZnJvbSUyMGFjY2VsZXJhdGUlMjBpbXBvcnQlMjBBY2NlbGVyYXRvciUwQSUwQWFjY2VsZXJhdG9yJTIwJTNEJTIwQWNjZWxlcmF0b3IoKQ==",highlighted:`<span class="hljs-meta">>>> </span><span class="hljs-keyword">from</span> accelerate <span class="hljs-keyword">import</span> Accelerator | |
| <span class="hljs-meta">>>> </span>accelerator = Accelerator()`,wrap:!1}}),g=new E({props:{title:"Preparati ad accelerare",local:"preparati-ad-accelerare",headingTag:"h2"}}),I=new y({props:{code:"dHJhaW5fZGF0YWxvYWRlciUyQyUyMGV2YWxfZGF0YWxvYWRlciUyQyUyMG1vZGVsJTJDJTIwb3B0aW1pemVyJTIwJTNEJTIwYWNjZWxlcmF0b3IucHJlcGFyZSglMEElMjAlMjAlMjAlMjB0cmFpbl9kYXRhbG9hZGVyJTJDJTIwZXZhbF9kYXRhbG9hZGVyJTJDJTIwbW9kZWwlMkMlMjBvcHRpbWl6ZXIlMEEp",highlighted:`<span class="hljs-meta">>>> </span>train_dataloader, eval_dataloader, model, optimizer = accelerator.prepare( | |
| <span class="hljs-meta">... </span> train_dataloader, eval_dataloader, model, optimizer | |
| <span class="hljs-meta">... </span>)`,wrap:!1}}),C=new E({props:{title:"Backward",local:"backward",headingTag:"h2"}}),A=new y({props:{code:"Zm9yJTIwZXBvY2glMjBpbiUyMHJhbmdlKG51bV9lcG9jaHMpJTNBJTBBJTIwJTIwJTIwJTIwZm9yJTIwYmF0Y2glMjBpbiUyMHRyYWluX2RhdGFsb2FkZXIlM0ElMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBvdXRwdXRzJTIwJTNEJTIwbW9kZWwoKipiYXRjaCklMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBsb3NzJTIwJTNEJTIwb3V0cHV0cy5sb3NzJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwYWNjZWxlcmF0b3IuYmFja3dhcmQobG9zcyklMEElMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBvcHRpbWl6ZXIuc3RlcCgpJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwbHJfc2NoZWR1bGVyLnN0ZXAoKSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMG9wdGltaXplci56ZXJvX2dyYWQoKSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMHByb2dyZXNzX2Jhci51cGRhdGUoMSk=",highlighted:`<span class="hljs-meta">>>> </span><span class="hljs-keyword">for</span> epoch <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(num_epochs): | |
| <span class="hljs-meta">... </span> <span class="hljs-keyword">for</span> batch <span class="hljs-keyword">in</span> train_dataloader: | |
| <span class="hljs-meta">... </span> outputs = model(**batch) | |
| <span class="hljs-meta">... </span> loss = outputs.loss | |
| <span class="hljs-meta">... </span> accelerator.backward(loss) | |
| <span class="hljs-meta">... </span> optimizer.step() | |
| <span class="hljs-meta">... </span> lr_scheduler.step() | |
| <span class="hljs-meta">... </span> optimizer.zero_grad() | |
| <span class="hljs-meta">... </span> progress_bar.update(<span class="hljs-number">1</span>)`,wrap:!1}}),v=new y({props:{code:"JTJCJTIwZnJvbSUyMGFjY2VsZXJhdGUlMjBpbXBvcnQlMjBBY2NlbGVyYXRvciUwQSUyMCUyMGZyb20lMjB0cmFuc2Zvcm1lcnMlMjBpbXBvcnQlMjBBZGFtVyUyQyUyMEF1dG9Nb2RlbEZvclNlcXVlbmNlQ2xhc3NpZmljYXRpb24lMkMlMjBnZXRfc2NoZWR1bGVyJTBBJTBBJTJCJTIwYWNjZWxlcmF0b3IlMjAlM0QlMjBBY2NlbGVyYXRvcigpJTBBJTBBJTIwJTIwbW9kZWwlMjAlM0QlMjBBdXRvTW9kZWxGb3JTZXF1ZW5jZUNsYXNzaWZpY2F0aW9uLmZyb21fcHJldHJhaW5lZChjaGVja3BvaW50JTJDJTIwbnVtX2xhYmVscyUzRDIpJTBBJTIwJTIwb3B0aW1pemVyJTIwJTNEJTIwQWRhbVcobW9kZWwucGFyYW1ldGVycygpJTJDJTIwbHIlM0QzZS01KSUwQSUwQS0lMjBkZXZpY2UlMjAlM0QlMjB0b3JjaC5kZXZpY2UoJTIyY3VkYSUyMiklMjBpZiUyMHRvcmNoLmN1ZGEuaXNfYXZhaWxhYmxlKCklMjBlbHNlJTIwdG9yY2guZGV2aWNlKCUyMmNwdSUyMiklMEEtJTIwbW9kZWwudG8oZGV2aWNlKSUwQSUwQSUyQiUyMHRyYWluX2RhdGFsb2FkZXIlMkMlMjBldmFsX2RhdGFsb2FkZXIlMkMlMjBtb2RlbCUyQyUyMG9wdGltaXplciUyMCUzRCUyMGFjY2VsZXJhdG9yLnByZXBhcmUoJTBBJTJCJTIwJTIwJTIwJTIwJTIwdHJhaW5fZGF0YWxvYWRlciUyQyUyMGV2YWxfZGF0YWxvYWRlciUyQyUyMG1vZGVsJTJDJTIwb3B0aW1pemVyJTBBJTJCJTIwKSUwQSUwQSUyMCUyMG51bV9lcG9jaHMlMjAlM0QlMjAzJTBBJTIwJTIwbnVtX3RyYWluaW5nX3N0ZXBzJTIwJTNEJTIwbnVtX2Vwb2NocyUyMColMjBsZW4odHJhaW5fZGF0YWxvYWRlciklMEElMjAlMjBscl9zY2hlZHVsZXIlMjAlM0QlMjBnZXRfc2NoZWR1bGVyKCUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMmxpbmVhciUyMiUyQyUwQSUyMCUyMCUyMCUyMCUyMCUyMG9wdGltaXplciUzRG9wdGltaXplciUyQyUwQSUyMCUyMCUyMCUyMCUyMCUyMG51bV93YXJtdXBfc3RlcHMlM0QwJTJDJTBBJTIwJTIwJTIwJTIwJTIwJTIwbnVtX3RyYWluaW5nX3N0ZXBzJTNEbnVtX3RyYWluaW5nX3N0ZXBzJTBBJTIwJTIwKSUwQSUwQSUyMCUyMHByb2dyZXNzX2JhciUyMCUzRCUyMHRxZG0ocmFuZ2UobnVtX3RyYWluaW5nX3N0ZXBzKSklMEElMEElMjAlMjBtb2RlbC50cmFpbigpJTBBJTIwJTIwZm9yJTIwZXBvY2glMjBpbiUyMHJhbmdlKG51bV9lcG9jaHMpJTNBJTBBJTIwJTIwJTIwJTIwJTIwJTIwZm9yJTIwYmF0Y2glMjBpbiUyMHRyYWluX2RhdGFsb2FkZXIlM0ElMEEtJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwYmF0Y2glMjAlM0QlMjAlN0JrJTNBJTIwdi50byhkZXZpY2UpJTIwZm9yJTIwayUyQyUyMHYlMjBpbiUyMGJhdGNoLml0ZW1zKCklN0QlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBvdXRwdXRzJTIwJTNEJTIwbW9kZWwoKipiYXRjaCklMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBsb3NzJTIwJTNEJTIwb3V0cHV0cy5sb3NzJTBBLSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMGxvc3MuYmFja3dhcmQoKSUwQSUyQiUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMGFjY2VsZXJhdG9yLmJhY2t3YXJkKGxvc3MpJTBBJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwb3B0aW1pemVyLnN0ZXAoKSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMGxyX3NjaGVkdWxlci5zdGVwKCklMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBvcHRpbWl6ZXIuemVyb19ncmFkKCklMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBwcm9ncmVzc19iYXIudXBkYXRlKDEp",highlighted:`<span class="hljs-addition">+ from accelerate import Accelerator</span> | |
| from transformers import AdamW, AutoModelForSequenceClassification, get_scheduler | |
| <span class="hljs-addition">+ accelerator = Accelerator()</span> | |
| model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) | |
| optimizer = AdamW(model.parameters(), lr=3e-5) | |
| <span class="hljs-deletion">- device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")</span> | |
| <span class="hljs-deletion">- model.to(device)</span> | |
| <span class="hljs-addition">+ train_dataloader, eval_dataloader, model, optimizer = accelerator.prepare(</span> | |
| <span class="hljs-addition">+ train_dataloader, eval_dataloader, model, optimizer</span> | |
| <span class="hljs-addition">+ )</span> | |
| num_epochs = 3 | |
| num_training_steps = num_epochs * len(train_dataloader) | |
| lr_scheduler = get_scheduler( | |
| "linear", | |
| optimizer=optimizer, | |
| num_warmup_steps=0, | |
| num_training_steps=num_training_steps | |
| ) | |
| progress_bar = tqdm(range(num_training_steps)) | |
| model.train() | |
| for epoch in range(num_epochs): | |
| for batch in train_dataloader: | |
| <span class="hljs-deletion">- batch = {k: v.to(device) for k, v in batch.items()}</span> | |
| outputs = model(**batch) | |
| loss = outputs.loss | |
| <span class="hljs-deletion">- loss.backward()</span> | |
| <span class="hljs-addition">+ accelerator.backward(loss)</span> | |
| optimizer.step() | |
| lr_scheduler.step() | |
| optimizer.zero_grad() | |
| progress_bar.update(1)`,wrap:!1}}),W=new E({props:{title:"Allenamento",local:"allenamento",headingTag:"h2"}}),X=new E({props:{title:"Allenamento con uno script",local:"allenamento-con-uno-script",headingTag:"h3"}}),Y=new y({props:{code:"YWNjZWxlcmF0ZSUyMGNvbmZpZw==",highlighted:"accelerate config",wrap:!1}}),z=new y({props:{code:"YWNjZWxlcmF0ZSUyMGxhdW5jaCUyMHRyYWluLnB5",highlighted:"accelerate launch train.py",wrap:!1}}),N=new E({props:{title:"Allenamento con un notebook",local:"allenamento-con-un-notebook",headingTag:"h3"}}),R=new y({props:{code:"ZnJvbSUyMGFjY2VsZXJhdGUlMjBpbXBvcnQlMjBub3RlYm9va19sYXVuY2hlciUwQSUwQW5vdGVib29rX2xhdW5jaGVyKHRyYWluaW5nX2Z1bmN0aW9uKQ==",highlighted:`<span class="hljs-meta">>>> </span><span class="hljs-keyword">from</span> accelerate <span class="hljs-keyword">import</span> notebook_launcher | |
| <span class="hljs-meta">>>> </span>notebook_launcher(training_function)`,wrap:!1}}),x=new Ee({props:{source:"https://github.com/huggingface/transformers/blob/main/docs/source/it/accelerate.md"}}),{c(){w=M("meta"),S=n(),F=M("p"),P=n(),s(J.$$.fragment),L=n(),j=M("p"),j.innerHTML=ge,K=n(),s(T.$$.fragment),q=n(),f=M("p"),f.textContent=$e,D=n(),s(b.$$.fragment),O=n(),U=M("p"),U.innerHTML=Ie,ee=n(),s(h.$$.fragment),le=n(),s(g.$$.fragment),te=n(),$=M("p"),$.innerHTML=Ce,ae=n(),s(I.$$.fragment),ne=n(),s(C.$$.fragment),ie=n(),B=M("p"),B.innerHTML=Be,se=n(),s(A.$$.fragment),oe=n(),Z=M("p"),Z.textContent=Ae,re=n(),s(v.$$.fragment),ce=n(),s(W.$$.fragment),pe=n(),G=M("p"),G.textContent=Ze,me=n(),s(X.$$.fragment),Me=n(),k=M("p"),k.textContent=ve,de=n(),s(Y.$$.fragment),ue=n(),_=M("p"),_.textContent=We,we=n(),s(z.$$.fragment),ye=n(),s(N.$$.fragment),Je=n(),V=M("p"),V.innerHTML=Ge,je=n(),s(R.$$.fragment),Te=n(),Q=M("p"),Q.innerHTML=Xe,fe=n(),s(x.$$.fragment),be=n(),H=M("p"),this.h()},l(e){const l=Qe("svelte-u9bgzb",document.head);w=d(l,"META",{name:!0,content:!0}),l.forEach(t),S=i(e),F=d(e,"P",{}),ke(F).forEach(t),P=i(e),o(J.$$.fragment,e),L=i(e),j=d(e,"P",{"data-svelte-h":!0}),u(j)!=="svelte-17ajov5"&&(j.innerHTML=ge),K=i(e),o(T.$$.fragment,e),q=i(e),f=d(e,"P",{"data-svelte-h":!0}),u(f)!=="svelte-dexkcz"&&(f.textContent=$e),D=i(e),o(b.$$.fragment,e),O=i(e),U=d(e,"P",{"data-svelte-h":!0}),u(U)!=="svelte-72811u"&&(U.innerHTML=Ie),ee=i(e),o(h.$$.fragment,e),le=i(e),o(g.$$.fragment,e),te=i(e),$=d(e,"P",{"data-svelte-h":!0}),u($)!=="svelte-1uhe1gm"&&($.innerHTML=Ce),ae=i(e),o(I.$$.fragment,e),ne=i(e),o(C.$$.fragment,e),ie=i(e),B=d(e,"P",{"data-svelte-h":!0}),u(B)!=="svelte-1i670zk"&&(B.innerHTML=Be),se=i(e),o(A.$$.fragment,e),oe=i(e),Z=d(e,"P",{"data-svelte-h":!0}),u(Z)!=="svelte-op71ru"&&(Z.textContent=Ae),re=i(e),o(v.$$.fragment,e),ce=i(e),o(W.$$.fragment,e),pe=i(e),G=d(e,"P",{"data-svelte-h":!0}),u(G)!=="svelte-12qrazq"&&(G.textContent=Ze),me=i(e),o(X.$$.fragment,e),Me=i(e),k=d(e,"P",{"data-svelte-h":!0}),u(k)!=="svelte-11jl52e"&&(k.textContent=ve),de=i(e),o(Y.$$.fragment,e),ue=i(e),_=d(e,"P",{"data-svelte-h":!0}),u(_)!=="svelte-1hc8rs1"&&(_.textContent=We),we=i(e),o(z.$$.fragment,e),ye=i(e),o(N.$$.fragment,e),Je=i(e),V=d(e,"P",{"data-svelte-h":!0}),u(V)!=="svelte-zv3zg4"&&(V.innerHTML=Ge),je=i(e),o(R.$$.fragment,e),Te=i(e),Q=d(e,"P",{"data-svelte-h":!0}),u(Q)!=="svelte-1inqsdp"&&(Q.innerHTML=Xe),fe=i(e),o(x.$$.fragment,e),be=i(e),H=d(e,"P",{}),ke(H).forEach(t),this.h()},h(){Ye(w,"name","hf:doc:metadata"),Ye(w,"content",He)},m(e,l){xe(document.head,w),a(e,S,l),a(e,F,l),a(e,P,l),r(J,e,l),a(e,L,l),a(e,j,l),a(e,K,l),r(T,e,l),a(e,q,l),a(e,f,l),a(e,D,l),r(b,e,l),a(e,O,l),a(e,U,l),a(e,ee,l),r(h,e,l),a(e,le,l),r(g,e,l),a(e,te,l),a(e,$,l),a(e,ae,l),r(I,e,l),a(e,ne,l),r(C,e,l),a(e,ie,l),a(e,B,l),a(e,se,l),r(A,e,l),a(e,oe,l),a(e,Z,l),a(e,re,l),r(v,e,l),a(e,ce,l),r(W,e,l),a(e,pe,l),a(e,G,l),a(e,me,l),r(X,e,l),a(e,Me,l),a(e,k,l),a(e,de,l),r(Y,e,l),a(e,ue,l),a(e,_,l),a(e,we,l),r(z,e,l),a(e,ye,l),r(N,e,l),a(e,Je,l),a(e,V,l),a(e,je,l),r(R,e,l),a(e,Te,l),a(e,Q,l),a(e,fe,l),r(x,e,l),a(e,be,l),a(e,H,l),Ue=!0},p:ze,i(e){Ue||(c(J.$$.fragment,e),c(T.$$.fragment,e),c(b.$$.fragment,e),c(h.$$.fragment,e),c(g.$$.fragment,e),c(I.$$.fragment,e),c(C.$$.fragment,e),c(A.$$.fragment,e),c(v.$$.fragment,e),c(W.$$.fragment,e),c(X.$$.fragment,e),c(Y.$$.fragment,e),c(z.$$.fragment,e),c(N.$$.fragment,e),c(R.$$.fragment,e),c(x.$$.fragment,e),Ue=!0)},o(e){p(J.$$.fragment,e),p(T.$$.fragment,e),p(b.$$.fragment,e),p(h.$$.fragment,e),p(g.$$.fragment,e),p(I.$$.fragment,e),p(C.$$.fragment,e),p(A.$$.fragment,e),p(v.$$.fragment,e),p(W.$$.fragment,e),p(X.$$.fragment,e),p(Y.$$.fragment,e),p(z.$$.fragment,e),p(N.$$.fragment,e),p(R.$$.fragment,e),p(x.$$.fragment,e),Ue=!1},d(e){e&&(t(S),t(F),t(P),t(L),t(j),t(K),t(q),t(f),t(D),t(O),t(U),t(ee),t(le),t(te),t($),t(ae),t(ne),t(ie),t(B),t(se),t(oe),t(Z),t(re),t(ce),t(pe),t(G),t(me),t(Me),t(k),t(de),t(ue),t(_),t(we),t(ye),t(Je),t(V),t(je),t(Te),t(Q),t(fe),t(be),t(H)),t(w),m(J,e),m(T,e),m(b,e),m(h,e),m(g,e),m(I,e),m(C,e),m(A,e),m(v,e),m(W,e),m(X,e),m(Y,e),m(z,e),m(N,e),m(R,e),m(x,e)}}}const He='{"title":"Allenamento distribuito con 🤗 Accelerate","local":"allenamento-distribuito-con--accelerate","sections":[{"title":"Configurazione","local":"configurazione","sections":[],"depth":2},{"title":"Preparati ad accelerare","local":"preparati-ad-accelerare","sections":[],"depth":2},{"title":"Backward","local":"backward","sections":[],"depth":2},{"title":"Allenamento","local":"allenamento","sections":[{"title":"Allenamento con uno script","local":"allenamento-con-uno-script","sections":[],"depth":3},{"title":"Allenamento con un notebook","local":"allenamento-con-un-notebook","sections":[],"depth":3}],"depth":2}],"depth":1}';function Se(he){return Ne(()=>{new URLSearchParams(window.location.search).get("fw")}),[]}class De extends Ve{constructor(w){super(),Re(this,w,Se,Fe,_e,{})}}export{De as component}; | |
Xet Storage Details
- Size:
- 15.9 kB
- Xet hash:
- b1f3f0198acaa6234bd9a294852d529ff4043080eee7d3ca68d17c46173d0125
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.