Buckets:
| # Sequence များစွာကို ကိုင်တွယ်ခြင်း[[handling-multiple-sequences]] | |
| <CourseFloatingBanner chapter={2} | |
| classNames="absolute z-10 right-0 top-0" | |
| notebooks={[ | |
| {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter2/section5_pt.ipynb"}, | |
| {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter2/section5_pt.ipynb"}, | |
| ]} /> | |
| <Youtube id="M6adb1j2jPI"/> | |
| ယခင်အပိုင်းမှာ ကျွန်တော်တို့ဟာ အသေးစား အရှည်ရှိတဲ့ sequence တစ်ခုတည်းပေါ်မှာ inference လုပ်တဲ့ အလွယ်ကူဆုံး အသုံးပြုမှုပုံစံကို လေ့လာခဲ့ပါတယ်။ သို့သော်လည်း၊ အချို့မေးခွန်းတွေ အခုကတည်းက ပေါ်ပေါက်လာပါတယ်- | |
| - sequence များစွာကို ဘယ်လိုကိုင်တွယ်မလဲ။ | |
| - *အရှည်မတူညီတဲ့* sequence များစွာကို ဘယ်လိုကိုင်တွယ်မလဲ။ | |
| - vocabulary indices တွေဟာ model က ကောင်းကောင်း အလုပ်လုပ်နိုင်ဖို့ တစ်ခုတည်းသော input တွေလား။ | |
| - အရမ်းရှည်လျားတဲ့ sequence မျိုး ရှိပါသလား။ | |
| ဒီမေးခွန်းတွေက ဘယ်လိုပြဿနာတွေ ဖြစ်စေလဲ၊ Hugging Face Transformers API ကို အသုံးပြုပြီး ဒါတွေကို ဘယ်လိုဖြေရှင်းနိုင်လဲဆိုတာ ကြည့်ရအောင်။ | |
| ## Model များသည် Inputs များ၏ Batch တစ်ခုကို မျှော်လင့်ကြသည်[[models-expect-a-batch-of-inputs]] | |
| ယခင် လေ့ကျင့်ခန်းမှာ sequence တွေကို ဂဏန်း list တွေအဖြစ် ဘယ်လိုပြောင်းလဲတယ်ဆိုတာကို သင်တွေ့ခဲ့ရပါတယ်။ ဒီဂဏန်း list ကို tensor အဖြစ် ပြောင်းလဲပြီး model ကို ပို့ကြည့်ရအောင်။ | |
| ```py | |
| import torch | |
| from transformers import AutoTokenizer, AutoModelForSequenceClassification | |
| checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" | |
| tokenizer = AutoTokenizer.from_pretrained(checkpoint) | |
| model = AutoModelForSequenceClassification.from_pretrained(checkpoint) | |
| sequence = "I've been waiting for a HuggingFace course my whole life." | |
| tokens = tokenizer.tokenize(sequence) | |
| ids = tokenizer.convert_tokens_to_ids(tokens) | |
| input_ids = torch.tensor(ids) | |
| # This line will fail. | |
| model(input_ids) | |
| ``` | |
| ```python out | |
| IndexError: Dimension out of range (expected to be in range of [-1, 0], but got 1) | |
| ``` | |
| ဟာ မဟုတ်သေးပါဘူး။ ဒါက ဘာကြောင့် အဆင်မပြေတာလဲ။ ကျွန်တော်တို့ အပိုင်း ၂ မှာပါတဲ့ pipeline အဆင့်တွေကို လိုက်နာခဲ့တာပဲလေဗျာ။ | |
| ပြဿနာကတော့ ကျွန်တော်တို့ model ကို single sequence တစ်ခုပဲ ပို့ခဲ့တာပါ၊ ဒါပေမယ့် 🤗 Transformers model တွေက default အားဖြင့် sentences များစွာကို မျှော်လင့်ထားပါတယ်။ ဒီနေရာမှာ tokenizer က `sequence` တစ်ခုပေါ်မှာ အသုံးပြုခဲ့တုန်းက နောက်ကွယ်မှာ လုပ်ခဲ့တဲ့အရာ အားလုံးကို ကျွန်တော်တို့ လုပ်ဆောင်ဖို့ ကြိုးစားခဲ့ပါတယ်။ ဒါပေမယ့် သေချာကြည့်မယ်ဆိုရင် tokenizer က input IDs list ကို tensor တစ်ခုအဖြစ် ပြောင်းပေးရုံသာမကဘဲ၊ ၎င်းရဲ့ အပေါ်မှာ dimension တစ်ခုကို ထည့်သွင်းခဲ့တယ်ဆိုတာကို သင်တွေ့ရပါလိမ့်မယ်- | |
| ```py | |
| tokenized_inputs = tokenizer(sequence, return_tensors="pt") | |
| print(tokenized_inputs["input_ids"]) | |
| ``` | |
| ```python out | |
| tensor([[ 101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, | |
| 2607, 2026, 2878, 2166, 1012, 102]]) | |
| ``` | |
| နောက်တစ်ကြိမ် ထပ်ကြိုးစားပြီး dimension အသစ်တစ်ခု ထည့်ကြည့်ရအောင်။ | |
| ```py | |
| import torch | |
| from transformers import AutoTokenizer, AutoModelForSequenceClassification | |
| checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" | |
| tokenizer = AutoTokenizer.from_pretrained(checkpoint) | |
| model = AutoModelForSequenceClassification.from_pretrained(checkpoint) | |
| sequence = "I've been waiting for a HuggingFace course my whole life." | |
| tokens = tokenizer.tokenize(sequence) | |
| ids = tokenizer.convert_tokens_to_ids(tokens) | |
| input_ids = torch.tensor([ids]) | |
| print("Input IDs:", input_ids) | |
| output = model(input_ids) | |
| print("Logits:", output.logits) | |
| ``` | |
| ကျွန်တော်တို့ input IDs တွေရော၊ ထွက်လာတဲ့ logits တွေရော print လုပ်လိုက်ပါတယ်၊ ဒါကတော့ output ပါ။ | |
| ```python out | |
| Input IDs: [[ 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012]] | |
| Logits: [[-2.7276, 2.8789]] | |
| ``` | |
| *Batching* ဆိုတာက model ကို sentences များစွာကို တစ်ပြိုင်နက်တည်း ပေးပို့တဲ့ လုပ်ဆောင်ချက်ပါပဲ။ သင့်မှာ စာကြောင်းတစ်ကြောင်းတည်းသာ ရှိရင်၊ single sequence တစ်ခုတည်းနဲ့ batch တစ်ခုကို တည်ဆောက်နိုင်ပါတယ်။ | |
| ``` | |
| batched_ids = [ids, ids] | |
| ``` | |
| ဒါက အတူတူ sequences နှစ်ခုပါတဲ့ batch တစ်ခုပါပဲ။ | |
| > [!TIP] | |
| > ✏️ **စမ်းသပ်ကြည့်ပါ။** ဒီ `batched_ids` list ကို tensor အဖြစ် ပြောင်းလဲပြီး သင့် model ကို ဖြတ်သန်းပါ။ ယခင်က ရရှိခဲ့တဲ့ logits တွေ အတူတူ (ဒါပေမယ့် နှစ်ဆ) ရရှိမရရှိ စစ်ဆေးပါ။ | |
| Batching လုပ်ခြင်းက သင် model ကို sentences များစွာ ထည့်သွင်းတဲ့အခါ အလုပ်လုပ်စေပါတယ်။ sentences များစွာကို အသုံးပြုတာက single sequence နဲ့ batch တစ်ခုတည်ဆောက်တာလိုပဲ ရိုးရှင်းပါတယ်။ ဒါပေမယ့် ဒုတိယပြဿနာတစ်ခု ရှိပါတယ်။ စာကြောင်းနှစ်ခု (သို့မဟုတ် ပိုများ) ကို batch လုပ်ဖို့ ကြိုးစားတဲ့အခါ၊ ၎င်းတို့ရဲ့ အရှည်တွေက မတူညီနိုင်ပါဘူး။ သင် tensors တွေနဲ့ အရင်က အလုပ်လုပ်ဖူးတယ်ဆိုရင်၊ ၎င်းတို့ဟာ ထောင့်မှန်ပုံစံ (rectangular shape) ဖြစ်ဖို့ လိုအပ်တယ်ဆိုတာ သင်သိပါလိမ့်မယ်။ ဒါကြောင့် input IDs list ကို tensor တစ်ခုအဖြစ် တိုက်ရိုက်ပြောင်းလို့ ရမှာ မဟုတ်ပါဘူး။ ဒီပြဿနာကို ဖြေရှင်းဖို့အတွက် ကျွန်တော်တို့ဟာ inputs တွေကို များသောအားဖြင့် *pad* လုပ်ပါတယ်။ | |
| ## Inputs များကို Padding လုပ်ခြင်း[[padding-the-inputs]] | |
| အောက်ပါ list of lists ကို tensor အဖြစ် ပြောင်းလဲလို့ မရပါဘူး။ | |
| ```py no-format | |
| batched_ids = [ | |
| [200, 200, 200], | |
| [200, 200] | |
| ] | |
| ``` | |
| ဒီပြဿနာကို ဖြေရှင်းဖို့အတွက် ကျွန်တော်တို့ tensors တွေကို ထောင့်မှန်ပုံစံ ဖြစ်အောင် ပြုလုပ်ဖို့ *padding* ကို အသုံးပြုပါမယ်။ Padding က ကျွန်တော်တို့ရဲ့ sentences တွေအားလုံးကို အရှည်တူညီအောင် သေချာစေဖို့အတွက် *padding token* လို့ခေါ်တဲ့ special word တစ်ခုကို တန်ဖိုးနည်းတဲ့ sentences တွေမှာ ထည့်ပေးပါတယ်။ ဥပမာအားဖြင့်၊ သင့်မှာ စကားလုံး ၁၀ လုံးပါတဲ့ စာကြောင်း ၁၀ ကြောင်းနဲ့ စကားလုံး ၂၀ လုံးပါတဲ့ စာကြောင်း ၁ ကြောင်းရှိရင်၊ padding က စာကြောင်းအားလုံးမှာ စကားလုံး ၂၀ လုံးစီ ရှိစေမှာပါ။ ကျွန်တော်တို့ရဲ့ ဥပမာမှာ၊ ထွက်လာတဲ့ tensor က ဒီလိုဖြစ်ပါတယ်။ | |
| ```py no-format | |
| padding_id = 100 | |
| batched_ids = [ | |
| [200, 200, 200], | |
| [200, 200, padding_id], | |
| ] | |
| ``` | |
| padding token ID ကို `tokenizer.pad_token_id` မှာ ရှာတွေ့နိုင်ပါတယ်။ ဒါကို အသုံးပြုပြီး ကျွန်တော်တို့ရဲ့ စာကြောင်းနှစ်ကြောင်းကို model ကနေတဆင့် တစ်ဦးချင်းစီနဲ့ batch အဖြစ် ပေါင်းပြီး ပို့ကြည့်ရအောင်။ | |
| ```py no-format | |
| model = AutoModelForSequenceClassification.from_pretrained(checkpoint) | |
| sequence1_ids = [[200, 200, 200]] | |
| sequence2_ids = [[200, 200]] | |
| batched_ids = [ | |
| [200, 200, 200], | |
| [200, 200, tokenizer.pad_token_id], | |
| ] | |
| print(model(torch.tensor(sequence1_ids)).logits) | |
| print(model(torch.tensor(sequence2_ids)).logits) | |
| print(model(torch.tensor(batched_ids)).logits) | |
| ``` | |
| ```python out | |
| tensor([[ 1.5694, -1.3895]], grad_fn=<AddmmBackward>) | |
| tensor([[ 0.5803, -0.4125]], grad_fn=<AddmmBackward>) | |
| tensor([[ 1.5694, -1.3895], | |
| [ 1.3373, -1.2163]], grad_fn=<AddmmBackward>) | |
| ``` | |
| ကျွန်တော်တို့ရဲ့ batched predictions တွေထဲက logits တွေမှာ တစ်ခုခု မှားယွင်းနေပါတယ်။ ဒုတိယ row က ဒုတိယစာကြောင်းအတွက် logits တွေနဲ့ တူညီသင့်ပေမယ့်၊ ကျွန်တော်တို့မှာ လုံးဝမတူညီတဲ့ တန်ဖိုးတွေ ရနေပါတယ်။ | |
| ဒါက Transformer model တွေရဲ့ အဓိကအင်္ဂါရပ်ဖြစ်တဲ့ attention layers တွေက token တစ်ခုစီကို *contextualize* လုပ်ပေးလို့ ဖြစ်ပါတယ်။ ၎င်းတို့သည် sequence တစ်ခု၏ tokens အားလုံးကို အာရုံစိုက်တာကြောင့် padding tokens တွေကို ထည့်သွင်းစဉ်းစားပါလိမ့်မယ်။ မတူညီတဲ့ အရှည်ရှိတဲ့ တစ်ဦးချင်းစီ စာကြောင်းတွေကို model ကနေတဆင့် ပို့တဲ့အခါ ဒါမှမဟုတ် တူညီတဲ့ စာကြောင်းတွေနဲ့ padding လုပ်ထားတဲ့ batch တစ်ခုကို ပို့တဲ့အခါ တူညီတဲ့ရလဒ် ရရှိဖို့အတွက်၊ အဲဒီ attention layers တွေကို padding tokens တွေကို လျစ်လျူရှုဖို့ ကျွန်တော်တို့ ပြောပြဖို့ လိုအပ်ပါတယ်။ ဒါကို attention mask ကို အသုံးပြုခြင်းဖြင့် လုပ်ဆောင်ပါတယ်။ | |
| ## Attention Masks[[attention-masks]] | |
| *Attention masks* တွေက input IDs tensor နဲ့ အတိအကျတူညီတဲ့ shape ရှိတဲ့ tensors တွေဖြစ်ပြီး 0 တွေနဲ့ 1 တွေနဲ့ ဖြည့်ထားပါတယ်။ 1 တွေက သက်ဆိုင်ရာ tokens တွေကို အာရုံစိုက်သင့်တယ်လို့ ဖော်ပြပြီး၊ 0 တွေကတော့ သက်ဆိုင်ရာ tokens တွေကို အာရုံစိုက်ရန် မလိုအပ်ဘူး (ဆိုလိုသည်မှာ model ရဲ့ attention layers တွေက လျစ်လျူရှုသင့်တယ်) လို့ ဖော်ပြပါတယ်။ | |
| ယခင် ဥပမာကို attention mask တစ်ခုနဲ့ ဖြည့်စွက်ကြည့်ရအောင်။ | |
| ```py no-format | |
| batched_ids = [ | |
| [200, 200, 200], | |
| [200, 200, tokenizer.pad_token_id], | |
| ] | |
| attention_mask = [ | |
| [1, 1, 1], | |
| [1, 1, 0], | |
| ] | |
| outputs = model(torch.tensor(batched_ids), attention_mask=torch.tensor(attention_mask)) | |
| print(outputs.logits) | |
| ``` | |
| ```python out | |
| tensor([[ 1.5694, -1.3895], | |
| [ 0.5803, -0.4125]], grad_fn=<AddmmBackward>) | |
| ``` | |
| အခု batch ထဲက ဒုတိယစာကြောင်းအတွက် logits တွေ အတူတူကို ရရှိပါပြီ။ | |
| ဒုတိယ sequence ရဲ့ နောက်ဆုံးတန်ဖိုးက padding ID တစ်ခုဖြစ်ပြီး၊ attention mask ထဲမှာတော့ 0 တန်ဖိုးဖြစ်နေတာကို သတိပြုပါ။ | |
| > [!TIP] | |
| > ✏️ **စမ်းသပ်ကြည့်ပါ။** အပိုင်း ၂ မှာ အသုံးပြုခဲ့တဲ့ စာကြောင်းနှစ်ကြောင်း ("I've been waiting for a HuggingFace course my whole life." နဲ့ "I hate this so much!") ပေါ်မှာ tokenization ကို ကိုယ်တိုင် လုပ်ဆောင်ပါ။ ၎င်းတို့ကို model ကို ဖြတ်သန်းပြီး အပိုင်း ၂ မှာ ရရှိခဲ့တဲ့ logits တွေ အတူတူ ရရှိမရရှိ စစ်ဆေးပါ။ အခု ၎င်းတို့ကို padding token ကို အသုံးပြုပြီး batch လုပ်ပါ၊ ပြီးရင် မှန်ကန်တဲ့ attention mask ကို ဖန်တီးပါ။ model ကို ဖြတ်သန်းတဲ့အခါ တူညီတဲ့ရလဒ်တွေ ရရှိမရရှိ စစ်ဆေးပါ။ | |
| ## ပိုမိုရှည်လျားသော Sequences များ[[longer-sequences]] | |
| Transformer model တွေနဲ့ဆိုရင် model တွေကို ပေးပို့နိုင်တဲ့ sequences တွေရဲ့ အရှည်မှာ ကန့်သတ်ချက်တစ်ခု ရှိပါတယ်။ model အများစုက tokens 512 သို့မဟုတ် 1024 အထိ sequences တွေကို ကိုင်တွယ်နိုင်ပြီး၊ ပိုရှည်တဲ့ sequences တွေကို လုပ်ဆောင်ဖို့ တောင်းဆိုတဲ့အခါ crash ဖြစ်ပါလိမ့်မယ်။ ဒီပြဿနာကို ဖြေရှင်းဖို့ နည်းလမ်းနှစ်ခု ရှိပါတယ်- | |
| - ပိုမိုရှည်လျားတဲ့ sequence length ကို ထောက်ပံ့ပေးတဲ့ model ကို အသုံးပြုပါ။ | |
| - သင်ရဲ့ sequences တွေကို truncate လုပ်ပါ။ | |
| Model တွေမှာ မတူညီတဲ့ ထောက်ပံ့ပေးထားတဲ့ sequence lengths တွေရှိပြီး၊ အချို့က အလွန်ရှည်လျားတဲ့ sequences တွေကို ကိုင်တွယ်ရာမှာ အထူးပြုပါတယ်။ [Longformer](https://huggingface.co/docs/transformers/model_doc/longformer) က ဥပမာတစ်ခုဖြစ်ပြီး၊ [LED](https://huggingface.co/docs/transformers/model_doc/led) က နောက်ဥပမာတစ်ခု ဖြစ်ပါတယ်။ သင်ဟာ အလွန်ရှည်လျားတဲ့ sequences တွေလိုအပ်တဲ့ လုပ်ငန်းတစ်ခုပေါ်မှာ အလုပ်လုပ်နေတယ်ဆိုရင်၊ အဲဒီ model တွေကို လေ့လာကြည့်ဖို့ ကျွန်တော်တို့ အကြံပြုပါတယ်။ | |
| မဟုတ်ရင်တော့ သင်ရဲ့ sequences တွေကို `max_sequence_length` parameter ကို သတ်မှတ်ခြင်းဖြင့် truncate လုပ်ဖို့ ကျွန်တော်တို့ အကြံပြုပါတယ်။ | |
| ```py | |
| sequence = sequence[:max_sequence_length] | |
| ``` | |
| ## ဝေါဟာရ ရှင်းလင်းချက် (Glossary) | |
| * **Inference**: လေ့ကျင့်ပြီးသား Artificial Intelligence (AI) မော်ဒယ်တစ်ခုကို အသုံးပြုပြီး input data ကနေ ခန့်မှန်းချက်တွေ ဒါမှမဟုတ် output တွေကို ထုတ်လုပ်တဲ့ လုပ်ငန်းစဉ်။ | |
| * **Sequence**: စာသားတစ်ခု သို့မဟုတ် စကားလုံးများ၊ tokens များ၏ အစဉ်လိုက် စီစဉ်ထားသော အစုအဝေး။ | |
| * **Vocabulary Indices**: စာသားကို encode လုပ်ပြီးနောက် ရရှိလာသော tokens တစ်ခုစီ၏ ထူးခြားသော ဂဏန်း ID များ။ | |
| * **🤗 Transformers API**: Hugging Face Transformers library ကို အသုံးပြုရန်အတွက် ပရိုဂရမ်မာများက ခေါ်ဆိုနိုင်သော လုပ်ဆောင်ချက်များ၊ class များနှင့် methods များ။ | |
| * **Batching**: မတူညီသော input များစွာကို တစ်ပြိုင်နက်တည်း လုပ်ဆောင်နိုင်ရန် အုပ်စုဖွဲ့ခြင်း။ | |
| * **Tensor**: Machine Learning frameworks (PyTorch, TensorFlow) များတွင် ဒေတာများကို ကိုယ်စားပြုသော multi-dimensional array များ။ | |
| * **`AutoTokenizer` Class**: Hugging Face Transformers library မှာ ပါဝင်တဲ့ class တစ်ခုဖြစ်ပြီး မော်ဒယ်အမည်ကို အသုံးပြုပြီး သက်ဆိုင်ရာ tokenizer ကို အလိုအလျောက် load လုပ်ပေးသည်။ | |
| * **`AutoModelForSequenceClassification` Class**: Hugging Face Transformers library မှာ ပါဝင်တဲ့ class တစ်ခုဖြစ်ပြီး sequence classification အတွက် pre-trained model ကို အလိုအလျောက် load လုပ်ပေးသည်။ | |
| * **`from_pretrained()` Method**: Pre-trained model သို့မဟုတ် tokenizer ကို load လုပ်ရန် အသုံးပြုသော method။ | |
| * **`tokenize()` Method**: tokenizer ၏ text ကို tokens များအဖြစ် ပိုင်းခြားပေးသော method။ | |
| * **`convert_tokens_to_ids()` Method**: tokens list ကို input IDs list အဖြစ် ပြောင်းလဲပေးသော tokenizer method။ | |
| * **`input_ids`**: Tokenizer မှ ထုတ်ပေးသော tokens တစ်ခုစီ၏ ထူးခြားသော ဂဏန်းဆိုင်ရာ ID များ။ | |
| * **`output.logits`**: မော်ဒယ်၏ နောက်ဆုံး layer မှ ထုတ်ပေးသော raw, unnormalized scores များ။ | |
| * **Padding**: မတူညီသော အရှည်ရှိသည့် input sequence များကို အရှည်တူညီအောင် သတ်မှတ်ထားသော တန်ဖိုးများဖြင့် ဖြည့်စွက်ခြင်း။ | |
| * **Padding Token**: Padding လုပ်ရာတွင် အသုံးပြုသော အထူး token (ဥပမာ - `[PAD]`)။ | |
| * **`tokenizer.pad_token_id`**: tokenizer ၏ padding token ၏ ID။ | |
| * **Attention Layers**: Transformer model ၏ အစိတ်အပိုင်းများဖြစ်ပြီး input sequence အတွင်းရှိ မတူညီသော tokens များ၏ အရေးပါမှုကို ဆုံးဖြတ်ရာတွင် အထောက်အကူပြုသည်။ | |
| * **Contextualize**: စကားလုံးတစ်ခု၏ အဓိပ္ပာယ်ကို ၎င်းပါဝင်သော စာကြောင်း သို့မဟုတ် စာသား၏ အခြေအနေအရ နားလည်စေခြင်း။ | |
| * **Attention Mask**: မော်ဒယ်ကို အာရုံစိုက်သင့်သည့် tokens များနှင့် လျစ်လျူရှုသင့်သည့် (padding) tokens များကို ခွဲခြားပေးသည့် binary mask။ | |
| * **Truncate**: sequences ၏ အရှည်ကို ကန့်သတ်ချက်တစ်ခုအထိ ဖြတ်တောက်ခြင်း။ | |
| * **`max_sequence_length` Parameter**: input sequence ၏ အများဆုံး အရှည်ကို သတ်မှတ်သော parameter။ | |
| * **Longformer**: အလွန်ရှည်လျားသော sequences များကို ကိုင်တွယ်နိုင်ရန် ဒီဇိုင်းထုတ်ထားသော Transformer model တစ်မျိုး။ | |
| * **LED (Longformer-Encoder-Decoder)**: Longformer ကို အခြေခံထားသော encoder-decoder Transformer model တစ်မျိုး။ | |
| <EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/my/chapter2/5.mdx" /> |
Xet Storage Details
- Size:
- 24.1 kB
- Xet hash:
- 0c2b5eb174c17c3cb0022d727d161077b12e5c6097190d680ab1c551522e4231
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.