Buckets:

rtrm's picture
download
raw
15.8 kB
import{s as _e,n as Ee,o as Ne}from"../chunks/scheduler.36a0863c.js";import{S as Ve,i as Re,g as M,s as n,r,A as xe,h as d,f as a,c as s,j as ke,u as o,x as y,k as Ye,y as Qe,a as l,v as i,d as c,t as p,w as m}from"../chunks/index.f891bdb2.js";import{C as u}from"../chunks/CodeBlock.3ec784ea.js";import{H as z,E as ze}from"../chunks/EditOnGithub.a58e27a9.js";function Fe(he){let w,S,F,P,J,K,j,$e='El paralelismo ha emergido como una estrategia para entrenar modelos grandes en hardware limitado e incrementar la velocidad de entrenamiento en varios órdenes de magnitud. En Hugging Face creamos la biblioteca <a href="https://huggingface.co/docs/accelerate" rel="nofollow">🤗 Accelerate</a> para ayudar a los usuarios a entrenar modelos 🤗 Transformers en cualquier tipo de configuración distribuida, ya sea en una máquina con múltiples GPUs o en múltiples GPUs distribuidas entre muchas máquinas. En este tutorial aprenderás cómo personalizar tu bucle de entrenamiento de PyTorch nativo para poder entrenar en entornos distribuidos.',L,T,q,f,ge="Empecemos por instalar 🤗 Accelerate:",D,b,O,U,Ie='Luego, importamos y creamos un objeto <a href="https://huggingface.co/docs/accelerate/package_reference/accelerator#accelerate.Accelerator" rel="nofollow"><code>Accelerator</code></a>. <code>Accelerator</code> detectará automáticamente el tipo de configuración distribuida que tengas disponible e inicializará todos los componentes necesarios para el entrenamiento. No necesitas especificar el dispositivo en donde se debe colocar tu modelo.',ee,h,te,$,ae,g,Ce='Pasa todos los objetos relevantes para el entrenamiento al método <a href="https://huggingface.co/docs/accelerate/package_reference/accelerator#accelerate.Accelerator.prepare" rel="nofollow"><code>prepare</code></a>. Esto incluye los DataLoaders de entrenamiento y evaluación, un modelo y un optimizador:',le,I,ne,C,se,B,Be='Por último, reemplaza el típico <code>loss.backward()</code> en tu bucle de entrenamiento con el método <a href="https://huggingface.co/docs/accelerate/package_reference/accelerator#accelerate.Accelerator.backward" rel="nofollow"><code>backward</code></a> de 🤗 Accelerate:',re,Z,oe,A,Ze="Como se puede ver en el siguiente código, ¡solo necesitas adicionar cuatro líneas de código a tu bucle de entrenamiento para habilitar el entrenamiento distribuido!",ie,W,ce,G,pe,X,Ae="Una vez que hayas añadido las líneas de código relevantes, inicia el entrenamiento desde un script o notebook como Colaboratory.",me,v,Me,k,We="Si estás corriendo tu entrenamiento desde un script ejecuta el siguiente comando para crear y guardar un archivo de configuración:",de,Y,ye,_,Ge="Comienza el entrenamiento con:",we,E,ue,N,Je,V,Xe="🤗 Accelerate puede correr en un notebook si, por ejemplo, estás planeando utilizar las TPUs de Colaboratory. Encierra el código responsable del entrenamiento en una función y pásalo a <code>notebook_launcher</code>:",je,R,Te,x,ve='Para obtener más información sobre 🤗 Accelerate y sus numerosas funciones, consulta la <a href="https://huggingface.co/docs/accelerate" rel="nofollow">documentación</a>.',fe,Q,be,H,Ue;return J=new z({props:{title:"Entrenamiento distribuido con 🤗 Accelerate",local:"entrenamiento-distribuido-con--accelerate",headingTag:"h1"}}),T=new z({props:{title:"Configuración",local:"configuración",headingTag:"h2"}}),b=new u({props:{code:"cGlwJTIwaW5zdGFsbCUyMGFjY2VsZXJhdGU=",highlighted:"pip install accelerate",wrap:!1}}),h=new u({props:{code:"ZnJvbSUyMGFjY2VsZXJhdGUlMjBpbXBvcnQlMjBBY2NlbGVyYXRvciUwQSUwQWFjY2VsZXJhdG9yJTIwJTNEJTIwQWNjZWxlcmF0b3IoKQ==",highlighted:`<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">from</span> accelerate <span class="hljs-keyword">import</span> Accelerator
<span class="hljs-meta">&gt;&gt;&gt; </span>accelerator = Accelerator()`,wrap:!1}}),$=new z({props:{title:"Prepárate para acelerar",local:"prepárate-para-acelerar",headingTag:"h2"}}),I=new u({props:{code:"dHJhaW5fZGF0YWxvYWRlciUyQyUyMGV2YWxfZGF0YWxvYWRlciUyQyUyMG1vZGVsJTJDJTIwb3B0aW1pemVyJTIwJTNEJTIwYWNjZWxlcmF0b3IucHJlcGFyZSglMEElMjAlMjAlMjAlMjB0cmFpbl9kYXRhbG9hZGVyJTJDJTIwZXZhbF9kYXRhbG9hZGVyJTJDJTIwbW9kZWwlMkMlMjBvcHRpbWl6ZXIlMEEp",highlighted:`<span class="hljs-meta">&gt;&gt;&gt; </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 z({props:{title:"Backward",local:"backward",headingTag:"h2"}}),Z=new u({props:{code:"Zm9yJTIwZXBvY2glMjBpbiUyMHJhbmdlKG51bV9lcG9jaHMpJTNBJTBBJTIwJTIwJTIwJTIwZm9yJTIwYmF0Y2glMjBpbiUyMHRyYWluX2RhdGFsb2FkZXIlM0ElMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBvdXRwdXRzJTIwJTNEJTIwbW9kZWwoKipiYXRjaCklMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBsb3NzJTIwJTNEJTIwb3V0cHV0cy5sb3NzJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwYWNjZWxlcmF0b3IuYmFja3dhcmQobG9zcyklMEElMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBvcHRpbWl6ZXIuc3RlcCgpJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwbHJfc2NoZWR1bGVyLnN0ZXAoKSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMG9wdGltaXplci56ZXJvX2dyYWQoKSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMHByb2dyZXNzX2Jhci51cGRhdGUoMSk=",highlighted:`<span class="hljs-meta">&gt;&gt;&gt; </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}}),W=new u({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(&quot;cuda&quot;) if torch.cuda.is_available() else torch.device(&quot;cpu&quot;)</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(
&quot;linear&quot;,
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}}),G=new z({props:{title:"Entrenamiento",local:"entrenamiento",headingTag:"h2"}}),v=new z({props:{title:"Entrenar con un script",local:"entrenar-con-un-script",headingTag:"h3"}}),Y=new u({props:{code:"YWNjZWxlcmF0ZSUyMGNvbmZpZw==",highlighted:"accelerate config",wrap:!1}}),E=new u({props:{code:"YWNjZWxlcmF0ZSUyMGxhdW5jaCUyMHRyYWluLnB5",highlighted:"accelerate launch train.py",wrap:!1}}),N=new z({props:{title:"Entrenar con un notebook",local:"entrenar-con-un-notebook",headingTag:"h3"}}),R=new u({props:{code:"ZnJvbSUyMGFjY2VsZXJhdGUlMjBpbXBvcnQlMjBub3RlYm9va19sYXVuY2hlciUwQSUwQW5vdGVib29rX2xhdW5jaGVyKHRyYWluaW5nX2Z1bmN0aW9uKQ==",highlighted:`<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">from</span> accelerate <span class="hljs-keyword">import</span> notebook_launcher
<span class="hljs-meta">&gt;&gt;&gt; </span>notebook_launcher(training_function)`,wrap:!1}}),Q=new ze({props:{source:"https://github.com/huggingface/transformers/blob/main/docs/source/es/accelerate.md"}}),{c(){w=M("meta"),S=n(),F=M("p"),P=n(),r(J.$$.fragment),K=n(),j=M("p"),j.innerHTML=$e,L=n(),r(T.$$.fragment),q=n(),f=M("p"),f.textContent=ge,D=n(),r(b.$$.fragment),O=n(),U=M("p"),U.innerHTML=Ie,ee=n(),r(h.$$.fragment),te=n(),r($.$$.fragment),ae=n(),g=M("p"),g.innerHTML=Ce,le=n(),r(I.$$.fragment),ne=n(),r(C.$$.fragment),se=n(),B=M("p"),B.innerHTML=Be,re=n(),r(Z.$$.fragment),oe=n(),A=M("p"),A.textContent=Ze,ie=n(),r(W.$$.fragment),ce=n(),r(G.$$.fragment),pe=n(),X=M("p"),X.textContent=Ae,me=n(),r(v.$$.fragment),Me=n(),k=M("p"),k.textContent=We,de=n(),r(Y.$$.fragment),ye=n(),_=M("p"),_.textContent=Ge,we=n(),r(E.$$.fragment),ue=n(),r(N.$$.fragment),Je=n(),V=M("p"),V.innerHTML=Xe,je=n(),r(R.$$.fragment),Te=n(),x=M("p"),x.innerHTML=ve,fe=n(),r(Q.$$.fragment),be=n(),H=M("p"),this.h()},l(e){const t=xe("svelte-u9bgzb",document.head);w=d(t,"META",{name:!0,content:!0}),t.forEach(a),S=s(e),F=d(e,"P",{}),ke(F).forEach(a),P=s(e),o(J.$$.fragment,e),K=s(e),j=d(e,"P",{"data-svelte-h":!0}),y(j)!=="svelte-gsqkro"&&(j.innerHTML=$e),L=s(e),o(T.$$.fragment,e),q=s(e),f=d(e,"P",{"data-svelte-h":!0}),y(f)!=="svelte-10vdwc7"&&(f.textContent=ge),D=s(e),o(b.$$.fragment,e),O=s(e),U=d(e,"P",{"data-svelte-h":!0}),y(U)!=="svelte-h27ljr"&&(U.innerHTML=Ie),ee=s(e),o(h.$$.fragment,e),te=s(e),o($.$$.fragment,e),ae=s(e),g=d(e,"P",{"data-svelte-h":!0}),y(g)!=="svelte-18shtua"&&(g.innerHTML=Ce),le=s(e),o(I.$$.fragment,e),ne=s(e),o(C.$$.fragment,e),se=s(e),B=d(e,"P",{"data-svelte-h":!0}),y(B)!=="svelte-s1kttw"&&(B.innerHTML=Be),re=s(e),o(Z.$$.fragment,e),oe=s(e),A=d(e,"P",{"data-svelte-h":!0}),y(A)!=="svelte-hqe2mt"&&(A.textContent=Ze),ie=s(e),o(W.$$.fragment,e),ce=s(e),o(G.$$.fragment,e),pe=s(e),X=d(e,"P",{"data-svelte-h":!0}),y(X)!=="svelte-o7k00x"&&(X.textContent=Ae),me=s(e),o(v.$$.fragment,e),Me=s(e),k=d(e,"P",{"data-svelte-h":!0}),y(k)!=="svelte-12guh7h"&&(k.textContent=We),de=s(e),o(Y.$$.fragment,e),ye=s(e),_=d(e,"P",{"data-svelte-h":!0}),y(_)!=="svelte-d4zz74"&&(_.textContent=Ge),we=s(e),o(E.$$.fragment,e),ue=s(e),o(N.$$.fragment,e),Je=s(e),V=d(e,"P",{"data-svelte-h":!0}),y(V)!=="svelte-18d6lv"&&(V.innerHTML=Xe),je=s(e),o(R.$$.fragment,e),Te=s(e),x=d(e,"P",{"data-svelte-h":!0}),y(x)!=="svelte-zuhnw8"&&(x.innerHTML=ve),fe=s(e),o(Q.$$.fragment,e),be=s(e),H=d(e,"P",{}),ke(H).forEach(a),this.h()},h(){Ye(w,"name","hf:doc:metadata"),Ye(w,"content",He)},m(e,t){Qe(document.head,w),l(e,S,t),l(e,F,t),l(e,P,t),i(J,e,t),l(e,K,t),l(e,j,t),l(e,L,t),i(T,e,t),l(e,q,t),l(e,f,t),l(e,D,t),i(b,e,t),l(e,O,t),l(e,U,t),l(e,ee,t),i(h,e,t),l(e,te,t),i($,e,t),l(e,ae,t),l(e,g,t),l(e,le,t),i(I,e,t),l(e,ne,t),i(C,e,t),l(e,se,t),l(e,B,t),l(e,re,t),i(Z,e,t),l(e,oe,t),l(e,A,t),l(e,ie,t),i(W,e,t),l(e,ce,t),i(G,e,t),l(e,pe,t),l(e,X,t),l(e,me,t),i(v,e,t),l(e,Me,t),l(e,k,t),l(e,de,t),i(Y,e,t),l(e,ye,t),l(e,_,t),l(e,we,t),i(E,e,t),l(e,ue,t),i(N,e,t),l(e,Je,t),l(e,V,t),l(e,je,t),i(R,e,t),l(e,Te,t),l(e,x,t),l(e,fe,t),i(Q,e,t),l(e,be,t),l(e,H,t),Ue=!0},p:Ee,i(e){Ue||(c(J.$$.fragment,e),c(T.$$.fragment,e),c(b.$$.fragment,e),c(h.$$.fragment,e),c($.$$.fragment,e),c(I.$$.fragment,e),c(C.$$.fragment,e),c(Z.$$.fragment,e),c(W.$$.fragment,e),c(G.$$.fragment,e),c(v.$$.fragment,e),c(Y.$$.fragment,e),c(E.$$.fragment,e),c(N.$$.fragment,e),c(R.$$.fragment,e),c(Q.$$.fragment,e),Ue=!0)},o(e){p(J.$$.fragment,e),p(T.$$.fragment,e),p(b.$$.fragment,e),p(h.$$.fragment,e),p($.$$.fragment,e),p(I.$$.fragment,e),p(C.$$.fragment,e),p(Z.$$.fragment,e),p(W.$$.fragment,e),p(G.$$.fragment,e),p(v.$$.fragment,e),p(Y.$$.fragment,e),p(E.$$.fragment,e),p(N.$$.fragment,e),p(R.$$.fragment,e),p(Q.$$.fragment,e),Ue=!1},d(e){e&&(a(S),a(F),a(P),a(K),a(j),a(L),a(q),a(f),a(D),a(O),a(U),a(ee),a(te),a(ae),a(g),a(le),a(ne),a(se),a(B),a(re),a(oe),a(A),a(ie),a(ce),a(pe),a(X),a(me),a(Me),a(k),a(de),a(ye),a(_),a(we),a(ue),a(Je),a(V),a(je),a(Te),a(x),a(fe),a(be),a(H)),a(w),m(J,e),m(T,e),m(b,e),m(h,e),m($,e),m(I,e),m(C,e),m(Z,e),m(W,e),m(G,e),m(v,e),m(Y,e),m(E,e),m(N,e),m(R,e),m(Q,e)}}}const He='{"title":"Entrenamiento distribuido con 🤗 Accelerate","local":"entrenamiento-distribuido-con--accelerate","sections":[{"title":"Configuración","local":"configuración","sections":[],"depth":2},{"title":"Prepárate para acelerar","local":"prepárate-para-acelerar","sections":[],"depth":2},{"title":"Backward","local":"backward","sections":[],"depth":2},{"title":"Entrenamiento","local":"entrenamiento","sections":[{"title":"Entrenar con un script","local":"entrenar-con-un-script","sections":[],"depth":3},{"title":"Entrenar con un notebook","local":"entrenar-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.8 kB
·
Xet hash:
a2959e4bd9a5912befd27e26ffd1acc0626cde83888f88eba80c6f084efe5c2f

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.