From 631b02b14d879dfe4e1c9b3728c9ed0ca38eef53 Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Fri, 1 Apr 2022 15:29:05 +0900 Subject: [PATCH 01/73] ko-chapter1/1 --- chapters/ko/chapter1/1.mdx | 52 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 chapters/ko/chapter1/1.mdx diff --git a/chapters/ko/chapter1/1.mdx b/chapters/ko/chapter1/1.mdx new file mode 100644 index 000000000..92fda2f4f --- /dev/null +++ b/chapters/ko/chapter1/1.mdx @@ -0,0 +1,52 @@ +# 단원 소개 + +## 🤗 강의 수강생 여러분 환영합니다! + + + +이번 강의에서는 [Hugging Face](https://huggingface.co/) 환경의 라이브러리([🤗 Transformers](https://github.com/huggingface/transformers), [🤗 Datasets](https://github.com/huggingface/datasets), [🤗 Tokenizers](https://github.com/huggingface/tokenizers), [🤗 Accelerate](https://github.com/huggingface/accelerate))와 [Hugging Face Hub](https://huggingface.co/models) 를 이용해 자연어 처리(NLP)에 대해 배워보겠습니다. (무료 강의에 광고도 없는건 비밀이에요!) + +## 무엇을 배우나요? + +강의 개요 훑어보기: + +
+Brief overview of the chapters of the course. + +
+ +- 단원 1~4에서는 🤗 Transformers 라이브러리의 핵심 개념에 대해 소개합니다. 이번 강의 끝무렵에 아마 여러분들은 트랜스포머 모델이 어떻게 동작하는지 터득하게 될거고, [Hugging Face Hub](https://huggingface.co/models)에서 모델을 사용하고 데이터셋으로 fine-tune하고 Hub에 여러분의 모델을 공유하는 방법까지 알게 될 것입니다! +- 단원 5~8은 본격적으로 전형적인 NLP 작업을 하기 앞서, 🤗 Datasets와 🤗 Tokenizers의 기초를 다룹니다. 이 부분을 모두 학습하면 여러분들은 가장 일반적인 NLP 문제를 스스로 해낼 수 있습니다. +- 단원 9~12에서는 NLP를 넘어, 트랜스포머 모델이 음성 처리 및 컴퓨터 비전에 어떻게 활용되는지 탐구합니다. 이 과정에서 여러분들의 모델 데모를 구축하고 공유하는 방법 및 이를 프로덕션 환경에 최적화하는 방법을 배우게 됩니다. 최종적으로, 여러분들은 (거의) 모든 머신 러닝 문제에 🤗 Transformers를 적용할 준비를 갖추게 됩니다! + +이번 강의는: + +- 파이썬에 대한 기초 지식이 필요합니다 +- [DeepLearning.AI](https://www.deeplearning.ai/) 의 프로그램이나 [fast.ai's](https://www.fast.ai/) [Practical Deep Learning for Coders](https://course.fast.ai/) 와 같은 딥러닝에 대한 기초 강의를 듣고 수강하면 더욱 효과적입니다 +- [PyTorch](https://pytorch.org/) , [TensorFlow](https://www.tensorflow.org/) 에 대한 선수 지식이 필요하지 않지만, 이에 익숙하다면 도움이 될 것입니다 + +본 강의를 모두 수강한 후, [DeepLearning.AI](http://deeplearning.ai/)의 [Natural Language Processing Specialization](https://www.coursera.org/specializations/natural-language-processing?utm_source=deeplearning-ai&utm_medium=institutions&utm_campaign=20211011-nlp-2-hugging_face-page-nlp-refresh)을 살펴보시길 권장드립니다. 해당 과정에서는 Naive Bayes, LSTM과 같은 알아두면 너무나 유용한 더 넓은 범위의 전통 NLP 모델에 대해 학습할 수 있습니다! + +## 우리가 누구일까요? + +저자 소개: + +**Matthew Carrigan**은 Hugging Face의 머신 러닝 엔지니어입니다. 현재 아일랜드 더블린에 살고 있으며, 이전에는 [Parse.ly](http://parse.ly/) 에서 ML 엔지니어로, 그 전에는 Trinity Collge Dublin에서 박사 과정 이후 연구원으로 근무했습니다. 우리가 기존 인공지능 아키텍쳐를 확장하여 사람 수준에는 도달하지 못할거라고 생각하지만, 그럼에도 불로장생 로봇에 대해 큰 기대를 갖고 있습니다. + +**Lysandre Debut**는 Hugging Face의 머신 러닝 엔지니어이며 초창기부터 🤗 Transformers 라이브러리 작업을 함께 했습니다. 아주 간단한 API를 개발하여 모두가 NLP를 쉽게 사용할 수 있도록 하는 목표를 갖고 있습니다. + +**Sylvain Gugger**는 Hugging Face의 리서치 엔지니어로 🤗 Transformers 라이브러리의 주요 관리자 중 한명입니다. 이전에 [fast.ai](http://fast.ai/) 에서 리서치 사이언티스트로 있었으며 Jeremy Howard와 함께 *[Deep Learning for Coders with fastai and PyTorch](https://learning.oreilly.com/library/view/deep-learning-for/9781492045519/)* 를 저술했습니다. 적은 리소스에서도 모델이 빠르게 학습되도록 기술을 디자인하고 개선하여 딥러닝에 보다 쉽게 접근할 수 있도록 하는 것을 리서치의 가장 큰 목표로 삼고 있습니다. + +**Merve Noyan**은 Hugging Face의 개발자 애드보케이트로, 모두를 위한 민주적인 머신 러닝 생태계를 만들고자 개발툴 작업 및 주변 컨텐츠 구축 작업을 담당합니다. + +**Lucile Saulnier**은 Hugging Face의 ML 엔지니어로 오픈 소스 툴 사용에 대한 개발 및 지원을 담당합니다. 자연어 처리 분야에서 협업 학습, BigScience등과 같은 다양한 리서치 프로젝트에도 활발히 참여하고 있습니다. + +**Lewis Tunstall**는 Hugging Face의 ML 엔지니어로 오픈 소스 툴을 개발하여 더 많은 커뮤니티에 상용화되도록 하는 데에 초점을 맞추고 있습니다. 곧 출간되는 [O’Reilly book on Transformers](https://www.oreilly.com/library/view/natural-language-processing/9781098103231/)의 공저자이기도 합니다. + +**Leandro von Werra**는 Hugging Face 오픈소스 팀의 머신 러닝 엔지니어이자 곧 출간될 [O’Reilly book on Transformers](https://www.oreilly.com/library/view/natural-language-processing/9781098103231/)의 공동 저자입니다. 모든 머신 러닝 스택에서의 작업을 통해 수 년간 NLP 프로젝트를 프로덕션으로 들여온 경력자입니다. + +시작할 준비가 되셨나요? 이번 단원에서 다룰 내용은 다음과 같습니다: + +- 텍스트 생성 및 분류와 같은 NLP 문제를 푸는 `pipeline()` 함수 사용법 +- 트랜스포머 모델 구조 +- 인코더(encoder), 디코더(decoder), 인코더-디코더(encoder-decoder) 구조의 구조와 용례 \ No newline at end of file From e27454bcb7656021261dafe01c3292fc5fe885bd Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Fri, 1 Apr 2022 15:30:23 +0900 Subject: [PATCH 02/73] ko _toctree.yml created --- chapters/ko/_toctree.yml | 173 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 chapters/ko/_toctree.yml diff --git a/chapters/ko/_toctree.yml b/chapters/ko/_toctree.yml new file mode 100644 index 000000000..db8e22827 --- /dev/null +++ b/chapters/ko/_toctree.yml @@ -0,0 +1,173 @@ +- title: 0. Setup + sections: + - local: chapter0/1 + title: Introduction + +- title: 1. 트랜스포머 모델 + sections: + - local: chapter1/1 + title: 단원 소개 + - local: chapter1/2 + title: 자연어 처리 + - local: chapter1/3 + title: 트랜스포머로 무엇을 할 수 있나요? + - local: chapter1/4 + title: 트랜스포머는 어떻게 동작하나요? + - local: chapter1/5 + title: 인코더 모델 + - local: chapter1/6 + title: 디코더 모델 + - local: chapter1/7 + title: 시퀀스-투-시퀀스 모델 + - local: chapter1/8 + title: 편견과 한계점 + - local: chapter1/9 + title: 정리 + - local: chapter1/10 + title: 단원 마무리 퀴즈 + quiz: 1 + +- title: 2. Using 🤗 Transformers + sections: + - local: chapter2/1 + title: Introduction + - local: chapter2/2 + title: Behind the pipeline + - local: chapter2/3 + title: Models + - local: chapter2/4 + title: Tokenizers + - local: chapter2/5 + title: Handling multiple sequences + - local: chapter2/6 + title: Putting it all together + - local: chapter2/7 + title: Basic usage completed! + - local: chapter2/8 + title: End-of-chapter quiz + quiz: 2 + +- title: 3. Fine-tuning a pretrained model + sections: + - local: chapter3/1 + title: Introduction + - local: chapter3/2 + title: Processing the data + - local: chapter3/3 + title: Fine-tuning a model with the Trainer API or Keras + local_fw: { pt: chapter3/3, tf: chapter3/3_tf } + - local: chapter3/4 + title: A full training + - local: chapter3/5 + title: Fine-tuning, Check! + - local: chapter3/6 + title: End-of-chapter quiz + quiz: 3 + +- title: 4. Sharing models and tokenizers + sections: + - local: chapter4/1 + title: The Hugging Face Hub + - local: chapter4/2 + title: Using pretrained models + - local: chapter4/3 + title: Sharing pretrained models + - local: chapter4/4 + title: Building a model card + - local: chapter4/5 + title: Part 1 completed! + - local: chapter4/6 + title: End-of-chapter quiz + quiz: 4 + +- title: 5. The 🤗 Datasets library + sections: + - local: chapter5/1 + title: Introduction + - local: chapter5/2 + title: What if my dataset isn't on the Hub? + - local: chapter5/3 + title: Time to slice and dice + - local: chapter5/4 + title: Big data? 🤗 Datasets to the rescue! + - local: chapter5/5 + title: Creating your own dataset + - local: chapter5/6 + title: Semantic search with FAISS + - local: chapter5/7 + title: 🤗 Datasets, check! + - local: chapter5/8 + title: End-of-chapter quiz + quiz: 5 + +- title: 6. The 🤗 Tokenizers library + sections: + - local: chapter6/1 + title: Introduction + - local: chapter6/2 + title: Training a new tokenizer from an old one + - local: chapter6/3 + title: Fast tokenizers' special powers + - local: chapter6/3b + title: Fast tokenizers in the QA pipeline + - local: chapter6/4 + title: Normalization and pre-tokenization + - local: chapter6/5 + title: Byte-Pair Encoding tokenization + - local: chapter6/6 + title: WordPiece tokenization + - local: chapter6/7 + title: Unigram tokenization + - local: chapter6/8 + title: Building a tokenizer, block by block + - local: chapter6/9 + title: Tokenizers, check! + - local: chapter6/10 + title: End-of-chapter quiz + quiz: 6 + +- title: 7. Main NLP tasks + sections: + - local: chapter7/1 + title: Introduction + - local: chapter7/2 + title: Token classification + - local: chapter7/3 + title: Fine-tuning a masked language model + - local: chapter7/4 + title: Translation + - local: chapter7/5 + title: Summarization + - local: chapter7/6 + title: Training a causal language model from scratch + - local: chapter7/7 + title: Question answering + - local: chapter7/8 + title: Mastering NLP + - local: chapter7/9 + title: End-of-chapter quiz + quiz: 7 + +- title: 8. How to ask for help + sections: + - local: chapter8/1 + title: Introduction + - local: chapter8/2 + title: What to do when you get an error + - local: chapter8/3 + title: Asking for help on the forums + - local: chapter8/4 + title: Debugging the training pipeline + local_fw: { pt: chapter8/4, tf: chapter8/4_tf } + - local: chapter8/5 + title: How to write a good issue + - local: chapter8/6 + title: Part 2 completed! + - local: chapter8/7 + title: End-of-chapter quiz + quiz: 8 + +- title: Hugging Face Course Event + sections: + - local: event/1 + title: Part 2 Release Event From ea10974251db79521fc79a333d363565f50850dd Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Sat, 2 Apr 2022 23:55:54 +0900 Subject: [PATCH 03/73] Fix the issue #80 --- chapters/ko/_toctree.yml | 155 ++------------------------------------- 1 file changed, 5 insertions(+), 150 deletions(-) diff --git a/chapters/ko/_toctree.yml b/chapters/ko/_toctree.yml index db8e22827..0bdd36db3 100644 --- a/chapters/ko/_toctree.yml +++ b/chapters/ko/_toctree.yml @@ -1,7 +1,7 @@ -- title: 0. Setup +- title: 0. 초기 설정 sections: - local: chapter0/1 - title: Introduction + title: 강의 소개 - title: 1. 트랜스포머 모델 sections: @@ -20,154 +20,9 @@ - local: chapter1/7 title: 시퀀스-투-시퀀스 모델 - local: chapter1/8 - title: 편견과 한계점 + title: 편향과 한계 - local: chapter1/9 - title: 정리 + title: 단원 정리 - local: chapter1/10 title: 단원 마무리 퀴즈 - quiz: 1 - -- title: 2. Using 🤗 Transformers - sections: - - local: chapter2/1 - title: Introduction - - local: chapter2/2 - title: Behind the pipeline - - local: chapter2/3 - title: Models - - local: chapter2/4 - title: Tokenizers - - local: chapter2/5 - title: Handling multiple sequences - - local: chapter2/6 - title: Putting it all together - - local: chapter2/7 - title: Basic usage completed! - - local: chapter2/8 - title: End-of-chapter quiz - quiz: 2 - -- title: 3. Fine-tuning a pretrained model - sections: - - local: chapter3/1 - title: Introduction - - local: chapter3/2 - title: Processing the data - - local: chapter3/3 - title: Fine-tuning a model with the Trainer API or Keras - local_fw: { pt: chapter3/3, tf: chapter3/3_tf } - - local: chapter3/4 - title: A full training - - local: chapter3/5 - title: Fine-tuning, Check! - - local: chapter3/6 - title: End-of-chapter quiz - quiz: 3 - -- title: 4. Sharing models and tokenizers - sections: - - local: chapter4/1 - title: The Hugging Face Hub - - local: chapter4/2 - title: Using pretrained models - - local: chapter4/3 - title: Sharing pretrained models - - local: chapter4/4 - title: Building a model card - - local: chapter4/5 - title: Part 1 completed! - - local: chapter4/6 - title: End-of-chapter quiz - quiz: 4 - -- title: 5. The 🤗 Datasets library - sections: - - local: chapter5/1 - title: Introduction - - local: chapter5/2 - title: What if my dataset isn't on the Hub? - - local: chapter5/3 - title: Time to slice and dice - - local: chapter5/4 - title: Big data? 🤗 Datasets to the rescue! - - local: chapter5/5 - title: Creating your own dataset - - local: chapter5/6 - title: Semantic search with FAISS - - local: chapter5/7 - title: 🤗 Datasets, check! - - local: chapter5/8 - title: End-of-chapter quiz - quiz: 5 - -- title: 6. The 🤗 Tokenizers library - sections: - - local: chapter6/1 - title: Introduction - - local: chapter6/2 - title: Training a new tokenizer from an old one - - local: chapter6/3 - title: Fast tokenizers' special powers - - local: chapter6/3b - title: Fast tokenizers in the QA pipeline - - local: chapter6/4 - title: Normalization and pre-tokenization - - local: chapter6/5 - title: Byte-Pair Encoding tokenization - - local: chapter6/6 - title: WordPiece tokenization - - local: chapter6/7 - title: Unigram tokenization - - local: chapter6/8 - title: Building a tokenizer, block by block - - local: chapter6/9 - title: Tokenizers, check! - - local: chapter6/10 - title: End-of-chapter quiz - quiz: 6 - -- title: 7. Main NLP tasks - sections: - - local: chapter7/1 - title: Introduction - - local: chapter7/2 - title: Token classification - - local: chapter7/3 - title: Fine-tuning a masked language model - - local: chapter7/4 - title: Translation - - local: chapter7/5 - title: Summarization - - local: chapter7/6 - title: Training a causal language model from scratch - - local: chapter7/7 - title: Question answering - - local: chapter7/8 - title: Mastering NLP - - local: chapter7/9 - title: End-of-chapter quiz - quiz: 7 - -- title: 8. How to ask for help - sections: - - local: chapter8/1 - title: Introduction - - local: chapter8/2 - title: What to do when you get an error - - local: chapter8/3 - title: Asking for help on the forums - - local: chapter8/4 - title: Debugging the training pipeline - local_fw: { pt: chapter8/4, tf: chapter8/4_tf } - - local: chapter8/5 - title: How to write a good issue - - local: chapter8/6 - title: Part 2 completed! - - local: chapter8/7 - title: End-of-chapter quiz - quiz: 8 - -- title: Hugging Face Course Event - sections: - - local: event/1 - title: Part 2 Release Event + quiz: 1 \ No newline at end of file From 2653c29a35df313144311ab8ad08cb240d21342f Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Sat, 2 Apr 2022 23:56:44 +0900 Subject: [PATCH 04/73] Single expression changed --- chapters/ko/chapter1/1.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ko/chapter1/1.mdx b/chapters/ko/chapter1/1.mdx index 92fda2f4f..8628ea321 100644 --- a/chapters/ko/chapter1/1.mdx +++ b/chapters/ko/chapter1/1.mdx @@ -31,7 +31,7 @@ 저자 소개: -**Matthew Carrigan**은 Hugging Face의 머신 러닝 엔지니어입니다. 현재 아일랜드 더블린에 살고 있으며, 이전에는 [Parse.ly](http://parse.ly/) 에서 ML 엔지니어로, 그 전에는 Trinity Collge Dublin에서 박사 과정 이후 연구원으로 근무했습니다. 우리가 기존 인공지능 아키텍쳐를 확장하여 사람 수준에는 도달하지 못할거라고 생각하지만, 그럼에도 불로장생 로봇에 대해 큰 기대를 갖고 있습니다. +**Matthew Carrigan**은 Hugging Face의 머신 러닝 엔지니어입니다. 현재 아일랜드 더블린에 살고 있으며, 이전에는 [Parse.ly](http://parse.ly/) 에서 ML 엔지니어로, 그 전에는 Trinity Collge Dublin에서 박사 과정 이후 연구원으로 근무했습니다. 우리가 기존 인공지능 아키텍쳐를 확장하여 사람 수준에는 도달하지 못할거라고 생각하지만, 그럼에도 불멸 로봇(immortality robot)에 대해 큰 기대를 갖고 있습니다. **Lysandre Debut**는 Hugging Face의 머신 러닝 엔지니어이며 초창기부터 🤗 Transformers 라이브러리 작업을 함께 했습니다. 아주 간단한 API를 개발하여 모두가 NLP를 쉽게 사용할 수 있도록 하는 목표를 갖고 있습니다. From f3073c204c96d4fa40297f324a25f1de81143d7b Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Sat, 2 Apr 2022 23:57:17 +0900 Subject: [PATCH 05/73] ko/chapter1 finished --- chapters/ko/chapter1/10.mdx | 253 ++++++++++++++++++++++++++ chapters/ko/chapter1/2.mdx | 21 +++ chapters/ko/chapter1/3.mdx | 350 ++++++++++++++++++++++++++++++++++++ chapters/ko/chapter1/4.mdx | 167 +++++++++++++++++ chapters/ko/chapter1/5.mdx | 17 ++ chapters/ko/chapter1/6.mdx | 16 ++ chapters/ko/chapter1/7.mdx | 16 ++ chapters/ko/chapter1/8.mdx | 34 ++++ chapters/ko/chapter1/9.mdx | 11 ++ 9 files changed, 885 insertions(+) create mode 100644 chapters/ko/chapter1/10.mdx create mode 100644 chapters/ko/chapter1/2.mdx create mode 100644 chapters/ko/chapter1/3.mdx create mode 100644 chapters/ko/chapter1/4.mdx create mode 100644 chapters/ko/chapter1/5.mdx create mode 100644 chapters/ko/chapter1/6.mdx create mode 100644 chapters/ko/chapter1/7.mdx create mode 100644 chapters/ko/chapter1/8.mdx create mode 100644 chapters/ko/chapter1/9.mdx diff --git a/chapters/ko/chapter1/10.mdx b/chapters/ko/chapter1/10.mdx new file mode 100644 index 000000000..69cf78baf --- /dev/null +++ b/chapters/ko/chapter1/10.mdx @@ -0,0 +1,253 @@ + + +# 단원 마무리 퀴즈 + +이번 단원에서는 정말 많은 내용을 다뤘습니다! 그러니 모든 디테일을 이해하지 못했다고 해서 좌절하지 마세요. 다음 단원은 내부 작동 방식을 이해하는 데에 도움이 될거에요. + +그래도 우선, 이번 단원에서 배운 내용에 대해 확인해보는 시간을 갖도록 하겠습니다! + +### 1. Hub에서 `roberta-large-mnli` 체크포인트를 검색해 보세요. 이 모델은 어떤 작업을 수행하나요? + +roberta-large-mnli page." +}, +{ +text: "텍스트 분류", +explain: "더 정확하게 말하면, 이 모델은 두 문장이 논리적으로 타당한지 세 가지 레이블(모순, 함의, 중립)로 분류합니다. 이러한 문제를 자연어 추론(natural language inference)이라고 부릅니다.", +correct: true +}, +{ +text: "텍스트 생성", +explain: "이 페이지를 다시 확인하세요 roberta-large-mnli page." +} +]} +/> + +### 2. 다음 코드는 무엇을 반환하나요? + +``` +from transformers import pipeline + +ner = pipeline("ner", grouped_entities=True) +ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") + +``` + +sentiment-analysis pipeline." +}, +{ +text: "이 문장을 완성할, 생성 텍스트를 반환합니다.", +explain: "This is incorrect — it would be a text-generation pipeline.", +}, +{ +text: "사람, 기관, 장소 등을 나타내는 단어들을 반환합니다.", +explain: "Furthermore, with grouped_entities=True, it will group together the words belonging to the same entity, like \"Hugging Face\".", +correct: true +} +]} +/> + +### 3. 다음 예제 코드에서 ... 대신 무엇이 들어가야 할까요? + +``` +from transformers import pipeline + +filler = pipeline("fill-mask", model="bert-base-cased") +result = filler("...") + +``` + +", +explain: "오답입니다. 여기 bert-base-cased 모델 카드를 보시고 다시 도전해보세요." +}, +{ +text: "[MASK]", +explain: "정답! 이 모델의 마스크 토큰은 [MASK]입니다.", +correct: true +}, +{ +text: "man", +explain: "오답입니다. 이 pipeline은 마스킹된 단어를 채워야하기에 어딘가에는 마스크 토큰이 있어야겠죠?" +} +]} +/> + +### 4. 다음 코드가 작동하지 않는 이유가 무엇일까요? + +``` +from transformers import pipeline + +classifier = pipeline("zero-shot-classification") +result = classifier("This is a course about the Transformers library") + +``` + +candidate_labels=[...].", +correct: true +}, +{ +text: "한 문장이 아니라, 여러 문장을 pipeline에 넣어주어야 합니다.", +explain: "틀렸지만, 다른 pipeline과 마찬가지로 제대로 사용한다면 물론 여러 리스트의 문장도 입력으로 넣어줄 수 있습니다." +}, +{ +text: "늘 그렇듯 🤗 Transformers 라이브러리가 또 고장난거 아닌가요?", +explain: "못 들은 걸로 하겠습니다!" +}, +{ +text: "위의 문장은 너무 짧아서, 더 긴 문장을 입력해야 합니다.", +explain: "오답입니다. 매우 긴 텍스트는 pipeline에서 처리할 때 잘리게 되는 것을 명심하세요." +} +]} +/> + +### 5. "전이 학습(transfer learning)"이 무엇인가요? + + + +### 6. 언어 모델은 일반적으로 사전 학습시에 레이블이 필요하지 않습니다. 이 문장은 참일까요 거짓일까요? + +자가 지도(self-supervised) 방식입니다. 이는 다음 단어 예측 혹은 마스킹 된 단어 채우기 등과 같이 입력으로부터 자동으로 레이블을 생성하는 것을 의미합니다.", +correct: true +}, +{ +text: "거짓", +explain: "정답이 아닙니다." +} +]} +/> + +### 7. 다음 중 “모델(model)”, “구조(architecture)”, “가중치(weights)”에 대해 가장 잘 설명한 것을 고르세요. + + + +### 8. 다음 중 어떤 모델이 텍스트를 생성하여 프롬트(prompt)를 완성시키는 데에 가장 적합할까요? + + + +### 9. 다음 중 어떤 모델이 텍스트 요약에 가장 적합할까요? + + + +### 10. 다음 중 어떤 모델이 입력 텍스트를 특정 레이블로 분류하는 데에 가장 적합할까요? + + + +### 11. 다음 중 모델이 편향성(bias)을 갖게 되는 데에 가장 가능성 있는 원인을 모두 고르세요. + + \ No newline at end of file diff --git a/chapters/ko/chapter1/2.mdx b/chapters/ko/chapter1/2.mdx new file mode 100644 index 000000000..3dc873652 --- /dev/null +++ b/chapters/ko/chapter1/2.mdx @@ -0,0 +1,21 @@ +# 자연어 처리(Natural Language Processing) + +트랜스포머 모델을 공부하기에 앞서 자연어 처리(NLP)가 무엇인지, 그리고 왜 NLP가 중요한지 빠르고 간단하게 살펴볼게요. + +## NLP가 무엇인가요? + +NLP(Natural Language Processing)란 사람의 언어와 관련된 모든 것을 이해하는 데에 중점을 둔 언어학 및 머신 러닝 분야를 말합니다. NLP의 목적은 단순히 하나의 개별 단어를 이해하는 것을 넘어, 해당 단어들의 문맥을 이해하는 것입니다. + +아래는 가장 일반적인 NLP 작업과 그 예시입니다: + +- **전체 문장 분류**: 리뷰에 드러난 감정 파악하기, 스팸 메일 분류하기, 문장이 문법적으로 올바른지 혹은 문장 쌍이 논리적으로 관련이 있는지 없는지 결정하기 +- **문장 내 단어 분류**: 문장 구성 성분(명사, 동사, 형용사 등) 혹은 개체명(사람, 장소, 기관) 식별하기 +- **텍스트 컨텐츠 생성**: 자동 생성 텍스트로 프롬프트 작성하기, 텍스트 내 마스킹 된 단어의 빈칸 채우기 +- **텍스트 안에서 정답 추출하기**: 지문과 질의가 주어질 때 지문에 주어진 정보를 이용해 질의에 대한 정답 추출하기 +- **입력 텍스트로부터 새로운 문장 생성하기**: 입력 텍스트를 다른 언어로 번역하거나, 요약하기 + +하지만 NLP는 위와 같이 텍스트에만 제한되지 않습니다. NLP에서는 오디오 샘플의 스크립트 및 이미지의 설명문 생성과 같이 음성 인식과 컴퓨터 비전 분야에서의 까다로운 문제도 다룹니다. + +## 왜 NLP가 어렵나요? + +컴퓨터와 사람은 서로 정보를 처리하는 방식이 다릅니다. 이를테면, “나는 배고파”라는 문장을 읽을 때 우리는 바로 그 의미를 이해할 수 있습니다. 마찬가지로 “나는 배고파”, “나 슬퍼”와 같은 문장 쌍이 주어질 때, 두 문장이 얼마나 유사한지 쉽게 판단할 수 있습니다. 그러나, 머신 러닝(ML) 모델은 사람만큼 이를 쉽게 할 수 없습니다. 우선 모델이 텍스트를 학습할 수 있도록 텍스트가 처리 과정을 거쳐야 하는데, 사람의 언어 체계는 매우 복잡하기 때문에 이러한 처리가 어떻게 이루어져야 하는지 면밀히 생각해야 합니다. 따라서 텍스트 표현 방법과 관련한 수많은 연구가 진행되어 왔고, 다음 단원에서 여러분들에게 그 중 몇 가지 방법들을 소개해드리겠습니다. \ No newline at end of file diff --git a/chapters/ko/chapter1/3.mdx b/chapters/ko/chapter1/3.mdx new file mode 100644 index 000000000..cd82ed78d --- /dev/null +++ b/chapters/ko/chapter1/3.mdx @@ -0,0 +1,350 @@ +# 트랜스포머로 무엇을 할 수 있나요? + + + +이번 장에서는 트랜스포머(Transformer) 모델을 사용해 무엇을 할 수 있는지 같이 살펴보고, 🤗 Transformers 라이브러리 툴의 첫 사용을 `pipeline()` 함수와 함께 시작하겠습니다. + + +👀 오른쪽 상단에 Open in Colab 버튼이 보이시나요? 버튼을 클릭하면 이번 장에서 사용한 모든 코드 샘플들을 Google Colab notebook을 통해 열 수 있습니다. 이 버튼은 예제 코드를 포함하는 모든 장에서 나타날 거에요. + +로컬 환경에서 예제 코드를 실행하려면 setup을 살펴보세요. + + +## 트랜스포머는 어디에나 있어요! + +트랜스포머 모델은 이전 단원에서 언급한 작업과 같은 모든 NLP 문제를 해결하기 위해 사용됩니다. 아래에 Hugging Face와 트랜스포머 모델을 이용하고 다시 모델을 공유하여 커뮤니티에 기여하는 기업과 기관들이 보이네요: + +Companies using Hugging Face + +[🤗 Transformers library](https://github.com/huggingface/transformers)는 이렇게 공유한 모델을 사용하고 구축하는 기능들을 제공합니다. [Model Hub](https://huggingface.co/models)에서는 모두가 다운로드 받아 쓸 수 있는 수 천 개의 사전 학습된 모델들이 여러분을 기다리고 있습니다. 여러분만의 모델을 Hub에 업로드하는 것 또한 가능합니다! + + + +⚠️ The Hugging Face Hub에는 트랜스포머 모델만 있지 않아요. 누구든지 어떠한 종류의 모델이나 데이터를 공유할 수 있답니다! Create a huggingface.co 링크에서 계정을 만들고 모든 기능을 사용해보세요! + + +트랜스포머 모델 안에서 무슨 일이 벌어지는지 알아보기 전에, 트랜스포머가 NLP 문제 해결에 어떻게 사용되는지 몇 가지 흥미로운 예시들을 살펴보겠습니다. + +## Pipeline으로 작업하기 + + + +🤗 Transformers 라이브러리의 가장 기본 객체는 `pipeline()` 함수입니다. 이 함수는 모델에 있어서 필수 과정인 전처리와 후처리 과정을 모델과 연결하고, 우리가 바로 어떠한 텍스트 입력을 넣든 원하는 답을 얻을 수 있도록 합니다: + +``` +from transformers import pipeline + +classifier = pipeline("sentiment-analysis") +classifier("I've been waiting for a HuggingFace course my whole life.") + +``` + +``` +[{'label': 'POSITIVE', 'score': 0.9598047137260437}] + +``` + +아래와 같이 여러 문장을 동시에 넣을 수도 있습니다! + +``` +classifier( + ["I've been waiting for a HuggingFace course my whole life.", "I hate this so much!"] +) + +``` + +``` +[{'label': 'POSITIVE', 'score': 0.9598047137260437}, + {'label': 'NEGATIVE', 'score': 0.9994558095932007}] + +``` + +기본적으로 이 pipeline은 영어 감정 분석에 미세 조정(fine-tune)된 사전 학습 모델을 선택합니다. 여기서 `classifier` 객체를 생성할 때 모델이 다운로드 되며 캐싱(caching)이 이루어지는데, 재실행 시 캐싱된 모델을 사용하게 되어 모델을 다시 다운로드 하지 않습니다. + +텍스트를 pipeline에 넣을 때 다음과 같은 세 가지 주요 과정을 거칩니다: + +1. 텍스트가 모델이 이해할 수 있는 형태로 전처리 과정을 거칩니다. +2. 전처리된 입력이 모델 입력으로 들어갑니다. +3. 모델의 예측값이 후처리를 거쳐, 사람이 이해할 수 있는 형태로 반환됩니다. + +현재까지 사용할 수 있는 pipeline([available pipelines](https://huggingface.co/transformers/main_classes/pipelines.html))은 다음과 같습니다: + +- `feature-extraction` : 특징 추출 (텍스트에 대한 벡터 표현 추출) +- `fill-mask` : 마스크 채우기 +- `ner` : 개체명 인식 (named entity recognition) +- `question-answering` : 질의 응답 +- `sentiment-analysis` : 감정 분석 +- `summarization` : 요약 +- `text-generation` : 텍스트 생성 +- `translation` : 번역 +- `zero-shot-classification` : 제로샷 분류 + +이 중 몇 가지를 같이 살펴볼까요? + +## 제로샷 분류(Zero-shot classification) + +레이블이 없는 텍스트를 분류하는 더 까다로운 과제부터 시작하겠습니다. 텍스트에 레이블을 다는 것은 시간이 많이 소요되고 도메인 지식이 필요하기 때문에 이러한 작업은 실제 프로젝트에서 아주 흔한 상황입니다. 이러한 상황에서 `zero-shot-classification` pipeline은 매우 유용합니다. 제로샷 pipeline은 사전 학습된 모델에 의존하지 않고도 분류 작업에 사용할 레이블을 특정할 수 있도록 합니다. 위의 예시에서 모델이 긍정(positive)과 부정(negative)의 두 레이블을 분류하는 샘플을 살펴보았는데, 제로샷 pipeline을 통해서는 어떠한 레이블 세트에 대해서도 분류 작업을 수행할 수 있습니다. + +``` +from transformers import pipeline + +classifier = pipeline("zero-shot-classification") +classifier( + "This is a course about the Transformers library", + candidate_labels=["education", "politics", "business"], +) + +``` + +``` +{'sequence': 'This is a course about the Transformers library', + 'labels': ['education', 'business', 'politics'], + 'scores': [0.8445963859558105, 0.111976258456707, 0.043427448719739914]} + +``` + +이러한 pipeline이 제로샷(zero-shot)이라 불리는 이유는 여러분의 데이터에 미세 조정(fine-tune)하지 않고도 사용할 수 있기 때문입니다. 제로샷은 여러분이 원하는 어떠한 레이블 목록에 대해서도 확률 점수를 바로 반환합니다. + + + +**✏️ 직접 해보기!** 여러분만의 시퀀스와 레이블로 모델이 어떻게 동작하는지 확인해보세요. + + + +## 텍스트 생성(Text generation) + +지금부터 pipeline을 사용해 텍스트를 생성하는 방법을 알아보겠습니다. 여기서의 핵심은 프롬트를 모델에 제공하면 모델이 나머지 텍스트를 생성하여 이를 자동으로 완성하는 것입니다. 이는 스마트폰의 텍스트 자동 완성 기능과 유사합니다. 텍스트 생성에는 랜덤하게 결과를 생성하는 과정이 포함되어 있어서 여러분이 아래와 같이 동일하게 입력을 넣어도 매번 다른 결과가 나올 수 있습니다. + +``` +from transformers import pipeline + +generator = pipeline("text-generation") +generator("In this course, we will teach you how to") + +``` + +``` +[{'generated_text': 'In this course, we will teach you how to understand and use ' + 'data flow and data interchange when handling user data. We ' + 'will be working with one or more of the most commonly used ' + 'data flows — data flows of various types, as seen by the ' + 'HTTP'}] + +``` + +`num_return_sequences` 인자(argument)를 통해 몇 개의 다른 출력 결과를 생성할지 조절할 수 있고, `max_length` 인자를 통해 출력 텍스트의 총 길이를 설정할 수 있습니다. + + + +**✏️ 직접 해보기!** `num_return_sequences` 와 `max_length` 인자를 설정해 15 단어의 서로 다른 두 개의 문장을 출력해보세요. + + + +## Pipeline에 Hub의 모델 적용하기 + +지금까지 예제들은 해당 작업에 대해 기본 모델들을 사용했지만, 특정 모델을 Hub에서 선택해 텍스트 생성과 같은 특정 작업에 대한 파이프라인에서도 사용할 수 있습니다. [Model Hub](https://huggingface.co/models) 페이지의 화면 왼쪽에 태그를 클릭하여 해당 태그 내용 작업을 지원하는 모델을 확인할 수 있습니다. [다음](https://huggingface.co/models?pipeline_tag=text-generation)과 같은 페이지로 이동하게 됩니다. + +함께 `[distilgpt2](https://huggingface.co/distilgpt2)` 모델을 사용해봐요! 위의 예제에서 사용한 pipeline에서 아래와 같이 로드 할 수 있습니다: + +``` +from transformers import pipeline + +generator = pipeline("text-generation", model="distilgpt2") +generator( + "In this course, we will teach you how to", + max_length=30, + num_return_sequences=2, +) + +``` + +``` +[{'generated_text': 'In this course, we will teach you how to manipulate the world and ' + 'move your mental and physical capabilities to your advantage.'}, + {'generated_text': 'In this course, we will teach you how to become an expert and ' + 'practice realtime, and with a hands on experience on both real ' + 'time and real'}] + +``` + +언어 태그를 클릭하여 해당 언어를 지원 및 생성하는 모델을 구체적으로 검색할 수 있습니다. Model Hub에는 다양한 언어를 지원하는 다국어 모델의 체크포인트(모델의 파라미터 값) 또한 포함하고 있습니다. + +모델을 클릭하여 선택하면 온라인에서 바로 사용이 가능한 위젯을 확인할 수 있고, 이를 통해 모델을 다운로드 받기 전에 모델의 기능을 빠르게 테스트 해볼 수 있습니다. + + + +**✏️ 직접 해보기!** 영어를 제외한 다른 언어를 생성하는 모델을 검색해보세요. 위젯을 자유롭게 사용해 보시고 pipeline을 사용해보세요! + + + +### 추론(Inference) API + +모든 모델들은 Hugging Face [웹사이트](https://huggingface.co/)에서 제공하는 추론 API를 통해 여러분의 브라우저상에서 직접 테스트가 가능합니다. 이 페이지를 통해 직접 나만의 텍스트를 입력하고 모델이 입력 데이터를 처리하는걸 구경하며 모델을 갖고 놀 수 있습니다. + +위젯을 구동하는 추론 API는 간편한 워크플로우를 가능하게 하는 유료 버전의 제품으로도 이용 가능합니다. 자세한 사항은 [가격 페이지](https://huggingface.co/pricing)를 참고해주세요. + +## 마스크 채우기(Mask filling) + +다음으로 사용해볼 pipeline은 마스크 채우기(`fill-mask`)입니다. 이 작업의 핵심 아이디어는 주어진 텍스트의 빈칸을 채우기입니다: + +``` +from transformers import pipeline + +unmasker = pipeline("fill-mask") +unmasker("This course will teach you all about models.", top_k=2) + +``` + +``` +[{'sequence': 'This course will teach you all about mathematical models.', + 'score': 0.19619831442832947, + 'token': 30412, + 'token_str': ' mathematical'}, + {'sequence': 'This course will teach you all about computational models.', + 'score': 0.04052725434303284, + 'token': 38163, + 'token_str': ' computational'}] + +``` + +몇 개의 가능성 있는 토큰을 표시할지 `top_k` 인자를 통해 조절합니다. 여기서 모델이 특이한 `` 단어를 채우는 것을 주목하세요. 이는 마스크 토큰(mask token)이라고 부릅니다. 다른 마스크 채우기 모델들은 다른 형태의 마스크 토큰을 사용할 수 있어서 다른 모델을 탐색할 때 항상 마스크 단어를 확인해야 합니다. 위젯에서 사용되는 마스크 단어를 보고 이를 확인해 볼 수 있습니다. + + + +**✏️ 직접 해보기!** Hub에서 `bert-base-cased` 를 검색해 보고 Inference API 위젯으로 마스크 단어를 확인해 보세요. 이 모델이 위의 `pipeline` 예제에서 사용한 문장에 대해 어떻게 예측하나요? + + + +## 개체명 인식(Named entity recognition) + +개체명 인식(NER)은 모델이 입력 텍스트의 어느 부분이 사람, 장소, 기관 등과 같은 개체에 해당하는지 찾는 작업입니다. 예제를 통해 확인해 봅시다: + +``` +from transformers import pipeline + +ner = pipeline("ner", grouped_entities=True) +ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") + +``` + +``` +[{'entity_group': 'PER', 'score': 0.99816, 'word': 'Sylvain', 'start': 11, 'end': 18}, + {'entity_group': 'ORG', 'score': 0.97960, 'word': 'Hugging Face', 'start': 33, 'end': 45}, + {'entity_group': 'LOC', 'score': 0.99321, 'word': 'Brooklyn', 'start': 49, 'end': 57} +] + +``` + +모델이 정확하게 Sylvain을 사람(PER)으로, Hugging Face를 기관(ORG)으로, Brooklyn을 장소(LOC)으로 예측했네요! + +Pipeline을 생성하는 함수에 `grouped_entities=True` 옵션을 전달하면 pipeline이 같은 개체에 해당하는 문장 부분을 다시 그룹화합니다. 이 경우 모델은 여러 단어로 구성된 단어임에도 “Hugging”과 “Face”를 하나의 기관으로 정확히 분류하게 됩니다. 다음 단원에서도 확인하겠지만, 놀랍게도 전처리 과정에서 각 단어들은 더 작은 부분으로 쪼개지게 됩니다. 예를 들어 `Sylvain` 이라는 단어는 `S`, `##yl`, `##va`, `##in` 이렇게 네 조각으로 쪼개집니다. 후처리 단계에서 pipeline은 이 조각들을 멋지게 재그룹화합니다. + + + +**✏️ 직접 해보기!** Model Hub에서 영어 품사 태깅(part-of-speech tagging, 줄여서 POS)이 가능한 모델을 찾아보세요. 이 모델이 위의 예시 문장으로 무엇을 예측하나요? + + + +## 질의 응답(Question-answering) + +질의 응답(`question-answering`) pipeline은 주어진 지문(context)의 정보를 활용하여 질문에 답을 합니다: + +``` +from transformers import pipeline + +question_answerer = pipeline("question-answering") +question_answerer( + question="Where do I work?", + context="My name is Sylvain and I work at Hugging Face in Brooklyn", +) + +``` + +``` +{'score': 0.6385916471481323, 'start': 33, 'end': 45, 'answer': 'Hugging Face'} + +``` + +본 pipeline은 답을 새롭게 생성하지 않고 주어진 지문에서 정답을 추출하는 방식임을 잘 기억하세요. + +## 요약(Summarization) + +요약은 참조 텍스트의 모든(혹은 대부분) 중요한 특징을 유지한 채로 텍스트를 짧게 줄이는 작업입니다. 아래 예제를 확인하세요: + +``` +from transformers import pipeline + +summarizer = pipeline("summarization") +summarizer( + """ + America has changed dramatically during recent years. Not only has the number of + graduates in traditional engineering disciplines such as mechanical, civil, + electrical, chemical, and aeronautical engineering declined, but in most of + the premier American universities engineering curricula now concentrate on + and encourage largely the study of engineering science. As a result, there + are declining offerings in engineering subjects dealing with infrastructure, + the environment, and related issues, and greater concentration on high + technology subjects, largely supporting increasingly complex scientific + developments. While the latter is important, it should not be at the expense + of more traditional engineering. + + Rapidly developing economies such as China and India, as well as other + industrial countries in Europe and Asia, continue to encourage and advance + the teaching of engineering. Both China and India, respectively, graduate + six and eight times as many traditional engineers as does the United States. + Other industrial countries at minimum maintain their output, while America + suffers an increasingly serious decline in the number of engineering graduates + and a lack of well-educated engineers. +""" +) + +``` + +``` +[{'summary_text': ' America has changed dramatically during recent years . The ' + 'number of engineering graduates in the U.S. has declined in ' + 'traditional engineering disciplines such as mechanical, civil ' + ', electrical, chemical, and aeronautical engineering . Rapidly ' + 'developing economies such as China and India, as well as other ' + 'industrial countries in Europe and Asia, continue to encourage ' + 'and advance engineering .'}] + +``` + +텍스트 생성과 마찬가지로 `max_length` 와 `min_length` 를 정할 수 있습니다. + +## 번역(Translation) + +For translation, you can use a default model if you provide a language pair in the task name (such as `"translation_en_to_fr"`), but the easiest way is to pick the model you want to use on the [Model Hub](https://huggingface.co/models). Here we'll try translating from French to English: + +번역의 경우 (`"translation_en_to_fr"` 와 같이) 작업명에 언어 쌍을 넣어준다면 기본 모델을 사용할 수 있지만, [Model Hub](https://huggingface.co/models)에서 원하는 모델을 고르는 방식이 가장 간단합니다. 여기서는 프랑스어에서 영어로 번역을 시도해 보겠습니다: + +``` +from transformers import pipeline + +translator = pipeline("translation", model="Helsinki-NLP/opus-mt-fr-en") +translator("Ce cours est produit par Hugging Face.") + +``` + +``` +[{'translation_text': 'This course is produced by Hugging Face.'}] + +``` + +텍스트 생성 및 요약에서와 마찬가지로, `max_length` 혹은 `min_length` 를 지정하여 결과를 출력할 수 있습니다. + + + +**✏️ 직접 해보기!** 다른 언어의 번역 모델을 검색해보고 위의 문장을 몇 가지 다른 언어들로 번역해 봅시다. + + + +The pipelines shown so far are mostly for demonstrative purposes. They were programmed for specific tasks and cannot perform variations of them. In the next chapter, you'll learn what's inside a `pipeline()` function and how to customize its behavior. + +지금까지 보여드린 pipeline들은 대부분 특정 작업을 위해 프로그래밍된, 다양한 변형 작업을 수행할 수 없는 데모용 pipeline입니다. 다음 단원에서는 `pipeline()` 함수 내부를 살펴보고 그 동작을 사용자가 직접 설계하는 방법을 다루겠습니다. \ No newline at end of file diff --git a/chapters/ko/chapter1/4.mdx b/chapters/ko/chapter1/4.mdx new file mode 100644 index 000000000..b8b552039 --- /dev/null +++ b/chapters/ko/chapter1/4.mdx @@ -0,0 +1,167 @@ +# 트랜스포머는 어떻게 동작하나요? + +이번 단원에서는 트랜스포머(Transformer) 모델의 대략적인 구조를 알아보겠습니다. + +## 트랜스포머 역사 훑어보기 + +아래에 트랜스포머 모델의 (짧은) 역사 중 주요한 지점을 나타냈습니다: + +
+A brief chronology of Transformers models. + +
+ +[Transformer architecture](https://arxiv.org/abs/1706.03762)는 2017년 6월에 처음 소개되었습니다. 처음 연구 목적은 번역 작업 수행이었습니다. 이후로 다음과 같이 줄줄이 막강한 모델들이 세상에 등장했습니다: + +- **2018년 6월**: [GPT](https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf), 최초로 사전 학습된 트랜스포머 모델로 다양한 NLP 작업에 미세 조정(fine-tune)되도록 사용되었으며 SOTA(state-of-the-art) 성능 달성 +- **2018년 10월**: [BERT](https://arxiv.org/abs/1810.04805), 또 다른 거대 사전 학습 언어 모델로, 더 좋은 문장 요약을 위해 설계 (이번 단원과 다음 단원에서 더 자세히 알아봐요!) +- **2019년 2월**: [GPT-2](https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf), 더 좋은 성능(그리고 더 큰) 버전의 GPT로, 윤리적 문제로 인해 즉시 공개되지 못하였음 +- **2019년 10월**: [DistilBERT](https://arxiv.org/abs/1910.01108), BERT의 60% 빠른 속도에 메모리 측면에서 40% 가볍지만 BERT 성능의 97%를 재현하는 경량화 버전의 BERT +- **2019년 10월**: [BART](https://arxiv.org/abs/1910.13461) 와 [T5](https://arxiv.org/abs/1910.10683), 동일한 구조의 (처음으로) 원본 트랜스포머 모델의 구조를 그대로 따른 두 거대 사전학습 언어 모델 +- **2020년 5월**, [GPT-3](https://arxiv.org/abs/2005.14165), 미세 조정 없이도 (zero-shot learning이라 부름) 다양한 작업을 훌륭하게 수행하는 GPT-2의 더 큰 버전 + +This list is far from comprehensive, and is just meant to highlight a few of the different kinds of Transformer models. Broadly, they can be grouped into three categories: + +위 리스트는 단순히 서로 다른 종류의 트랜스포머 모델들 중 몇몇을 강조하기 위한 목록일 뿐, 포괄적이지 않습니다. 넓은 관점에서 트랜스포머 모델은 아래와 같이 세 카테고리로 그룹화 할 수 있습니다: + +- GPT-계열 (*Auto-regressive* 트랜스포머 모델로도 불림) +- BERT-계열 (*Auto-encoding* 트랜스포머 모델로도 불림) +- BART/T5-계열 (*Sequence-to-sequence* 트랜스포머 모델로도 불림) + +추후에 각 계열들에 대해 더 자세히 살펴보도록 하겠습니다. + +## 트랜스포머는 언어 모델입니다 + +위에 언급한 모델(GPT, BERT, BART, T5 등)들은 *언어 모델(language model)*로서 학습 되었습니다. 다르게 말하면 이 모델들은 스스로 지도하는 방식으로 수많은 텍스트에 대해 학습된 모델들입니다. 이러한 자가 지도 학습(self-supervised learning)은 학습의 목적이 모델 입력으로부터 자동으로 계산되는 방식을 말합니다. 결국 사람이 데이터에 레이블을 달지 않아도 학습이 가능한 것입니다! + +이러한 종류의 모델은 학습한 언어에 대해 통계 기반의 이해를 생성하지만 이는 몇몇 실생활 문제에 적합하지 않습니다. 이러한 이유로 사전 학습된 모델은 *전이 학습(transfer learning)*이라 불리는 과정을 거칩니다. 이 과정에서 모델은 특정 작업에 맞춰 지도적(supervised)인 방법, 즉 사람이 레이블을 추가한 데이터를 사용하는 방법으로 미세 조정(fine-tune)이 이루어지며 + +하나의 예시로 문장 내에서 이전 *n*개의 단어를 읽고 다음에 올 단어를 에측하는 문제를 들 수 있습니다. 이를 과거와 현재의 입력 정보를 이용하는 방식(미래에 올 입력 정보는 이용하지 않습니다)이기 때문에 *인과적 언어 모델링(causal language modeling)*이라고 부릅니다. + +
+Example of causal language modeling in which the next word from a sentence is predicted. + +
+ +다른 예시로 *마스크 언어 모델링(masked language modeling)*을 들 수 있습니다. 여기서 모델은 문장 내에 마스킹 된 단어를 예측합니다. + +
+Example of masked language modeling in which a masked word from a sentence is predicted. + +
+ +## 트랜스포머는 거대 모델입니다 + +(DistilBERT와 같은 몇몇 예외를 제외하고) 모델의 성능을 향상시키는 일반적인 전략은 사전 학습에 사용하는 모델의 크기와 데이터의 양을 늘리는 방식입니다. + +
+Number of parameters of recent Transformers models +
+ +불행히도 아주 아주 큰 모델의 경우, 학습을 위해 어마무시한 양의 데이터를 필요로 하여 시간과 컴퓨팅 리소스 관점에서 비용이 매우 많이 듭니다. 아래 그래프에서 볼 수 있듯이 이는 환경 오염 문제로 이어지기도 합니다. + +
+The carbon footprint of a large language model. + +
+ + + +위 비디오는 사전 학습 과정이 환경에 끼치는 부정적 영향을 꾸준히 줄이기 위해 노력하는 팀의 (초거대) 언어 모델 프로젝트를 소개합니다. 최적의 하이퍼파라미터를 찾기 위한 수많은 시도에는 아직 많은 여정이 남았습니다. + +매번 리서치 팀, 학생 기관, 기업 등등이 밑바닥부터 모델을 학습시킨다고 생각해보세요. 정말 어마어마한 글로벌 비용으로 이어지겠죠? + +이제 왜 언어 모델을 공유하는 것이 중요한지 아시겠죠? 학습된 가중치를 공유하고, 이미 학습된 가중치에 이를 차곡차곡 쌓아 올리는 방식으로 커뮤니티의 컴퓨팅 비용과 탄소 발자국을 줄일 수 있습니다. + +## 전이 학습(Transfer Learning) + + + +*사전 학습(Pretraining)*시에는 모델을 밑바닥부터 학습시키게 됩니다. 모델 가중치를 랜덤하게 초기화하고 사전 지식 없이 학습을 시작합니다. + +
+The pretraining of a language model is costly in both time and money. + +
+ +이러한 사전 학습은 엄청난 양의 데이터로 이루어지기 때문에 방대한 양의 코퍼스 데이터와 수 주 씩 걸리는 학습 시간을 필요로 하기도 합니다. + +하지만 *미세 조정(Fine-tuning)*은 모델이 사전 학습된 **이후에** 하는 학습을 의미합니다. 미세 조정을 하기 위해서 우선 사전 학습된 언어 모델을 가져오고, 여러분이 할 작업에 특화된 데이터셋을 이용해 추가 학습을 수행합니다. 잠깐만요, 그냥 한번에 최종 태스크에 맞춰 학습시키면 안될까요? 이렇게 하는 데에는 몇 가지 이유가 있습니다: + +- 사전 학습된 모델은 이미 미세 조정 데이터셋과 유사한 데이터셋으로 학습이 이루어진 상태입니다. 결국 모델이 사전 학습시에 얻은 지식(이를테면, NLP 문제에서 사전 학습된 모델이 얻게 되는 통계적 이해)을 십분 활용해 미세 조정에 활용할 수 있게 됩니다. +- 사전 학습된 모델은 이미 방대한 데이터로 학습되었기 떄문에 미세 조정에서는 원하는 성능을 얻기까지 적은 양의 데이터만 필요로 하게 됩니다. +- 위와 같은 이유로, 원하는 성능을 얻기까지 적은 시간과 리소스만 필요하게 됩니다. + +예시로, 영어로 사전 학습된 모델을 활용해 arXiv 코퍼스로 미세 조정하여 과학/연구 기반 모델을 만들 수 있습니다. 이 때 미세 조정에는 적은 양의 데이터만 필요할 것입니다. 여기서 사전 학습 과정에서 얻은 지식이 “전이”되었다고 하여 *전이 학습(transfer learning)*이라 부릅니다. + +
+The fine-tuning of a language model is cheaper than pretraining in both time and money. + +
+ +모델의 미세 조정은 이렇게 시간, 데이터, 경제, 그리고 환경 비용 측면에서 훨씬 저렴합니다. 뿐만 아니라 전체 사전 학습 과정보다 제약이 적기 때문에 다양한 방식의 미세 조정을 쉽고 빠르게 반복할 수 있습니다. + +이렇듯 엄청나게 많은 데이터를 확보하지 않은 이상 미세 조정 방식이 밑바닥부터 학습시키는 방식보다 더 좋은 결과를 낼 수 있습니다. 따라서 항상 여러분의 지금 작업 내용과 최대한 비슷한 사전 학습 모델을 불러와 미세 조정하세요! + +## 일반적인 구조 + +이번 섹션에서는 전반적인 트랜스포머 모델의 구조에 대해 알아보겠습니다. 설령 몇몇 개념을 이해하지 못하게 되더라도 걱정하지 마세요. 추후에 각 구성 요소를 자세하게 다루는 섹션이 있으니까요. + + + +## Introduction + +모델은 기본적으로 두 개의 블럭으로 이루어져 있습니다: + +- **인코더 (왼쪽)**: 인코더는 입력을 받아 입력(혹은 입력의 특징)을 구축합니다. 이는 인코더 모델이 입력을 이해하는 데에 최적화되어 있음을 의미합니다. +- **디코더 (오른쪽)**: 디코더는 인코더의 (특징) 표현과 또 다른 입력을 활용해 타겟 시퀀스를 생성합니다. 이는 디코더 모델이 출력을 생성하는 데에 최적화되어 있음을 의미합니다. + +
+Architecture of a Transformers models + +
+ +트랜스포머 모델의 각 파트는 태스크에 따라 다음과 같이 개별적으로 쓰일 수도 있습니다: + +- **인코더 모델(Encoder-only models)**: 문장 분류, 개체명 인식과 같이 입력에 대한 높은 이해를 요구하는 작업에 특화 +- **디코더 모델(Decoder-only models)**: 텍스트 생성과 같이 생성 관련 작업에 특화 +- **인코더-디코더(Encoder-decoder) 모델 또는 시퀀스-투-시퀀스 (Sequence-to-sequence) 모델**: 번역, 요약과 같이 입력을 필요로 하는 생성 관련 작업에 특화 + +다음 단원들에서 각각의 구조에 대해 더 깊게 살펴보도록 하겠습니다. + +## 어텐션 레이어(Attention layers) + +트랜스포머 모델의 중요한 특징은 *어텐션 레이어(attention layers)*라 불리는 특수한 레이어로 구성되었다는 점입니다. 사실, 트랜스포머 구조를 처음 소개한 논문 제목마저 ["Attention Is All You Need"](https://arxiv.org/abs/1706.03762)입니다! 어텐션 레이어의 디테일에 대해서는 추후 강의에서 자세히 다루겠지만, 우선은 이 레이어가 단어의 표현을 다룰 때 입력으로 넣어준 문장의 특정 단어에 어텐션(주의)을 기울이고 특정 단어는 무시하도록 알려준다는 사실을 기억하셔야 합니다. + +이러한 상황을 설명하기 위해 영어 텍스트를 프랑스어로 번역하는 작업을 생각해봅시다. “You like this course”라는 입력이 주어지면 번역 모델은 “like”라는 단어를 알맞게 번역하기 위해 인접한 단어 “You”에도 주의를 기울입니다. 이는 프랑스어의 동사 “like”가 문맥에 따라 다른 의미로 해석되기 때문입니다. 그러나 문장의 나머지 단어들은 이 단어를 번역하는 데에 크게 유용하지 않습니다. 같은 맥락에서 “this”를 번역할 때, 이 단어는 연결 명사가 남성형이거나 여성형이냐에 따라 다르게 해석될 수 있기 때문에 모델은 “course”라는 단어에 주의를 기울입니다. 여기서도 문장의 나머지 다른 단어들은 “this”의 의미를 해석하는 데에 크게 중요하지 않습니다. 더 복잡한 문법의 문장에서 모델은 문장의 각 단어를 적절히 번역하기 위해 더 멀리 떨어진 단어들에 대해서도 주의를 기울여야 합니다. + +이와 동일한 개념이 자연어의 모든 문제에 적용됩니다. 단어는 그 자체로도 의미를 갖지만 문맥상 앞뒤의 다른 단어정보를 알게 되면 의미가 달라지기도 하죠. + +지금까지 어텐션 레이어가 무엇인지 알아보았으니 트랜스포머 구조에 대해 살펴보겠습니다. + +## 원본 구조 The original architecture + +트랜스포머 구조는 처음에 번역을 위해 만들어졌습니다. 학습시에 인코더는 특정 언어의 입력 문장을 받고, 동시에 디코더는 타겟 언어로된 동일한 의미의 문장을 받습니다. 인코더에서 어텐션 레이어는 문장 내의 모든 단어를 활요할 수 있습니다(방금 보았듯이 주어진 단어의 번역은 문장의 전후를 살펴보아야 하니까요). 반면, 디코더는 순차적으로 작동하기 때문에 문장 내에서 이미 번역이 이루어진 부분에만 주의를 기울일 수 밖에 없습니다. 이로 인해 현재 생성(번역)되고 있는 단어의 앞에 단어들만 이용할 수 있죠. 예시로, 번역된 타겟의 처음 세 단어를 예측해 놨을 때, 이 결과를 디코더로 넘기면 디코더는 인코더로부터 받은 모든 입력 정보를 함께 이용해 네 번째 올 단어를 예측하는 것입니다. + +모델이 타겟 문장에 대한 액세스(access)가 있는 상황에서, 훈련 속도를 높이기 위해 디코더는 전체 타겟을 제공하지만 뒤에 올 단어들을 사용할 수 없습니다. (모델이 두 번째 올 단어를 예측하기 위해 두 번째 위치 단어를 접근할 수 있다면 예측이 의미없어지겠죠?) 예를 들어, 네 번째 단어를 예측할 때 어텐션 레이어는 1~3 번째 단어에만 액세스하도록 합니다. + +원본의 트랜스포머 구조는 아래와 같이 왼쪽에는 인코더, 오른쪽에는 디코더가 있는 형태를 지닙니다: + +
+Architecture of a Transformers models + +
+ +디코더 블럭의 첫 번째 어텐션 레이어는 모든 이전의 디코더 입력에 대해 주의를 기울이지만, 두 번째 어텐션 레이어는 인코더의 출력만 사용하는 점을 주목하세요. 이로써 디코더는 전체 입력 문장에 액세스하여 현재 올 단어를 잘 예측하게 되는 것입니다. 이는 서로 다른 언어는 서로 다른 어순을 갖거나 문장의 뒷부분에 등장하는 문맥이 주어진 단어의 가장 적합한 번역을 결정할 수 있기 때문에 매우 유용합니다. + +*어텐션 마스크(attention mask)*는 또한 모델이 몇몇 특수 단어들에 어텐션을 주는 것을 막는 데에 사용됩니다. 그 예로, 여러 다른 길이의 문장들을 모아 배치를 구성할 때, 패딩이라고 불리는 특수한 단어를 넣어 문장들의 길이를 맞춰주는데 사용하는 경우 있습니다. + +## 구조(Architectures) vs. 체크포인트(Checkpoints) + +트랜스포머 모델을 본격적으로 공부하기 앞서, 모델(models)과 함께 *구조(architectures)*와 *체크포인트(checkpoints)*라는 단어를 들으시게 될겁니다. 이 셋은 아래와 같이 조금 다른 의미를 갖고 있습니다: + +- **구조(Architecture)**: 모델의 뼈대를 의미하는 용어로, 모델 내부의 각 레이어와 각 연산 작용들을 의미합니다. +- 체크포인트(**Checkpoints)**: 주어진 구조(architecture)에 적용될 가중치들을 의미합니다. +- 모델(**Model)**: 사실 모델은 “구조”나 “가중치”만큼 구체적이지 않은 두루뭉실한 용어입니다. 이 강의에서는 모호함을 피하기 위해 *구조(architecture)*와 *체크포인트(checkpoint)*를 구분해서 사용하도록 하겠습니다. + +예를 들어, BERT는 구조인 반면, Google 팀이 최초 공개에서 내놓은 학습된 가중치 모음인 `bert-base-cased` 는 체크포인트입니다. 그치만 “BERT 모델”, “`bert-base-cased` 모델” 등과 같이 혼용해도 괜찮습니다. \ No newline at end of file diff --git a/chapters/ko/chapter1/5.mdx b/chapters/ko/chapter1/5.mdx new file mode 100644 index 000000000..755310f6c --- /dev/null +++ b/chapters/ko/chapter1/5.mdx @@ -0,0 +1,17 @@ +# 인코더 모델 + + + +인코더 모델(Encoder models)은 트랜스포머 모델의 인코더만 사용합니다. 각각의 단계에서 어텐션 레이어는 초기 문장의 모든 단어에 액세스 할 수 있습니다. 이러한 모델은 “양방향성(bi-directional)” 어텐션을 지닌 특성이 있다고도 하며 *자동 인코딩(auto-enoding) 모델*이라고 부릅니다. + +이러한 모델은 주어진 문장을 훼손시킨 후(랜덤으로 단어에 마스킹을 하는 방식 등으로) 모델이 원본 문장을 찾아 재구성하게끔 하는 과정을 반복시키는 방식으로 사전 학습을 진행 합니다. + +인코더 모델은 문장 분류, 개체명 인식(더 넓은 범위에서 단어 분류), 추출 질의 응답 등과 같이 전체 문장에 대한 이해를 요구하는 작업에 특화되어 있습니다. + +이 계열을 대표하는 모델들은 아래와 같습니다: + +- [ALBERT](https://huggingface.co/transformers/model_doc/albert.html) +- [BERT](https://huggingface.co/transformers/model_doc/bert.html) +- [DistilBERT](https://huggingface.co/transformers/model_doc/distilbert.html) +- [ELECTRA](https://huggingface.co/transformers/model_doc/electra.html) +- [RoBERTa](https://huggingface.co/transformers/model_doc/roberta.html) \ No newline at end of file diff --git a/chapters/ko/chapter1/6.mdx b/chapters/ko/chapter1/6.mdx new file mode 100644 index 000000000..4f8f0afa8 --- /dev/null +++ b/chapters/ko/chapter1/6.mdx @@ -0,0 +1,16 @@ +# 디코더 모델 + + + +디코더 모델(Decoder models)은 트랜스포머 모델의 디코더만 사용합니다. 각각의 단계마다, 어텐션 레이어는 주어진 단어에 대해 문장 내에서 해당 단어 앞에 위치한 단어들에 대해서만 액세스 할 수 있습니다. 이러한 모델을 *자동 회귀(auto-regressive) 모델*이라고 부릅니다. + +디코더 모델의 사전 학습은 보통 문장 내 다음 단어 예측을 반복하는 방식으로 이루어집니다. + +이러한 모델은 텍스트 생성에 특화되어 있습니다. + +디코더 모델 계열의 대표 주자들은 다음과 같습니다: + +- [CTRL](https://huggingface.co/transformers/model_doc/ctrl.html) +- [GPT](https://huggingface.co/transformers/model_doc/gpt.html) +- [GPT-2](https://huggingface.co/transformers/model_doc/gpt2.html) +- [Transformer XL](https://huggingface.co/transformers/model_doc/transformerxl.html) \ No newline at end of file diff --git a/chapters/ko/chapter1/7.mdx b/chapters/ko/chapter1/7.mdx new file mode 100644 index 000000000..2cca23686 --- /dev/null +++ b/chapters/ko/chapter1/7.mdx @@ -0,0 +1,16 @@ +# 시퀀스-투-시퀀스 모델 + + + +인코더-디코더 모델(Encoder-decoder models)로도 불리는 *시퀀스-투-시퀀스 모델(sequence-to-sequence models)*은 트랜스포머 구조의 인코더, 디코더 둘을 모두 사용합니다. 각 단계마다, 인코더의 어텐션 레이어는 초기 문장의 모든 단어에 액세스 할 수 있는 반면, 디코더의 어텐션 레이어는 주어진 단어 앞에 위치한 단어들에만 액세스 할 수 있습니다. + +이러한 모델의 사전 학습은 인코더 혹은 디코더 모델의 방식을 모두 사용할 수 있지만 조금 더 복잡합니다. 이를테면, [T5](https://huggingface.co/t5-base)는 (여러 단어를 포함하기도 하는) 임의의 텍스트 범위를 하나의 특수 마스크 토큰으로 바꾸고 마스크 단어를 대체할 텍스트를 예측하는 방식으로 사전 학습 되었습니다. + +시퀀스-투-시퀀스 모델은 요약, 번역, 생성 질의 응답과 같이 주어진 입력을 기반으로 새로운 문장을 생성하는 작업에 가장 적합합니다. + +이 계열을 대표하는 모델은 다음과 같습니다: + +- [BART](https://huggingface.co/transformers/model_doc/bart.html) +- [mBART](https://huggingface.co/transformers/model_doc/mbart.html) +- [Marian](https://huggingface.co/transformers/model_doc/marian.html) +- [T5](https://huggingface.co/transformers/model_doc/t5.html) \ No newline at end of file diff --git a/chapters/ko/chapter1/8.mdx b/chapters/ko/chapter1/8.mdx new file mode 100644 index 000000000..919cadd54 --- /dev/null +++ b/chapters/ko/chapter1/8.mdx @@ -0,0 +1,34 @@ +# 편향과 한계 + + + +사전 학습된 혹은 미세 조정된 모델을 프로덕션 단계에서 사용하실 계획이라면, 이러한 모델들은 강력한 툴이지만 한계가 있음을 반드시 명심하셔야 합니다. 가장 큰 한계점은 리서처들이 무수히 많은 양의 데이터를 사전 학습에 사용하기 위해, 인터넷상에서 모을 수 있는 양질의 데이터와 함께 그렇지 않은 데이터까지 수집했을 가능성이 있다는 것입니다. + +이를 빠르게 보여드리기 위해 `fill-mask` pipeline에 BERT 모델을 연결한 예제를 다시 살펴보겠습니다: + +``` +from transformers import pipeline + +unmasker = pipeline("fill-mask", model="bert-base-uncased") +result = unmasker("This man works as a [MASK].") +print([r["token_str"] for r in result]) + +result = unmasker("This woman works as a [MASK].") +print([r["token_str"] for r in result]) + +``` + +``` +['lawyer', 'carpenter', 'doctor', 'waiter', 'mechanic'] +['nurse', 'waitress', 'teacher', 'maid', 'prostitute'] + +``` + +주어의 성별만 바꾼 두 문장에서 빠진 단어를 채울 때, 모델은 성별과 관계 없는 공통 답변(waiter/waitress)을 하나만 내놓았습니다. 다른 답변들은 일반적으로 특정 성별에 편향된 답변이었습니다. 이를테면, 모델은 매춘이라는 단어와 연관된 상위 5개의 단어에 “여성”과 “일”을 포함시켰습니다. BERT가 전체 인터넷 상의 텍스트를 이용하여 사전 학습된 것이 아니라 [English Wikipedia](https://huggingface.co/datasets/wikipedia) 와 [BookCorpus](https://huggingface.co/datasets/bookcorpus) 같이 상당히 중립적인 데이터를 이용하여 사전 학습 되었음에도 불구하고 이러한 현상이 일어납니다. + +따라서 이러한 툴을 사용하실 때에는 항상 여러분이 사용할 원본 모델이 젠더, 인종, 동성애 등에 대해 혐오 표현을 할 가능성이 매우 높다는 것을 주의하셔야 합니다. 이러한 모델은 미세 조정을 거쳐도 내제된 편향성을 없애지 못합니다. \ No newline at end of file diff --git a/chapters/ko/chapter1/9.mdx b/chapters/ko/chapter1/9.mdx new file mode 100644 index 000000000..3ebcd1701 --- /dev/null +++ b/chapters/ko/chapter1/9.mdx @@ -0,0 +1,11 @@ +# 단원 정리 + +이번 단원에서는 🤗 Transformers의 하이레벨 함수인 `pipeline()` 를 사용하여 다양한 NLP 문제에 대한 접근 방식을 학습했습니다. 그리고 Hub에서 모델을 검색 및 사용하는 방법, Inference API를 이용해 브라우저 상에서 바로 모델을 테스트 하는 방법 또한 알아보았습니다. + +지금까지 트랜스포머 모델의 대략작인 동작 방식과, 전이 학습(transfer learning)과 미세 조정(fine-tuning)의 중요성에 알아보았습니다. 핵심은 어떤 문제를 풀고싶냐에 따라 전체 모델 구조를 다 사용하거나 인코더, 디코더만 사용할 수도 있다는 것입니다. 아래 표는 이를 요약해서 보여주고 있습니다: + +| Model | Examples | Tasks | +| --- | --- | --- | +| 인코더 | ALBERT, BERT, DistilBERT, ELECTRA, RoBERTa | 문장 분류, 개체명 인식, 추출 질의 응답 | +| 디코더 | CTRL, GPT, GPT-2, Transformer XL | 텍스트 생성 | +| 인코더-디코더 | BART, T5, Marian, mBART | 오약, 번역, 생성 질의 응답 | \ No newline at end of file From 278753a2952da59b1e744288c2a4b85c16157179 Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Sat, 2 Apr 2022 23:57:56 +0900 Subject: [PATCH 06/73] ko/chapter0 finished --- chapters/ko/chapter0/1.mdx | 110 +++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 chapters/ko/chapter0/1.mdx diff --git a/chapters/ko/chapter0/1.mdx b/chapters/ko/chapter0/1.mdx new file mode 100644 index 000000000..6ab7c8e23 --- /dev/null +++ b/chapters/ko/chapter0/1.mdx @@ -0,0 +1,110 @@ +# Introduction + +Welcome to the Hugging Face course! This introduction will guide you through setting up a working environment. If you're just starting the course, we recommend you first take a look at [Chapter 1](/course/chapter1), then come back and set up your environment so you can try the code yourself. + +All the libraries that we'll be using in this course are available as Python packages, so here we'll show you how to set up a Python environment and install the specific libraries you'll need. + +We'll cover two ways of setting up your working environment, using a Colab notebook or a Python virtual environment. Feel free to choose the one that resonates with you the most. For beginners, we strongly recommend that you get started by using a Colab notebook. + +Note that we will not be covering the Windows system. If you're running on Windows, we recommend following along using a Colab notebook. If you're using a Linux distribution or macOS, you can use either approach described here. + +Most of the course relies on you having a Hugging Face account. We recommend creating one now: [create an account](https://huggingface.co/join). + +## Using a Google Colab notebook + +Using a Colab notebook is the simplest possible setup; boot up a notebook in your browser and get straight to coding! + +If you're not familiar with Colab, we recommend you start by following the [introduction](https://colab.research.google.com/notebooks/intro.ipynb). Colab allows you to use some accelerating hardware, like GPUs or TPUs, and it is free for smaller workloads. + +Once you're comfortable moving around in Colab, create a new notebook and get started with the setup: + +
+An empty colab notebook +
+ +The next step is to install the libraries that we'll be using in this course. We'll use `pip` for the installation, which is the package manager for Python. In notebooks, you can run system commands by preceding them with the `!` character, so you can install the 🤗 Transformers library as follows: + +``` +!pip install transformers +``` + +You can make sure the package was correctly installed by importing it within your Python runtime: + +``` +import transformers +``` + +
+A gif showing the result of the two commands above: installation and import +
+ +This installs a very light version of 🤗 Transformers. In particular, no specific machine learning frameworks (like PyTorch or TensorFlow) are installed. Since we'll be using a lot of different features of the library, we recommend installing the development version, which comes with all the required dependencies for pretty much any imaginable use case: + +``` +!pip install transformers[sentencepiece] +``` + +This will take a bit of time, but then you'll be ready to go for the rest of the course! + +## Using a Python virtual environment + +If you prefer to use a Python virtual environment, the first step is to install Python on your system. We recommend following [this guide](https://realpython.com/installing-python/) to get started. + +Once you have Python installed, you should be able to run Python commands in your terminal. You can start by running the following command to ensure that it is correctly installed before proceeding to the next steps: `python --version`. This should print out the Python version now available on your system. + +When running a Python command in your terminal, such as `python --version`, you should think of the program running your command as the "main" Python on your system. We recommend keeping this main installation free of any packages, and using it to create separate environments for each application you work on — this way, each application can have its own dependencies and packages, and you won't need to worry about potential compatibility issues with other applications. + +In Python this is done with [*virtual environments*](https://docs.python.org/3/tutorial/venv.html), which are self-contained directory trees that each contain a Python installation with a particular Python version alongside all the packages the application needs. Creating such a virtual environment can be done with a number of different tools, but we'll use the official Python package for that purpose, which is called [`venv`](https://docs.python.org/3/library/venv.html#module-venv). + +First, create the directory you'd like your application to live in — for example, you might want to make a new directory called *transformers-course* at the root of your home directory: + +``` +mkdir ~/transformers-course +cd ~/transformers-course +``` + +From inside this directory, create a virtual environment using the Python `venv` module: + +``` +python -m venv .env +``` + +You should now have a directory called *.env* in your otherwise empty folder: + +``` +ls -a +``` + +```out +. .. .env +``` + +You can jump in and out of your virtual environment with the `activate` and `deactivate` scripts: + +``` +# Activate the virtual environment +source .env/bin/activate + +# Deactivate the virtual environment +source .env/bin/deactivate +``` + +You can make sure that the environment is activated by running the `which python` command: if it points to the virtual environment, then you have successfully activated it! + +``` +which python +``` + +```out +/home//transformers-course/.env/bin/python +``` + +### Installing dependencies + +As in the previous section on using Google Colab instances, you'll now need to install the packages required to continue. Again, you can install the development version of 🤗 Transformers using the `pip` package manager: + +``` +pip install "transformers[sentencepiece]" +``` + +You're now all set up and ready to go! From 1ec6d9c04ebd0516ee25c01f8b19027ca5d12a9c Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Sun, 3 Apr 2022 00:20:08 +0900 Subject: [PATCH 07/73] ko/chapter0 finished --- chapters/ko/chapter0/1.mdx | 73 ++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/chapters/ko/chapter0/1.mdx b/chapters/ko/chapter0/1.mdx index 6ab7c8e23..eaf1f232b 100644 --- a/chapters/ko/chapter0/1.mdx +++ b/chapters/ko/chapter0/1.mdx @@ -1,85 +1,92 @@ -# Introduction +# 강의 소개 -Welcome to the Hugging Face course! This introduction will guide you through setting up a working environment. If you're just starting the course, we recommend you first take a look at [Chapter 1](/course/chapter1), then come back and set up your environment so you can try the code yourself. +Hugging Face 강의에 오신 여러분들 환영합니다! 이번 강의 소개에서는 작업 환경 설정에 대해 안내드리겠습니다. 방금 막 이번 과정을 시작하셨다면 먼저 [Chapter 1](notion://www.notion.so/course/chapter1) 내용을 살펴보고 돌아오신 뒤, 환경을 설정하여 코드를 직접 실행해보시길 추천드립니다. -All the libraries that we'll be using in this course are available as Python packages, so here we'll show you how to set up a Python environment and install the specific libraries you'll need. +이번 과정에서 사용할 모든 라이브러리는 파이썬 패키지를 통해 사용할 수 있으므로 여기서는 파이썬 환경 설정 방법 및 필요한 라이브러리 설치 방법을 보여드리겠습니다. -We'll cover two ways of setting up your working environment, using a Colab notebook or a Python virtual environment. Feel free to choose the one that resonates with you the most. For beginners, we strongly recommend that you get started by using a Colab notebook. +작업 환경 설정 방법으로 Colab 노트북을 이용한 방법과 파이썬 가상 환경을 이용한 방법, 두 가지를 다룰 것이고 둘 중 더 마음이 가는 방식을 자유롭게 선택하셔도 됩니다. 입문자의 경우 Colab 노트북을 이용하시길 강력하게 추천합니다. -Note that we will not be covering the Windows system. If you're running on Windows, we recommend following along using a Colab notebook. If you're using a Linux distribution or macOS, you can use either approach described here. +여기서 Windows 환경에 대해서는 다루지 않기 때문에 Windows에서 실행 중이시면 Colab 노트북을 이용해 아래 과정을 따라가 주시길 권장드립니다. Linux 혹은 macOS를 실행 중이시라면 어떤 방식을 택해도 무방합니다. -Most of the course relies on you having a Hugging Face account. We recommend creating one now: [create an account](https://huggingface.co/join). +대부분의 강의는 여러분이 Hugging Face 계정이 있다는 것을 전제로 하기 때문에 지금 바로 계정을 생성하시길 추천드립니다: [계정 생성하기](https://huggingface.co/join) -## Using a Google Colab notebook +## Google Colab 노트북 사용하기 -Using a Colab notebook is the simplest possible setup; boot up a notebook in your browser and get straight to coding! +Colab 노트북은 가장 쉬운 설정 방식입니다. 브라우저에 노트북을 켜고 망설이지 말고 바로 코딩을 시작하세요! -If you're not familiar with Colab, we recommend you start by following the [introduction](https://colab.research.google.com/notebooks/intro.ipynb). Colab allows you to use some accelerating hardware, like GPUs or TPUs, and it is free for smaller workloads. +Colab에 익숙하지 않으시다면 [introduction](https://colab.research.google.com/notebooks/intro.ipynb) 링크를 따라 시작하시길 권장드립니다. Colab에서는 GPU, TPU와 같은 가속 하드웨어를 사용할 수 있으며 적은 양의 워크로드에 대해서는 무료입니다. -Once you're comfortable moving around in Colab, create a new notebook and get started with the setup: +Colab과 친숙해지셨다면 새로운 노트북을 생성하여 아래 설정을 시작하세요:
-An empty colab notebook +An empty colab notebook
-The next step is to install the libraries that we'll be using in this course. We'll use `pip` for the installation, which is the package manager for Python. In notebooks, you can run system commands by preceding them with the `!` character, so you can install the 🤗 Transformers library as follows: +다음은 이번 강의에서 사용할 라이브러리를 설치할 단계입니다. 설치에는 파이썬 패키지 관리자인 `pip` 를 사용하도록 하겠습니다. 노트북 파일에서 시스템 명령어 앞에 문자 `!` 를 붙여 실행시킬 수 있고, 아래와 같이 🤗 Transformers 라이브러리를 설치할 수 있습니다: ``` !pip install transformers + ``` -You can make sure the package was correctly installed by importing it within your Python runtime: +이제 파이썬 런타임에 패키지를 가져와 패키지가 제대로 설치되었는지 확인해보겠습니다: ``` import transformers + ```
-A gif showing the result of the two commands above: installation and import +A gif showing the result of the two commands above: installation and import
-This installs a very light version of 🤗 Transformers. In particular, no specific machine learning frameworks (like PyTorch or TensorFlow) are installed. Since we'll be using a lot of different features of the library, we recommend installing the development version, which comes with all the required dependencies for pretty much any imaginable use case: +위의 방식으로는 PyTorch나 TensorFlow와 같은 특정 머신 러닝 프레임워크를 포함하지 않는, 아주 가벼운 버전의 🤗 Transformers가 설치됩니다. 본 강의에서는 라이브러리의 수많은 다양한 기능들을 사용합니다. 따라서, 실상 거의 모든 예제에 필요한 종속성(dependency)을 제공하는 개발 버전을 설치하시길 바랍니다: ``` !pip install transformers[sentencepiece] + ``` -This will take a bit of time, but then you'll be ready to go for the rest of the course! +설치에 시간이 조금 걸리겠지만 이제 나머지 강의를 위한 준비를 모두 마쳤습니다! -## Using a Python virtual environment +## 파이썬 가상 환경 사용하기 -If you prefer to use a Python virtual environment, the first step is to install Python on your system. We recommend following [this guide](https://realpython.com/installing-python/) to get started. +파이썬 가상 환경 사용을 원하신다면 우선 시스템에 파이썬을 설치해야 합니다. 이 [가이드](https://realpython.com/installing-python/)를 따라 시작해보세요. -Once you have Python installed, you should be able to run Python commands in your terminal. You can start by running the following command to ensure that it is correctly installed before proceeding to the next steps: `python --version`. This should print out the Python version now available on your system. +파이썬 설치가 완료되면 터미널에서 파이썬 명령어를 실행할 수 있습니다. 다음 단계로 넘어가기 전에, 다음과 같은 명령어를 실행하여 설치가 잘 되었는지 확인하세요: `python --version`. 이 때 시스템에 사용할 수 있는 파이썬 버전을 출력되어야 합니다. -When running a Python command in your terminal, such as `python --version`, you should think of the program running your command as the "main" Python on your system. We recommend keeping this main installation free of any packages, and using it to create separate environments for each application you work on — this way, each application can have its own dependencies and packages, and you won't need to worry about potential compatibility issues with other applications. +터미널에서 `python --version` 과 같은 파이썬 명령어를 실행하면, 명령어를 실행하는 프로그램을 시스템의 “메인(main)” 파이썬으로 생각해야 합니다. 이 메인 설치에 패키지를 설치하지 않은 채로 놔두시고, 이를 작업 중인 각 어플리케이션에 별도의 환경을 생성하는 데에 이용하는 것을 추천드립니다. 이렇게 하면, 각 어플리케이션은 각각의 의존성과 패키지를 갖게 되어 서로 다른 어플리케이션과 추후에 호환성 문제로부터 자유롭게 됩니다. -In Python this is done with [*virtual environments*](https://docs.python.org/3/tutorial/venv.html), which are self-contained directory trees that each contain a Python installation with a particular Python version alongside all the packages the application needs. Creating such a virtual environment can be done with a number of different tools, but we'll use the official Python package for that purpose, which is called [`venv`](https://docs.python.org/3/library/venv.html#module-venv). +파이썬에서 이는 *[가상 환경](https://docs.python.org/3/tutorial/venv.html)*을 통해 완수됩니다. 가상 환경은 자체 포함 디렉토리 트리로, 각 트리는 어플리케이션에게 필요한 모든 패키지와 함께 특정 파이썬 버전에 대한 파이썬 설치를 포함합니다. 이러한 가상 환경을 생성하는 방법은 여러 툴을 통해 할 수 있지만, 여기서는 공식 파이썬 패키지인 `[venv](https://docs.python.org/3/library/venv.html#module-venv)` 를 통해 생성해 보겠습니다. -First, create the directory you'd like your application to live in — for example, you might want to make a new directory called *transformers-course* at the root of your home directory: +먼저, 여러분의 어플리케이션을 넣어줄 디렉토리를 생성하세요. 예를 들어, 여러분의 홈 디렉토리의 *transformers-course*와 같은 이름의 디렉토리를 만들어 볼까요?: ``` mkdir ~/transformers-course cd ~/transformers-course + ``` -From inside this directory, create a virtual environment using the Python `venv` module: +디렉토리 내부에서, 파이썬 `venv` 모듈을 사용하여 가상 환경을 생성합니다: ``` python -m venv .env + ``` -You should now have a directory called *.env* in your otherwise empty folder: +원래 아무것도 없던 빈 폴더에 *.env*라는 디렉토리가 생기게 됩니다: ``` ls -a + ``` -```out +``` . .. .env + ``` -You can jump in and out of your virtual environment with the `activate` and `deactivate` scripts: +`activate` 스크립트를 통해 가상 환경으로 접속할 수 있고, `deactivate` 를 통해 가상 환경 밖으로 나올 수 있습니다: ``` # Activate the virtual environment @@ -87,24 +94,28 @@ source .env/bin/activate # Deactivate the virtual environment source .env/bin/deactivate + ``` -You can make sure that the environment is activated by running the `which python` command: if it points to the virtual environment, then you have successfully activated it! +환경이 제대로 활성화 되는지 `which python` 명령어를 실행하여 확인해보세요. 아래와 같이 가상 환경을 가리킨다면 활성화가 완료된 것입니다! ``` which python + ``` -```out +``` /home//transformers-course/.env/bin/python + ``` -### Installing dependencies +### 의존성(dependencies) 설치하기 -As in the previous section on using Google Colab instances, you'll now need to install the packages required to continue. Again, you can install the development version of 🤗 Transformers using the `pip` package manager: +Google Colab 사용법에서와 마찬가지로 다음 단계로 넘어가기 위해 패키지를 설치해야 합니다. 여기서도, `pip` 패키지 관리자를 통해 🤗 Transformers 개발 버전을 설치할 수 있습니다: ``` pip install "transformers[sentencepiece]" + ``` -You're now all set up and ready to go! +이제 모든 설정이 끝났고 시작할 준비를 마쳤습니다! \ No newline at end of file From e5285b7e5ccd5d5566caecbf6292ae7b1b985412 Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Sun, 3 Apr 2022 22:28:49 +0900 Subject: [PATCH 08/73] reviewed by @bzantium ko/chapter0 --- chapters/ko/chapter0/1.mdx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/chapters/ko/chapter0/1.mdx b/chapters/ko/chapter0/1.mdx index eaf1f232b..051bb609c 100644 --- a/chapters/ko/chapter0/1.mdx +++ b/chapters/ko/chapter0/1.mdx @@ -12,17 +12,17 @@ Hugging Face 강의에 오신 여러분들 환영합니다! 이번 강의 소개 ## Google Colab 노트북 사용하기 -Colab 노트북은 가장 쉬운 설정 방식입니다. 브라우저에 노트북을 켜고 망설이지 말고 바로 코딩을 시작하세요! +Colab 노트북은 가장 쉬운 설정 방식입니다. 브라우저에 Colab 노트북을 켜고 바로 코딩을 시작하시면 됩니다! Colab에 익숙하지 않으시다면 [introduction](https://colab.research.google.com/notebooks/intro.ipynb) 링크를 따라 시작하시길 권장드립니다. Colab에서는 GPU, TPU와 같은 가속 하드웨어를 사용할 수 있으며 적은 양의 워크로드에 대해서는 무료입니다. -Colab과 친숙해지셨다면 새로운 노트북을 생성하여 아래 설정을 시작하세요: +Colab과 친숙해 지셨다면 새로운 노트북을 생성하여 아래와 같이 시작합니다:
An empty colab notebook
-다음은 이번 강의에서 사용할 라이브러리를 설치할 단계입니다. 설치에는 파이썬 패키지 관리자인 `pip` 를 사용하도록 하겠습니다. 노트북 파일에서 시스템 명령어 앞에 문자 `!` 를 붙여 실행시킬 수 있고, 아래와 같이 🤗 Transformers 라이브러리를 설치할 수 있습니다: +다음으로, 이번 강의에서 사용할 라이브러리를 설치합니다. 설치에는 파이썬 패키지 관리자인 `pip` 를 사용하도록 하겠습니다. 노트북 파일에서는 시스템 명령어 앞에 `!` 를 붙여 실행시킬 수 있으므로, 아래와 같이 🤗 Transformers 라이브러리를 설치할 수 있습니다: ``` !pip install transformers @@ -40,7 +40,7 @@ import transformers A gif showing the result of the two commands above: installation and import -위의 방식으로는 PyTorch나 TensorFlow와 같은 특정 머신 러닝 프레임워크를 포함하지 않는, 아주 가벼운 버전의 🤗 Transformers가 설치됩니다. 본 강의에서는 라이브러리의 수많은 다양한 기능들을 사용합니다. 따라서, 실상 거의 모든 예제에 필요한 종속성(dependency)을 제공하는 개발 버전을 설치하시길 바랍니다: +위의 방식으로는 PyTorch나 TensorFlow와 같은 특정 기계학습 프레임워크를 포함하지 않는, 아주 가벼운 버전의 🤗 Transformers가 설치됩니다. 본 강의에서는 이 라이브러리의 많고 다양한 기능들을 사용할 예정이므로, 거의 모든 예제에 필요한 종속성(dependency)을 제공하는 개발 버전을 아래의 명령어를 통해 설치하시길 바랍니다: ``` !pip install transformers[sentencepiece] @@ -51,15 +51,15 @@ import transformers ## 파이썬 가상 환경 사용하기 -파이썬 가상 환경 사용을 원하신다면 우선 시스템에 파이썬을 설치해야 합니다. 이 [가이드](https://realpython.com/installing-python/)를 따라 시작해보세요. +파이썬 가상 환경 사용을 원하신다면 먼저 파이썬을 설치해야 합니다. 이 [가이드](https://realpython.com/installing-python/)를 따라 시작하면 됩니다. 파이썬 설치가 완료되면 터미널에서 파이썬 명령어를 실행할 수 있습니다. 다음 단계로 넘어가기 전에, 다음과 같은 명령어를 실행하여 설치가 잘 되었는지 확인하세요: `python --version`. 이 때 시스템에 사용할 수 있는 파이썬 버전을 출력되어야 합니다. -터미널에서 `python --version` 과 같은 파이썬 명령어를 실행하면, 명령어를 실행하는 프로그램을 시스템의 “메인(main)” 파이썬으로 생각해야 합니다. 이 메인 설치에 패키지를 설치하지 않은 채로 놔두시고, 이를 작업 중인 각 어플리케이션에 별도의 환경을 생성하는 데에 이용하는 것을 추천드립니다. 이렇게 하면, 각 어플리케이션은 각각의 의존성과 패키지를 갖게 되어 서로 다른 어플리케이션과 추후에 호환성 문제로부터 자유롭게 됩니다. +터미널에서 `python --version` 과 같은 파이썬 명령어를 실행하면, 명령어를 실행하는 프로그램을 시스템의 “메인(main)” 파이썬으로 생각해야 합니다. 이 메인 파이썬은 어떤 패키지도 설치하지 않은 상태로 유지하면서, 작업 중인 각 어플리케이션마다 별도의 환경을 생성하여 이용하는 것을 권장합니다. 이렇게 하면, 각 어플리케이션은 각각의 의존성 및 패키지를 갖게 되어 다른 어플리케이션과의 잠재적 호환성 문제를 피할 수 있습니다. 파이썬에서 이는 *[가상 환경](https://docs.python.org/3/tutorial/venv.html)*을 통해 완수됩니다. 가상 환경은 자체 포함 디렉토리 트리로, 각 트리는 어플리케이션에게 필요한 모든 패키지와 함께 특정 파이썬 버전에 대한 파이썬 설치를 포함합니다. 이러한 가상 환경을 생성하는 방법은 여러 툴을 통해 할 수 있지만, 여기서는 공식 파이썬 패키지인 `[venv](https://docs.python.org/3/library/venv.html#module-venv)` 를 통해 생성해 보겠습니다. -먼저, 여러분의 어플리케이션을 넣어줄 디렉토리를 생성하세요. 예를 들어, 여러분의 홈 디렉토리의 *transformers-course*와 같은 이름의 디렉토리를 만들어 볼까요?: +먼저, 어플리케이션을 넣어줄 디렉토리를 생성합니다. 예를 들어, 홈 디렉토리의 *transformers-course*와 같은 이름의 디렉토리를 만들어 봅시다: ``` mkdir ~/transformers-course @@ -97,7 +97,7 @@ source .env/bin/deactivate ``` -환경이 제대로 활성화 되는지 `which python` 명령어를 실행하여 확인해보세요. 아래와 같이 가상 환경을 가리킨다면 활성화가 완료된 것입니다! +환경이 제대로 활성화 되었는지 `which python` 명령어를 실행하여 확인해 봅시다. 아래와 같이 가상 환경을 보여준다면 제대로 활성화가 것입니다! ``` which python @@ -118,4 +118,4 @@ pip install "transformers[sentencepiece]" ``` -이제 모든 설정이 끝났고 시작할 준비를 마쳤습니다! \ No newline at end of file +이제 모든 환경 설정믈 마치고 시작할 준비가 되었습니다! \ No newline at end of file From 95bb45580b24fbfb1ae76c5ac0509a3aba75be4c Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Sun, 3 Apr 2022 22:44:13 +0900 Subject: [PATCH 09/73] reviewed by @bzantium chapter0 & fixed typo --- chapters/ko/chapter0/1.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ko/chapter0/1.mdx b/chapters/ko/chapter0/1.mdx index 051bb609c..194a396ee 100644 --- a/chapters/ko/chapter0/1.mdx +++ b/chapters/ko/chapter0/1.mdx @@ -118,4 +118,4 @@ pip install "transformers[sentencepiece]" ``` -이제 모든 환경 설정믈 마치고 시작할 준비가 되었습니다! \ No newline at end of file +이제 모든 환경 설정을 마치고 시작할 준비가 되었습니다! \ No newline at end of file From 3012092baca66a017b51b091eef207096252ea21 Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Sun, 3 Apr 2022 22:45:34 +0900 Subject: [PATCH 10/73] reviewed by @rainmaker712 --- chapters/ko/chapter1/1.mdx | 2 +- chapters/ko/chapter1/10.mdx | 16 ++++++++-------- chapters/ko/chapter1/2.mdx | 4 ++-- chapters/ko/chapter1/3.mdx | 34 +++++++++++++++------------------- chapters/ko/chapter1/4.mdx | 2 -- chapters/ko/chapter1/8.mdx | 2 +- 6 files changed, 27 insertions(+), 33 deletions(-) diff --git a/chapters/ko/chapter1/1.mdx b/chapters/ko/chapter1/1.mdx index 8628ea321..7ed285c2a 100644 --- a/chapters/ko/chapter1/1.mdx +++ b/chapters/ko/chapter1/1.mdx @@ -17,7 +17,7 @@ - 단원 1~4에서는 🤗 Transformers 라이브러리의 핵심 개념에 대해 소개합니다. 이번 강의 끝무렵에 아마 여러분들은 트랜스포머 모델이 어떻게 동작하는지 터득하게 될거고, [Hugging Face Hub](https://huggingface.co/models)에서 모델을 사용하고 데이터셋으로 fine-tune하고 Hub에 여러분의 모델을 공유하는 방법까지 알게 될 것입니다! - 단원 5~8은 본격적으로 전형적인 NLP 작업을 하기 앞서, 🤗 Datasets와 🤗 Tokenizers의 기초를 다룹니다. 이 부분을 모두 학습하면 여러분들은 가장 일반적인 NLP 문제를 스스로 해낼 수 있습니다. -- 단원 9~12에서는 NLP를 넘어, 트랜스포머 모델이 음성 처리 및 컴퓨터 비전에 어떻게 활용되는지 탐구합니다. 이 과정에서 여러분들의 모델 데모를 구축하고 공유하는 방법 및 이를 프로덕션 환경에 최적화하는 방법을 배우게 됩니다. 최종적으로, 여러분들은 (거의) 모든 머신 러닝 문제에 🤗 Transformers를 적용할 준비를 갖추게 됩니다! +- 단원 9~12에서는 NLP를 넘어, 트랜스포머 모델이 음성 처리 및 컴퓨터 비전에 어떻게 활용되는지 탐구합니다. 이 과정에서 여러분들의 모델 데모를 구축하고 공유하는 방법 및 이를 프로덕션 환경에 최적화하는 방법을 배우게 됩니다. 최종적으로, 여러분들은 거의 모든 기계 학습(머신 러닝) 문제에 🤗 Transformers를 적용할 준비를 갖추게 됩니다! 이번 강의는: diff --git a/chapters/ko/chapter1/10.mdx b/chapters/ko/chapter1/10.mdx index 69cf78baf..bcbe320a5 100644 --- a/chapters/ko/chapter1/10.mdx +++ b/chapters/ko/chapter1/10.mdx @@ -40,15 +40,15 @@ ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") choices={[ { text: "문장에 대해 \"positive\" 혹은 \"negative\" 로 분류한 레이블과 함께 분류 점수를 반환합니다.", -explain: "This is incorrect — this would be a sentiment-analysis pipeline." +explain: "오답입니다 — 이는 sentiment-analysis 파이프라인에 대한 설명입니다." }, { text: "이 문장을 완성할, 생성 텍스트를 반환합니다.", -explain: "This is incorrect — it would be a text-generation pipeline.", +explain: "오답입니다 — 이는 text-generation 파이프라인에 대한 설명입니다.", }, { text: "사람, 기관, 장소 등을 나타내는 단어들을 반환합니다.", -explain: "Furthermore, with grouped_entities=True, it will group together the words belonging to the same entity, like \"Hugging Face\".", +explain: "이 뿐만 아니라, grouped_entities=True를 사용해 \"Hugging Face\"와 같이 같은 개체에 해당하는 단어들을 그룹화해줍니다.", correct: true } ]} @@ -77,7 +77,7 @@ correct: true }, { text: "man", -explain: "오답입니다. 이 pipeline은 마스킹된 단어를 채워야하기에 어딘가에는 마스크 토큰이 있어야겠죠?" +explain: "오답입니다. 이 파이프라인은 마스킹된 단어를 채워야하기에 어딘가에는 마스크 토큰이 있어야겠죠?" } ]} /> @@ -95,13 +95,13 @@ result = classifier("This is a course about the Transformers library") candidate_labels=[...].", correct: true }, { -text: "한 문장이 아니라, 여러 문장을 pipeline에 넣어주어야 합니다.", -explain: "틀렸지만, 다른 pipeline과 마찬가지로 제대로 사용한다면 물론 여러 리스트의 문장도 입력으로 넣어줄 수 있습니다." +text: "한 문장이 아니라, 여러 문장을 파이프라인에 넣어주어야 합니다.", +explain: "틀렸지만, 다른 파이프라인과 마찬가지로 제대로 사용한다면 물론 여러 리스트의 문장도 입력으로 넣어줄 수 있습니다." }, { text: "늘 그렇듯 🤗 Transformers 라이브러리가 또 고장난거 아닌가요?", @@ -109,7 +109,7 @@ explain: "못 들은 걸로 하겠습니다!" }, { text: "위의 문장은 너무 짧아서, 더 긴 문장을 입력해야 합니다.", -explain: "오답입니다. 매우 긴 텍스트는 pipeline에서 처리할 때 잘리게 되는 것을 명심하세요." +explain: "오답입니다. 매우 긴 텍스트는 파이프라인에서 처리할 때 잘리게 되는 것을 명심하세요." } ]} /> diff --git a/chapters/ko/chapter1/2.mdx b/chapters/ko/chapter1/2.mdx index 3dc873652..2a9426aa7 100644 --- a/chapters/ko/chapter1/2.mdx +++ b/chapters/ko/chapter1/2.mdx @@ -4,7 +4,7 @@ ## NLP가 무엇인가요? -NLP(Natural Language Processing)란 사람의 언어와 관련된 모든 것을 이해하는 데에 중점을 둔 언어학 및 머신 러닝 분야를 말합니다. NLP의 목적은 단순히 하나의 개별 단어를 이해하는 것을 넘어, 해당 단어들의 문맥을 이해하는 것입니다. +NLP(Natural Language Processing)란 사람의 언어와 관련된 모든 것을 이해하는 데에 중점을 둔 언어학 및 기계 학습(머신 러닝) 분야를 말합니다. NLP의 목적은 단순히 하나의 개별 단어를 이해하는 것을 넘어, 해당 단어들의 문맥을 이해하는 것입니다. 아래는 가장 일반적인 NLP 작업과 그 예시입니다: @@ -18,4 +18,4 @@ NLP(Natural Language Processing)란 사람의 언어와 관련된 모든 것을 ## 왜 NLP가 어렵나요? -컴퓨터와 사람은 서로 정보를 처리하는 방식이 다릅니다. 이를테면, “나는 배고파”라는 문장을 읽을 때 우리는 바로 그 의미를 이해할 수 있습니다. 마찬가지로 “나는 배고파”, “나 슬퍼”와 같은 문장 쌍이 주어질 때, 두 문장이 얼마나 유사한지 쉽게 판단할 수 있습니다. 그러나, 머신 러닝(ML) 모델은 사람만큼 이를 쉽게 할 수 없습니다. 우선 모델이 텍스트를 학습할 수 있도록 텍스트가 처리 과정을 거쳐야 하는데, 사람의 언어 체계는 매우 복잡하기 때문에 이러한 처리가 어떻게 이루어져야 하는지 면밀히 생각해야 합니다. 따라서 텍스트 표현 방법과 관련한 수많은 연구가 진행되어 왔고, 다음 단원에서 여러분들에게 그 중 몇 가지 방법들을 소개해드리겠습니다. \ No newline at end of file +컴퓨터와 사람은 서로 정보를 처리하는 방식이 다릅니다. 이를테면, “나는 배고파”라는 문장을 읽을 때 우리는 바로 그 의미를 이해할 수 있습니다. 마찬가지로 “나는 배고파”, “나 슬퍼”와 같은 문장 쌍이 주어질 때, 두 문장이 얼마나 유사한지 쉽게 판단할 수 있습니다. 그러나, 기계 학습 모델은 사람만큼 이를 쉽게 할 수 없습니다. 우선 모델이 텍스트를 학습할 수 있도록 텍스트가 처리 과정을 거쳐야 하는데, 사람의 언어 체계는 매우 복잡하기 때문에 이러한 처리가 어떻게 이루어져야 하는지 면밀히 생각해야 합니다. 따라서 텍스트 표현 방법과 관련한 수많은 연구가 진행되어 왔고, 다음 단원에서 여러분들에게 그 중 몇 가지 방법들을 소개해드리겠습니다. \ No newline at end of file diff --git a/chapters/ko/chapter1/3.mdx b/chapters/ko/chapter1/3.mdx index cd82ed78d..72a22f741 100644 --- a/chapters/ko/chapter1/3.mdx +++ b/chapters/ko/chapter1/3.mdx @@ -30,7 +30,7 @@ options={[ 트랜스포머 모델 안에서 무슨 일이 벌어지는지 알아보기 전에, 트랜스포머가 NLP 문제 해결에 어떻게 사용되는지 몇 가지 흥미로운 예시들을 살펴보겠습니다. -## Pipeline으로 작업하기 +## 파이프라인으로 작업하기 @@ -64,15 +64,15 @@ classifier( ``` -기본적으로 이 pipeline은 영어 감정 분석에 미세 조정(fine-tune)된 사전 학습 모델을 선택합니다. 여기서 `classifier` 객체를 생성할 때 모델이 다운로드 되며 캐싱(caching)이 이루어지는데, 재실행 시 캐싱된 모델을 사용하게 되어 모델을 다시 다운로드 하지 않습니다. +기본적으로 이 파이프라인은 영어 감정 분석에 미세 조정(fine-tune)된 사전 학습 모델을 선택합니다. 여기서 `classifier` 객체를 생성할 때 모델이 다운로드 되며 캐싱(caching)이 이루어지는데, 재실행 시 캐싱된 모델을 사용하게 되어 모델을 다시 다운로드 하지 않습니다. -텍스트를 pipeline에 넣을 때 다음과 같은 세 가지 주요 과정을 거칩니다: +텍스트를 파이프라인에 넣을 때 다음과 같은 세 가지 주요 과정을 거칩니다: 1. 텍스트가 모델이 이해할 수 있는 형태로 전처리 과정을 거칩니다. 2. 전처리된 입력이 모델 입력으로 들어갑니다. 3. 모델의 예측값이 후처리를 거쳐, 사람이 이해할 수 있는 형태로 반환됩니다. -현재까지 사용할 수 있는 pipeline([available pipelines](https://huggingface.co/transformers/main_classes/pipelines.html))은 다음과 같습니다: +현재까지 사용할 수 있는 파이프라인([available pipelines](https://huggingface.co/transformers/main_classes/pipelines.html))은 다음과 같습니다: - `feature-extraction` : 특징 추출 (텍스트에 대한 벡터 표현 추출) - `fill-mask` : 마스크 채우기 @@ -88,7 +88,7 @@ classifier( ## 제로샷 분류(Zero-shot classification) -레이블이 없는 텍스트를 분류하는 더 까다로운 과제부터 시작하겠습니다. 텍스트에 레이블을 다는 것은 시간이 많이 소요되고 도메인 지식이 필요하기 때문에 이러한 작업은 실제 프로젝트에서 아주 흔한 상황입니다. 이러한 상황에서 `zero-shot-classification` pipeline은 매우 유용합니다. 제로샷 pipeline은 사전 학습된 모델에 의존하지 않고도 분류 작업에 사용할 레이블을 특정할 수 있도록 합니다. 위의 예시에서 모델이 긍정(positive)과 부정(negative)의 두 레이블을 분류하는 샘플을 살펴보았는데, 제로샷 pipeline을 통해서는 어떠한 레이블 세트에 대해서도 분류 작업을 수행할 수 있습니다. +레이블이 없는 텍스트를 분류하는 더 까다로운 과제부터 시작하겠습니다. 텍스트에 레이블을 다는 것은 시간이 많이 소요되고 도메인 지식이 필요하기 때문에 이러한 작업은 실제 프로젝트에서 아주 흔한 상황입니다. 이러한 상황에서 `zero-shot-classification` 파이프라인은 매우 유용합니다. 제로샷 파이프라인은 사전 학습된 모델에 의존하지 않고도 분류 작업에 사용할 레이블을 특정할 수 있도록 합니다. 위의 예시에서 모델이 긍정(positive)과 부정(negative)의 두 레이블을 분류하는 샘플을 살펴보았는데, 제로샷 파이프라인을 통해서는 어떠한 레이블 세트에 대해서도 분류 작업을 수행할 수 있습니다. ``` from transformers import pipeline @@ -108,7 +108,7 @@ classifier( ``` -이러한 pipeline이 제로샷(zero-shot)이라 불리는 이유는 여러분의 데이터에 미세 조정(fine-tune)하지 않고도 사용할 수 있기 때문입니다. 제로샷은 여러분이 원하는 어떠한 레이블 목록에 대해서도 확률 점수를 바로 반환합니다. +이러한 파이프라인이 제로샷(zero-shot)이라 불리는 이유는 여러분의 데이터에 미세 조정(fine-tune)하지 않고도 사용할 수 있기 때문입니다. 제로샷은 여러분이 원하는 어떠한 레이블 목록에 대해서도 확률 점수를 바로 반환합니다. @@ -118,7 +118,7 @@ classifier( ## 텍스트 생성(Text generation) -지금부터 pipeline을 사용해 텍스트를 생성하는 방법을 알아보겠습니다. 여기서의 핵심은 프롬트를 모델에 제공하면 모델이 나머지 텍스트를 생성하여 이를 자동으로 완성하는 것입니다. 이는 스마트폰의 텍스트 자동 완성 기능과 유사합니다. 텍스트 생성에는 랜덤하게 결과를 생성하는 과정이 포함되어 있어서 여러분이 아래와 같이 동일하게 입력을 넣어도 매번 다른 결과가 나올 수 있습니다. +지금부터 파이프라인을 사용해 텍스트를 생성하는 방법을 알아보겠습니다. 여기서의 핵심은 프롬트를 모델에 제공하면 모델이 나머지 텍스트를 생성하여 이를 자동으로 완성하는 것입니다. 이는 스마트폰의 텍스트 자동 완성 기능과 유사합니다. 텍스트 생성에는 랜덤하게 결과를 생성하는 과정이 포함되어 있어서 여러분이 아래와 같이 동일하게 입력을 넣어도 매번 다른 결과가 나올 수 있습니다. ``` from transformers import pipeline @@ -145,11 +145,11 @@ generator("In this course, we will teach you how to") -## Pipeline에 Hub의 모델 적용하기 +## 파이프라인에 Hub의 모델 적용하기 지금까지 예제들은 해당 작업에 대해 기본 모델들을 사용했지만, 특정 모델을 Hub에서 선택해 텍스트 생성과 같은 특정 작업에 대한 파이프라인에서도 사용할 수 있습니다. [Model Hub](https://huggingface.co/models) 페이지의 화면 왼쪽에 태그를 클릭하여 해당 태그 내용 작업을 지원하는 모델을 확인할 수 있습니다. [다음](https://huggingface.co/models?pipeline_tag=text-generation)과 같은 페이지로 이동하게 됩니다. -함께 `[distilgpt2](https://huggingface.co/distilgpt2)` 모델을 사용해봐요! 위의 예제에서 사용한 pipeline에서 아래와 같이 로드 할 수 있습니다: +함께 `[distilgpt2](https://huggingface.co/distilgpt2)` 모델을 사용해봐요! 위의 예제에서 사용한 파이프라인에서 아래와 같이 로드 할 수 있습니다: ``` from transformers import pipeline @@ -178,7 +178,7 @@ generator( -**✏️ 직접 해보기!** 영어를 제외한 다른 언어를 생성하는 모델을 검색해보세요. 위젯을 자유롭게 사용해 보시고 pipeline을 사용해보세요! +**✏️ 직접 해보기!** 영어를 제외한 다른 언어를 생성하는 모델을 검색해보세요. 위젯을 자유롭게 사용해 보시고 파이프라인을 사용해보세요! @@ -190,7 +190,7 @@ generator( ## 마스크 채우기(Mask filling) -다음으로 사용해볼 pipeline은 마스크 채우기(`fill-mask`)입니다. 이 작업의 핵심 아이디어는 주어진 텍스트의 빈칸을 채우기입니다: +다음으로 사용해볼 파이프라인은 마스크 채우기(`fill-mask`)입니다. 이 작업의 핵심 아이디어는 주어진 텍스트의 빈칸을 채우기입니다: ``` from transformers import pipeline @@ -242,7 +242,7 @@ ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") 모델이 정확하게 Sylvain을 사람(PER)으로, Hugging Face를 기관(ORG)으로, Brooklyn을 장소(LOC)으로 예측했네요! -Pipeline을 생성하는 함수에 `grouped_entities=True` 옵션을 전달하면 pipeline이 같은 개체에 해당하는 문장 부분을 다시 그룹화합니다. 이 경우 모델은 여러 단어로 구성된 단어임에도 “Hugging”과 “Face”를 하나의 기관으로 정확히 분류하게 됩니다. 다음 단원에서도 확인하겠지만, 놀랍게도 전처리 과정에서 각 단어들은 더 작은 부분으로 쪼개지게 됩니다. 예를 들어 `Sylvain` 이라는 단어는 `S`, `##yl`, `##va`, `##in` 이렇게 네 조각으로 쪼개집니다. 후처리 단계에서 pipeline은 이 조각들을 멋지게 재그룹화합니다. +파이프라인을 생성하는 함수에 `grouped_entities=True` 옵션을 전달하면 파이프라인이 같은 개체에 해당하는 문장 부분을 다시 그룹화합니다. 이 경우 모델은 여러 단어로 구성된 단어임에도 “Hugging”과 “Face”를 하나의 기관으로 정확히 분류하게 됩니다. 다음 단원에서도 확인하겠지만, 놀랍게도 전처리 과정에서 각 단어들은 더 작은 부분으로 쪼개지게 됩니다. 예를 들어 `Sylvain` 이라는 단어는 `S`, `##yl`, `##va`, `##in` 이렇게 네 조각으로 쪼개집니다. 후처리 단계에서 파이프라인은 이 조각들을 멋지게 재그룹화합니다. @@ -252,7 +252,7 @@ Pipeline을 생성하는 함수에 `grouped_entities=True` 옵션을 전달하 ## 질의 응답(Question-answering) -질의 응답(`question-answering`) pipeline은 주어진 지문(context)의 정보를 활용하여 질문에 답을 합니다: +질의 응답(`question-answering`) 파이프라인은 주어진 지문(context)의 정보를 활용하여 질문에 답을 합니다: ``` from transformers import pipeline @@ -270,7 +270,7 @@ question_answerer( ``` -본 pipeline은 답을 새롭게 생성하지 않고 주어진 지문에서 정답을 추출하는 방식임을 잘 기억하세요. +본 파이프라인은 답을 새롭게 생성하지 않고 주어진 지문에서 정답을 추출하는 방식임을 잘 기억하세요. ## 요약(Summarization) @@ -320,8 +320,6 @@ summarizer( ## 번역(Translation) -For translation, you can use a default model if you provide a language pair in the task name (such as `"translation_en_to_fr"`), but the easiest way is to pick the model you want to use on the [Model Hub](https://huggingface.co/models). Here we'll try translating from French to English: - 번역의 경우 (`"translation_en_to_fr"` 와 같이) 작업명에 언어 쌍을 넣어준다면 기본 모델을 사용할 수 있지만, [Model Hub](https://huggingface.co/models)에서 원하는 모델을 고르는 방식이 가장 간단합니다. 여기서는 프랑스어에서 영어로 번역을 시도해 보겠습니다: ``` @@ -345,6 +343,4 @@ translator("Ce cours est produit par Hugging Face.") -The pipelines shown so far are mostly for demonstrative purposes. They were programmed for specific tasks and cannot perform variations of them. In the next chapter, you'll learn what's inside a `pipeline()` function and how to customize its behavior. - -지금까지 보여드린 pipeline들은 대부분 특정 작업을 위해 프로그래밍된, 다양한 변형 작업을 수행할 수 없는 데모용 pipeline입니다. 다음 단원에서는 `pipeline()` 함수 내부를 살펴보고 그 동작을 사용자가 직접 설계하는 방법을 다루겠습니다. \ No newline at end of file +지금까지 보여드린 파이프라인들은 대부분 특정 작업을 위해 프로그래밍된, 다양한 변형 작업을 수행할 수 없는 데모용 파이프라인입니다. 다음 단원에서는 `pipeline()` 함수 내부를 살펴보고 그 동작을 사용자가 직접 설계하는 방법을 다루겠습니다. \ No newline at end of file diff --git a/chapters/ko/chapter1/4.mdx b/chapters/ko/chapter1/4.mdx index b8b552039..3b041e435 100644 --- a/chapters/ko/chapter1/4.mdx +++ b/chapters/ko/chapter1/4.mdx @@ -20,8 +20,6 @@ - **2019년 10월**: [BART](https://arxiv.org/abs/1910.13461) 와 [T5](https://arxiv.org/abs/1910.10683), 동일한 구조의 (처음으로) 원본 트랜스포머 모델의 구조를 그대로 따른 두 거대 사전학습 언어 모델 - **2020년 5월**, [GPT-3](https://arxiv.org/abs/2005.14165), 미세 조정 없이도 (zero-shot learning이라 부름) 다양한 작업을 훌륭하게 수행하는 GPT-2의 더 큰 버전 -This list is far from comprehensive, and is just meant to highlight a few of the different kinds of Transformer models. Broadly, they can be grouped into three categories: - 위 리스트는 단순히 서로 다른 종류의 트랜스포머 모델들 중 몇몇을 강조하기 위한 목록일 뿐, 포괄적이지 않습니다. 넓은 관점에서 트랜스포머 모델은 아래와 같이 세 카테고리로 그룹화 할 수 있습니다: - GPT-계열 (*Auto-regressive* 트랜스포머 모델로도 불림) diff --git a/chapters/ko/chapter1/8.mdx b/chapters/ko/chapter1/8.mdx index 919cadd54..1466b0fbe 100644 --- a/chapters/ko/chapter1/8.mdx +++ b/chapters/ko/chapter1/8.mdx @@ -9,7 +9,7 @@ options={[ 사전 학습된 혹은 미세 조정된 모델을 프로덕션 단계에서 사용하실 계획이라면, 이러한 모델들은 강력한 툴이지만 한계가 있음을 반드시 명심하셔야 합니다. 가장 큰 한계점은 리서처들이 무수히 많은 양의 데이터를 사전 학습에 사용하기 위해, 인터넷상에서 모을 수 있는 양질의 데이터와 함께 그렇지 않은 데이터까지 수집했을 가능성이 있다는 것입니다. -이를 빠르게 보여드리기 위해 `fill-mask` pipeline에 BERT 모델을 연결한 예제를 다시 살펴보겠습니다: +이를 빠르게 보여드리기 위해 `fill-mask` 파이프라인에 BERT 모델을 연결한 예제를 다시 살펴보겠습니다: ``` from transformers import pipeline From d84afe9489593822b7f6fedf465ffc18f0bf8b0f Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Sun, 3 Apr 2022 22:56:43 +0900 Subject: [PATCH 11/73] maximize Korean expressions --- chapters/ko/chapter1/1.mdx | 2 +- chapters/ko/chapter1/10.mdx | 2 +- chapters/ko/chapter1/3.mdx | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/chapters/ko/chapter1/1.mdx b/chapters/ko/chapter1/1.mdx index 7ed285c2a..3a657a966 100644 --- a/chapters/ko/chapter1/1.mdx +++ b/chapters/ko/chapter1/1.mdx @@ -15,7 +15,7 @@ -- 단원 1~4에서는 🤗 Transformers 라이브러리의 핵심 개념에 대해 소개합니다. 이번 강의 끝무렵에 아마 여러분들은 트랜스포머 모델이 어떻게 동작하는지 터득하게 될거고, [Hugging Face Hub](https://huggingface.co/models)에서 모델을 사용하고 데이터셋으로 fine-tune하고 Hub에 여러분의 모델을 공유하는 방법까지 알게 될 것입니다! +- 단원 1~4에서는 🤗 Transformers 라이브러리의 핵심 개념에 대해 소개합니다. 이번 강의 끝무렵에 아마 여러분들은 트랜스포머 모델이 어떻게 동작하는지 터득하게 될거고, [Hugging Face Hub](https://huggingface.co/models)에서 모델을 사용하고 데이터셋으로 미세 조정(fine-tune)하고 Hub에 여러분의 모델을 공유하는 방법까지 알게 될 것입니다! - 단원 5~8은 본격적으로 전형적인 NLP 작업을 하기 앞서, 🤗 Datasets와 🤗 Tokenizers의 기초를 다룹니다. 이 부분을 모두 학습하면 여러분들은 가장 일반적인 NLP 문제를 스스로 해낼 수 있습니다. - 단원 9~12에서는 NLP를 넘어, 트랜스포머 모델이 음성 처리 및 컴퓨터 비전에 어떻게 활용되는지 탐구합니다. 이 과정에서 여러분들의 모델 데모를 구축하고 공유하는 방법 및 이를 프로덕션 환경에 최적화하는 방법을 배우게 됩니다. 최종적으로, 여러분들은 거의 모든 기계 학습(머신 러닝) 문제에 🤗 Transformers를 적용할 준비를 갖추게 됩니다! diff --git a/chapters/ko/chapter1/10.mdx b/chapters/ko/chapter1/10.mdx index bcbe320a5..ae80692e5 100644 --- a/chapters/ko/chapter1/10.mdx +++ b/chapters/ko/chapter1/10.mdx @@ -2,7 +2,7 @@ # 단원 마무리 퀴즈 -이번 단원에서는 정말 많은 내용을 다뤘습니다! 그러니 모든 디테일을 이해하지 못했다고 해서 좌절하지 마세요. 다음 단원은 내부 작동 방식을 이해하는 데에 도움이 될거에요. +이번 챕터에서는 정말 많은 내용들을 다뤘습니다! 그러니 모든 디테일을 이해하지 못했다고 해서 좌절하지 마세요. 다음 단원은 내부 작동 방식을 이해하는 데에 도움이 될거에요. 그래도 우선, 이번 단원에서 배운 내용에 대해 확인해보는 시간을 갖도록 하겠습니다! diff --git a/chapters/ko/chapter1/3.mdx b/chapters/ko/chapter1/3.mdx index 72a22f741..ae47531b2 100644 --- a/chapters/ko/chapter1/3.mdx +++ b/chapters/ko/chapter1/3.mdx @@ -21,7 +21,7 @@ options={[ Companies using Hugging Face -[🤗 Transformers library](https://github.com/huggingface/transformers)는 이렇게 공유한 모델을 사용하고 구축하는 기능들을 제공합니다. [Model Hub](https://huggingface.co/models)에서는 모두가 다운로드 받아 쓸 수 있는 수 천 개의 사전 학습된 모델들이 여러분을 기다리고 있습니다. 여러분만의 모델을 Hub에 업로드하는 것 또한 가능합니다! +[🤗 Transformers 라이브러리](https://github.com/huggingface/transformers)는 이렇게 공유한 모델을 사용하고 구축하는 기능들을 제공합니다. [Model Hub](https://huggingface.co/models)에서는 모두가 다운로드 받아 쓸 수 있는 수 천 개의 사전 학습된 모델들이 여러분을 기다리고 있습니다. 여러분만의 모델을 Hub에 업로드하는 것 또한 가능합니다! @@ -184,9 +184,9 @@ generator( ### 추론(Inference) API -모든 모델들은 Hugging Face [웹사이트](https://huggingface.co/)에서 제공하는 추론 API를 통해 여러분의 브라우저상에서 직접 테스트가 가능합니다. 이 페이지를 통해 직접 나만의 텍스트를 입력하고 모델이 입력 데이터를 처리하는걸 구경하며 모델을 갖고 놀 수 있습니다. +모든 모델들은 [Hugging Face 웹사이트](https://huggingface.co/)에서 제공하는 추론 API를 통해 여러분의 브라우저상에서 직접 테스트가 가능합니다. 이 페이지를 통해 직접 나만의 텍스트를 입력하고 모델이 입력 데이터를 처리하는걸 구경하며 모델을 갖고 놀 수 있습니다. -위젯을 구동하는 추론 API는 간편한 워크플로우를 가능하게 하는 유료 버전의 제품으로도 이용 가능합니다. 자세한 사항은 [가격 페이지](https://huggingface.co/pricing)를 참고해주세요. +위젯을 구동하는 추론 API는 간편한 워크플로우를 가능하게 하는 유료 버전의 제품으로도 이용 가능합니다. 자세한 사항은 [가격 정책 페이지](https://huggingface.co/pricing)를 참고해주세요. ## 마스크 채우기(Mask filling) From 1193811ac416d943e5c8daf69f2cf4a7570cb269 Mon Sep 17 00:00:00 2001 From: m_khandaker Date: Mon, 4 Apr 2022 16:34:51 +0900 Subject: [PATCH 12/73] [Chapter 1] bangla traslation initial commit --- chapters/bn/chapter0/1.mdx | 113 +++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 chapters/bn/chapter0/1.mdx diff --git a/chapters/bn/chapter0/1.mdx b/chapters/bn/chapter0/1.mdx new file mode 100644 index 000000000..be248acba --- /dev/null +++ b/chapters/bn/chapter0/1.mdx @@ -0,0 +1,113 @@ +# ভূমিকা + +হাগিং ফেস কোর্সে স্বাগতম! এই অধ্যায়টি একটি "ওয়ার্কিং এনভায়রনমেন্ট" সেট আপ করতে আপনাকে গাইড করবে। আপনি যদি এইপ্রথম কোর্সটি শুরু করে থাকেন, আমরা আপনাকে প্রথমে [অধ্যায় 1](/course/chapter1) একবার দেখে পড়ে আসার পরামর্শ দিচ্ছি, ফিরে এসে "ওয়ার্কিং এনভায়রনমেন্ট" সেট আপ করুন যাতে আপনি নিজেই কোডটি চেষ্টা করতে পারেন। + +এই কোর্সে আমরা যে সমস্ত লাইব্রেরিগুলি ব্যবহার করব সেগুলি পাইথন প্যাকেজ হিসাবে পাওয়া যাবে, তাই এখানে আমরা আপনাকে দেখাব কিভাবে একটি পাইথন এনভায়রনমেন্ট সেট আপ করতে হয় এবং আপনার প্রয়োজনীয় নির্দিষ্ট লাইব্রেরিগুলি ইনস্টল করতে হয়৷ + +Colab নোটবুক বা পাইথন virtual environment ব্যবহার করে আমরা "ওয়ার্কিং এনভায়রনমেন্ট" সেট-আপ করার দুটি উপায় কভার করব। যে পদ্ধতিটি আপনার কাছে সহজ সেটি আপনি বেছে নিতে পাড়েন। যারা নতুন শুরু করছেন তাদের জন্য আমরা Colab নোটবুক ব্যবহার করে শুরু করতে জোরালোভাবে রিকমেন্ড করি। + +মনে রাখবেন যে এখানে উইন্ডোজ সিস্টেম কভার করা হবে না। আপনি যদি উইন্ডোজ চালান, তাহলে আমরা Colab নোটবুক ব্যবহার করে ফলো করার পরামর্শ দিচ্ছি। আর আপনি যদি লিনাক্স ডিস্ট্রিবিউশন বা ম্যাকওএস ব্যবহার করেন তবে এখানে বর্ণিত পদ্ধতির যেকোনো একটি ব্যবহার করতে পারেন। + +কোর্সের অনেকটাই হাগিং ফেস অ্যাকাউন্ট উপর নির্ভর করবে। তাই আমরা একটি একাউন্ট ওপেন করার করার পরামর্শ দিচ্ছি: [একটি অ্যাকাউন্ট তৈরি করুন](https://huggingface.co/join)। + +## Google Colab নোটবুক ব্যবহার করার পদ্ধতি + +Colab নোটবুক ব্যবহার করার সবচেয়ে সহজ সেটআপ হচ্ছে ব্রাউজারে একটি নোটবুক ওপেন করুন এবং সরাসরি কোডিং এ যান! + +আপনি যদি Colab-এর সাথে পরিচিত না হন তাহলে আমরা আপনাকে [পরিচয়](https://colab.research.google.com/notebooks/intro.ipynb) অনুসরণ করে শুরু করার পরামর্শ দিচ্ছি। Colab আপনাকে কিছু এক্সেলারেসন হার্ডওয়্যার ব্যবহার করতে দেয়, যেমন GPUs বা TPUs এবং এটি ছোট ওয়ার্ক লোডের জন্য ফ্রি। + +Colab-এর আপানার হাত চলে আসলে, একটি নতুন নোটবুক ওপেন করে সেট-আপ শুরু করুন: + +
+An empty colab notebook +
+ +পরবর্তী ধাপে আমরা এই কোর্সে ব্যবহার হবে এমন লাইব্রেরিগুলি ইনস্টল করা দেখাবো। আমরা ইনস্টলেশনের জন্য `pip` ব্যবহার করব, যা পাইথনের প্যাকেজ ম্যানেজার। নোটবুকগুলিতে, আপনি `!` অক্ষর দিয়ে আগে সিস্টেম কমান্ড চালাতে পারবেন। যেমন ধরুন, নিচের কমান্ডটি দিয়ে 🤗 Transformers লাইব্রেরি ইনস্টল করতে পারবেন: + +``` +!pip install transformers +``` + +প্যাকেজটি আপনার পাইথন রানটাইমের মধ্যে সঠিকভাবে ইনস্টল করা হয়েছে কিনা তা import করে নিশ্চিত হতে পাড়েন। + +``` +import transformers +``` + +
+একটি gif উপরের দুটি কমান্ডের ফলাফল দেখাচ্ছে: installation and import +
+ +এটি 🤗 ট্রান্সফরমারের একটি খুব লাইট ভার্সন ইনস্টল করে। বিশেষ করে, যদিনা নির্দিষ্ট মেশিন লার্নিং ফ্রেমওয়ার্ক (যেমন PyTorch বা TensorFlow) ইনস্টল করা থাকে। যেহেতু আমরা লাইব্রেরির বিভিন্ন ফিচার ব্যবহার করব, তাই আমরা ডেভেলপমেন্ট ভার্সন ইনস্টল করার পরামর্শ দিচ্ছি, যতে ধারানা করার এমন সব ইউজ কেসে কাজ করবে: + +``` +!pip install transformers[sentencepiece] +``` + +ইনস্টল হতে কিছুটা সময় লাগবে, কিন্তু এরপর আপনি বাকি কোর্সের জন্য প্রস্তুত হয়ে যাবেন! + +## একটি পাইথন virtual environment ব্যবহার করা + +আপনি যদি পাইথন virtual environment ব্যবহার করতে পছন্দ করেন, প্রথম ধাপ হল আপনার সিস্টেমে পাইথন ইনস্টল করা। শুরু করার জন্য আমরা [এই নির্দেশিকা](https://realpython.com/installing-python/) অনুসরণ করার পরামর্শ দিচ্ছি। + +একবার আপনি পাইথন ইনস্টল করলে, আপনি আপনার টার্মিনালে পাইথন কমান্ড চালাতে সক্ষম হবেন। পরবর্তী ধাপে যাওয়ার আগে এটি সঠিকভাবে ইনস্টল করা হয়েছে তা নিশ্চিত করতে আপনি নিম্নলিখিত কমান্ডটি চালিয়ে শুরু করতে পারেন: `python --version`। এটি আপনার সিস্টেমে উপলব্ধ পাইথন সংস্করণটি প্রিন্ট করা উচিত। + +আপনার টার্মিনালে পাইথন কমান্ড চালানোর সময়, যেমন `python --version`, আপনার সিস্টেমে "main" পাইথন হিসাবে আপনার কমান্ডটি চালানোর প্রোগ্রামটিকে ভাবতে হবে। আমরা এই মূল ইনস্টলেশনটিকে যেকোন প্যাকেজ ইনস্টল থেকে মুক্ত রাখার সুপারিশ করি। এ আপনি যখন আলাদা অ্যাপ্লিকেশনে কাজ করবেঙ তখন তার জন্য আলাদা virtual environment তৈরি করতে এই পাইথন ইনস্টলেশনটিকে ব্যবহার করবেন। এতে করে প্রতিটি অ্যাপ্লিকেশনের নিজস্ব ডিপেন্ডেন্সি এবং প্যাকেজ আলাদা থাকবে এবং অন্যান্য অ্যাপ্লিকেশনের সাথে এর সম্ভাব্য কম্পাটিবিলটি নিয়ে আপানকে সমস্যায় করতে হবে না। + +পাইথনে এটি [*virtual environments*](https://docs.python.org/3/tutorial/venv.html) দিয়ে করা হয়, যেটি স্বয়ংসম্পূর্ণ ডিরেক্টরি ট্রি। যার প্রত্যেকটিতে এপ্লিকেশন প্রয়োজনীয় সমস্ত প্যাকেজের পাশাপাশি একটি নির্দিষ্ট পাইথন ভার্শনের পাইথন ইনস্টলেশন আছে। এই ধরনের একটি virtual environments তৈরি করা বিভিন্ন ভাবে করা যেতে পারে। তবে আমরা এর জন্য অফিসিয়াল পাইথন প্যাকেজ ব্যবহার করব, যাকে বলা হয় [`venv`](https://docs.python.org/3/library) /venv.html#module-venv)। + +প্রথমে, আপনি যে ডিরেক্টরিটি আপনার অ্যাপ্লিকেশনটিতে রাখতে চান তা তৈরি করুন — উদাহরণস্বরূপ, আপনি আপনার হোম ডিরেক্টরির বা ফোল্ডার ভেতর *transformers-course* নামে একটি নতুন ডিরেক্টরি তৈরি করতে চাইতে পারেন: + +``` +mkdir ~/transformers-course +cd ~/transformers-course +``` + +এই ডিরেক্টরির ভিতর থেকে, পাইথন `venv` মডিউল ব্যবহার করে একটি virtual environment তৈরি করুন: + +``` +python -m venv .env +``` + +আপনার এখন *.env* নামে একটি ফোল্ডার থাকা উচিত, অন্যথায় খালি ফোল্ডার : + +``` +ls -a +``` + +```out +. .. .env +``` +আপনি এখন virtual environment টি `activate` করতে বা `deactivate` নিচের কমান্ড গুলো ব্যবহার করতে পারেন। + +``` + + +``` +# virtual environment টি activate করার কমান্ড +source .env/bin/activate + +# virtual environment টি deactivate করার কমান্ড +source .env/bin/deactivate +``` + +`which python` কমান্ড চালিয়ে নিশ্চিত করতে পারেন যে virtual environment টি activate হয়েছে কিনা। +যদি এটি virtual environment টি কে পয়েন্ট করে করে, তাহলে আপনি সফলভাবে এটি সক্রিয় করেছেন! + +``` +which python +``` + +```out +/home//transformers-course/.env/bin/python +``` + +### ডিপেন্ডেন্সি ইনস্টল করা + +আগের সেকশনে Google Colab এ যেভাবে প্যাকেজ ইনস্টল করা হয়েছে একই ভাবে এখানেও `pip` প্যাকেজ ম্যানেজার ব্যবহার করে 🤗 Transformer এর development সংস্করণ ইনস্টল করতে পারেন: + +```` +pip install "transformers[sentencepiece]" +```` + +আপনি এখন শুরু করা জন্য সম্পূর্ণ প্রস্তুত! \ No newline at end of file From 33e0a046ae33b9f664fa954dd871d9f15c916cad Mon Sep 17 00:00:00 2001 From: "Md. Al-Amin Khandaker" Date: Mon, 4 Apr 2022 16:41:12 +0900 Subject: [PATCH 13/73] Update 1.mdx update and fix formating --- chapters/bn/chapter0/1.mdx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/chapters/bn/chapter0/1.mdx b/chapters/bn/chapter0/1.mdx index be248acba..ac094fab3 100644 --- a/chapters/bn/chapter0/1.mdx +++ b/chapters/bn/chapter0/1.mdx @@ -76,12 +76,11 @@ ls -a ``` ```out -. .. .env +. .. .env ``` -আপনি এখন virtual environment টি `activate` করতে বা `deactivate` নিচের কমান্ড গুলো ব্যবহার করতে পারেন। -``` +আপনি এখন virtual environment টি `activate` করতে বা `deactivate` নিচের কমান্ড গুলো ব্যবহার করতে পারেন। ``` # virtual environment টি activate করার কমান্ড @@ -110,4 +109,4 @@ which python pip install "transformers[sentencepiece]" ```` -আপনি এখন শুরু করা জন্য সম্পূর্ণ প্রস্তুত! \ No newline at end of file +আপনি এখন শুরু করা জন্য সম্পূর্ণ প্রস্তুত! From fa77e72667ae1bf7f8bf25831d254f3ec9623e08 Mon Sep 17 00:00:00 2001 From: m_khandaker Date: Mon, 4 Apr 2022 20:49:03 +0900 Subject: [PATCH 14/73] Fix formating and typos --- chapters/bn/_toctree.yml | 173 +++++++++++++++++++++++++++++++++++++ chapters/bn/chapter0/1.mdx | 12 +-- 2 files changed, 179 insertions(+), 6 deletions(-) create mode 100644 chapters/bn/_toctree.yml diff --git a/chapters/bn/_toctree.yml b/chapters/bn/_toctree.yml new file mode 100644 index 000000000..6c1a4730c --- /dev/null +++ b/chapters/bn/_toctree.yml @@ -0,0 +1,173 @@ +- title: 0. Setup + sections: + - local: chapter0/1 + title: Introduction + +- title: 1. Transformer models + sections: + - local: chapter1/1 + title: Introduction + - local: chapter1/2 + title: Natural Language Processing + - local: chapter1/3 + title: Transformers, what can they do? + - local: chapter1/4 + title: How do Transformers work? + - local: chapter1/5 + title: Encoder models + - local: chapter1/6 + title: Decoder models + - local: chapter1/7 + title: Sequence-to-sequence models + - local: chapter1/8 + title: Bias and limitations + - local: chapter1/9 + title: Summary + - local: chapter1/10 + title: End-of-chapter quiz + quiz: 1 + +- title: 2. Using 🤗 Transformers + sections: + - local: chapter2/1 + title: Introduction + - local: chapter2/2 + title: Behind the pipeline + - local: chapter2/3 + title: Models + - local: chapter2/4 + title: Tokenizers + - local: chapter2/5 + title: Handling multiple sequences + - local: chapter2/6 + title: Putting it all together + - local: chapter2/7 + title: Basic usage completed! + - local: chapter2/8 + title: End-of-chapter quiz + quiz: 2 + +- title: 3. Fine-tuning a pretrained model + sections: + - local: chapter3/1 + title: Introduction + - local: chapter3/2 + title: Processing the data + - local: chapter3/3 + title: Fine-tuning a model with the Trainer API or Keras + local_fw: { pt: chapter3/3, tf: chapter3/3_tf } + - local: chapter3/4 + title: A full training + - local: chapter3/5 + title: Fine-tuning, Check! + - local: chapter3/6 + title: End-of-chapter quiz + quiz: 3 + +- title: 4. Sharing models and tokenizers + sections: + - local: chapter4/1 + title: The Hugging Face Hub + - local: chapter4/2 + title: Using pretrained models + - local: chapter4/3 + title: Sharing pretrained models + - local: chapter4/4 + title: Building a model card + - local: chapter4/5 + title: Part 1 completed! + - local: chapter4/6 + title: End-of-chapter quiz + quiz: 4 + +- title: 5. The 🤗 Datasets library + sections: + - local: chapter5/1 + title: Introduction + - local: chapter5/2 + title: What if my dataset isn't on the Hub? + - local: chapter5/3 + title: Time to slice and dice + - local: chapter5/4 + title: Big data? 🤗 Datasets to the rescue! + - local: chapter5/5 + title: Creating your own dataset + - local: chapter5/6 + title: Semantic search with FAISS + - local: chapter5/7 + title: 🤗 Datasets, check! + - local: chapter5/8 + title: End-of-chapter quiz + quiz: 5 + +- title: 6. The 🤗 Tokenizers library + sections: + - local: chapter6/1 + title: Introduction + - local: chapter6/2 + title: Training a new tokenizer from an old one + - local: chapter6/3 + title: Fast tokenizers' special powers + - local: chapter6/3b + title: Fast tokenizers in the QA pipeline + - local: chapter6/4 + title: Normalization and pre-tokenization + - local: chapter6/5 + title: Byte-Pair Encoding tokenization + - local: chapter6/6 + title: WordPiece tokenization + - local: chapter6/7 + title: Unigram tokenization + - local: chapter6/8 + title: Building a tokenizer, block by block + - local: chapter6/9 + title: Tokenizers, check! + - local: chapter6/10 + title: End-of-chapter quiz + quiz: 6 + +- title: 7. Main NLP tasks + sections: + - local: chapter7/1 + title: Introduction + - local: chapter7/2 + title: Token classification + - local: chapter7/3 + title: Fine-tuning a masked language model + - local: chapter7/4 + title: Translation + - local: chapter7/5 + title: Summarization + - local: chapter7/6 + title: Training a causal language model from scratch + - local: chapter7/7 + title: Question answering + - local: chapter7/8 + title: Mastering NLP + - local: chapter7/9 + title: End-of-chapter quiz + quiz: 7 + +- title: 8. How to ask for help + sections: + - local: chapter8/1 + title: Introduction + - local: chapter8/2 + title: What to do when you get an error + - local: chapter8/3 + title: Asking for help on the forums + - local: chapter8/4 + title: Debugging the training pipeline + local_fw: { pt: chapter8/4, tf: chapter8/4_tf } + - local: chapter8/5 + title: How to write a good issue + - local: chapter8/6 + title: Part 2 completed! + - local: chapter8/7 + title: End-of-chapter quiz + quiz: 8 + +- title: Hugging Face Course Event + sections: + - local: event/1 + title: Part 2 Release Event diff --git a/chapters/bn/chapter0/1.mdx b/chapters/bn/chapter0/1.mdx index ac094fab3..b1e5879df 100644 --- a/chapters/bn/chapter0/1.mdx +++ b/chapters/bn/chapter0/1.mdx @@ -14,15 +14,15 @@ Colab নোটবুক বা পাইথন virtual environment ব্যব Colab নোটবুক ব্যবহার করার সবচেয়ে সহজ সেটআপ হচ্ছে ব্রাউজারে একটি নোটবুক ওপেন করুন এবং সরাসরি কোডিং এ যান! -আপনি যদি Colab-এর সাথে পরিচিত না হন তাহলে আমরা আপনাকে [পরিচয়](https://colab.research.google.com/notebooks/intro.ipynb) অনুসরণ করে শুরু করার পরামর্শ দিচ্ছি। Colab আপনাকে কিছু এক্সেলারেসন হার্ডওয়্যার ব্যবহার করতে দেয়, যেমন GPUs বা TPUs এবং এটি ছোট ওয়ার্ক লোডের জন্য ফ্রি। +আপনি যদি Colab-এর সাথে পরিচিত না হন তাহলে আমরা আপনাকে [Colab পরিচয়](https://colab.research.google.com/notebooks/intro.ipynb) অনুসরণ করে শুরু করার পরামর্শ দিচ্ছি। Colab আপনাকে কিছু এক্সেলারেসন হার্ডওয়্যার ব্যবহার করতে দেয়, যেমন GPUs বা TPUs যা ছোট ওয়ার্ক লোডের জন্য ফ্রি। -Colab-এর আপানার হাত চলে আসলে, একটি নতুন নোটবুক ওপেন করে সেট-আপ শুরু করুন: +Colab-এর উপর আপানার হাত চলে আসলে একটি নতুন নোটবুক ওপেন করে সেট-আপ শুরু করুন:
An empty colab notebook
-পরবর্তী ধাপে আমরা এই কোর্সে ব্যবহার হবে এমন লাইব্রেরিগুলি ইনস্টল করা দেখাবো। আমরা ইনস্টলেশনের জন্য `pip` ব্যবহার করব, যা পাইথনের প্যাকেজ ম্যানেজার। নোটবুকগুলিতে, আপনি `!` অক্ষর দিয়ে আগে সিস্টেম কমান্ড চালাতে পারবেন। যেমন ধরুন, নিচের কমান্ডটি দিয়ে 🤗 Transformers লাইব্রেরি ইনস্টল করতে পারবেন: +পরবর্তী ধাপে আমরা এই কোর্সে ব্যবহার হবে এমন লাইব্রেরিগুলি ইনস্টল করা দেখাবো। আমরা ইনস্টলেশনের জন্য পাইথনের প্যাকেজ ম্যানেজার `pip` ব্যবহার করব। নোটবুকগুলিতে, আপনি `!` অক্ষর দিয়ে আগে সিস্টেম কমান্ড চালাতে পারবেন। যেমন ধরুন, নিচের কমান্ডটি দিয়ে 🤗 Transformers লাইব্রেরি ইনস্টল করতে পারবেন: ``` !pip install transformers @@ -50,11 +50,11 @@ import transformers আপনি যদি পাইথন virtual environment ব্যবহার করতে পছন্দ করেন, প্রথম ধাপ হল আপনার সিস্টেমে পাইথন ইনস্টল করা। শুরু করার জন্য আমরা [এই নির্দেশিকা](https://realpython.com/installing-python/) অনুসরণ করার পরামর্শ দিচ্ছি। -একবার আপনি পাইথন ইনস্টল করলে, আপনি আপনার টার্মিনালে পাইথন কমান্ড চালাতে সক্ষম হবেন। পরবর্তী ধাপে যাওয়ার আগে এটি সঠিকভাবে ইনস্টল করা হয়েছে তা নিশ্চিত করতে আপনি নিম্নলিখিত কমান্ডটি চালিয়ে শুরু করতে পারেন: `python --version`। এটি আপনার সিস্টেমে উপলব্ধ পাইথন সংস্করণটি প্রিন্ট করা উচিত। +একবার আপনি পাইথন ইনস্টল করলে, আপনি আপনার টার্মিনালে পাইথন কমান্ড চালাতে সক্ষম হবেন। পরবর্তী ধাপে যাওয়ার আগে এটি সঠিকভাবে ইনস্টল করা হয়েছে তা নিশ্চিত করতে আপনি নিম্নলিখিত কমান্ডটি চালিয়ে শুরু করতে পারেন: `python --version`। এটি আপনার সিস্টেমে ইনস্টল হওয়া পাইথন সংস্করণটি প্রিন্ট করা উচিত। -আপনার টার্মিনালে পাইথন কমান্ড চালানোর সময়, যেমন `python --version`, আপনার সিস্টেমে "main" পাইথন হিসাবে আপনার কমান্ডটি চালানোর প্রোগ্রামটিকে ভাবতে হবে। আমরা এই মূল ইনস্টলেশনটিকে যেকোন প্যাকেজ ইনস্টল থেকে মুক্ত রাখার সুপারিশ করি। এ আপনি যখন আলাদা অ্যাপ্লিকেশনে কাজ করবেঙ তখন তার জন্য আলাদা virtual environment তৈরি করতে এই পাইথন ইনস্টলেশনটিকে ব্যবহার করবেন। এতে করে প্রতিটি অ্যাপ্লিকেশনের নিজস্ব ডিপেন্ডেন্সি এবং প্যাকেজ আলাদা থাকবে এবং অন্যান্য অ্যাপ্লিকেশনের সাথে এর সম্ভাব্য কম্পাটিবিলটি নিয়ে আপানকে সমস্যায় করতে হবে না। +আপনার টার্মিনালে পাইথন কমান্ড চালানোর সময়, যেমন `python --version`, আপানাকে ভাবতে হবে যে এটি "main" পাইথন প্রোগ্রাম যা আপানার কমান্ড টিকে রান করছে। আমরা এই মূল ইনস্টলেশনটিকে যেকোন প্যাকেজ ইনস্টল থেকে মুক্ত রাখার সুপারিশ করি। এ আপনি যখন আলাদা অ্যাপ্লিকেশনে কাজ করবেন তখন তার জন্য আলাদা virtual environment তৈরি করতে এই পাইথন ইনস্টলেশনটিকে ব্যবহার করবেন। এতে করে প্রতিটি অ্যাপ্লিকেশনের নিজস্ব ডিপেন্ডেন্সি এবং প্যাকেজ আলাদা থাকবে এবং অন্যান্য অ্যাপ্লিকেশনের সাথে এর সম্ভাব্য কম্পাটিবিলটি নিয়ে আপানকে সমস্যায় করতে হবে না। -পাইথনে এটি [*virtual environments*](https://docs.python.org/3/tutorial/venv.html) দিয়ে করা হয়, যেটি স্বয়ংসম্পূর্ণ ডিরেক্টরি ট্রি। যার প্রত্যেকটিতে এপ্লিকেশন প্রয়োজনীয় সমস্ত প্যাকেজের পাশাপাশি একটি নির্দিষ্ট পাইথন ভার্শনের পাইথন ইনস্টলেশন আছে। এই ধরনের একটি virtual environments তৈরি করা বিভিন্ন ভাবে করা যেতে পারে। তবে আমরা এর জন্য অফিসিয়াল পাইথন প্যাকেজ ব্যবহার করব, যাকে বলা হয় [`venv`](https://docs.python.org/3/library) /venv.html#module-venv)। +পাইথনে এটি [*virtual environments*](https://docs.python.org/3/tutorial/venv.html) দিয়ে করা হয়, যেটি স্বয়ংসম্পূর্ণ ডিরেক্টরি ট্রি। যার প্রত্যেকটিতে এপ্লিকেশনের প্রয়োজনীয় সমস্ত প্যাকেজের পাশাপাশি একটি নির্দিষ্ট পাইথন ভার্শনের পাইথন ইনস্টলেশন আছে। এই ধরনের একটি virtual environments বিভিন্ন ভাবে তৈরি করা যেতে পারে। তবে আমরা এর জন্য অফিসিয়াল পাইথন প্যাকেজ ব্যবহার করব, যাকে বলা হয় [`venv`](https://docs.python.org/3/library) /venv.html#module-venv)। প্রথমে, আপনি যে ডিরেক্টরিটি আপনার অ্যাপ্লিকেশনটিতে রাখতে চান তা তৈরি করুন — উদাহরণস্বরূপ, আপনি আপনার হোম ডিরেক্টরির বা ফোল্ডার ভেতর *transformers-course* নামে একটি নতুন ডিরেক্টরি তৈরি করতে চাইতে পারেন: From ef201cbba77594412927694cf5f2b17885dcf3ce Mon Sep 17 00:00:00 2001 From: m_khandaker Date: Mon, 4 Apr 2022 21:41:41 +0900 Subject: [PATCH 15/73] translate _toctree.yml 0-1 chapter --- chapters/bn/_toctree.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/chapters/bn/_toctree.yml b/chapters/bn/_toctree.yml index 6c1a4730c..fb1fabec5 100644 --- a/chapters/bn/_toctree.yml +++ b/chapters/bn/_toctree.yml @@ -1,30 +1,30 @@ -- title: 0. Setup +- title: 0. সেটআপ sections: - local: chapter0/1 - title: Introduction + title: ভূমিকা -- title: 1. Transformer models +- title: 1. ট্রান্সফরমার মডেল sections: - local: chapter1/1 - title: Introduction + title: ভূমিকা - local: chapter1/2 - title: Natural Language Processing + title: ন্যাচারাল ল্যঙ্গুএজ প্রসেসিং - local: chapter1/3 - title: Transformers, what can they do? + title: ট্রান্সফরমার, কি করতে পারে? - local: chapter1/4 - title: How do Transformers work? + title: ট্রান্সফরমার কিভাবে কাজ করে? - local: chapter1/5 - title: Encoder models + title: এনকোডার মডেল - local: chapter1/6 - title: Decoder models + title: ডিকোডার মডেল - local: chapter1/7 - title: Sequence-to-sequence models + title: সিকোয়েন্স টু সিকোয়েন্স মডেল - local: chapter1/8 - title: Bias and limitations + title: পক্ষপাত এবং সীমাবদ্ধতা (বায়াস এবং লিমিটেশন) - local: chapter1/9 - title: Summary + title: সারসংক্ষেপ - local: chapter1/10 - title: End-of-chapter quiz + title: অধ্যায়ের শেষ কুইজ quiz: 1 - title: 2. Using 🤗 Transformers From b66482824b8ef4dc87193f602282d2e1f531bb93 Mon Sep 17 00:00:00 2001 From: Lewis Tunstall Date: Mon, 4 Apr 2022 15:47:58 +0200 Subject: [PATCH 16/73] Add Korean to CI --- .github/workflows/build_documentation.yml | 2 +- .github/workflows/build_pr_documentation.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_documentation.yml b/.github/workflows/build_documentation.yml index a1bea055e..0ea12e682 100644 --- a/.github/workflows/build_documentation.yml +++ b/.github/workflows/build_documentation.yml @@ -14,6 +14,6 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: en es fr he pt th tr + languages: en es fr he ko pt th tr secrets: token: ${{ secrets.HUGGINGFACE_PUSH }} \ No newline at end of file diff --git a/.github/workflows/build_pr_documentation.yml b/.github/workflows/build_pr_documentation.yml index d5757272d..8fcd7524d 100644 --- a/.github/workflows/build_pr_documentation.yml +++ b/.github/workflows/build_pr_documentation.yml @@ -16,5 +16,5 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: en es fr he pt th tr + languages: en es fr he ko pt th tr hub_base_path: https://moon-ci-docs.huggingface.co/course \ No newline at end of file From b58e7e4d63ffc3a1e1b99573b4e7e2a7bee6d6c4 Mon Sep 17 00:00:00 2001 From: ftarlaci <18291571+ftarlaci@users.noreply.github.com> Date: Mon, 4 Apr 2022 13:39:08 -0500 Subject: [PATCH 17/73] [tr] Translated chapter1/2.mdx --- chapters/tr/chapter1/2.mdx | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 chapters/tr/chapter1/2.mdx diff --git a/chapters/tr/chapter1/2.mdx b/chapters/tr/chapter1/2.mdx new file mode 100644 index 000000000..a9536d43a --- /dev/null +++ b/chapters/tr/chapter1/2.mdx @@ -0,0 +1,21 @@ +# Doğal Dil İşleme (NLP) + +Transformer modellerine geçiş yapmadan önce, doğal dil işlemenin tanımına ve neden önemli olduğuna kısaca bir göz atalım. + + +## NLP Nedir? + +NLP, dil bilim ve makina öğrenmesi alanlarini kapsayan, dogal dil üzerine olan herşeyi anlamaya yönelik bir alandır. NLP her bir kelimeyi anlamanın yanısıra, kelimelerin bağlamını anlayabilmeyi amaçlar. Aşağıda NLP görevlerinin genel bir listesini, her bir göreve dair bir kaç örnekle birlikte görülebilir: + +- **Cümle Sınıflandırması: Değerlendirmeler üzerine duygu analizi, spam e-posta saptaması, bir cümlenin dilbilgisel doğruluğunu, ya da iki cümlenin mantıksal olarak bağlı olup olmadığını anlama +- **Cümle içerisindeki her bir kelimenin sınıflandırması: Bir cümlenin dilbilgisel öğelerinin (isim, fiil, sıfat), ya da isim verilmiş varlıkların tanımlanması +- **Metin üretme: Verilen bir ipucunu kullanarak, otomatik olarak metni tamamlama, maskeli kelimeler ile metindeki boşlukları doldurma +- **Metinden cevap çıkarımı: Verilen bir soru ve bağlamı kullanarak, bağlamda verilmi olan bilgiye dayanarak verilen soruyu cevaplama +- **Verilen metni kullanarak yeni bir cümle üretme: Metni başka bir dile çevirme, metin özetleme. + +Metin işlemenin yanısıra, NLP, konuşma tanıma ve bilgisayar görmesi alanlarında gorülen, bir ses örneğini yazıya dökme ya da bir fotoğrafı betimleme gibi komplike işlemleri çözümlemek için de kullanılabilir. + +## NLP Neden Zor? + +Bilgisayarlar, bilgiyi biz insanların yaptığı gibi işlemiyor. Örneğin, insan beyni “Acıktım” gibi basit bir cümlenin anlamını kolaylıkla anlayabilir. Benzer bir şekilde, “acıktım” ve “üzgünüm” cümlelerinin dilbilgisel açıdan benzerliğini kolayca görebiliyoruz. Ancak, makine öğrenmesi modelleri için bu gibi işlemler hiç de kolay değil. Bir modelin, verilen metnin anlamını öğrenebilmesi için metnin belirli bir yöntem ile işlenmesi gerekir. İnsan dilinin bileşikliği nedeniyle, bu işlemenin nasıl yapılacağı konsunu dikkatlice düşünmeliyiz. Bu güne kadar NLP alanında yazının nasıl temsil edileceğine dair bir çok çalışma yapıldı. Bir sonraki bölümde, bu çalışmalarda geliştirilen bazı yöntemlere göz atacağız. + From e82e845f21b232f46dfb5337934d6479ad35b8f8 Mon Sep 17 00:00:00 2001 From: m_khandaker Date: Tue, 5 Apr 2022 22:41:38 +0900 Subject: [PATCH 18/73] remove translation from sec titles not yet translated --- chapters/bn/_toctree.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/chapters/bn/_toctree.yml b/chapters/bn/_toctree.yml index fb1fabec5..b04da2c14 100644 --- a/chapters/bn/_toctree.yml +++ b/chapters/bn/_toctree.yml @@ -6,25 +6,25 @@ - title: 1. ট্রান্সফরমার মডেল sections: - local: chapter1/1 - title: ভূমিকা + title: Introduction - local: chapter1/2 - title: ন্যাচারাল ল্যঙ্গুএজ প্রসেসিং + title: Natural Language Processing - local: chapter1/3 - title: ট্রান্সফরমার, কি করতে পারে? + title: Transformers, what can they do? - local: chapter1/4 - title: ট্রান্সফরমার কিভাবে কাজ করে? + title: How do Transformers work? - local: chapter1/5 - title: এনকোডার মডেল + title: Encoder models - local: chapter1/6 - title: ডিকোডার মডেল + title: Decoder models - local: chapter1/7 - title: সিকোয়েন্স টু সিকোয়েন্স মডেল + title: Sequence-to-sequence models - local: chapter1/8 - title: পক্ষপাত এবং সীমাবদ্ধতা (বায়াস এবং লিমিটেশন) + title: Bias and limitations - local: chapter1/9 - title: সারসংক্ষেপ + title: Summary - local: chapter1/10 - title: অধ্যায়ের শেষ কুইজ + title: End-of-chapter quiz quiz: 1 - title: 2. Using 🤗 Transformers From 045ca30872b385b75e4f73d7d2b4cf9eb9367fa7 Mon Sep 17 00:00:00 2001 From: Lewis Tunstall Date: Tue, 5 Apr 2022 15:55:49 +0200 Subject: [PATCH 19/73] Add authors [th ru] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 32e7d7b11..a10534eef 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,9 @@ This repo contains the content that's used to create the **[Hugging Face course] | Language | Source | Authors | |:-------------------------------------------------------|:-----------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [English](https://huggingface.co/course/en/chapter1/1) | [`chapters/en`](https://github.com/huggingface/course/tree/main/chapters/en) | [@sgugger](https://github.com/sgugger), [@lewtun](https://github.com/lewtun), [@LysandreJik](https://github.com/LysandreJik), [@Rocketknight1](https://github.com/Rocketknight1), [@sashavor](https://github.com/sashavor), [@osanseviero](https://github.com/osanseviero), [@SaulLu](https://github.com/SaulLu), [@lvwerra](https://github.com/lvwerra) | +| [Russian](https://huggingface.co/course/ru/chapter1/1) (WIP) | [`chapters/ru`](https://github.com/huggingface/course/tree/main/chapters/ru) | [@pdumin](https://github.com/pdumin) | | [Spanish](https://huggingface.co/course/es/chapter1/1) (WIP) | [`chapters/es`](https://github.com/huggingface/course/tree/main/chapters/es) | [@camartinezbu](https://github.com/camartinezbu) | -| [Thai](https://huggingface.co/course/th/chapter1/1) (WIP) | [`chapters/th`](https://github.com/huggingface/course/tree/main/chapters/th) | [@peeraponw](https://github.com/peeraponw) | +| [Thai](https://huggingface.co/course/th/chapter1/1) (WIP) | [`chapters/th`](https://github.com/huggingface/course/tree/main/chapters/th) | [@peeraponw](https://github.com/peeraponw), [@a-krirk](https://github.com/a-krirk), [@jomariya23156](https://github.com/jomariya23156) | ### Translating the course into your language From 0f068d502ed56b7bc6298e53349fc0370fb4cdaf Mon Sep 17 00:00:00 2001 From: m_khandaker Date: Tue, 5 Apr 2022 23:55:23 +0900 Subject: [PATCH 20/73] [FIX] _toctree.yml --- chapters/bn/_toctree.yml | 169 --------------------------------------- 1 file changed, 169 deletions(-) diff --git a/chapters/bn/_toctree.yml b/chapters/bn/_toctree.yml index b04da2c14..6be05c074 100644 --- a/chapters/bn/_toctree.yml +++ b/chapters/bn/_toctree.yml @@ -2,172 +2,3 @@ sections: - local: chapter0/1 title: ভূমিকা - -- title: 1. ট্রান্সফরমার মডেল - sections: - - local: chapter1/1 - title: Introduction - - local: chapter1/2 - title: Natural Language Processing - - local: chapter1/3 - title: Transformers, what can they do? - - local: chapter1/4 - title: How do Transformers work? - - local: chapter1/5 - title: Encoder models - - local: chapter1/6 - title: Decoder models - - local: chapter1/7 - title: Sequence-to-sequence models - - local: chapter1/8 - title: Bias and limitations - - local: chapter1/9 - title: Summary - - local: chapter1/10 - title: End-of-chapter quiz - quiz: 1 - -- title: 2. Using 🤗 Transformers - sections: - - local: chapter2/1 - title: Introduction - - local: chapter2/2 - title: Behind the pipeline - - local: chapter2/3 - title: Models - - local: chapter2/4 - title: Tokenizers - - local: chapter2/5 - title: Handling multiple sequences - - local: chapter2/6 - title: Putting it all together - - local: chapter2/7 - title: Basic usage completed! - - local: chapter2/8 - title: End-of-chapter quiz - quiz: 2 - -- title: 3. Fine-tuning a pretrained model - sections: - - local: chapter3/1 - title: Introduction - - local: chapter3/2 - title: Processing the data - - local: chapter3/3 - title: Fine-tuning a model with the Trainer API or Keras - local_fw: { pt: chapter3/3, tf: chapter3/3_tf } - - local: chapter3/4 - title: A full training - - local: chapter3/5 - title: Fine-tuning, Check! - - local: chapter3/6 - title: End-of-chapter quiz - quiz: 3 - -- title: 4. Sharing models and tokenizers - sections: - - local: chapter4/1 - title: The Hugging Face Hub - - local: chapter4/2 - title: Using pretrained models - - local: chapter4/3 - title: Sharing pretrained models - - local: chapter4/4 - title: Building a model card - - local: chapter4/5 - title: Part 1 completed! - - local: chapter4/6 - title: End-of-chapter quiz - quiz: 4 - -- title: 5. The 🤗 Datasets library - sections: - - local: chapter5/1 - title: Introduction - - local: chapter5/2 - title: What if my dataset isn't on the Hub? - - local: chapter5/3 - title: Time to slice and dice - - local: chapter5/4 - title: Big data? 🤗 Datasets to the rescue! - - local: chapter5/5 - title: Creating your own dataset - - local: chapter5/6 - title: Semantic search with FAISS - - local: chapter5/7 - title: 🤗 Datasets, check! - - local: chapter5/8 - title: End-of-chapter quiz - quiz: 5 - -- title: 6. The 🤗 Tokenizers library - sections: - - local: chapter6/1 - title: Introduction - - local: chapter6/2 - title: Training a new tokenizer from an old one - - local: chapter6/3 - title: Fast tokenizers' special powers - - local: chapter6/3b - title: Fast tokenizers in the QA pipeline - - local: chapter6/4 - title: Normalization and pre-tokenization - - local: chapter6/5 - title: Byte-Pair Encoding tokenization - - local: chapter6/6 - title: WordPiece tokenization - - local: chapter6/7 - title: Unigram tokenization - - local: chapter6/8 - title: Building a tokenizer, block by block - - local: chapter6/9 - title: Tokenizers, check! - - local: chapter6/10 - title: End-of-chapter quiz - quiz: 6 - -- title: 7. Main NLP tasks - sections: - - local: chapter7/1 - title: Introduction - - local: chapter7/2 - title: Token classification - - local: chapter7/3 - title: Fine-tuning a masked language model - - local: chapter7/4 - title: Translation - - local: chapter7/5 - title: Summarization - - local: chapter7/6 - title: Training a causal language model from scratch - - local: chapter7/7 - title: Question answering - - local: chapter7/8 - title: Mastering NLP - - local: chapter7/9 - title: End-of-chapter quiz - quiz: 7 - -- title: 8. How to ask for help - sections: - - local: chapter8/1 - title: Introduction - - local: chapter8/2 - title: What to do when you get an error - - local: chapter8/3 - title: Asking for help on the forums - - local: chapter8/4 - title: Debugging the training pipeline - local_fw: { pt: chapter8/4, tf: chapter8/4_tf } - - local: chapter8/5 - title: How to write a good issue - - local: chapter8/6 - title: Part 2 completed! - - local: chapter8/7 - title: End-of-chapter quiz - quiz: 8 - -- title: Hugging Face Course Event - sections: - - local: event/1 - title: Part 2 Release Event From fd8bef7af104d66d29fe711ca150f44c1ce66818 Mon Sep 17 00:00:00 2001 From: "Md. Al-Amin Khandaker" Date: Wed, 6 Apr 2022 00:42:18 +0900 Subject: [PATCH 21/73] Update chapters/bn/chapter0/1.mdx [FIX] syntax formatting Co-authored-by: lewtun --- chapters/bn/chapter0/1.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/bn/chapter0/1.mdx b/chapters/bn/chapter0/1.mdx index b1e5879df..ab323044e 100644 --- a/chapters/bn/chapter0/1.mdx +++ b/chapters/bn/chapter0/1.mdx @@ -19,7 +19,7 @@ Colab নোটবুক ব্যবহার করার সবচেয় Colab-এর উপর আপানার হাত চলে আসলে একটি নতুন নোটবুক ওপেন করে সেট-আপ শুরু করুন:
-An empty colab notebook +An empty colab notebook
পরবর্তী ধাপে আমরা এই কোর্সে ব্যবহার হবে এমন লাইব্রেরিগুলি ইনস্টল করা দেখাবো। আমরা ইনস্টলেশনের জন্য পাইথনের প্যাকেজ ম্যানেজার `pip` ব্যবহার করব। নোটবুকগুলিতে, আপনি `!` অক্ষর দিয়ে আগে সিস্টেম কমান্ড চালাতে পারবেন। যেমন ধরুন, নিচের কমান্ডটি দিয়ে 🤗 Transformers লাইব্রেরি ইনস্টল করতে পারবেন: From 07766e61feb30e506aa4001af146ff692f3aec77 Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Wed, 6 Apr 2022 01:52:48 +0900 Subject: [PATCH 22/73] tag typos & indentation & unnatural expressions --- chapters/ko/_toctree.yml | 3 +- chapters/ko/chapter0/1.mdx | 31 +--- chapters/ko/chapter1/1.mdx | 30 +-- chapters/ko/chapter1/10.mdx | 361 ++++++++++++++++++------------------ chapters/ko/chapter1/2.mdx | 6 +- chapters/ko/chapter1/3.mdx | 130 ++++++------- chapters/ko/chapter1/4.mdx | 84 +++++---- chapters/ko/chapter1/5.mdx | 2 +- chapters/ko/chapter1/6.mdx | 2 +- chapters/ko/chapter1/7.mdx | 2 +- chapters/ko/chapter1/8.mdx | 16 +- chapters/ko/chapter1/9.mdx | 4 +- 12 files changed, 324 insertions(+), 347 deletions(-) diff --git a/chapters/ko/_toctree.yml b/chapters/ko/_toctree.yml index 0bdd36db3..fe4e110ef 100644 --- a/chapters/ko/_toctree.yml +++ b/chapters/ko/_toctree.yml @@ -25,4 +25,5 @@ title: 단원 정리 - local: chapter1/10 title: 단원 마무리 퀴즈 - quiz: 1 \ No newline at end of file + quiz: 1 + \ No newline at end of file diff --git a/chapters/ko/chapter0/1.mdx b/chapters/ko/chapter0/1.mdx index 194a396ee..0a8dd7735 100644 --- a/chapters/ko/chapter0/1.mdx +++ b/chapters/ko/chapter0/1.mdx @@ -1,6 +1,6 @@ # 강의 소개 -Hugging Face 강의에 오신 여러분들 환영합니다! 이번 강의 소개에서는 작업 환경 설정에 대해 안내드리겠습니다. 방금 막 이번 과정을 시작하셨다면 먼저 [Chapter 1](notion://www.notion.so/course/chapter1) 내용을 살펴보고 돌아오신 뒤, 환경을 설정하여 코드를 직접 실행해보시길 추천드립니다. +Hugging Face 강의에 오신 여러분들 환영합니다! 이번 강의 소개에서는 작업 환경 설정에 대해 안내드리겠습니다. 방금 막 이번 과정을 시작하셨다면 먼저 [Chapter 1](/course/chapter1) 내용을 살펴보고 돌아오신 뒤, 환경을 설정하여 코드를 직접 실행해보시길 추천드립니다. 이번 과정에서 사용할 모든 라이브러리는 파이썬 패키지를 통해 사용할 수 있으므로 여기서는 파이썬 환경 설정 방법 및 필요한 라이브러리 설치 방법을 보여드리겠습니다. @@ -19,71 +19,64 @@ Colab에 익숙하지 않으시다면 [introduction](https://colab.research.goog Colab과 친숙해 지셨다면 새로운 노트북을 생성하여 아래와 같이 시작합니다:
-An empty colab notebook +An empty colab notebook
다음으로, 이번 강의에서 사용할 라이브러리를 설치합니다. 설치에는 파이썬 패키지 관리자인 `pip` 를 사용하도록 하겠습니다. 노트북 파일에서는 시스템 명령어 앞에 `!` 를 붙여 실행시킬 수 있으므로, 아래와 같이 🤗 Transformers 라이브러리를 설치할 수 있습니다: ``` !pip install transformers - ``` 이제 파이썬 런타임에 패키지를 가져와 패키지가 제대로 설치되었는지 확인해보겠습니다: ``` import transformers - ```
-A gif showing the result of the two commands above: installation and import +A gif showing the result of the two commands above: installation and import
-위의 방식으로는 PyTorch나 TensorFlow와 같은 특정 기계학습 프레임워크를 포함하지 않는, 아주 가벼운 버전의 🤗 Transformers가 설치됩니다. 본 강의에서는 이 라이브러리의 많고 다양한 기능들을 사용할 예정이므로, 거의 모든 예제에 필요한 종속성(dependency)을 제공하는 개발 버전을 아래의 명령어를 통해 설치하시길 바랍니다: +위의 방식으로는 아주 가벼운 버전의 🤗 Transformers가 설치되고, 이는 PyTorch나 TensorFlow와 같은 특정 기계학습 프레임워크를 포함하지 않습니다. 하지만 본 강의에서는 이 라이브러리의 아주 다양한 기능들을 사용할 예정이므로, 아래의 명령어를 통해 대부분의 예제에 필요한 종속성(dependency)을 제공하는 개발 버전을 설치하시길 바랍니다: ``` !pip install transformers[sentencepiece] - ``` -설치에 시간이 조금 걸리겠지만 이제 나머지 강의를 위한 준비를 모두 마쳤습니다! +설치에 시간이 조금 걸리지만 곧 강의를 위한 준비가 모두 끝납니다! ## 파이썬 가상 환경 사용하기 -파이썬 가상 환경 사용을 원하신다면 먼저 파이썬을 설치해야 합니다. 이 [가이드](https://realpython.com/installing-python/)를 따라 시작하면 됩니다. +파이썬 가상 환경 사용을 원하신다면 먼저 파이썬을 설치해야 합니다. 이 [가이드](https://realpython.com/installing-python/)를 따라 설치를 진행하실 수 있습니다. 파이썬 설치가 완료되면 터미널에서 파이썬 명령어를 실행할 수 있습니다. 다음 단계로 넘어가기 전에, 다음과 같은 명령어를 실행하여 설치가 잘 되었는지 확인하세요: `python --version`. 이 때 시스템에 사용할 수 있는 파이썬 버전을 출력되어야 합니다. 터미널에서 `python --version` 과 같은 파이썬 명령어를 실행하면, 명령어를 실행하는 프로그램을 시스템의 “메인(main)” 파이썬으로 생각해야 합니다. 이 메인 파이썬은 어떤 패키지도 설치하지 않은 상태로 유지하면서, 작업 중인 각 어플리케이션마다 별도의 환경을 생성하여 이용하는 것을 권장합니다. 이렇게 하면, 각 어플리케이션은 각각의 의존성 및 패키지를 갖게 되어 다른 어플리케이션과의 잠재적 호환성 문제를 피할 수 있습니다. -파이썬에서 이는 *[가상 환경](https://docs.python.org/3/tutorial/venv.html)*을 통해 완수됩니다. 가상 환경은 자체 포함 디렉토리 트리로, 각 트리는 어플리케이션에게 필요한 모든 패키지와 함께 특정 파이썬 버전에 대한 파이썬 설치를 포함합니다. 이러한 가상 환경을 생성하는 방법은 여러 툴을 통해 할 수 있지만, 여기서는 공식 파이썬 패키지인 `[venv](https://docs.python.org/3/library/venv.html#module-venv)` 를 통해 생성해 보겠습니다. +파이썬에서 이는 [*가상 환경*](https://docs.python.org/3/tutorial/venv.html)을 통해 완수됩니다. 가상 환경은 자체 포함 디렉토리 트리로, 각 트리는 어플리케이션에게 필요한 모든 패키지와 함께 특정 파이썬 버전에 대한 파이썬 설치를 포함합니다. 이러한 가상 환경을 생성하는 방법은 여러 툴을 통해 할 수 있지만, 여기서는 공식 파이썬 패키지인 `[venv](https://docs.python.org/3/library/venv.html#module-venv)` 를 통해 생성해 보겠습니다. 먼저, 어플리케이션을 넣어줄 디렉토리를 생성합니다. 예를 들어, 홈 디렉토리의 *transformers-course*와 같은 이름의 디렉토리를 만들어 봅시다: ``` mkdir ~/transformers-course cd ~/transformers-course - ``` 디렉토리 내부에서, 파이썬 `venv` 모듈을 사용하여 가상 환경을 생성합니다: ``` python -m venv .env - ``` 원래 아무것도 없던 빈 폴더에 *.env*라는 디렉토리가 생기게 됩니다: ``` ls -a - ``` -``` +```out . .. .env - ``` `activate` 스크립트를 통해 가상 환경으로 접속할 수 있고, `deactivate` 를 통해 가상 환경 밖으로 나올 수 있습니다: @@ -94,19 +87,16 @@ source .env/bin/activate # Deactivate the virtual environment source .env/bin/deactivate - ``` 환경이 제대로 활성화 되었는지 `which python` 명령어를 실행하여 확인해 봅시다. 아래와 같이 가상 환경을 보여준다면 제대로 활성화가 것입니다! ``` which python - ``` -``` +```out /home//transformers-course/.env/bin/python - ``` ### 의존성(dependencies) 설치하기 @@ -115,7 +105,6 @@ Google Colab 사용법에서와 마찬가지로 다음 단계로 넘어가기 ``` pip install "transformers[sentencepiece]" - ``` -이제 모든 환경 설정을 마치고 시작할 준비가 되었습니다! \ No newline at end of file +이제 모든 환경 설정을 마치고 시작할 준비가 되었습니다! diff --git a/chapters/ko/chapter1/1.mdx b/chapters/ko/chapter1/1.mdx index 3a657a966..3bfb81f49 100644 --- a/chapters/ko/chapter1/1.mdx +++ b/chapters/ko/chapter1/1.mdx @@ -4,40 +4,40 @@ -이번 강의에서는 [Hugging Face](https://huggingface.co/) 환경의 라이브러리([🤗 Transformers](https://github.com/huggingface/transformers), [🤗 Datasets](https://github.com/huggingface/datasets), [🤗 Tokenizers](https://github.com/huggingface/tokenizers), [🤗 Accelerate](https://github.com/huggingface/accelerate))와 [Hugging Face Hub](https://huggingface.co/models) 를 이용해 자연어 처리(NLP)에 대해 배워보겠습니다. (무료 강의에 광고도 없는건 비밀이에요!) +이번 강의에서는 [Hugging Face](https://huggingface.co/) 환경의 라이브러리([🤗 Transformers](https://github.com/huggingface/transformers), [🤗 Datasets](https://github.com/huggingface/datasets), [🤗 Tokenizers](https://github.com/huggingface/tokenizers), [🤗 Accelerate](https://github.com/huggingface/accelerate))와 [Hugging Face Hub](https://huggingface.co/models) 를 이용해 자연어 처리(NLP)에 대해 배워보겠습니다. (무료 강의에 광고도 없는건 비밀입니다!) ## 무엇을 배우나요? 강의 개요 훑어보기:
-Brief overview of the chapters of the course. - +Brief overview of the chapters of the course. +
-- 단원 1~4에서는 🤗 Transformers 라이브러리의 핵심 개념에 대해 소개합니다. 이번 강의 끝무렵에 아마 여러분들은 트랜스포머 모델이 어떻게 동작하는지 터득하게 될거고, [Hugging Face Hub](https://huggingface.co/models)에서 모델을 사용하고 데이터셋으로 미세 조정(fine-tune)하고 Hub에 여러분의 모델을 공유하는 방법까지 알게 될 것입니다! -- 단원 5~8은 본격적으로 전형적인 NLP 작업을 하기 앞서, 🤗 Datasets와 🤗 Tokenizers의 기초를 다룹니다. 이 부분을 모두 학습하면 여러분들은 가장 일반적인 NLP 문제를 스스로 해낼 수 있습니다. -- 단원 9~12에서는 NLP를 넘어, 트랜스포머 모델이 음성 처리 및 컴퓨터 비전에 어떻게 활용되는지 탐구합니다. 이 과정에서 여러분들의 모델 데모를 구축하고 공유하는 방법 및 이를 프로덕션 환경에 최적화하는 방법을 배우게 됩니다. 최종적으로, 여러분들은 거의 모든 기계 학습(머신 러닝) 문제에 🤗 Transformers를 적용할 준비를 갖추게 됩니다! +- 챕터 1~4에서는 🤗 Transformers 라이브러리의 핵심 개념에 대해 소개합니다. 이 부분을 마치면 트랜스포머 모델의 동작 원리를 이해하실 수 있고, [Hugging Face Hub](https://huggingface.co/models)에서 모델을 사용하여 데이터셋으로 미세 조정(fine-tune)한 후 Hub에 모델을 공유하는 방법까지 터득하게 될 것입니다! +- 챕터 5~8은 본격적으로 고전 NLP 업무를 수행하기 앞서, 🤗 Datasets와 🤗 Tokenizers의 기초에 대해 알아봅니다. 이 부분을 모두 학습하시면 일반적인 NLP 문제를 스스로 해낼 수 있게 됩니다. +- 챕터 9~12에서는 트랜스포머 모델이 NLP 문제를 넘어, 음성 처리 및 컴퓨터 비전에 어떻게 활용되는지 탐구합니다. 이 과정에서 모델 데모를 구축하고 공유하는 방법과 이를 프로덕션 환경에 최적화하는 방법을 공부합니다. 이러한 과정을 거쳐서, 여러분들은 거의 모든 기계 학습(머신 러닝) 문제에 🤗 Transformers를 적용할 준비를 갖추게 됩니다! 이번 강의는: -- 파이썬에 대한 기초 지식이 필요합니다 -- [DeepLearning.AI](https://www.deeplearning.ai/) 의 프로그램이나 [fast.ai's](https://www.fast.ai/) [Practical Deep Learning for Coders](https://course.fast.ai/) 와 같은 딥러닝에 대한 기초 강의를 듣고 수강하면 더욱 효과적입니다 -- [PyTorch](https://pytorch.org/) , [TensorFlow](https://www.tensorflow.org/) 에 대한 선수 지식이 필요하지 않지만, 이에 익숙하다면 도움이 될 것입니다 +* 파이썬에 대한 기초 지식이 필요합니다 +* [DeepLearning.AI](https://www.deeplearning.ai/) 의 프로그램이나 [fast.ai's](https://www.fast.ai/) [Practical Deep Learning for Coders](https://course.fast.ai/) 와 같은 딥러닝에 대한 기초 강의를 듣고 수강하면 더욱 효과적입니다 +* [PyTorch](https://pytorch.org/) , [TensorFlow](https://www.tensorflow.org/) 에 대한 선수 지식이 필요하지는 않지만, 이에 익숙하시다면 도움이 될 것입니다 -본 강의를 모두 수강한 후, [DeepLearning.AI](http://deeplearning.ai/)의 [Natural Language Processing Specialization](https://www.coursera.org/specializations/natural-language-processing?utm_source=deeplearning-ai&utm_medium=institutions&utm_campaign=20211011-nlp-2-hugging_face-page-nlp-refresh)을 살펴보시길 권장드립니다. 해당 과정에서는 Naive Bayes, LSTM과 같은 알아두면 너무나 유용한 더 넓은 범위의 전통 NLP 모델에 대해 학습할 수 있습니다! +본 강의를 모두 수강한 후, DeepLearning.AI의 [Natural Language Processing Specialization](https://www.coursera.org/specializations/natural-language-processing?utm_source=deeplearning-ai&utm_medium=institutions&utm_campaign=20211011-nlp-2-hugging_face-page-nlp-refresh)을 학습하시길 권장드립니다. 해당 과정에서는 Naive Bayes, LSTM과 같은 알아두면 너무나 유용한 더 넓은 범위의 전통 NLP 모델에 대해 학습할 수 있습니다! ## 우리가 누구일까요? 저자 소개: -**Matthew Carrigan**은 Hugging Face의 머신 러닝 엔지니어입니다. 현재 아일랜드 더블린에 살고 있으며, 이전에는 [Parse.ly](http://parse.ly/) 에서 ML 엔지니어로, 그 전에는 Trinity Collge Dublin에서 박사 과정 이후 연구원으로 근무했습니다. 우리가 기존 인공지능 아키텍쳐를 확장하여 사람 수준에는 도달하지 못할거라고 생각하지만, 그럼에도 불멸 로봇(immortality robot)에 대해 큰 기대를 갖고 있습니다. +**Matthew Carrigan**은 Hugging Face의 머신 러닝 엔지니어입니다. 현재 아일랜드 더블린에 살고 있으며, 이전에는 [Parse.ly](http://parse.ly/) 에서 ML 엔지니어로, 그 전에는 Trinity Collge Dublin에서 박사 과정 이후 연구원으로 근무했습니다. 사람이 기존 인공지능 아키텍쳐를 확장하여 사람 수준에는 도달하지 못할거라고 생각하지만, 그럼에도 불멸 로봇(immortality robot)에 대해 큰 기대를 갖고 있습니다. -**Lysandre Debut**는 Hugging Face의 머신 러닝 엔지니어이며 초창기부터 🤗 Transformers 라이브러리 작업을 함께 했습니다. 아주 간단한 API를 개발하여 모두가 NLP를 쉽게 사용할 수 있도록 하는 목표를 갖고 있습니다. +**Lysandre Debut**는 Hugging Face의 머신 러닝 엔지니어이며 초창기부터 🤗 Transformers 라이브러리 작업을 함께 했습니다. 아주 사용하기 쉬운 API를 개발하여 모두가 NLP를 쉽게 사용할 수 있도록 하는 목표를 갖고 있습니다. **Sylvain Gugger**는 Hugging Face의 리서치 엔지니어로 🤗 Transformers 라이브러리의 주요 관리자 중 한명입니다. 이전에 [fast.ai](http://fast.ai/) 에서 리서치 사이언티스트로 있었으며 Jeremy Howard와 함께 *[Deep Learning for Coders with fastai and PyTorch](https://learning.oreilly.com/library/view/deep-learning-for/9781492045519/)* 를 저술했습니다. 적은 리소스에서도 모델이 빠르게 학습되도록 기술을 디자인하고 개선하여 딥러닝에 보다 쉽게 접근할 수 있도록 하는 것을 리서치의 가장 큰 목표로 삼고 있습니다. -**Merve Noyan**은 Hugging Face의 개발자 애드보케이트로, 모두를 위한 민주적인 머신 러닝 생태계를 만들고자 개발툴 작업 및 주변 컨텐츠 구축 작업을 담당합니다. +**Merve Noyan**은 Hugging Face의 개발자 애드보케이트로, 모두에게 평등한 민주적인 머신 러닝 생태계를 만드는 목표를 갖고 있으며, 개발툴 작업 및 주변 컨텐츠 구축 작업을 담당하고 있습니다. **Lucile Saulnier**은 Hugging Face의 ML 엔지니어로 오픈 소스 툴 사용에 대한 개발 및 지원을 담당합니다. 자연어 처리 분야에서 협업 학습, BigScience등과 같은 다양한 리서치 프로젝트에도 활발히 참여하고 있습니다. @@ -45,8 +45,8 @@ **Leandro von Werra**는 Hugging Face 오픈소스 팀의 머신 러닝 엔지니어이자 곧 출간될 [O’Reilly book on Transformers](https://www.oreilly.com/library/view/natural-language-processing/9781098103231/)의 공동 저자입니다. 모든 머신 러닝 스택에서의 작업을 통해 수 년간 NLP 프로젝트를 프로덕션으로 들여온 경력자입니다. -시작할 준비가 되셨나요? 이번 단원에서 다룰 내용은 다음과 같습니다: +시작할 준비가 되셨나요? 이번 챕터에서 다룰 내용은 다음과 같습니다: - 텍스트 생성 및 분류와 같은 NLP 문제를 푸는 `pipeline()` 함수 사용법 - 트랜스포머 모델 구조 -- 인코더(encoder), 디코더(decoder), 인코더-디코더(encoder-decoder) 구조의 구조와 용례 \ No newline at end of file +- 인코더(encoder), 디코더(decoder), 인코더-디코더(encoder-decoder)의 구조와 용례 \ No newline at end of file diff --git a/chapters/ko/chapter1/10.mdx b/chapters/ko/chapter1/10.mdx index ae80692e5..a05bd4c3b 100644 --- a/chapters/ko/chapter1/10.mdx +++ b/chapters/ko/chapter1/10.mdx @@ -2,252 +2,253 @@ # 단원 마무리 퀴즈 -이번 챕터에서는 정말 많은 내용들을 다뤘습니다! 그러니 모든 디테일을 이해하지 못했다고 해서 좌절하지 마세요. 다음 단원은 내부 작동 방식을 이해하는 데에 도움이 될거에요. +이번 챕터에서는 정말 많은 내용들을 다뤘습니다! 그러니 모든 세부 사항을 다 이해하지 못했다고 해서 좌절하지 마세요. 다음 챕터에서 다루는 내용은 내부 작동 방식을 이해하는 데에 도움이 될거에요. + +그래도 우선, 이번 챕터에서 배운 내용에 대해 확인해보는 시간을 갖도록 하겠습니다! -그래도 우선, 이번 단원에서 배운 내용에 대해 확인해보는 시간을 갖도록 하겠습니다! ### 1. Hub에서 `roberta-large-mnli` 체크포인트를 검색해 보세요. 이 모델은 어떤 작업을 수행하나요? + roberta-large-mnli page." -}, -{ -text: "텍스트 분류", -explain: "더 정확하게 말하면, 이 모델은 두 문장이 논리적으로 타당한지 세 가지 레이블(모순, 함의, 중립)로 분류합니다. 이러한 문제를 자연어 추론(natural language inference)이라고 부릅니다.", -correct: true -}, -{ -text: "텍스트 생성", -explain: "이 페이지를 다시 확인하세요 roberta-large-mnli page." -} -]} + choices={[ + { + text: "요약", + explain: "이 페이지를 다시 확인하세요 roberta-large-mnli page." + }, + { + text: "텍스트 분류", + explain: "더 정확하게 말하면, 이 모델은 두 문장이 논리적으로 타당한지 세 가지 레이블(모순, 함의, 중립)로 분류합니다. 이러한 문제를 자연어 추론(natural language inference)이라고 부릅니다.", + correct: true + }, + { + text: "텍스트 생성", + explain: "이 페이지를 다시 확인하세요 roberta-large-mnli page." + } + ]} /> ### 2. 다음 코드는 무엇을 반환하나요? -``` +```py from transformers import pipeline ner = pipeline("ner", grouped_entities=True) ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") - ``` sentiment-analysis 파이프라인에 대한 설명입니다." -}, -{ -text: "이 문장을 완성할, 생성 텍스트를 반환합니다.", -explain: "오답입니다 — 이는 text-generation 파이프라인에 대한 설명입니다.", -}, -{ -text: "사람, 기관, 장소 등을 나타내는 단어들을 반환합니다.", -explain: "이 뿐만 아니라, grouped_entities=True를 사용해 \"Hugging Face\"와 같이 같은 개체에 해당하는 단어들을 그룹화해줍니다.", -correct: true -} -]} + choices={[ + { + text: "문장에 대해 \"positive\" 혹은 \"negative\" 로 분류한 레이블과 함께 분류 점수를 반환합니다.", + explain: "오답입니다 — 이는 sentiment-analysis 파이프라인에 대한 설명입니다." + }, + { + text: "이 문장을 완성할, 생성 텍스트를 반환합니다.", + explain: "오답입니다 — 이는 text-generation 파이프라인에 대한 설명입니다.", + }, + { + text: "사람, 기관, 장소 등을 나타내는 단어들을 반환합니다.", + explain: "이 뿐만 아니라, grouped_entities=True를 사용해 \"Hugging Face\"와 같이 같은 개체에 해당하는 단어들을 그룹화해줍니다.", + correct: true + } + ]} /> ### 3. 다음 예제 코드에서 ... 대신 무엇이 들어가야 할까요? -``` +```py from transformers import pipeline filler = pipeline("fill-mask", model="bert-base-cased") result = filler("...") - ``` ", -explain: "오답입니다. 여기 bert-base-cased 모델 카드를 보시고 다시 도전해보세요." -}, -{ -text: "[MASK]", -explain: "정답! 이 모델의 마스크 토큰은 [MASK]입니다.", -correct: true -}, -{ -text: "man", -explain: "오답입니다. 이 파이프라인은 마스킹된 단어를 채워야하기에 어딘가에는 마스크 토큰이 있어야겠죠?" -} -]} + choices={[ + { + text: "", + explain: "오답입니다. 여기 bert-base-cased 모델 카드를 보시고 다시 도전해보세요." + }, + { + text: "[MASK]", + explain: "정답! 이 모델의 마스크 토큰은 [MASK]입니다.", + correct: true + }, + { + text: "man", + explain: "오답입니다. 이 파이프라인은 마스킹된 단어를 채워야하기니까 어딘가에는 마스크 토큰이 있어야겠죠?" + } + ]} /> -### 4. 다음 코드가 작동하지 않는 이유가 무엇일까요? +### 4. 다음 코드가 실행되지 않는 이유는 무엇일까요? -``` +```py from transformers import pipeline classifier = pipeline("zero-shot-classification") result = classifier("This is a course about the Transformers library") - ``` candidate_labels=[...].", -correct: true -}, -{ -text: "한 문장이 아니라, 여러 문장을 파이프라인에 넣어주어야 합니다.", -explain: "틀렸지만, 다른 파이프라인과 마찬가지로 제대로 사용한다면 물론 여러 리스트의 문장도 입력으로 넣어줄 수 있습니다." -}, -{ -text: "늘 그렇듯 🤗 Transformers 라이브러리가 또 고장난거 아닌가요?", -explain: "못 들은 걸로 하겠습니다!" -}, -{ -text: "위의 문장은 너무 짧아서, 더 긴 문장을 입력해야 합니다.", -explain: "오답입니다. 매우 긴 텍스트는 파이프라인에서 처리할 때 잘리게 되는 것을 명심하세요." -} -]} + choices={[ + { + text: "해당 텍스트를 분류하기 위해서는 파이프라인에 레이블을 넣어주어야 합니다.", + explain: "맞습니다 — 제대로 작동시키기 위해 다음 코드가 필요합니다. candidate_labels=[...].", + correct: true + }, + { + text: "한 문장이 아니라, 여러 문장을 파이프라인에 넣어주어야 합니다.", + explain: "틀렸지만, 다른 파이프라인과 마찬가지로 제대로 사용한다면 물론 여러 리스트의 문장도 입력으로 넣어줄 수 있습니다." + }, + { + text: "늘 그렇듯 🤗 Transformers 라이브러리가 또 고장난거 아닌가요?", + explain: "못 들은 걸로 하겠습니다!" + }, + { + text: "위의 문장은 너무 짧아서, 더 긴 문장을 입력해야 합니다.", + explain: "오답입니다. 매우 긴 텍스트는 파이프라인에서 처리할 때 잘리게 되는 것을 명심하세요." + } + ]} /> -### 5. "전이 학습(transfer learning)"이 무엇인가요? +### 5. "전이 학습(transfer learning)"이란 무엇을 의미하나요? -### 6. 언어 모델은 일반적으로 사전 학습시에 레이블이 필요하지 않습니다. 이 문장은 참일까요 거짓일까요? +### 6. 언어 모델은 일반적으로 사전 학습시에 레이블을 필요로 하지 않습니다. 이 문장은 참일까요 거짓일까요? + 자가 지도(self-supervised) 방식입니다. 이는 다음 단어 예측 혹은 마스킹 된 단어 채우기 등과 같이 입력으로부터 자동으로 레이블을 생성하는 것을 의미합니다.", -correct: true -}, -{ -text: "거짓", -explain: "정답이 아닙니다." -} -]} + choices={[ + { + text: "참", + explain: "사전 학습 과정은 일반적으로 자가 지도(self-supervised) 방식입니다. 이는 다음 단어 예측 혹은 마스킹 된 단어 채우기 등과 같이 입력으로부터 자동으로 레이블을 생성하는 것을 의미합니다.", + correct: true + }, + { + text: "거짓", + explain: "정답이 아닙니다." + } + ]} /> ### 7. 다음 중 “모델(model)”, “구조(architecture)”, “가중치(weights)”에 대해 가장 잘 설명한 것을 고르세요. -### 8. 다음 중 어떤 모델이 텍스트를 생성하여 프롬트(prompt)를 완성시키는 데에 가장 적합할까요? + +### 8. 다음 중 어떤 모델이 텍스트를 생성하여 프롬프트(prompt)를 완성시키는 데에 가장 적합할까요? ### 9. 다음 중 어떤 모델이 텍스트 요약에 가장 적합할까요? ### 10. 다음 중 어떤 모델이 입력 텍스트를 특정 레이블로 분류하는 데에 가장 적합할까요? ### 11. 다음 중 모델이 편향성(bias)을 갖게 되는 데에 가장 가능성 있는 원인을 모두 고르세요. \ No newline at end of file + choices={[ + { + text: "모델은 사전 학습 모델의 미세 조정된 버전이고, 여기서 편향성이 따라오게 됩니다.", + explain: "전이 학습 시 사용되는 사전 학습 모델의 편향성이 미세 조정된 모델로도 전달됩니다.", + correct: true + }, + { + text: "모델 학습에 사용된 데이터가 편향되어 있습니다.", + explain: "이는 가장 분명한 편향의 원인이지만, 유일한 원인은 아닙니다.", + correct: true + }, + { + text: "모델이 최적화한 메트릭(metric)이 편향되어 있습니다.", + explain: "모델 학습 방식은 편향이 발생되는 불분명한 원인 중 하나입니다. 모델은 어떤 메트릭을 고르든 아무 생각 없이 그에 맞춰 최적화를 합니다.", + correct: true + } + ]} +/> diff --git a/chapters/ko/chapter1/2.mdx b/chapters/ko/chapter1/2.mdx index 2a9426aa7..ca5d62dc8 100644 --- a/chapters/ko/chapter1/2.mdx +++ b/chapters/ko/chapter1/2.mdx @@ -1,6 +1,6 @@ # 자연어 처리(Natural Language Processing) -트랜스포머 모델을 공부하기에 앞서 자연어 처리(NLP)가 무엇인지, 그리고 왜 NLP가 중요한지 빠르고 간단하게 살펴볼게요. +트랜스포머 모델을 공부하기에 앞서 자연어 처리(NLP)가 무엇인지, 그리고 왜 NLP가 중요한지 빠르고 간단하게 살펴보겠습니다. ## NLP가 무엇인가요? @@ -14,8 +14,8 @@ NLP(Natural Language Processing)란 사람의 언어와 관련된 모든 것을 - **텍스트 안에서 정답 추출하기**: 지문과 질의가 주어질 때 지문에 주어진 정보를 이용해 질의에 대한 정답 추출하기 - **입력 텍스트로부터 새로운 문장 생성하기**: 입력 텍스트를 다른 언어로 번역하거나, 요약하기 -하지만 NLP는 위와 같이 텍스트에만 제한되지 않습니다. NLP에서는 오디오 샘플의 스크립트 및 이미지의 설명문 생성과 같이 음성 인식과 컴퓨터 비전 분야에서의 까다로운 문제도 다룹니다. +하지만 NLP는 위와 같은 텍스트 처리에만 제한되지 않습니다. NLP에서는 오디오 샘플의 스크립트 생성 및 이미지의 설명문 생성과 같이 음성 인식과 컴퓨터 비전 분야에서의 까다로운 문제 또한 다룹니다. ## 왜 NLP가 어렵나요? -컴퓨터와 사람은 서로 정보를 처리하는 방식이 다릅니다. 이를테면, “나는 배고파”라는 문장을 읽을 때 우리는 바로 그 의미를 이해할 수 있습니다. 마찬가지로 “나는 배고파”, “나 슬퍼”와 같은 문장 쌍이 주어질 때, 두 문장이 얼마나 유사한지 쉽게 판단할 수 있습니다. 그러나, 기계 학습 모델은 사람만큼 이를 쉽게 할 수 없습니다. 우선 모델이 텍스트를 학습할 수 있도록 텍스트가 처리 과정을 거쳐야 하는데, 사람의 언어 체계는 매우 복잡하기 때문에 이러한 처리가 어떻게 이루어져야 하는지 면밀히 생각해야 합니다. 따라서 텍스트 표현 방법과 관련한 수많은 연구가 진행되어 왔고, 다음 단원에서 여러분들에게 그 중 몇 가지 방법들을 소개해드리겠습니다. \ No newline at end of file +컴퓨터와 사람은 서로 정보를 처리하는 방식이 다릅니다. 이를테면, “나는 배고파”라는 문장을 읽을 때 우리는 바로 그 의미를 이해할 수 있습니다. 마찬가지로 사람은 “나는 배고파”, “나 슬퍼”와 같은 문장 쌍이 주어질 때, 두 문장이 얼마나 유사한지 쉽게 판단할 수 있습니다. 그러나, 기계 학습 모델은 사람만큼 이를 쉽게 할 수 없습니다. 우선 모델이 텍스트를 학습할 수 있도록 텍스트가 처리 과정을 거쳐야 하는데, 사람의 언어 체계는 매우 복잡하기 때문에 이러한 처리가 어떻게 이루어져야 하는지 면밀히 고민해야 합니다. 따라서 텍스트 표현 방법과 관련한 수많은 연구가 진행되어 왔고, 다음 챕터에서 그 중 몇 가지 방법들을 소개해드리겠습니다. \ No newline at end of file diff --git a/chapters/ko/chapter1/3.mdx b/chapters/ko/chapter1/3.mdx index ae47531b2..f32892430 100644 --- a/chapters/ko/chapter1/3.mdx +++ b/chapters/ko/chapter1/3.mdx @@ -1,31 +1,30 @@ # 트랜스포머로 무엇을 할 수 있나요? 이번 장에서는 트랜스포머(Transformer) 모델을 사용해 무엇을 할 수 있는지 같이 살펴보고, 🤗 Transformers 라이브러리 툴의 첫 사용을 `pipeline()` 함수와 함께 시작하겠습니다. -👀 오른쪽 상단에 Open in Colab 버튼이 보이시나요? 버튼을 클릭하면 이번 장에서 사용한 모든 코드 샘플들을 Google Colab notebook을 통해 열 수 있습니다. 이 버튼은 예제 코드를 포함하는 모든 장에서 나타날 거에요. +👀 오른쪽 상단에 Open in Colab 버튼이 보이시나요? 버튼을 클릭하면 이번 장에서 사용한 모든 코드 샘플들을 Google Colab notebook을 통해 열 수 있습니다. 이런 버튼을 예제 코드를 포함하는 모든 단원에서 발견하실 수 있습니다. 로컬 환경에서 예제 코드를 실행하려면 setup을 살펴보세요. ## 트랜스포머는 어디에나 있어요! -트랜스포머 모델은 이전 단원에서 언급한 작업과 같은 모든 NLP 문제를 해결하기 위해 사용됩니다. 아래에 Hugging Face와 트랜스포머 모델을 이용하고 다시 모델을 공유하여 커뮤니티에 기여하는 기업과 기관들이 보이네요: +트랜스포머 모델은 이전 단원에서 언급한 작업과 같은 모든 NLP 문제를 해결하기 위해 사용됩니다. 아래와 같이 Hugging Face와 트랜스포머 모델을 이용하고 다시 모델을 공유하여 커뮤니티에 기여하는 많은 기업과 기관이 있습니다: -Companies using Hugging Face +Companies using Hugging Face [🤗 Transformers 라이브러리](https://github.com/huggingface/transformers)는 이렇게 공유한 모델을 사용하고 구축하는 기능들을 제공합니다. [Model Hub](https://huggingface.co/models)에서는 모두가 다운로드 받아 쓸 수 있는 수 천 개의 사전 학습된 모델들이 여러분을 기다리고 있습니다. 여러분만의 모델을 Hub에 업로드하는 것 또한 가능합니다! - -⚠️ The Hugging Face Hub에는 트랜스포머 모델만 있지 않아요. 누구든지 어떠한 종류의 모델이나 데이터를 공유할 수 있답니다! Create a huggingface.co 링크에서 계정을 만들고 모든 기능을 사용해보세요! +⚠️ The Hugging Face Hub에는 트랜스포머 모델만 있지 않아요. 누구든지 어떠한 종류의 모델이나 데이터를 공유할 수 있습니다! Create a huggingface.co 링크에서 계정을 만들고 모든 기능을 사용해보세요! 트랜스포머 모델 안에서 무슨 일이 벌어지는지 알아보기 전에, 트랜스포머가 NLP 문제 해결에 어떻게 사용되는지 몇 가지 흥미로운 예시들을 살펴보겠습니다. @@ -36,35 +35,31 @@ options={[ 🤗 Transformers 라이브러리의 가장 기본 객체는 `pipeline()` 함수입니다. 이 함수는 모델에 있어서 필수 과정인 전처리와 후처리 과정을 모델과 연결하고, 우리가 바로 어떠한 텍스트 입력을 넣든 원하는 답을 얻을 수 있도록 합니다: -``` +```python from transformers import pipeline classifier = pipeline("sentiment-analysis") classifier("I've been waiting for a HuggingFace course my whole life.") - ``` -``` +```python out [{'label': 'POSITIVE', 'score': 0.9598047137260437}] - ``` -아래와 같이 여러 문장을 동시에 넣을 수도 있습니다! +아래와 같이 여러 문장을 함께 넣을 수도 있습니다! -``` +```python classifier( ["I've been waiting for a HuggingFace course my whole life.", "I hate this so much!"] ) - ``` -``` +```python out [{'label': 'POSITIVE', 'score': 0.9598047137260437}, {'label': 'NEGATIVE', 'score': 0.9994558095932007}] - ``` -기본적으로 이 파이프라인은 영어 감정 분석에 미세 조정(fine-tune)된 사전 학습 모델을 선택합니다. 여기서 `classifier` 객체를 생성할 때 모델이 다운로드 되며 캐싱(caching)이 이루어지는데, 재실행 시 캐싱된 모델을 사용하게 되어 모델을 다시 다운로드 하지 않습니다. +기본적으로 이 파이프라인은 영어 감정 분석에 미세 조정(fine-tune)된 사전 학습 모델을 선택하여 넣게 됩니다. 여기서 `classifier` 객체를 생성할 때 모델이 다운로드 되며 캐싱(caching)이 이루어지때문에, 재실행 시에는 캐싱된 모델을 사용하게 되어 모델을 다시 다운로드 하지 않습니다. 텍스트를 파이프라인에 넣을 때 다음과 같은 세 가지 주요 과정을 거칩니다: @@ -72,6 +67,7 @@ classifier( 2. 전처리된 입력이 모델 입력으로 들어갑니다. 3. 모델의 예측값이 후처리를 거쳐, 사람이 이해할 수 있는 형태로 반환됩니다. + 현재까지 사용할 수 있는 파이프라인([available pipelines](https://huggingface.co/transformers/main_classes/pipelines.html))은 다음과 같습니다: - `feature-extraction` : 특징 추출 (텍스트에 대한 벡터 표현 추출) @@ -84,13 +80,13 @@ classifier( - `translation` : 번역 - `zero-shot-classification` : 제로샷 분류 -이 중 몇 가지를 같이 살펴볼까요? +이 중 몇 가지를 같이 살펴보도록 하겠습니다! ## 제로샷 분류(Zero-shot classification) 레이블이 없는 텍스트를 분류하는 더 까다로운 과제부터 시작하겠습니다. 텍스트에 레이블을 다는 것은 시간이 많이 소요되고 도메인 지식이 필요하기 때문에 이러한 작업은 실제 프로젝트에서 아주 흔한 상황입니다. 이러한 상황에서 `zero-shot-classification` 파이프라인은 매우 유용합니다. 제로샷 파이프라인은 사전 학습된 모델에 의존하지 않고도 분류 작업에 사용할 레이블을 특정할 수 있도록 합니다. 위의 예시에서 모델이 긍정(positive)과 부정(negative)의 두 레이블을 분류하는 샘플을 살펴보았는데, 제로샷 파이프라인을 통해서는 어떠한 레이블 세트에 대해서도 분류 작업을 수행할 수 있습니다. -``` +```python from transformers import pipeline classifier = pipeline("zero-shot-classification") @@ -98,60 +94,58 @@ classifier( "This is a course about the Transformers library", candidate_labels=["education", "politics", "business"], ) - ``` -``` +```python out {'sequence': 'This is a course about the Transformers library', 'labels': ['education', 'business', 'politics'], 'scores': [0.8445963859558105, 0.111976258456707, 0.043427448719739914]} - ``` -이러한 파이프라인이 제로샷(zero-shot)이라 불리는 이유는 여러분의 데이터에 미세 조정(fine-tune)하지 않고도 사용할 수 있기 때문입니다. 제로샷은 여러분이 원하는 어떠한 레이블 목록에 대해서도 확률 점수를 바로 반환합니다. +이러한 파이프라인이 제로샷(zero-shot)이라 불리는 이유는 여러분의 데이터에 맞춰 미세 조정(fine-tune)하지 않고도 바로 작업에 사용할 수 있기 때문입니다. 제로샷은 여러분이 원하는 어떠한 분류 레이블에 대해서도 확률 점수를 즉시 반환합니다. -**✏️ 직접 해보기!** 여러분만의 시퀀스와 레이블로 모델이 어떻게 동작하는지 확인해보세요. +✏️ **직접 해보기!** 여러분이 직접 작성한 시퀀스와 레이블을 사용해 모델이 어떻게 동작하는지 확인해보세요. + ## 텍스트 생성(Text generation) 지금부터 파이프라인을 사용해 텍스트를 생성하는 방법을 알아보겠습니다. 여기서의 핵심은 프롬트를 모델에 제공하면 모델이 나머지 텍스트를 생성하여 이를 자동으로 완성하는 것입니다. 이는 스마트폰의 텍스트 자동 완성 기능과 유사합니다. 텍스트 생성에는 랜덤하게 결과를 생성하는 과정이 포함되어 있어서 여러분이 아래와 같이 동일하게 입력을 넣어도 매번 다른 결과가 나올 수 있습니다. -``` +```python from transformers import pipeline generator = pipeline("text-generation") generator("In this course, we will teach you how to") - ``` -``` +```python out [{'generated_text': 'In this course, we will teach you how to understand and use ' 'data flow and data interchange when handling user data. We ' 'will be working with one or more of the most commonly used ' 'data flows — data flows of various types, as seen by the ' 'HTTP'}] - ``` -`num_return_sequences` 인자(argument)를 통해 몇 개의 다른 출력 결과를 생성할지 조절할 수 있고, `max_length` 인자를 통해 출력 텍스트의 총 길이를 설정할 수 있습니다. +`num_return_sequences`라는 인자(argument)를 통해 몇 개의 서로 다른 출력 결과를 생성할지 정할 수 있고, `max_length` 인자를 통해 출력 텍스트의 총 길이를 설정할 수 있습니다. -**✏️ 직접 해보기!** `num_return_sequences` 와 `max_length` 인자를 설정해 15 단어의 서로 다른 두 개의 문장을 출력해보세요. +✏️ **직접 해보기!** `num_return_sequences` 와 `max_length` 인자를 설정해 15개의 단어를 가진 서로 다른 두 개의 문장을 출력해보세요. + ## 파이프라인에 Hub의 모델 적용하기 -지금까지 예제들은 해당 작업에 대해 기본 모델들을 사용했지만, 특정 모델을 Hub에서 선택해 텍스트 생성과 같은 특정 작업에 대한 파이프라인에서도 사용할 수 있습니다. [Model Hub](https://huggingface.co/models) 페이지의 화면 왼쪽에 태그를 클릭하여 해당 태그 내용 작업을 지원하는 모델을 확인할 수 있습니다. [다음](https://huggingface.co/models?pipeline_tag=text-generation)과 같은 페이지로 이동하게 됩니다. +지금까지 예제들은 해당 작업에 대해 기본 모델들을 사용했지만, 특정 모델을 Hub에서 선택해 텍스트 생성과 같은 특정 작업에 대한 파이프라인에서도 사용할 수 있습니다. [Model Hub](https://huggingface.co/models) 페이지의 화면 왼쪽에 태그를 클릭하여 태그명에 해당하는 작업을 지원하는 모델을 확인할 수 있습니다. 이 때, [다음](https://huggingface.co/models?pipeline_tag=text-generation)과 같은 페이지로 이동하게 됩니다. -함께 `[distilgpt2](https://huggingface.co/distilgpt2)` 모델을 사용해봐요! 위의 예제에서 사용한 파이프라인에서 아래와 같이 로드 할 수 있습니다: +함께 [`distilgpt2`](https://huggingface.co/distilgpt2) 모델을 사용해보겠습니다! 위 예제에서 사용한 파이프라인에서 모델을 아래와 같이 로드 할 수 있습니다: -``` +```python from transformers import pipeline generator = pipeline("text-generation", model="distilgpt2") @@ -160,31 +154,29 @@ generator( max_length=30, num_return_sequences=2, ) - ``` -``` +```python out [{'generated_text': 'In this course, we will teach you how to manipulate the world and ' 'move your mental and physical capabilities to your advantage.'}, {'generated_text': 'In this course, we will teach you how to become an expert and ' 'practice realtime, and with a hands on experience on both real ' 'time and real'}] - ``` -언어 태그를 클릭하여 해당 언어를 지원 및 생성하는 모델을 구체적으로 검색할 수 있습니다. Model Hub에는 다양한 언어를 지원하는 다국어 모델의 체크포인트(모델의 파라미터 값) 또한 포함하고 있습니다. +언어 태그를 클릭하여 해당 언어를 지원하고 생성하는 모델을 보다 구체적으로 검색할 수 있습니다. Model Hub에는 다양한 언어를 처리하는 다국어 모델의 체크포인트(모델의 파라미터 값) 또한 포함하고 있습니다. -모델을 클릭하여 선택하면 온라인에서 바로 사용이 가능한 위젯을 확인할 수 있고, 이를 통해 모델을 다운로드 받기 전에 모델의 기능을 빠르게 테스트 해볼 수 있습니다. +모델을 클릭하면 온라인상에서 바로 사용 가능한 위젯을 확인할 수 있고, 이를 통해 모델을 직접 다운로드 받기 전에 모델의 기능을 빠르게 테스트 해볼 수 있습니다. -**✏️ 직접 해보기!** 영어를 제외한 다른 언어를 생성하는 모델을 검색해보세요. 위젯을 자유롭게 사용해 보시고 파이프라인을 사용해보세요! +✏️ **직접 해보기!** 영어를 제외한 다른 언어를 생성하는 모델을 검색해보세요. 위젯을 자유롭게 다뤄 보시고 파이프라인을 사용해보세요! ### 추론(Inference) API -모든 모델들은 [Hugging Face 웹사이트](https://huggingface.co/)에서 제공하는 추론 API를 통해 여러분의 브라우저상에서 직접 테스트가 가능합니다. 이 페이지를 통해 직접 나만의 텍스트를 입력하고 모델이 입력 데이터를 처리하는걸 구경하며 모델을 갖고 놀 수 있습니다. +모든 모델들은 [Hugging Face 웹사이트](https://huggingface.co/)에서 제공하는 추론 API를 통해 여러분의 브라우저상에서 직접 테스트할 수 있습니다. 이 페이지 링크로 접속해 직접 작성하신 텍스트를 입력하시면 모델의 입력 데이터를 처리 결과를 확인할 수 있습니다. 위젯을 구동하는 추론 API는 간편한 워크플로우를 가능하게 하는 유료 버전의 제품으로도 이용 가능합니다. 자세한 사항은 [가격 정책 페이지](https://huggingface.co/pricing)를 참고해주세요. @@ -192,15 +184,14 @@ generator( 다음으로 사용해볼 파이프라인은 마스크 채우기(`fill-mask`)입니다. 이 작업의 핵심 아이디어는 주어진 텍스트의 빈칸을 채우기입니다: -``` +```python from transformers import pipeline unmasker = pipeline("fill-mask") unmasker("This course will teach you all about models.", top_k=2) - ``` -``` +```python out [{'sequence': 'This course will teach you all about mathematical models.', 'score': 0.19619831442832947, 'token': 30412, @@ -209,52 +200,49 @@ unmasker("This course will teach you all about models.", top_k=2) 'score': 0.04052725434303284, 'token': 38163, 'token_str': ' computational'}] - ``` -몇 개의 가능성 있는 토큰을 표시할지 `top_k` 인자를 통해 조절합니다. 여기서 모델이 특이한 `` 단어를 채우는 것을 주목하세요. 이는 마스크 토큰(mask token)이라고 부릅니다. 다른 마스크 채우기 모델들은 다른 형태의 마스크 토큰을 사용할 수 있어서 다른 모델을 탐색할 때 항상 마스크 단어를 확인해야 합니다. 위젯에서 사용되는 마스크 단어를 보고 이를 확인해 볼 수 있습니다. +상위 몇 개의 높은 확률을 띠는 토큰을 출력할지 `top_k` 인자를 통해 조절합니다. 여기서 모델이 특이한 `` 단어를 채우는 것을 주목하세요. 이를 마스크 토큰(mask token)이라고 부릅니다. 다른 마스크 채우기 모델들은 다른 형태의 마스크 토큰을 사용할 수 있기 때문에 다른 모델을 탐색할 때 항상 해당 모델의 마스크 단어가 무엇인지 확인해야 합니다. 위젯에서 사용되는 마스크 단어를 보고 이를 확인할 수 있습니다. -**✏️ 직접 해보기!** Hub에서 `bert-base-cased` 를 검색해 보고 Inference API 위젯으로 마스크 단어를 확인해 보세요. 이 모델이 위의 `pipeline` 예제에서 사용한 문장에 대해 어떻게 예측하나요? +✏️ **직접 해보기!** Hub에서 `bert-base-cased`를 검색해 보고 추론 API 위젯을 통해 모델의 마스크 단어가 무엇인지 확인해 보세요. 이 모델이 위의 `pipeline` 예제에서 사용한 문장에 대해 어떻게 예측하나요? ## 개체명 인식(Named entity recognition) -개체명 인식(NER)은 모델이 입력 텍스트의 어느 부분이 사람, 장소, 기관 등과 같은 개체에 해당하는지 찾는 작업입니다. 예제를 통해 확인해 봅시다: +모델이 입력 텍스트의 어느 부분이 사람, 장소, 기관 등과 같은 개체에 해당하는지 찾는 작업을 개체명 인식(NER)이라고 합니다. 예제를 통해 확인해 봅시다: -``` +```python from transformers import pipeline ner = pipeline("ner", grouped_entities=True) ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") - ``` -``` +```python out [{'entity_group': 'PER', 'score': 0.99816, 'word': 'Sylvain', 'start': 11, 'end': 18}, {'entity_group': 'ORG', 'score': 0.97960, 'word': 'Hugging Face', 'start': 33, 'end': 45}, {'entity_group': 'LOC', 'score': 0.99321, 'word': 'Brooklyn', 'start': 49, 'end': 57} ] - ``` 모델이 정확하게 Sylvain을 사람(PER)으로, Hugging Face를 기관(ORG)으로, Brooklyn을 장소(LOC)으로 예측했네요! -파이프라인을 생성하는 함수에 `grouped_entities=True` 옵션을 전달하면 파이프라인이 같은 개체에 해당하는 문장 부분을 다시 그룹화합니다. 이 경우 모델은 여러 단어로 구성된 단어임에도 “Hugging”과 “Face”를 하나의 기관으로 정확히 분류하게 됩니다. 다음 단원에서도 확인하겠지만, 놀랍게도 전처리 과정에서 각 단어들은 더 작은 부분으로 쪼개지게 됩니다. 예를 들어 `Sylvain` 이라는 단어는 `S`, `##yl`, `##va`, `##in` 이렇게 네 조각으로 쪼개집니다. 후처리 단계에서 파이프라인은 이 조각들을 멋지게 재그룹화합니다. +파이프라인을 생성하는 함수에 `grouped_entities=True` 옵션을 전달하면 파이프라인이 같은 개체에 해당하는 문장 부분을 다시 그룹화합니다. 이 옵션을 설정하면 모델은 여러 단어로 구성된 단어임에도 “Hugging”과 “Face”를 하나의 기관으로 정확히 분류하게 됩니다. 다음 챕터에서도 확인하겠지만, 놀랍게도 전처리 과정에서 각 단어들은 더 작은 부분으로 쪼개집니다. 예를 들어 `Sylvain` 이라는 단어는 `S`, `##yl`, `##va`, `##in` 이렇게 네 조각으로 쪼개집니다. 후처리 단계에서 파이프라인은 이 조각들을 멋지게 재그룹화합니다. -**✏️ 직접 해보기!** Model Hub에서 영어 품사 태깅(part-of-speech tagging, 줄여서 POS)이 가능한 모델을 찾아보세요. 이 모델이 위의 예시 문장으로 무엇을 예측하나요? +✏️ **직접 해보기!** Model Hub에서 영어 품사 태깅(part-of-speech tagging, 줄여서 POS)이 가능한 모델을 찾아보세요. 이 모델이 위의 예시 문장으로 무엇을 예측하나요? ## 질의 응답(Question-answering) -질의 응답(`question-answering`) 파이프라인은 주어진 지문(context)의 정보를 활용하여 질문에 답을 합니다: +질의 응답(`question-answering`) 파이프라인은 주어진 지문(context)의 정보를 활용하여 질문에 대한 답을 하는 태스크입니다: -``` +```python from transformers import pipeline question_answerer = pipeline("question-answering") @@ -262,21 +250,19 @@ question_answerer( question="Where do I work?", context="My name is Sylvain and I work at Hugging Face in Brooklyn", ) - ``` -``` +```python out {'score': 0.6385916471481323, 'start': 33, 'end': 45, 'answer': 'Hugging Face'} - ``` -본 파이프라인은 답을 새롭게 생성하지 않고 주어진 지문에서 정답을 추출하는 방식임을 잘 기억하세요. +본 파이프라인은 답을 새롭게 생성하는 방식이 아닌, 주어진 지문 내에서 정답을 추출하는 방식임을 잘 기억하세요. ## 요약(Summarization) -요약은 참조 텍스트의 모든(혹은 대부분) 중요한 특징을 유지한 채로 텍스트를 짧게 줄이는 작업입니다. 아래 예제를 확인하세요: +요약(Summarization)은 참조 텍스트의 모든(혹은 대부분의) 중요한 특징을 그대로 유지한 채 텍스트를 짧게 줄이는 작업입니다. 아래 예제를 확인하세요: -``` +```python from transformers import pipeline summarizer = pipeline("summarization") @@ -302,10 +288,9 @@ summarizer( and a lack of well-educated engineers. """ ) - ``` -``` +```python out [{'summary_text': ' America has changed dramatically during recent years . The ' 'number of engineering graduates in the U.S. has declined in ' 'traditional engineering disciplines such as mechanical, civil ' @@ -313,34 +298,31 @@ summarizer( 'developing economies such as China and India, as well as other ' 'industrial countries in Europe and Asia, continue to encourage ' 'and advance engineering .'}] - ``` -텍스트 생성과 마찬가지로 `max_length` 와 `min_length` 를 정할 수 있습니다. +텍스트 생성에서와 마찬가지로 `max_length` 와 `min_length` 를 미리 설정할 수 있습니다. ## 번역(Translation) -번역의 경우 (`"translation_en_to_fr"` 와 같이) 작업명에 언어 쌍을 넣어준다면 기본 모델을 사용할 수 있지만, [Model Hub](https://huggingface.co/models)에서 원하는 모델을 고르는 방식이 가장 간단합니다. 여기서는 프랑스어에서 영어로 번역을 시도해 보겠습니다: +번역(Translation)의 경우 `"translation_en_to_fr"` 와 같이 태스크명에 해당하는 언어 쌍을 넣어준다면 기본 모델을 사용할 수 있지만, 더 간단하게 [Model Hub](https://huggingface.co/models)에서 원하는 모델을 선택해 사용하는 방법이 있습니다. 아래에서는 프랑스어에서 영어로 번역을 시도해 보겠습니다: -``` +```python from transformers import pipeline translator = pipeline("translation", model="Helsinki-NLP/opus-mt-fr-en") translator("Ce cours est produit par Hugging Face.") - ``` -``` +```python out [{'translation_text': 'This course is produced by Hugging Face.'}] - ``` 텍스트 생성 및 요약에서와 마찬가지로, `max_length` 혹은 `min_length` 를 지정하여 결과를 출력할 수 있습니다. -**✏️ 직접 해보기!** 다른 언어의 번역 모델을 검색해보고 위의 문장을 몇 가지 다른 언어들로 번역해 봅시다. +✏️ **직접 해보기!** 다른 언어를 지원하는 번역 모델을 검색해보고 위의 문장을 몇 가지 다른 언어들로 번역해 봅시다. -지금까지 보여드린 파이프라인들은 대부분 특정 작업을 위해 프로그래밍된, 다양한 변형 작업을 수행할 수 없는 데모용 파이프라인입니다. 다음 단원에서는 `pipeline()` 함수 내부를 살펴보고 그 동작을 사용자가 직접 설계하는 방법을 다루겠습니다. \ No newline at end of file +지금까지 보여드린 파이프라인들은 대부분 특정 작업을 위해 프로그래밍된 데모용 파이프라인으로, 여러 태스크를 동시에 지원하지는 않습니다. 다음 단원에서는 `pipeline()` 함수 내부를 살펴보고 그 동작 방식을 직접 설계하는 방법에 대해 다루겠습니다. \ No newline at end of file diff --git a/chapters/ko/chapter1/4.mdx b/chapters/ko/chapter1/4.mdx index 3b041e435..96456fab5 100644 --- a/chapters/ko/chapter1/4.mdx +++ b/chapters/ko/chapter1/4.mdx @@ -7,20 +7,25 @@ 아래에 트랜스포머 모델의 (짧은) 역사 중 주요한 지점을 나타냈습니다:
-A brief chronology of Transformers models. - +A brief chronology of Transformers models. +
[Transformer architecture](https://arxiv.org/abs/1706.03762)는 2017년 6월에 처음 소개되었습니다. 처음 연구 목적은 번역 작업 수행이었습니다. 이후로 다음과 같이 줄줄이 막강한 모델들이 세상에 등장했습니다: - **2018년 6월**: [GPT](https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf), 최초로 사전 학습된 트랜스포머 모델로 다양한 NLP 작업에 미세 조정(fine-tune)되도록 사용되었으며 SOTA(state-of-the-art) 성능 달성 + - **2018년 10월**: [BERT](https://arxiv.org/abs/1810.04805), 또 다른 거대 사전 학습 언어 모델로, 더 좋은 문장 요약을 위해 설계 (이번 단원과 다음 단원에서 더 자세히 알아봐요!) + - **2019년 2월**: [GPT-2](https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf), 더 좋은 성능(그리고 더 큰) 버전의 GPT로, 윤리적 문제로 인해 즉시 공개되지 못하였음 + - **2019년 10월**: [DistilBERT](https://arxiv.org/abs/1910.01108), BERT의 60% 빠른 속도에 메모리 측면에서 40% 가볍지만 BERT 성능의 97%를 재현하는 경량화 버전의 BERT + - **2019년 10월**: [BART](https://arxiv.org/abs/1910.13461) 와 [T5](https://arxiv.org/abs/1910.10683), 동일한 구조의 (처음으로) 원본 트랜스포머 모델의 구조를 그대로 따른 두 거대 사전학습 언어 모델 + - **2020년 5월**, [GPT-3](https://arxiv.org/abs/2005.14165), 미세 조정 없이도 (zero-shot learning이라 부름) 다양한 작업을 훌륭하게 수행하는 GPT-2의 더 큰 버전 -위 리스트는 단순히 서로 다른 종류의 트랜스포머 모델들 중 몇몇을 강조하기 위한 목록일 뿐, 포괄적이지 않습니다. 넓은 관점에서 트랜스포머 모델은 아래와 같이 세 카테고리로 그룹화 할 수 있습니다: +위 리스트는 단순히 여러 종류의 트랜스포머 모델들 중 몇몇을 강조하기 위한 목록입니다. 넓은 관점에서 트랜스포머 모델은 아래와 같이 세 개의 카테고리로 묶을 수 있습니다: - GPT-계열 (*Auto-regressive* 트랜스포머 모델로도 불림) - BERT-계열 (*Auto-encoding* 트랜스포머 모델로도 불림) @@ -32,44 +37,45 @@ 위에 언급한 모델(GPT, BERT, BART, T5 등)들은 *언어 모델(language model)*로서 학습 되었습니다. 다르게 말하면 이 모델들은 스스로 지도하는 방식으로 수많은 텍스트에 대해 학습된 모델들입니다. 이러한 자가 지도 학습(self-supervised learning)은 학습의 목적이 모델 입력으로부터 자동으로 계산되는 방식을 말합니다. 결국 사람이 데이터에 레이블을 달지 않아도 학습이 가능한 것입니다! -이러한 종류의 모델은 학습한 언어에 대해 통계 기반의 이해를 생성하지만 이는 몇몇 실생활 문제에 적합하지 않습니다. 이러한 이유로 사전 학습된 모델은 *전이 학습(transfer learning)*이라 불리는 과정을 거칩니다. 이 과정에서 모델은 특정 작업에 맞춰 지도적(supervised)인 방법, 즉 사람이 레이블을 추가한 데이터를 사용하는 방법으로 미세 조정(fine-tune)이 이루어지며 +이러한 종류의 모델은 학습한 언어에 대해 통계 기반의 방식으로 이해를 하지만, 이는 몇몇 실생활 문제에 적합하지 않습니다. 그렇기 때문에 사전 학습된 모델은 *전이 학습(transfer learning)*이라 불리는 과정을 거칩니다. 이 과정에서 모델은 특정 작업에 맞춰 지도적(supervised)인 방법, 즉 사람이 레이블을 추가한 데이터를 사용하는 방법으로 미세 조정(fine-tune)이 이루어지는 단계를 거칩니다. 하나의 예시로 문장 내에서 이전 *n*개의 단어를 읽고 다음에 올 단어를 에측하는 문제를 들 수 있습니다. 이를 과거와 현재의 입력 정보를 이용하는 방식(미래에 올 입력 정보는 이용하지 않습니다)이기 때문에 *인과적 언어 모델링(causal language modeling)*이라고 부릅니다.
-Example of causal language modeling in which the next word from a sentence is predicted. - +Example of causal language modeling in which the next word from a sentence is predicted. +
다른 예시로 *마스크 언어 모델링(masked language modeling)*을 들 수 있습니다. 여기서 모델은 문장 내에 마스킹 된 단어를 예측합니다.
-Example of masked language modeling in which a masked word from a sentence is predicted. - +Example of masked language modeling in which a masked word from a sentence is predicted. +
## 트랜스포머는 거대 모델입니다 -(DistilBERT와 같은 몇몇 예외를 제외하고) 모델의 성능을 향상시키는 일반적인 전략은 사전 학습에 사용하는 모델의 크기와 데이터의 양을 늘리는 방식입니다. +(DistilBERT와 같은 몇몇 예외를 제외하고) 모델의 성능을 향상시키는 일반적인 전략은 사전 학습에 사용하는 "모델과 데이터의 크기를 늘리기" 입니다.
-Number of parameters of recent Transformers models +Number of parameters of recent Transformers models
불행히도 아주 아주 큰 모델의 경우, 학습을 위해 어마무시한 양의 데이터를 필요로 하여 시간과 컴퓨팅 리소스 관점에서 비용이 매우 많이 듭니다. 아래 그래프에서 볼 수 있듯이 이는 환경 오염 문제로 이어지기도 합니다.
-The carbon footprint of a large language model. - +The carbon footprint of a large language model. +
-위 비디오는 사전 학습 과정이 환경에 끼치는 부정적 영향을 꾸준히 줄이기 위해 노력하는 팀의 (초거대) 언어 모델 프로젝트를 소개합니다. 최적의 하이퍼파라미터를 찾기 위한 수많은 시도에는 아직 많은 여정이 남았습니다. +위 비디오는 사전 학습 과정이 환경에 끼치는 부정적 영향을 꾸준히 줄이기 위해 노력하는 한 팀의 (초거대) 언어 모델 프로젝트를 소개합니다. 최적의 하이퍼파라미터를 찾기 위한 수많은 시도에는 아직 많은 여정이 남아 있습니다. + +매번 리서치 팀, 학생 기관, 기업 등등이 밑바닥부터 모델을 학습시킨다고 생각해보세요. 이는 결국 정말 어마어마한 양의 글로벌 비용으로 이어질 것입니다! -매번 리서치 팀, 학생 기관, 기업 등등이 밑바닥부터 모델을 학습시킨다고 생각해보세요. 정말 어마어마한 글로벌 비용으로 이어지겠죠? +이제 왜 언어 모델을 공유하는 것이 중요한지 아시겠나요? 학습 가중치를 공유하고, 이미 학습시킨 가중치에 이를 차곡차곡 쌓아 올리는 방식으로 커뮤니티의 컴퓨팅 비용과 탄소 발자국을 줄일 수 있기 때문입니다. -이제 왜 언어 모델을 공유하는 것이 중요한지 아시겠죠? 학습된 가중치를 공유하고, 이미 학습된 가중치에 이를 차곡차곡 쌓아 올리는 방식으로 커뮤니티의 컴퓨팅 비용과 탄소 발자국을 줄일 수 있습니다. ## 전이 학습(Transfer Learning) @@ -78,23 +84,23 @@ *사전 학습(Pretraining)*시에는 모델을 밑바닥부터 학습시키게 됩니다. 모델 가중치를 랜덤하게 초기화하고 사전 지식 없이 학습을 시작합니다.
-The pretraining of a language model is costly in both time and money. - +The pretraining of a language model is costly in both time and money. +
-이러한 사전 학습은 엄청난 양의 데이터로 이루어지기 때문에 방대한 양의 코퍼스 데이터와 수 주 씩 걸리는 학습 시간을 필요로 하기도 합니다. +이러한 사전 학습 과정은 엄청난 양의 데이터로 이루어지기 때문에 방대한 양의 코퍼스 데이터와 수 주 씩 걸리는 학습 시간을 필요로 하기도 합니다. -하지만 *미세 조정(Fine-tuning)*은 모델이 사전 학습된 **이후에** 하는 학습을 의미합니다. 미세 조정을 하기 위해서 우선 사전 학습된 언어 모델을 가져오고, 여러분이 할 작업에 특화된 데이터셋을 이용해 추가 학습을 수행합니다. 잠깐만요, 그냥 한번에 최종 태스크에 맞춰 학습시키면 안될까요? 이렇게 하는 데에는 몇 가지 이유가 있습니다: +반면에 *미세 조정(Fine-tuning)*이란 모델이 모두 사전 학습을 마친 **이후에** 하는 학습을 의미합니다. 미세 조정을 하기 위해서 우선 사전 학습된 언어 모델을 가져오고, 여러분이 할 작업에 특화된 데이터셋을 이용해 추가 학습을 수행합니다. 잠깐만요, 그냥 한번에 최종 태스크에 맞춰 학습시키면 안될까요? 이렇게 하는 데에는 몇 가지 이유가 있습니다: -- 사전 학습된 모델은 이미 미세 조정 데이터셋과 유사한 데이터셋으로 학습이 이루어진 상태입니다. 결국 모델이 사전 학습시에 얻은 지식(이를테면, NLP 문제에서 사전 학습된 모델이 얻게 되는 통계적 이해)을 십분 활용해 미세 조정에 활용할 수 있게 됩니다. +- 사전 학습된 모델은 이미 미세 조정 데이터셋과 유사한 데이터셋으로 학습이 이루어진 상태입니다. 결국 모델이 사전 학습시에 얻은 지식(이를테면, NLP 문제에서 사전 학습된 모델이 얻게 되는 언어의 통계적 이해)을 십분 활용해 미세 조정에 활용할 수 있게 됩니다. - 사전 학습된 모델은 이미 방대한 데이터로 학습되었기 떄문에 미세 조정에서는 원하는 성능을 얻기까지 적은 양의 데이터만 필요로 하게 됩니다. - 위와 같은 이유로, 원하는 성능을 얻기까지 적은 시간과 리소스만 필요하게 됩니다. 예시로, 영어로 사전 학습된 모델을 활용해 arXiv 코퍼스로 미세 조정하여 과학/연구 기반 모델을 만들 수 있습니다. 이 때 미세 조정에는 적은 양의 데이터만 필요할 것입니다. 여기서 사전 학습 과정에서 얻은 지식이 “전이”되었다고 하여 *전이 학습(transfer learning)*이라 부릅니다.
-The fine-tuning of a language model is cheaper than pretraining in both time and money. - +The fine-tuning of a language model is cheaper than pretraining in both time and money. +
모델의 미세 조정은 이렇게 시간, 데이터, 경제, 그리고 환경 비용 측면에서 훨씬 저렴합니다. 뿐만 아니라 전체 사전 학습 과정보다 제약이 적기 때문에 다양한 방식의 미세 조정을 쉽고 빠르게 반복할 수 있습니다. @@ -107,23 +113,23 @@ -## Introduction +## 구조 소개 모델은 기본적으로 두 개의 블럭으로 이루어져 있습니다: -- **인코더 (왼쪽)**: 인코더는 입력을 받아 입력(혹은 입력의 특징)을 구축합니다. 이는 인코더 모델이 입력을 이해하는 데에 최적화되어 있음을 의미합니다. -- **디코더 (오른쪽)**: 디코더는 인코더의 (특징) 표현과 또 다른 입력을 활용해 타겟 시퀀스를 생성합니다. 이는 디코더 모델이 출력을 생성하는 데에 최적화되어 있음을 의미합니다. +* **인코더 (왼쪽)**: 인코더는 입력을 받아 입력(혹은 입력의 특징)을 구축합니다. 이는 인코더 모델이 입력을 이해하는 데에 최적화되어 있음을 의미합니다. +* **디코더 (오른쪽)**: 디코더는 인코더의 (특징) 표현과 또 다른 입력을 활용해 타겟 시퀀스를 생성합니다. 이는 디코더 모델이 출력을 생성하는 데에 최적화되어 있음을 의미합니다.
-Architecture of a Transformers models - +Architecture of a Transformers models +
트랜스포머 모델의 각 파트는 태스크에 따라 다음과 같이 개별적으로 쓰일 수도 있습니다: -- **인코더 모델(Encoder-only models)**: 문장 분류, 개체명 인식과 같이 입력에 대한 높은 이해를 요구하는 작업에 특화 -- **디코더 모델(Decoder-only models)**: 텍스트 생성과 같이 생성 관련 작업에 특화 -- **인코더-디코더(Encoder-decoder) 모델 또는 시퀀스-투-시퀀스 (Sequence-to-sequence) 모델**: 번역, 요약과 같이 입력을 필요로 하는 생성 관련 작업에 특화 +* **인코더 모델(Encoder-only models)**: 문장 분류, 개체명 인식과 같이 입력에 대한 높은 이해를 요구하는 작업에 특화 +* **디코더 모델(Decoder-only models)**: 텍스트 생성과 같이 생성 관련 작업에 특화 +* **인코더-디코더(Encoder-decoder) 모델 또는 시퀀스-투-시퀀스 (Sequence-to-sequence) 모델**: 번역, 요약과 같이 입력을 필요로 하는 생성 관련 작업에 특화 다음 단원들에서 각각의 구조에 대해 더 깊게 살펴보도록 하겠습니다. @@ -131,23 +137,23 @@ 트랜스포머 모델의 중요한 특징은 *어텐션 레이어(attention layers)*라 불리는 특수한 레이어로 구성되었다는 점입니다. 사실, 트랜스포머 구조를 처음 소개한 논문 제목마저 ["Attention Is All You Need"](https://arxiv.org/abs/1706.03762)입니다! 어텐션 레이어의 디테일에 대해서는 추후 강의에서 자세히 다루겠지만, 우선은 이 레이어가 단어의 표현을 다룰 때 입력으로 넣어준 문장의 특정 단어에 어텐션(주의)을 기울이고 특정 단어는 무시하도록 알려준다는 사실을 기억하셔야 합니다. -이러한 상황을 설명하기 위해 영어 텍스트를 프랑스어로 번역하는 작업을 생각해봅시다. “You like this course”라는 입력이 주어지면 번역 모델은 “like”라는 단어를 알맞게 번역하기 위해 인접한 단어 “You”에도 주의를 기울입니다. 이는 프랑스어의 동사 “like”가 문맥에 따라 다른 의미로 해석되기 때문입니다. 그러나 문장의 나머지 단어들은 이 단어를 번역하는 데에 크게 유용하지 않습니다. 같은 맥락에서 “this”를 번역할 때, 이 단어는 연결 명사가 남성형이거나 여성형이냐에 따라 다르게 해석될 수 있기 때문에 모델은 “course”라는 단어에 주의를 기울입니다. 여기서도 문장의 나머지 다른 단어들은 “this”의 의미를 해석하는 데에 크게 중요하지 않습니다. 더 복잡한 문법의 문장에서 모델은 문장의 각 단어를 적절히 번역하기 위해 더 멀리 떨어진 단어들에 대해서도 주의를 기울여야 합니다. +이러한 상황을 설명하기 위해 영어 텍스트를 프랑스어로 번역하는 작업을 생각해 보겠습니다. “You like this course”라는 입력이 주어지면 번역 모델은 “like”라는 단어를 알맞게 번역하기 위해 인접한 단어 “You”에도 주의를 기울입니다. 이는 프랑스어의 동사 “like”가 문맥에 따라 다른 의미로 해석되기 때문입니다. 그러나 문장의 나머지 단어들은 이 단어를 번역하는 데에 크게 유용하지 않습니다. 같은 맥락에서 “this”를 번역할 때, 이 단어는 연결 명사가 남성형이거나 여성형이냐에 따라 다르게 해석될 수 있기 때문에 모델은 “course”라는 단어에 주의를 기울입니다. 여기서도 문장의 나머지 다른 단어들은 “this”의 의미를 해석하는 데에 크게 중요하지 않습니다. 더 복잡한 문법의 문장에서 모델은 문장의 각 단어를 적절히 번역하기 위해 더 멀리 떨어진 단어들에 대해서도 주의를 기울여야 합니다. 이와 동일한 개념이 자연어의 모든 문제에 적용됩니다. 단어는 그 자체로도 의미를 갖지만 문맥상 앞뒤의 다른 단어정보를 알게 되면 의미가 달라지기도 하죠. 지금까지 어텐션 레이어가 무엇인지 알아보았으니 트랜스포머 구조에 대해 살펴보겠습니다. -## 원본 구조 The original architecture +## 원본 구조 트랜스포머 구조는 처음에 번역을 위해 만들어졌습니다. 학습시에 인코더는 특정 언어의 입력 문장을 받고, 동시에 디코더는 타겟 언어로된 동일한 의미의 문장을 받습니다. 인코더에서 어텐션 레이어는 문장 내의 모든 단어를 활요할 수 있습니다(방금 보았듯이 주어진 단어의 번역은 문장의 전후를 살펴보아야 하니까요). 반면, 디코더는 순차적으로 작동하기 때문에 문장 내에서 이미 번역이 이루어진 부분에만 주의를 기울일 수 밖에 없습니다. 이로 인해 현재 생성(번역)되고 있는 단어의 앞에 단어들만 이용할 수 있죠. 예시로, 번역된 타겟의 처음 세 단어를 예측해 놨을 때, 이 결과를 디코더로 넘기면 디코더는 인코더로부터 받은 모든 입력 정보를 함께 이용해 네 번째 올 단어를 예측하는 것입니다. 모델이 타겟 문장에 대한 액세스(access)가 있는 상황에서, 훈련 속도를 높이기 위해 디코더는 전체 타겟을 제공하지만 뒤에 올 단어들을 사용할 수 없습니다. (모델이 두 번째 올 단어를 예측하기 위해 두 번째 위치 단어를 접근할 수 있다면 예측이 의미없어지겠죠?) 예를 들어, 네 번째 단어를 예측할 때 어텐션 레이어는 1~3 번째 단어에만 액세스하도록 합니다. -원본의 트랜스포머 구조는 아래와 같이 왼쪽에는 인코더, 오른쪽에는 디코더가 있는 형태를 지닙니다: +원래 처음 트랜스포머의 구조는 아래와 같이 왼쪽에는 인코더, 오른쪽에는 디코더가 있는 형태를 지닙니다:
-Architecture of a Transformers models - +Architecture of a Transformers models +
디코더 블럭의 첫 번째 어텐션 레이어는 모든 이전의 디코더 입력에 대해 주의를 기울이지만, 두 번째 어텐션 레이어는 인코더의 출력만 사용하는 점을 주목하세요. 이로써 디코더는 전체 입력 문장에 액세스하여 현재 올 단어를 잘 예측하게 되는 것입니다. 이는 서로 다른 언어는 서로 다른 어순을 갖거나 문장의 뒷부분에 등장하는 문맥이 주어진 단어의 가장 적합한 번역을 결정할 수 있기 때문에 매우 유용합니다. @@ -158,8 +164,8 @@ 트랜스포머 모델을 본격적으로 공부하기 앞서, 모델(models)과 함께 *구조(architectures)*와 *체크포인트(checkpoints)*라는 단어를 들으시게 될겁니다. 이 셋은 아래와 같이 조금 다른 의미를 갖고 있습니다: -- **구조(Architecture)**: 모델의 뼈대를 의미하는 용어로, 모델 내부의 각 레이어와 각 연산 작용들을 의미합니다. -- 체크포인트(**Checkpoints)**: 주어진 구조(architecture)에 적용될 가중치들을 의미합니다. -- 모델(**Model)**: 사실 모델은 “구조”나 “가중치”만큼 구체적이지 않은 두루뭉실한 용어입니다. 이 강의에서는 모호함을 피하기 위해 *구조(architecture)*와 *체크포인트(checkpoint)*를 구분해서 사용하도록 하겠습니다. +* **구조(Architecture)**: 모델의 뼈대를 의미하는 용어로, 모델 내부의 각 레이어와 각 연산 작용들을 의미합니다. +* **체크포인트(Checkpoints)**: 주어진 구조(architecture)에 적용될 가중치들을 의미합니다. +* **모델(Model)**: 사실 모델은 “구조”나 “가중치”만큼 구체적이지 않은, 다소 뭉뚱그려 사용되는 용어입니다. 이 강의에서는 모호함을 피하기 위해 *구조(architecture)*와 *체크포인트(checkpoint)*를 구분해서 사용하도록 하겠습니다. -예를 들어, BERT는 구조인 반면, Google 팀이 최초 공개에서 내놓은 학습된 가중치 모음인 `bert-base-cased` 는 체크포인트입니다. 그치만 “BERT 모델”, “`bert-base-cased` 모델” 등과 같이 혼용해도 괜찮습니다. \ No newline at end of file +예를 들면, BERT는 구조에 해당하고, Google 팀이 최초 공개에서 내놓은 학습 가중치 셋인 `bert-base-cased`는 체크포인에 해당합니다. 그렇지만 “BERT 모델”, “`bert-base-cased` 모델” 등과 같이 구분하지 않고 사용하기도 합니다. diff --git a/chapters/ko/chapter1/5.mdx b/chapters/ko/chapter1/5.mdx index 755310f6c..3c133aea8 100644 --- a/chapters/ko/chapter1/5.mdx +++ b/chapters/ko/chapter1/5.mdx @@ -14,4 +14,4 @@ - [BERT](https://huggingface.co/transformers/model_doc/bert.html) - [DistilBERT](https://huggingface.co/transformers/model_doc/distilbert.html) - [ELECTRA](https://huggingface.co/transformers/model_doc/electra.html) -- [RoBERTa](https://huggingface.co/transformers/model_doc/roberta.html) \ No newline at end of file +- [RoBERTa](https://huggingface.co/transformers/model_doc/roberta.html) diff --git a/chapters/ko/chapter1/6.mdx b/chapters/ko/chapter1/6.mdx index 4f8f0afa8..121403b4d 100644 --- a/chapters/ko/chapter1/6.mdx +++ b/chapters/ko/chapter1/6.mdx @@ -13,4 +13,4 @@ - [CTRL](https://huggingface.co/transformers/model_doc/ctrl.html) - [GPT](https://huggingface.co/transformers/model_doc/gpt.html) - [GPT-2](https://huggingface.co/transformers/model_doc/gpt2.html) -- [Transformer XL](https://huggingface.co/transformers/model_doc/transformerxl.html) \ No newline at end of file +- [Transformer XL](https://huggingface.co/transformers/model_doc/transformerxl.html) diff --git a/chapters/ko/chapter1/7.mdx b/chapters/ko/chapter1/7.mdx index 2cca23686..98aad86e9 100644 --- a/chapters/ko/chapter1/7.mdx +++ b/chapters/ko/chapter1/7.mdx @@ -2,7 +2,7 @@ -인코더-디코더 모델(Encoder-decoder models)로도 불리는 *시퀀스-투-시퀀스 모델(sequence-to-sequence models)*은 트랜스포머 구조의 인코더, 디코더 둘을 모두 사용합니다. 각 단계마다, 인코더의 어텐션 레이어는 초기 문장의 모든 단어에 액세스 할 수 있는 반면, 디코더의 어텐션 레이어는 주어진 단어 앞에 위치한 단어들에만 액세스 할 수 있습니다. +인코더-디코더 모델(Encoder-decoder models) (*시퀀스-투-시퀀스 모델(sequence-to-sequence models)*로 부르기도 합니다)은 트랜스포머 구조의 인코더, 디코더 둘을 모두 사용합니다. 각 단계마다, 인코더의 어텐션 레이어는 초기 문장의 모든 단어에 액세스 할 수 있는 반면, 디코더의 어텐션 레이어는 주어진 단어 앞에 위치한 단어들에만 액세스 할 수 있습니다. 이러한 모델의 사전 학습은 인코더 혹은 디코더 모델의 방식을 모두 사용할 수 있지만 조금 더 복잡합니다. 이를테면, [T5](https://huggingface.co/t5-base)는 (여러 단어를 포함하기도 하는) 임의의 텍스트 범위를 하나의 특수 마스크 토큰으로 바꾸고 마스크 단어를 대체할 텍스트를 예측하는 방식으로 사전 학습 되었습니다. diff --git a/chapters/ko/chapter1/8.mdx b/chapters/ko/chapter1/8.mdx index 1466b0fbe..edbd32548 100644 --- a/chapters/ko/chapter1/8.mdx +++ b/chapters/ko/chapter1/8.mdx @@ -1,17 +1,17 @@ # 편향과 한계 사전 학습된 혹은 미세 조정된 모델을 프로덕션 단계에서 사용하실 계획이라면, 이러한 모델들은 강력한 툴이지만 한계가 있음을 반드시 명심하셔야 합니다. 가장 큰 한계점은 리서처들이 무수히 많은 양의 데이터를 사전 학습에 사용하기 위해, 인터넷상에서 모을 수 있는 양질의 데이터와 함께 그렇지 않은 데이터까지 수집했을 가능성이 있다는 것입니다. 이를 빠르게 보여드리기 위해 `fill-mask` 파이프라인에 BERT 모델을 연결한 예제를 다시 살펴보겠습니다: -``` +```python from transformers import pipeline unmasker = pipeline("fill-mask", model="bert-base-uncased") @@ -20,15 +20,13 @@ print([r["token_str"] for r in result]) result = unmasker("This woman works as a [MASK].") print([r["token_str"] for r in result]) - ``` -``` +```python out ['lawyer', 'carpenter', 'doctor', 'waiter', 'mechanic'] ['nurse', 'waitress', 'teacher', 'maid', 'prostitute'] - ``` -주어의 성별만 바꾼 두 문장에서 빠진 단어를 채울 때, 모델은 성별과 관계 없는 공통 답변(waiter/waitress)을 하나만 내놓았습니다. 다른 답변들은 일반적으로 특정 성별에 편향된 답변이었습니다. 이를테면, 모델은 매춘이라는 단어와 연관된 상위 5개의 단어에 “여성”과 “일”을 포함시켰습니다. BERT가 전체 인터넷 상의 텍스트를 이용하여 사전 학습된 것이 아니라 [English Wikipedia](https://huggingface.co/datasets/wikipedia) 와 [BookCorpus](https://huggingface.co/datasets/bookcorpus) 같이 상당히 중립적인 데이터를 이용하여 사전 학습 되었음에도 불구하고 이러한 현상이 일어납니다. +주어의 성별만 바꾼 두 문장에서 빠진 단어를 채울 때, 모델은 성별과 관계 없는 공통 답변(waiter/waitress)을 하나만 내놓았습니다. 다른 답변들은 일반적으로 특정 성별에 편향된 답변이었습니다. 이를테면, 모델은 매춘이라는 단어와 연관된 상위 5개의 단어에 “여성”과 “일”을 포함시켰습니다. BERT가 전체 인터넷 상의 텍스트를 이용하여 사전 학습된 것이 아니라 [English Wikipedia](https://huggingface.co/datasets/wikipedia) 와 [BookCorpus](https://huggingface.co/datasets/bookcorpus) 같이 상당히 중립적인 데이터를 이용해 사전 학습 되었음에도 불구하고 이러한 현상이 일어납니다. 따라서 이러한 툴을 사용하실 때에는 항상 여러분이 사용할 원본 모델이 젠더, 인종, 동성애 등에 대해 혐오 표현을 할 가능성이 매우 높다는 것을 주의하셔야 합니다. 이러한 모델은 미세 조정을 거쳐도 내제된 편향성을 없애지 못합니다. \ No newline at end of file diff --git a/chapters/ko/chapter1/9.mdx b/chapters/ko/chapter1/9.mdx index 3ebcd1701..191b5654d 100644 --- a/chapters/ko/chapter1/9.mdx +++ b/chapters/ko/chapter1/9.mdx @@ -1,8 +1,8 @@ # 단원 정리 -이번 단원에서는 🤗 Transformers의 하이레벨 함수인 `pipeline()` 를 사용하여 다양한 NLP 문제에 대한 접근 방식을 학습했습니다. 그리고 Hub에서 모델을 검색 및 사용하는 방법, Inference API를 이용해 브라우저 상에서 바로 모델을 테스트 하는 방법 또한 알아보았습니다. +이번 단원에서는 🤗 Transformers의 하이레벨 함수인 `pipeline()` 를 사용하여 다양한 NLP 문제에 대한 접근 방식을 배웠습니다. 그리고 Hub에서 모델을 검색하여 사용하는 방법, 추론 API를 이용해 브라우저 상에서 바로 모델을 테스트 하는 방법 또한 알아보았습니다. -지금까지 트랜스포머 모델의 대략작인 동작 방식과, 전이 학습(transfer learning)과 미세 조정(fine-tuning)의 중요성에 알아보았습니다. 핵심은 어떤 문제를 풀고싶냐에 따라 전체 모델 구조를 다 사용하거나 인코더, 디코더만 사용할 수도 있다는 것입니다. 아래 표는 이를 요약해서 보여주고 있습니다: +지금까지 트랜스포머 모델의 대략작인 동작 방식과, 전이 학습(transfer learning) 및 미세 조정(fine-tuning)의 중요성에 알아보았습니다. 핵심은 어떤 문제를 풀고싶냐에 따라 전체 모델 구조를 다 사용하거나 인코더, 디코더만 사용할 수도 있다는 것입니다. 아래 표는 이를 요약해서 보여주고 있습니다: | Model | Examples | Tasks | | --- | --- | --- | From 9855aa90394b2dc26ac4fdc5cf762c1f3c732443 Mon Sep 17 00:00:00 2001 From: ftarlaci <18291571+ftarlaci@users.noreply.github.com> Date: Tue, 5 Apr 2022 15:30:57 -0500 Subject: [PATCH 23/73] modified toctree.yml for chapter1/2 --- chapters/tr/_toctree.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/chapters/tr/_toctree.yml b/chapters/tr/_toctree.yml index 41c6d6420..5d84b3422 100644 --- a/chapters/tr/_toctree.yml +++ b/chapters/tr/_toctree.yml @@ -2,3 +2,9 @@ sections: - local: chapter0/1 title: Giriş + + +- title: 1. Transormer modelleri + sections: + - local: chapter1/2 + title: Doğal Dil İşleme From 05cb27c29d1a8b49917e7c818bbcd9677e3a5876 Mon Sep 17 00:00:00 2001 From: ftarlaci <18291571+ftarlaci@users.noreply.github.com> Date: Tue, 5 Apr 2022 15:36:17 -0500 Subject: [PATCH 24/73] modified toctree.yml for chapter1/2 & fix typo --- chapters/tr/_toctree.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/tr/_toctree.yml b/chapters/tr/_toctree.yml index 5d84b3422..7c06284a4 100644 --- a/chapters/tr/_toctree.yml +++ b/chapters/tr/_toctree.yml @@ -4,7 +4,7 @@ title: Giriş -- title: 1. Transormer modelleri +- title: 1. Transformer modelleri sections: - local: chapter1/2 title: Doğal Dil İşleme From 40a3ea8c1dcf6fa55201cf6751a00ebc5ac8b9f9 Mon Sep 17 00:00:00 2001 From: melaniedrevet Date: Wed, 6 Apr 2022 13:54:59 +0200 Subject: [PATCH 25/73] French Translation - Chapter 5 --- chapters/fr/_toctree.yml | 22 +- chapters/fr/chapter5/1.mdx | 17 + chapters/fr/chapter5/2.mdx | 167 +++++++++ chapters/fr/chapter5/3.mdx | 744 +++++++++++++++++++++++++++++++++++++ chapters/fr/chapter5/4.mdx | 287 ++++++++++++++ chapters/fr/chapter5/5.mdx | 469 +++++++++++++++++++++++ chapters/fr/chapter5/6.mdx | 530 ++++++++++++++++++++++++++ chapters/fr/chapter5/7.mdx | 11 + chapters/fr/chapter5/8.mdx | 226 +++++++++++ 9 files changed, 2472 insertions(+), 1 deletion(-) create mode 100644 chapters/fr/chapter5/1.mdx create mode 100644 chapters/fr/chapter5/2.mdx create mode 100644 chapters/fr/chapter5/3.mdx create mode 100644 chapters/fr/chapter5/4.mdx create mode 100644 chapters/fr/chapter5/5.mdx create mode 100644 chapters/fr/chapter5/6.mdx create mode 100644 chapters/fr/chapter5/7.mdx create mode 100644 chapters/fr/chapter5/8.mdx diff --git a/chapters/fr/_toctree.yml b/chapters/fr/_toctree.yml index 4a4973f75..ad9953b2d 100644 --- a/chapters/fr/_toctree.yml +++ b/chapters/fr/_toctree.yml @@ -1,4 +1,24 @@ - title: 0. Configuration sections: - local: chapter0/1 - title: Introduction \ No newline at end of file + title: Introduction + +- title: 5. La bibliothèque 🤗 Datasets + sections: + - local: chapter5/1 + title: Introduction + - local: chapter5/2 + title: Que faire si mon ensemble de données n'est pas sur le Hub ? + - local: chapter5/3 + title: Il est temps de trancher et de découper + - local: chapter5/4 + title: Big Data? 🤗 Des jeux de données à la rescousse ! + - local: chapter5/5 + title: Création de votre propre jeu de données + - local: chapter5/6 + title: Recherche sémantique avec FAISS + - local: chapter5/7 + title: 🤗 Datasets, vérifié ! + - local: chapter5/8 + title: Quiz de fin de chapitre + quiz: 5 \ No newline at end of file diff --git a/chapters/fr/chapter5/1.mdx b/chapters/fr/chapter5/1.mdx new file mode 100644 index 000000000..8e76cea5e --- /dev/null +++ b/chapters/fr/chapter5/1.mdx @@ -0,0 +1,17 @@ +# Introduction + +Dans le [Chapitre 3](/course/chapter3) vous avez eu un premier aperçu de la bibliothèque 🤗 Datasets et vous avez vu qu'il y avait trois étapes principales pour affiner un modèle: + +1. Chargez un jeu de données à partir de Hugging Face Hub. +2. Prétraitez les données avec `Dataset.map()`. +3. Charger et calculer des métriques. + +Mais ce n'est qu'effleurer la surface de ce que 🤗 Datasets peut faire ! Dans ce chapitre, nous allons plonger profondément dans la bibliothèque. En cours de route, nous trouverons des réponses aux questions suivantes: + +* Que faites-vous lorsque votre jeu de données n'est pas sur le Hub ? +* Comment pouvez-vous découper et trancher un ensemble de données ? (Et si vous avez _vraiment_ besoin d'utiliser Pandas ?) +* Que faites-vous lorsque votre ensemble de données est énorme et va faire fondre la RAM de votre ordinateur portable ? +* Qu'est-ce que c'est que le "mappage de la mémoire" et Apache Arrow ? +* Comment pouvez-vous créer votre propre ensemble de données et le pousser vers le Hub ? + +Les techniques que vous apprenez ici vous prépareront aux tâches avancées de tokenisation et de réglage fin du [Chapitre 6](/course/chapter6) et du [Chapitre 7](/course/chapter7) -- alors prenez un café et commençons ! \ No newline at end of file diff --git a/chapters/fr/chapter5/2.mdx b/chapters/fr/chapter5/2.mdx new file mode 100644 index 000000000..896dc8ca2 --- /dev/null +++ b/chapters/fr/chapter5/2.mdx @@ -0,0 +1,167 @@ +# Que faire si mon ensemble de données n'est pas sur le Hub ? + + + +Vous savez comment utiliser le [Hugging Face Hub](https://huggingface.co/datasets) pour télécharger des ensembles de données, mais vous vous retrouverez souvent à travailler avec des données stockées sur votre ordinateur portable ou sur un serveur distant. Dans cette section, nous allons vous montrer comment 🤗 Datasets peut être utilisé pour charger des ensembles de données qui ne sont pas disponibles sur le Hugging Face Hub. + + + +## Travailler avec des ensembles de données locaux et distants + +🤗 Datasets fournit des scripts de chargement pour gérer le chargement des ensembles de données locaux et distants. Il prend en charge plusieurs formats de données courants, tels que : + +| Format de données | Chargement du script | Exemple | +| :----------------: | :------------------: | :-----------------------------------------------------: | +| CSV & TSV | `csv` | `load_dataset("csv", data_files="my_file.csv")` | +| Fichiers texte | `text` | `load_dataset("text", data_files="my_file.txt")` | +| JSON & Lignes JSON | `json` | `load_dataset("json", data_files="my_file.jsonl")` | +| DataFrames marinés | `pandas` | `load_dataset("pandas", data_files="my_dataframe.pkl")` | + +Comme indiqué dans le tableau, pour chaque format de données, nous avons juste besoin de spécifier le type de script de chargement dans la fonction `load_dataset()`, ainsi qu'un argument `data_files` qui spécifie le chemin vers un ou plusieurs fichiers. Commençons par charger un jeu de données à partir de fichiers locaux ; plus tard, nous verrons comment faire la même chose avec des fichiers distants. + +## Charger un jeu de données local + +Pour cet exemple, nous utiliserons l'ensemble de données [SQuAD-it](https://github.com/crux82/squad-it/), qui est un ensemble de données à grande échelle pour répondre aux questions en Italien. + +Les fractionnements de formation et de test sont hébergés sur GitHub, nous pouvons donc les télécharger avec une simple commande `wget` : + +```python +!wget https://github.com/crux82/squad-it/raw/master/SQuAD_it-train.json.gz +!wget https://github.com/crux82/squad-it/raw/master/SQuAD_it-test.json.gz +``` + +Cela téléchargera deux fichiers compressés appelés *SQuAD_it-train.json.gz* et *SQuAD_it-test.json.gz*, que nous pouvons décompresser avec la commande Linux `gzip` : + +```python +!gzip -dkv SQuAD_it-*.json.gz +``` + +```bash +SQuAD_it-test.json.gz: 87.4% -- replaced with SQuAD_it-test.json +SQuAD_it-train.json.gz: 82.2% -- replaced with SQuAD_it-train.json +``` + +Nous pouvons voir que les fichiers compressés ont été remplacés par _SQuAD_it-train.json_ et _SQuAD_it-text.json_, et que les données sont stockées au format JSON. + + + +✎ Si vous vous demandez pourquoi il y a un caractère `!` dans les commandes shell ci-dessus, c'est parce que nous les exécutons dans un cahier Jupyter. Supprimez simplement le préfixe si vous souhaitez télécharger et décompresser l'ensemble de données dans un terminal. + + + +Pour charger un fichier JSON avec la fonction `load_dataset()`, nous avons juste besoin de savoir si nous avons affaire à du JSON ordinaire (similaire à un dictionnaire imbriqué) ou à des lignes JSON (JSON séparé par des lignes). Comme de nombreux ensembles de données de questions-réponses, SQuAD-it utilise le format imbriqué, avec tout le texte stocké dans un champ "données". Cela signifie que nous pouvons charger le jeu de données en spécifiant l'argument `field` comme suit : + +```py +from datasets import load_dataset + +squad_it_dataset = load_dataset("json", data_files="SQuAD_it-train.json", field="data") +``` + +Par défaut, le chargement de fichiers locaux crée un objet `DatasetDict` avec une division `train`. Nous pouvons le voir en inspectant l'objet `squad_it_dataset` : + +```py +squad_it_dataset +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['title', 'paragraphs'], + num_rows: 442 + }) +}) +``` + +Cela nous montre le nombre de lignes et les noms de colonnes associés à l'ensemble d'apprentissage. Nous pouvons afficher l'un des exemples en indexant la division "train" comme suit : + +```py +squad_it_dataset["train"][0] +``` + +```python out +{ + "title": "Terremoto del Sichuan del 2008", + "paragraphs": [ + { + "context": "Il terremoto del Sichuan del 2008 o il terremoto...", + "qas": [ + { + "answers": [{"answer_start": 29, "text": "2008"}], + "id": "56cdca7862d2951400fa6826", + "question": "In quale anno si è verificato il terremoto nel Sichuan?", + }, + ... + ], + }, + ... + ], +} +``` + +Super, nous avons chargé notre premier jeu de données local ! Mais bien que cela ait fonctionné pour l'ensemble d'entraînement, ce que nous voulons vraiment, c'est inclure à la fois les divisions `train` et `test` dans un seul objet `DatasetDict` afin que nous puissions appliquer les fonctions `Dataset.map()` sur les deux divisions à la fois . Pour ce faire, nous pouvons fournir un dictionnaire à l'argument `data_files` qui associe chaque nom de division à un fichier associé à cette division : + +```py +data_files = {"train": "SQuAD_it-train.json", "test": "SQuAD_it-test.json"} +squad_it_dataset = load_dataset("json", data_files=data_files, field="data") +squad_it_dataset +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['title', 'paragraphs'], + num_rows: 442 + }) + test: Dataset({ + features: ['title', 'paragraphs'], + num_rows: 48 + }) +}) +``` + +C'est exactement ce que nous voulions. Désormais, nous pouvons appliquer diverses techniques de prétraitement pour nettoyer les données, tokeniser les avis, etc. + + + +The `data_files` argument of the `load_dataset()` function is quite flexible and can be either a single file path, a list of file paths, or a dictionary that maps split names to file paths. You can also group files matching a specified pattern according to the rules used by the Unix shell (for example, you can group all JSON files in a directory into a single division by setting `data_files="*.json"` ). See 🤗 Datasets [documentation](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) for details. + + + +Les scripts de chargement dans 🤗 Datasets prend en charge la décompression automatique des fichiers d'entrée, nous aurions donc pu ignorer l'utilisation de `gzip` en pointant l'argument `data_files` directement sur les fichiers compressés : + +```py +data_files = {"train": "SQuAD_it-train.json.gz", "test": "SQuAD_it-test.json.gz"} +squad_it_dataset = load_dataset("json", data_files=data_files, field="data") +``` + +Cela peut être utile si vous ne souhaitez pas décompresser manuellement de nombreux fichiers GZIP. La décompression automatique s'applique également à d'autres formats courants tels que ZIP et TAR, il vous suffit donc de pointer `data_files` vers les fichiers compressés et vous êtes prêt à partir ! + +Maintenant que vous savez comment charger des fichiers locaux sur votre ordinateur portable ou de bureau, examinons le chargement de fichiers distants. + +## Charger un jeu de données distant + +Si vous travaillez en tant que data scientist ou codeur dans une entreprise, il y a de fortes chances que les ensembles de données que vous souhaitez analyser soient stockés sur un serveur distant. Heureusement, charger des fichiers distants est aussi simple que de charger des fichiers locaux ! Au lieu de fournir un chemin vers les fichiers locaux, nous pointons l'argument `data_files` de `load_dataset()` vers une ou plusieurs URL où les fichiers distants sont stockés. Par exemple, pour l'ensemble de données SQuAD-it hébergé sur GitHub, nous pouvons simplement faire pointer `data_files` vers les URL _SQuAD_it-*.json.gz_ comme suit : + +```py +url = "https://github.com/crux82/squad-it/raw/master/" +data_files = { + "train": url + "SQuAD_it-train.json.gz", + "test": url + "SQuAD_it-test.json.gz", +} +squad_it_dataset = load_dataset("json", data_files=data_files, field="data") +``` + +Cela renvoie le même objet `DatasetDict` obtenu ci-dessus, mais nous évite de télécharger et de décompresser manuellement les fichiers _SQuAD_it-*.json.gz_. Ceci conclut notre incursion dans les différentes façons de charger des ensembles de données qui ne sont pas hébergés sur le Hugging Face Hub. Maintenant que nous avons un ensemble de données avec lequel jouer, mettons-nous la main à la pâte avec diverses techniques de gestion des données ! + + + +✏️ **Essayez-le !** Choisissez un autre ensemble de données hébergé sur GitHub ou le [UCI Machine Learning Repository](https://archive.ics.uci.edu/ml/index.php) et essayez de le charger localement et à distance en utilisant les techniques présentées ci-dessus. Pour obtenir des points bonus, essayez de charger un ensemble de données stocké au format CSV ou texte (voir la [documentation](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) pour plus d'informations sur ces formats). + + + + diff --git a/chapters/fr/chapter5/3.mdx b/chapters/fr/chapter5/3.mdx new file mode 100644 index 000000000..9d6a57959 --- /dev/null +++ b/chapters/fr/chapter5/3.mdx @@ -0,0 +1,744 @@ +# Il est temps de trancher et de découper + + + +La plupart du temps, les données avec lesquelles vous travaillez ne seront pas parfaitement préparées pour les modèles de formation. Dans cette section, nous allons explorer les différentes fonctionnalités fournies par 🤗 Datasets pour nettoyer vos ensembles de données. + + + +## Trancher et découper nos données + +Semblable à Pandas, 🤗 Datasets fournit plusieurs fonctions pour manipuler le contenu des objets `Dataset` et `DatasetDict`. Nous avons déjà rencontré la méthode `Dataset.map()` dans le [Chapitre 3](/course/chapter3), et dans cette section nous allons explorer certaines des autres fonctions à notre disposition. + +Pour cet exemple, nous utiliserons le [Drug Review Dataset](https://archive.ics.uci.edu/ml/datasets/Drug+Review+Dataset+%28Drugs.com%29) qui est hébergé sur [UC Irvine Machine Learning Repository] (https://archive.ics.uci.edu/ml/index.php), qui contient des avis de patients sur divers médicaments, ainsi que la condition traitée et une note de 10 étoiles sur la satisfaction du patient. + +Nous devons d'abord télécharger et extraire les données, ce qui peut être fait avec les commandes `wget` et `unzip` : + +```py +!wget "https://archive.ics.uci.edu/ml/machine-learning-databases/00462/drugsCom_raw.zip" +!unzip drugsCom_raw.zip +``` + +Étant donné que TSV n'est qu'une variante de CSV qui utilise des tabulations au lieu de virgules comme séparateurs, nous pouvons charger ces fichiers en utilisant le script de chargement `csv` et en spécifiant l'argument `delimiter` dans la fonction `load_dataset()` comme suit : + +```py +from datasets import load_dataset + +data_files = {"train": "drugsComTrain_raw.tsv", "test": "drugsComTest_raw.tsv"} +# \t is the tab character in Python +drug_dataset = load_dataset("csv", data_files=data_files, delimiter="\t") +``` + +Une bonne pratique lors de toute sorte d'analyse de données consiste à prélever un petit échantillon aléatoire pour avoir une idée rapide du type de données avec lesquelles vous travaillez. Dans 🤗 Datasets, nous pouvons créer un échantillon aléatoire en enchaînant les fonctions `Dataset.shuffle()` et `Dataset.select()` : + +```py +drug_sample = drug_dataset["train"].shuffle(seed=42).select(range(1000)) +# Peek at the first few examples +drug_sample[:3] +``` + +```python out +{'Unnamed: 0': [87571, 178045, 80482], + 'drugName': ['Naproxen', 'Duloxetine', 'Mobic'], + 'condition': ['Gout, Acute', 'ibromyalgia', 'Inflammatory Conditions'], + 'review': ['"like the previous person mention, I'm a strong believer of aleve, it works faster for my gout than the prescription meds I take. No more going to the doctor for refills.....Aleve works!"', + '"I have taken Cymbalta for about a year and a half for fibromyalgia pain. It is great\r\nas a pain reducer and an anti-depressant, however, the side effects outweighed \r\nany benefit I got from it. I had trouble with restlessness, being tired constantly,\r\ndizziness, dry mouth, numbness and tingling in my feet, and horrible sweating. I am\r\nbeing weaned off of it now. Went from 60 mg to 30mg and now to 15 mg. I will be\r\noff completely in about a week. The fibro pain is coming back, but I would rather deal with it than the side effects."', + '"I have been taking Mobic for over a year with no side effects other than an elevated blood pressure. I had severe knee and ankle pain which completely went away after taking Mobic. I attempted to stop the medication however pain returned after a few days."'], + 'rating': [9.0, 3.0, 10.0], + 'date': ['September 2, 2015', 'November 7, 2011', 'June 5, 2013'], + 'usefulCount': [36, 13, 128]} +``` + +Notez que nous avons corrigé la graine dans `Dataset.shuffle()` à des fins de reproductibilité. `Dataset.select()` attend un itérable d'indices, nous avons donc passé `range(1000)` pour récupérer les 1 000 premiers exemples de l'ensemble de données mélangé. À partir de cet échantillon, nous pouvons déjà voir quelques bizarreries dans notre ensemble de données : + +* La colonne "Sans nom : 0" ressemble étrangement à un identifiant anonyme pour chaque patient. +* La colonne "condition" comprend un mélange d'étiquettes en majuscules et en minuscules. +* Les avis sont de longueur variable et contiennent un mélange de séparateurs de lignes Python (`\r\n`) ainsi que des codes de caractères HTML comme `&\#039;`. + +Voyons comment nous pouvons utiliser 🤗 Datasets pour traiter chacun de ces problèmes. Pour tester l'hypothèse de l'ID patient pour la colonne `Unnamed : 0`, nous pouvons utiliser la fonction `Dataset.unique()` pour vérifier que le nombre d'ID correspond au nombre de lignes dans chaque division : + +```py +for split in drug_dataset.keys(): + assert len(drug_dataset[split]) == len(drug_dataset[split].unique("Unnamed: 0")) +``` + +Cela semble confirmer notre hypothèse, alors nettoyons un peu l'ensemble de données en renommant la colonne `Unnamed: 0` en quelque chose d'un peu plus interprétable. Nous pouvons utiliser la fonction `DatasetDict.rename_column()` pour renommer la colonne sur les deux divisions en une seule fois : + +```py +drug_dataset = drug_dataset.rename_column( + original_column_name="Unnamed: 0", new_column_name="patient_id" +) +drug_dataset +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount'], + num_rows: 161297 + }) + test: Dataset({ + features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount'], + num_rows: 53766 + }) +}) +``` + + + +✏️ **Essayez-le !** Utilisez la fonction "Dataset.unique()" pour trouver le nombre de médicaments et de conditions uniques dans les ensembles d'entraînement et de test. + + + +Ensuite, normalisons toutes les étiquettes `condition` en utilisant `Dataset.map()`. Comme nous l'avons fait avec la tokenisation dans le [chapitre 3](/course/chapter3), nous pouvons définir une fonction simple qui peut être appliquée sur toutes les lignes de chaque division dans `drug_dataset` : + +```py +def lowercase_condition(example): + return {"condition": example["condition"].lower()} + + +drug_dataset.map(lowercase_condition) +``` + +```python out +AttributeError: 'NoneType' object has no attribute 'lower' +``` + +Oh non, nous avons rencontré un problème avec notre fonction de carte ! À partir de l'erreur, nous pouvons déduire que certaines des entrées de la colonne "condition" sont "Aucune", qui ne peuvent pas être mises en minuscules car ce ne sont pas des chaînes. Supprimons ces lignes en utilisant `Dataset.filter()`, qui fonctionne de manière similaire à `Dataset.map()` et attend une fonction qui reçoit un seul exemple de l'ensemble de données. Au lieu d'écrire une fonction explicite comme : + +```py +def filter_nones(x): + return x["condition"] is not None +``` + +puis en exécutant `drug_dataset.filter(filter_nones)`, nous pouvons le faire en une seule ligne en utilisant une _lambda function_. En Python, les fonctions lambda sont de petites fonctions que vous pouvez définir sans les nommer explicitement. Ils prennent la forme générale : + +``` +lambda : +``` + +où `lambda` est l'un des [mots clés] spéciaux de Python (https://docs.python.org/3/reference/lexical_analysis.html#keywords), `` est une liste/ensemble de valeurs séparées par des virgules qui définissent les entrées de la fonction et `` représente les opérations que vous souhaitez exécuter. Par exemple, nous pouvons définir une simple fonction lambda qui met au carré un nombre comme suit : + +``` +lambda x : x * x +``` + +Pour appliquer cette fonction à une entrée, nous devons l'envelopper ainsi que l'entrée entre parenthèses : + +```py +(lambda x: x * x)(3) +``` + +```python out +9 +``` + +De même, nous pouvons définir des fonctions lambda avec plusieurs arguments en les séparant par des virgules. Par exemple, nous pouvons calculer l'aire d'un triangle comme suit : + +```py +(lambda base, height: 0.5 * base * height)(4, 8) +``` + +```python out +16.0 +``` + +Les fonctions Lambda sont pratiques lorsque vous souhaitez définir de petites fonctions à usage unique (pour plus d'informations à leur sujet, nous vous recommandons de lire l'excellent [tutoriel Real Python](https://realpython.com/python-lambda/) d'André Burgaud) . Dans le contexte 🤗 Datasets, nous pouvons utiliser des fonctions lambda pour définir des opérations simples de mappage et de filtrage, alors utilisons cette astuce pour éliminer les entrées "None" dans notre jeu de données : + +```py +drug_dataset = drug_dataset.filter(lambda x: x["condition"] is not None) +``` + +Avec les entrées "None" supprimées, nous pouvons normaliser notre colonne "condition" : + +```py +drug_dataset = drug_dataset.map(lowercase_condition) +# Check that lowercasing worked +drug_dataset["train"]["condition"][:3] +``` + +```python out +['left ventricular dysfunction', 'adhd', 'birth control'] +``` + +Ça marche ! Maintenant que nous avons nettoyé les étiquettes, examinons le nettoyage des avis eux-mêmes. + +## Création de nouvelles colonnes + +Chaque fois que vous avez affaire à des avis de clients, une bonne pratique consiste à vérifier le nombre de mots dans chaque avis. Une critique peut être un simple mot comme "Génial !" ou un essai complet avec des milliers de mots, et selon le cas d'utilisation, vous devrez gérer ces extrêmes différemment. Pour calculer le nombre de mots dans chaque révision, nous utiliserons une heuristique approximative basée sur la division de chaque texte par des espaces. + +Définissons une fonction simple qui compte le nombre de mots dans chaque avis : + +```py +def compute_review_length(example): + return {"review_length": len(example["review"].split())} +``` + +Contrairement à notre fonction `lowercase_condition()`, `compute_review_length()` renvoie un dictionnaire dont la clé ne correspond pas à l'un des noms de colonne de l'ensemble de données. Dans ce cas, lorsque `compute_review_length()` est passé à `Dataset.map()`, il sera appliqué à toutes les lignes du jeu de données pour créer une nouvelle colonne `review_length` : + +```py +drug_dataset = drug_dataset.map(compute_review_length) +# Inspect the first training example +drug_dataset["train"][0] +``` + +```python out +{'patient_id': 206461, + 'drugName': 'Valsartan', + 'condition': 'left ventricular dysfunction', + 'review': '"It has no side effect, I take it in combination of Bystolic 5 Mg and Fish Oil"', + 'rating': 9.0, + 'date': 'May 20, 2012', + 'usefulCount': 27, + 'review_length': 17} +``` + +Comme prévu, nous pouvons voir qu'une colonne "review_length" a été ajoutée à notre ensemble d'entraînement. Nous pouvons trier cette nouvelle colonne avec `Dataset.sort()` pour voir à quoi ressemblent les valeurs extrêmes : + +```py +drug_dataset["train"].sort("review_length")[:3] +``` + +```python out +{'patient_id': [103488, 23627, 20558], + 'drugName': ['Loestrin 21 1 / 20', 'Chlorzoxazone', 'Nucynta'], + 'condition': ['birth control', 'muscle spasm', 'pain'], + 'review': ['"Excellent."', '"useless"', '"ok"'], + 'rating': [10.0, 1.0, 6.0], + 'date': ['November 4, 2008', 'March 24, 2017', 'August 20, 2016'], + 'usefulCount': [5, 2, 10], + 'review_length': [1, 1, 1]} +``` + +Comme nous le soupçonnions, certaines critiques ne contiennent qu'un seul mot, ce qui, bien que cela puisse convenir à l'analyse des sentiments, ne serait pas informatif si nous voulons prédire la condition. + + + +🙋 Une autre façon d'ajouter de nouvelles colonnes à un ensemble de données consiste à utiliser la fonction `Dataset.add_column()`. Cela vous permet de fournir la colonne sous forme de liste Python ou de tableau NumPy et peut être utile dans les situations où `Dataset.map()` n'est pas bien adapté à votre analyse. + + + +Utilisons la fonction `Dataset.filter()` pour supprimer les avis contenant moins de 30 mots. De la même manière que nous l'avons fait avec la colonne "condition", nous pouvons filtrer les avis très courts en exigeant que les avis aient une longueur supérieure à ce seuil : + +```py +drug_dataset = drug_dataset.filter(lambda x: x["review_length"] > 30) +print(drug_dataset.num_rows) +``` + +```python out +{'train': 138514, 'test': 46108} +``` + +Comme vous pouvez le constater, cela a supprimé environ 15 % des avis de nos ensembles d'entraînement et de test d'origine. + + + +✏️ **Essayez-le !** Utilisez la fonction `Dataset.sort()` pour inspecter les avis avec le plus grand nombre de mots. Consultez la [documentation](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.sort) pour voir quel argument vous devez utiliser pour trier les avis par longueur dans l'ordre décroissant. + + + +La dernière chose à laquelle nous devons faire face est la présence de codes de caractères HTML dans nos avis. Nous pouvons utiliser le module `html` de Python pour supprimer ces caractères, comme ceci : + +```py +import html + +text = "I'm a transformer called BERT" +html.unescape(text) +``` + +```python out +"I'm a transformer called BERT" +``` + +Nous utiliserons `Dataset.map()` pour démasquer tous les caractères HTML de notre corpus : + +```python +drug_dataset = drug_dataset.map(lambda x: {"review": html.unescape(x["review"])}) +``` + +Comme vous pouvez le voir, la méthode `Dataset.map()` est très utile pour le traitement des données -- et nous n'avons même pas effleuré la surface de tout ce qu'elle peut faire ! + +## Les superpouvoirs de la méthode `map()` + +La méthode `Dataset.map()` prend un argument `batched` qui, s'il est défini sur `True`, l'amène à envoyer un lot d'exemples à la fonction map en une seule fois (la taille du lot est configurable mais par défaut à 1 000). Par exemple, la fonction de carte précédente qui dégageait tout le code HTML prenait un peu de temps à s'exécuter (vous pouvez lire le temps pris dans les barres de progression). On peut accélérer cela en traitant plusieurs éléments en même temps à l'aide d'une liste en compréhension. + +Lorsque vous spécifiez `batched=True`, la fonction reçoit un dictionnaire avec les champs de l'ensemble de données, mais chaque valeur est maintenant une _liste de valeurs_, et non plus une seule valeur. La valeur de retour de `Dataset.map()` devrait être la même : un dictionnaire avec les champs que nous voulons mettre à jour ou ajouter à notre ensemble de données, et une liste de valeurs. Par exemple, voici une autre façon de supprimer tous les caractères HTML, mais en utilisant `batched=True` : + +```python +new_drug_dataset = drug_dataset.map( + lambda x: {"review": [html.unescape(o) for o in x["review"]]}, batched=True +) +``` + +Si vous exécutez ce code dans un notebook, vous verrez que cette commande s'exécute beaucoup plus rapidement que la précédente. Et ce n'est pas parce que nos critiques ont déjà été sans échappement HTML -- si vous ré-exécutez l'instruction de la section précédente (sans `batched=True`), cela prendra le même temps qu'avant. En effet, les compréhensions de liste sont généralement plus rapides que l'exécution du même code dans une boucle "for", et nous gagnons également en performances en accédant à de nombreux éléments en même temps au lieu d'un par un. + +L'utilisation de `Dataset.map()` avec `batched=True` sera essentielle pour débloquer la vitesse des tokenizers "rapides" que nous rencontrerons dans [Chapitre 6](/course/chapter6), qui peuvent rapidement tokeniser de grandes listes de textes. Par exemple, pour tokeniser toutes les revues de médicaments avec un tokenizer rapide, nous pourrions utiliser une fonction comme celle-ci : + +```python +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") + + +def tokenize_function(examples): + return tokenizer(examples["review"], truncation=True) +``` + +Comme vous l'avez vu dans le [Chapitre 3](/course/chapter3), nous pouvons passer un ou plusieurs exemples au tokenizer, nous pouvons donc utiliser cette fonction avec ou sans `batched=True`. Profitons-en pour comparer les performances des différentes options. Dans un cahier, vous pouvez chronométrer une instruction d'une ligne en ajoutant `%time` avant la ligne de code que vous souhaitez mesurer : + +```python no-format +%time tokenized_dataset = drug_dataset.map(tokenize_function, batched=True) +``` + +Vous pouvez également chronométrer une cellule entière en mettant `%%time` au début de la cellule. Sur le matériel sur lequel nous avons exécuté cela, il affichait 10,8 s pour cette instruction (c'est le nombre écrit après "Wall time"). + + + +✏️ **Essayez-le !** Exécutez la même instruction avec et sans `batched=True`, puis essayez-le avec un tokenizer lent (ajoutez `use_fast=False` dans la méthode `AutoTokenizer.from_pretrained()`) afin que vous puissiez voir quels numéros vous obtenez sur votre matériel. + + + +Voici les résultats que nous avons obtenus avec et sans batching, avec un tokenizer rapide et un lent : + +Options | Tokenizer rapide | Tokenizer lent +:--------------:|:----------------:|:-----------------: +`batched=True` | 10.8s | 4min41s +`batched=False` | 59.2s | 5min3s + +Cela signifie que l'utilisation d'un tokenizer rapide avec l'option `batched=True` est 30 fois plus rapide que son homologue lent sans traitement par lot -- c'est vraiment incroyable ! C'est la raison principale pour laquelle les tokenizers rapides sont la valeur par défaut lors de l'utilisation de `AutoTokenizer` (et pourquoi ils sont appelés "rapides"). Ils sont capables d'atteindre une telle accélération car dans les coulisses, le code de tokenisation est exécuté dans Rust, qui est un langage qui facilite la parallélisation de l'exécution du code. + +La parallélisation est également la raison de l'accélération de près de 6 fois obtenue par le fast tokenizer avec le traitement par lots : vous ne pouvez pas paralléliser une seule opération de tokenisation, mais lorsque vous souhaitez tokeniser de nombreux textes en même temps, vous pouvez simplement répartir l'exécution sur plusieurs processus. chacun responsable de ses propres textes. + +`Dataset.map()` possède également ses propres capacités de parallélisation. Comme ils ne sont pas soutenus par Rust, ils ne laisseront pas un tokenizer lent rattraper un rapide, mais ils peuvent toujours être utiles (surtout si vous utilisez un tokenizer qui n'a pas de version rapide). Pour activer le multitraitement, utilisez l'argument `num_proc` et spécifiez le nombre de processus à utiliser dans votre appel à `Dataset.map()` : + +```py +slow_tokenizer = AutoTokenizer.from_pretrained("bert-base-cased", use_fast=False) + + +def slow_tokenize_function(examples): + return slow_tokenizer(examples["review"], truncation=True) + + +tokenized_dataset = drug_dataset.map(slow_tokenize_function, batched=True, num_proc=8) +``` + +Vous pouvez expérimenter un peu le timing pour déterminer le nombre optimal de processus à utiliser ; dans notre cas 8 semblait produire le meilleur gain de vitesse. Voici les chiffres que nous avons obtenus avec et sans multitraitement : + +Options | Tokenizer rapide | Tokenizer lent +:----------------------------:|:----------------:|:---------------: +`batched=True` | 10.8s | 4min41s +`batched=False` | 59.2s | 5min3s +`batched=True`, `num_proc=8` | 6.52s | 41.3s +`batched=False`, `num_proc=8` | 9.49s | 45.2s + +Ce sont des résultats beaucoup plus raisonnables pour le tokenizer lent, mais les performances du tokenizer rapide ont également été considérablement améliorées. Notez, cependant, que ce ne sera pas toujours le cas - pour les valeurs de `num_proc` autres que 8, nos tests ont montré qu'il était plus rapide d'utiliser `batched=True` sans cette option. En général, nous ne recommandons pas d'utiliser le multitraitement Python pour les tokenizers rapides avec `batched=True`. + + + +Utiliser `num_proc` pour accélérer votre traitement est généralement une bonne idée, tant que la fonction que vous utilisez n'effectue pas déjà une sorte de multitraitement. + + + +Toutes ces fonctionnalités condensées en une seule méthode sont déjà assez étonnantes, mais il y a plus ! Avec `Dataset.map()` et `batched=True` vous pouvez modifier le nombre d'éléments dans votre jeu de données. Ceci est très utile dans de nombreuses situations où vous souhaitez créer plusieurs fonctionnalités d'entraînement à partir d'un exemple, et nous devrons le faire dans le cadre du prétraitement de plusieurs des tâches NLP que nous entreprendrons dans [Chapitre 7](/course/ Chapitre 7). + + + +💡 En machine learning, un _example_ est généralement défini comme l'ensemble de _features_ que nous alimentons au modèle. Dans certains contextes, ces caractéristiques seront l'ensemble des colonnes d'un `Dataset`, mais dans d'autres (comme ici et pour la réponse aux questions), plusieurs caractéristiques peuvent être extraites d'un seul exemple et appartenir à une seule colonne. + + + +Voyons comment cela fonctionne ! Ici, nous allons tokeniser nos exemples et les tronquer à une longueur maximale de 128, mais nous demanderons au tokenizer de renvoyer *tous* les morceaux des textes au lieu du premier. Cela peut être fait avec `return_overflowing_tokens=True` : + +```py +def tokenize_and_split(examples): + return tokenizer( + examples["review"], + truncation=True, + max_length=128, + return_overflowing_tokens=True, + ) +``` + +Testons cela sur un exemple avant d'utiliser `Dataset.map()` sur l'ensemble de données : + +```py +result = tokenize_and_split(drug_dataset["train"][0]) +[len(inp) for inp in result["input_ids"]] +``` + +```python out +[128, 49] +``` + +Ainsi, notre premier exemple dans l'ensemble de formation est devenu deux fonctionnalités car il a été segmenté à plus que le nombre maximum de jetons que nous avons spécifié : le premier de longueur 128 et le second de longueur 49. Faisons maintenant cela pour tous les éléments du base de données! + +```py +tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True) +``` + +```python out +ArrowInvalid: Column 1 named condition expected length 1463 but got length 1000 +``` + +Oh non! Cela n'a pas fonctionné ! Pourquoi pas? L'examen du message d'erreur nous donnera un indice : il y a une incompatibilité dans les longueurs de l'une des colonnes, l'une étant de longueur 1 463 et l'autre de longueur 1 000. Si vous avez consulté la [documentation] `Dataset.map()`(https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map), vous vous souviendrez peut-être qu'il s'agit du nombre d'échantillons passés à la fonction que nous mappons ; ici, ces 1 000 exemples ont donné 1 463 nouvelles fonctionnalités, entraînant une erreur de forme. + +Le problème est que nous essayons de mélanger deux ensembles de données différents de tailles différentes : les colonnes `drug_dataset` auront un certain nombre d'exemples (les 1 000 dans notre erreur), mais le `tokenized_dataset` que nous construisons en aura plus (le 1 463 dans le message d'erreur). Cela ne fonctionne pas pour un `Dataset`, nous devons donc soit supprimer les colonnes de l'ancien jeu de données, soit leur donner la même taille que dans le nouveau jeu de données. Nous pouvons faire le premier avec l'argument `remove_columns` : + +```py +tokenized_dataset = drug_dataset.map( + tokenize_and_split, batched=True, remove_columns=drug_dataset["train"].column_names +) +``` + +Maintenant, cela fonctionne sans erreur. Nous pouvons vérifier que notre nouveau jeu de données contient beaucoup plus d'éléments que le jeu de données d'origine en comparant les longueurs : + +```py +len(tokenized_dataset["train"]), len(drug_dataset["train"]) +``` + +```python out +(206772, 138514) +``` + +Nous avons mentionné que nous pouvions également résoudre le problème de longueur non concordante en donnant aux anciennes colonnes la même taille que les nouvelles. Pour ce faire, nous aurons besoin du champ `overflow_to_sample_mapping` que le tokenizer renvoie lorsque nous définissons `return_overflowing_tokens=True`. Il nous donne une correspondance entre un nouvel index de fonctionnalité et l'index de l'échantillon dont il est issu. Grâce à cela, nous pouvons associer chaque clé présente dans notre jeu de données d'origine à une liste de valeurs de la bonne taille en répétant les valeurs de chaque exemple autant de fois qu'il génère de nouvelles fonctionnalités : + +```py +def tokenize_and_split(examples): + result = tokenizer( + examples["review"], + truncation=True, + max_length=128, + return_overflowing_tokens=True, + ) + # Extract mapping between new and old indices + sample_map = result.pop("overflow_to_sample_mapping") + for key, values in examples.items(): + result[key] = [values[i] for i in sample_map] + return result +``` + +Nous pouvons voir que cela fonctionne avec `Dataset.map()` sans que nous ayons besoin de supprimer les anciennes colonnes : + +```py +tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True) +tokenized_dataset +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['attention_mask', 'condition', 'date', 'drugName', 'input_ids', 'patient_id', 'rating', 'review', 'review_length', 'token_type_ids', 'usefulCount'], + num_rows: 206772 + }) + test: Dataset({ + features: ['attention_mask', 'condition', 'date', 'drugName', 'input_ids', 'patient_id', 'rating', 'review', 'review_length', 'token_type_ids', 'usefulCount'], + num_rows: 68876 + }) +}) +``` + +Nous obtenons le même nombre de fonctionnalités d'entraînement qu'auparavant, mais ici nous avons conservé tous les anciens champs. Si vous en avez besoin pour un post-traitement après l'application de votre modèle, vous pouvez utiliser cette approche. + +Vous avez maintenant vu comment 🤗 Datasets peut être utilisé pour prétraiter un ensemble de données de différentes manières. Bien que les fonctions de traitement de 🤗 Datasets couvrent la plupart de vos besoins de formation de modèles, +il peut arriver que vous deviez passer à Pandas pour accéder à des fonctionnalités plus puissantes, telles que `DataFrame.groupby()` ou des API de haut niveau pour la visualisation. Heureusement, 🤗 Datasets est conçu pour être interopérable avec des bibliothèques telles que Pandas, NumPy, PyTorch, TensorFlow et JAX. Voyons comment cela fonctionne. + +## De `Dataset`s à `DataFrame`s et vice versa + + + +Pour permettre la conversion entre diverses bibliothèques tierces, 🤗 Datasets fournit une fonction `Dataset.set_format()`. Cette fonction ne modifie que le _format de sortie_ de l'ensemble de données, vous pouvez donc facilement passer à un autre format sans affecter le _format de données_ sous-jacent, qui est Apache Arrow. Le formatage se fait sur place. Pour démontrer, convertissons notre jeu de données en Pandas : + +```py +drug_dataset.set_format("pandas") +``` + +Maintenant, lorsque nous accédons aux éléments du jeu de données, nous obtenons un `pandas.DataFrame` au lieu d'un dictionnaire : + +```py +drug_dataset["train"][:3] +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
patient_iddrugNameconditionreviewratingdateusefulCountreview_length
095260Guanfacineadhd"My son is halfway through his fourth week of Intuniv..."8.0April 27, 2010192141
192703Lybrelbirth control"I used to take another oral contraceptive, which had 21 pill cycle, and was very happy- very light periods, max 5 days, no other side effects..."5.0December 14, 200917134
2138000Ortho Evrabirth control"This is my first time using any form of birth control..."8.0November 3, 20151089
+ +Créons un `pandas.DataFrame` pour l'ensemble d'entraînement en sélectionnant tous les éléments de `drug_dataset["train"]` : + +```py +train_df = drug_dataset["train"][:] +``` + + + +🚨 Sous le capot, `Dataset.set_format()` change le format de retour pour la méthode dunder `__getitem__()` de l'ensemble de données. Cela signifie que lorsque nous voulons créer un nouvel objet comme `train_df` à partir d'un `Dataset` au format `"pandas"`, nous devons découper tout l'ensemble de données pour obtenir un `pandas.DataFrame`. Vous pouvez vérifier par vous-même que le type de `drug_dataset["train"]` est `Dataset`, quel que soit le format de sortie. + + + + +De là, nous pouvons utiliser toutes les fonctionnalités Pandas que nous voulons. Par exemple, nous pouvons faire un chaînage sophistiqué pour calculer la distribution de classe parmi les entrées `condition` : + +```py +frequencies = ( + train_df["condition"] + .value_counts() + .to_frame() + .reset_index() + .rename(columns={"index": "condition", "condition": "frequency"}) +) +frequencies.head() +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
conditionfrequency
0birth control27655
1depression8023
2acne5209
3anxiety4991
4pain4744
+ + +Et une fois que nous avons terminé notre analyse Pandas, nous pouvons toujours créer un nouvel objet `Dataset` en utilisant la fonction `Dataset.from_pandas()` comme suit : + + +```py +from datasets import Dataset + +freq_dataset = Dataset.from_pandas(frequencies) +freq_dataset +``` + +```python out +Dataset({ + features: ['condition', 'frequency'], + num_rows: 819 +}) +``` + + + +✏️ **Essayez-le !** Calculez la note moyenne par médicament et stockez le résultat dans un nouvel ensemble de données. + + + +Ceci conclut notre visite des différentes techniques de prétraitement disponibles dans 🤗 Datasets. Pour compléter la section, créons un ensemble de validation pour préparer l'ensemble de données pour la formation d'un classificateur. Avant cela, nous allons réinitialiser le format de sortie de `drug_dataset` de `"pandas"` à `"arrow"` : + +```python +drug_dataset.reset_format() +``` + +## Création d'un ensemble de validation + +Bien que nous ayons un jeu de test que nous pourrions utiliser pour l'évaluation, il est recommandé de ne pas toucher au jeu de test et de créer un jeu de validation séparé pendant le développement. Une fois que vous êtes satisfait des performances de vos modèles sur l'ensemble de validation, vous pouvez effectuer une dernière vérification d'intégrité sur l'ensemble de test. Ce processus permet d'atténuer le risque de dépassement de l'ensemble de test et de déploiement d'un modèle qui échoue sur des données du monde réel. + +🤗 Datasets fournit une fonction `Dataset.train_test_split()` basée sur la célèbre fonctionnalité de `scikit-learn`. Utilisons-le pour diviser notre ensemble d'entraînement en divisions "train" et "validation" (nous définissons l'argument "seed" pour la reproductibilité) : + +```py +drug_dataset_clean = drug_dataset["train"].train_test_split(train_size=0.8, seed=42) +# Rename the default "test" split to "validation" +drug_dataset_clean["validation"] = drug_dataset_clean.pop("test") +# Add the "test" set to our `DatasetDict` +drug_dataset_clean["test"] = drug_dataset["test"] +drug_dataset_clean +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length', 'review_clean'], + num_rows: 110811 + }) + validation: Dataset({ + features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length', 'review_clean'], + num_rows: 27703 + }) + test: Dataset({ + features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length', 'review_clean'], + num_rows: 46108 + }) +}) +``` + +Génial, nous avons maintenant préparé un jeu de données prêt pour l'entraînement de certains modèles ! Dans la [section 5](/course/chapter5/5), nous vous montrerons comment télécharger des ensembles de données sur le Hugging Face Hub, mais pour l'instant, terminons notre analyse en examinant quelques façons d'enregistrer des ensembles de données sur votre ordinateur local. + +## Enregistrer un jeu de données + + + +Bien que 🤗 Datasets mette en cache chaque jeu de données téléchargé et les opérations qui y sont effectuées, il y a des moments où vous voudrez enregistrer un jeu de données sur le disque (par exemple, au cas où le cache serait supprimé). Comme indiqué dans le tableau ci-dessous, 🤗 Datasets fournit trois fonctions principales pour enregistrer votre jeu de données dans différents formats : + +| Format de données | Fonction | +| :---------------: | :----------------------: | +| Flèche | `Dataset.save_to_disk()` | +| CSV | `Dataset.to_csv()` | +| JSON | `Dataset.to_json()` | + +Par exemple, enregistrons notre jeu de données nettoyé au format Arrow : + +```py +drug_dataset_clean.save_to_disk("drug-reviews") +``` + +Cela créera un répertoire avec la structure suivante : + +``` +drug-reviews/ +├── dataset_dict.json +├── test +│ ├── dataset.arrow +│ ├── dataset_info.json +│ └── state.json +├── train +│ ├── dataset.arrow +│ ├── dataset_info.json +│ ├── indices.arrow +│ └── state.json +└── validation + ├── dataset.arrow + ├── dataset_info.json + ├── indices.arrow + └── state.json +``` + +où nous pouvons voir que chaque division est associée à sa propre table * dataset.arrow * et à certaines métadonnées dans * dataset_info.json * et * state.json *. Vous pouvez considérer le format Arrow comme un tableau sophistiqué de colonnes et de lignes optimisé pour la création d'applications hautes performances qui traitent et transportent de grands ensembles de données. + +Une fois le jeu de données enregistré, nous pouvons le charger en utilisant la fonction `load_from_disk()` comme suit : + +```py +from datasets import load_from_disk + +drug_dataset_reloaded = load_from_disk("drug-reviews") +drug_dataset_reloaded +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length'], + num_rows: 110811 + }) + validation: Dataset({ + features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length'], + num_rows: 27703 + }) + test: Dataset({ + features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length'], + num_rows: 46108 + }) +}) +``` + +Pour les formats CSV et JSON, nous devons stocker chaque fractionnement dans un fichier séparé. Pour ce faire, vous pouvez parcourir les clés et les valeurs de l'objet "DatasetDict" : + +```py +for split, dataset in drug_dataset_clean.items(): + dataset.to_json(f"drug-reviews-{split}.jsonl") +``` + +Cela enregistre chaque fractionnement au [format de lignes JSON] (https://jsonlines.org), où chaque ligne de l'ensemble de données est stockée sous la forme d'une seule ligne de JSON. Voici à quoi ressemble le premier exemple : + +```py +!head -n 1 drug-reviews-train.jsonl +``` + +```python out +{"patient_id":141780,"drugName":"Escitalopram","condition":"depression","review":"\"I seemed to experience the regular side effects of LEXAPRO, insomnia, low sex drive, sleepiness during the day. I am taking it at night because my doctor said if it made me tired to take it at night. I assumed it would and started out taking it at night. Strange dreams, some pleasant. I was diagnosed with fibromyalgia. Seems to be helping with the pain. Have had anxiety and depression in my family, and have tried quite a few other medications that haven't worked. Only have been on it for two weeks but feel more positive in my mind, want to accomplish more in my life. Hopefully the side effects will dwindle away, worth it to stick with it from hearing others responses. Great medication.\"","rating":9.0,"date":"May 29, 2011","usefulCount":10,"review_length":125} +``` + +Nous pouvons ensuite utiliser les techniques de [section 2](/course/chapter5/2) pour charger les fichiers JSON comme suit : + +```py +data_files = { + "train": "drug-reviews-train.jsonl", + "validation": "drug-reviews-validation.jsonl", + "test": "drug-reviews-test.jsonl", +} +drug_dataset_reloaded = load_dataset("json", data_files=data_files) +``` + +Et c'est tout pour notre excursion dans le data wrangling avec 🤗 Datasets ! Maintenant que nous disposons d'un ensemble de données nettoyé pour entraîner un modèle, voici quelques idées que vous pouvez essayer : + +1. Utilisez les techniques du [Chapitre 3](/course/chapter3) pour former un classificateur capable de prédire l'état du patient en fonction de l'examen du médicament. +2. Utilisez le pipeline `summarization` du [Chapitre 1](/course/chapter1) pour générer des résumés des révisions. + +Ensuite, nous verrons comment 🤗 Datasets peut vous permettre de travailler avec d'énormes ensembles de données sans faire exploser votre ordinateur portable ! diff --git a/chapters/fr/chapter5/4.mdx b/chapters/fr/chapter5/4.mdx new file mode 100644 index 000000000..63ed0be44 --- /dev/null +++ b/chapters/fr/chapter5/4.mdx @@ -0,0 +1,287 @@ +# Big Data? 🤗 Datasets à la rescousse ! + + + + +De nos jours, il n'est pas rare de travailler avec des ensembles de données de plusieurs gigaoctets, surtout si vous envisagez de pré-entraîner un transformateur comme BERT ou GPT-2 à partir de zéro. Dans ces cas, même _charger_ les données peut être un défi. Par exemple, le corpus WebText utilisé pour pré-entraîner GPT-2 se compose de plus de 8 millions de documents et de 40 Go de texte - le charger dans la RAM de votre ordinateur portable est susceptible de lui donner une crise cardiaque ! + +Heureusement, 🤗 Datasets a été conçu pour surmonter ces limitations. Il vous libère des problèmes de gestion de la mémoire en traitant les ensembles de données comme des fichiers _mappés en mémoire_, et des limites du disque dur en _streaming_ les entrées dans un corpus. + + + +Dans cette section, nous allons explorer ces fonctionnalités de 🤗 Datasets avec un énorme corpus de 825 Go connu sous le nom de [the Pile](https://pile.eleuther.ai). Commençons! + +## Qu'est-ce que The Pile ? + +The Pile est un corpus de texte en anglais créé par [EleutherAI](https://www.eleuther.ai) pour entraîner des modèles de langage à grande échelle. Il comprend une gamme variée d'ensembles de données, couvrant des articles scientifiques, des référentiels de code GitHub et du texte Web filtré. Le corpus de formation est disponible en [morceaux de 14 Go](https://mystic.the-eye.eu/public/AI/pile/), et vous pouvez également télécharger plusieurs des [composants individuels](https://mystic .the-eye.eu/public/AI/pile_preliminary_components/). Commençons par jeter un coup d'œil à l'ensemble de données PubMed Abstracts, qui est un corpus de résumés de 15 millions de publications biomédicales sur [PubMed](https://pubmed.ncbi.nlm.nih.gov/). L'ensemble de données est au [format JSON Lines](https://jsonlines.org) et est compressé à l'aide de la bibliothèque `zstandard`, nous devons donc d'abord l'installer : + +```py +!pip install zstandard +``` + +Ensuite, nous pouvons charger le jeu de données en utilisant la méthode pour les fichiers distants que nous avons apprise dans [section 2](/course/chapter5/2) : + +```py +from datasets import load_dataset + +# Cela prend quelques minutes à exécuter, alors allez prendre un thé ou un café en attendant :) +data_files = "https://mystic.the-eye.eu/public/AI/pile_preliminary_components/PUBMED_title_abstracts_2019_baseline.jsonl.zst" +pubmed_dataset = load_dataset("json", data_files=data_files, split="train") +pubmed_dataset +``` + +```python out +Dataset({ + features: ['meta', 'text'], + num_rows: 15518009 +}) +``` + +Nous pouvons voir qu'il y a 15 518 009 lignes et 2 colonnes dans notre ensemble de données -- c'est beaucoup ! + + + +✎ Par défaut, 🤗 Datasets décompressera les fichiers nécessaires pour charger un jeu de données. Si vous souhaitez conserver de l'espace sur le disque dur, vous pouvez passer `DownloadConfig(delete_extracted=True)` à l'argument `download_config` de `load_dataset()`. Voir la [documentation](https://huggingface.co/docs/datasets/package_reference/builder_classes.html?#datasets.utils.DownloadConfig) pour plus de détails. + + + +Inspectons le contenu du premier exemple : + +```py +pubmed_dataset[0] +``` + +```python out +{'meta': {'pmid': 11409574, 'language': 'eng'}, + 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection.\nTo determine the prevalence of hypoxaemia in children aged under 5 years suffering acute lower respiratory infections (ALRI), the risk factors for hypoxaemia in children under 5 years of age with ALRI, and the association of hypoxaemia with an increased risk of dying in children of the same age ...'} +``` + +OK, ça ressemble au résumé d'un article médical. Voyons maintenant combien de RAM nous avons utilisé pour charger le jeu de données ! + +## La magie de la cartographie mémoire + +Un moyen simple de mesurer l'utilisation de la mémoire dans Python consiste à utiliser la bibliothèque [`psutil`](https://psutil.readthedocs.io/en/latest/), qui peut être installée avec `pip` comme suit : + +```python +!pip install psutil +``` + +Il fournit une classe `Process` qui nous permet de vérifier l'utilisation de la mémoire du processus en cours comme suit : + +```py +import psutil + +# Process.memory_info is expressed in bytes, so convert to megabytes +print(f"RAM used: {psutil.Process().memory_info().rss / (1024 * 1024):.2f} MB") +``` + +```python out +RAM used: 5678.33 MB +``` + +Ici, l'attribut `rss` fait référence à la _taille de l'ensemble résident_, qui est la fraction de mémoire qu'un processus occupe dans la RAM. Cette mesure inclut également la mémoire utilisée par l'interpréteur Python et les bibliothèques que nous avons chargées, de sorte que la quantité réelle de mémoire utilisée pour charger l'ensemble de données est un peu plus petite. À titre de comparaison, voyons la taille de l'ensemble de données sur le disque, en utilisant l'attribut `dataset_size`. Comme le résultat est exprimé en octets comme précédemment, nous devons le convertir manuellement en gigaoctets : + +```py +print(f"Number of files in dataset : {pubmed_dataset.dataset_size}") +size_gb = pubmed_dataset.dataset_size / (1024**3) +print(f"Dataset size (cache file) : {size_gb:.2f} GB") +``` + +```python out +Number of files in dataset : 20979437051 +Dataset size (cache file) : 19.54 GB +``` + +Bien - malgré sa taille de près de 20 Go, nous pouvons charger et accéder à l'ensemble de données avec beaucoup moins de RAM ! + + + +✏️ **Essayez-le !** Choisissez l'un des [sous-ensembles](https://mystic.the-eye.eu/public/AI/pile_preliminary_components/) de la Pile qui est plus grand que la RAM de votre ordinateur portable ou de bureau, chargez avec 🤗 Datasets, et mesurez la quantité de RAM utilisée. Notez que pour obtenir une mesure précise, vous devrez le faire dans un nouveau processus. Vous pouvez trouver les tailles décompressées de chaque sous-ensemble dans le tableau 1 de [the Pile paper](https://arxiv.org/abs/2101.00027). + + + +Si vous êtes familier avec les pandas, ce résultat pourrait surprendre en raison de la célèbre [règle d'or](https://wesmckinney.com/blog/apache-arrow-pandas-internals/) de Wes Kinney selon laquelle vous avez généralement besoin de 5 à 10 fois plus de RAM que la taille de votre jeu de données. Alors, comment 🤗 Datasets résout-il ce problème de gestion de la mémoire ? 🤗 Datasets traite chaque ensemble de données comme un [fichier mappé en mémoire] (https://en.wikipedia.org/wiki/Memory-mapped_file), qui fournit un mappage entre la RAM et le stockage du système de fichiers qui permet à la bibliothèque d'accéder et d'opérer sur des éléments du jeu de données sans avoir besoin de le charger entièrement en mémoire. + +Les fichiers mappés en mémoire peuvent également être partagés entre plusieurs processus, ce qui permet de paralléliser des méthodes telles que `Dataset.map()` sans avoir à déplacer ou copier l'ensemble de données. Sous le capot, ces capacités sont toutes réalisées par le format de mémoire [Apache Arrow](https://arrow.apache.org) et [`pyarrow`](https://arrow.apache.org/docs/python/index .html), qui accélèrent le chargement et le traitement des données. (Pour plus de détails sur Apache Arrow et les comparaisons avec Pandas, consultez [l'article de blog de Dejan Simic](https://towardsdatascience.com/apache-arrow-read-dataframe-with-zero-memory-69634092b1a).) Pour voir ceci en action, effectuons un petit test de vitesse en itérant sur tous les éléments du jeu de données PubMed Abstracts : + +```py +import timeit + +code_snippet = """batch_size = 1000 + +for idx in range(0, len(pubmed_dataset), batch_size): + _ = pubmed_dataset[idx:idx + batch_size] +""" + +time = timeit.timeit(stmt=code_snippet, number=1, globals=globals()) +print( + f"Iterated over {len(pubmed_dataset)} examples (about {size_gb:.1f} GB) in " + f"{time:.1f}s, i.e. {size_gb/time:.3f} GB/s" +) +``` + +```python out +'Iterated over 15518009 examples (about 19.5 GB) in 64.2s, i.e. 0.304 GB/s' +``` + +Ici, nous avons utilisé le module `timeit` de Python pour mesurer le temps d'exécution pris par `code_snippet`. Vous pourrez généralement itérer sur un ensemble de données à une vitesse de quelques dixièmes de Go/s à plusieurs Go/s. Cela fonctionne très bien pour la grande majorité des applications, mais vous devrez parfois travailler avec un ensemble de données trop volumineux pour être même stocké sur le disque dur de votre ordinateur portable. Par exemple, si nous essayions de télécharger la Pile dans son intégralité, nous aurions besoin de 825 Go d'espace disque libre ! Pour gérer ces cas, 🤗 Datasets fournit une fonctionnalité de streaming qui nous permet de télécharger et d'accéder aux éléments à la volée, sans avoir besoin de télécharger l'intégralité du jeu de données. Voyons comment cela fonctionne. + + + +💡 Dans les notebooks Jupyter, vous pouvez également chronométrer les cellules à l'aide de la fonction magique [`%%timeit`](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-timeit). + + + +## Ensembles de données en continu + +Pour activer le streaming de l'ensemble de données, il vous suffit de passer l'argument `streaming=True` à la fonction `load_dataset()`. Par exemple, chargeons à nouveau le jeu de données PubMed Abstracts, mais en mode streaming : + +```py +pubmed_dataset_streamed = load_dataset( + "json", data_files=data_files, split="train", streaming=True +) +``` + +Au lieu du familier `Dataset` que nous avons rencontré ailleurs dans ce chapitre, l'objet retourné avec `streaming=True` est un `IterableDataset`. Comme son nom l'indique, pour accéder aux éléments d'un `IterableDataset`, nous devons parcourir celui-ci. Nous pouvons accéder au premier élément de notre jeu de données diffusé comme suit : + + +```py +next(iter(pubmed_dataset_streamed)) +``` + +```python out +{'meta': {'pmid': 11409574, 'language': 'eng'}, + 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection.\nTo determine the prevalence of hypoxaemia in children aged under 5 years suffering acute lower respiratory infections (ALRI), the risk factors for hypoxaemia in children under 5 years of age with ALRI, and the association of hypoxaemia with an increased risk of dying in children of the same age ...'} +``` + +Les éléments d'un ensemble de données diffusé en continu peuvent être traités à la volée à l'aide de `IterableDataset.map()`, ce qui est utile pendant la formation si vous avez besoin de tokeniser les entrées. Le processus est exactement le même que celui que nous avons utilisé pour tokeniser notre jeu de données dans [Chapitre 3](/course/chapter3), à la seule différence que les sorties sont renvoyées une par une : + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased") +tokenized_dataset = pubmed_dataset_streamed.map(lambda x: tokenizer(x["text"])) +next(iter(tokenized_dataset)) +``` + +```python out +{'input_ids': [101, 4958, 5178, 4328, 6779, ...], 'attention_mask': [1, 1, 1, 1, 1, ...]} +``` + + + +💡 Pour accélérer la tokenisation avec le streaming, vous pouvez passer `batched=True`, comme nous l'avons vu dans la dernière section. Il traitera les exemples lot par lot ; la taille de lot par défaut est de 1 000 et peut être spécifiée avec l'argument `batch_size`. + + + +Vous pouvez également mélanger un ensemble de données diffusé en continu à l'aide de `IterableDataset.shuffle()`, mais contrairement à `Dataset.shuffle()`, cela ne mélange que les éléments dans un `buffer_size` prédéfini : + +```py +shuffled_dataset = pubmed_dataset_streamed.shuffle(buffer_size=10_000, seed=42) +next(iter(shuffled_dataset)) +``` + +```python out +{'meta': {'pmid': 11410799, 'language': 'eng'}, + 'text': 'Randomized study of dose or schedule modification of granulocyte colony-stimulating factor in platinum-based chemotherapy for elderly patients with lung cancer ...'} +``` + +Dans cet exemple, nous avons sélectionné un exemple aléatoire parmi les 10 000 premiers exemples du tampon. Une fois qu'un exemple est accédé, sa place dans le tampon est remplie avec l'exemple suivant dans le corpus (c'est-à-dire le 10 001e exemple dans le cas ci-dessus). Vous pouvez également sélectionner des éléments d'un ensemble de données diffusé en continu à l'aide des fonctions `IterableDataset.take()` et `IterableDataset.skip()`, qui agissent de la même manière que `Dataset.select()`. Par exemple, pour sélectionner les 5 premiers exemples dans l'ensemble de données PubMed Abstracts, nous pouvons procéder comme suit : + +```py +dataset_head = pubmed_dataset_streamed.take(5) +list(dataset_head) +``` + +```python out +[{'meta': {'pmid': 11409574, 'language': 'eng'}, + 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection ...'}, + {'meta': {'pmid': 11409575, 'language': 'eng'}, + 'text': 'Clinical signs of hypoxaemia in children with acute lower respiratory infection: indicators of oxygen therapy ...'}, + {'meta': {'pmid': 11409576, 'language': 'eng'}, + 'text': "Hypoxaemia in children with severe pneumonia in Papua New Guinea ..."}, + {'meta': {'pmid': 11409577, 'language': 'eng'}, + 'text': 'Oxygen concentrators and cylinders ...'}, + {'meta': {'pmid': 11409578, 'language': 'eng'}, + 'text': 'Oxygen supply in rural africa: a personal experience ...'}] +``` + +De même, vous pouvez utiliser la fonction `IterableDataset.skip()` pour créer des fractionnements d'entraînement et de validation à partir d'un ensemble de données mélangé comme suit : + +```py +# Skip the first 1,000 examples and include the rest in the training set +train_dataset = shuffled_dataset.skip(1000) +# Take the first 1,000 examples for the validation set +validation_dataset = shuffled_dataset.take(1000) +``` + +Terminons notre exploration du streaming d'ensembles de données avec une application commune : combiner plusieurs ensembles de données pour créer un seul corpus. 🤗 Datasets fournit une fonction `interleave_datasets()` qui convertit une liste d'objets `IterableDataset` en un seul `IterableDataset`, où les éléments du nouveau jeu de données sont obtenus en alternant entre les exemples source. Cette fonction est particulièrement utile lorsque vous essayez de combiner de grands ensembles de données. Par exemple, diffusons le sous-ensemble FreeLaw de la pile, qui est un ensemble de données de 51 Go d'avis juridiques de tribunaux américains : + +```py +law_dataset_streamed = load_dataset( + "json", + data_files="https://mystic.the-eye.eu/public/AI/pile_preliminary_components/FreeLaw_Opinions.jsonl.zst", + split="train", + streaming=True, +) +next(iter(law_dataset_streamed)) +``` + +```python out +{'meta': {'case_ID': '110921.json', + 'case_jurisdiction': 'scotus.tar.gz', + 'date_created': '2010-04-28T17:12:49Z'}, + 'text': '\n461 U.S. 238 (1983)\nOLIM ET AL.\nv.\nWAKINEKONA\nNo. 81-1581.\nSupreme Court of United States.\nArgued January 19, 1983.\nDecided April 26, 1983.\nCERTIORARI TO THE UNITED STATES COURT OF APPEALS FOR THE NINTH CIRCUIT\n*239 Michael A. Lilly, First Deputy Attorney General of Hawaii, argued the cause for petitioners. With him on the brief was James H. Dannenberg, Deputy Attorney General...'} +``` + +Cet ensemble de données est suffisamment volumineux pour solliciter la RAM de la plupart des ordinateurs portables, mais nous avons pu le charger et y accéder sans transpirer ! Combinons maintenant les exemples des jeux de données FreeLaw et PubMed Abstracts avec la fonction `interleave_datasets()` : + +```py +from itertools import islice +from datasets import interleave_datasets + +combined_dataset = interleave_datasets([pubmed_dataset_streamed, law_dataset_streamed]) +list(islice(combined_dataset, 2)) +``` + +```python out +[{'meta': {'pmid': 11409574, 'language': 'eng'}, + 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection ...'}, + {'meta': {'case_ID': '110921.json', + 'case_jurisdiction': 'scotus.tar.gz', + 'date_created': '2010-04-28T17:12:49Z'}, + 'text': '\n461 U.S. 238 (1983)\nOLIM ET AL.\nv.\nWAKINEKONA\nNo. 81-1581.\nSupreme Court of United States.\nArgued January 19, 1983.\nDecided April 26, 1983.\nCERTIORARI TO THE UNITED STATES COURT OF APPEALS FOR THE NINTH CIRCUIT\n*239 Michael A. Lilly, First Deputy Attorney General of Hawaii, argued the cause for petitioners. With him on the brief was James H. Dannenberg, Deputy Attorney General...'}] +``` + +Ici, nous avons utilisé la fonction `islice()` du module `itertools` de Python pour sélectionner les deux premiers exemples de l'ensemble de données combiné, et nous pouvons voir qu'ils correspondent aux premiers exemples de chacun des deux ensembles de données source. + +Enfin, si vous souhaitez diffuser le Pile dans son intégralité de 825 Go, vous pouvez récupérer tous les fichiers préparés comme suit : + +```py +base_url = "https://mystic.the-eye.eu/public/AI/pile/" +data_files = { + "train": [base_url + "train/" + f"{idx:02d}.jsonl.zst" for idx in range(30)], + "validation": base_url + "val.jsonl.zst", + "test": base_url + "test.jsonl.zst", +} +pile_dataset = load_dataset("json", data_files=data_files, streaming=True) +next(iter(pile_dataset["train"])) +``` + +```python out +{'meta': {'pile_set_name': 'Pile-CC'}, + 'text': 'It is done, and submitted. You can play “Survival of the Tastiest” on Android, and on the web...'} +``` + + + +✏️ **Essayez-le !** Utilisez l'un des grands corpus Common Crawl comme [`mc4`](https://huggingface.co/datasets/mc4) ou [`oscar`](https://huggingface.co /datasets/oscar) pour créer un jeu de données multilingue en continu qui représente les proportions de langues parlées dans un pays de votre choix. Par exemple, les quatre langues nationales en Suisse sont l'allemand, le français, l'italien et le romanche, vous pouvez donc essayer de créer un corpus suisse en échantillonnant les sous-ensembles Oscar en fonction de leur proportion parlée. + + + +Vous disposez maintenant de tous les outils dont vous avez besoin pour charger et traiter des ensembles de données de toutes formes et tailles - mais à moins que vous ne soyez exceptionnellement chanceux, il arrivera un moment dans votre parcours PNL où vous devrez réellement créer un ensemble de données pour résoudre le problème à portée de main. C'est le sujet de la section suivante ! diff --git a/chapters/fr/chapter5/5.mdx b/chapters/fr/chapter5/5.mdx new file mode 100644 index 000000000..298f69200 --- /dev/null +++ b/chapters/fr/chapter5/5.mdx @@ -0,0 +1,469 @@ +# Création de votre propre jeu de données + + + +Parfois, l'ensemble de données dont vous avez besoin pour créer une application NLP n'existe pas, vous devrez donc le créer vous-même. Dans cette section, nous allons vous montrer comment créer un corpus de [problèmes GitHub](https://github.com/features/issues/), qui sont couramment utilisés pour suivre les bogues ou les fonctionnalités dans les référentiels GitHub. Ce corpus pourrait être utilisé à diverses fins, notamment : + +* Explorer combien de temps il faut pour fermer les problèmes ouverts ou les demandes d'extraction +* Entraînement d'un _classificateur multilabel_ capable d'étiqueter les problèmes avec des métadonnées basées sur la description du problème (par exemple, "bogue", "amélioration" ou "question") +* Création d'un moteur de recherche sémantique pour trouver les problèmes correspondant à la requête d'un utilisateur + +Ici, nous nous concentrerons sur la création du corpus, et dans la section suivante, nous aborderons l'application de recherche sémantique. Pour garder les choses méta, nous utiliserons les problèmes GitHub associés à un projet open source populaire : 🤗 Datasets ! Voyons comment obtenir les données et explorons les informations contenues dans ces problèmes. + +## Obtenir les données + +Vous pouvez trouver tous les problèmes dans 🤗 Datasets en accédant à l'[onglet Problèmes] du référentiel (https://github.com/huggingface/datasets/issues). Comme le montre la capture d'écran suivante, au moment de la rédaction, il y avait 331 problèmes ouverts et 668 problèmes fermés. + +
+Les problèmes GitHub associés aux 🤗 Datasets. +
+ +Si vous cliquez sur l'un de ces problèmes, vous constaterez qu'il contient un titre, une description et un ensemble d'étiquettes qui caractérisent le problème. Un exemple est montré dans la capture d'écran ci-dessous. + +
+Un problème GitHub typique dans le référentiel 🤗 Datasets. +
+ +Pour télécharger tous les problèmes du référentiel, nous utiliserons l'[API REST GitHub](https://docs.github.com/en/rest) pour interroger le point de terminaison [`Issues`](https://docs.github. com/en/rest/reference/issues#list-repository-issues). Ce point de terminaison renvoie une liste d'objets JSON, chaque objet contenant un grand nombre de champs qui incluent le titre et la description ainsi que des métadonnées sur l'état du problème, etc. + +Un moyen pratique de télécharger les problèmes consiste à utiliser la bibliothèque "requests", qui est la méthode standard pour effectuer des requêtes HTTP en Python. Vous pouvez installer la bibliothèque en exécutant : + +```python +!pip install requests +``` + +Une fois la bibliothèque installée, vous pouvez envoyer des requêtes GET au point de terminaison `Issues` en appelant la fonction `requests.get()`. Par exemple, vous pouvez exécuter la commande suivante pour récupérer le premier numéro sur la première page : + +```py +import requests + +url = "https://api.github.com/repos/huggingface/datasets/issues?page=1&per_page=1" +response = requests.get(url) +``` + +L'objet `response` contient de nombreuses informations utiles sur la requête, y compris le code d'état HTTP : + +```py +response.status_code +``` + +```python out +200 +``` + +où un statut "200" signifie que la requête a réussi (vous pouvez trouver une liste des codes de statut HTTP possibles [ici](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes)). Ce qui nous intéresse vraiment, cependant, c'est le _payload_, qui peut être consulté dans différents formats comme les octets, les chaînes ou JSON. Comme nous savons que nos problèmes sont au format JSON, examinons la charge utile comme suit : + +```py +response.json() +``` + +```python out +[{'url': 'https://api.github.com/repos/huggingface/datasets/issues/2792', + 'repository_url': 'https://api.github.com/repos/huggingface/datasets', + 'labels_url': 'https://api.github.com/repos/huggingface/datasets/issues/2792/labels{/name}', + 'comments_url': 'https://api.github.com/repos/huggingface/datasets/issues/2792/comments', + 'events_url': 'https://api.github.com/repos/huggingface/datasets/issues/2792/events', + 'html_url': 'https://github.com/huggingface/datasets/pull/2792', + 'id': 968650274, + 'node_id': 'MDExOlB1bGxSZXF1ZXN0NzEwNzUyMjc0', + 'number': 2792, + 'title': 'Update GooAQ', + 'user': {'login': 'bhavitvyamalik', + 'id': 19718818, + 'node_id': 'MDQ6VXNlcjE5NzE4ODE4', + 'avatar_url': 'https://avatars.githubusercontent.com/u/19718818?v=4', + 'gravatar_id': '', + 'url': 'https://api.github.com/users/bhavitvyamalik', + 'html_url': 'https://github.com/bhavitvyamalik', + 'followers_url': 'https://api.github.com/users/bhavitvyamalik/followers', + 'following_url': 'https://api.github.com/users/bhavitvyamalik/following{/other_user}', + 'gists_url': 'https://api.github.com/users/bhavitvyamalik/gists{/gist_id}', + 'starred_url': 'https://api.github.com/users/bhavitvyamalik/starred{/owner}{/repo}', + 'subscriptions_url': 'https://api.github.com/users/bhavitvyamalik/subscriptions', + 'organizations_url': 'https://api.github.com/users/bhavitvyamalik/orgs', + 'repos_url': 'https://api.github.com/users/bhavitvyamalik/repos', + 'events_url': 'https://api.github.com/users/bhavitvyamalik/events{/privacy}', + 'received_events_url': 'https://api.github.com/users/bhavitvyamalik/received_events', + 'type': 'User', + 'site_admin': False}, + 'labels': [], + 'state': 'open', + 'locked': False, + 'assignee': None, + 'assignees': [], + 'milestone': None, + 'comments': 1, + 'created_at': '2021-08-12T11:40:18Z', + 'updated_at': '2021-08-12T12:31:17Z', + 'closed_at': None, + 'author_association': 'CONTRIBUTOR', + 'active_lock_reason': None, + 'pull_request': {'url': 'https://api.github.com/repos/huggingface/datasets/pulls/2792', + 'html_url': 'https://github.com/huggingface/datasets/pull/2792', + 'diff_url': 'https://github.com/huggingface/datasets/pull/2792.diff', + 'patch_url': 'https://github.com/huggingface/datasets/pull/2792.patch'}, + 'body': '[GooAQ](https://github.com/allenai/gooaq) dataset was recently updated after splits were added for the same. This PR contains new updated GooAQ with train/val/test splits and updated README as well.', + 'performed_via_github_app': None}] +``` + +Waouh, ça fait beaucoup d'informations ! Nous pouvons voir des champs utiles comme `title`, `body` et `number` qui décrivent le problème, ainsi que des informations sur l'utilisateur GitHub qui a ouvert le problème. + + + +✏️ **Essayez-le !** Cliquez sur quelques-unes des URL dans la charge utile JSON ci-dessus pour avoir une idée du type d'informations auxquelles chaque problème GitHub est lié. + + + +Comme décrit dans la [documentation] GitHub(https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting), les requêtes non authentifiées sont limitées à 60 requêtes par heure. Bien que vous puissiez augmenter le paramètre de requête `per_page` pour réduire le nombre de requêtes que vous effectuez, vous atteindrez toujours la limite de débit sur tout référentiel contenant plus de quelques milliers de problèmes. Donc, à la place, vous devez suivre les [instructions] de GitHub (https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) sur la création d'un _jeton d'accès personnel_ afin que vous peut augmenter la limite de débit à 5 000 requêtes par heure. Une fois que vous avez votre jeton, vous pouvez l'inclure dans l'en-tête de la requête : + +```py +GITHUB_TOKEN = xxx # Copy your GitHub token here +headers = {"Authorization": f"token {GITHUB_TOKEN}"} +``` + + + +⚠️ Ne partagez pas un notebook avec votre `GITHUB_TOKEN` collé dedans. Nous vous recommandons de supprimer la dernière cellule une fois que vous l'avez exécutée pour éviter de divulguer accidentellement ces informations. Mieux encore, stockez le jeton dans un fichier *.env* et utilisez la [bibliothèque `python-dotenv`](https://github.com/theskumar/python-dotenv) pour le charger automatiquement pour vous en tant que variable d'environnement. + + + +Maintenant que nous avons notre jeton d'accès, créons une fonction qui peut télécharger tous les problèmes depuis un référentiel GitHub : + +```py +import time +import math +from pathlib import Path +import pandas as pd +from tqdm.notebook import tqdm + + +def fetch_issues( + owner="huggingface", + repo="datasets", + num_issues=10_000, + rate_limit=5_000, + issues_path=Path("."), +): + if not issues_path.is_dir(): + issues_path.mkdir(exist_ok=True) + + batch = [] + all_issues = [] + per_page = 100 # Number of issues to return per page + num_pages = math.ceil(num_issues / per_page) + base_url = "https://api.github.com/repos" + + for page in tqdm(range(num_pages)): + # Query with state=all to get both open and closed issues + query = f"issues?page={page}&per_page={per_page}&state=all" + issues = requests.get(f"{base_url}/{owner}/{repo}/{query}", headers=headers) + batch.extend(issues.json()) + + if len(batch) > rate_limit and len(all_issues) < num_issues: + all_issues.extend(batch) + batch = [] # Flush batch for next time period + print(f"Reached GitHub rate limit. Sleeping for one hour ...") + time.sleep(60 * 60 + 1) + + all_issues.extend(batch) + df = pd.DataFrame.from_records(all_issues) + df.to_json(f"{issues_path}/{repo}-issues.jsonl", orient="records", lines=True) + print( + f"Downloaded all the issues for {repo}! Dataset stored at {issues_path}/{repo}-issues.jsonl" + ) +``` + +Désormais, lorsque nous appellerons `fetch_issues()`, tous les problèmes seront téléchargés par lots pour éviter de dépasser la limite de GitHub sur le nombre de requêtes par heure ; le résultat sera stocké dans un fichier _repository_name-issues.jsonl_, où chaque ligne est un objet JSON qui représente un problème. Utilisons cette fonction pour saisir tous les problèmes de 🤗 Datasets : + +```py +# Depending on your internet connection, this can take several minutes to run... +fetch_issues() +``` + +Une fois les problèmes téléchargés, nous pouvons les charger localement en utilisant nos nouvelles compétences de [section 2](/course/chaper5/2) : + +```py +issues_dataset = load_dataset("json", data_files="datasets-issues.jsonl", split="train") +issues_dataset +``` + +```python out +Dataset({ + features: ['url', 'repository_url', 'labels_url', 'comments_url', 'events_url', 'html_url', 'id', 'node_id', 'number', 'title', 'user', 'labels', 'state', 'locked', 'assignee', 'assignees', 'milestone', 'comments', 'created_at', 'updated_at', 'closed_at', 'author_association', 'active_lock_reason', 'pull_request', 'body', 'timeline_url', 'performed_via_github_app'], + num_rows: 3019 +}) +``` + +Génial, nous avons créé notre premier ensemble de données à partir de rien ! Mais pourquoi y a-t-il plusieurs milliers de problèmes alors que l'[onglet Problèmes](https://github.com/huggingface/datasets/issues) du 🤗 Datasets n'affiche qu'environ 1 000 problèmes au total 🤔 ? Comme décrit dans la [documentation] GitHub(https://docs.github.com/en/rest/reference/issues#list-issues-assigned-to-the-authenticated-user), c'est parce que nous avons téléchargé tous les les demandes d'extraction également : + +> L'API REST v3 de GitHub considère chaque demande d'extraction comme un problème, mais chaque problème n'est pas une demande d'extraction. Pour cette raison, les points de terminaison "Problèmes" peuvent renvoyer à la fois des problèmes et des demandes d'extraction dans la réponse. Vous pouvez identifier les demandes d'extraction par la clé `pull_request`. Sachez que l'identifiant d'une demande d'extraction renvoyée par les points de terminaison "Problèmes" sera un identifiant de problème. + +Étant donné que le contenu des problèmes et des demandes d'extraction est assez différent, procédons à un prétraitement mineur pour nous permettre de les distinguer. + +## Nettoyer les données + +L'extrait ci-dessus de la documentation de GitHub nous indique que la colonne "pull_request" peut être utilisée pour différencier les problèmes et les demandes d'extraction. Regardons un échantillon aléatoire pour voir quelle est la différence. Comme nous l'avons fait dans [section 3](/course/chapter5/3), nous allons enchaîner `Dataset.shuffle()` et `Dataset.select()` pour créer un échantillon aléatoire, puis compresser `html_url` et ` pull_request` afin que nous puissions comparer les différentes URL : + +```py +sample = issues_dataset.shuffle(seed=666).select(range(3)) + +# Print out the URL and pull request entries +for url, pr in zip(sample["html_url"], sample["pull_request"]): + print(f">> URL: {url}") + print(f">> Pull request: {pr}\n") +``` + +```python out +>> URL: https://github.com/huggingface/datasets/pull/850 +>> Pull request: {'url': 'https://api.github.com/repos/huggingface/datasets/pulls/850', 'html_url': 'https://github.com/huggingface/datasets/pull/850', 'diff_url': 'https://github.com/huggingface/datasets/pull/850.diff', 'patch_url': 'https://github.com/huggingface/datasets/pull/850.patch'} + +>> URL: https://github.com/huggingface/datasets/issues/2773 +>> Pull request: None + +>> URL: https://github.com/huggingface/datasets/pull/783 +>> Pull request: {'url': 'https://api.github.com/repos/huggingface/datasets/pulls/783', 'html_url': 'https://github.com/huggingface/datasets/pull/783', 'diff_url': 'https://github.com/huggingface/datasets/pull/783.diff', 'patch_url': 'https://github.com/huggingface/datasets/pull/783.patch'} +``` + +Ici, nous pouvons voir que chaque demande d'extraction est associée à diverses URL, tandis que les problèmes ordinaires ont une entrée "Aucun". Nous pouvons utiliser cette distinction pour créer une nouvelle colonne `is_pull_request` qui vérifie si le champ `pull_request` est `None` ou non : + +```py +issues_dataset = issues_dataset.map( + lambda x: {"is_pull_request": False if x["pull_request"] is None else True} +) +``` + + + +✏️ **Essayez-le !** Calculez le temps moyen nécessaire pour résoudre les problèmes dans 🤗 Datasets. Vous pouvez trouver la fonction `Dataset.filter()` utile pour filtrer les demandes d'extraction et les problèmes ouverts, et vous pouvez utiliser la fonction `Dataset.set_format()` pour convertir l'ensemble de données en un `DataFrame` afin que vous puissiez facilement manipuler les horodatages `created_at` et `closed_at`. Pour les points bonus, calculez le temps moyen nécessaire pour fermer les demandes d'extraction. + + + +Bien que nous puissions continuer à nettoyer davantage l'ensemble de données en supprimant ou en renommant certaines colonnes, il est généralement recommandé de conserver l'ensemble de données aussi "brut" que possible à ce stade afin qu'il puisse être facilement utilisé dans plusieurs applications. + +Avant de pousser notre ensemble de données vers le Hugging Face Hub, traitons d'une chose qui lui manque : les commentaires associés à chaque problème et pull request. Nous les ajouterons ensuite avec - vous l'avez deviné - l'API GitHub REST ! + +## Enrichir le jeu de données + +Comme le montre la capture d'écran suivante, les commentaires associés à un problème ou à une demande d'extraction fournissent une riche source d'informations, en particulier si nous souhaitons créer un moteur de recherche pour répondre aux requêtes des utilisateurs sur la bibliothèque. + +
+Commentaires associés à un problème concernant 🤗 Datasets. +
+ +L'API REST GitHub fournit un point de terminaison [`Comments`](https://docs.github.com/en/rest/reference/issues#list-issue-comments) qui renvoie tous les commentaires associés à un numéro de problème. Testons le point de terminaison pour voir ce qu'il renvoie : + +```py +issue_number = 2792 +url = f"https://api.github.com/repos/huggingface/datasets/issues/{issue_number}/comments" +response = requests.get(url, headers=headers) +response.json() +``` + +```python out +[{'url': 'https://api.github.com/repos/huggingface/datasets/issues/comments/897594128', + 'html_url': 'https://github.com/huggingface/datasets/pull/2792#issuecomment-897594128', + 'issue_url': 'https://api.github.com/repos/huggingface/datasets/issues/2792', + 'id': 897594128, + 'node_id': 'IC_kwDODunzps41gDMQ', + 'user': {'login': 'bhavitvyamalik', + 'id': 19718818, + 'node_id': 'MDQ6VXNlcjE5NzE4ODE4', + 'avatar_url': 'https://avatars.githubusercontent.com/u/19718818?v=4', + 'gravatar_id': '', + 'url': 'https://api.github.com/users/bhavitvyamalik', + 'html_url': 'https://github.com/bhavitvyamalik', + 'followers_url': 'https://api.github.com/users/bhavitvyamalik/followers', + 'following_url': 'https://api.github.com/users/bhavitvyamalik/following{/other_user}', + 'gists_url': 'https://api.github.com/users/bhavitvyamalik/gists{/gist_id}', + 'starred_url': 'https://api.github.com/users/bhavitvyamalik/starred{/owner}{/repo}', + 'subscriptions_url': 'https://api.github.com/users/bhavitvyamalik/subscriptions', + 'organizations_url': 'https://api.github.com/users/bhavitvyamalik/orgs', + 'repos_url': 'https://api.github.com/users/bhavitvyamalik/repos', + 'events_url': 'https://api.github.com/users/bhavitvyamalik/events{/privacy}', + 'received_events_url': 'https://api.github.com/users/bhavitvyamalik/received_events', + 'type': 'User', + 'site_admin': False}, + 'created_at': '2021-08-12T12:21:52Z', + 'updated_at': '2021-08-12T12:31:17Z', + 'author_association': 'CONTRIBUTOR', + 'body': "@albertvillanova my tests are failing here:\r\n```\r\ndataset_name = 'gooaq'\r\n\r\n def test_load_dataset(self, dataset_name):\r\n configs = self.dataset_tester.load_all_configs(dataset_name, is_local=True)[:1]\r\n> self.dataset_tester.check_load_dataset(dataset_name, configs, is_local=True, use_local_dummy_data=True)\r\n\r\ntests/test_dataset_common.py:234: \r\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \r\ntests/test_dataset_common.py:187: in check_load_dataset\r\n self.parent.assertTrue(len(dataset[split]) > 0)\r\nE AssertionError: False is not true\r\n```\r\nWhen I try loading dataset on local machine it works fine. Any suggestions on how can I avoid this error?", + 'performed_via_github_app': None}] +``` + +Nous pouvons voir que le commentaire est stocké dans le champ `body`, écrivons donc une fonction simple qui renvoie tous les commentaires associés à un problème en sélectionnant le contenu `body` pour chaque élément dans `response.json()` : + +```py +def get_comments(issue_number): + url = f"https://api.github.com/repos/huggingface/datasets/issues/{issue_number}/comments" + response = requests.get(url, headers=headers) + return [r["body"] for r in response.json()] + + +# Testez notre fonction fonctionne comme prévu +get_comments(2792) +``` + +```python out +["@albertvillanova my tests are failing here:\r\n```\r\ndataset_name = 'gooaq'\r\n\r\n def test_load_dataset(self, dataset_name):\r\n configs = self.dataset_tester.load_all_configs(dataset_name, is_local=True)[:1]\r\n> self.dataset_tester.check_load_dataset(dataset_name, configs, is_local=True, use_local_dummy_data=True)\r\n\r\ntests/test_dataset_common.py:234: \r\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \r\ntests/test_dataset_common.py:187: in check_load_dataset\r\n self.parent.assertTrue(len(dataset[split]) > 0)\r\nE AssertionError: False is not true\r\n```\r\nWhen I try loading dataset on local machine it works fine. Any suggestions on how can I avoid this error?"] +``` + +Cela a l'air bien, alors utilisons `Dataset.map()` pour ajouter une nouvelle colonne `commentaires` à chaque problème de notre ensemble de données : + +```py +# Selon votre connexion internet, cela peut prendre quelques minutes... +issues_with_comments_dataset = issues_dataset.map( + lambda x: {"comments": get_comments(x["number"])} +) +``` + +La dernière étape consiste à enregistrer l'ensemble de données augmentées avec nos données brutes afin que nous puissions les pousser toutes les deux vers le Hub : + +```py +issues_with_comments_dataset.to_json("issues-datasets-with-comments.jsonl") +``` + +## Téléchargement de l'ensemble de données sur le Hugging Face Hub + + + +Maintenant que nous avons notre jeu de données augmenté, il est temps de le pousser vers le Hub afin que nous puissions le partager avec la communauté ! Pour télécharger l'ensemble de données, nous utiliserons la [bibliothèque Hub 🤗](https://github.com/huggingface/huggingface_hub), qui nous permet d'interagir avec le hub Hugging Face via une API Python. 🤗 Hub est préinstallé avec 🤗 Transformers, nous pouvons donc l'utiliser directement. Par exemple, nous pouvons utiliser la fonction `list_datasets()` pour obtenir des informations sur tous les ensembles de données publics actuellement hébergés sur le Hub : + +```py +from huggingface_hub import list_datasets + +all_datasets = list_datasets() +print(f"Number of datasets on Hub: {len(all_datasets)}") +print(all_datasets[0]) +``` + +```python out +Number of datasets on Hub: 1487 +Dataset Name: acronym_identification, Tags: ['annotations_creators:expert-generated', 'language_creators:found', 'languages:en', 'licenses:mit', 'multilinguality:monolingual', 'size_categories:10K + +✏️ **Essayez-le !** Utilisez votre nom d'utilisateur et votre mot de passe Hugging Face Hub pour obtenir un jeton et créer un référentiel vide appelé "github-issues". N'oubliez pas de **n'enregistrez jamais vos informations d'identification** dans Colab ou tout autre référentiel, car ces informations peuvent être exploitées par de mauvais acteurs. + +
+ +Ensuite, clonons le référentiel du Hub sur notre machine locale et copions-y notre fichier d'ensemble de données. 🤗 Hub fournit une classe `Repository` pratique qui encapsule de nombreuses commandes Git courantes, donc pour cloner le référentiel distant, nous devons simplement fournir l'URL et le chemin local vers lesquels nous souhaitons cloner : + +```py +from huggingface_hub import Repository + +repo = Repository(local_dir="github-issues", clone_from=repo_url) +!cp datasets-issues-with-comments.jsonl github-issues/ +``` + +Par défaut, diverses extensions de fichiers (telles que *.bin*, *.gz* et *.zip*) sont suivies avec Git LFS afin que les fichiers volumineux puissent être versionnés dans le même workflow Git. Vous pouvez trouver une liste des extensions de fichiers suivis dans le fichier *.gitattributes* du référentiel. Pour inclure le format JSON Lines dans la liste, nous pouvons exécuter la commande suivante : + +```py +repo.lfs_track("*.jsonl") +``` + +Ensuite, nous pouvons utiliser `Repository.push_to_hub()` pour pousser l'ensemble de données vers le Hub : + +```py +repo.push_to_hub() +``` + +Si nous naviguons vers l'URL contenue dans `repo_url`, nous devrions maintenant voir que notre fichier de jeu de données a été téléchargé. + +
+Notre référentiel d'ensembles de données sur le Hugging Face Hub. +
+ +À partir de là, n'importe qui peut télécharger l'ensemble de données en fournissant simplement `load_dataset()` avec l'ID du référentiel comme argument `path` : + +```py +remote_dataset = load_dataset("lewtun/github-issues", split="train") +remote_dataset +``` + +```python out +Dataset({ + features: ['url', 'repository_url', 'labels_url', 'comments_url', 'events_url', 'html_url', 'id', 'node_id', 'number', 'title', 'user', 'labels', 'state', 'locked', 'assignee', 'assignees', 'milestone', 'comments', 'created_at', 'updated_at', 'closed_at', 'author_association', 'active_lock_reason', 'pull_request', 'body', 'performed_via_github_app', 'is_pull_request'], + num_rows: 2855 +}) +``` + +Cool, nous avons poussé notre jeu de données vers le Hub et il est disponible pour que d'autres puissent l'utiliser ! Il ne reste plus qu'une chose importante à faire : ajouter une _carte de jeu de données_ qui explique comment le corpus a été créé et fournit d'autres informations utiles à la communauté. + + + +💡 Vous pouvez également télécharger un ensemble de données sur le Hugging Face Hub directement depuis le terminal en utilisant `huggingface-cli` et un peu de magie Git. Consultez le [🤗 Datasets guide](https://huggingface.co/docs/datasets/share.html#add-a-community-dataset) pour savoir comment procéder. + + + +## Création d'une fiche de jeu de données + +Des ensembles de données bien documentés sont plus susceptibles d'être utiles aux autres (y compris à votre futur moi !), car ils fournissent le contexte permettant aux utilisateurs de décider si l'ensemble de données est pertinent pour leur tâche et d'évaluer les biais potentiels ou les risques associés à l'utilisation l'ensemble de données. + +Sur le Hugging Face Hub, ces informations sont stockées dans le fichier *README.md* de chaque référentiel d'ensembles de données. Il y a deux étapes principales que vous devez suivre avant de créer ce fichier : + +1. Utilisez l'[application `datasets-tagging`](https://huggingface.co/datasets/tagging/) pour créer des balises de métadonnées au format YAML. Ces balises sont utilisées pour une variété de fonctionnalités de recherche sur le Hugging Face Hub et garantissent que votre ensemble de données peut être facilement trouvé par les membres de la communauté. Puisque nous avons créé un ensemble de données personnalisé ici, vous devrez cloner le référentiel `datasets-tagging` et exécuter l'application localement. Voici à quoi ressemble l'interface : + +
+L'interface `datasets-tagging`. +
+ +2. Lisez le [🤗 Datasets guide](https://github.com/huggingface/datasets/blob/master/templates/README_guide.md) sur la création de cartes d'ensemble de données informatives et utilisez-le comme modèle. + +Vous pouvez créer le fichier *README.md* directement sur le Hub, et vous pouvez trouver un modèle de carte d'ensemble de données dans le référentiel d'ensemble de données `lewtun/github-issues`. Une capture d'écran de la carte de jeu de données remplie est illustrée ci-dessous. + +
+Une carte de jeu de données. +
+ + + +* Fichier README.md* pour votre ensemble de données de problèmes GitHub. + + + +C'est ça! Nous avons vu dans cette section que la création d'un bon ensemble de données peut être assez complexe, mais heureusement, le télécharger et le partager avec la communauté ne l'est pas. Dans la section suivante, nous utiliserons notre nouvel ensemble de données pour créer un moteur de recherche sémantique avec 🤗 Deatasets qui peut faire correspondre les questions aux problèmes et commentaires les plus pertinents. + + + +✏️ **Essayez-le !** Suivez les étapes que nous avons suivies dans cette section pour créer un ensemble de données de problèmes GitHub pour votre bibliothèque open source préférée (choisissez autre chose que 🤗 Datasets, bien sûr !). Pour obtenir des points bonus, ajustez un classificateur multilabel pour prédire les balises présentes dans le champ "labels". + + + + diff --git a/chapters/fr/chapter5/6.mdx b/chapters/fr/chapter5/6.mdx new file mode 100644 index 000000000..fb055ccb8 --- /dev/null +++ b/chapters/fr/chapter5/6.mdx @@ -0,0 +1,530 @@ + + +# Recherche sémantique avec FAISS + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +Dans [section 5](/course/chapter5/5), nous avons créé un ensemble de données de problèmes et de commentaires GitHub à partir du référentiel 🤗 Datasets. Dans cette section, nous utiliserons ces informations pour créer un moteur de recherche qui peut nous aider à trouver des réponses à nos questions les plus urgentes sur la bibliothèque ! + + + +## Utilisation des représentations vectorielles continues pour la recherche sémantique + +Comme nous l'avons vu dans le [Chapitre 1](/course/chapter1), les modèles de langage basés sur Transformer représentent chaque jeton dans une étendue de texte sous la forme d'un _vecteur d'intégration_. Il s'avère que l'on peut "regrouper" les incorporations individuelles pour créer une représentation vectorielle pour des phrases entières, des paragraphes ou (dans certains cas) des documents. Ces intégrations peuvent ensuite être utilisées pour trouver des documents similaires dans le corpus en calculant la similarité du produit scalaire (ou une autre métrique de similarité) entre chaque intégration et en renvoyant les documents avec le plus grand chevauchement. + +Dans cette section, nous utiliserons les incorporations pour développer un moteur de recherche sémantique. Ces moteurs de recherche offrent plusieurs avantages par rapport aux approches conventionnelles basées sur la correspondance des mots-clés dans une requête avec les documents. + +
+Recherche sémantique. + +
+ +## Chargement et préparation du jeu de données + +La première chose que nous devons faire est de télécharger notre ensemble de données de problèmes GitHub, alors utilisons la bibliothèque 🤗 Hub pour résoudre l'URL où notre fichier est stocké sur le Hugging Face Hub : + +```py +from huggingface_hub import hf_hub_url + +data_files = hf_hub_url( + repo_id="lewtun/github-issues", + filename="datasets-issues-with-comments.jsonl", + repo_type="dataset", +) +``` + +Avec l'URL stockée dans `data_files`, nous pouvons ensuite charger le jeu de données distant en utilisant la méthode introduite dans [section 2](/course/chapter5/2) : + +```py +from datasets import load_dataset + +issues_dataset = load_dataset("json", data_files=data_files, split="train") +issues_dataset +``` + +```python out +Dataset({ + features: ['url', 'repository_url', 'labels_url', 'comments_url', 'events_url', 'html_url', 'id', 'node_id', 'number', 'title', 'user', 'labels', 'state', 'locked', 'assignee', 'assignees', 'milestone', 'comments', 'created_at', 'updated_at', 'closed_at', 'author_association', 'active_lock_reason', 'pull_request', 'body', 'performed_via_github_app', 'is_pull_request'], + num_rows: 2855 +}) +``` + +Ici, nous avons spécifié la division `train` par défaut dans `load_dataset()`, de sorte qu'elle renvoie un `Dataset` au lieu d'un `DatasetDict`. La première chose à faire est de filtrer les demandes d'extraction, car celles-ci ont tendance à être rarement utilisées pour répondre aux requêtes des utilisateurs et introduiront du bruit dans notre moteur de recherche. Comme cela devrait être familier maintenant, nous pouvons utiliser la fonction `Dataset.filter()` pour exclure ces lignes de notre ensemble de données. Pendant que nous y sommes, filtrons également les lignes sans commentaires, car celles-ci ne fournissent aucune réponse aux requêtes des utilisateurs : + +```py +issues_dataset = issues_dataset.filter( + lambda x: (x["is_pull_request"] == False and len(x["comments"]) > 0) +) +issues_dataset +``` + +```python out +Dataset({ + features: ['url', 'repository_url', 'labels_url', 'comments_url', 'events_url', 'html_url', 'id', 'node_id', 'number', 'title', 'user', 'labels', 'state', 'locked', 'assignee', 'assignees', 'milestone', 'comments', 'created_at', 'updated_at', 'closed_at', 'author_association', 'active_lock_reason', 'pull_request', 'body', 'performed_via_github_app', 'is_pull_request'], + num_rows: 771 +}) +``` + +Nous pouvons voir qu'il y a beaucoup de colonnes dans notre ensemble de données, dont la plupart n'ont pas besoin de construire notre moteur de recherche. Du point de vue de la recherche, les colonnes les plus informatives sont `title`, `body` et `comments`, tandis que `html_url` nous fournit un lien vers le problème source. Utilisons la fonction `Dataset.remove_columns()` pour supprimer le reste : + +```py +columns = issues_dataset.column_names +columns_to_keep = ["title", "body", "html_url", "comments"] +columns_to_remove = set(columns_to_keep).symmetric_difference(columns) +issues_dataset = issues_dataset.remove_columns(columns_to_remove) +issues_dataset +``` + +```python out +Dataset({ + features: ['html_url', 'title', 'comments', 'body'], + num_rows: 771 +}) +``` + +Pour créer nos intégrations, nous ajouterons à chaque commentaire le titre et le corps du problème, car ces champs contiennent souvent des informations contextuelles utiles. Étant donné que notre colonne `comments` est actuellement une liste de commentaires pour chaque problème, nous devons "éclater" la colonne afin que chaque ligne se compose d'un tuple `(html_url, title, body, comment)`. Dans Pandas, nous pouvons le faire avec la fonction [`DataFrame.explode()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.explode.html), qui crée une nouvelle ligne pour chaque élément dans une colonne de type liste, tout en répliquant toutes les autres valeurs de colonne. Pour voir cela en action, passons d'abord au format "DataFrame" de Pandas : + +```py +issues_dataset.set_format("pandas") +df = issues_dataset[:] +``` + +Si nous inspectons la première ligne de ce `DataFrame`, nous pouvons voir qu'il y a quatre commentaires associés à ce problème : + +```py +df["comments"][0].tolist() +``` + +```python out +['the bug code locate in :\r\n if data_args.task_name is not None:\r\n # Downloading and loading a dataset from the hub.\r\n datasets = load_dataset("glue", data_args.task_name, cache_dir=model_args.cache_dir)', + 'Hi @jinec,\r\n\r\nFrom time to time we get this kind of `ConnectionError` coming from the github.com website: https://raw.githubusercontent.com\r\n\r\nNormally, it should work if you wait a little and then retry.\r\n\r\nCould you please confirm if the problem persists?', + 'cannot connect,even by Web browser,please check that there is some problems。', + 'I can access https://raw.githubusercontent.com/huggingface/datasets/1.7.0/datasets/glue/glue.py without problem...'] +``` + +Lorsque nous décomposons `df`, nous nous attendons à obtenir une ligne pour chacun de ces commentaires. Vérifions si c'est le cas : + +```py +comments_df = df.explode("comments", ignore_index=True) +comments_df.head(4) +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
html_urltitlecommentsbody
0https://github.com/huggingface/datasets/issues/2787ConnectionError: Couldn't reach https://raw.githubusercontent.comthe bug code locate in :\r\n if data_args.task_name is not None...Hello,\r\nI am trying to run run_glue.py and it gives me this error...
1https://github.com/huggingface/datasets/issues/2787ConnectionError: Couldn't reach https://raw.githubusercontent.comHi @jinec,\r\n\r\nFrom time to time we get this kind of `ConnectionError` coming from the github.com website: https://raw.githubusercontent.com...Hello,\r\nI am trying to run run_glue.py and it gives me this error...
2https://github.com/huggingface/datasets/issues/2787ConnectionError: Couldn't reach https://raw.githubusercontent.comcannot connect,even by Web browser,please check that there is some problems。Hello,\r\nI am trying to run run_glue.py and it gives me this error...
3https://github.com/huggingface/datasets/issues/2787ConnectionError: Couldn't reach https://raw.githubusercontent.comI can access https://raw.githubusercontent.com/huggingface/datasets/1.7.0/datasets/glue/glue.py without problem...Hello,\r\nI am trying to run run_glue.py and it gives me this error...
+ +Génial, nous pouvons voir que les lignes ont été répliquées, avec la colonne "commentaires" contenant les commentaires individuels ! Maintenant que nous en avons fini avec Pandas, nous pouvons rapidement revenir à un `Dataset` en chargeant le `DataFrame` en mémoire : + +```py +from datasets import Dataset + +comments_dataset = Dataset.from_pandas(comments_df) +comments_dataset +``` + +```python out +Dataset({ + features: ['html_url', 'title', 'comments', 'body'], + num_rows: 2842 +}) +``` + +D'accord, cela nous a donné quelques milliers de commentaires avec lesquels travailler ! + + + + +✏️ **Essayez-le !** Voyez si vous pouvez utiliser `Dataset.map()` pour exploser la colonne `comments` de `issues_dataset` _sans_ recourir à l'utilisation de Pandas. C'est un peu délicat; vous pourriez trouver la section ["Batch mapping"](https://huggingface.co/docs/datasets/v1.12.1/about_map_batch.html?batch-mapping#batch-mapping) de la documentation 🤗 Datasets utile pour cette tâche. + + + +Maintenant que nous avons un commentaire par ligne, créons une nouvelle colonne `comments_length` contenant le nombre de mots par commentaire : + +```py +comments_dataset = comments_dataset.map( + lambda x: {"comment_length": len(x["comments"].split())} +) +``` + +Nous pouvons utiliser cette nouvelle colonne pour filtrer les commentaires courts, qui incluent généralement des éléments tels que "cc @lewtun" ou "Merci !" qui ne sont pas pertinents pour notre moteur de recherche. Il n'y a pas de nombre précis à sélectionner pour le filtre, mais environ 15 mots semblent être un bon début : + +```py +comments_dataset = comments_dataset.filter(lambda x: x["comment_length"] > 15) +comments_dataset +``` + +```python out +Dataset({ + features: ['html_url', 'title', 'comments', 'body', 'comment_length'], + num_rows: 2098 +}) +``` + +Après avoir un peu nettoyé notre ensemble de données, concaténons le titre, la description et les commentaires du problème dans une nouvelle colonne "texte". Comme d'habitude, nous allons écrire une fonction simple que nous pouvons passer à `Dataset.map()` : + +```py +def concatenate_text(examples): + return { + "text": examples["title"] + + " \n " + + examples["body"] + + " \n " + + examples["comments"] + } + + +comments_dataset = comments_dataset.map(concatenate_text) +``` + +Nous sommes enfin prêts à créer des embeddings ! Nous allons jeter un coup d'oeil. + +## Création d'incorporations de texte + +Nous avons vu dans [Chapitre 2](/course/chapter2) que nous pouvons obtenir des incorporations de jetons en utilisant la classe `AutoModel`. Tout ce que nous avons à faire est de choisir un point de contrôle approprié à partir duquel charger le modèle. Heureusement, il existe une bibliothèque appelée `sentence-transformers` dédiée à la création d'incorporations. Comme décrit dans la [documentation] de la bibliothèque (https://www.sbert.net/examples/applications/semantic-search/README.html#symmetric-vs-asymmetric-semantic-search), notre cas d'utilisation est un exemple de _asymmetric recherche sémantique_ car nous avons une requête courte dont nous aimerions trouver la réponse dans un document plus long, comme un commentaire sur un problème. Le [tableau de présentation des modèles] (https://www.sbert.net/docs/pretrained_models.html#model-overview) pratique de la documentation indique que le point de contrôle `multi-qa-mpnet-base-dot-v1` a le meilleures performances pour la recherche sémantique, nous l'utiliserons donc pour notre application. Nous allons également charger le tokenizer en utilisant le même point de contrôle : + +{#if fw === 'pt'} + +```py +from transformers import AutoTokenizer, AutoModel + +model_ckpt = "sentence-transformers/multi-qa-mpnet-base-dot-v1" +tokenizer = AutoTokenizer.from_pretrained(model_ckpt) +model = AutoModel.from_pretrained(model_ckpt) +``` + +Pour accélérer le processus d'intégration, il est utile de placer le modèle et les entrées sur un périphérique GPU, alors faisons-le maintenant : + +```py +import torch + +device = torch.device("cuda") +model.to(device) +``` + +{:else} + +```py +from transformers import AutoTokenizer, TFAutoModel + +model_ckpt = "sentence-transformers/multi-qa-mpnet-base-dot-v1" +tokenizer = AutoTokenizer.from_pretrained(model_ckpt) +model = TFAutoModel.from_pretrained(model_ckpt, from_pt=True) +``` + +Notez que nous avons défini `from_pt=True` comme argument de la méthode `from_pretrained()`. C'est parce que le point de contrôle `multi-qa-mpnet-base-dot-v1` n'a que des poids PyTorch, donc définir `from_pt=True` les convertira automatiquement au format TensorFlow pour nous. Comme vous pouvez le voir, il est très simple de passer d'un framework à l'autre dans 🤗 Transformers ! + +{/if} + +Comme nous l'avons mentionné précédemment, nous aimerions représenter chaque entrée dans notre corpus de problèmes GitHub comme un vecteur unique, nous devons donc "regrouper" ou faire la moyenne de nos incorporations de jetons d'une manière ou d'une autre. Une approche populaire consiste à effectuer un * regroupement CLS * sur les sorties de notre modèle, où nous collectons simplement le dernier état caché pour le jeton spécial `[CLS]`. La fonction suivante fait l'affaire pour nous : + +```py +def cls_pooling(model_output): + return model_output.last_hidden_state[:, 0] +``` + +Ensuite, nous allons créer une fonction d'assistance qui va tokeniser une liste de documents, placer les tenseurs sur le GPU, les alimenter au modèle et enfin appliquer le regroupement CLS aux sorties : + +{#if fw === 'pt'} + +```py +def get_embeddings(text_list): + encoded_input = tokenizer( + text_list, padding=True, truncation=True, return_tensors="pt" + ) + encoded_input = {k: v.to(device) for k, v in encoded_input.items()} + model_output = model(**encoded_input) + return cls_pooling(model_output) +``` + +Nous pouvons tester le fonctionnement de la fonction en lui fournissant la première entrée de texte dans notre corpus et en inspectant la forme de sortie : + +```py +embedding = get_embeddings(comments_dataset["text"][0]) +embedding.shape +``` + +```python out +torch.Size([1, 768]) +``` + +Super, nous avons converti la première entrée de notre corpus en un vecteur à 768 dimensions ! Nous pouvons utiliser `Dataset.map()` pour appliquer notre fonction `get_embeddings()` à chaque ligne de notre corpus, créons donc une nouvelle colonne `embeddings` comme suit : + +```py +embeddings_dataset = comments_dataset.map( + lambda x: {"embeddings": get_embeddings(x["text"]).detach().cpu().numpy()[0]} +) +``` + +{:else} + +```py +def get_embeddings(text_list): + encoded_input = tokenizer( + text_list, padding=True, truncation=True, return_tensors="tf" + ) + encoded_input = {k: v for k, v in encoded_input.items()} + model_output = model(**encoded_input) + return cls_pooling(model_output) +``` + +Nous pouvons tester le fonctionnement de la fonction en lui fournissant la première entrée de texte dans notre corpus et en inspectant la forme de sortie : + +```py +embedding = get_embeddings(comments_dataset["text"][0]) +embedding.shape +``` + +```python out +TensorShape([1, 768]) +``` + +Super, nous avons converti la première entrée de notre corpus en un vecteur à 768 dimensions ! Nous pouvons utiliser `Dataset.map()` pour appliquer notre fonction `get_embeddings()` à chaque ligne de notre corpus, créons donc une nouvelle colonne `embeddings` comme suit : + +```py +embeddings_dataset = comments_dataset.map( + lambda x: {"embeddings": get_embeddings(x["text"]).numpy()[0]} +) +``` + +{/if} + + +Notez que nous avons converti les intégrations en tableaux NumPy -- c'est parce que 🤗 Datasets nécessite ce format lorsque nous essayons de les indexer avec FAISS, ce que nous ferons ensuite. + +## Utilisation de FAISS pour une recherche de similarité efficace + +Maintenant que nous avons un ensemble de données d'incorporations, nous avons besoin d'un moyen de les rechercher. Pour ce faire, nous utiliserons une structure de données spéciale dans 🤗 Datasets appelée _FAISS index_. [FAISS](https://faiss.ai/) (abréviation de Facebook AI Similarity Search) est une bibliothèque qui fournit des algorithmes efficaces pour rechercher et regrouper rapidement des vecteurs d'intégration. + +L'idée de base derrière FAISS est de créer une structure de données spéciale appelée un _index_ qui permet de trouver quels plongements sont similaires à un plongement d'entrée. Créer un index FAISS dans 🤗 Datasets est simple -- nous utilisons la fonction `Dataset.add_faiss_index()` et spécifions quelle colonne de notre jeu de données nous aimerions indexer : + +```py +embeddings_dataset.add_faiss_index(column="embeddings") +``` + +Nous pouvons maintenant effectuer des requêtes sur cet index en effectuant une recherche de voisin le plus proche avec la fonction `Dataset.get_nearest_examples()`. Testons cela en intégrant d'abord une question comme suit : + +{#if fw === 'pt'} + +```py +question = "How can I load a dataset offline?" +question_embedding = get_embeddings([question]).cpu().detach().numpy() +question_embedding.shape +``` + +```python out +torch.Size([1, 768]) +``` + +{:else} + +```py +question = "How can I load a dataset offline?" +question_embedding = get_embeddings([question]).numpy() +question_embedding.shape +``` + +```python out +(1, 768) +``` + +{/if} + +Tout comme avec les documents, nous avons maintenant un vecteur de 768 dimensions représentant la requête, que nous pouvons comparer à l'ensemble du corpus pour trouver les plongements les plus similaires : + +```py +scores, samples = embeddings_dataset.get_nearest_examples( + "embeddings", question_embedding, k=5 +) +``` + +La fonction `Dataset.get_nearest_examples()` renvoie un tuple de scores qui classent le chevauchement entre la requête et le document, et un ensemble correspondant d'échantillons (ici, les 5 meilleures correspondances). Collectons-les dans un `pandas.DataFrame` afin de pouvoir les trier facilement : + +```py +import pandas as pd + +samples_df = pd.DataFrame.from_dict(samples) +samples_df["scores"] = scores +samples_df.sort_values("scores", ascending=False, inplace=True) +``` + +Nous pouvons maintenant parcourir les premières lignes pour voir dans quelle mesure notre requête correspond aux commentaires disponibles : + +```py +for _, row in samples_df.iterrows(): + print(f"COMMENT: {row.comments}") + print(f"SCORE: {row.scores}") + print(f"TITLE: {row.title}") + print(f"URL: {row.html_url}") + print("=" * 50) + print() +``` + +```python out +""" +COMMENT: Requiring online connection is a deal breaker in some cases unfortunately so it'd be great if offline mode is added similar to how `transformers` loads models offline fine. + +@mandubian's second bullet point suggests that there's a workaround allowing you to use your offline (custom?) dataset with `datasets`. Could you please elaborate on how that should look like? +SCORE: 25.505046844482422 +TITLE: Discussion using datasets in offline mode +URL: https://github.com/huggingface/datasets/issues/824 +================================================== + +COMMENT: The local dataset builders (csv, text , json and pandas) are now part of the `datasets` package since #1726 :) +You can now use them offline +\`\`\`python +datasets = load_dataset("text", data_files=data_files) +\`\`\` + +We'll do a new release soon +SCORE: 24.555509567260742 +TITLE: Discussion using datasets in offline mode +URL: https://github.com/huggingface/datasets/issues/824 +================================================== + +COMMENT: I opened a PR that allows to reload modules that have already been loaded once even if there's no internet. + +Let me know if you know other ways that can make the offline mode experience better. I'd be happy to add them :) + +I already note the "freeze" modules option, to prevent local modules updates. It would be a cool feature. + +---------- + +> @mandubian's second bullet point suggests that there's a workaround allowing you to use your offline (custom?) dataset with `datasets`. Could you please elaborate on how that should look like? + +Indeed `load_dataset` allows to load remote dataset script (squad, glue, etc.) but also you own local ones. +For example if you have a dataset script at `./my_dataset/my_dataset.py` then you can do +\`\`\`python +load_dataset("./my_dataset") +\`\`\` +and the dataset script will generate your dataset once and for all. + +---------- + +About I'm looking into having `csv`, `json`, `text`, `pandas` dataset builders already included in the `datasets` package, so that they are available offline by default, as opposed to the other datasets that require the script to be downloaded. +cf #1724 +SCORE: 24.14896583557129 +TITLE: Discussion using datasets in offline mode +URL: https://github.com/huggingface/datasets/issues/824 +================================================== + +COMMENT: > here is my way to load a dataset offline, but it **requires** an online machine +> +> 1. (online machine) +> +> ``` +> +> import datasets +> +> data = datasets.load_dataset(...) +> +> data.save_to_disk(/YOUR/DATASET/DIR) +> +> ``` +> +> 2. copy the dir from online to the offline machine +> +> 3. (offline machine) +> +> ``` +> +> import datasets +> +> data = datasets.load_from_disk(/SAVED/DATA/DIR) +> +> ``` +> +> +> +> HTH. + + +SCORE: 22.893993377685547 +TITLE: Discussion using datasets in offline mode +URL: https://github.com/huggingface/datasets/issues/824 +================================================== + +COMMENT: here is my way to load a dataset offline, but it **requires** an online machine +1. (online machine) +\`\`\` +import datasets +data = datasets.load_dataset(...) +data.save_to_disk(/YOUR/DATASET/DIR) +\`\`\` +2. copy the dir from online to the offline machine +3. (offline machine) +\`\`\` +import datasets +data = datasets.load_from_disk(/SAVED/DATA/DIR) +\`\`\` + +HTH. +SCORE: 22.406635284423828 +TITLE: Discussion using datasets in offline mode +URL: https://github.com/huggingface/datasets/issues/824 +================================================== +""" +``` + +Pas mal! Notre deuxième résultat semble correspondre à la requête. + + + +✏️ **Essayez-le !** Créez votre propre requête et voyez si vous pouvez trouver une réponse dans les documents récupérés. Vous devrez peut-être augmenter le paramètre `k` dans `Dataset.get_nearest_examples()` pour élargir la recherche. + + \ No newline at end of file diff --git a/chapters/fr/chapter5/7.mdx b/chapters/fr/chapter5/7.mdx new file mode 100644 index 000000000..a4da397e5 --- /dev/null +++ b/chapters/fr/chapter5/7.mdx @@ -0,0 +1,11 @@ +# 🤗 Datasets, vérifié ! + +Eh bien, ce fut toute une visite de la 🤗 Datasets -- félicitations pour être arrivé jusqu'ici ! Avec les connaissances que vous avez acquises dans ce chapitre, vous devriez être en mesure de : + +- Chargez des ensembles de données de n'importe où, que ce soit le Hugging Face Hub, votre ordinateur portable ou un serveur distant de votre entreprise. +- Démêlez vos données en utilisant un mélange des fonctions `Dataset.map()` et `Dataset.filter()`. +- Basculez rapidement entre les formats de données comme Pandas et NumPy en utilisant `Dataset.set_format()`. +- Créez votre propre ensemble de données et transférez-le vers le Hugging Face Hub. +- Intégrez vos documents à l'aide d'un modèle Transformer et créez un moteur de recherche sémantique à l'aide de FAISS. + +Dans le [Chapitre 7](/course/chapter7), nous mettrons tout cela à profit en approfondissant les principales tâches de la PNL pour lesquelles les modèles Transformer sont parfaits. Avant de vous lancer, mettez à l'épreuve vos connaissances sur 🤗 Datasets avec un quiz rapide ! diff --git a/chapters/fr/chapter5/8.mdx b/chapters/fr/chapter5/8.mdx new file mode 100644 index 000000000..19bb1d08a --- /dev/null +++ b/chapters/fr/chapter5/8.mdx @@ -0,0 +1,226 @@ + + +# Quiz de fin de chapitre + +Ce chapitre a couvert beaucoup de terrain! Ne vous inquiétez pas si vous n'avez pas saisi tous les détails ; les prochains chapitres vous aideront à comprendre comment les choses fonctionnent sous le capot. + +Avant de poursuivre, testons ce que vous avez appris dans ce chapitre. + +### 1. La fonction `load_dataset()` dans 🤗 Datasets vous permet de charger un jeu de données depuis lequel des emplacements suivants ? + +data_files de load_dataset() pour charger les jeux de données locaux.", + correct: true + }, + { + text: "Le hub du visage étreignant", + explain: "Correct! Vous pouvez charger des ensembles de données sur le Hub en fournissant l'ID de l'ensemble de données, par ex. load_dataset('emotion').", + correct: true + }, + { + text: "Un serveur distant", + explain: "Correct! Vous pouvez passer des URL à l'argument data_files de load_dataset() pour charger des fichiers distants.", + correct: true + }, + ]} +/> + +### 2. Supposons que vous chargiez l'une des tâches GLUE comme suit : + +```py +from datasets import load_dataset + +dataset = load_dataset("glue", "mrpc", split="train") +``` + +Laquelle des commandes suivantes produira un échantillon aléatoire de 50 éléments à partir de `dataset` ? + +dataset.sample(50)", + explain: "Ceci est incorrect -- il n'y a pas de méthode Dataset.sample()." + }, + { + text: "dataset.shuffle().select(range(50))", + explain: "Correct! Comme vous l'avez vu dans ce chapitre, vous mélangez d'abord l'ensemble de données, puis sélectionnez les échantillons à partir de celui-ci.", + correct: true + }, + { + text: "dataset.select(range(50)).shuffle()", + explain: "Ceci est incorrect - bien que le code s'exécute, il ne mélange que les 50 premiers éléments de l'ensemble de données." + } + ]} +/> + +### 3. Supposons que vous disposiez d'un ensemble de données sur les animaux domestiques appelé "pets_dataset", qui comporte une colonne "name" indiquant le nom de chaque animal. Parmi les approches suivantes, laquelle vous permettrait de filtrer l'ensemble de données pour tous les animaux dont le nom commence par la lettre "L" ? + +pets_dataset.filter(lambda x : x['name'].startswith('L'))", + explain: "Correct! L'utilisation d'une fonction Python lambda pour ces filtres rapides est une excellente idée. Pouvez-vous penser à une autre solution?", + correct: true + }, + { + text: "pets_dataset.filter(lambda x['name'].startswith('L'))", + explain: "Ceci est incorrect -- une fonction lambda prend la forme générale lambda *arguments* : *expression*, vous devez donc fournir des arguments dans ce cas." + }, + { + text: "Créez une fonction comme def filter_names(x): return x['name'].startswith('L') et exécutez pets_dataset.filter(filter_names).", + explain: "Correct! Tout comme avec Dataset.map(), vous pouvez passer des fonctions explicites à Dataset.filter(). Ceci est utile lorsque vous avez une logique complexe qui ne convient pas à une fonction lambda courte. Parmi les autres solutions, laquelle fonctionnerait ?", + correct: true + } + ]} +/> + +### 4. Qu'est-ce que la cartographie mémoire ? + + + +### 5. Parmi les éléments suivants, lesquels sont les principaux avantages du mappage mémoire ? + + + +### 6. Pourquoi le code suivant échoue-t-il ? + +```py +from datasets import load_dataset + +dataset = load_dataset("allocine", streaming=True, split="train") +dataset[0] +``` + +IterableDataset.", + explain: "Correct! Un IterableDataset est un générateur, pas un conteneur, vous devez donc accéder à ses éléments en utilisant next(iter(dataset)).", + correct: true + }, + { + text: "L'ensemble de données allocine n'a pas de division train.", + explain: "Ceci est incorrect - consultez la [fiche de l'ensemble de données allocine](https://huggingface.co/datasets/allocine) sur le Hub pour voir quelles divisions elle contient." + } + ]} +/> + +### 7. Parmi les avantages suivants, lesquels sont les principaux avantages de la création d'une fiche d'ensemble de données ? + + + + +### 8. Qu'est-ce que la recherche sémantique ? + + + +### 9. Pour la recherche sémantique asymétrique, vous avez généralement : + + + +### 10. Puis-je utiliser 🤗 Datasets pour charger des données à utiliser dans d'autres domaines, comme le traitement de la parole ? + +MNIST dataset sur le Hub pour un exemple de vision par ordinateur." + }, + { + text: "Oui", + explain: "Correct! Découvrez les développements passionnants avec la parole et la vision dans la bibliothèque 🤗 Transformers pour voir comment 🤗 Datasets est utilisé dans ces domaines.", + correct : true + }, + ]} +/> From 0821f1f0b7f65b1eaa1b265cbc7a077452576ef0 Mon Sep 17 00:00:00 2001 From: Lewis Tunstall Date: Mon, 11 Apr 2022 10:28:10 +0200 Subject: [PATCH 26/73] Add Bengali to CI --- .github/workflows/build_documentation.yml | 2 +- .github/workflows/build_pr_documentation.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_documentation.yml b/.github/workflows/build_documentation.yml index 14e786916..a7714c94a 100644 --- a/.github/workflows/build_documentation.yml +++ b/.github/workflows/build_documentation.yml @@ -14,6 +14,6 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: en es fa fr he ko pt ru th tr + languages: bn en es fa fr he ko pt ru th tr secrets: token: ${{ secrets.HUGGINGFACE_PUSH }} \ No newline at end of file diff --git a/.github/workflows/build_pr_documentation.yml b/.github/workflows/build_pr_documentation.yml index d1a24e255..f7b92f51d 100644 --- a/.github/workflows/build_pr_documentation.yml +++ b/.github/workflows/build_pr_documentation.yml @@ -16,5 +16,5 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: en es fa fr he ko pt ru th tr + languages: bn en es fa fr he ko pt ru th tr hub_base_path: https://moon-ci-docs.huggingface.co/course \ No newline at end of file From 74c9f35551969291dc8b4a79989ec9325020a5f7 Mon Sep 17 00:00:00 2001 From: Lewis Tunstall Date: Mon, 11 Apr 2022 10:28:31 +0200 Subject: [PATCH 27/73] Update author list --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a10534eef..2b70941d7 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ This repo contains the content that's used to create the **[Hugging Face course] | Language | Source | Authors | |:-------------------------------------------------------|:-----------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [English](https://huggingface.co/course/en/chapter1/1) | [`chapters/en`](https://github.com/huggingface/course/tree/main/chapters/en) | [@sgugger](https://github.com/sgugger), [@lewtun](https://github.com/lewtun), [@LysandreJik](https://github.com/LysandreJik), [@Rocketknight1](https://github.com/Rocketknight1), [@sashavor](https://github.com/sashavor), [@osanseviero](https://github.com/osanseviero), [@SaulLu](https://github.com/SaulLu), [@lvwerra](https://github.com/lvwerra) | +| [Korean](https://huggingface.co/course/ko/chapter1/1) (WIP) | [`chapters/ko`](https://github.com/huggingface/course/tree/main/chapters/ko) | [@Doohae](https://github.com/Doohae) | | [Russian](https://huggingface.co/course/ru/chapter1/1) (WIP) | [`chapters/ru`](https://github.com/huggingface/course/tree/main/chapters/ru) | [@pdumin](https://github.com/pdumin) | | [Spanish](https://huggingface.co/course/es/chapter1/1) (WIP) | [`chapters/es`](https://github.com/huggingface/course/tree/main/chapters/es) | [@camartinezbu](https://github.com/camartinezbu) | | [Thai](https://huggingface.co/course/th/chapter1/1) (WIP) | [`chapters/th`](https://github.com/huggingface/course/tree/main/chapters/th) | [@peeraponw](https://github.com/peeraponw), [@a-krirk](https://github.com/a-krirk), [@jomariya23156](https://github.com/jomariya23156) | From 772400ddf96be0bcec9f2d05e60ce8ede73d8908 Mon Sep 17 00:00:00 2001 From: Jose M Munoz Date: Mon, 11 Apr 2022 09:18:16 -0500 Subject: [PATCH 28/73] =?UTF-8?q?Adding=20translations=20for=202/4=20and?= =?UTF-8?q?=202/5=20=F0=9F=9A=80=20(#74)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adding translations for 2/4 and 2/5 🚀 * Remove English content Co-authored-by: lewtun --- chapters/es/_toctree.yml | 7 + chapters/es/chapter2/4.mdx | 235 ++++++++++++++++++++++++++ chapters/es/chapter2/5.mdx | 332 +++++++++++++++++++++++++++++++++++++ 3 files changed, 574 insertions(+) create mode 100644 chapters/es/chapter2/4.mdx create mode 100644 chapters/es/chapter2/5.mdx diff --git a/chapters/es/_toctree.yml b/chapters/es/_toctree.yml index 5ee96568f..2cdc73523 100644 --- a/chapters/es/_toctree.yml +++ b/chapters/es/_toctree.yml @@ -26,3 +26,10 @@ - local: chapter1/10 title: Quiz de final de capítulo quiz: 1 + +- title: 2. Usando Transformers 🤗 + sections: + - local: chapter2/4 + title: Tokenizadores + - local: chapter2/5 + title: Manejando Secuencias Múltiples diff --git a/chapters/es/chapter2/4.mdx b/chapters/es/chapter2/4.mdx new file mode 100644 index 000000000..7a3b40160 --- /dev/null +++ b/chapters/es/chapter2/4.mdx @@ -0,0 +1,235 @@ + + +# Tokenizadores + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + + + +Los tokenizadores son uno de los componentes fundamentales del pipeline en NLP. Sirven para traducir texto en datos que los modelos puedan procesar; es decir, de texto a valores numéricos. En esta sección veremos en qué se fundamenta todo el proceso de tokenizado. + +En las tareas de NLP, los datos generalmente ingresan como texto crudo. Por ejemplo: +``` +Jim Henson era un titiritero +``` + +Sin embargo, necesitamos una forma de convertir el texto crudo a valores numéricos para los modelos. Eso es precisamente lo que hacen los tokenizadores, y existe una variedad de formas en que puede hacerse. El objetivo final es obetener valores que sean cortos pero muy significativos para el modelo. + +Veamos algunos algoritmos de tokenización, e intentemos atacar algunas preguntas que puedas tener. + +## Tokenización Word-based + + + +El primer tokenizador que nos ocurre es el _word-based_ (_basado-en-palabras_). Es generalmente sencillo, con pocas normas, y generalmente da buenos resultados. Por ejemplo, en la imagen a continuación separamos el texto en palabras y buscamos una representación numérica. +
+ Un ejemplo de tokenizador _word-based_. + +
+ +Existen varias formas de separar el texto. Por ejempĺo, podríamos usar los espacios para tokenizar usando Python y la función `split()`. + +```py +tokenized_text = "Jim Henson era un titiritero".split() +print(tokenized_text) +``` + +```python out +['Jim', 'Henson', 'era', 'un', 'titiritero'] +``` +También hay variaciones de tokenizadores de palabras que tienen reglas adicionales para la puntuación. Con este tipo de tokenizador, podemos acabar con unos "vocabularios" bastante grandes, donde un vocabulario se define por el número total de tokens independientes que tenemos en nuestro corpus. + +A cada palabra se le asigna un ID, empezando por 0 y subiendo hasta el tamaño del vocabulario. El modelo utiliza estos ID para identificar cada palabra. + +Si queremos cubrir completamente un idioma con un tokenizador basado en palabras, necesitaremos tener un identificador para cada palabra del idioma, lo que generará una enorme cantidad de tokens. Por ejemplo, hay más de 500.000 palabras en el idioma inglés, por lo que para construir un mapa de cada palabra a un identificador de entrada necesitaríamos hacer un seguimiento de esa cantidad de identificadores. Además, palabras como "perro" se representan de forma diferente a palabras como "perros", y el modelo no tendrá forma de saber que "perro" y "perros" son similares: identificará las dos palabras como no relacionadas. Lo mismo ocurre con otras palabras similares, como "correr" y "corriendo", que el modelo no verá inicialmente como similares. + +Por último, necesitamos un token personalizado para representar palabras que no están en nuestro vocabulario. Esto se conoce como el token "desconocido", a menudo representado como "[UNK]" o "<unk>". Generalmente, si el tokenizador está produciendo muchos de estos tokens es una mala señal, ya que no fue capaz de recuperar una representación de alguna palabra y está perdiendo información en el proceso. El objetivo al elaborar el vocabulario es hacerlo de tal manera que el tokenizador tokenice el menor número de palabras posibles en tokens desconocidos. + +Una forma de reducir la cantidad de tokens desconocidos es ir un poco más allá, utilizando un tokenizador _word-based_. + +## Tokenización Character-based + + + +Character-based tokenizers split the text into characters, rather than words. This has two primary benefits: +Un tokenizador _character-based_ separa el texto en caracteres, y no en palabras. Conllevando dos beneficios principales: + +- Obtenemos un vocabulario mucho más corto. +- Habrá muchos menos tokens por fuera del vocabulatio conocido. + +No obstante, pueden surgir incovenientes por los espacios en blanco y signos de puntuación. + +
+ Ejemplo de tokenizador basado en palabras. + +
+ +Así, este método tampoco es perfecto. Dada que la representación se construyó con caracteres, uno podría pensar intuitivamente que resulta menos significativo: Cada una de las palabras no significa mucho por separado, mientras que las palabras sí. Sin embargo, eso es dependiente del idioma. Por ejemplo en Chino, cada uno de los caracteres conlleva más información que en un idioma latino. + +Otro aspecto a considerar es que terminamos con una gran cantidad de tokens que el modelo debe procesar, mientras que en el caso del tokenizador _word-based_, un token representa una palabra, en la representación de caracteres fácilmente puede necesitar más de 10 tokens. + +Para obtener lo mejor de ambos mundos, podemos usar una combinación de las técnicas: la tokenización por *subword tokenization*. + +## Tokenización por Subword + + + +Los algoritmos de tokenización de subpalabras se basan en el principio de que las palabras de uso frecuente no deben dividirse, mientras que las palabras raras deben descomponerse en subpalabras significativas. + +Por ejemplo, "extrañamente" podría considerarse una palabra rara y podría descomponerse en "extraña" y "mente". Es probable que ambas aparezcan con más frecuencia como subpalabras independientes, mientras que al mismo tiempo el significado de "extrañamente" se mantiene por el significado compuesto de "extraña" y "mente". + +Este es un ejemplo que muestra cómo un algoritmo de tokenización de subpalabras tokenizaría la secuencia "Let's do tokenization!": + +
+ Un tokenizador basado en subpalabras. + +
+ +Estas subpalabras terminan aportando mucho significado semántico: por ejemplo, en el ejemplo anterior, "tokenización" se dividió en "token" y "ización", dos tokens que tienen un significado semántico y a la vez son eficientes en cuanto al espacio (sólo se necesitan dos tokens para representar una palabra larga). Esto nos permite tener una cobertura relativamente buena con vocabularios pequeños y casi sin tokens desconocidos. + +Este enfoque es especialmente útil en algunos idimas como el turco, donde se pueden formar palabras complejas (casi) arbitrariamente largas encadenando subpalabras. + +### Y más! + +Como es lógico, existen muchas más técnicas. Por nombrar algunas: + +- Byte-level BPE (a nivel de bytes), como usa GPT-2 +- WordPiece, usado por BERT +- SentencePiece or Unigram (pedazo de sentencia o unigrama), como se usa en los modelos multilengua + +A este punto, deberías tener conocimientos suficientes sobre el funcionamiento de los tokenizadores para empezar a utilizar la API. + +## Cargando y guardando + +Cargar y guardar tokenizadores es tan sencillo como lo es con los modelos. En realidad, se basa en los mismos dos métodos: `from_pretrained()` y `save_pretrained()`. Estos métodos cargarán o guardarán el algoritmo utilizado por el tokenizador (un poco como la *arquitectura* del modelo) así como su vocabulario (un poco como los *pesos* del modelo). + +La carga del tokenizador BERT entrenado con el mismo punto de control que BERT se realiza de la misma manera que la carga del modelo, excepto que utilizamos la clase `BertTokenizer`: + +```py +from transformers import BertTokenizer + +tokenizer = BertTokenizer.from_pretrained("bert-base-cased") +``` + +{#if fw === 'pt'} +Al igual que `AutoModel`, la clase `AutoTokenizer` tomará la clase de tokenizador adecuada en la biblioteca basada en el nombre del punto de control, y se puede utilizar directamente con cualquier punto de control: + +{:else} +Al igual que `TFAutoModel`, la clase `AutoTokenizer` tomará la clase de tokenizador adecuada en la biblioteca basada en el nombre del punto de control, y se puede utilizar directamente con cualquier punto de control: + +{/if} + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +``` + +Ahora podemos utilizar el tokenizador como se muestra en la sección anterior: + +```python +tokenizer("Using a Transformer network is simple") +``` + +```python out +{'input_ids': [101, 7993, 170, 11303, 1200, 2443, 1110, 3014, 102], + 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0], + 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]} +``` +Guardar un tokenizador es idéntico a guardar un modelo: + +```py +tokenizer.save_pretrained("directorio_en_mi_computador") +``` + +Hablaremos más sobre `token_type_ids` en el [Capítulo 3](/course/chapter3), y explicaremos la clave `attention_mask` un poco más tarde. Primero, veamos cómo se generan los `input_ids`. Para ello, tendremos que ver los métodos intermedios del tokenizador. + +## Encoding + + + +La traducción de texto a números se conoce como _codificación_. La codificación se realiza en un proceso de dos pasos: la tokenización, seguida de la conversión a IDs de entrada. + +Como hemos visto, el primer paso es dividir el texto en palabras (o partes de palabras, símbolos de puntuación, etc.), normalmente llamadas *tokens*. Hay múltiples reglas que pueden gobernar ese proceso, por lo que necesitamos instanciar el tokenizador usando el nombre del modelo, para asegurarnos de que usamos las mismas reglas que se usaron cuando se preentrenó el modelo. + +El segundo paso es convertir esos tokens en números, para poder construir un tensor con ellos y alimentar el modelo. Para ello, el tokenizador tiene un *vocabulario*, que es la parte que descargamos cuando lo instanciamos con el método `from_pretrained()`. De nuevo, necesitamos usar el mismo vocabulario que se usó cuando el modelo fue preentrenado. + +Para entender mejor los dos pasos, los exploraremos por separado. Ten en cuenta que utilizaremos algunos métodos que realizan partes del proceso de tokenización por separado para mostrarte los resultados intermedios de esos pasos, pero en la práctica, deberías llamar al tokenizador directamente en tus _inputs_ (como se muestra en la sección 2). + +### Tokenization + +El proceso de tokenización se realiza mediante el método `tokenize()` del tokenizador: + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") + +sequence = "Using a Transformer network is simple" +tokens = tokenizer.tokenize(sequence) + +print(tokens) +``` + +La salida de este método es una lista de cadenas, o tokens: + +```python out +['Using', 'a', 'transform', '##er', 'network', 'is', 'simple'] +``` + +Este tokenizador es un tokenizador de subpalabras: divide las palabras hasta obtener tokens que puedan ser representados por su vocabulario. Este es el caso de `transformer`, que se divide en dos tokens: `transform` y `##er`. + +### De tokens a IDs de entrada + +La conversión a IDs de entrada se hace con el método del tokenizador `convert_tokens_to_ids()`: +```py +ids = tokenizer.convert_tokens_to_ids(tokens) + +print(ids) +``` + +```python out +[7993, 170, 11303, 1200, 2443, 1110, 3014] +``` + +Estos resultados, una vez convertidos en el tensor del marco apropiado, pueden utilizarse como entradas de un modelo, como se ha visto anteriormente en este capítulo. + + + +✏️ **Try it out!** Replica los dos últimos pasos (tokenización y conversión a IDs de entrada) en las frases de entrada que utilizamos en la sección 2 ("Llevo toda la vida esperando un curso de HuggingFace" y "¡Odio tanto esto!"). Comprueba que obtienes los mismos ID de entrada que obtuvimos antes! + + + +## Decodificación + +La *decodificación* va al revés: a partir de los índices del vocabulario, queremos obtener una cadena. Esto se puede hacer con el método `decode()` de la siguiente manera: + +```py +decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014]) +print(decoded_string) +``` + +```python out +'Using a Transformer network is simple' +``` +Notemos que el método `decode` no sólo convierte los índices de nuevo en tokens, sino que también agrupa los tokens que formaban parte de las mismas palabras para producir una frase legible. Este comportamiento será extremadamente útil cuando utilicemos modelos que predigan texto nuevo (ya sea texto generado a partir de una indicación, o para problemas de secuencia a secuencia como la traducción o el resumen). + +A estas alturas deberías entender las operaciones atómicas que un tokenizador puede manejar: tokenización, conversión a IDs, y conversión de IDs de vuelta a una cadena. Sin embargo, sólo hemos rozado la punta del iceberg. En la siguiente sección, llevaremos nuestro enfoque a sus límites y echaremos un vistazo a cómo superarlos. \ No newline at end of file diff --git a/chapters/es/chapter2/5.mdx b/chapters/es/chapter2/5.mdx new file mode 100644 index 000000000..606f9bc89 --- /dev/null +++ b/chapters/es/chapter2/5.mdx @@ -0,0 +1,332 @@ + + +# Manejando Secuencias Múltiples + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +{#if fw === 'pt'} + +{:else} + +{/if} + +En la sección anterior, hemos explorado el caso de uso más sencillo: hacer inferencia sobre una única secuencia de poca longitud. Sin embargo, surgen algunas preguntas: + +- ¿Cómo manejamos las secuencias múltiples? +- ¿Cómo manejamos las secuencias múltiples *de diferentes longitudes*? +- ¿Son los índices de vocabulario las únicas entradas que permiten que un modelo funcione bien? +- ¿Existe una secuencia demasiado larga? + +Veamos qué tipo de problemas plantean estas preguntas, y cómo podemos resolverlos utilizando la API de Transformers 🤗. + +## Los modelos esperan Baches de entrada + +En el ejercicio anterior has visto cómo las secuencias se traducen en listas de números. Convirtamos esta lista de números en un tensor y enviémoslo al modelo: + +{#if fw === 'pt'} +```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) +# Esta línea va a fallar: +model(input_ids) +``` + +```python out +IndexError: Dimension out of range (expected to be in range of [-1, 0], but got 1) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.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 = tf.constant(ids) +# Esta línea va a fallar: +model(input_ids) +``` + +```py out +InvalidArgumentError: Input to reshape is a tensor with 14 values, but the requested shape has 196 [Op:Reshape] +``` +{/if} +¡Oh, no! ¿Por qué ha fallado esto? "Hemos seguido los pasos de la tubería en la sección 2. + +El problema es que enviamos una sola secuencia al modelo, mientras que los modelos de 🤗 Transformers esperan múltiples frases por defecto. Aquí tratamos de hacer todo lo que el tokenizador hizo detrás de escena cuando lo aplicamos a una `secuencia`, pero si te fijas bien, verás que no sólo convirtió la lista de IDs de entrada en un tensor, sino que le agregó una dimensión encima: + +{#if fw === 'pt'} +```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]]) +``` +{:else} +```py +tokenized_inputs = tokenizer(sequence, return_tensors="tf") +print(tokenized_inputs["input_ids"]) +``` + +```py out + +``` +{/if} +Intentémoslo de nuevo y añadamos una nueva dimensión encima: + + +{#if fw === 'pt'} +```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) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.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 = tf.constant([ids]) +print("Input IDs:", input_ids) + +output = model(input_ids) +print("Logits:", output.logits) +``` +{/if} +Imprimimos los IDs de entrada así como los logits resultantes - aquí está la salida: + +{#if fw === 'pt'} +```python out +Input IDs: [[ 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012]] +Logits: [[-2.7276, 2.8789]] +``` +{:else} +```py out +Input IDs: tf.Tensor( +[[ 1045 1005 2310 2042 3403 2005 1037 17662 12172 2607 2026 2878 + 2166 1012]], shape=(1, 14), dtype=int32) +Logits: tf.Tensor([[-2.7276208 2.8789377]], shape=(1, 2), dtype=float32) +``` +{/if} +*El "batching"* es el acto de enviar varias frases a través del modelo, todas a la vez. Si sólo tienes una frase, puedes construir un lote con una sola secuencia: + +``` +batched_ids = [ids, ids] +``` + +Se trata de un lote de dos secuencias idénticas. + + + +✏️ **Try it out!** Convierte esta lista `batched_ids` en un tensor y pásalo por tu modelo. Comprueba que obtienes los mismos logits que antes (¡pero dos veces!). + + + +La creación de lotes permite que el modelo funcione cuando lo alimentas con múltiples sentencias. Utilizar varias secuencias es tan sencillo como crear un lote con una sola secuencia. Sin embargo, hay un segundo problema. Cuando se trata de agrupar dos (o más) frases, éstas pueden ser de diferente longitud. Si alguna vez ha trabajado con tensores, sabrá que deben tener forma rectangular, por lo que no podrá convertir la lista de IDs de entrada en un tensor directamente. Para evitar este problema, usamos el *padding* para las entradas. + +## Padding a las entradas + +La siguiente lista de listas no se puede convertir en un tensor: + +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200] +] +``` +Para solucionar esto, utilizaremos *padding* para que nuestros tensores tengan una forma rectangular. El acolchado asegura que todas nuestras sentencias tengan la misma longitud añadiendo una palabra especial llamada *padding token* a las sentencias con menos valores. Por ejemplo, si tienes 10 frases con 10 palabras y 1 frase con 20 palabras, el relleno asegurará que todas las frases tengan 20 palabras. En nuestro ejemplo, el tensor resultante tiene este aspecto: + +```py no-format +padding_id = 100 + +batched_ids = [ + [200, 200, 200], + [200, 200, padding_id], +] +``` +El ID del *padding token* se puede encontrar en `tokenizer.pad_token_id`. Usémoslo y enviemos nuestras dos sentencias a través del modelo de forma individual y por lotes: + + +{#if fw === 'pt'} +```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=) +tensor([[ 0.5803, -0.4125]], grad_fn=) +tensor([[ 1.5694, -1.3895], + [ 1.3373, -1.2163]], grad_fn=) +``` +{:else} +```py no-format +model = TFAutoModelForSequenceClassification.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(tf.constant(sequence1_ids)).logits) +print(model(tf.constant(sequence2_ids)).logits) +print(model(tf.constant(batched_ids)).logits) +``` + +```py out +tf.Tensor([[ 1.5693678 -1.3894581]], shape=(1, 2), dtype=float32) +tf.Tensor([[ 0.5803005 -0.41252428]], shape=(1, 2), dtype=float32) +tf.Tensor( +[[ 1.5693681 -1.3894582] + [ 1.3373486 -1.2163193]], shape=(2, 2), dtype=float32) +``` +{/if} + +Hay un problema con los logits en nuestras predicciones por lotes: la segunda fila debería ser la misma que los logits de la segunda frase, ¡pero tenemos valores completamente diferentes! + +Esto se debe a que la característica clave de los modelos Transformer son las capas de atención que *contextualizan* cada token. Éstas tendrán en cuenta los tokens de relleno, ya que atienden a todos los tokens de una secuencia. Para obtener el mismo resultado al pasar oraciones individuales de diferente longitud por el modelo o al pasar un lote con las mismas oraciones y el padding aplicado, tenemos que decirles a esas capas de atención que ignoren los tokens de padding. Esto se hace utilizando una máscara de atención. + +## Máscaras de atención + +*Las máscaras de atención* son tensores con la misma forma que el tensor de IDs de entrada, rellenados con 0s y 1s: los 1s indican que los tokens correspondientes deben ser atendidos, y los 0s indican que los tokens correspondientes no deben ser atendidos (es decir, deben ser ignorados por las capas de atención del modelo). + +{#if fw === 'pt'} +```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=) +``` +{:else} +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200, tokenizer.pad_token_id], +] + +attention_mask = [ + [1, 1, 1], + [1, 1, 0], +] + +outputs = model(tf.constant(batched_ids), attention_mask=tf.constant(attention_mask)) +print(outputs.logits) +``` + +```py out +tf.Tensor( +[[ 1.5693681 -1.3894582 ] + [ 0.5803021 -0.41252586]], shape=(2, 2), dtype=float32) +``` +{/if} + +Ahora obtenemos los mismos logits para la segunda frase del lote. + +Podemos ver que el último valor de la segunda secuencia es un ID de relleno, que es un valor 0 en la máscara de atención. + + + +✏️ **Try it out!** Aplique la tokenización manualmente a las dos frases utilizadas en la sección 2 ("Llevo toda la vida esperando un curso de HuggingFace" y "¡Odio tanto esto!"). Páselas por el modelo y compruebe que obtiene los mismos logits que en la sección 2. Ahora júntalos usando el token de relleno, y luego crea la máscara de atención adecuada. Comprueba que obtienes los mismos resultados al pasarlos por el modelo. + + + +## Secuencias largas + +Con los modelos Transformer, hay un límite en la longitud de las secuencias que podemos pasar a los modelos. La mayoría de los modelos manejan secuencias de hasta 512 o 1024 tokens, y se bloquean cuando se les pide que procesen secuencias más largas. Hay dos soluciones a este problema: + +- Usar un modelo que soporte secuencias largas +- Truncar tus secuencias + +Los modelos tienen diferentes longitudes de secuencia soportadas, y algunos se especializan en el manejo de secuencias muy largas. Un ejemplo es [Longformer](https://huggingface.co/transformers/model_doc/longformer.html) y otro es [LED](https://huggingface.co/transformers/model_doc/led.html). Si estás trabajando en una tarea que requiere secuencias muy largas, te recomendamos que eches un vistazo a esos modelos. + +En caso contrario, le recomendamos que trunque sus secuencias especificando el parámetro `max_sequence_length`: + +```py +sequence = sequence[:max_sequence_length] +``` From bec12056c3c8a4612e69e9de2c39568c9b139b1b Mon Sep 17 00:00:00 2001 From: svv73 <88366711+svv73@users.noreply.github.com> Date: Tue, 12 Apr 2022 12:48:05 +0400 Subject: [PATCH 29/73] Translation to Russian (#97) * translation of chapter 2/section 1 * add section 1 / chapter 2 to _toctree.yml --- chapters/ru/_toctree.yml | 5 +++++ chapters/ru/chapter2/1.mdx | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 chapters/ru/chapter2/1.mdx diff --git a/chapters/ru/_toctree.yml b/chapters/ru/_toctree.yml index e597bd2e0..b8a26b63b 100644 --- a/chapters/ru/_toctree.yml +++ b/chapters/ru/_toctree.yml @@ -11,3 +11,8 @@ title: Обработка естесственного языка - local: chapter1/3 title: Трансформеры, на что они способны? + +- title: 2. Использование библиотеки 🤗 Transformers + sections: + - local: chapter2/1 + title: Введение \ No newline at end of file diff --git a/chapters/ru/chapter2/1.mdx b/chapters/ru/chapter2/1.mdx new file mode 100644 index 000000000..99dbd07b6 --- /dev/null +++ b/chapters/ru/chapter2/1.mdx @@ -0,0 +1,19 @@ +# Введение + +Как вы могли заметить в [Главе 1](/course/chapter1), модели трансформеров обычно бывают очень большие. Обучение и развертывание таких моделей с миллионами и даже десятками *миллиардов* параметров является сложной задачей. Кроме того, новые модели выпускаются почти ежедневно, и каждая из них имеет собственную реализацию, опробовать их все — непростая задача. + +Библиотека 🤗 Transformers была создана для решения этой проблемы. Её цель — предоставить единый API, с помощью которого можно загружать, обучать и сохранять любую модель трансформера. Основными функциями библиотеки являются: + +- **Удобство в использовании**: Скачивание, загрузку и использование современной модели NLP для вывода данных, можно выполнять всего двумя строками кода. +- **Гибкость**: По своей сути все модели представляют собой простые классы библиотек PyTorch `nn.Module` или TensorFlow `tf.keras.Model` и могут обрабатываться, как и любые другие модели, в соответствующих средах машинного обучения (МО). +- **Простота**: В библиотеке практически не используются абстракции. "Все в одном файле" является основной концепцией: прямой проход модели полностью определяется в одном файле, так что сам код понятен, но при этом доступен для взлома. + +Последняя особенность сильно отличает библиотеку 🤗 Transformers от других библиотек машинного обучения. Модели не строятся на модулях, которые являются общими для всех файлов; вместо этого каждая модель имеет свои собственные слои. Это не только делает модели более доступными и понятными, но и позволяет легко экспериментировать с одной моделью, не затрагивая другие. + +Эта глава начнается со сквозного примера, в котором мы используем модель и токенизатор вместе, чтобы воспроизвести функцию `pipeline()` представленную в [Главе 1](/course/chapter1). Далее мы обсудим API модели: углубимся в классы модели и конфигурации и покажем, как загружать модель и как она обрабатывает числовые входные данные для получения прогнозов. + +Затем мы рассмотрим API токенизатора, который является другим основным компонентом функции `pipeline()`. Токенизаторы берут на себя первый и последний этапы обработки, обрабатывая преобразование текста в числовые входные данные для нейронной сети и обратное преобразование в текст, когда это необходимо. Наконец, мы покажем вам, как обработывается передача нескольких предложений в модель с помощью подготовленных пакетов, а затем завершим все это более детальным рассмотрением высокоуровневой функции `tokenizer()`. + + +⚠️ Чтобы воспользоваться всеми функциями, доступными в Model Hub и 🤗 Transformers, мы рекомендуем создать учетную запись. + \ No newline at end of file From f64e1e6f8f19ffa084c7714b4ce28d59ebdda8b6 Mon Sep 17 00:00:00 2001 From: Vedant Pandya Date: Tue, 12 Apr 2022 14:39:14 +0530 Subject: [PATCH 30/73] Translation of Chapter0 to Hindi (#86) * Hindi?Chapter0-Part_1 * Hindi/Chapter0-Part_2 --- chapters/hi/_toctree.yml | 9 +++ chapters/hi/chapter0/1.mdx | 110 +++++++++++++++++++++++++++++++++++++ chapters/hi/chapter1/1.mdx | 51 +++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 chapters/hi/_toctree.yml create mode 100644 chapters/hi/chapter0/1.mdx create mode 100644 chapters/hi/chapter1/1.mdx diff --git a/chapters/hi/_toctree.yml b/chapters/hi/_toctree.yml new file mode 100644 index 000000000..86dd2c5bd --- /dev/null +++ b/chapters/hi/_toctree.yml @@ -0,0 +1,9 @@ +- title: 0. स्थापना + sections: + - local: chapter0/1 + title: परिचय + +- title: 1. ट्रांसफार्मर मॉडल + sections: + - local: chapter1/1 + title: परिचय diff --git a/chapters/hi/chapter0/1.mdx b/chapters/hi/chapter0/1.mdx new file mode 100644 index 000000000..7fef3c4bf --- /dev/null +++ b/chapters/hi/chapter0/1.mdx @@ -0,0 +1,110 @@ +# परिचय + +हगिंग फेस में आपका स्वागत है! यह परिचय कार्य वातावरण स्थापित करने में आपका मार्गदर्शन करेगा। यदि आप अभी पाठ्यक्रम शुरू कर रहे हैं, तो हम अनुशंसा करते हैं कि आप पहले [अध्याय 1](course/chapter1) पर एक नज़र डालें, फिर वापस आएं और अपना वातावरण सेट करें ताकि आप कोड को स्वयं आज़मा सकें। + +इस पाठ्यक्रम में हम जिन सभी पुस्तकालयों का उपयोग करेंगे, वे पायथन पैकेज के रूप में उपलब्ध हैं, इसलिए यहां हम आपको दिखाएंगे कि पायथन वातावरण कैसे स्थापित करें और विशिष्ट पुस्तकालयों को स्थापित करें जिनकी आपको आवश्यकता होगी। + +हम आपके कार्य परिवेश को स्थापित करने के दो तरीकों को कवर करेंगे, एक Colab नोटबुक या एक पायथन आभासी वातावरण का उपयोग करके। बेझिझक वह चुनें जो आपके साथ सबसे अधिक प्रतिध्वनित हो। शुरुआती लोगों के लिए, हम दृढ़ता से अनुशंसा करते हैं कि आप Colab नोटबुक का उपयोग करके शुरुआत करें। + +ध्यान दें कि हम विंडोज सिस्टम को कवर नहीं करेंगे। यदि आप Windows पर चल रहे हैं, तो हम अनुशंसा करते हैं कि Colab नोटबुक का उपयोग करने के साथ-साथ अनुसरण करें। यदि आप Linux वितरण या macOS का उपयोग कर रहे हैं, तो आप यहाँ वर्णित किसी भी दृष्टिकोण का उपयोग कर सकते हैं। + +अधिकांश पाठ्यक्रम आपके हगिंग फेस खाते पर निर्भर करता है। हम अभी एक बनाने की सलाह देते हैं: [एक खाता बनाएँ](https://huggingface.co/join)। + +## Google Colab नोटबुक का उपयोग करना + +Colab नोटबुक का उपयोग करना सबसे आसान संभव सेटअप है; अपने ब्राउज़र में एक नोटबुक बूट करें और सीधे कोडिंग पर जाएं! + +यदि आप Colab से परिचित नहीं हैं, तो हम अनुशंसा करते हैं कि आप [परिचय](https://colab.research.google.com/notebooks/intro.ipynb) का पालन करके शुरुआत करें। Colab आपको GPU या TPU जैसे कुछ त्वरित हार्डवेयर का उपयोग करने की अनुमति देता है, और यह छोटे कार्यभार के लिए मुफ़्त है। + +एक बार जब आप Colab में घूमने में सहज हो जाएं, तो एक नई नोटबुक बनाएं और स्थापना के साथ आरंभ करें: +
+ एक खाली Colab नोटबुक +
+ +अगला चरण उन पुस्तकालयों को स्थापित करना है जिनका हम इस पाठ्यक्रम में उपयोग करेंगे। हम स्थापना के लिए `pip` का उपयोग करेंगे, जो कि पायथन के लिए पैकेज मैनेजर है। नोटबुक्स में, आप `!` वर्ण से पहले सिस्टम कमांड चला सकते हैं, इसलिए आप ट्रान्सफ़ॉर्मर लाइब्रेरी को निम्नानुसार स्थापित कर सकते हैं: +अगला चरण उन पुस्तकालयों को स्थापित करना है जिनका हम इस पाठ्यक्रम में उपयोग करेंगे। हम स्थापना के लिए `pip` का उपयोग करेंगे, जो कि पायथन के लिए पैकेज मैनेजर है। नोटबुक्स में, आप `!` वर्ण से पहले सिस्टम कमांड चला सकते हैं, इसलिए आप :hugs: ट्रान्सफ़ॉर्मर लाइब्रेरी को निम्नानुसार स्थापित कर सकते हैं: + +``` +!pip install transformers +``` + +आप यह सुनिश्चित कर सकते हैं कि पैकेज आपके पायथन रनटाइम के भीतर आयात करके सही ढंग से स्थापित किया गया है: + +``` +import transformers +``` + +
+ उपरोक्त दो आदेशों का परिणाम दिखाने वाला एक GIF: स्थापना और आयात +
+ +यह :hugs: ट्रांसफॉर्मर का एक बहुत हल्का संस्करण स्थापित करता है। विशेष रूप से, कोई विशिष्ट मशीन लर्निंग फ्रेमवर्क (जैसे PyTorch या TensorFlow) स्थापित नहीं हैं। चूंकि हम पुस्तकालय की कई अलग-अलग विशेषताओं का उपयोग करेंगे, हम विकास संस्करण को स्थापित करने की सलाह देते हैं, जो किसी भी कल्पनाशील उपयोग के मामले के लिए सभी आवश्यक निर्भरताओं के साथ आता है: + +``` +!pip install transformers[sentencepiece] +``` + +इसमें थोड़ा समय लगेगा, लेकिन फिर आप बाकी पाठ्यक्रम के लिए तैयार हो जाएंगे। + +## पायथन आभासी वातावरण का उपयोग करना + +यदि आप एक पायथन आभासी वातावरण का उपयोग करना पसंद करते हैं, तो पहला कदम आपके सिस्टम पर पायथन को स्थापित करना है। हम आरंभ करने के लिए [इस गाइड](https://realpython.com/installing-python/) का पालन करने की सलाह देते हैं। + +एक बार जब आप पायथन स्थापित कर लेते हैं, तो आपको अपने टर्मिनल में पायथन आदेश चलाने में सक्षम होना चाहिए। अगले चरण पर आगे बढ़ने से पहले यह सुनिश्चित करने के लिए कि यह सही ढंग से स्थापित है, आप निम्न आदेश चलाकर प्रारंभ कर सकते हैं: `python --version`. यह आपके सिस्टम पर अब उपलब्ध पायथन संस्करण को प्रिंट करना चाहिए। + +अपने टर्मिनल में पायथन आदेश चलाते समय, जैसे `python --version` आदेश को चलाने वाले प्रोग्राम को अपने सिस्टम में "main" पायथन के रूप में सोचना चाहिए। हम अनुशंसा करते हैं कि इस मुख्य स्थापना को किसी भी पैकेज से मुक्त रखें, और इसका उपयोग प्रत्येक एप्लिकेशन के लिए अलग वातावरण बनाने के लिए करें, जिस पर आप काम कर रहे हैं - इस तरह, प्रत्येक एप्लिकेशन की अपनी निर्भरताएं और पैकेज होंगे, और आपको अन्य एप्लिकेशन के साथ संभावित संगतता समस्याओं के बारे में चिंता करने की आवश्यकता नहीं होगी। + +पायथन में यह [आभासी वातावरण](https://docs.python.org/3/tutorial/venv.html) के साथ किया जाता है, जो स्व-निहित निर्देशिका ट्री हैं जिनमें से प्रत्येक में एक विशेष पायथन संस्करण के साथ एक पायथन स्थापना होती है, जिसमें सभी पैकेजों के साथ एप्लिकेशन की आवश्यकता होती है। इस तरह के आभासी वातावरण का निर्माण कई अलग-अलग उपकरणों के साथ किया जा सकता है, लेकिन हम उस उद्देश्य के लिए आधिकारिक पायथन पैकेज का उपयोग करेंगे, जिसे कहा जाता है [`venv`](https://docs.python.org/3/library/venv.html#module-venv)। + +सबसे पहले, एक निर्देशिका बनाएं जिसमें आप अपने आवेदन में रहना चाहते हैं - उदाहरण के लिए, आप अपनी होम निर्देशिका के मूल में *transformers-course* नामक एक नई निर्देशिका बनाना चाहेंगे: + +``` +mkdir ~/transformers-course +cd ~/transformers-course +``` + +इस निर्देशिका के अंदर, पायथन `venv` मॉड्यूल का उपयोग करके एक आभासी वातावरण बनाएं: + +``` +python3 -m venv .env +``` + +अब आपके पास आपके अन्यथा खाली फ़ोल्डर में *.env* नामक एक निर्देशिका होनी चाहिए: + +``` +ls -a +``` + +```out +. .. .env +``` + +आप 'activate' और 'deactivate' स्क्रिप्ट के साथ अपने आभासी वातावरण में और बाहर कूद सकते हैं: + +``` +# Activate the virtual environment +source .env/bin/activate + +# Deactivate the virtual environment +source .env/bin/deactivate +``` + +आप यह सुनिश्चित कर सकते हैं कि `which python` आदेश चलाकर कौन सा पर्यावरण सक्रिय है: यदि यह आभासी वातावरण की ओर इशारा करता है, तो आपने इसे सफलतापूर्वक सक्रिय कर दिया है! + +``` +which python +``` + +```out +/home//transformers-course/.env/bin/python +``` + +## निर्भरता स्थापित करना + +Google Colab इंस्टेंस का उपयोग करने पर पिछले अनुभाग की तरह, अब आपको जारी रखने के लिए आवश्यक पैकेजों को स्थापित करने की आवश्यकता होगी। फिर से, आप `pip` पैकेज मैनेजर का उपयोग करके :hugs: ट्रांसफॉर्मर के विकास संस्करण को स्थापित कर सकते हैं: + +``` +pip install "transformers[sentencepiece]" +``` + +अब आप पूरी तरह से तैयार हैं! \ No newline at end of file diff --git a/chapters/hi/chapter1/1.mdx b/chapters/hi/chapter1/1.mdx new file mode 100644 index 000000000..3107062cc --- /dev/null +++ b/chapters/hi/chapter1/1.mdx @@ -0,0 +1,51 @@ +# परिचय + +## :hugs: पाठ्यक्रम में आपका स्वागत है! + + + +यह पाठ्यक्रम आपको [Hugging Face](https://huggingface.co) पारिस्थितिकी तंत्र - [:hugs: ट्रान्सफ़ॉर्मर](https://github.com/huggingface/transformers), [:hugs: डेटासेट](https://github.com/huggingface/datasets), [:hugs: टोकनीज़र](https://github.com/huggingface/tokenizers), तथा [:hugs: एक्सेलेरेट](https://github.com/huggingface/accelerate) - इसके साथ ही [हगिंग फेस हब](https://huggingface.co/models) पुस्तकालयों का उपयोग करके प्राकृतिक भाषा प्रसंस्करण (एनएलपी) के बारे में सिखाएगा। यह पूरी तरह से मुफ़्त है और विज्ञापनों के बिना है। + +## क्या उम्मीद करें? + +यहां पाठ्यक्रम का संक्षिप्त विवरण दिया गया है। + +
+ Brief overview of the chapters of the course. + +
+ +- अध्याय 1 से 4 :hugs: ट्रान्सफ़ॉर्मर पुस्तकालय की मुख्य अवधारणाओं का परिचय प्रदान करते हैं। पाठ्यक्रम के इस भाग के अंत तक, आप इस बात से परिचित होंगे कि ट्रांसफार्मर मॉडल कैसे काम करते हैं और [हगिंग फेस हब](https://huggingface.co/models) से मॉडल का उपयोग करना जानते हैं, इसे ठीक करें। डेटासेट पर, और हब पर अपने परिणाम साझा करें! +- अध्याय 5 से 8 क्लासिक एनएलपी कार्यों में गोता लगाने से पहले :hugs: डेटासेट और :hugs: टोकनाइज़र की मूल बातें सिखाते हैं। इस भाग के अंत तक, आप सबसे आम एनएलपी समस्याओं से स्वयं निपटने में सक्षम होंगे। +- अध्याय 9 से 12 एनएलपी से आगे जाते हैं और यह पता लगाते हैं कि भाषा प्रसंस्करण और कंप्यूटर दृष्टि में कार्यों से निपटने के लिए ट्रांसफार्मर मॉडल का उपयोग कैसे किया जा सकता है। साथ ही, आप सीखेंगे कि अपने मॉडलों के डेमो कैसे बनाएं और साझा करें, और उन्हें उत्पादन परिवेशों के लिए अनुकूलित करें। इस भाग के अंत तक, आप (लगभग) किसी भी मशीन सीखने की समस्या के लिए :hugs: ट्रांसफॉर्मर लगाने के लिए तैयार होंगे! + +यह पाठ्यक्रम के लिए: + +* पायथन के अच्छे ज्ञान की आवश्यकता है +* प्रारंभिक गहन शिक्षण पाठ्यक्रम, जैसे [fast.ai के](https://www.fast.ai/) [कोडर्स के लिए प्रैक्टिकल डीप लर्निंग](https://course.fast.ai/) के बाद लेना बेहतर है। +* पूर्व [PyTorch](https://pytorch.org/) या [TensorFlow](https://www.tensorflow.org/) ज्ञान की अपेक्षा नहीं करता है, हालांकि इनमें से किसी के साथ कुछ परिचित होने से मदद मिलेगी। + +आपके द्वारा इस पाठ्यक्रम को पूरा करने के बाद, हम आपको DeepLearning.AI की [प्राकृतिक भाषा संसाधन विशेषज्ञता](https://www.coursera.org/specializations/natural-language-processing?utm_source=deeplearning-ai&utm_medium=institutes&utm_campaign=20211011-nlp-2-hugging_face-page-nlp-refresh) की जाँच करने की सलाह देते हैं। जो पारंपरिक NLP मॉडल जैसे कि Naive Bayes और LSTMs की एक विस्तृत श्रृंखला को कवर करता है, जो अच्छी तरह से जानने योग्य हैं! + +## हम कौन हैं? + +लेखक के बारे में: + +**मैथ्यू कैरिगन** हगिंग फेस में मशीन लर्निंग इंजीनियर हैं। वह डबलिन, आयरलैंड में रहता है, और पहले Parse.ly में एक एमएल इंजीनियर के रूप में काम करता था और उससे पहले ट्रिनिटी कॉलेज डबलिन में पोस्ट-डॉक्टरेट शोधकर्ता के रूप में काम करता था। वह विश्वास नहीं कर सकता कि हम मौजूदा आर्किटेक्चर को स्केल करके एजीआई तक पहुंचने जा रहे हैं, लेकिन रोबोट अमरता की परवाह किए बिना उच्च उम्मीदें हैं। + +**लिसेंड्रे डेब्यू** हगिंग फेस में एक मशीन लर्निंग इंजीनियर है और बहुत प्रारंभिक विकास चरणों के बाद से :hugs: ट्रांसफॉर्मर्स लाइब्रेरी पर काम कर रहा है। उनका उद्देश्य एक बहुत ही सरल एपीआई के साथ उपकरण विकसित करके एनएलपी को सभी के लिए सुलभ बनाना है। + +**सिल्वेन गुगर** हगिंग फेस में एक रिसर्च इंजीनियर हैं और :hugs: ट्रान्सफ़ॉर्मर्स लाइब्रेरी के मुख्य अनुरक्षकों में से एक हैं। पहले वे fast.ai में एक शोध वैज्ञानिक थे, और उन्होंने _[डीप लर्निंग फॉर कोडर्स विद फास्टाई और पायटॉर्च](https://learning.oreilly.com/library/view/deep-learning-for/9781492045519/) का सह-लेखन किया जेरेमी हॉवर्ड के साथ। उनके शोध का मुख्य फोकस तकनीकों को डिजाइन और सुधार करके गहन शिक्षण को और अधिक सुलभ बनाने पर है जो मॉडल को सीमित संसाधनों पर तेजी से प्रशिक्षित करने की अनुमति देता है। + +**मर्व नोयान** हगिंग फेस में एक डेवलपर एडवोकेट है, जो सभी के लिए मशीन लर्निंग का लोकतंत्रीकरण करने के लिए टूल विकसित करने और उनके आसपास सामग्री बनाने पर काम कर रहे है। + +**ल्यूसिले शाॅलनियर** हगिंग फेस में एक मशीन लर्निंग इंजीनियर है, जो ओपन-सोर्स टूल के उपयोग का विकास और समर्थन करता है। वह सहयोगात्मक प्रशिक्षण और बिगसाइंस जैसे प्राकृतिक भाषा प्रसंस्करण के क्षेत्र में कई शोध परियोजनाओं में भी सक्रिय रूप से शामिल हैं। + +**लुईस ट्यूनस्टाल** हगिंग फेस में एक मशीन लर्निंग इंजीनियर है, जो ओपन-सोर्स टूल विकसित करने और उन्हें व्यापक समुदाय के लिए सुलभ बनाने पर केंद्रित है। वह आगामी [ओ'रेली बुक ऑन ट्रांसफॉर्मर्स](https://www.oreilly.com/library/view/natural-language-processing/9781098103231/) के सह-लेखक भी हैं। + +**लिंड्रो वॉन वेरा** हगिंग फेस की ओपन-सोर्स टीम में मशीन लर्निंग इंजीनियर हैं और आगामी [ओ'रेली बुक ऑन ट्रांसफॉर्मर्स](https://www.oreilly.com/library/view/natural-language-processing/9781098103231/) के सह-लेखक भी हैं। पूरे मशीन लर्निंग स्टैक में काम करके एनएलपी परियोजनाओं को उत्पादन में लाने के लिए उनके पास कई वर्षों का औद्योगिक अनुभव है। + +क्या आप तैयार हैं? इस अध्याय में आप सीखेंगे: +* पाठ निर्माण और वर्गीकरण जैसे एनएलपी कार्यों को हल करने के लिए `pipeline()` फ़ंक्शन का उपयोग कैसे करें +* ट्रांसफार्मर आर्किटेक्चर के बारे में +* एन्कोडर, डिकोडर और एन्कोडर-डिकोडर आर्किटेक्चर के बीच अंतर कैसे करें और उपयोग करें From 79fea05bd9fbf1ddfbe3f92f9f67974d0b64f50a Mon Sep 17 00:00:00 2001 From: Bahram Shamshiri Date: Tue, 12 Apr 2022 16:33:26 +0430 Subject: [PATCH 31/73] Chapter 0 Persian Translation First Draft (#95) * merged branch0 into main. no toctree yet. * updated toctree. * Updated the glossary with terms from chapter0. * Second draft in collab w/ @schoobani. Added empty chapter1 for preview. * Glossary typo fix. --- chapters/fa/_toctree.yml | 10 +++ chapters/fa/chapter0/1.mdx | 149 +++++++++++++++++++++++++++++++++++++ chapters/fa/chapter1/1.mdx | 7 ++ chapters/fa/glossary/1.mdx | 85 ++++++++++++++++++--- 4 files changed, 241 insertions(+), 10 deletions(-) create mode 100644 chapters/fa/chapter0/1.mdx create mode 100644 chapters/fa/chapter1/1.mdx diff --git a/chapters/fa/_toctree.yml b/chapters/fa/_toctree.yml index c3b653696..179c9d87a 100644 --- a/chapters/fa/_toctree.yml +++ b/chapters/fa/_toctree.yml @@ -1,3 +1,13 @@ +- title: راه‌اندازی + sections: + - local: chapter0/1 + title: مقدمه + +- title: ۱- مدل‌های ترنسفورمر + sections: + - local: chapter1/1 + title: مقدمه + - title: ۲- بکارگیری ترنسفورمرهای هاگینگ‌فیس sections: - local: chapter2/1 diff --git a/chapters/fa/chapter0/1.mdx b/chapters/fa/chapter0/1.mdx new file mode 100644 index 000000000..d46295940 --- /dev/null +++ b/chapters/fa/chapter0/1.mdx @@ -0,0 +1,149 @@ +
+# مقدمه + + +به دوره‌ی آموزشی هاگینگ‌فیس خوش آمدید! این مقدمه شما را در طی مراحل راه‌اندازی محیط کار راهنمایی می‌کند. اگر تازه این دوره را شروع کرده‌اید، پیشنهاد می‌کنیم ابتدا نگاهی به [فصل اول](/course/chapter1) بیاندازید و سپس به این بخش بازگشته تا محیط کاری را راه‌اندازی کنید و بتوانید خودتان کد را اجرا کنید. + +همه کتابخانه‌هایی که در این دوره‌ی آموزشی استفاده خواهیم کرد، پکیج‌های پایتون هستند. در این بخش می‌بینیم که چگونه باید محیط کار پایتون را راه‌اندازی نموده و کتابخانه‌های مورد نیاز را نصب کنید. + +ما دو شیوه راه‌اندازی محیط کار، یکی استفاده از نوت‌بوک کولَب و دیگری استفاده از محیط مجازی پایتون را نشان خواهیم داد. می‌توانید هرکدام را که می‌خواهید انتخاب کنید. اگر تازه‌کارها هستید، توصیه مؤکد داریم که از نوت‌بوک کولَب استفاده کنید. + +توجه کنید که به محیط ویندوز نخواهیم پرداخت. اگر از ویندوز استفاده می‌کنید توصیه می‌کنیم از نوت‌بوک‌های کولَب استفاده کنید. اگر از سیستم‌عامل مک یا یکی از توزیع‌های لینوکس استفاده می‌کنید می‌توانید هر‌کدام از روش‌هایی که در اینجا ارائه می‌کنیم را دنبال کنید. + +برای طی بخش زیادی از این دوره نیاز به حساب کاربری ‌هاگینگ‌فیس‌ دارید. پیشنهاد می‌کنیم همین الان [حساب خود را بسازید](https://huggingface.co/join). + +

استفاده از نوت‌بوک‌ کولَب گوگل

+ +استفاده از نوت‌بوک کولَب ساده‌ترین راه شروع است. در مرورگر خود نوت‌بوکی جدید باز کرده و بلافاصله شروع به کد زدن کنید! + +اگر با کولَب آشنایی ندارید پیشنهاد می‌کنیم از این [راهنما](https://colab.research.google.com/notebooks/intro.ipynb) استفاده کنید. کولَب به شما امکان استفاده از سخت‌افزار‌‌‌های شتاب‌دهنده مانند GPU یا TPU می‌‌دهد و استفاده از آن برای محاسبات سبک رایگان است. + +وقتی که با محیط کاربری کولَب آشنا شدید، نوت‌بوکی جدید بسازید و مراحل راه‌اندازی را شروع کنید. +
+ +
+An empty colab notebook +
+
+ +قدم اول نصب کتابخانه‌هایی است که در این دوره استفاده خواهیم کرد. برای نصب کتابخانه‌ها از `pip` استفاده می‌کنیم که پکیج‌منیجر پایتون است. در فضای نوت‌بوک، برای اجرای دستورهای سیستمی، کافی است علامت `!` را به ابتدای خط اضافه کنید. برای نصب کتابخانه ترنسفورمرهای هاگینگ‌فیس این دستور را اجرا کنید: + +
+ + ``` + !pip install transformers + ``` + +
+ +برای اطمینان از نصب صحیح این پکیج، آن را ایمپورت کنید: + +
+ + ``` + import transformers + ``` + +
+ +
+
+A gif showing the result of the two commands above: installation and import +
+
+ +این دستور نسخه‌ای بسیار کم حجم از ترنسفورمرهای هاگینگ‌فیس را نصب می‌کند بدون آنکه فریمورک‌ یادگیری ماشین مشخصی مانند پایتورچ یا تنسورفلو را اضافه کند. با توجه به اینکه ما از بسیاری از قابلیت‌های مختلف این کتابخانه استفاده خواهیم کرد، پیشنهاد می‌کنیم نسخه توسعه‌ی این کتابخانه، که حاوی تمام پکیج‌های وابسته برای تقریبا همه مسائل قابل تصور است، را نصب کنید: + +
+ + ``` + !pip install transformers[sentencepiece] + ``` + +
+ +اجرای این فرمان کمی بیشتر طول می‌کشد ولی برای طی بقیه دوره نیازی به نصب پکیج دیگری نخواهید داشت! + +

استفاده از محیط مجازی پایتون

+ +اگر ترجیح می‌دهید از یکی از محیط‌های مجازی پایتون استفاده کنید، اولین مرحله نصب پایتون روی سیستم‌تان است. پیشنهاد می‌کنیم از این [راهنما](https://realpython.com/installing-python/) استفاده کنید. +اگر پایتون را نصب کردید، می‌توانید فرمان‌های پایتون را در ترمینال اجرا کنید. قبل از اینکه به سراغ مراحل بعدی بروید، با اجرای دستور `python --version` از نصب صحیح پایتون مطمئن شوید. این دستور، نسخه‌ی پایتون نصب شده روی سیستم‌تان را نمایش می‌دهد. + + +زمانی که فرمان‌های پایتون را در ترمینال اجرا می کنید، نسخه "اصلی” پایتون روی سیستم خود را درگیر می کنید. توصیه می کنیم این نسخه‌ را تمیز نگه دارید و هیچ پکیج اضافه‌ای روی آن نصب نکنید، بلکه از آن صرفا برای ایجاد محیط‌های مجازی دیگر و برای پروژه‌های مختلف استفاده کنید. با این روش هر پروژه می‌تواند وابستگی‌های مخصوص به خود را داشته‌باشد و دیگر نیازی نیست نگران ناسازگاری‌‌‌های احتمالی میان پکیج‌های نصب شده برای پروژه‌های مختلف باشید. + +این کار در پایتون با استفاده از [محیط‌های مجازی](https://docs.python.org/3/tutorial/venv.html) انجام می‌شود. محیط مجازی، پوشه ای قائم به خود روی فایل‌سیستم است که محتوی نسخه‌ای مشخص از پایتون به همراه تمام پکیج‌های مورد استفاده در پروژه‌ای خاص است. ساخت این پوشه با ابزارهای مختلفی امکان‌پذیر است. ما در اینجا از ابزار رسمی پایتون به نام [`venv`](https://docs.python.org/3/library/venv.html#module-venv) استفاده می‌کنیم. + +ابتدا پوشه‌ای جدید برای پروژه خود ایجاد کنید. برای مثال پوشه‌ای به نام transformers-course زیر پوشه‌ی خانه خودتان در فایل‌سیستم بسازید: + +
+ + ``` + mkdir ~/transformers-course + cd ~/transformers-course + ``` + +
+ +درون این پوشه، با استفاده از ماژول `venv` پایتون، محیط مجازی خود را بسازید: + +
+ + ``` + python -m venv .env + ``` + +
+ +حالا می‌بایست زیر پوشه پروژه شما تنها یک پوشه دیگر به نام .env وجود داشته باشد. + +
+ + ``` + ls -a + . .. .env + ``` + +
+ +برای ورود و خروج از محیط مجازی پروژه خود از اسکریپت‌های activate و deactivate استفاده کنید: + +
+ + ``` + \# Activate the virtual environment + source .env/bin/activate + + \# Deactivate the virtual environment + source .env/bin/deactivate + ``` + +
+ + +‌با اجرای دستور `which python` از فعال شدن محیط مجازی خود اطمینان حاصل کنید. اگر این دستور به آدرس محیط مجازی جدید اشاره کند، با موفقیت این محیط را فعال کرده‌اید. + +
+ + ``` + which python + /home/<user>/transformers-course/.env/bin/python + ``` + +
+ +

نصب وابستگی‌ها

+ +مانند آنچه در بخش استفاده از گوگل کولَب گفتیم، اکنون باید پکیج‌های موردنیاز برای ادامه دوره را نصب کنید. می‌توانید نسخه توسعه‌ی پکیج ترنسفورمرهای هاگینگ‌فیس را با استفاده از پکیج‌منیجر `pip` نصب کنید: + +
+ + ``` + pip install "transformers[sentencepiece]" + ``` + +
+ +شما تمام مراحل راه‌اندازی را طی کرده و آماده شروع دوره هستید! + +
diff --git a/chapters/fa/chapter1/1.mdx b/chapters/fa/chapter1/1.mdx new file mode 100644 index 000000000..03e429b99 --- /dev/null +++ b/chapters/fa/chapter1/1.mdx @@ -0,0 +1,7 @@ +
+# مقدمه + + +به دوره‌ی آموزشی هاگینگ‌فیس خوش آمدید! + +
diff --git a/chapters/fa/glossary/1.mdx b/chapters/fa/glossary/1.mdx index 8f5229155..8587b671b 100644 --- a/chapters/fa/glossary/1.mdx +++ b/chapters/fa/glossary/1.mdx @@ -27,30 +27,95 @@ | Configuration | تنظیمات | | Batch | بتچ | | Model Hub | Model Hub | +| Course | دوره‌ی آموزشی | +| Working Environment | محیط کار | +| Workspace | فضای کار | +| Setup | راه‌اندازی | +| Create | ایجاد یا ساختن | +| Code | کد | +| Package | پکیج‌ | +| Python | پایتون | +| Colab Notebook | نوت‌بوک کولَب | +| Google | گوگل | +| Windows | ویندوز | +| macOS | سیستم‌عامل مک | +| Distribution | توزیع | +| Linux | لینوکس | +| Workload | محاسبه، محاسبات | +| Package Manager | پکیج‌منیجر | +| Command | دستور یا فرمان | +| Feature | قابلیت‌ | +| Development | توسعه نرم‌افزار | +| Dependency | وابسته، وابستگی | +| Virtual Environment | محیط مجازی | +| Terminal | ترمینال | +| Incompatibility | ناسازگاری | +| Self-Contained | قائم به خود یا بدون وابستگی خارجی؟ | +| Script | اسکریپت‌ | +| Feature | قابلیت | +| Folder | پوشه | -Acronyms: +معادل‌هایی که استفاده نمی‌کنیم: -| معادل در منبع | معادل در ترجمه | +| معادل در منبع | معادل اشتباه در ترجمه | |-----------------------|------------------| -| NLP | NLP | -| API | API | +| Application, as in an app and not as in apply | کاربرد | -Convenience Acronyms: +کلمات مخفف: | معادل در منبع | معادل در ترجمه | |-----------------------|------------------| +| NLP | NLP | +| API | API | +| GPU | GPU | +| TPU | TPU | | ML | یادگیری ماشین | + +املای مورد استفاده کلمات فارسی: + +|ارائه| + - * Used in chapter1/page2 to loosely mean 'running' the model. If used anywhere else to exact technical meaning we could go with 'استنتاج' probably? But that sounds archaic to me. -- Don't translate industry-accepted acronyms. -- Translate acronyms used for convenience in English to full Persian form. -- Transliterate brand names to minimize mixing of Persian and English - characters, which makes for a fragmentary text. This should be a Persian text - with some English words sprinkled in, only when really necessary. +- Don't translate industry-accepted acronyms. e.g. TPU or GPU. + +- Translate acronyms used for convenience in English to full Persian form. e.g. ML + +- Keep voice active and consistent. Don't overdo it but try to avoid a passive voice. + +- Refer and contribute to the glossary frequently to stay on top of the latest + choices we make. This minimizes the amount of editing that is required. + +- Keep POV consistent. + +- Smaller sentences are better sentences. Apply with nuance. + +- If translating a technical word, keep the choice of Persian equivalent consistent. + If workspace is mohit-e-kari don't just switch to faza-ye-kari. This ofc + does not apply for non-technical choices, as in those cases variety actually + helps keep the text engaging. + +- This is merely a translation. Don't add any technical/contextual information + not present in the original text. Also don't leave stuff out. The creative + choices in composing this information were the original authors' to make. + Our creative choices are in doing a quality translation. + +- Note on translating indefinite articles(a, an) to Persian. Persian syntax does + not have these. Common problem in translations is using + the equivalent of 'One'("Yek", "Yeki") as a direct word-for-word substitute + which makes for ugly Persian. Be creative with Persian word order to avoid this. + + For example, the sentence "we use a library" should be translated as + "ما از کتابخانه‌ای استفاده می‌کنیم" and not "ما از یک کتابخانه استفاده می‌کنیم". + "Yek" here implies a number(1) to the Persian reader, but the original text + was emphasizing the indefinite nature of the library and not its count. + +- Be exact when choosing equivalents for technical words. Package is package. + Library is library. Don't mix and match. From 35b63781aa4470ec205415dcd24b5c2be9c3d5f3 Mon Sep 17 00:00:00 2001 From: Giyaseddin Bayrak <34009210+giyaseddin@users.noreply.github.com> Date: Tue, 12 Apr 2022 15:06:10 +0300 Subject: [PATCH 32/73] Translation of Chapter0 (setup) to Arabic (#104) * Add AR translation for `introduction` * Fix alignment & format * Add Arabic to CI build --- .github/workflows/build_documentation.yml | 2 +- .github/workflows/build_pr_documentation.yml | 4 +- chapters/ar/_toctree.yml | 4 + chapters/ar/chapter0/1.mdx | 136 +++++++++++++++++++ 4 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 chapters/ar/_toctree.yml create mode 100644 chapters/ar/chapter0/1.mdx diff --git a/.github/workflows/build_documentation.yml b/.github/workflows/build_documentation.yml index a7714c94a..a03061dc8 100644 --- a/.github/workflows/build_documentation.yml +++ b/.github/workflows/build_documentation.yml @@ -14,6 +14,6 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: bn en es fa fr he ko pt ru th tr + languages: ar bn en es fa fr he ko pt ru th tr secrets: token: ${{ secrets.HUGGINGFACE_PUSH }} \ No newline at end of file diff --git a/.github/workflows/build_pr_documentation.yml b/.github/workflows/build_pr_documentation.yml index f7b92f51d..84af57f75 100644 --- a/.github/workflows/build_pr_documentation.yml +++ b/.github/workflows/build_pr_documentation.yml @@ -16,5 +16,5 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: bn en es fa fr he ko pt ru th tr - hub_base_path: https://moon-ci-docs.huggingface.co/course \ No newline at end of file + languages: ar bn en es fa fr he ko pt ru th tr + hub_base_path: https://moon-ci-docs.huggingface.co/course diff --git a/chapters/ar/_toctree.yml b/chapters/ar/_toctree.yml new file mode 100644 index 000000000..b9e6467fd --- /dev/null +++ b/chapters/ar/_toctree.yml @@ -0,0 +1,4 @@ +- title: 0.الإعداد + sections: + - local: chapter0/1 + title: مقدمة diff --git a/chapters/ar/chapter0/1.mdx b/chapters/ar/chapter0/1.mdx new file mode 100644 index 000000000..7951b9d94 --- /dev/null +++ b/chapters/ar/chapter0/1.mdx @@ -0,0 +1,136 @@ +
+ +# مقدمة + +مرحبًا بك في دورة Hugging Face! ستساعدك هذه المقدمة خلال إعداد بيئة العمل. إذا كنت قد بدأت الدورة للتو، فننصحك أولاً بإلقاء نظرة على [الفصل 1](/course/chapter1)، ثم العودة وإعداد بيئتك حتى تتمكن من تجربة الكود بنفسك. + +تتوفر جميع المكتبات التي سنستخدمها في هذه الدورة التدريبية على شكل حزم (Package) Python، لذلك سنوضح لك هنا كيفية إعداد بيئة Python وتثبيت المكتبات المحددة التي ستحتاج إليها. + +سنغطي طريقتين لإعداد بيئة العمل الخاصة بك، باستخدام دفتر Colab أو بيئة Python الافتراضية. لا تتردد في اختيار البيئة التي تناسبك أكثر.نوصي المبتدئين بشدة أن يبدأوا باستخدام دفتر Colab. + +لاحظ أننا لن نغطي نظام Windows. إذا كنت تعمل على نظام Windows، فإننا نوصي بمتابعة استخدام دفتر Colab. إذا كنت تستخدم توزيعة Linux أو macOS، فيمكنك استخدام أي من الطريقتين الموضحتين هنا. + +تعتمد معظم الدورة على امتلاكك لحساب Hugging Face. نوصي بإنشاء حساب الآن: [إنشاء حساب](https://huggingface.co/join). + +## استخدام دفتر Google Colab + +يعد استخدام دفتر Colab أبسط إعداد ممكن؛ فقط قم بتشغيل دفتر Colab في متصفحك ابدأ مباشرة بالبرمجة! + +إذا لم تكن معتادًا على Colab، نوصيك بالبدء باتباع [المقدمة](https://colab.research.google.com/notebooks/intro.ipynb). يتيح لك Colab استخدام بعض أجهزة التسريع، مثل GPUs أو TPUs، وهو مجاني في حال تشغيل مهمات خفيفة. + +بمجرد أن تشعر بالأريحية في التنقل في Colab، أنشئ دفتر ملاحظات جديدًا وابدأ في الإعداد: + +
+An empty colab notebook +
+ +الخطوة التالية هي تثبيت المكتبات التي سنستخدمها في هذه الدورة. سنستخدم `pip` للتثبيت، وهو مدير الحزم لPython. حتى تتمكن من تثبيت مكتبة 🤗 Transformers يمكنك تشغيل أوامر النظام عن طريق تسبقها بالحرف `!` في دفتر Colab, على النحو التالي: + +
+ +``` +!pip install transformers +``` + +
+يمكنك التأكد من تثبيت الحزمة بشكل صحيح عن طريق استيرادها (import) خلال وقت تشغيل Python: +
+ +``` +import transformers +``` + +
+A gif showing the result of the two commands above: installation and import +
+ +
+هذا يثبت نسخة خفيفة جدا من مكتبة 🤗 Transformers. أي أنه لم يتم تثبيت أي إطارات عمل محددة للتعلم الآلي (مثل PyTorch أو TensorFlow). نوصي بتثبيت "إصدار التطوير" للمكتبة لأننا سوف نستخدم الكثير من الميزات المختلفة, و هذا الإصدار يأتي مع جميع التبعيات المطلوبة تقريباً لأي حالة استخدام يمكن تخيلها: + +
+ +``` +!pip install transformers[sentencepiece] +``` + +
+سيستغرق هذا بعض الوقت، لكنك ستكون جاهزًا بعد ذلك لبقية الدورة! + +## استخدام بيئة Python افتراضية + +إذا كنت تفضل استخدام بيئة Python الافتراضية، فإن الخطوة الأولى هي تثبيت Python على نظامك. للبدء, نوصي باتباع [دليل الإرشادات هذا](https://realpython.com/installing-python/). + +بمجرد تثبيت Python، يجب أن تكون قادرًا على تشغيل أوامر Python في الجهاز المستخدم. للتأكد من تثبيته بشكل صحيح قبل المتابعة إلى الخطوات التالية يمكنك البدء بتشغيل الأمر التالي: `python --version`. يجب أن يطبع هذا إصدار Python المتاح الآن على نظامك. + +عند تشغيل أمر Python في الجهاز المستخدم، مثل `python --version`، يجب أن تفكر في البرنامج الذي يقوم بتشغيل الأمر الخاص بك باعتباره Python "الرئيسي" على نظامك. نوصي بالحفاظ على هذا التثبيت الرئيسي خاليًا من أي حزم، واستخدامه لإنشاء بيئات منفصلة لكل تطبيق تعمل عليه, وبهذه الطريقة، يمكن لكل تطبيق أن يكون له تبعيات وحزم خاصة به، ولن تقلق بشأن مشكلات التوافق المحتملة مع تطبيقات أخرى. + +في Python، يتم ذلك باستخدام [* البيئات الافتراضية *](https://docs.python.org/3/tutorial/venv.html)، وهي عبارة عن تفرعات من المجلدات كل منها قائم بحد ذاته, ويحتوي كل منها على Python مثبت بإصدار معين بالإضافة إلى جميع الحزم التي يحتاجها التطبيق. يمكن إنشاء مثل هذه البيئة الافتراضية باستخدام عدد من الأدوات المختلفة ، لكننا سنستخدم حزمة Python الرسمية لهذا الغرض، والتي تسمى [`venv`](https://docs.python.org/3/library/venv.html#module-venv). + +أولاً، قم بإنشاء المجلد الذي تريد أن يتواجد فيه التطبيق الخاص بك -على سبيل المثال، قد ترغب في إنشاء مجلد جديد يسمى *transformers-course* في المجلد الرئيسي للدورة: +
+ +``` +mkdir ~/transformers-course +cd ~/transformers-course +``` + +
+ +من داخل هذا المجلد، أنشئ بيئة افتراضية باستخدام وحدة Python `venv`: + +
+ +``` +python -m venv .env +``` + +
+يجب أن يكون لديك الآن مجلد يسمى *.env* في المجلد الفارغ الخاص بك: +
+ +``` +ls -a +``` + +```out +. .. .env +``` + +
+يمكنك الدخول والخروج من بيئتك الافتراضية باستخدام أوامر "التنشيط" و "إلغاء التنشيط": +
+ +``` +# Activate the virtual environment +source .env/bin/activate + +# Deactivate the virtual environment +source .env/bin/deactivate +``` + +
+يمكنك التأكد من تنشيط البيئة عن طريق تشغيل الأمر `which python`: إذا كان يشير إلى البيئة الافتراضية، فقد قمت بتنشيطها بنجاح! +
+ +``` +which python +``` + +```out +/home//transformers-course/.env/bin/python +``` + +
+ +### تثبيت التبعيات + +كما في القسم السابق حول استخدام مثيلات Google Colab، ستحتاج الآن إلى تثبيت الحزم المطلوبة للمتابعة. مرة أخرى، يمكنك تثبيت إصدار التطوير من 🤗 Transformers باستخدام مدير الحزم `pip`: +
+ +``` +pip install "transformers[sentencepiece]" +``` + +
+أنت الآن جاهز تمامًا للانطلاق! +
From 12a524062d799de6367bc70d65849c436c83f4ae Mon Sep 17 00:00:00 2001 From: Pavel <60391448+pdumin@users.noreply.github.com> Date: Tue, 12 Apr 2022 18:28:57 +0300 Subject: [PATCH 33/73] Russian - Chapter 1 finished (#98) * 01/4 start * 1/4 finished * 1/5 finished * 1/5 update toc * 1/6 finished * 1/7 finished * 1/8 finished * 1/9 finished * 1/4 fix * toc update --- chapters/ru/_toctree.yml | 18 +++- chapters/ru/chapter1/4.mdx | 173 +++++++++++++++++++++++++++++++++++++ chapters/ru/chapter1/5.mdx | 17 ++++ chapters/ru/chapter1/6.mdx | 16 ++++ chapters/ru/chapter1/7.mdx | 16 ++++ chapters/ru/chapter1/8.mdx | 33 +++++++ chapters/ru/chapter1/9.mdx | 12 +++ 7 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 chapters/ru/chapter1/4.mdx create mode 100644 chapters/ru/chapter1/5.mdx create mode 100644 chapters/ru/chapter1/6.mdx create mode 100644 chapters/ru/chapter1/7.mdx create mode 100644 chapters/ru/chapter1/8.mdx create mode 100644 chapters/ru/chapter1/9.mdx diff --git a/chapters/ru/_toctree.yml b/chapters/ru/_toctree.yml index b8a26b63b..895b7475c 100644 --- a/chapters/ru/_toctree.yml +++ b/chapters/ru/_toctree.yml @@ -3,7 +3,7 @@ - local: chapter0/1 title: Введение -- title: 1. Transformer models +- title: 1. Трансформеры sections: - local: chapter1/1 title: Введение @@ -11,8 +11,22 @@ title: Обработка естесственного языка - local: chapter1/3 title: Трансформеры, на что они способны? + - local: chapter1/4 + title: Как работают трансформеры? + - local: chapter1/5 + title: Модели энкодеров + - local: chapter1/6 + title: Модели декодеров + - local: chapter1/7 + title: Модели "seq2seq" + - local: chapter1/8 + title: Предвзятости и ограничения + - local: chapter1/9 + title: Итоги + - title: 2. Использование библиотеки 🤗 Transformers sections: - local: chapter2/1 - title: Введение \ No newline at end of file + title: Введение + diff --git a/chapters/ru/chapter1/4.mdx b/chapters/ru/chapter1/4.mdx new file mode 100644 index 000000000..3c901acd4 --- /dev/null +++ b/chapters/ru/chapter1/4.mdx @@ -0,0 +1,173 @@ +# Как работают трансформеры? + +В этом разделе мы посмотрим в общих чертах на то, как работают трансфореры. + +## Немного истории + +Здесь приведены несколько ссылок на (короткую) историю трансформеров: + +
+A brief chronology of Transformers models. + +
+ +[Архитектура трансформеров](https://arxiv.org/abs/1706.03762) была опубликована в июне 2017. Основной фокус оригинального исследования был сосредоточен на задачах перевода. Эта публикация повлекла за собой несколько влиятельных моделей: + +- **Июнь 2018**: [GPT](https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf), первая предобученная модель, часто используется процедура тонкой настройки (fine-tuning) и применение для различных NLP-задач с последующим получением результатов высокого качества. + +- **Октябрь 2018**: [BERT](https://arxiv.org/abs/1810.04805), другая большая предобученная модель, была разработана для для получения хороших саммаризаций предложений (больше мы узнаем об этом в следующей главе!) + +- **Февраль 2019**: [GPT-2](https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf), улучшенная (и более объемная) версия GPT, которая не была сразу опубликована по этическим соображениям + +- **Октябрь 2019**: [DistilBERT](https://arxiv.org/abs/1910.01108), «дистиллированная» версия BERT, которая на 60% быстрее и на 40% менее объемная, однако сохраняющая 97% производительности BERT + +- **Октябрь 2019**: [BART](https://arxiv.org/abs/1910.13461) and [T5](https://arxiv.org/abs/1910.10683), две больших модели, повторяющие архитектуру классического трансформера + +- **Май 2020**, [GPT-3](https://arxiv.org/abs/2005.14165), еще более крупная версия GPT-2, способная хорошо справляться с различными задачами без необходимости fine-tuning (так называемое _zero-shot learning_) + +Этот список далеко не полный, он всего лишь призван выделить несколько разновидностей моделей трансформеров. +В широком смысле трансформеры могут быть классифицированы на три типа: +- GPT-подобные модели (также часто называемые _авторегрессионные_ трансформеры) +- BERT-подобные модели (также часто называемые _автокодирующие_ трансформеры (_auto-encoding_)) +- тип BART/T5 модели (также часто называются модели класса _последовательность-последовательность_ (_sequence2sequence, seq2seq_)) + +Мы рассмотри эти семейства более глубоко позже. + +## Трансформеры - языковые модели + +Все модели трансформеров, упомянутые выше (GPT, BERT, BART, T5, etc.) обучены как *языковые модели*. Это означает, что они обучены на огромном количестве текста в технике самостоятельного обучения (self-supervised learning). Самостоятельное обучение - это такой способ обучения, в котором цель обучения автоматически вычислятся на основе входных данных. Это означает, что люди не должны размечать данные! + +Такой тип моделей реализует статистическое понимание языка, на котором он был обучен, но он не очень полезен для конкретных практических задач. Из-за этого базовая предварительно обученная модель потом подвергается процедуре, называемой *трансферным обучением*. В ходе этого процесса модель настраивается под конкретные наблюдения, т. е. с размеченными человеком данными конкретной задачи. + +В качестве примера можно привести предсказание следующего слова в предложении на основе *n* предыдущих слов. Это называется *каузальным языковым моделированием*, потому что модель зависит от прошлых и текущих слов, но не от будущих. + + +
+Example of causal language modeling in which the next word from a sentence is predicted. + +
+ +Другой пример - *максированная языковая модель*, которая предсказывает замаскированное слово в предложении. + +
+Example of masked language modeling in which a masked word from a sentence is predicted. + +
+ +## Трансформеры - большие модели + +За исключением нескольких моделей (например, DistilBERT), общий подход к достижению высокого качества заключается в увеличении размера моделей и увеличении количества данных для обучения. + +
+Number of parameters of recent Transformers models +
+ +К сожалению, обучение модели, особенно большой, требует большого количества данных. Это приводит к увеличению времени и вычислительных потребностей. Это воздействует даже на окружающую среду, что можно увидеть графике ниже. + +
+The carbon footprint of a large language model. + +
+ + + +Это продемонстрировано командой разработчиков на примере очень большой модели. Команда сознательно пытающется уменьшить воздействие предобучения на окружающую среду. Углеродный следу от проведения множества экспериментов для получения лучших гиперпараметров будет еще выше. + +Представьте себе, что каждый раз, когда исследовательская группа, студенческая организация или компания хотят обучить модель, они делают это с нуля. Это привело бы к огромным, ненужным глобальным затратам! + +Вот почему совместное использование языковых моделей имеет первостепенное значение: совместное использование обученных весов и построение на основе уже обученных весов снижает общую стоимость вычислений и углеродный след сообщества. + +## Трансферное обучение + + + +*Предобучение* - это процесс обучения модели с нуля: веса модели случайным образом инициализируются, после начинается обучение без предварительных настроек. + +
+The pretraining of a language model is costly in both time and money. + +
+ +Предобучение обычно происходит на огромных наборах данных, сам процесс может занять несколько недель. + +*Fine-tuning*, с другой стороны, это обучение, проведенной *после* того, как модель была предобучена. Для проведения fine-tuning вы сначала должны выбрать предобученную языковую модель, а после провести обучение на данных собственной задачи. Стойте -- почему не обучить модель сразу же на данных конкретной задачи? Этому есть несколько причин: + +* Предобученная модель уже обучена на датасете, который имеет много сходств с датасетом для fine-tuning. Процесс тонкой настройки может использовать знания, которые были получены моделью в процессе предобучения (например, в задачах NLP предварительно обученная модель будет иметь представление о статистических закономерностях языка, который вы используете в своей задаче). + +* Так как предобученная модель уже "видела" много данных, процесс тонкой настройки требует меньшего количества данных для получения приемлемых результатов. + +* По этой же причине требуется и намного меньше времени для получения хороших результатов. + +Например, можно использовать предварительно обученную на английском языке модель, а затем провести ее fine-tuning на корпусе arXiv, в результате чего получится научно-исследовательская модель. Для тонкой настройки потребуется лишь ограниченный объем данных: знания, которые приобрела предварительно обученная модель, «передаются» (осуществляют трансфер), отсюда и термин «трансферное обучение». + +
+The fine-tuning of a language model is cheaper than pretraining in both time and money. + +
+ +Таким образом, тонкая настройка модели требует меньше времени, данных, финансовых и экологических затрат. Также быстрее и проще перебирать различные схемы тонкой настройки, поскольку обучение требует меньше усилий, чем полное предварительное обучение. + +Этот процесс также даст лучшие результаты, чем обучение с нуля (если только у вас нет большого количества данных), поэтому вы всегда должны пытаться использовать предобученную модель — модель, максимально приближенную к поставленной задаче, а потом дообучить ее. + +## Общая архитектура + +В этом разделе мы рассмотрим общую архитектуру модели трансформера. Не беспокойтесь, если вы не понимаете некоторых понятий; далее есть подробные разделы, посвященные каждому из компонентов. + + + +## Введение + +Модель состоит из двух блоков: + +* **Encoder (слева)** (кодировщик, энкодер): энкодер получает входные данные и строит их репрезентацию (формирует признаки). Это означает, модель нацелена на "понимание" входных данных. +* **Декодер (справа)** (декодировщик, декодер): декодер использует репрезентации (признаки) энкодера с другими входными данными для создания нужной последовательности. Это означает, что модель нацелена на генерацию выходных данных. + +
+Architecture of a Transformers models + +
+ +Каждая из этих частей может быть использована отдельно, это зависит от задачи: + +* **Encoder-модели**: полезны для задач, требющих понимания входных данных, таких как классификация предложений и распознавание именованных сущностей. +* **Decoder-модели**: полезны для генеративных задач, таких как генерация текста. +* **Encoder-decoder модели** или **seq2seq-модели**: полезны в генеративных задачах, требущих входных данных. Например: перевод или саммаризация текста. + +Мы изучим эти архитектуры глубже в следующих разделах. + +## Слой внимания или attention + +Ключевой особенностью трансформеров является наличие в архитектуре специального слоя, называемого слоем внимания или attention'ом. Статья, в которой была описана архитектура трансформера, называлась["Attention Is All You Need"](https://arxiv.org/abs/1706.03762) ("Внимание - все, что вам нужно")! Мы изучим детали этого слоя позже. На текущий момент мы сформулируем механизм его работы так: attention-слой помогает модели "обращать внимание" на одни слова в поданном на вход предложении, а другие слова в той или иной степени игнорировать. И это происходит в процессе анализа каждого слова. + +Чтобы поместить это в контекст, рассмотрим задачу перевода текста с английского на французский язык. Для предложения "You like this course", модель должна будет также учитывать соседнее слово "You", чтобы получить правильный перевод слова "like", потому что во французском языке глагол "like" спрягается по-разному в зависимости от подлежащего. Однако остальная часть предложения бесполезна для перевода этого слова. В том же духе при переводе "like" также необходимо будет обратить внимание на слово "course", потому что "this" переводится по-разному в зависимости от того, стоит ли ассоциированное существительное в мужском или женском роде. Опять же, другие слова в предложении не будут иметь значения для перевода "this". С более сложными предложениями (и более сложными грамматическими правилами) модели потребуется уделять особое внимание словам, которые могут оказаться дальше в предложении, чтобы правильно перевести каждое слово. + +Такая же концепция применима к любой задаче, связанной с обработкой естесственного языка: слово само по себе имеет некоторое значение, однако значение очень часто зависит от контекста, которым может являться слово (или слова), стоящие вокруг искомого слова. + +Теперь, когда вы знакомы с идеей attention в целом, посмотрим поближе на архитектуру всего трансформера. + +## Первоначальная архитектура + +Архитектура трансформера изначально была разработана для перевода. Во время обучения энкодер получает входные данные (предложения) на определенном языке, а декодер получает те же предложения на желаемом целевом языке. В энкодере слои внимания могут использовать все слова в предложении (поскольку, как мы только что видели, перевод данного слова может зависеть от того, что в предложении находится после и перед ним). Декодер, в свою очерель, работает последовательно и может обращать внимание только на слова в предложении, которые он уже перевел (то есть только на слова перед генерируемым в данный момент словом). Например, когда мы предсказали первые три слова переведенной цели, мы передаем их декодеру, который затем использует все входные данные энкодера, чтобы попытаться предсказать четвертое слово. + +Чтобы ускорить процесс во время обучения (когда модель имеет доступ к целевым предложениям), декодер получает целевое предложение полностью, но ему не разрешается использовать будущие слова (если он имел доступ к слову в позиции 2 при попытке предсказать слово на позиции 2, задача не будет сложной!). Например, при попытке предсказать четвертое слово уровень внимания будет иметь доступ только к словам в позициях с 1 по 3. + +Первоначальная архитектура Transformer выглядела так: энкодер слева и декодер справа: + +
+Architecture of a Transformers models + +
+ +Обратите внимание, что первый уровень внимания в блоке декодера обращает внимание на все (прошлые) входные данные декодера, а второй уровень внимания использует выходные данные первого энкодера. Таким образом, он может получить доступ ко всему входному предложению, чтобы наилучшим образом предсказать текущее слово. Это очень полезно, так как разные языки могут иметь грамматические правила, которые располагают слова в разном порядке, или некоторый контекст, предоставленный в предложении далеко от текущего слова. Конекст может быть полезен для определения наилучшего перевода данного слова. + +*Attention-mask* (маска внимания) также может использоваться в энкодере/декодере, чтобы модель не обращала внимания на некоторые специальные слова — например, специальное несуществующее слово-заполнитель (служебный токен), используемое для придания всем входным данным одинаковой длины при группировке предложений. + +## Архитектуры и контрольные точки + +По мере погружения в трансформеры, вы будете встречать термины *архитектуры* и *контрольные точки* (checkpoints) в смысле *модели*. Эти термины имеют разный смысл: + +**Архитектура** - скелет модели -- слои, связи и операции, которые выполняются в модели. +**Контрольная точка** - веса модели, которые могут быть загружены для конкретной архитектуры. +**Модель** - зонтичный термин, который может означать и архитектуру, и веса для конкретной архитектуры. В этом курсе мы будем точнее использовать термины *архитектуры* и *чекпоинт*, если это будет важно для лучшего понимания. + +Например, BERT - это архитектура, а `bert-base-cased` - набор весов, подготовленный Google к первому выпуску BERT'а, - это чекпоинт. Однако можно сказать и "модель BERT", и "модель bert-base-cased". diff --git a/chapters/ru/chapter1/5.mdx b/chapters/ru/chapter1/5.mdx new file mode 100644 index 000000000..7e4dc8b1a --- /dev/null +++ b/chapters/ru/chapter1/5.mdx @@ -0,0 +1,17 @@ +# Модели энкодеров + + + +Энкодеры используют только компонент кодировщика трансформера. На каждом этапе слой внимания может использовать все слова исходного предложения. Эти модели часто характеризуют как имеющие двунаправленное внимание ("bi-directional attention"), и часто называют моделями *автоэнкодеров*. + +Предварительное обучение этих моделей обычно заключаетс в том, чтобы как-то исказить данное предложение (например, путем маскировки в нем случайных слов) и поставить перед моделью задачу найти или восстановить исходное предложение. + +Энкодеры лучше всего подходят для задач, требующих _понимания_ всего предложения, таких как классификация предложений, распознавание именованных сущностей (и, в более общем смысле, классификация слов) и ответы на вопросы с извлечением информации из контекста. + +К представителям этого семейства моделей относятся: + +- [ALBERT](https://huggingface.co/transformers/model_doc/albert.html) +- [BERT](https://huggingface.co/transformers/model_doc/bert.html) +- [DistilBERT](https://huggingface.co/transformers/model_doc/distilbert.html) +- [ELECTRA](https://huggingface.co/transformers/model_doc/electra.html) +- [RoBERTa](https://huggingface.co/transformers/model_doc/roberta.html) diff --git a/chapters/ru/chapter1/6.mdx b/chapters/ru/chapter1/6.mdx new file mode 100644 index 000000000..d9ca11089 --- /dev/null +++ b/chapters/ru/chapter1/6.mdx @@ -0,0 +1,16 @@ +# Модели декодеров + + + +Декодировщики используют только компонент декодер трансформера. На каждом этапе для текущего слова слой внимания может получить доступ только к словам, которые были расположены до текущего в предложении. Такие модели часто называются *авторегрессионными моделями*. + +Процесс предобучения декодеров обычно заключается в предсказании следующего слова в предложении. ё + +Такие модели лучше всего подходят для задач, связанных с генерацией текста. + +Представителями этого семейства моделей являются: + +- [CTRL](https://huggingface.co/transformers/model_doc/ctrl.html) +- [GPT](https://huggingface.co/transformers/model_doc/gpt.html) +- [GPT-2](https://huggingface.co/transformers/model_doc/gpt2.html) +- [Transformer XL](https://huggingface.co/transformers/model_doc/transformerxl.html) diff --git a/chapters/ru/chapter1/7.mdx b/chapters/ru/chapter1/7.mdx new file mode 100644 index 000000000..730b8f96f --- /dev/null +++ b/chapters/ru/chapter1/7.mdx @@ -0,0 +1,16 @@ +# Модели вида "seq2seq" + + + +Энкодер-декодер модели (также называемые *sequence-to-sequence models*) используют обе части трансформера. На каждом этапе слой внимания энкодера получает доступ ко всем словам в исходной последовательности, тогда как слой внимания декодера получает доступ только к тем словам, которые позиционированы до текущего слова. + +Предобучение таких моделей может быть проведено по аналогии с процессом предобучения энкодера или декодера, но обычно это происходит сложнее. Например, модель [T5](https://huggingface.co/t5-base) была предобучена путем замены случайных фрагментов текста (фрагменты могут содержать несколько слов) на специальную маску, цель модели - предсказать текст, который заменила маска. + +Модели seq2seq лучше всего подходят для задач генерации новых предложений, зависящих от входного массива данных, например: саммаризация текста, перевод или генерация ответов на вопросы. + +Представителями этого семейства являются: + +- [BART](https://huggingface.co/transformers/model_doc/bart.html) +- [mBART](https://huggingface.co/transformers/model_doc/mbart.html) +- [Marian](https://huggingface.co/transformers/model_doc/marian.html) +- [T5](https://huggingface.co/transformers/model_doc/t5.html) diff --git a/chapters/ru/chapter1/8.mdx b/chapters/ru/chapter1/8.mdx new file mode 100644 index 000000000..05d3b724d --- /dev/null +++ b/chapters/ru/chapter1/8.mdx @@ -0,0 +1,33 @@ +# Предвзятости и ограничения + + + +Если вы намерены использовать предварительно обученную модель или точно настроенную версию в рабочей среде, имейте в виду, что, хотя эти модели являются мощными инструментами, они имеют ограничения. Самая большая из них заключается в том, что для предварительной подготовки на больших объемах данных исследователи часто очищают весь контент, который они могут найти, беря как лучшее, так и худшее из того, что доступно в Интернете. + +Для иллюстрации вернемся к примеру пайплайна `fill-mask` с моделью BERT: + +```python +from transformers import pipeline + +unmasker = pipeline("fill-mask", model="bert-base-uncased") +result = unmasker("This man works as a [MASK].") +print([r["token_str"] for r in result]) + +result = unmasker("This woman works as a [MASK].") +print([r["token_str"] for r in result]) +``` + +```python out +['lawyer', 'carpenter', 'doctor', 'waiter', 'mechanic'] +['nurse', 'waitress', 'teacher', 'maid', 'prostitute'] +``` + +На просьбу вставить пропущенное слово в этих двух предложениях модель дает только один ответ без гендерной принадлежности (официант/официантка). Другие рабочие профессии обычно ассоциируются с одним конкретным полом — и да, проститутка попала в топ-5 вариантов, которые модель ассоциирует с "женщиной" и "работой". Это происходит даже несмотря на то, что BERT — одна из редких моделей трансформеров, созданная не путем сбора данных со всего Интернета, а с использованием явно нейтральных данных (он обучен на [английской Википедии](https://huggingface.co/datasets/wikipedia) и наборе данных [BookCorpus](https://huggingface.co/datasets/bookcorpus). + +Поэтому, когда вы используете эти инструменты, вам нужно помнить, что исходная модель, которую вы используете, может очень легко генерировать сексистский, расистский или гомофобный контент. Тонкая настройка модели на ваших данных не избавит вас от этой внутренней предвзятости. + diff --git a/chapters/ru/chapter1/9.mdx b/chapters/ru/chapter1/9.mdx new file mode 100644 index 000000000..730712e4e --- /dev/null +++ b/chapters/ru/chapter1/9.mdx @@ -0,0 +1,12 @@ +# Итоги + +В этой главе вы увидели, как подходить к различным задачам NLP, используя высокоуровневую функцию `pipeline()` из библиотеки 🤗 Transformers. Вы также увидели, как искать и использовать модели в Hub, а также как использовать Inference API для тестирования моделей прямо в браузере. + +Мы обсудили, как трансформеры работают на высоком уровне, и поговорили о важности трансферного обучения и тонкой настройки. Ключевым аспектом является то, что вы можете использовать всю архитектуру или только энкодер или декодер, в зависимости от того, какую задачу вы хотите решить. Следующая таблица резюмирует это: + + +| Модель | Примеры | Задачи | +|-----------------|--------------------------------------------|----------------------------------------------------------------------------------| +| Энкодер | ALBERT, BERT, DistilBERT, ELECTRA, RoBERTa | Классификация предложений, распознавание именованных сущностей, генерация ответов на вопросы с извлечением информации | +| Декодер | CTRL, GPT, GPT-2, Transformer XL | Генерация текста | +| Энкодер-декодер | BART, T5, Marian, mBART | Саммаризация, перевод, генеративный подход к ответам на вопросы | From e812f74222691502f6e4bfba041bc855889dd866 Mon Sep 17 00:00:00 2001 From: 1375626371 <40328311+1375626371@users.noreply.github.com> Date: Wed, 13 Apr 2022 17:58:59 +0800 Subject: [PATCH 34/73] Chinese - Chapter 1 finished (#113) * Chinese - Chapter 1 finished * Add zh to the languages field Co-authored-by: petrichor1122 <87262598+petrichor1122@users.noreply.github.com> Co-authored-by: zhlhyx <95976146+zhlhyx@users.noreply.github.com> --- .github/workflows/build_documentation.yml | 2 +- .github/workflows/build_pr_documentation.yml | 2 +- chapters/zh/_toctree.yml | 23 ++ chapters/zh/chapter1/1.mdx | 52 ++++ chapters/zh/chapter1/10.mdx | 253 ++++++++++++++++ chapters/zh/chapter1/2.mdx | 20 ++ chapters/zh/chapter1/3.mdx | 287 +++++++++++++++++++ chapters/zh/chapter1/4.mdx | 172 +++++++++++ chapters/zh/chapter1/5.mdx | 17 ++ chapters/zh/chapter1/6.mdx | 17 ++ chapters/zh/chapter1/7.mdx | 16 ++ chapters/zh/chapter1/8.mdx | 31 ++ chapters/zh/chapter1/9.mdx | 11 + 13 files changed, 901 insertions(+), 2 deletions(-) create mode 100644 chapters/zh/_toctree.yml create mode 100644 chapters/zh/chapter1/1.mdx create mode 100644 chapters/zh/chapter1/10.mdx create mode 100644 chapters/zh/chapter1/2.mdx create mode 100644 chapters/zh/chapter1/3.mdx create mode 100644 chapters/zh/chapter1/4.mdx create mode 100644 chapters/zh/chapter1/5.mdx create mode 100644 chapters/zh/chapter1/6.mdx create mode 100644 chapters/zh/chapter1/7.mdx create mode 100644 chapters/zh/chapter1/8.mdx create mode 100644 chapters/zh/chapter1/9.mdx diff --git a/.github/workflows/build_documentation.yml b/.github/workflows/build_documentation.yml index a03061dc8..8e0f0b7e9 100644 --- a/.github/workflows/build_documentation.yml +++ b/.github/workflows/build_documentation.yml @@ -14,6 +14,6 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: ar bn en es fa fr he ko pt ru th tr + languages: ar bn en es fa fr he ko pt ru th tr zh secrets: token: ${{ secrets.HUGGINGFACE_PUSH }} \ No newline at end of file diff --git a/.github/workflows/build_pr_documentation.yml b/.github/workflows/build_pr_documentation.yml index 84af57f75..ff5039db9 100644 --- a/.github/workflows/build_pr_documentation.yml +++ b/.github/workflows/build_pr_documentation.yml @@ -16,5 +16,5 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: ar bn en es fa fr he ko pt ru th tr + languages: ar bn en es fa fr he ko pt ru th tr zh hub_base_path: https://moon-ci-docs.huggingface.co/course diff --git a/chapters/zh/_toctree.yml b/chapters/zh/_toctree.yml new file mode 100644 index 000000000..453fc5e99 --- /dev/null +++ b/chapters/zh/_toctree.yml @@ -0,0 +1,23 @@ +- title: 1. Transformer 模型 + sections: + - local: chapter1/1 + title: 章节简介 + - local: chapter1/2 + title: 自然语言处理 + - local: chapter1/3 + title: Transformers能做什么? + - local: chapter1/4 + title: Transformers 是如何工作的? + - local: chapter1/5 + title: 编码器模型 + - local: chapter1/6 + title: 解码器模型 + - local: chapter1/7 + title: 序列到序列模型 + - local: chapter1/8 + title: 偏见和局限性 + - local: chapter1/9 + title: 总结 + - local: chapter1/10 + title: 章末小测验 + quiz: 1 \ No newline at end of file diff --git a/chapters/zh/chapter1/1.mdx b/chapters/zh/chapter1/1.mdx new file mode 100644 index 000000000..68e6a14c7 --- /dev/null +++ b/chapters/zh/chapter1/1.mdx @@ -0,0 +1,52 @@ +# 简介 + +## 欢迎来到🤗课程 + + + +本课程将使用 Hugging Face 生态系统中的库——🤗 Transformers、🤗 Datasets、🤗 Tokenizers 和 🤗 Accelerate——以及 Hugging Face Hub 教你自然语言处理 (NLP)。它是完全免费的,并且没有广告。 + + +## 有什么是值得期待的? + +以下是课程的简要概述: + +
+Brief overview of the chapters of the course. + +
+ +- 第 1 章到第 4 章介绍了 🤗 Transformers 库的主要概念。在本课程的这一部分结束时,您将熟悉 Transformer 模型的工作原理,并将了解如何使用 [Hugging Face Hub](https://huggingface.co/models) 中的模型,在数据集上对其进行微调,并在 Hub 上分享您的结果。 +- 第 5 章到第 8 章在深入研究经典 NLP 任务之前,教授 🤗 Datasets和 🤗 Tokenizers的基础知识。在本部分结束时,您将能够自己解决最常见的 NLP 问题。 +- 第 9 章到第 12 章更加深入,探讨了如何使用 Transformer 模型处理语音处理和计算机视觉中的任务。在此过程中,您将学习如何构建和分享模型,并针对生产环境对其进行优化。在这部分结束时,您将准备好将🤗 Transformers 应用于(几乎)任何机器学习问题! + +这个课程: + +* 需要良好的 Python 知识 +* 最好先学习深度学习入门课程,例如[DeepLearning.AI](https://www.deeplearning.ai/) 提供的 [fast.ai实用深度学习教程](https://course.fast.ai/) +* 不需要事先具备 [PyTorch](https://pytorch.org/) 或 [TensorFlow](https://www.tensorflow.org/) 知识,虽然熟悉其中任何一个都会对huggingface的学习有所帮助 + +完成本课程后,我们建议您查看 [DeepLearning.AI的自然语言处理系列课程](https://www.coursera.org/specializations/natural-language-processing?utm_source=deeplearning-ai&utm_medium=institutions&utm_campaign=20211011-nlp-2-hugging_face-page-nlp-refresh),其中涵盖了广泛的传统 NLP 模型,如朴素贝叶斯和 LSTM,这些模型非常值得了解! + +## 我们是谁? + +关于作者: + +**Matthew Carrigan** 是 Hugging Face 的机器学习工程师。他住在爱尔兰都柏林,之前在 Parse.ly 担任机器学习工程师,在此之前,他在Trinity College Dublin担任博士后研究员。他不相信我们会通过扩展现有架构来实现 AGI,但无论如何都对机器人充满希望。 + +**Lysandre Debut** 是 Hugging Face 的机器学习工程师,从早期的开发阶段就一直致力于 🤗 Transformers 库。他的目标是通过使用非常简单的 API 开发工具,让每个人都可以使用 NLP。 + +**Sylvain Gugger** 是 Hugging Face 的一名研究工程师,也是 🤗Transformers库的核心维护者之一。此前,他是 fast.ai 的一名研究科学家,他与Jeremy Howard 共同编写了[Deep Learning for Coders with fastai and Py Torch](https://learning.oreilly.com/library/view/deep-learning-for/9781492045519/)。他的主要研究重点是通过设计和改进允许模型在有限资源上快速训练的技术,使深度学习更容易普及。 + +**Merve Noyan** 是 Hugging Face 的开发者倡导者,致力于开发工具并围绕它们构建内容,以使每个人的机器学习平民化。 + +**Lucile Saulnier** 是 Hugging Face 的机器学习工程师,负责开发和支持开源工具的使用。她还积极参与了自然语言处理领域的许多研究项目,例如协作训练和 BigScience。 + +**Lewis Tunstall** 是 Hugging Face 的机器学习工程师,专注于开发开源工具并使更广泛的社区可以使用它们。他也是即将出版的一本书[O’Reilly book on Transformers](https://www.oreilly.com/library/view/natural-language-processing/9781098103231/)的作者之一。 + +**Leandro von Werra** 是 Hugging Face 开源团队的机器学习工程师,也是即将出版的一本书[O’Reilly book on Transformers](https://www.oreilly.com/library/view/natural-language-processing/9781098103231/)的作者之一。他拥有多年的行业经验,通过在整个机器学习堆栈中工作,将 NLP 项目投入生产。 + +你准备好了吗?在本章中,您将学习: +* 如何使用 `pipeline()` 函数解决文本生成、分类等NLP任务 +* 关于 Transformer 架构 +* 如何区分编码器、解码器和编码器-解码器架构和用例 diff --git a/chapters/zh/chapter1/10.mdx b/chapters/zh/chapter1/10.mdx new file mode 100644 index 000000000..23f768115 --- /dev/null +++ b/chapters/zh/chapter1/10.mdx @@ -0,0 +1,253 @@ + + +# 章末小测试 + +这一章涵盖了很多内容! 如果有一些不太明白的地方,请不要担心; 下一章将帮助你了解这些模块在底层是如何工作的。 + +让我们来测试一下你在这一章学到了什么! + +### 1. 探索 Hub 并寻找 `roberta-large-mnli` checkpoint。 它可以完成什么类型的任务? + + +roberta-large-mnli 页面回顾一下." + }, + { + text: "文本分类", + explain: "更准确地说,它对两个句子在三个标签(矛盾、无关、相近)之间的逻辑链接进行分类——这项任务也称为自然语言推理.", + correct: true + }, + { + text: "文本生成", + explain: "点击前往roberta-large-mnli 页面回顾一下." + } + ]} +/> + +### 2. 下面的代码将会返回什么结果? + +```py +from transformers import pipeline + +ner = pipeline("ner", grouped_entities=True) +ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") +``` + +sentiment-analysis pipeline将会返回这些." + }, + { + text: "它将返回一个生成的文本来完成这句话。", + explain: "这个选项是不对的 — text-generation pipeline将会返回这些.", + }, + { + text: "它将返回代表人员、组织或位置的单词。", + explain: "此外,使用 grouped_entities=True,它会将属于同一实体的单词组合在一起,例如“Hugging Face”。", + correct: true + } + ]} +/> + +### 3. 在此代码示例中...的地方应该填写什么? + +```py +from transformers import pipeline + +filler = pipeline("fill-mask", model="bert-base-cased") +result = filler("...") +``` + + has been waiting for you.", + explain: "这个选项是不对的。 请查看 bert-base-cased 模型卡片,然后再尝试找找错在哪里。" + }, + { + text: "This [MASK] has been waiting for you.", + explain: "正解! 这个模型的mask的掩码是[MASK].", + correct: true + }, + { + text: "This man has been waiting for you.", + explain: "这个选项是不对的。 这个pipeline的作用是填充经过mask的文字,因此它需要在输入的文本中存在mask的token。" + } + ]} +/> + +### 4. 为什么这段代码会无法运行? + +```py +from transformers import pipeline + +classifier = pipeline("zero-shot-classification") +result = classifier("This is a course about the Transformers library") +``` + +candidate_labels=[...].", + correct: true + }, + { + text: "这个pipeline需要多个句子,而不仅仅是一个。", + explain: "这个选项是不对的。尽管正确使用时,此pipeline可以同时处理多个句子(与所有其他pipeline一样)。" + }, + { + text: "像往常一样,🤗 Transformers库出故障了。", + explain: "对此,我们不予置评!" + }, + { + text: "该pipeline需要更长的输入; 这个句子太短了。", + explain: "这个选项是不对的。 不过请注意,在这个pipeline处理时,太长的文本将被截断。" + } + ]} +/> + +### 5. “迁移学习”是什么意思? + + + +### 6. 语言模型在预训练时通常不需要标签,这样的说法是否正确。 + + +自监督,这意味着标签是根据输入自动创建的(例如:预测下一个单词或填充一些[MARSK]单词)。", + correct: true + }, + { + text: "错误", + explain: "这不是一个正确的答案。" + } + ]} +/> + + +### 7. 选择最能描述“模型(model)”、“架构(architecture)”和“权重(weights)”的句子。 + + + +### 8. 你将使用以下哪种类型的模型来根据输入的提示生成文本? + + + +### 9. 你会使用哪些类型的模型来生成文本的摘要? + + + +### 10. 你会使用哪一种类型的模型来根据特定的标签对文本输入进行分类? + + + +### 11. 模型中观察到的偏见有哪些可能的来源? + + diff --git a/chapters/zh/chapter1/2.mdx b/chapters/zh/chapter1/2.mdx new file mode 100644 index 000000000..1b5ee0ea6 --- /dev/null +++ b/chapters/zh/chapter1/2.mdx @@ -0,0 +1,20 @@ +# 自然语言处理 + +在进入 Transformer 模型之前,让我们快速概述一下自然语言处理是什么以及我们为什么这么重视它。 + +## 什么是自然语言处理? + +NLP 是语言学和机器学习交叉领域,专注于理解与人类语言相关的一切。 NLP 任务的目标不仅是单独理解单个单词,而且是能够理解这些单词的上下文。 + +以下是常见 NLP 任务的列表,每个任务都有一些示例: + +- **对整个句子进行分类**: 获取评论的情绪,检测电子邮件是否为垃圾邮件,确定句子在语法上是否正确或两个句子在逻辑上是否相关 +- **对句子中的每个词进行分类**: 识别句子的语法成分(名词、动词、形容词)或命名实体(人、地点、组织) +- **生成文本内容**: 用自动生成的文本完成提示,用屏蔽词填充文本中的空白 +- **从文本中提取答案**: 给定问题和上下文,根据上下文中提供的信息提取问题的答案 +- **从输入文本生成新句子**: 将文本翻译成另一种语言,总结文本 + +NLP 不仅限于书面文本。它还解决了语音识别和计算机视觉中的复杂挑战,例如生成音频样本的转录或图像描述。 +## 为什么具有挑战性? + +计算机处理信息的方式与人类不同。例如,当我们读到“我饿了”这句话时,我们很容易理解它的意思。同样,给定两个句子,例如“我很饿”和“我很伤心”,我们可以轻松确定它们的相似程度。对于机器学习 (ML) 模型,此类任务更加困难。文本需要以一种使模型能够从中学习的方式进行处理。而且由于语言很复杂,我们需要仔细考虑必须如何进行这种处理。关于如何表示文本已经做了很多研究,我们将在下一章中介绍一些方法。 \ No newline at end of file diff --git a/chapters/zh/chapter1/3.mdx b/chapters/zh/chapter1/3.mdx new file mode 100644 index 000000000..076263ba4 --- /dev/null +++ b/chapters/zh/chapter1/3.mdx @@ -0,0 +1,287 @@ +# Transformers能做什么? + + + +在本节中,我们将看看 Transformer 模型可以做什么,并使用 🤗 Transformers 库中的第一个工具:pipeline() 函数。 + +👀 看到那个右上角的 在Colab中打开的按钮了吗? 单击它就可以打开一个包含本节所有代码示例的 Google Colab 笔记本。 每一个有实例代码的小节都会有它。 + +如果您想在本地运行示例,我们建议您查看准备. + + +## Transformer被应用于各个方面! +Transformer 模型用于解决各种 NLP 任务,就像上一节中提到的那样。以下是一些使用 Hugging Face 和 Transformer 模型的公司和组织,他们也通过分享他们的模型回馈社区: + +![使用 Hugging Face 的公司](https://huggingface.co/course/static/chapter1/companies.PNG) +[🤗 Transformers 库](https://github.com/huggingface/transformers)提供了创建和使用这些共享模型的功能。[模型中心(hub)](https://huggingface.co/models)包含数千个任何人都可以下载和使用的预训练模型。您还可以将自己的模型上传到 Hub! + + +⚠️ Hugging Face Hub 不限于 Transformer 模型。任何人都可以分享他们想要的任何类型的模型或数据集!创建一个 Huggingface.co 帐户(https://huggingface.co/join)以使用所有可用功能! + + +在深入研究 Transformer 模型的底层工作原理之前,让我们先看几个示例,看看它们如何用于解决一些有趣的 NLP 问题。 + +## 使用pipelines + + +(这里有一个视频,但是国内可能打不开,译者注) + + +🤗 Transformers 库中最基本的对象是 **pipeline()** 函数。它将模型与其必要的预处理和后处理步骤连接起来,使我们能够通过直接输入任何文本并获得最终的答案: + +```python +from transformers import pipeline + +classifier = pipeline("sentiment-analysis") +classifier("I've been waiting for a HuggingFace course my whole life.") +``` +```python out +[{'label': 'POSITIVE', 'score': 0.9598047137260437}] +``` + + +我们也可以多传几句! +```python +classifier( + ["I've been waiting for a HuggingFace course my whole life.", "I hate this so much!"] +) +``` +```python out +[{'label': 'POSITIVE', 'score': 0.9598047137260437}, + {'label': 'NEGATIVE', 'score': 0.9994558095932007}] +``` +默认情况下,此pipeline选择一个特定的预训练模型,该模型已针对英语情感分析进行了微调。创建**分类器**对象时,将下载并缓存模型。如果您重新运行该命令,则将使用缓存的模型,无需再次下载模型。 + +将一些文本传递到pipeline时涉及三个主要步骤: + +1. 文本被预处理为模型可以理解的格式。 +2. 预处理的输入被传递给模型。 +3. 模型处理后输出最终人类可以理解的结果。 + +目前[可用的一些pipeline](https://huggingface.co/transformers/main_classes/pipelines.html)是: + +* **特征提取**(获取文本的向量表示) +* **填充空缺** +* **ner**(命名实体识别) +* **问答** +* **情感分析** +* **文本摘要** +* **文本生成** +* **翻译** +* **零样本分类** + +让我们来看看其中的一些吧! + +## 零样本分类 +我们将首先处理一项非常具挑战性的任务,我们需要对尚未标记的文本进行分类。这是实际项目中的常见场景,因为注释文本通常很耗时并且需要领域专业知识。对于这项任务**zero-shot-classification**pipeline非常强大:它允许您直接指定用于分类的标签,因此您不必依赖预训练模型的标签。下面的模型展示了如何使用这两个标签将句子分类为正面或负面——但也可以使用您喜欢的任何其他标签集对文本进行分类。 + +```python +from transformers import pipeline + +classifier = pipeline("zero-shot-classification") +classifier( + "This is a course about the Transformers library", + candidate_labels=["education", "politics", "business"], +) +``` +```python out +{'sequence': 'This is a course about the Transformers library', + 'labels': ['education', 'business', 'politics'], + 'scores': [0.8445963859558105, 0.111976258456707, 0.043427448719739914]} +``` + +此pipeline称为zero-shot,因为您不需要对数据上的模型进行微调即可使用它。它可以直接返回您想要的任何标签列表的概率分数! + +✏️**快来试试吧!**使用您自己的序列和标签,看看模型的行为。 + + +## 文本生成 +现在让我们看看如何使用pipeline来生成一些文本。这里的主要使用方法是您提供一个提示,模型将通过生成剩余的文本来自动完成整段话。这类似于许多手机上的预测文本功能。文本生成涉及随机性,因此如果您没有得到相同的如下所示的结果,这是正常的。 + +```python +from transformers import pipeline + +generator = pipeline("text-generation") +generator("In this course, we will teach you how to") +``` +```python out +[{'generated_text': 'In this course, we will teach you how to understand and use ' + 'data flow and data interchange when handling user data. We ' + 'will be working with one or more of the most commonly used ' + 'data flows — data flows of various types, as seen by the ' + 'HTTP'}] +``` +您可以使用参数 **num_return_sequences** 控制生成多少个不同的序列,并使用参数 **max_length** 控制输出文本的总长度。 + + +✏️**快来试试吧!**使用 num_return_sequences 和 max_length 参数生成两个句子,每个句子 15 个单词。 + + +## 在pipeline中使用 Hub 中的其他模型 +前面的示例使用了默认模型,但您也可以从 Hub 中选择特定模型以在特定任务的pipeline中使用 - 例如,文本生成。转到[模型中心(hub)](https://huggingface.co/models)并单击左侧的相应标签将会只显示该任务支持的模型。[例如这样](https://huggingface.co/models?pipeline_tag=text-generation)。 + +让我们试试 [**distilgpt2**](https://huggingface.co/distilgpt2) 模型吧!以下是如何在与以前相同的pipeline中加载它: + +```python +from transformers import pipeline + +generator = pipeline("text-generation", model="distilgpt2") +generator( + "In this course, we will teach you how to", + max_length=30, + num_return_sequences=2, +) +``` +```python out +[{'generated_text': 'In this course, we will teach you how to manipulate the world and ' + 'move your mental and physical capabilities to your advantage.'}, + {'generated_text': 'In this course, we will teach you how to become an expert and ' + 'practice realtime, and with a hands on experience on both real ' + 'time and real'}] +``` +您可以通过单击语言标签来筛选搜索结果,然后选择另一种文本生成模型的模型。模型中心(hub)甚至包含支持多种语言的多语言模型。 + +通过单击选择模型后,您会看到有一个小组件,可让您直接在线试用。通过这种方式,您可以在下载之前快速测试模型的功能。 + +✏️**快来试试吧!**使用标签筛选查找另一种语言的文本生成模型。使用小组件测试并在pipeline中使用它! + + +## 推理 API +所有模型都可以使用 Inference API 直接通过浏览器进行测试,该 API 可在 [Hugging Face 网站](https://huggingface.co/)上找到。通过输入自定义文本并观察模型的输出,您可以直接在此页面上使用模型。 + +小组件形式的推理 API 也可作为付费产品使用,如果您的工作流程需要它,它会派上用场。有关更多详细信息,请参阅[定价页面](https://huggingface.co/pricing)。 + +## Mask filling +您将尝试的下一个pipeline是 **fill-mask**。此任务的想法是填充给定文本中的空白: +```python +from transformers import pipeline + +unmasker = pipeline("fill-mask") +unmasker("This course will teach you all about models.", top_k=2) +``` +```python out +[{'sequence': 'This course will teach you all about mathematical models.', + 'score': 0.19619831442832947, + 'token': 30412, + 'token_str': ' mathematical'}, + {'sequence': 'This course will teach you all about computational models.', + 'score': 0.04052725434303284, + 'token': 38163, + 'token_str': ' computational'}] +``` +**top_k** 参数控制要显示的结果有多少种。请注意,这里模型填充了特殊的< **mask** >词,它通常被称为掩码标记。其他掩码填充模型可能有不同的掩码标记,因此在探索其他模型时要验证正确的掩码字是什么。检查它的一种方法是查看小组件中使用的掩码。 + + +✏️**快来试试吧!**在 Hub 上搜索基于 bert 的模型并在推理 API 小组件中找到它的掩码。这个模型对上面pipeline示例中的句子预测了什么? + + +## 命名实体识别 +命名实体识别 (NER) 是一项任务,其中模型必须找到输入文本的哪些部分对应于诸如人员、位置或组织之类的实体。让我们看一个例子: +```python +from transformers import pipeline + +ner = pipeline("ner", grouped_entities=True) +ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") +``` +```python out +[{'entity_group': 'PER', 'score': 0.99816, 'word': 'Sylvain', 'start': 11, 'end': 18}, + {'entity_group': 'ORG', 'score': 0.97960, 'word': 'Hugging Face', 'start': 33, 'end': 45}, + {'entity_group': 'LOC', 'score': 0.99321, 'word': 'Brooklyn', 'start': 49, 'end': 57} +] +``` +在这里,模型正确地识别出 Sylvain 是一个人 (PER),Hugging Face 是一个组织 (ORG),而布鲁克林是一个位置 (LOC)。 + +我们在pipeline创建函数中传递选项 **grouped_entities=True** 以告诉pipeline将对应于同一实体的句子部分重新组合在一起:这里模型正确地将“Hugging”和“Face”分组为一个组织,即使名称由多个词组成。事实上,正如我们即将在下一章看到的,预处理甚至会将一些单词分成更小的部分。例如,**Sylvain** 分割为了四部分:**S、##yl、##va** 和 **##in**。在后处理步骤中,pipeline成功地重新组合了这些部分。 + + +✏️**快来试试吧!**在模型中心(hub)搜索能够用英语进行词性标注(通常缩写为 POS)的模型。这个模型对上面例子中的句子预测了什么? + + +## 问答系统 +问答pipeline使用来自给定上下文的信息回答问题: +```python +from transformers import pipeline + +question_answerer = pipeline("question-answering") +question_answerer( + question="Where do I work?", + context="My name is Sylvain and I work at Hugging Face in Brooklyn", +) +``` +```python out +{'score': 0.6385916471481323, 'start': 33, 'end': 45, 'answer': 'Hugging Face'} +klyn", +) + +``` +请注意,此pipeline通过从提供的上下文中提取信息来工作;它不会凭空生成答案。 + +## 文本摘要 +文本摘要是将文本缩减为较短文本的任务,同时保留文本中的主要(重要)信息。下面是一个例子: + +```python +from transformers import pipeline + +summarizer = pipeline("summarization") +summarizer( + """ + America has changed dramatically during recent years. Not only has the number of + graduates in traditional engineering disciplines such as mechanical, civil, + electrical, chemical, and aeronautical engineering declined, but in most of + the premier American universities engineering curricula now concentrate on + and encourage largely the study of engineering science. As a result, there + are declining offerings in engineering subjects dealing with infrastructure, + the environment, and related issues, and greater concentration on high + technology subjects, largely supporting increasingly complex scientific + developments. While the latter is important, it should not be at the expense + of more traditional engineering. + + Rapidly developing economies such as China and India, as well as other + industrial countries in Europe and Asia, continue to encourage and advance + the teaching of engineering. Both China and India, respectively, graduate + six and eight times as many traditional engineers as does the United States. + Other industrial countries at minimum maintain their output, while America + suffers an increasingly serious decline in the number of engineering graduates + and a lack of well-educated engineers. +""" +) +``` +```python out +[{'summary_text': ' America has changed dramatically during recent years . The ' + 'number of engineering graduates in the U.S. has declined in ' + 'traditional engineering disciplines such as mechanical, civil ' + ', electrical, chemical, and aeronautical engineering . Rapidly ' + 'developing economies such as China and India, as well as other ' + 'industrial countries in Europe and Asia, continue to encourage ' + 'and advance engineering .'}] +``` +与文本生成一样,您指定结果的 **max_length** 或 **min_length**。 + +## 翻译 +对于翻译,如果您在任务名称中提供语言对(例如“**translation_en_to_fr**”),则可以使用默认模型,但最简单的方法是在[模型中心(hub)](https://huggingface.co/models)选择要使用的模型。在这里,我们将尝试从法语翻译成英语: + +```python +from transformers import pipeline + +translator = pipeline("translation", model="Helsinki-NLP/opus-mt-fr-en") +translator("Ce cours est produit par Hugging Face.") +``` +```python out +[{'translation_text': 'This course is produced by Hugging Face.'}] + +``` + +与文本生成和摘要一样,您可以指定结果的 **max_length** 或 **min_length**。 + + + +✏️**快来试试吧!**搜索其他语言的翻译模型,尝试将前一句翻译成几种不同的语言。 + + + +到目前为止显示的pipeline主要用于演示目的。它们是为特定任务而编程的,不能对他们进行自定义的修改。在下一章中,您将了解 **pipeline()** 函数内部的内容以及如何进行自定义的修改。 \ No newline at end of file diff --git a/chapters/zh/chapter1/4.mdx b/chapters/zh/chapter1/4.mdx new file mode 100644 index 000000000..45641e71e --- /dev/null +++ b/chapters/zh/chapter1/4.mdx @@ -0,0 +1,172 @@ +# Transformers 是如何工作的? + +在本节中,我们将深入了解 Transformer 模型的架构。 + +## 一点Transformers的发展历史 + +以下是 Transformer 模型(简短)历史中的一些关键节点: + +
+A brief chronology of Transformers models. + +
+ +[Transformer 架构](https://arxiv.org/abs/1706.03762) 于 2017 年 6 月推出。原本研究的重点是翻译任务。随后推出了几个有影响力的模型,包括 + +- **2018 年 6 月**: [GPT](https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf), 第一个预训练的 Transformer 模型,用于各种 NLP 任务并获得极好的结果 + +- **2018 年 10 月**: [BERT](https://arxiv.org/abs/1810.04805), 另一个大型预训练模型,该模型旨在生成更好的句子摘要(下一章将详细介绍!) + +- **2019 年 2 月**: [GPT-2](https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf), GPT 的改进(并且更大)版本,由于道德问题没有立即公开发布 + +- **2019 年 10 月**: [DistilBERT](https://arxiv.org/abs/1910.01108), BERT 的提炼版本,速度提高 60%,内存减轻 40%,但仍保留 BERT 97% 的性能 + +- **2019 年 10 月**: [BART](https://arxiv.org/abs/1910.13461) 和 [T5](https://arxiv.org/abs/1910.10683), 两个使用与原始 Transformer 模型相同架构的大型预训练模型(第一个这样做) + +- **2020 年 5 月**, [GPT-3](https://arxiv.org/abs/2005.14165), GPT-2 的更大版本,无需微调即可在各种任务上表现良好(称为零样本学习) + +这个列表并不全面,只是为了突出一些不同类型的 Transformer 模型。大体上,它们可以分为三类: + +- GPT-like (也被称作自回归Transformer模型) +- BERT-like (也被称作自动编码Transformer模型) +- BART/T5-like (也被称作序列到序列的 Transformer模型) + +稍后我们将更深入地探讨这些分类。 + +## Transformers是语言模型 + +上面提到的所有 Transformer 模型(GPT、BERT、BART、T5 等)都被训练为语言模型。这意味着他们已经以无监督学习的方式接受了大量原始文本的训练。无监督学习是一种训练类型,其中目标是根据模型的输入自动计算的。这意味着不需要人工来标记数据! + +这种类型的模型可以对其训练过的语言进行统计理解,但对于特定的实际任务并不是很有用。因此,一般的预训练模型会经历一个称为*迁移学习*的过程。在此过程中,模型在给定任务上以监督方式(即使用人工注释标签)进行微调。 + +任务的一个例子是阅读 *n* 个单词的句子,预测下一个单词。这被称为因果语言建模,因为输出取决于过去和现在的输入。 + +
+Example of causal language modeling in which the next word from a sentence is predicted. + +
+ +另一个例子是*遮罩语言建模*,该模型预测句子中的遮住的词。 + +
+Example of masked language modeling in which a masked word from a sentence is predicted. + +
+ +## Transformer是大模型 + +除了一些特例(如 DistilBERT)外,实现更好性能的一般策略是增加模型的大小以及预训练的数据量。 + +
+Number of parameters of recent Transformers models +
+ +不幸的是,训练模型,尤其是大型模型,需要大量的数据,时间和计算资源。它甚至会对环境产生影响,如下图所示。 + +
+The carbon footprint of a large language model. + +
+ + + +Transformers是由一个团队领导的(非常大的)模型项目,该团队试图减少预训练对环境的影响,通过运行大量试验以获得最佳超参数。 + +想象一下,如果每次一个研究团队、一个学生组织或一家公司想要训练一个模型,都从头开始训练的。这将导致巨大的、不必要的浪费! + +这就是为什么共享语言模型至关重要:共享经过训练的权重,当遇见新的需求时在预训练的权重之上进行微调,可以降低训练模型训练的算力和时间消耗,降低全球的总体计算成本和碳排放。 + + +## 迁移学习 + + + +*预训练是*训练模型前的一个操作:随机初始化权重,在没有任何先验知识的情况下开始训练。 + +
+The pretraining of a language model is costly in both time and money. + +
+ +这种预训练通常是在非常大量的数据上进行的。因此,它需要大量的数据,而且训练可能需要几周的时间。 + +另一方面,*微调*是在模型经过预训练后完成的训练。要执行微调,首先需要获取一个经过预训练的语言模型,然后使用特定于任务的数据集执行额外的训练。等等,为什么不直接为最后的任务而训练呢?有几个原因: + +* 预训练模型已经在与微调数据集有一些相似之处的数据集上进行了训练。因此,微调过程能够利用模型在预训练期间获得的知识(例如,对于NLP问题,预训练模型将对您在任务中使用的语言有某种统计规律上的理解)。 +* 由于预训练模型已经在大量数据上进行了训练,因此微调需要更少的数据来获得不错的结果。 +* 出于同样的原因,获得好结果所需的时间和资源要少得多 + +例如,可以利用英语的预训练过的模型,然后在arXiv语料库上对其进行微调,从而形成一个基于科学/研究的模型。微调只需要有限的数据量:预训练模型获得的知识可以“迁移”到目标任务上,因此被称为*迁移学习*。 + +
+The fine-tuning of a language model is cheaper than pretraining in both time and money. + +
+ +因此,微调模型具有较低的时间、数据、财务和环境成本。迭代不同的微调方案也更快、更容易,因为与完整的预训练相比,训练的约束更少。 + +这个过程也会比从头开始的训练(除非你有很多数据)取得更好的效果,这就是为什么你应该总是尝试利用一个预训练的模型--一个尽可能接近你手头的任务的模型--并对其进行微调。 + +## 一般的体系结构 +在这一部分,我们将介绍Transformer模型的一般架构。如果你不理解其中的一些概念,不要担心;下文将详细介绍每个组件。 + + + +## 介绍 + +该模型主要由两个块组成: + +* **Encoder (左侧)**: 编码器接收输入并构建其表示(其特征)。这意味着对模型进行了优化,以从输入中获得理解。 +* **Decoder (右侧)**: 解码器使用编码器的表示(特征)以及其他输入来生成目标序列。这意味着该模型已针对生成输出进行了优化。 + +
+Architecture of a Transformers models + +
+ +这些部件中的每一个都可以独立使用,具体取决于任务: + +* **Encoder-only models**: 适用于需要理解输入的任务,如句子分类和命名实体识别。 +* **Decoder-only models**: 适用于生成任务,如文本生成。 +* **Encoder-decoder models** 或者 **sequence-to-sequence models**: 适用于需要根据输入进行生成的任务,如翻译或摘要。 + +在后面的部分中,我们将单独地深入研究这些体系结构。 + +## 注意力层 + +Transformer模型的一个关键特性是*注意力层*。事实上,介绍Transformer架构的文章的标题是[“注意力就是你所需要的”](https://arxiv.org/abs/1706.03762)! 我们将在课程的后面更加深入地探索注意力层;现在,您需要知道的是,这一层将告诉模型在处理每个单词的表示时,要特别重视您传递给它的句子中的某些单词(并且或多或少地忽略其他单词)。 + +把它放在语境中,考虑将文本从英语翻译成法语的任务。在输入“You like this course”的情况下,翻译模型还需要注意相邻的单词“You”,以获得单词“like”的正确翻译,因为在法语中,动词“like”的变化取决于主题。然而,句子的其余部分对于该词的翻译没有用处。同样,在翻译“this”时,模型也需要注意“course”一词,因为“this”的翻译不同,取决于相关名词是单数还是复数。同样,句子中的其他单词对于“this”的翻译也不重要。对于更复杂的句子(以及更复杂的语法规则),模型需要特别注意可能出现在句子中更远位置的单词,以便正确地翻译每个单词。 + +同样的概念也适用于与自然语言相关的任何任务:一个词本身有一个含义,但这个含义受语境的影响很大,语境可以是研究该词之前或之后的任何其他词(或多个词)。 + +现在您已经了解了注意力层的含义,让我们更仔细地了解Transformer架构。 + +## 原始的结构 + +Transformer架构最初是为翻译而设计的。在训练期间,编码器接收特定语言的输入(句子),而解码器需要输出对应语言的翻译。在编码器中,注意力层可以使用一个句子中的所有单词(正如我们刚才看到的,给定单词的翻译可以取决于它在句子中的其他单词)。然而,解码器是按顺序工作的,并且只能注意它已经翻译过的句子中的单词。例如,当我们预测了翻译目标的前三个单词时,我们将它们提供给解码器,然后解码器使用编码器的所有输入来尝试预测第四个单词。 + +为了在训练过程中加快速度(当模型可以访问目标句子时),解码器会被输入整个目标,但不允许获取到要翻译的单词(如果它在尝试预测位置2的单词时可以访问位置2的单词,解码器就会偷懒,直接输出那个单词,从而无法学习到正确的语言关系!)。例如,当试图预测第4个单词时,注意力层只能获取位置1到3的单词。 + +最初的Transformer架构如下所示,编码器位于左侧,解码器位于右侧: + +
+Architecture of a Transformers models + +
+ +注意,解码器块中的第一个注意力层关联到解码器的所有(过去的)输入,但是第二注意力层使用编码器的输出。因此,它可以访问整个输入句子,以最好地预测当前单词。这是非常有用的,因为不同的语言可以有语法规则将单词按不同的顺序排列,或者句子后面提供的一些上下文可能有助于确定给定单词的最佳翻译。 + +也可以在编码器/解码器中使用*注意力遮罩层*,以防止模型注意某些特殊单词。例如,在批处理句子时,填充特殊词使所有句子的长度一致。 + +## 架构与参数 + +在本课程中,当我们深入探讨Transformers模型时,您将看到 +架构、参数和模型 +。 这些术语的含义略有不同: + +* **架构**: 这是模型的骨架 -- 每个层的定义以及模型中发生的每个操作。 +* **Checkpoints**: 这些是将在给架构中结构中加载的权重。 +* **模型**: 这是一个笼统的术语,没有“架构”或“参数”那么精确:它可以指两者。为了避免歧义,本课程使用将使用架构和参数。 + +例如,BERT是一个架构,而 `bert-base-cased`, 这是谷歌团队为BERT的第一个版本训练的一组权重参数,是一个参数。我们可以说“BERT模型”和"`bert-base-cased`模型." diff --git a/chapters/zh/chapter1/5.mdx b/chapters/zh/chapter1/5.mdx new file mode 100644 index 000000000..7aa765ec2 --- /dev/null +++ b/chapters/zh/chapter1/5.mdx @@ -0,0 +1,17 @@ +# “编码器”模型 + + + +“编码器”模型指仅使用编码器的Transformer模型。在每个阶段,注意力层都可以获取初始句子中的所有单词。这些模型通常具有“双向”注意力,被称为自编码模型。 + +这些模型的预训练通常围绕着以某种方式破坏给定的句子(例如:通过随机遮盖其中的单词),并让模型寻找或重建给定的句子。 + +“编码器”模型最适合于需要理解完整句子的任务,例如:句子分类、命名实体识别(以及更普遍的单词分类)和阅读理解后回答问题。 + +该系列模型的典型代表有: + +- [ALBERT](https://huggingface.co/transformers/model_doc/albert.html) +- [BERT](https://huggingface.co/transformers/model_doc/bert.html) +- [DistilBERT](https://huggingface.co/transformers/model_doc/distilbert.html) +- [ELECTRA](https://huggingface.co/transformers/model_doc/electra.html) +- [RoBERTa](https://huggingface.co/transformers/model_doc/roberta.html) diff --git a/chapters/zh/chapter1/6.mdx b/chapters/zh/chapter1/6.mdx new file mode 100644 index 000000000..2de4c44a6 --- /dev/null +++ b/chapters/zh/chapter1/6.mdx @@ -0,0 +1,17 @@ +# “解码器”模型 + + + +“解码器”模型通常指仅使用解码器的Transformer模型。在每个阶段,对于给定的单词,注意力层只能获取到句子中位于将要预测单词前面的单词。这些模型通常被称为自回归模型。 + +“解码器”模型的预训练通常围绕预测句子中的下一个单词进行。 + +这些模型最适合于涉及文本生成的任务。 + +该系列模型的典型代表有: + + +- [CTRL](https://huggingface.co/transformers/model_doc/ctrl.html) +- [GPT](https://huggingface.co/transformers/model_doc/gpt.html) +- [GPT-2](https://huggingface.co/transformers/model_doc/gpt2.html) +- [Transformer XL](https://huggingface.co/transformers/model_doc/transformerxl.html) diff --git a/chapters/zh/chapter1/7.mdx b/chapters/zh/chapter1/7.mdx new file mode 100644 index 000000000..99dc00eea --- /dev/null +++ b/chapters/zh/chapter1/7.mdx @@ -0,0 +1,16 @@ +# 序列到序列模型 + + + +编码器-解码器模型(也称为序列到序列模型)同时使用Transformer架构的编码器和解码器两个部分。在每个阶段,编码器的注意力层可以访问初始句子中的所有单词,而解码器的注意力层只能访问位于输入中将要预测单词前面的单词。 + +这些模型的预训练可以使用训练编码器或解码器模型的方式来完成,但通常涉及更复杂的内容。例如,[T5](https://huggingface.co/t5-base)通过将文本的随机跨度(可以包含多个单词)替换为单个特殊单词来进行预训练,然后目标是预测该掩码单词替换的文本。 + +序列到序列模型最适合于围绕根据给定输入生成新句子的任务,如摘要、翻译或生成性问答。 + +该系列模型的典型代表有: + +- [BART](https://huggingface.co/transformers/model_doc/bart.html) +- [mBART](https://huggingface.co/transformers/model_doc/mbart.html) +- [Marian](https://huggingface.co/transformers/model_doc/marian.html) +- [T5](https://huggingface.co/transformers/model_doc/t5.html) diff --git a/chapters/zh/chapter1/8.mdx b/chapters/zh/chapter1/8.mdx new file mode 100644 index 000000000..707731892 --- /dev/null +++ b/chapters/zh/chapter1/8.mdx @@ -0,0 +1,31 @@ +# Bias and limitations + + + +如果您打算在正式的项目中使用经过预训练或经过微调的模型。请注意:虽然这些模型是很强大,但它们也有局限性。其中最大的一个问题是,为了对大量数据进行预训练,研究人员通常会搜集所有他们能找到的内容,中间可能夹带一些意识形态或者价值观的刻板印象。 + +为了快速解释清楚这个问题,让我们回到一个使用BERT模型的pipeline的例子: + +```python +from transformers import pipeline + +unmasker = pipeline("fill-mask", model="bert-base-uncased") +result = unmasker("This man works as a [MASK].") +print([r["token_str"] for r in result]) + +result = unmasker("This woman works as a [MASK].") +print([r["token_str"] for r in result]) +``` + +```python out +['lawyer', 'carpenter', 'doctor', 'waiter', 'mechanic'] +['nurse', 'waitress', 'teacher', 'maid', 'prostitute'] +``` +当要求模型填写这两句话中缺少的单词时,模型给出的答案中,只有一个与性别无关(服务员/女服务员)。其他职业通常与某一特定性别相关,妓女最终进入了模型中与“女人”和“工作”相关的前五位。尽管BERT是使用经过筛选和清洗后,明显中立的数据集上建立的的Transformer模型,而不是通过从互联网上搜集数据(它是在[Wikipedia 英文](https://huggingface.co/datasets/wikipedia)和[BookCorpus](https://huggingface.co/datasets/bookcorpus)数据集)。 + +因此,当您使用这些工具时,您需要记住,使用的原始模型的时候,很容易生成性别歧视、种族主义或恐同内容。这种固有偏见不会随着微调模型而使消失。 \ No newline at end of file diff --git a/chapters/zh/chapter1/9.mdx b/chapters/zh/chapter1/9.mdx new file mode 100644 index 000000000..16c5ab6ad --- /dev/null +++ b/chapters/zh/chapter1/9.mdx @@ -0,0 +1,11 @@ +# 总结 + +在本章中,您了解了如何使用来自🤗Transformers的函数pipeline()处理不同的NLP任务。您还了解了如何在模型中心(hub)中搜索和使用模型,以及如何使用推理API直接在浏览器中测试模型。 + +我们讨论了Transformer模型如何在应用层上工作,并讨论了迁移学习和微调的重要性。您可以使用完整的体系结构,也可以仅使用编码器或解码器,具体取决于您要解决的任务类型。下表总结了这一点: + +| 模型 | 示例 | 任务| +| ---- | ---- |----| +| 编码器 | ALBERT, BERT, DistilBERT, ELECTRA, RoBERTa |句子分类、命名实体识别、从文本中提取答案| +| 解码器 | CTRL, GPT, GPT-2, Transformer XL |文本生成| +| 编码器-解码器 | BART, T5, Marian, mBART |文本摘要、翻译、生成问题的回答| \ No newline at end of file From 98cc578ee3bce68a3c8d6bf23ace17556bf92de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gustavo=20A=2E=20Amorim?= Date: Wed, 13 Apr 2022 10:57:07 -0300 Subject: [PATCH 35/73] [PT] Translation of chapter 2 (#107) * add PT translate to 2.1 * add PT translate to 2.2 * add portuguese translation to 2.3 * WIP portuguese translation to 2.4 * add portuguese translation to 2.4 * add portuguese translation to 2.5 * add portuguese translation to 2.6 * add _toctree infos Co-authored-by: lewtun --- chapters/pt/_toctree.yml | 19 ++ chapters/pt/chapter2/1.mdx | 20 +++ chapters/pt/chapter2/2.mdx | 354 +++++++++++++++++++++++++++++++++++++ chapters/pt/chapter2/3.mdx | 229 ++++++++++++++++++++++++ chapters/pt/chapter2/4.mdx | 248 ++++++++++++++++++++++++++ chapters/pt/chapter2/5.mdx | 340 +++++++++++++++++++++++++++++++++++ chapters/pt/chapter2/6.mdx | 167 +++++++++++++++++ chapters/pt/chapter2/7.mdx | 13 ++ chapters/pt/chapter2/8.mdx | 305 ++++++++++++++++++++++++++++++++ 9 files changed, 1695 insertions(+) create mode 100644 chapters/pt/chapter2/1.mdx create mode 100644 chapters/pt/chapter2/2.mdx create mode 100644 chapters/pt/chapter2/3.mdx create mode 100644 chapters/pt/chapter2/4.mdx create mode 100644 chapters/pt/chapter2/5.mdx create mode 100644 chapters/pt/chapter2/6.mdx create mode 100644 chapters/pt/chapter2/7.mdx create mode 100644 chapters/pt/chapter2/8.mdx diff --git a/chapters/pt/_toctree.yml b/chapters/pt/_toctree.yml index 00b2efaf4..dd1bb1a5f 100644 --- a/chapters/pt/_toctree.yml +++ b/chapters/pt/_toctree.yml @@ -2,3 +2,22 @@ sections: - local: chapter0/1 title: Introdução +- title: 2. Usando 🤗 Transformers + sections: + - local: chapter2/1 + title: Introdução + - local: chapter2/2 + title: Por dentro da função pipeline + - local: chapter2/3 + title: Modelos + - local: chapter2/4 + title: Tokenizers + - local: chapter2/5 + title: Tratando sequências múltiplas + - local: chapter2/6 + title: Colocando tudo junto + - local: chapter2/7 + title: Uso básico concluído! + - local: chapter2/8 + title: Questionário de fim de capítulo + quiz: 2 diff --git a/chapters/pt/chapter2/1.mdx b/chapters/pt/chapter2/1.mdx new file mode 100644 index 000000000..4bc8850d5 --- /dev/null +++ b/chapters/pt/chapter2/1.mdx @@ -0,0 +1,20 @@ +# Introdução + +Como você viu no [Capitulo 1](/course/pt/chapter1), normalmente modelos Transformers são muito grandes. Com milhões a dezenas de *bilhões* de parâmetros, o treinamento e o deploy destes modelos é uma tarefa complicado. Além disso, com novos modelos sendo lançados quase diariamente e cada um tendo sua própria implementação, experimentá-los a todos não é tarefa fácil. + +A biblioteca 🤗 Transformers foi criado para resolver este problema. Seu objetivo é fornecer uma API única através do qual qualquer modelo Transformer possa ser carregado, treinado e salvo. As principais características da biblioteca são: + +- **Fácil de usar**: Baixar, carregar e usar um modelo de processamento natural de linguagem (PNL) de última geração para inferência pode ser feito em apenas duas linhas de código +- **Flexibilidade**: Em sua essência, todos os modelos são uma simples classe PyTorch `nn.Module` ou TensorFlow `tf.keras.Model` e podem ser tratadas como qualquer outro modelo em seus respectivos frameworks de machine learning (ML). +- **Simplicidade**: Quase nenhuma abstração é feita em toda a biblioteca. O "Tudo em um arquivo" é um conceito principal: o "passe para frente" de um modelo é inteiramente definido em um único arquivo, de modo que o código em si seja compreensível e hackeável. + +Esta última característica torna 🤗 Transformers bem diferente de outras bibliotecas ML que modelos e/ou configurações são compartilhados entre arquivos; em vez disso, cada modelo tem suas próprias camadas. Além de tornar os modelos mais acessíveis e compreensíveis, isto permite que você experimente facilmente um modelo sem afetar outros. + +Este capítulo começará com um exemplo de ponta a ponta onde usamos um modelo e um tokenizer juntos para replicar a função `pipeline()` introduzida no [Capitulo 1](/course/pt/chapter1). A seguir, discutiremos o modelo da API: onde veremos profundamente as classes de modelo e configuração, além de mostrar como carregar um modelo e como ele processa as entradas numéricas para as previsões de saída. + +Depois veremos a API do tokenizer, que é o outro componente principal da função `pipeline()`. Os Tokenizers cuidam da primeira e da última etapa do processamento, cuidando da conversão de texto para entradas numéricas para a rede neural, e da conversão de volta ao texto quando for necessário. Por fim, mostraremos a você como lidar com o envio de várias frases através de um modelo em um batch preparado, depois olharemos tudo mais atentamente a função de alto nível `tokenizer()`. + + + +⚠️ Para beneficiar-se de todos os recursos disponíveis com o Model Hub e 🤗 Transformers, recomendamos criar uma conta. + \ No newline at end of file diff --git a/chapters/pt/chapter2/2.mdx b/chapters/pt/chapter2/2.mdx new file mode 100644 index 000000000..88c9a068e --- /dev/null +++ b/chapters/pt/chapter2/2.mdx @@ -0,0 +1,354 @@ + + +# Por dentro da função pipeline + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + + +Esta é a primeira seção onde o conteúdo é ligeiramente diferente, dependendo se você usa PyTorch e TensorFlow. Para selecionar a plataforma que você prefere, basta alterar no botão no topo. + + +{#if fw === 'pt'} + +{:else} + +{/if} + +Vamos começar com um exemplo completo, dando uma olhada no que acontece dentro da função quando executamos o seguinte código no [Capítulo 1](/course/pt/chapter1): + +```python +from transformers import pipeline + +classifier = pipeline("sentiment-analysis") +classifier( + [ + "I've been waiting for a HuggingFace course my whole life.", + "I hate this so much!", + ] +) +``` + +tendo o resultado: + +```python out +[{'label': 'POSITIVE', 'score': 0.9598047137260437}, + {'label': 'NEGATIVE', 'score': 0.9994558095932007}] +``` + +Como visto no [Capítulo 1](/course/pt/chapter1), este pipeline agrupa os três passos: o pré-processamento, passagem das entradas através do modelo, e o pós-processamento: + +
+O pipeline NLP completa: tokenização do texto, conversão para IDs, e inferência através do Transformer e pela 'cabeça' do modelo. + +
+ +Vamos rever rapidamente cada um deles. + +## Pré-processamento com o tokenizer + +Como outras redes neurais, os Transformers não podem processar texto bruto diretamente, portanto, o primeiro passo do nosso pipeline é converter as entradas de texto em números que o modelo possa fazer sentido. Para fazer isso, usamos um *tokenizer*, que será responsável por: + +- Dividir a entrada em palavras, sub-palavras ou símbolos (como pontuação) que são chamados de *tokens*. +- Mapeando cada ficha para um número inteiro +- Adicionando entradas adicionais que podem ser úteis ao modelo + +Todo esse pré-processamento precisa ser feito exatamente da mesma forma que quando o modelo foi pré-treinado, então precisamos primeiro baixar essas informações do [Model Hub](https://huggingface.co/models). Para isso, utilizamos a classe `AutoTokenizer` e seu método `from_pretrained()`. Utilizando o nome do ponto de verificação de nosso modelo, ele irá buscar automaticamente os dados associados ao tokenizer do modelo e armazená-los em cache (portanto, ele só é baixado na primeira vez que você executar o código abaixo). + +Desde que o checkpoint default do pipeline `sentiment-analysis` é `distilbert-base-uncased-finetuned-sst-2-english` (você pode ver o card do modelo [aqui](https://huggingface.co/distilbert-base-uncased-finetuned-sst-2-english)), então executamos o seguinte: + +```python +from transformers import AutoTokenizer + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +``` + +Assim que tivermos o tokenizer, podemos passar diretamente nossas frases para ele e receberemos de volta um dicionário que está pronto para alimentar nosso modelo! A única coisa que falta fazer é converter a lista de identificações de entrada em tensores. + +Você pode usar 🤗 Transformers sem ter que se preocupar com qual estrutura ML é usada como backend; pode ser PyTorch ou TensorFlow, ou Flax para alguns modelos. Entretanto, os Transformers só aceitam *tensores* como entrada. Se esta é a primeira vez que você ouve falar de tensores, você pode pensar neles como matrizes da NumPy. Uma matriz NumPy pode ser um escalar (0D), um vetor (1D), uma matriz (2D), ou ter mais dimensões. É efetivamente um tensor; os tensores de outras estruturas ML comportam-se de forma semelhante, e geralmente são tão simples de instanciar como os arrays da NumPy. + +Para especificar o tipo de tensores que queremos recuperar (PyTorch, TensorFlow ou NumPy), utilizamos o argumento `return_tensors`: + +{#if fw === 'pt'} +```python +raw_inputs = [ + "I've been waiting for a HuggingFace course my whole life.", + "I hate this so much!", +] +inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="pt") +print(inputs) +``` +{:else} +```python +raw_inputs = [ + "I've been waiting for a HuggingFace course my whole life.", + "I hate this so much!", +] +inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="tf") +print(inputs) +``` +{/if} + +Não se preocupe ainda com o truncamento e o padding; explicaremos isso mais tarde. As principais coisas a lembrar aqui são que você pode passar uma frase ou uma lista de frases, bem como especificar o tipo de tensores que você quer recuperar (se nenhum tipo for passado, você receberá uma lista de listas como resultado). + +{#if fw === 'pt'} + +Eis como são os resultados como tensores PyTorch: + +```python out +{ + 'input_ids': tensor([ + [ 101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102], + [ 101, 1045, 5223, 2023, 2061, 2172, 999, 102, 0, 0, 0, 0, 0, 0, 0, 0] + ]), + 'attention_mask': tensor([ + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ]) +} +``` +{:else} + +Eis como são os resultados como tensores TensorFlow: + +```python out +{ + 'input_ids': , + 'attention_mask': +} +``` +{/if} + +A saída em si é um dicionário contendo duas chaves, `input_ids' e `attention_mask'. O `input_ids' contém duas linhas de inteiros (uma para cada frase) que são os identificadores únicos dos tokens em cada frase. Explicaremos o que é a "máscara de atenção" (attention mask) mais adiante neste capítulo. + +## Indo adianta pelo modelo + +{#if fw === 'pt'} +Podemos baixar nosso modelo pré-treinado da mesma forma que fizemos com nosso tokenizer. 🤗 Transformers fornece uma classe `AutoModel` que também tem um método `from_pretrained()`: + +```python +from transformers import AutoModel + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = AutoModel.from_pretrained(checkpoint) +``` +{:else} +Podemos baixar nosso modelo pré-treinado da mesma forma que fizemos com nosso tokenizer. 🤗 Transformers fornece uma classe "TFAutoModel" que também tem um método "from_pretrained": + + +```python +from transformers import TFAutoModel + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = TFAutoModel.from_pretrained(checkpoint) +``` +{/if} + +Neste trecho de código, fizemos o download do mesmo checkpoint que usamos anteriormente em nosso pipeline (já deveria estar em cache) e instanciamos um modelo com ele. + +Esta arquitetura contém apenas o módulo base do Transformer: dadas algumas entradas, ele produz o que chamaremos de *hidden states* (estados ocultos), também conhecidos como *features* (características). Para cada modelo de entrada, recuperaremos um vetor de alta dimensionalidade representando a **compreensão contextual dessa entrada pelo Transformer***. + +Se isto não faz sentido, não se preocupe com isso. Explicaremos tudo isso mais tarde. + +Embora estes hidden states possam ser úteis por si mesmos, eles geralmente são entradas para outra parte do modelo, conhecida como *head* (cabeça). No [Capítulo 1](/course/pt/chapter1), as diferentes tarefas poderiam ter sido realizadas com a mesma arquitetura, mas cada uma destas tarefas teria uma head diferente associada a ela. + +### Um vetor de alta dimensionalidade? + +A saída vetorial pelo módulo do Transformer é geralmente grande. Geralmente tem três dimensões: + +- **Tamanho do lote** (Batch size): O número de sequências processadas de cada vez (2 em nosso exemplo). +- **Tamanho da sequencia** (Sequence length): O comprimento da representação numérica da sequência (16 em nosso exemplo). +- **Tamanho oculto** (Hidden size): A dimensão vetorial de cada modelo de entrada. + +Diz-se que é "de alta dimensionalidade" por causa do último valor. O tamanho oculto pode ser muito grande (768 é comum para modelos menores, e em modelos maiores isto pode chegar a 3072 ou mais). + +Podemos ver isso se alimentarmos os inputs que pré-processamos para nosso modelo: + +{#if fw === 'pt'} +```python +outputs = model(**inputs) +print(outputs.last_hidden_state.shape) +``` + +```python out +torch.Size([2, 16, 768]) +``` +{:else} +```py +outputs = model(inputs) +print(outputs.last_hidden_state.shape) +``` + +```python out +(2, 16, 768) +``` +{/if} + +Observe que as saídas dos 🤗 Transformer se comportam como 'tuplas nomeadas' (namedtuple) ou dicionários. Você pode acessar os elementos por atributos (como fizemos) ou por chave (`outputs["last_hidden_state"]`), ou mesmo por índice se você souber exatamente onde o que está procurando (`outputs[0]`). + +### Cabeça do modelo (model heads): Fazendo sentido a partir dos números + +As *heads* do modelo usam o vetor de alta dimensionalidade dos hidden states como entrada e os projetam em uma dimensão diferente. Eles são geralmente compostos de uma ou algumas camadas lineares: + +
+Uma rede Transformer ao lado de sua head. + +
+ +A saída do Transformer é enviada diretamente para a *head* do modelo a ser processado. + +Neste diagrama, o modelo é representado por sua camada de embeddings (vetores) e pelas camadas subsequentes. A camada de embeddings converte cada ID de entrada na entrada tokenizada em um vetor que representa o token associado. As camadas subsequentes manipulam esses vetores usando o mecanismo de atenção para produzir a representação final das sentenças. + +Há muitas arquiteturas diferentes disponíveis no 🤗 Transformers, com cada uma projetada em torno de uma tarefa específica. Aqui está uma lista por **algumas** destas tarefas: + +- `*Model` (recuperar os hidden states) +- `*ForCausalLM` +- `*ForMaskedLM` +- `*ForMultipleChoice` +- `*ForQuestionAnswering` +- `*ForSequenceClassification` +- `*ForTokenClassification` +- e outros 🤗 + +{#if fw === 'pt'} +Para nosso exemplo, precisaremos de um modelo com uma *head* de classificação em sequencia (para poder classificar as sentenças como positivas ou negativas). Portanto, não utilizaremos a classe `AutoModel`, mas sim, a classe `AutoModelForSequenceClassification`: + +```python +from transformers import AutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) +outputs = model(**inputs) +``` +{:else} +Para nosso exemplo, precisaremos de um modelo com uma *head* de classificação em sequencia (para poder classificar as sentenças como positivas ou negativas). Portanto, não utilizaremos a classe `TFAutoModel`, mas sim, a classe `TFAutoModelForSequenceClassification`: + +```python +from transformers import TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) +outputs = model(inputs) +``` +{/if} + +Agora se observarmos o tamanho dos nossos inputs, a dimensionalidade será muito menor: a *head* do modelo toma como entrada os vetores de alta dimensionalidade que vimos anteriormente, e os vetores de saída contendo dois valores (um por label): + +```python +print(outputs.logits.shape) +``` + +{#if fw === 'pt'} +```python out +torch.Size([2, 2]) +``` +{:else} +```python out +(2, 2) +``` +{/if} + +Como temos apenas duas sentenças e duas labels, o resultado que obtemos de nosso modelo é de tamanho 2 x 2. + +## Pós-processamento da saída + +Os valores que obtemos como resultado de nosso modelo não fazem necessariamente sentido sozinhos. Vamos dar uma olhada: + +```python +print(outputs.logits) +``` + +{#if fw === 'pt'} +```python out +tensor([[-1.5607, 1.6123], + [ 4.1692, -3.3464]], grad_fn=) +``` +{:else} +```python out + +``` +{/if} + +Nosso modelo previu `[-1.5607, 1.6123]` para a primeira frase e `[ 4.1692, -3.3464]` para a segunda. Essas não são probabilidades, mas *logits*, a pontuação bruta e não normalizada produzida pela última camada do modelo. Para serem convertidos em probabilidades, eles precisam passar por uma camada [SoftMax](https://en.wikipedia.org/wiki/Softmax_function) (todas saídas dos 🤗 Transformers produzem *logits*, já que a função de *loss* (perda) para treinamento geralmente fundirá a última função de ativação, como SoftMax, com a função de *loss* real, por exemplo a *cross entropy*): + +{#if fw === 'pt'} +```py +import torch + +predictions = torch.nn.functional.softmax(outputs.logits, dim=-1) +print(predictions) +``` +{:else} +```py +import tensorflow as tf + +predictions = tf.math.softmax(outputs.logits, axis=-1) +print(predictions) +``` +{/if} + +{#if fw === 'pt'} +```python out +tensor([[4.0195e-02, 9.5980e-01], + [9.9946e-01, 5.4418e-04]], grad_fn=) +``` +{:else} +```python out +tf.Tensor( +[[4.01951671e-02 9.59804833e-01] + [9.9945587e-01 5.4418424e-04]], shape=(2, 2), dtype=float32) +``` +{/if} + +Agora podemos ver que o modelo previu `[0.0402, 0.9598]` para a primeira frase e `[0.9995, 0.0005]` para a segunda. Estas são pontuações de probabilidade reconhecíveis. + +Para obter as etiquetas correspondentes a cada posição, podemos inspecionar o atributo `id2label` da configuração do modelo (mais sobre isso na próxima seção): + +```python +model.config.id2label +``` + +```python out +{0: 'NEGATIVE', 1: 'POSITIVE'} +``` + +Agora podemos concluir que o modelo previu o seguinte: + +- A primeira frase: NEGATIVE: 0.0402, POSITIVE: 0.9598 +- Segunda frase: NEGATIVE: 0.9995, POSITIVE: 0.0005 + +Reproduzimos com sucesso as três etapas do pipeline: o pré-processamento, passagem das entradas através do modelo, e o pós-processamento! Agora, vamos levar algum tempo para mergulhar mais fundo em cada uma dessas etapas. + + + +✏️ **Experimente!** Escolha duas (ou mais) textos próprios e passe-os através do pipeline `sentiment-analysis`. Em seguida, replique as etapas que você mesmo viu aqui e verifique se você obtém os mesmos resultados! + + diff --git a/chapters/pt/chapter2/3.mdx b/chapters/pt/chapter2/3.mdx new file mode 100644 index 000000000..634cc3a6e --- /dev/null +++ b/chapters/pt/chapter2/3.mdx @@ -0,0 +1,229 @@ + + +# Modelos + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +{#if fw === 'pt'} + +{:else} + +{/if} + +{#if fw === 'pt'} +Nesta seção, vamos analisar mais de perto a criação e a utilização de um modelo. Vamos utilizar a classe `AutoModel`, que é útil quando você quer instanciar qualquer modelo a partir de um checkpoint. + +A classe `AutoModel` e todas as classes filhas são na verdade simples wrapper sobre a grande variedade de modelos disponíveis na biblioteca. É um wrapper inteligente, pois pode automaticamente "adivinhar" a arquitetura apropriada do modelo para seu checkpoint, e então instancia um modelo com esta arquitetura. + +{:else} +Nesta seção, vamos analisar mais de perto a criação e a utilização de um modelo. Vamos utilizar a classe `TFAutoModel`, que é útil quando você quer instanciar qualquer modelo a partir de um checkpoint. + +A classe `TFAutoModel` e todas as classes filhas são na verdade simples wrapper sobre a grande variedade de modelos disponíveis na biblioteca. É um wrapper inteligente, pois pode automaticamente "adivinhar" a arquitetura apropriada do modelo para seu checkpoint, e então instancia um modelo com esta arquitetura. + +{/if} + +Entretanto, se você conhece o tipo de modelo que deseja usar, pode usar diretamente a classe que define sua arquitetura. Vamos dar uma olhada em como isto funciona com um modelo BERT. + +## Criando um Transformer + +A primeira coisa que precisamos fazer para inicializar um modelo BERT é carregar um objeto de configuração: + +{#if fw === 'pt'} +```py +from transformers import BertConfig, BertModel + +# Construindo a configuração +config = BertConfig() + +# Construindo o modelo a partir da configuração +model = BertModel(config) +``` +{:else} +```py +from transformers import BertConfig, TFBertModel + +# Construindo a configuração +config = BertConfig() + +# Construindo o modelo a partir da configuração +model = TFBertModel(config) +``` +{/if} + +A configuração contém muitos atributos que são usados para construir o modelo: + +```py +print(config) +``` + +```python out +BertConfig { + [...] + "hidden_size": 768, + "intermediate_size": 3072, + "max_position_embeddings": 512, + "num_attention_heads": 12, + "num_hidden_layers": 12, + [...] +} +``` + +Embora você ainda não tenha visto o que todos esses atributos fazem, você deve reconhecer alguns deles: o atributo `hidden_size` define o tamanho do vetor `hidden_states`, e o `num_hidden_layers` define o número de camadas que o Transformer possui. + + +### Diferentes métodos de inicializar o modelo + +A criação de um modelo a partir da configuração padrão o inicializa com valores aleatórios: + +{#if fw === 'pt'} +```py +from transformers import BertConfig, BertModel + +config = BertConfig() +model = BertModel(config) + +# O modelo é inicializado aleatoriamente! +``` +{:else} +```py +from transformers import BertConfig, TFBertModel + +config = BertConfig() +model = TFBertModel(config) + +# O modelo é inicializado aleatoriamente! +``` +{/if} + +O modelo pode ser utilizado neste estado, mas produzirá saídas errôneas; ele precisa ser treinado primeiro. Poderíamos treinar o modelo a partir do zero na tarefa em mãos, mas como você viu em [Capítulo 1](/course/pt/chapter1), isto exigiria muito tempo e muitos dados, e teria um impacto ambiental não negligenciável. Para evitar esforços desnecessários e duplicados, normalmente é possível compartilhar e reutilizar modelos que já foram treinados. + +Carregar um Transformer já treinado é simples - podemos fazer isso utilizando o método `from_pretrained()`: + +{#if fw === 'pt'} +```py +from transformers import BertModel + +model = BertModel.from_pretrained("bert-base-cased") +``` + +Como você viu anteriormente, poderíamos substituir o `BertModel` pela classe equivalente ao `AutoModel`. Faremos isto de agora em diante, pois isto produz um código generalista a partir de um checkpoint; se seu código funciona para checkpoint, ele deve funcionar perfeitamente com outro. Isto se aplica mesmo que a arquitetura seja diferente, desde que o checkpoint tenha sido treinado para uma tarefa semelhante (por exemplo, uma tarefa de análise de sentimento). + +{:else} +```py +from transformers import TFBertModel + +model = TFBertModel.from_pretrained("bert-base-cased") +``` + +Como você viu anteriormente, poderíamos substituir o `TFBertModel` pela classe equivalente ao `TFAutoModel`. Faremos isto de agora em diante, pois isto produz um código generalista a partir de um checkpoint; se seu código funciona para checkpoint, ele deve funcionar perfeitamente com outro. Isto se aplica mesmo que a arquitetura seja diferente, desde que o checkpoint tenha sido treinado para uma tarefa semelhante (por exemplo, uma tarefa de análise de sentimento). + + +{/if} + +No exemplo de código acima não utilizamos `BertConfig`, e em vez disso carregamos um modelo pré-treinado através do identificador `bert-base-cased`. Este é um checkpoint do modelo que foi treinado pelos próprios autores do BERT; você pode encontrar mais detalhes sobre ele em seu [model card](https://huggingface.co/bert-base-cased). + +Este modelo agora é inicializado com todos os pesos do checkpoint. Ele pode ser usado diretamente para inferência sobre as tarefas nas quais foi treinado, e também pode ser *fine-tuned* (aperfeiçoado) em uma nova tarefa. Treinando com pesos pré-treinados e não do zero, podemos rapidamente alcançar bons resultados. + +Os pesos foram baixados e armazenados em cache (logo, para as futuras chamadas do método `from_pretrained()` não será realizado o download novamente) em sua respectiva pasta, que tem como padrão o path *~/.cache/huggingface/transformers*. Você pode personalizar sua pasta de cache definindo a variável de ambiente `HF_HOME`. + +O identificador usado para carregar o modelo pode ser o identificador de qualquer modelo no Model Hub, desde que seja compatível com a arquitetura BERT. A lista completa dos checkpoints BERT disponíveis podem ser encontrada [aqui].https://huggingface.co/models?filter=bert). + +### Métodos para salvar/armazenar o modelo + +Salvar um modelo é tão fácil quanto carregar um - utilizamos o método `save_pretrained()`, que é análogo ao método `from_pretrained()`: + +```py +model.save_pretrained("path_no_seu_computador") +``` + +Isto salva dois arquivos em seu disco: + +{#if fw === 'pt'} +``` +ls path_no_seu_computador + +config.json pytorch_model.bin +``` +{:else} +``` +ls path_no_seu_computador + +config.json tf_model.h5 +``` +{/if} + +Se você der uma olhada no arquivo *config.json*, você reconhecerá os atributos necessários para construir a arquitetura modelo. Este arquivo também contém alguns metadados, como a origem do checkpoint e a versão 🤗 Transformers que você estava usando quando salvou o checkpoint pela última vez. + +{#if fw === 'pt'} +O arquivo *pytorch_model.bin* é conhecido como o *dicionário de estado*; ele contém todos os pesos do seu modelo. Os dois arquivos andam de mãos dadas; a configuração é necessária para conhecer a arquitetura de seu modelo, enquanto os pesos do modelo são os parâmetros de seu modelo. + +{:else} +O arquivo *tf_model.h5* é conhecido como o *dicionário de estado*; ele contém todos os pesos do seu modelo. Os dois arquivos andam de mãos dadas; a configuração é necessária para conhecer a arquitetura de seu modelo, enquanto os pesos do modelo são os parâmetros de seu modelo. + +{/if} + +## Usando um modelo de Transformer para inferência + +Agora que você sabe como carregar e salvar um modelo, vamos tentar usá-lo para fazer algumas predições. Os Transformers só podem processar números - números que o tokenizer gera. Mas antes de discutirmos os tokenizers, vamos explorar quais entradas o modelo aceita. + +Os Tokenizers podem se encarregar de lançar as entradas nos tensores da estrutura apropriada, mas para ajudá-lo a entender o que está acontecendo, vamos dar uma rápida olhada no que deve ser feito antes de enviar as entradas para o modelo. + +Digamos que temos um par de sequências: + +```py +sequences = ["Hello!", "Cool.", "Nice!"] +``` + +O tokenizer os converte em índices de vocabulário que são normalmente chamados de *IDs de entrada*. Cada sequência é agora uma lista de números! A saída resultante é: + +```py no-format +encoded_sequences = [ + [101, 7592, 999, 102], + [101, 4658, 1012, 102], + [101, 3835, 999, 102], +] +``` + +Esta é uma lista de sequências codificadas: uma lista de listas. Os tensores só aceitam shapes (tamanhos) retangulares (pense em matrizes). Esta "matriz" já é de forma retangular, portanto, convertê-la em um tensor é fácil: + +{#if fw === 'pt'} +```py +import torch + +model_inputs = torch.tensor(encoded_sequences) +``` +{:else} +```py +import tensorflow as tf + +model_inputs = tf.constant(encoded_sequences) +``` +{/if} + +### Usando os tensores como entradas para o modelo + +Fazer uso dos tensores com o modelo é extremamente simples - chamamos apenas o modelo com os inputs: + +```py +output = model(model_inputs) +``` + +Embora o modelo aceite muitos argumentos diferentes, apenas os IDs de entrada são necessários. Explicaremos o que os outros argumentos fazem e quando eles são necessários mais tarde, mas primeiro precisamos olhar mais de perto os tokenizers que constroem as entradas que um Transformer pode compreender. diff --git a/chapters/pt/chapter2/4.mdx b/chapters/pt/chapter2/4.mdx new file mode 100644 index 000000000..7b2f70ff6 --- /dev/null +++ b/chapters/pt/chapter2/4.mdx @@ -0,0 +1,248 @@ + + +# Tokenizers + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + + + +Os Tokenizers são um dos componentes centrais do pipeline da PNL. Eles têm um propósito: traduzir texto em dados que podem ser processados pelo modelo. Os modelos só podem processar números, portanto os tokenizers precisam converter nossas entradas de texto em dados numéricos. Nesta seção, vamos explorar exatamente o que acontece no pipeline de tokenização. + +Nas tarefas de PNL, os dados que são geralmente processados são texto bruto. Aqui está um exemplo de tal texto: + +``` +Jim Henson was a puppeteer +``` + +Entretanto, os modelos só podem processar números, portanto, precisamos encontrar uma maneira de converter o texto bruto em números. Isto é o que os tokenizers fazem, e há muitas maneiras de se fazer isso. O objetivo é encontrar a representação mais significativa - ou seja, a que faz mais sentido para o modelo - e, se possível, a menor representação. + +Vamos dar uma olhada em alguns exemplos de algoritmos de tokenização, e tentar responder algumas das perguntas que você possa ter sobre tokenização. + +## Baseado em palavras (word-based) + + + +O primeiro tipo de tokenizer que me vem à mente é _baseado em palavras_. É geralmente muito fácil de instalar e usar com apenas algumas regras, e muitas vezes produz resultados decentes. Por exemplo, na imagem abaixo, o objetivo é dividir o texto bruto em palavras e encontrar uma representação numérica para cada uma delas: + +
+ Um exemplo de tokenização baseado em palavras. + +
+ +Há diferentes maneiras de dividir o texto. Por exemplo, poderíamos utilizar o espaço em branco para simbolizar o texto em palavras, usando a função `split()` do Python: + +```py +tokenized_text = "Jim Henson was a puppeteer".split() +print(tokenized_text) +``` + +```python out +['Jim', 'Henson', 'was', 'a', 'puppeteer'] +``` + +Há também variações de tokenizers de palavras que têm regras extras para pontuação. Com este tipo de tokenizer, podemos terminar com alguns "vocabulários" bem grandes, onde um vocabulário é definido pelo número total de tokens independentes que tem no texto de exemplo. + +A cada palavra é atribuída uma identificação, começando em 0 e indo até o tamanho do vocabulário. O modelo utiliza estas identificações para identificar cada palavra. + +Se quisermos cobrir completamente um idioma com um tokenizer baseado em palavras, precisaremos ter um identificador para cada palavra no idioma, o que gerará uma enorme quantidade de tokens. Por exemplo, existem mais de 500.000 palavras no idioma inglês, portanto, para construir um mapa a partir de cada palavra para um ID de entrada, precisaríamos manter um registro desse grande número de IDs. Além disso, palavras como "dog" são representadas de forma diferente de palavras como "dogs", e o modelo inicialmente não terá como saber que "dog" e "dogs" são semelhantes: ele identificará as duas palavras como não relacionadas. O mesmo se aplica a outras palavras semelhantes, como "run" e "running", que o modelo não verá inicialmente como sendo semelhantes. + + +Finalmente, precisamos de token personalizada para representar palavras que não estão em nosso vocabulário. Isto é conhecido como o símbolo "unknown" (desconhecido), frequentemente representado como "[UNK]" ou "<unk>". Geralmente é um mau sinal se você vê que o tokenizer está produzindo muitos desses tokens, pois não foi capaz de recuperar uma representação sensata de uma palavra e você está perdendo informações ao longo do caminho. O objetivo ao elaborar o vocabulário é fazê-lo de tal forma que o tokenizer transforme o menor número possível de palavras no token desconhecido. + +Uma maneira de reduzir a quantidade de tokens desconhecidas é ir um nível mais fundo, usando um tokenizer _baseado em caracteres_. + +## Baseado em caracteres (Character-based) + + + +Os tokenizers baseados em caracteres dividem o texto em caracteres, ao invés de palavras. Isto tem dois benefícios principais: + +- O vocabulário será muito menor; +- Há muito menos tokes fora de vocabulário (desconhecidas), uma vez que cada palavra pode ser construída a partir de personagens. + +Mas também aqui surgem algumas questões sobre os espaços e à pontuação: + +
+ Um exemplo de tokenização baseado em caracteres. + +
+ +Esta abordagem também não é perfeita. Como a representação agora é baseada em caracteres e não em palavras, pode-se argumentar que, intuitivamente, ela é menos significativa: cada caractere não significa muito por si só, ao contrario do caso das palavras. No entanto, isto novamente difere de acordo com o idioma; em chinês, por exemplo, cada caractere traz mais informações do que um caractere em um idioma latino. + +Outra coisa a considerar é que acabaremos com uma quantidade muito grande de tokens a serem processadas por nosso modelo: enquanto uma palavra seria apenas um único token com um tokenizer baseado em palavras, ela pode facilmente se transformar em 10 ou mais tokens quando convertida em caracteres. + + +Para obter o melhor dos dois mundos, podemos usar uma terceira técnica que combina as duas abordagens: *Tokenização por sub-palavras*. + +## Tokenização por sub-palavras (Subword tokenization) + + + +Algoritmos de tokenização de sub-palavras baseiam-se no princípio de que palavras frequentemente usadas não devem ser divididas em sub-palavras menores, mas palavras raras devem ser decompostas em sub-palavras significativas. + +Por exemplo, "irritantemente" poderia ser considerado uma palavra rara e poderia ser decomposto em "irritante" e "mente". É provável que ambas apareçam mais frequentemente como sub-palavras isoladas, enquanto ao mesmo tempo o significado de "irritantemente" é mantido pelo significado composto de "irritante" e "mente". + +Aqui está um exemplo que mostra como um algoritmo de tokenização de uma sub-palavra indicaria a sequência "Let's do tokenization! + +
+ Exemplo de algoritmo de tokenização por sub-palavras. + +
+ +Estas sub-palavras acabam fornecendo muito significado semântico: por exemplo, no exemplo acima "tokenization" foi dividido em "token" e "ization", dois tokens que têm um significado semântico enquanto são eficientes em termos de espaço (apenas dois tokens são necessários para representar uma palavra longa). Isto nos permite ter uma cobertura relativamente boa com pequenos vocabulários, e perto de nenhum token desconhecido. + + +Esta abordagem é especialmente útil em idiomas aglutinativos como o turco, onde é possível formar palavras (quase) arbitrariamente longas e complexas, encadeando sub-palavras. + +### E outros! + +Sem surpresas, há muito mais técnicas por aí. Para citar algumas: + +- Byte-level BPE, utilizada no GPT-2 +- WordPiece, utilizada em BERT +- SentencePiece ou Unigram, como as utilizadas em vários modelos multilíngue + +Agora você deve ter conhecimento suficiente de como funcionam os tokenizers para começar a utilizar a API. + +## Carregando e salvando + +Carregando e salvando tokenizers é tão simples quanto com os modelos. Na verdade, ele se baseia nos mesmos dois métodos: `from_pretrained()` e `save_pretrained()`. Estes métodos irão carregar ou salvar o algoritmo utilizado pelo tokenizer (um pouco como a *arquitetura* do modelo), bem como seu vocabulário (um pouco como os *pesos* do modelo). + +O carregamento do tokenizer BERT treinado com o mesmo checkpoint do BERT é feito da mesma forma que o carregamento do modelo, exceto que utilizamos a classe `BertTokenizer`: + +```py +from transformers import BertTokenizer + +tokenizer = BertTokenizer.from_pretrained("bert-base-cased") +``` + +{#if fw === 'pt'} +Similar ao `AutoModel`, a classe `AutoTokenizer` ira carregar a classe tokenizer apropriada na biblioteca com base no nome do checkpoint, e pode ser utilizada diretamente com qualquer checkpoint: + +{:else} +Similar ao `TFAutoModel`, a classe `AutoTokenizer` ira carregar a classe tokenizer apropriada na biblioteca com base no nome do checkpoint, e pode ser utilizada diretamente com qualquer checkpoint: + +{/if} + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +``` + +Agora podemos usar o tokenizer, como mostrado na seção anterior: + +```python +tokenizer("Using a Transformer network is simple") +``` + +```python out +{'input_ids': [101, 7993, 170, 11303, 1200, 2443, 1110, 3014, 102], + 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0], + 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]} +``` + +Salvar um tokenizer é idêntico a salvar um modelo: + +```py +tokenizer.save_pretrained("directory_on_my_computer") +``` + + +Falaremos mais sobre `token_type_ids' no [Capítulo 3](/course/pt/chapter3), e explicaremos a `attention_mask' um pouco mais tarde. Primeiro, vamos ver como os `input_ids` são gerados. Para fazer isso, precisaremos olhar os métodos intermediários do tokenizer. + + +## Encoding + + + +Traduzir texto para números é conhecido como _encoding_. O encoding é feito em um processo de duas etapas: a tokenização, seguida pela conversão para IDs de entrada. + +Como vimos, o primeiro passo é dividir o texto em palavras (ou partes de palavras, símbolos de pontuação, etc.), normalmente chamadas de *tokens*. Há várias regras que podem guiar esse processo, e é por isso que precisamos instanciar o tokenizer usando o nome do modelo, para nos certificarmos de usar as mesmas regras que foram usadas quando o modelo foi pré-treinado. + +O segundo passo é converter esses tokens em números, para que possamos construir um tensor a partir deles e alimentá-los com o modelo. Para isso, o tokenizer tem um *vocabulário* (vocabulary), que é a parte que realizamos o download quando o instanciamos com o método `from_pretrained()`. Mais uma vez, precisamos utilizar o mesmo vocabulário utilizado quando o modelo foi pré-treinado. + +Para entender melhor os dois passos, vamos explorá-los separadamente. Note que usaremos alguns métodos que executam partes da pipeline de tokenização separadamente para mostrar os resultados intermediários dessas etapas, mas na prática, você deve chamar o tokenizer diretamente em suas entradas (como mostrado na seção 2). + +### Tokenização + +O processo de tokenization é feito através do método `tokenize()` do tokenizer: + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") + +sequence = "Using a Transformer network is simple" +tokens = tokenizer.tokenize(sequence) + +print(tokens) +``` + +A saída deste método é uma lista de strings, ou tokens: + +```python out +['Using', 'a', 'transform', '##er', 'network', 'is', 'simple'] +``` + +Este tokenizer é um tokenizer de sub-palavras: ele divide as palavras até obter tokens que podem ser representadas por seu vocabulário. É o caso aqui do "transformer", que é dividido em dois tokens: "transform" e "##er". + +### Desde os tokens até IDs de entrada + +A conversão para IDs de entrada é feita pelo método de tokenização `convert_tokens_to_ids()`: + +```py +ids = tokenizer.convert_tokens_to_ids(tokens) + +print(ids) +``` + +```python out +[7993, 170, 11303, 1200, 2443, 1110, 3014] +``` + +Estas saídas, uma vez convertidas no tensor com a estrutura apropriada, podem então ser usadas como entradas para um modelo como visto anteriormente neste capítulo. + + + +✏️ **Experimente realizar isso!** Replicar os dois últimos passos (tokenização e conversão para IDs de entrada) nas frases de entrada que usamos na seção 2 ("I've been waiting for a HuggingFace course my whole life." e "I hate this so much!"). Verifique se você recebe os mesmos IDs de entrada que recebemos antes! + + + +## Decoding + +*Decoding* vai pela direção ao contrário: a partir de índices de vocabulário, queremos obter uma string. Isto pode ser feito com o método `decode()` da seguinte forma: + + +```py +decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014]) +print(decoded_string) +``` + +```python out +'Using a Transformer network is simple' +``` + +Observe que o método `decode` não apenas converte os índices em tokens, mas também agrupa os tokens que fizeram parte das mesmas palavras para produzir uma frase legível. Este comportamento será extremamente útil quando utilizamos modelos que preveem um novo texto (seja texto gerado a partir de um prompt, ou para problemas de _sequence-to-sequence_ como tradução ou sumarização). + + + +Até agora você já deve entender as operações atômicas que um tokenizer pode lidar: tokenização, conversão para IDs, e conversão de IDs de volta para uma string. Entretanto, acabamos de começar a ver a ponta do iceberg. Na seção seguinte, vamos nos aproximar de seus limites e dar uma olhada em como superá-los. \ No newline at end of file diff --git a/chapters/pt/chapter2/5.mdx b/chapters/pt/chapter2/5.mdx new file mode 100644 index 000000000..9b45c2c47 --- /dev/null +++ b/chapters/pt/chapter2/5.mdx @@ -0,0 +1,340 @@ + + +# Tratando sequências múltiplas + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +{#if fw === 'pt'} + +{:else} + +{/if} + +Na seção anterior, exploramos os casos mais simples de uso: fazer inferência sobre uma única sequência de pequeno comprimento. No entanto, surgem algumas questões: + +- Como nós tratamos diversas sequências? +- Como nós tratamos diversas sequências *de diferentes tamanhos*? +- Os índices de vocabulário são as únicas entradas que permitem que um modelo funcione bem? +- Existe uma sequência muito longa? + +Vamos ver que tipos de problemas estas questões colocam, e como podemos resolvê-los usando a API do 🤗 Transformers. + +## Modelos esperam um batch de entradas + +No exercício anterior, você viu como as sequências são traduzidas em listas de números. Vamos converter esta lista de números em um tensor e enviá-la para o modelo: + +{#if fw === 'pt'} +```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) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.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 = tf.constant(ids) +# This line will fail. +model(input_ids) +``` + +```py out +InvalidArgumentError: Input to reshape is a tensor with 14 values, but the requested shape has 196 [Op:Reshape] +``` +{/if} + +Oh não! Por que isso falhou? "Seguimos os passos do pipeline na seção 2. + +O problema é que enviamos uma única sequência para o modelo, enquanto que os 🤗 transformers esperam várias sentenças por padrão. Aqui tentamos fazer tudo o que o tokenizer fez nos bastidores quando o aplicamos a uma `sequência`, mas se você olhar com atenção, verá que ele não apenas converteu a lista de IDs de entrada em um tensor, mas acrescentou uma dimensão em cima dele: + +{#if fw === 'pt'} +```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]]) +``` +{:else} +```py +tokenized_inputs = tokenizer(sequence, return_tensors="tf") +print(tokenized_inputs["input_ids"]) +``` + +```py out + +``` +{/if} + +Vamos tentar novamente e acrescentar uma nova dimensão: + +{#if fw === 'pt'} +```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) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.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 = tf.constant([ids]) +print("Input IDs:", input_ids) + +output = model(input_ids) +print("Logits:", output.logits) +``` +{/if} + +Printamos os IDs de entrada assim como os logits resultantes - aqui está a saída: + +{#if fw === 'pt'} +```python out +Input IDs: [[ 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012]] +Logits: [[-2.7276, 2.8789]] +``` +{:else} +```py out +Input IDs: tf.Tensor( +[[ 1045 1005 2310 2042 3403 2005 1037 17662 12172 2607 2026 2878 + 2166 1012]], shape=(1, 14), dtype=int32) +Logits: tf.Tensor([[-2.7276208 2.8789377]], shape=(1, 2), dtype=float32) +``` +{/if} + +*Batching* é o ato de enviar múltiplas sentenças através do modelo, todas de uma só vez. Se você tiver apenas uma frase, você pode apenas construir um lote com uma única sequência: + +``` +batched_ids = [ids, ids] +``` + +Este é um lote de duas sequências idênticas! + + + +✏️ **Experimente!** Converta esta lista de `batched_ids` em um tensor e passe-a através de seu modelo. Verifique se você obtém os mesmos logits que antes (mas duas vezes)! + + + +O Batching permite que o modelo funcione quando você o alimenta com várias frases. Usar várias sequências é tão simples quanto construir um lote com uma única sequência. Há uma segunda questão, no entanto. Quando você está tentando agrupar duas (ou mais) sentenças, elas podem ser de comprimentos diferentes. Se você já trabalhou com tensores antes, você sabe que eles precisam ser de forma retangular, então você não será capaz de converter a lista de IDs de entrada em um tensor diretamente. Para contornar este problema, normalmente realizamos uma *padronização* (padding) nas entradas. + + +## Realizando padding nas entradas + +A seguinte lista de listas não pode ser convertida em um tensor: + +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200] +] +``` + +Para contornar isso, usaremos *padding* para fazer com que nossos tensores tenham uma forma retangular. O padding garante que todas as nossas frases tenham o mesmo comprimento, acrescentando uma palavra especial chamada *padding token* às frases com menos valores. Por exemplo, se você tiver 10 frases com 10 palavras e 1 frase com 20 palavras, o padding garantirá que todas as frases tenham 20 palavras. Em nosso exemplo, o tensor resultante se parece com isto: + + +```py no-format +padding_id = 100 + +batched_ids = [ + [200, 200, 200], + [200, 200, padding_id], +] +``` + +O padding do ID token pode ser encontrada em `tokenizer.pad_token_id`. Vamos utilizá-lo e enviar nossas duas frases através do modelo individualmente e agrupadas em batches: + +{#if fw === 'pt'} +```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=) +tensor([[ 0.5803, -0.4125]], grad_fn=) +tensor([[ 1.5694, -1.3895], + [ 1.3373, -1.2163]], grad_fn=) +``` +{:else} +```py no-format +model = TFAutoModelForSequenceClassification.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(tf.constant(sequence1_ids)).logits) +print(model(tf.constant(sequence2_ids)).logits) +print(model(tf.constant(batched_ids)).logits) +``` + +```py out +tf.Tensor([[ 1.5693678 -1.3894581]], shape=(1, 2), dtype=float32) +tf.Tensor([[ 0.5803005 -0.41252428]], shape=(1, 2), dtype=float32) +tf.Tensor( +[[ 1.5693681 -1.3894582] + [ 1.3373486 -1.2163193]], shape=(2, 2), dtype=float32) +``` +{/if} + +Há algo errado com os logits em nossas predições em batches: a segunda fileira deveria ser a mesma que os logits para a segunda frase, mas temos valores completamente diferentes! + +Isto porque a característica chave dos Transformer são as camadas de atenção que *contextualizam* cada token. Estes levarão em conta os tokens de padding, uma vez que atendem a todos os tokens de uma sequência. Para obter o mesmo resultado ao passar frases individuais de diferentes comprimentos pelo modelo ou ao passar um batch com as mesmas frases e os paddings aplicados, precisamos dizer a essas camadas de atenção para ignorar os tokens de padding. Isto é feito com o uso de uma máscara de atenção (*attention mask*). + +## Attention masks + +*Attention masks* são tensores com a mesma forma exata do tensor de IDs de entrada, preenchidos com 0s e 1s: 1s indicam que os tokens correspondentes devem ser atendidas, e 0s indicam que os tokens correspondentes não devem ser atendidas (ou seja, devem ser ignoradas pelas camadas de atenção do modelo). + +Vamos completar o exemplo anterior com uma máscara de atenção: + +{#if fw === 'pt'} +```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=) +``` +{:else} +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200, tokenizer.pad_token_id], +] + +attention_mask = [ + [1, 1, 1], + [1, 1, 0], +] + +outputs = model(tf.constant(batched_ids), attention_mask=tf.constant(attention_mask)) +print(outputs.logits) +``` + +```py out +tf.Tensor( +[[ 1.5693681 -1.3894582 ] + [ 0.5803021 -0.41252586]], shape=(2, 2), dtype=float32) +``` +{/if} + +Agora obtemos os mesmos logits para a segunda frase do batch. + +Observe como o último valor da segunda sequência é um ID de padding, que é um valor 0 na máscara de atenção. + + + +✏️ **Experimente!** Aplique a tokenização manualmente nas duas frases usadas na seção 2 ("I've been waiting for a HuggingFace course my whole life." e "I hate this so much!"). Passe-as através do modelo e verifique se você obtém os mesmos logits que na seção 2. Agora, agrupe-os usando o token de padding e depois crie a máscara de atenção adequada. Verifique que você obtenha os mesmos resultados ao passar pelo modelo! + + + +## Sequências mais longas + +Com os Transformer, há um limite para os comprimentos das sequências, podemos passar os modelos. A maioria dos modelos manipula sequências de até 512 ou 1024 tokens, e se chocará quando solicitados a processar sequências mais longas. Há duas soluções para este problema: + +- Use um modelo com suporte a um comprimento mais longo de sequência. +- Trunque suas sequências. + +Os modelos têm diferentes comprimentos de sequência suportados, e alguns são especializados no tratamento de sequências muito longas. O [Longformer](https://huggingface.co/transformers/model_doc/longformer.html) é um exemplo, e outro exemplo é o [LED](https://huggingface.co/transformers/model_doc/led.html). Se você estiver trabalhando em uma tarefa que requer sequências muito longas, recomendamos que você dê uma olhada nesses modelos. + +Caso contrário, recomendamos que você trunque suas sequências, especificando o parâmetro `max_sequence_length`: + +```py +sequence = sequence[:max_sequence_length] +``` diff --git a/chapters/pt/chapter2/6.mdx b/chapters/pt/chapter2/6.mdx new file mode 100644 index 000000000..a1ba25c38 --- /dev/null +++ b/chapters/pt/chapter2/6.mdx @@ -0,0 +1,167 @@ + + +# Colocando tudo junto + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +Nas últimas seções, temos feito o nosso melhor para fazer a maior parte do trabalho à mão. Exploramos como funcionam os tokenizers e analisamos a tokenização, conversão para IDs de entrada, padding, truncagem e máscaras de atenção. + +Entretanto, como vimos na seção 2, a API dos 🤗 Transformers pode tratar de tudo isso para nós com uma função de alto nível, na qual mergulharemos aqui. Quando você chama seu `tokenizer` diretamente na frase, você recebe de volta entradas que estão prontas para passar pelo seu modelo: + +```py +from transformers import AutoTokenizer + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." + +model_inputs = tokenizer(sequence) +``` + +Aqui, a variável `model_inputs` contém tudo o que é necessário para que um modelo funcione bem. Para DistilBERT, isso inclui os IDs de entrada, bem como a máscara de atenção. Outros modelos que aceitam entradas adicionais também terão essas saídas pelo objeto `tokenizer`. + +Como veremos em alguns exemplos abaixo, este método é muito poderoso. Primeiro, ele pode simbolizar uma única sequência: + +```py +sequence = "I've been waiting for a HuggingFace course my whole life." + +model_inputs = tokenizer(sequence) +``` + +Também lida com várias sequências de cada vez, sem nenhuma mudança na API: + +```py +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +model_inputs = tokenizer(sequences) +``` + +Ela pode ser aplicada de acordo com vários objetivos: + +```py +# Irá preencher as sequências até o comprimento máximo da sequência +model_inputs = tokenizer(sequences, padding="longest") + +# Irá preencher as sequências até o comprimento máximo do modelo +# (512 para o modelo BERT ou DistilBERT) +model_inputs = tokenizer(sequences, padding="max_length") + +# Irá preencher as sequências até o comprimento máximo especificado +model_inputs = tokenizer(sequences, padding="max_length", max_length=8) +``` + +Também pode truncar sequências: + +```py +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +# Irá preencher as sequências até o comprimento máximo do modelo +# (512 para o modelo BERT ou DistilBERT) +model_inputs = tokenizer(sequences, truncation=True) + +# Truncará as sequências que são mais longas do que o comprimento máximo especificado +model_inputs = tokenizer(sequences, max_length=8, truncation=True) +``` + +O objeto `tokenizer` pode lidar com a conversão para tensores de estrutura específicos, que podem então ser enviados diretamente para o modelo. Por exemplo, na seguinte amostra de código, estamos solicitando que o tokenizer retorne tensores de diferentes estruturas - `"pt"` retorna tensores PyTorch, `"tf"` retorna tensores TensorFlow, e `"np"` retorna arrays NumPy: + +```py +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +# Retorna tensores PyTorch +model_inputs = tokenizer(sequences, padding=True, return_tensors="pt") + +# Retorna tensores TensorFlow +model_inputs = tokenizer(sequences, padding=True, return_tensors="tf") + +# Retorna NumPy arrays +model_inputs = tokenizer(sequences, padding=True, return_tensors="np") +``` + +## Tokens especiais + +Se dermos uma olhada nos IDs de entrada devolvidos pelo tokenizer, veremos que eles são um pouco diferentes do que tínhamos anteriormente: + +```py +sequence = "I've been waiting for a HuggingFace course my whole life." + +model_inputs = tokenizer(sequence) +print(model_inputs["input_ids"]) + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) +print(ids) +``` + +```python out +[101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102] +[1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012] +``` + + +Um token ID foi adicionada no início e uma no final. Vamos decodificar as duas sequências de IDs acima para ver do que se trata: + + +```py +print(tokenizer.decode(model_inputs["input_ids"])) +print(tokenizer.decode(ids)) +``` + +```python out +"[CLS] i've been waiting for a huggingface course my whole life. [SEP]" +"i've been waiting for a huggingface course my whole life." +``` + +O tokenizer acrescentou a palavra especial `[CLS]` no início e a palavra especial `[SEP]` no final. Isto porque o modelo foi pré-treinado com esses, então para obter os mesmos resultados para inferência, precisamos adicioná-los também. Note que alguns modelos não acrescentam palavras especiais, ou acrescentam palavras diferentes; os modelos também podem acrescentar estas palavras especiais apenas no início, ou apenas no final. Em qualquer caso, o tokenizer sabe quais são as palavras que são esperadas e tratará disso para você. + + +## Do tokenizer ao modelo + +Agora que já vimos todos os passos individuais que o objeto `tokenizer` utiliza quando aplicado em textos, vamos ver uma última vez como ele pode lidar com múltiplas sequências (padding!), sequências muito longas (truncagem!), e múltiplos tipos de tensores com seu API principal: + +{#if fw === 'pt'} +```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) +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt") +output = model(**tokens) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="tf") +output = model(**tokens) +``` +{/if} diff --git a/chapters/pt/chapter2/7.mdx b/chapters/pt/chapter2/7.mdx new file mode 100644 index 000000000..2b2f1df5a --- /dev/null +++ b/chapters/pt/chapter2/7.mdx @@ -0,0 +1,13 @@ +# Uso básico concluído! + +Ótimo trabalho seguindo o curso até aqui! Recapitulando, neste capítulo, você: + +- Aprendeu os elementos básicos de um modelo Transformer. +- Aprendeu que compõe o pipeline de tokenização. +- Vou como utilizar um transformer na prática. +- Aprendeu como aproveitar um tokenizer para converter texto em tensores que são compreensíveis pelo modelo. +- Montar um tokenizer e um modelo juntos para ir do texto às previsões. +- Aprendeu as limitações dos IDs de entrada e aprendeu sobre máscaras de atenção. +- Testou os métodos de tokenizer versáteis e configuráveis. + +De agora em diante, você deve ser capaz de navegar livremente pelos documentos dos 🤗 transformers: o vocabulário soará familiar, e você já viu os métodos que utilizará na maior parte do tempo. diff --git a/chapters/pt/chapter2/8.mdx b/chapters/pt/chapter2/8.mdx new file mode 100644 index 000000000..00a283ad3 --- /dev/null +++ b/chapters/pt/chapter2/8.mdx @@ -0,0 +1,305 @@ + + + + +# Questionário de fim de capítulo + +### 1. Qual é a ordem do pipeline para a modelagem de linguagem? + + + +### 2. Quantas dimensões tem o tensor do Transformer de base, e quais são elas? + + + +### 3. Qual dos seguintes é um exemplo de Tokenização por sub-palavras? + + + +### 4. O que é uma *model head*? + + + +{#if fw === 'pt'} +### 5. O que seria um `AutoModel`? + +AutoNLP?" + }, + { + text: "Um objeto que devolve a arquitetura correta com base em um checkpoint", + explain: "Exatamente: o AutoModel só precisa saber o checkpoint para saber como inicializar então devolver a arquitetura correta.", + correct: true + }, + { + text: "Um modelo que detecta automaticamente a linguagem utilizada para suas entradas a fim de carregar os pesos corretos", + explain: "Incorreto; embora alguns checkpoints e modelos sejam capazes de lidar com vários idiomas, não há ferramentas embutidas para seleção automática de checkpoints de acordo com o idioma. Você deve ir para o Model Hub para encontrar o melhor checkpoint para realizar sua tarefa!" + } + ]} +/> + +{:else} +### 5. O que seria um `TFAutoModel`? + +AutoNLP?" + }, + { + text: "Um objeto que devolve a arquitetura correta com base em um checkpoint", + explain: "Exatamente: o TFAutoModel só precisa saber o checkpoint para saber como inicializar então devolver a arquitetura correta.", + correct: true + }, + { + text: "Um modelo que detecta automaticamente a linguagem utilizada para suas entradas a fim de carregar os pesos corretos", + explain: "Incorreto; embora alguns checkpoints e modelos sejam capazes de lidar com vários idiomas, não há ferramentas embutidas para seleção automática de checkpoints de acordo com o idioma. Você deve ir para o Model Hub para encontrar o melhor checkpoint para realizar sua tarefa!" + } + ]} +/> + +{/if} + +### 6. Quais são as técnicas a serem observadas quando realizar batches com sequências de diferentes tamanhos? + + + +### 7. Qual é o objetivo de aplicar uma função SoftMax à saída de logits para um modelo de classificação sequencial?? + + + +### 8. Qual é o método core da API tokenizer? + +encode, pois pode codificar texto em IDs e IDs em predições", + explain: "Errado! O método encode existe na tokenização, porém não existe nos modelos." + }, + { + text: "Chamando diretamente o objeto de tokenização (tokenizer).", + explain: "Exatamente! O método __call__ do tokenizer é um método muito poderoso que pode lidar com praticamente qualquer coisa. É também o método usado para recuperar as predições de um modelo.", + correct: true + }, + { + text: "padding", + explain: "Errado! O padding é muito útil, mas é apenas uma parte da API do tokenizer." + }, + { + text: "tokenize", + explain: "O método tokenize é indiscutivelmente um dos métodos mais úteis, mas não é o núcleo do API do tokenizer." + } + ]} +/> + +### 9. O que a variável `result` contém nesta pedaço de código? + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +result = tokenizer.tokenize("Hello!") +``` + +__call__ ou convert_tokens_to_ids!" + }, + { + text: "Uma string contendo todos os tokens ", + explain: "Isto seria subótimo, pois o objetivo é dividir a string em vários tokens." + } + ]} +/> + +{#if fw === 'pt'} +### 10. Tem algo errado com o código abaixo? + +```py +from transformers import AutoTokenizer, AutoModel + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +model = AutoModel.from_pretrained("gpt2") + +encoded = tokenizer("Hey!", return_tensors="pt") +result = model(**encoded) +``` + + + +{:else} +### 10. Tem algo errado com o código abaixo? + +```py +from transformers import AutoTokenizer, TFAutoModel + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +model = TFAutoModel.from_pretrained("gpt2") + +encoded = tokenizer("Hey!", return_tensors="pt") +result = model(**encoded) +``` + + + +{/if} From 421e83766cbdf846e35a59b8cd2ec2eb0c74d872 Mon Sep 17 00:00:00 2001 From: lbourdois <58078086+lbourdois@users.noreply.github.com> Date: Wed, 13 Apr 2022 15:58:55 +0200 Subject: [PATCH 36/73] [FR] Translation of chapter 2 & event + Review of chapters 0 & 5 (#106) * Update _toctree.yml Add chapter 2 + little fix of chapter 5 * Update 1.mdx Review of chapter 0 * Create 1.mdx * Create 2.mdx * Create 3.mdx * Create 4.mdx * Create 5.mdx * Create 6.mdx * Create 7.mdx * Create 8.mdx * Update 8.mdx Since AutoNLP has recently been renamed to AutoTrain, let me make the correction on the English file * Update 1.mdx Review of chapter 5/1 * Update 2.mdx Review of chapter 5/2 * Update 3.mdx Review of chapter 5/3 * Update 4.mdx Review of chapter 5/4 * Update 5.mdx Review of chapter 5/5 * Update 6.mdx Review of chapter 5/6 * Update 7.mdx Review of chapter 5/7 * Update 8.mdx Review of chapter 5/8 * Create 1.mdx event's translation * Update _toctree.yml add event to the tree * Update _toctree.yml deletion of the files that pose a problem to pass the checks, will be resubmitted in another PR * Delete 1.mdx deletion of the files that pose a problem to pass the checks, will be resubmitted in another PR * make style correction * Update _toctree.yml the - * Fix spacing Co-authored-by: Lewis Tunstall --- chapters/en/chapter2/8.mdx | 2 +- chapters/fr/_toctree.yml | 26 ++- chapters/fr/chapter0/1.mdx | 35 ++-- chapters/fr/chapter2/1.mdx | 24 +++ chapters/fr/chapter2/2.mdx | 344 ++++++++++++++++++++++++++++++++++++ chapters/fr/chapter2/3.mdx | 231 ++++++++++++++++++++++++ chapters/fr/chapter2/4.mdx | 253 ++++++++++++++++++++++++++ chapters/fr/chapter2/5.mdx | 351 +++++++++++++++++++++++++++++++++++++ chapters/fr/chapter2/6.mdx | 186 ++++++++++++++++++++ chapters/fr/chapter2/7.mdx | 12 ++ chapters/fr/chapter2/8.mdx | 307 ++++++++++++++++++++++++++++++++ chapters/fr/chapter5/1.mdx | 20 +-- chapters/fr/chapter5/2.mdx | 50 +++--- chapters/fr/chapter5/3.mdx | 197 +++++++++++---------- chapters/fr/chapter5/4.mdx | 99 ++++++----- chapters/fr/chapter5/5.mdx | 124 +++++++------ chapters/fr/chapter5/6.mdx | 74 ++++---- chapters/fr/chapter5/7.mdx | 17 +- chapters/fr/chapter5/8.mdx | 104 +++++------ 19 files changed, 2095 insertions(+), 361 deletions(-) create mode 100644 chapters/fr/chapter2/1.mdx create mode 100644 chapters/fr/chapter2/2.mdx create mode 100644 chapters/fr/chapter2/3.mdx create mode 100644 chapters/fr/chapter2/4.mdx create mode 100644 chapters/fr/chapter2/5.mdx create mode 100644 chapters/fr/chapter2/6.mdx create mode 100644 chapters/fr/chapter2/7.mdx create mode 100644 chapters/fr/chapter2/8.mdx diff --git a/chapters/en/chapter2/8.mdx b/chapters/en/chapter2/8.mdx index 43f0a8c9c..ef07b0b31 100644 --- a/chapters/en/chapter2/8.mdx +++ b/chapters/en/chapter2/8.mdx @@ -105,7 +105,7 @@ choices={[ { text: "A model that automatically trains on your data", - explain: "Incorrect. Are you mistaking this with our AutoNLP product?" + explain: "Incorrect. Are you mistaking this with our AutoTrain product?" }, { text: "An object that returns the correct architecture based on the checkpoint", diff --git a/chapters/fr/_toctree.yml b/chapters/fr/_toctree.yml index ad9953b2d..ab363315c 100644 --- a/chapters/fr/_toctree.yml +++ b/chapters/fr/_toctree.yml @@ -3,16 +3,36 @@ - local: chapter0/1 title: Introduction +- title: 2. Utilisation de 🤗 Transformers + sections: + - local: chapter2/1 + title: Introduction + - local: chapter2/2 + title: Derrière le pipeline + - local: chapter2/3 + title: Modèles + - local: chapter2/4 + title: Tokenizers + - local: chapter2/5 + title: Manipulation de plusieurs séquences + - local: chapter2/6 + title: Tout assembler + - local: chapter2/7 + title: Utilisation de base terminée ! + - local: chapter2/8 + title: Quiz de fin de chapitre + quiz: 2 + - title: 5. La bibliothèque 🤗 Datasets sections: - local: chapter5/1 title: Introduction - local: chapter5/2 - title: Que faire si mon ensemble de données n'est pas sur le Hub ? + title: Que faire si mon jeu de données n'est pas sur le Hub ? - local: chapter5/3 title: Il est temps de trancher et de découper - local: chapter5/4 - title: Big Data? 🤗 Des jeux de données à la rescousse ! + title: Données massives ? 🤗 Des jeux de données à la rescousse ! - local: chapter5/5 title: Création de votre propre jeu de données - local: chapter5/6 @@ -21,4 +41,4 @@ title: 🤗 Datasets, vérifié ! - local: chapter5/8 title: Quiz de fin de chapitre - quiz: 5 \ No newline at end of file + quiz: 5 diff --git a/chapters/fr/chapter0/1.mdx b/chapters/fr/chapter0/1.mdx index 14aa13313..3dd008c1a 100644 --- a/chapters/fr/chapter0/1.mdx +++ b/chapters/fr/chapter0/1.mdx @@ -1,28 +1,29 @@ # Introduction -Bienvenue au cours Hugging Face ! Cette introduction vous guidera dans la mise en place d'un environnement de travail. Si vous venez de commencer le cours, nous vous recommandons de consulter d'abord le [Chapitre 1](/course/chapter1), puis de revenir et de configurer votre environnement afin de pouvoir essayer le code vous-même. +Bienvenue au cours d'Hugging Face ! Cette introduction est là pour vous guider dans la mise en place d'un environnement de travail. Si vous venez de commencer le cours, nous vous recommandons de consulter d'abord le [Chapitre 1](/course/fr/chapter1) puis de revenir et de configurer votre environnement afin de pouvoir essayer le code vous-même. -Toutes les bibliothèques que nous utiliserons dans ce cours sont disponibles sous forme de packages Python. Nous allons donc vous montrer comment configurer un environnement Python et installer les bibliothèques spécifiques dont vous aurez besoin. +Toutes les bibliothèques que nous utiliserons dans ce cours sont disponibles sous forme de *packages* Python. Nous allons donc vous montrer comment configurer un environnement Python et installer les bibliothèques spécifiques dont vous aurez besoin. -Nous aborderons deux façons de configurer votre environnement de travail, en utilisant un notebook google Colab ou un environnement virtuel Python. N'hésitez pas à choisir celle qui vous convient le mieux. Pour les débutants, nous vous recommandons vivement de commencer par utiliser un notebook google colab. +Nous aborderons deux façons de configurer votre environnement de travail : soit en utilisant un *notebook* Google Colab, soit en utilisant un environnement virtuel Python. N'hésitez pas à choisir celle qui vous convient le mieux. Pour les débutants, nous vous recommandons vivement de commencer en utilisant un *notebook* Google Colab. -Notez que nous ne couvrirons pas le système Windows. Si vous travaillez sous Windows, nous vous recommandons de suivre le cours en utilisant un cahier Colab. Si vous utilisez une distribution Linux ou macOS, vous pouvez utiliser l'une des deux approches décrites ici. +Notez que nous ne couvrirons pas le système Windows. Si vous travaillez sous Windows, nous vous recommandons de suivre le cours en utilisant un *notebook* Google Colab. Si vous utilisez une distribution Linux ou macOS, vous pouvez utiliser l'une des deux approches décrites ci-dessous. -La plupart du cours repose sur le fait que vous ayez un compte Hugging Face. Nous vous recommandons d'en créer un dès maintenant :[créer un compte](https://huggingface.co/join). +La plupart du cours repose sur le fait que vous ayez un compte Hugging Face. Si vous n'en disposez pas d'un, nous vous recommandons d'en créer un dès maintenant : [créer un compte](https://huggingface.co/join). -## Utilisatoin d'un notebook Google Colab +## Utilisatoin d'un *notebook* Google Colab -L'utilisation d'un notebook google Colab est la configuration la plus simple possible ; démarrez un notebook colab dans votre navigateur et passez directement au codage ! +L'utilisation d'un *notebook* Google Colab est la configuration la plus simple possible. Démarrez un *notebook* dans votre navigateur et passez directement au codage ! -Si vous n'êtes pas familier avec Colab, nous vous recommandons de commencer par suivre les [introduction](https://colab.research.google.com/notebooks/intro.ipynb).Colab vous permet d'utiliser du matériel d'accélération, comme les GPU ou les TPU, et il est gratuit pour les petites charges de travail. +Si vous n'êtes pas familier avec Colab, nous vous recommandons de commencer par suivre l'[introduction](https://colab.research.google.com/notebooks/intro.ipynb). Colab vous permet d'utiliser du matériel comme les GPUs ou les TPUs et est gratuit pour les petites charges de travail. -Une fois que vous vous sentez à l'aise dans Colab, créez un nouveau notebook et commencez à le configurer : +Une fois que vous vous sentez suffisamment à l'aise avec Colab, créez un nouveau *notebook* et commencez à le configurer :
An empty colab notebook
-L'étape suivante consiste à installer les bibliothèques que nous allons utiliser dans ce cours. Nous utiliserons `pip` pour l'installation, qui est le gestionnaire de paquets pour Python. Dans les notebooks, vous pouvez exécuter des commandes système en les faisant précéder du caractère `!`, vous pouvez donc installer la bibliothèque 🤗 Transformers comme suit : +L'étape suivante consiste à installer les bibliothèques que nous allons utiliser dans ce cours. Nous utiliserons `pip` pour l'installation qui est le gestionnaire de *packages* pour Python. Dans les *notebooks*, vous pouvez exécuter des commandes système en les faisant précéder du caractère `!`. Vous pouvez donc installer la bibliothèque 🤗 *Transformers* comme suit : + ``` !pip install transformers ``` @@ -37,22 +38,24 @@ import transformers A gif showing the result of the two commands above: installation and import -Cela installe une version très légère de 🤗 Transformers. En particulier, aucun framework d'apprentissage automatique spécifique (comme PyTorch ou TensorFlow) n'est installé. Comme nous utiliserons de nombreuses fonctionnalités différentes de la bibliothèque, nous recommandons d'installer la version de développement, qui est livrée avec toutes les dépendances requises pour à peu près tous les cas d'utilisation imaginables : +Cela installe une version très légère de 🤗 *Transformers*. En particulier, aucun *framework* d'apprentissage automatique spécifique (comme PyTorch ou TensorFlow) n'est installé. Comme nous utiliserons de nombreuses fonctionnalités différentes de la bibliothèque, nous recommandons d'installer la version de développement qui est livrée avec toutes les dépendances requises pour à peu près tous les cas d'utilisation imaginables : ``` !pip install transformers[sentencepiece] ``` + Cela prendra un peu de temps, mais vous serez alors prêt pour le reste du cours ! + ## Utilisation d'un environnement virtuel Python Si vous préférez utiliser un environnement virtuel Python, la première étape consiste à installer Python sur votre système. Nous vous recommandons de suivre [ce guide](https://realpython.com/installing-python/) pour commencer. -Une fois que Python est installé, vous devriez être en mesure d'exécuter des commandes Python dans votre terminal. Vous pouvez commencer par exécuter la commande suivante pour vous assurer qu'il est correctement installé avant de passer aux étapes suivantes : `python --version`. Cette commande devrait vous indiquer la version de Python disponible sur votre système. +Une fois Python installé, vous devriez être en mesure d'exécuter des commandes Python dans votre terminal. Vous pouvez commencer par exécuter la commande suivante pour vous assurer qu'il est correctement installé avant de passer aux étapes suivantes : `python --version`. Cette commande devrait vous indiquer la version de Python disponible sur votre système. -Lorsque vous exécutez une commande Python dans votre terminal, comme `python --version`, vous devez considérer le programme qui exécute votre commande comme la fonction "main" Python sur votre système. Nous vous recommandons de garder cette installation principale libre de tout paquet, et de l'utiliser pour créer des environnements séparés pour chaque application sur laquelle vous travaillez - de cette façon, chaque application peut avoir ses propres dépendances et paquets, et vous n'aurez pas à vous soucier de problèmes potentiels de compatibilité avec d'autres applications. +Lorsque vous exécutez une commande Python dans votre terminal, comme `python --version`, vous devez considérer le programme qui exécute votre commande comme la fonction « main » Python sur votre système. Nous vous recommandons de garder cette installation principale libre de tout *package* et de l'utiliser pour créer des environnements séparés pour chaque application sur laquelle vous travaillez. De cette façon, chaque application peut avoir ses propres dépendances et *packages*, et vous n'aurez pas à vous soucier de problèmes potentiels de compatibilité avec d'autres applications. -En Python, cela se fait avec les [*environnements virtuels*](https://docs.python.org/3/tutorial/venv.html), qui sont des arbres de répertoires autonomes contenant chacun une installation Python avec une version particulière de Python ainsi que tous les paquets dont l'application a besoin. La création d'un tel environnement virtuel peut se faire à l'aide d'un certain nombre d'outils différents, mais nous utiliserons le paquetage officiel de Python à cette fin, qui s'appelle [`venv`](https://docs.python.org/3/library/venv.html#module-venv). +En Python, cela se fait avec les [*environnements virtuels*](https://docs.python.org/3/tutorial/venv.html), qui sont des arbres de répertoires autonomes contenant chacun une installation Python avec une version particulière de Python ainsi que tous les *packages* dont l'application a besoin. La création d'un tel environnement virtuel peut se faire à l'aide d'un certain nombre d'outils différents, mais nous utiliserons le *package* officiel de Python : [`venv`](https://docs.python.org/3/library/venv.html#module-venv). Tout d'abord, créez le répertoire dans lequel vous souhaitez que votre application se trouve. Par exemple, vous pouvez créer un nouveau répertoire appelé *transformers-course* à la racine de votre répertoire personnel : ``` @@ -98,10 +101,10 @@ which python ### Installation des dépendances -Comme dans la section précédente sur l'utilisation des instances Google Colab, vous devez maintenant installer les packages requis pour continuer. Encore une fois, vous pouvez installer la version de développement de 🤗 Transformers à l'aide du gestionnaire de packages `pip` : +Comme dans la section précédente sur l'utilisation des instances Google Colab, vous devez maintenant installer les *packages* requis pour continuer. Encore une fois, vous pouvez installer la version de développement de 🤗 *Transformers* à l'aide du gestionnaire de packages `pip` : ``` pip install "transformers[sentencepiece]" ``` -Vous êtes maintenant prêt ! \ No newline at end of file +Vous êtes maintenant prêt ! diff --git a/chapters/fr/chapter2/1.mdx b/chapters/fr/chapter2/1.mdx new file mode 100644 index 000000000..bf0c05190 --- /dev/null +++ b/chapters/fr/chapter2/1.mdx @@ -0,0 +1,24 @@ +# Introduction + +Comme vous l'avez vu dans le [Chapitre 1](/course/fr/chapter1), les *transformers* sont généralement très grands. Pouvant aller de plusieurs millions à des dizaines de milliards de paramètres, l'entraînement et le déploiement de ces modèles est une entreprise compliquée. De plus, avec de nouveaux modèles publiés presque quotidiennement et ayant chacun sa propre implémentation, les essayer tous n'est pas une tâche facile. + +La bibliothèque 🤗 *Transformers* a été créée pour résoudre ce problème. Son objectif est de fournir une API unique à travers laquelle tout modèle de *transformers* peut être chargé, entraîné et sauvegardé. Les principales caractéristiques de la bibliothèque sont : + +- **la facilité d'utilisation** : en seulement deux lignes de code il est possible de télécharger, charger et utiliser un modèle de NLP à l'état de l'art pour faire de l'inférence, +- **la flexibilité** : au fond, tous les modèles sont de simples classes PyTorch `nn.Module` ou TensorFlow `tf.keras.Model` et peuvent être manipulés comme n'importe quel autre modèle dans leurs *frameworks* d'apprentissage automatique respectifs, +- **la simplicité** : pratiquement aucune abstraction n'est faite dans la bibliothèque. Avoir tout dans un fichier est un concept central : la passe avant d'un modèle est entièrement définie dans un seul fichier afin que le code lui-même soit compréhensible et piratable. + +Cette dernière caractéristique rend 🤗 *Transformers* très différent des autres bibliothèques d'apprentissage automatique. +Les modèles ne sont pas construits sur des modules partagés entre plusieurs fichiers. Au lieu de cela, chaque modèle possède ses propres couches. +En plus de rendre les modèles plus accessibles et compréhensibles, cela vous permet d'expérimenter des choses facilement sur un modèle sans affecter les autres. + +Ce chapitre commence par un exemple de bout en bout où nous utilisons un modèle et un *tokenizer* ensemble pour reproduire la fonction `pipeline()` introduite dans le [Chapitre 1](/course/chapter1). +Ensuite, nous aborderons l'API *model* : nous nous plongerons dans les classes de modèle et de configuration, nous verrons comment charger un modèle et enfin comment il traite les entrées numériques pour produire des prédictions. + +Nous examinerons ensuite l'API *tokenizer* qui est l'autre composant principal de la fonction `pipeline()`. +Les *tokenizers* s'occupent de la première et de la dernière étape du traitement en gérant la conversion du texte en entrées numériques pour le réseau neuronal et la reconversion en texte lorsqu'elle est nécessaire. +Enfin, nous montrerons comment gérer l'envoi de plusieurs phrases à travers un modèle dans un batch préparé et nous conclurons le tout en examinant de plus près la fonction `tokenizer()`. + + +⚠️ Afin de bénéficier de toutes les fonctionnalités disponibles avec le Model Hub et le 🤗 *Transformers*, nous vous recommandons de créer un compte. + diff --git a/chapters/fr/chapter2/2.mdx b/chapters/fr/chapter2/2.mdx new file mode 100644 index 000000000..f53b1e891 --- /dev/null +++ b/chapters/fr/chapter2/2.mdx @@ -0,0 +1,344 @@ + + +# Derrière le pipeline + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + + +Il s'agit de la première section dont le contenu est légèrement différent selon que vous utilisez PyTorch ou TensorFlow. Cliquez sur le bouton situé au-dessus du titre pour sélectionner la plateforme que vous préférez ! + + +{#if fw === 'pt'} + +{:else} + +{/if} + +Commençons par un exemple complet en regardant ce qui s'est passé en coulisses lorsque nous avons exécuté le code suivant dans le [Chapitre 1](/course/chapter1) : + +```python +from transformers import pipeline + +classifier = pipeline("sentiment-analysis") +classifier( + [ + "I've been waiting for a HuggingFace course my whole life.", # J'ai attendu un cours de HuggingFace toute ma vie. + "I hate this so much!", # Je déteste tellement ça ! + ] +) +``` + +la sortie : + +```python out +[{'label': 'POSITIVE', 'score': 0.9598047137260437}, + {'label': 'NEGATIVE', 'score': 0.9994558095932007}] +``` + +Comme nous l'avons vu dans le [Chapitre 1](/course/fr/chapter1), ce pipeline regroupe trois étapes : le prétraitement, le passage des entrées dans le modèle et le post-traitement : + +
+The full NLP pipeline: tokenization of text, conversion to IDs, and inference through the Transformer model and the model head. + +
+ +Passons rapidement en revue chacun de ces éléments. + +## Prétraitement avec un *tokenizer* + +Comme d'autres réseaux de neurones, les *transformers* ne peuvent pas traiter directement le texte brut, donc la première étape de notre pipeline est de convertir les entrées textuelles en nombres afin que le modèle puisse les comprendre. Pour ce faire, nous utilisons un *tokenizer*, qui sera responsable de : +- diviser l'entrée en mots, sous-mots, ou symboles (comme la ponctuation) qui sont appelés *tokens*, +- associer chaque *token* à un nombre entier, +- ajouter des entrées supplémentaires qui peuvent être utiles au modèle. + +Tout ce prétraitement doit être effectué exactement de la même manière que celui appliqué lors du pré-entraînement du modèle. Nous devons donc d'abord télécharger ces informations depuis le [*Model Hub*](https://huggingface.co/models). Pour ce faire, nous utilisons la classe `AutoTokenizer` et sa méthode `from_pretrained()`. En utilisant le nom du *checkpoint* de notre modèle, elle va automatiquement récupérer les données associées au *tokenizer* du modèle et les mettre en cache (afin qu'elles ne soient téléchargées que la première fois que vous exécutez le code ci-dessous). + +Puisque le *checkpoint* par défaut du pipeline `sentiment-analysis` (analyse de sentiment) est `distilbert-base-uncased-finetuned-sst-2-english` (vous pouvez voir la carte de ce modèle [ici](https://huggingface.co/distilbert-base-uncased-finetuned-sst-2-english)), nous exécutons ce qui suit : + +```python +from transformers import AutoTokenizer + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +``` + +Une fois que nous avons le *tokenizer* nous pouvons lui passer directement nos phrases et obtenir un dictionnaire prêt à être donné à notre modèle ! La seule chose qui reste à faire est de convertir en tenseurs la liste des identifiants d'entrée. + +Vous pouvez utiliser 🤗 *Transformers* sans avoir à vous soucier du *framework* utilisé comme *backend*. Il peut s'agir de PyTorch, de TensorFlow ou de Flax pour certains modèles. Cependant, les *transformers* n'acceptent que les *tenseurs* en entrée. Si c'est la première fois que vous entendez parler de tenseurs, vous pouvez les considérer comme des tableaux NumPy. Un tableau NumPy peut être un scalaire (0D), un vecteur (1D), une matrice (2D), ou avoir davantage de dimensions. Les tenseurs des autres *frameworks* d'apprentissage machine se comportent de manière similaire et sont généralement aussi simples à instancier que les tableaux NumPy. + +Pour spécifier le type de tenseurs que nous voulons récupérer (PyTorch, TensorFlow, ou simplement NumPy), nous utilisons l'argument `return_tensors` : + +{#if fw === 'pt'} +```python +raw_inputs = [ + "I've been waiting for a HuggingFace course my whole life.", # J'ai attendu un cours de HuggingFace toute ma vie. + "I hate this so much!", # Je déteste tellement ça ! +] +inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="pt") +print(inputs) +``` +{:else} +```python +raw_inputs = [ + "I've been waiting for a HuggingFace course my whole life.", # J'ai attendu un cours de HuggingFace toute ma vie. + "I hate this so much!", # Je déteste tellement ça ! +] +inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="tf") +print(inputs) +``` +{/if} + +Ne vous préoccupez pas encore du remplissage (*padding*) et de la troncature, nous les expliquerons plus tard. Les principales choses à retenir ici sont que vous pouvez passer une phrase ou une liste de phrases, ainsi que spécifier le type de tenseurs que vous voulez récupérer (si aucun type n'est passé, par défaut vous obtiendrez une liste de listes comme résultat). + +{#if fw === 'pt'} + +Voici à quoi ressemblent les résultats sous forme de tenseurs PyTorch : + +```python out +{ + 'input_ids': tensor([ + [ 101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102], + [ 101, 1045, 5223, 2023, 2061, 2172, 999, 102, 0, 0, 0, 0, 0, 0, 0, 0] + ]), + 'attention_mask': tensor([ + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ]) +} +``` +{:else} + +Voici à quoi ressemblent les résultats sous forme de tenseurs TensorFlow : + +```python out +{ + 'input_ids': , + 'attention_mask': +} +``` +{/if} + +La sortie elle-même est un dictionnaire contenant deux clés : `input_ids` et `attention_mask`. `input_ids` contient deux lignes d'entiers (une pour chaque phrase) qui sont les identifiants uniques des *tokens* dans chaque phrase. Nous expliquerons ce qu'est l'`attention_mask` plus tard dans ce chapitre. + +## Passage au modèle + +{#if fw === 'pt'} +Nous pouvons télécharger notre modèle prétraîné de la même manière que nous l'avons fait avec notre *tokenizer*. 🤗 *Transformers* fournit une classe `AutoModel` qui possède également une méthode `from_pretrained()` : + +```python +from transformers import AutoModel + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = AutoModel.from_pretrained(checkpoint) +``` +{:else} +Nous pouvons télécharger notre modèle prétraîné de la même manière que nous l'avons fait avec notre *tokenizer*. 🤗 *Transformers* fournit une classe `TFAutoModel` qui possède également une méthode `from_pretrained()` : + +```python +from transformers import TFAutoModel + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = TFAutoModel.from_pretrained(checkpoint) +``` +{/if} + +Dans cet extrait de code, nous avons téléchargé le même *checkpoint* que nous avons utilisé dans notre pipeline auparavant (il devrait en fait avoir déjà été mis en cache) et instancié un modèle avec lui. + +Cette architecture ne contient que le module de *transformer* de base : étant donné certaines entrées, il produit ce que nous appellerons des *états cachés*,également connus sous le nom de *caractéristiques*. +Pour chaque entrée du modèle, nous récupérons un vecteur en grande dimension représentant la **compréhension contextuelle de cette entrée par le *transformer***. + +Si cela ne fait pas sens, ne vous inquiétez pas. Nous expliquons tout plus tard. + +Bien que ces états cachés puissent être utiles en eux-mêmes, ils sont généralement les entrées d'une autre partie du modèle, connue sous le nom de *tête*. Dans le [Chapitre 1](/course/fr/chapter1), les différentes tâches auraient pu être réalisées avec la même architecture mais en ayant chacune d'elles une tête différente. + +### Un vecteur de grande dimension ? + +Le vecteur produit en sortie par le *transformer* est généralement de grande dimension. Il a généralement trois dimensions : + +- **la taille du lot** : le nombre de séquences traitées à la fois (2 dans notre exemple), +- **la longueur de la séquence** : la longueur de la représentation numérique de la séquence (16 dans notre exemple), +- **la taille cachée** : la dimension du vecteur de chaque entrée du modèle. + +On dit qu'il est de « grande dimension » en raison de la dernière valeur. La taille cachée peut être très grande (généralement 768 pour les petits modèles et pour les grands modèles cela peut atteindre 3072 voire plus). + +Nous pouvons le constater si nous alimentons notre modèle avec les entrées que nous avons prétraitées : + + +{#if fw === 'pt'} +```python +outputs = model(**inputs) +print(outputs.last_hidden_state.shape) +``` + +```python out +torch.Size([2, 16, 768]) +``` +{:else} +```py +outputs = model(inputs) +print(outputs.last_hidden_state.shape) +``` + +```python out +(2, 16, 768) +``` +{/if} + +Notez que les sorties des modèles de la bibliothèque 🤗 Transformers se comportent comme des `namedtuples` ou des dictionnaires. Vous pouvez accéder aux éléments par attributs (comme nous l'avons fait), par clé (`outputs["last_hidden_state"]`), ou même par l’index si vous savez exactement où se trouve la chose que vous cherchez (`outputs[0]`). + +### Les têtes des modèles : donner du sens aux chiffres +Les têtes des modèles prennent en entrée le vecteur de grande dimension des états cachés et le projettent sur une autre dimension. Elles sont généralement composées d'une ou de quelques couches linéaires : +
+A Transformer network alongside its head. + +
+ +La sortie du *transformer* est envoyée directement à la tête du modèle pour être traitée. +Dans ce diagramme, le modèle est représenté par sa couche d’enchâssement et les couches suivantes. La couche d’enchâssement convertit chaque identifiant d'entrée dans l'entrée tokenisée en un vecteur qui représente le *token* associé. Les couches suivantes manipulent ces vecteurs en utilisant le mécanisme d'attention pour produire la représentation finale des phrases. +Il existe de nombreuses architectures différentes disponibles dans la bibliothèque 🤗 *Transformers*, chacune étant conçue autour de la prise en charge d'une tâche spécifique. En voici une liste non exhaustive : +- `*Model` (récupérer les états cachés) +- `*ForCausalLM` +- `*ForMaskedLM` +- `*ForMultipleChoice` +- `*ForQuestionAnswering` +- `*ForSequenceClassification` +- `*ForTokenClassification` +- et autres 🤗 + +{#if fw === 'pt'} +Pour notre exemple, nous avons besoin d'un modèle avec une tête de classification de séquence (pour pouvoir classer les phrases comme positives ou négatives). Donc, nous n'utilisons pas réellement la classe `AutoModel` mais plutôt `AutoModelForSequenceClassification` : +```python +from transformers import AutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) +outputs = model(**inputs) +``` +{:else} +Pour notre exemple, nous avons besoin d'un modèle avec une tête de classification de séquence (pour pouvoir classer les phrases comme positives ou négatives). Donc, nous n'utilisons pas réellement la classe ` TFAutoModel` mais plutôt ` TFAutoModelForSequenceClassification` : +```python +from transformers import TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) +outputs = model(inputs) +``` +{/if} + +Maintenant, si nous examinons la forme de nos entrées, la dimensionnalité est beaucoup plus faible. La tête du modèle prend en entrée les vecteurs de grande dimension que nous avons vus précédemment et elle produit des vecteurs contenant deux valeurs (une par étiquette) : +```python +print(outputs.logits.shape) +``` + +{#if fw === 'pt'} +```python out +torch.Size([2, 2]) +``` +{:else} +```python out +(2, 2) +``` +{/if} + +Comme nous n'avons que deux phrases et deux étiquettes, le résultat que nous obtenons est de forme 2 x 2 + +## Post-traitement de la sortie + +Les valeurs que nous obtenons en sortie de notre modèle n'ont pas nécessairement de sens en elles-mêmes. Jetons-y un coup d'oeil : + +```python +print(outputs.logits) +``` + +{#if fw === 'pt'} +```python out +tensor([[-1.5607, 1.6123], + [ 4.1692, -3.3464]], grad_fn=) +``` +{:else} +```python out + +``` +{/if} + +Notre modèle a prédit `[-1.5607, 1.6123]` pour la première phrase et `[ 4.1692, -3.3464]` pour la seconde. Ce ne sont pas des probabilités mais des *logits*, les scores bruts, non normalisés, produits par la dernière couche du modèle. Pour être convertis en probabilités, ils doivent passer par une couche [SoftMax](https://fr.wikipedia.org/wiki/Fonction_softmax) (tous les modèles de la bibliotèque 🤗 Transformers sortent les logits car la fonction de perte de l'entraînement fusionne généralement la dernière fonction d'activation, comme la SoftMax, avec la fonction de perte réelle, comme l'entropie croisée) : + +{#if fw === 'pt'} +```py +import torch + +predictions = torch.nn.functional.softmax(outputs.logits, dim=-1) +print(predictions) +``` +{:else} +```py +import tensorflow as tf + +predictions = tf.math.softmax(outputs.logits, axis=-1) +print(predictions) +``` +{/if} + +{#if fw === 'pt'} +```python out +tensor([[4.0195e-02, 9.5980e-01], + [9.9946e-01, 5.4418e-04]], grad_fn=) +``` +{:else} +```python out +tf.Tensor( +[[4.01951671e-02 9.59804833e-01] + [9.9945587e-01 5.4418424e-04]], shape=(2, 2), dtype=float32) +``` +{/if} + +Maintenant nous pouvons voir que le modèle a prédit `[0.0402, 0.9598]` pour la première phrase et `[0.9995, 0.0005]` pour la seconde. Ce sont des scores de probabilité reconnaissables. + +Pour obtenir les étiquettes correspondant à chaque position, nous pouvons inspecter l'attribut `id2label` de la configuration du modèle (plus de détails dans la section suivante) : + +```python +model.config.id2label +``` + +```python out +{0: 'NEGATIVE', 1: 'POSITIVE'} +``` + +Nous pouvons maintenant conclure que le modèle a prédit ce qui suit : + +- première phrase : NEGATIVE: 0.0402, POSITIVE: 0.9598 +- deuxième phrase : NEGATIVE: 0.9995, POSITIVE: 0.0005 + +Nous avons reproduit avec succès les trois étapes du pipeline : prétraitement avec les *tokenizers*, passage des entrées dans le modèle et post-traitement ! Prenons maintenant le temps de nous plonger plus profondément dans chacune de ces étapes. + + +✏️ **Essayez !** Choisissez deux (ou plus) textes de votre choix (en anglais) et faites-les passer par le pipeline `sentiment-analysis`. Reproduisez ensuite vous-même les étapes vues ici et vérifiez que vous obtenez les mêmes résultats ! + diff --git a/chapters/fr/chapter2/3.mdx b/chapters/fr/chapter2/3.mdx new file mode 100644 index 000000000..96e555191 --- /dev/null +++ b/chapters/fr/chapter2/3.mdx @@ -0,0 +1,231 @@ + + +# Les modèles + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +{#if fw === 'pt'} + +{:else} + +{/if} + +{#if fw === 'pt'} +Dans cette section, nous allons examiner de plus près la création et l'utilisation d'un modèle. Nous utiliserons la classe `AutoModel` qui est pratique lorsque vous voulez instancier n'importe quel modèle à partir d'un checkpoint. + +La classe `AutoModel` et toutes les classes apparentées sont en fait de simples *wrappers* sur la grande variété de modèles disponibles dans la bibliothèque. C'est une enveloppe intelligente car elle peut automatiquement deviner l'architecture appropriée pour votre *checkpoint* et ensuite instancier un modèle avec cette architecture. + +{:else} +Dans cette section, nous allons examiner de plus près la création et l'utilisation d'un modèle. Nous utiliserons la classe `TFAutoModel` qui est pratique lorsque vous voulez instancier n'importe quel modèle à partir d'un checkpoint. + +La classe `TFAutoModel` et toutes les classes apparentées sont en fait de simples *wrappers* sur la grande variété de modèles disponibles dans la bibliothèque. C'est une enveloppe intelligente car elle peut automatiquement deviner l'architecture appropriée pour votre *checkpoint* et ensuite instancier un modèle avec cette architecture. + +{/if} + +Cependant, si vous connaissez le type de modèle que vous voulez utiliser, vous pouvez utiliser directement la classe qui définit son architecture. Voyons comment cela fonctionne avec un modèle BERT. + +## Création d’un *transformer* + +La première chose que nous devons faire pour initialiser un modèle BERT est de charger un objet configuration : + +{#if fw === 'pt'} +```py +from transformers import BertConfig, BertModel + +# Construire la configuration +config = BertConfig() + +# Construire le modèle à partir de la configuration +model = BertModel(config) +``` +{:else} +```py +from transformers import BertConfig, TFBertModel + +# Construire la configuration +config = BertConfig() + +# Construire le modèle à partir de la configuration +model = TFBertModel(config) +``` +{/if} + +La configuration contient de nombreux attributs qui sont utilisés pour construire le modèle : +```py +print(config) +``` + +```python out +BertConfig { + [...] + "hidden_size": 768, + "intermediate_size": 3072, + "max_position_embeddings": 512, + "num_attention_heads": 12, + "num_hidden_layers": 12, + [...] +} +``` + +Bien que vous n'ayez pas encore vu ce que font tous ces attributs, vous devriez en reconnaître certains : l'attribut `hidden_size` définit la taille du vecteur `hidden_states`, et `num_hidden_layers` définit le nombre de couches que le *transformer* possède. + +### Différentes méthodes de chargement + +Un modèle créé à partir de la configuration par défaut est initialisé avec des valeurs aléatoires : + + +{#if fw === 'pt'} +```py +from transformers import BertConfig, BertModel + +config = BertConfig() +model = BertModel(config) + +# Le modèle est initialisé de façon aléatoire ! +``` +{:else} +```py +from transformers import BertConfig, TFBertModel + +config = BertConfig() +model = TFBertModel(config) + +# Le modèle est initialisé de façon aléatoire ! +``` +{/if} + +Le modèle peut être utilisé tel quel mais il produira du charabia. En effet, il doit d'abord être entraîné. Nous pourrions entraîner le modèle à partir de zéro sur la tâche qui nous intéresse mais comme vous l'avez vu dans le [Chapitre 1](/course/fr/chapter1) cela nécessiterait beaucoup de temps et de données. De plus cela aurait un impact environnemental non négligeable. Pour éviter les efforts inutiles et redondants, il est impératif de pouvoir partager et réutiliser les modèles qui ont déjà été entraînés. + +Charger un *transformer* qui a déjà été entraîné est simple : nous pouvons le faire en utilisant la méthode `from_pretrained()` : + + +{#if fw === 'pt'} +```py +from transformers import BertModel + +model = BertModel.from_pretrained("bert-base-cased") +``` + +Comme vu précédemment, nous pouvons remplacer `BertModel` par la classe équivalente `AutoModel`. A partir de maintenant nous ferons cela car cela produit un code agnostique *checkpoint*, c’est-à-dire que si votre code fonctionne pour un *checkpoint* donné, il devrait fonctionner sans problème avec un autre. Cela s'applique même si l'architecture est différente du moment que le *checkpoint* a été entraîné pour une tâche similaire (par exemple, une tâche d'analyse de sentiments). + +{:else} +```py +from transformers import TFBertModel + +model = TFBertModel.from_pretrained("bert-base-cased") +``` + +Comme vu précédemment, nous pouvons remplacer `TFBertModel` par la classe équivalente `TFAutoModel`. A partir de maintenant nous ferons cela car cela produit un code agnostique *checkpoint*, c’est-à-dire que si votre code fonctionne pour un *checkpoint* donné, il devrait fonctionner sans problème avec un autre. Cela s'applique même si l'architecture est différente du moment que le *checkpoint* a été entraîné pour une tâche similaire (par exemple, une tâche d'analyse de sentiments). + +{/if} + +Dans l'exemple de code ci-dessus, nous n'avons pas utilisé `BertConfig` et avons à la place chargé un modèle pré-entraîné via l'identifiant `bert-base-cased`. Il s'agit d'un *checkpoint* qui a été entraîné par les auteurs de BERT eux-mêmes. Vous pouvez trouver davantage de détails à son sujet dans la [fiche du modèle](https://huggingface.co/bert-base-cased). + +Ce modèle est maintenant initialisé avec tous les poids du *checkpoint*. Il peut être utilisé directement pour l'inférence sur les tâches sur lesquelles il a été entraîné. Il peut également être *finetuné* sur une nouvelle tâche. En entraînant avec des poids pré-entraînés plutôt qu'à partir de zéro, nous pouvons rapidement obtenir de bons résultats. + +Les poids ont été téléchargés et mis en cache (afin que les futurs appels à la méthode `from_pretrained()` ne les retéléchargent pas) dans le dossier cache, qui est par défaut *~/.cache/huggingface/transformers*. Vous pouvez personnaliser votre dossier de cache en définissant la variable d'environnement `HF_HOME`. + +L'identifiant utilisé pour charger le modèle peut être l'identifiant de n'importe quel modèle sur le *Model Hub* du moment qu'il est compatible avec l'architecture BERT. La liste complète des *checkpoints* de BERT disponibles peut être trouvée [ici](https://huggingface.co/models?filter=bert). + +### Méthodes de sauvegarde + +Sauvegarder un modèle est aussi facile que d'en charger un. Nous utilisons la méthode `save_pretrained()`, qui est analogue à la méthode `from_pretrained()` : + + +```py +model.save_pretrained("directory_on_my_computer") +``` + +Cela enregistre deux fichiers sur votre disque : + +{#if fw === 'pt'} +``` +ls directory_on_my_computer + +config.json pytorch_model.bin +``` +{:else} +``` +ls directory_on_my_computer + +config.json tf_model.h5 +``` +{/if} + +Si vous jetez un coup d'œil au fichier *config.json*, vous reconnaîtrez les attributs nécessaires pour construire l'architecture du modèle. Ce fichier contient également certaines métadonnées, comme l'origine du *checkpoint* et la version de la bibliothèque 🤗 *Transformers* que vous utilisiez lors du dernier enregistrement du point *checkpoint*. + +{#if fw === 'pt'} +Le fichier *pytorch_model.bin* est connu comme le *dictionnaire d'état*. Il contient tous les poids de votre modèle. Les deux fichiers vont de pair : la configuration est nécessaire pour connaître l'architecture de votre modèle, tandis que les poids du modèle sont les paramètres de votre modèle. + +{:else} +Le fichier *tf_model.h5* est connu comme le *dictionnaire d'état*. Il contient tous les poids de votre modèle. Les deux fichiers vont de pair : la configuration est nécessaire pour connaître l'architecture de votre modèle, tandis que les poids du modèle sont les paramètres de votre modèle. + +{/if} + +### Utilisation d'un *transformer* pour l'inférence + +Maintenant que vous savez comment charger et sauvegarder un modèle, essayons de l'utiliser pour faire quelques prédictions. Les *transformers* ne peuvent traiter que des nombres. Des nombres que le *tokenizer* génère. Mais avant de parler des *tokenizers*, explorons les entrées que le modèle accepte. + +Les *tokenizers* se chargent de passer les entrées vers les tenseurs du *framework* approprié. Pour vous aider à comprendre ce qui se passe, jetons un coup d'œil rapide à ce qui doit être fait avant d'envoyer les entrées au modèle. + +Disons que nous avons les séquences suivantes : + + +```py +sequences = ["Hello!", "Cool.", "Nice!"] +``` + +Le *tokenizer* les convertit en indices de vocabulaire qui sont généralement appelés *input IDs*. Chaque séquence est maintenant une liste de nombres ! La sortie résultante est : + +```py no-format +encoded_sequences = [ + [101, 7592, 999, 102], + [101, 4658, 1012, 102], + [101, 3835, 999, 102], +] +``` + +Il s'agit d'une liste de séquences encodées : une liste de listes. Les tenseurs n'acceptent que des formes rectangulaires (pensez aux matrices). Ce « tableau » est déjà de forme rectangulaire, donc le convertir en tenseur est facile : + +{#if fw === 'pt'} +```py +import torch + +model_inputs = torch.tensor(encoded_sequences) +``` +{:else} +```py +import tensorflow as tf + +model_inputs = tf.constant(encoded_sequences) +``` +{/if} + +### Utilisation des tenseurs comme entrées du modèle + +L'utilisation des tenseurs avec le modèle est extrêmement simple, il suffit d'appeler le modèle avec les entrées : + + +```py +output = model(model_inputs) +``` + +Bien que le modèle accepte un grand nombre d'arguments différents, seuls les identifiants d'entrée sont nécessaires. Nous expliquerons plus tard ce que font les autres arguments et quand ils sont nécessaires. Avant cela, regardons de plus près les *tokenizers*, cet outil qui construit les entrées qu'un *transformer* peut comprendre. diff --git a/chapters/fr/chapter2/4.mdx b/chapters/fr/chapter2/4.mdx new file mode 100644 index 000000000..a8fb7e3e7 --- /dev/null +++ b/chapters/fr/chapter2/4.mdx @@ -0,0 +1,253 @@ + + +# Les *tokenizers* + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + + + +Les *tokenizers* sont l'un des principaux composants du pipeline de NLP. Ils ont un seul objectif : traduire le texte en données pouvant être traitées par le modèle. Les modèles ne pouvant traiter que des nombres, les *tokenizers* doivent convertir nos entrées textuelles en données numériques. Dans cette section, nous allons explorer ce qui se passe exactement dans le pipeline de tokénisation. + +Dans les tâches de NLP, les données traitées sont généralement du texte brut. Voici un exemple de ce type de texte : + + +``` +Jim Henson was a puppeteer # Jim Henson était un marionnettiste. +``` + +Les modèles ne pouvant traiter que des nombres, nous devons trouver un moyen de convertir le texte brut en nombres. C'est ce que font les *tokenizers* et il existe de nombreuses façons de procéder. L'objectif est de trouver la représentation la plus significative, c'est-à-dire celle qui a le plus de sens pour le modèle, et si possible qui soit la plus petite. + +Voyons quelques exemples d'algorithmes de tokénisation et essayons de répondre à certaines des questions que vous pouvez vous poser à ce sujet. + +## *Tokenizer* basé sur les mots + + + + +Le premier type de *tokenizer* qui vient à l'esprit est celui basé sur les mots. Il est généralement très facile à utiliser et configurable avec seulement quelques règles. Il donne souvent des résultats décents. Par exemple, dans l'image ci-dessous, l'objectif est de diviser le texte brut en mots et de trouver une représentation numérique pour chacun d'eux : + +
+ An example of word-based tokenization. + +
+ +Il existe différentes façons de diviser le texte. Par exemple, nous pouvons utiliser les espaces pour segmenter le texte en mots en appliquant la fonction `split()` de Python : + +```py +tokenized_text = "Jim Henson was a puppeteer".split() +print(tokenized_text) +``` + +```python out +['Jim', 'Henson', 'was', 'a', 'puppeteer'] # ['Jim', 'Henson', était, 'un', 'marionnettiste'] +``` + +Il existe également des variantes des *tokenizers* basés sur les mots qui ont des règles supplémentaires pour la ponctuation. Avec ce type de *tokenizers* nous pouvons nous retrouver avec des « vocabulaires » assez larges, où un vocabulaire est défini par le nombre total de *tokens* indépendants que nous avons dans notre corpus. + +Un identifiant est attribué à chaque mot, en commençant par 0 et en allant jusqu'à la taille du vocabulaire. Le modèle utilise ces identifiants pour identifier chaque mot. + +Si nous voulons couvrir complètement une langue avec un *tokenizer* basé sur les mots, nous devons avoir un identifiant pour chaque mot de la langue que nous traitons, ce qui génére une énorme quantité de *tokens*. Par exemple, il y a plus de 500 000 mots dans la langue anglaise. Ainsi pour associer chaque mot à un identifiant, nous devrions garder la trace d'autant d'identifiants. De plus, des mots comme « chien » sont représentés différemment de mots comme « chiens ». Le modèle n'a initialement aucun moyen de savoir que « chien » et « chiens » sont similaires : il identifie les deux mots comme non apparentés. Il en va de même pour d'autres mots similaires, comme « maison » et « maisonnette » que le modèle ne considérera pas comme similaires au départ. + +Enfin, nous avons besoin d'un *token* personnalisé pour représenter les mots qui ne font pas partie de notre vocabulaire. C'est ce qu'on appelle le *token* « inconnu » souvent représenté par « [UNK] » (de l’anglais « unknown ») ou « <unk> ; ». C'est généralement un mauvais signe si vous constatez que le *tokenizer* produit un nombre important de ce jeton spécial. Cela signifie qu’il n'a pas été en mesure de récupérer une représentation sensée d'un mot et que vous perdez des informations en cours de route. L'objectif de l'élaboration du vocabulaire est de faire en sorte que le *tokenizer* transforme le moins de mots possible en *token* inconnu. + +Une façon de réduire la quantité de *tokens* inconnus est d'aller un niveau plus profond, en utilisant un *tokenizer* basé sur les caractères. + + +## *Tokenizer* basé sur les caractères + + + +Les *tokenizers* basés sur les caractères divisent le texte en caractères, plutôt qu'en mots. Cela présente deux avantages principaux : + +- le vocabulaire est beaucoup plus petit +- il y a beaucoup moins de *tokens* hors vocabulaire (inconnus) puisque chaque mot peut être construit à partir de caractères. + +Mais là aussi, des questions se posent concernant les espaces et la ponctuation : + + +
+ An example of character-based tokenization. + +
+ +Cette approche n'est pas non plus parfaite. Puisque la représentation est maintenant basée sur des caractères plutôt que sur des mots, on pourrait dire intuitivement qu’elle est moins significative : chaque caractère ne signifie pas grand-chose en soi, alors que c'est le cas pour les mots. Toutefois, là encore, cela diffère selon la langue. En chinois, par exemple, chaque caractère est porteur de plus d'informations qu'un caractère dans une langue latine. + +Un autre élément à prendre en compte est que nous nous retrouverons avec une très grande quantité de *tokens* à traiter par notre modèle. Alors qu’avec un *tokenizer* basé sur les mots, pour un mot donné on aurait qu'un seul *token*, avec un *tokenizer* basé sur les caractères, cela peut facilement se transformer en 10 *tokens* voire plus. + +Pour obtenir le meilleur des deux mondes, nous pouvons utiliser une troisième technique qui combine les deux approches : la *tokénisation en sous-mots*. + + +## Tokénisation en sous-mots + + + +Les algorithmes de tokenisation en sous-mots reposent sur le principe selon lequel les mots fréquemment utilisés ne doivent pas être divisés en sous-mots plus petits, mais les mots rares doivent être décomposés en sous-mots significatifs. + +Par exemple, le mot « maisonnette » peut être considéré comme un mot rare et peut être décomposé en « maison » et « ette ». Ces deux mots sont susceptibles d'apparaître plus fréquemment en tant que sous-mots autonomes, alors qu'en même temps le sens de « maison » est conservé par le sens composite de « maison » et « ette ». + +Voici un exemple montrant comment un algorithme de tokenisation en sous-mots tokeniserait la séquence « Let's do tokenization ! » : + + +
+ A subword tokenization algorithm. + +
+ +Ces sous-mots finissent par fournir beaucoup de sens sémantique. Par exemple, ci-dessus, « tokenization » a été divisé en « token » et « ization » : deux *tokens* qui ont un sens sémantique tout en étant peu encombrants (seuls deux *tokens* sont nécessaires pour représenter un long mot). Cela nous permet d'avoir une couverture relativement bonne avec de petits vocabulaires et presque aucun *token* inconnu. + +Cette approche est particulièrement utile dans les langues agglutinantes comme le turc, où l'on peut former des mots complexes (presque) arbitrairement longs en enchaînant des sous-mots. + + +### Et plus encore ! + +Il existe de nombreuses autres techniques. Pour n'en citer que quelques-unes : + +- le Byte-level BPE utilisé par exemple dans le GPT-2 +- le WordPiece utilisé par exemple dans BERT +- SentencePiece ou Unigram, utilisés dans plusieurs modèles multilingues. + +Vous devriez maintenant avoir une connaissance suffisante du fonctionnement des tokenizers pour commencer à utiliser l'API. + + +## Chargement et sauvegarde + +Le chargement et la sauvegarde des *tokenizers* est aussi simple que pour les modèles. En fait, c'est basé sur les deux mêmes méthodes : `from_pretrained()` et `save_pretrained()`. Ces méthodes vont charger ou sauvegarder l'algorithme utilisé par le *tokenizer* (un peu comme l'*architecture* du modèle) ainsi que son vocabulaire (un peu comme les *poids* du modèle). + +Le chargement du *tokenizer* de BERT entraîné avec le même *checkpoint* que BERT se fait de la même manière que le chargement du modèle, sauf que nous utilisons la classe `BertTokenizer` : + + +```py +from transformers import BertTokenizer + +tokenizer = BertTokenizer.from_pretrained("bert-base-cased") +``` + +{#if fw === 'pt'} +Similaire à `AutoModel`, la classe `AutoTokenizer` récupère la classe de *tokenizer* appropriée dans la bibliothèque basée sur le nom du *checkpoint*. Elle peut être utilisée directement avec n'importe quel *checkpoint* : + +{:else} +Similaire à `TFAutoModel`, la classe `AutoTokenizer` récupère la classe de *tokenizer* appropriée dans la bibliothèque basée sur le nom du *checkpoint*. Elle peut être utilisée directement avec n'importe quel *checkpoint* : + +{/if} + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +``` + +Nous pouvons à présent utiliser le *tokenizer* comme indiqué dans la section précédente : + +```python +tokenizer("Using a Transformer network is simple") +``` + +```python out +{'input_ids': [101, 7993, 170, 11303, 1200, 2443, 1110, 3014, 102], + 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0], + 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]} +``` + +La sauvegarde d'un tokenizer est identique à celle d'un modèle : + +```py +tokenizer.save_pretrained("directory_on_my_computer") +``` + +Nous parlerons plus en détail des `token_type_ids` au [Chapitre 3](/course/fr/chapter3) et nous expliquerons la clé `attention_mask` un peu plus tard. Tout d'abord, voyons comment les `input_ids` sont générés. Pour ce faire, nous devons examiner les méthodes intermédiaires du *tokenizer*. + +## Encodage + + + + +La traduction d'un texte en chiffres est connue sous le nom d’*encodage*. L'encodage se fait en deux étapes : la tokenisation, suivie de la conversion en identifiants d'entrée. + +Comme nous l'avons vu, la première étape consiste à diviser le texte en mots (ou parties de mots, symboles de ponctuation, etc.), généralement appelés *tokens*. De nombreuses règles peuvent régir ce processus. C'est pourquoi nous devons instancier le *tokenizer* en utilisant le nom du modèle afin de nous assurer que nous utilisons les mêmes règles que celles utilisées lors du pré-entraînement du modèle. + +La deuxième étape consiste à convertir ces *tokens* en nombres afin de construire un tenseur à partir de ceux-ci ainsi que de les transmettre au modèle. Pour ce faire, le *tokenizer* possède un *vocabulaire*, qui est la partie que nous téléchargeons lorsque nous l'instancions avec la méthode `from_pretrained()`. Encore une fois, nous devons utiliser le même vocabulaire que celui utilisé lors du pré-entraînement du modèle. + +Pour mieux comprendre les deux étapes, nous allons les explorer séparément. A noter que nous utilisons des méthodes effectuant séparément des parties du pipeline de tokenisation afin de montrer les résultats intermédiaires de ces étapes. Néanmoins, en pratique, il faut appeler le *tokenizer* directement sur vos entrées (comme indiqué dans la section 2). + +### Tokenisation + +Le processus de tokenisation est effectué par la méthode `tokenize()` du *tokenizer* : + + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") + +sequence = "Using a Transformer network is simple" +tokens = tokenizer.tokenize(sequence) + +print(tokens) +``` + +La sortie de cette méthode est une liste de chaînes de caractères ou de *tokens* : + +```python out +['Using', 'a', 'transform', '##er', 'network', 'is', 'simple'] +``` + +Ce *tokenizer* est un *tokenizer* de sous-mots : il découpe les mots jusqu'à obtenir des *tokens* qui peuvent être représentés par son vocabulaire. C'est le cas ici avec `transformer` qui est divisé en deux *tokens* : `transform` et `##er`. + +### De *tokens* aux identifiants d'entrée + +La conversion en identifiants d'entrée est gérée par la méthode `convert_tokens_to_ids()` du *tokenizer* : + + +```py +ids = tokenizer.convert_tokens_to_ids(tokens) + +print(ids) +``` + +```python out +[7993, 170, 11303, 1200, 2443, 1110, 3014] +``` + +Une fois converties en tenseur dans le *framework* approprié, ces sorties peuvent ensuite être utilisées comme entrées d'un modèle, comme nous l'avons vu précédemment dans ce chapitre. + + + +✏️ **Essayez !** Reproduisez les deux dernières étapes (tokénisation et conversion en identifiants d'entrée) sur les phrases des entrées que nous avons utilisées dans la section 2 (« I've been waiting for a HuggingFace course my whole life. » et « I hate this so much! »). Vérifiez que vous obtenez les mêmes identifiants d'entrée que nous avons obtenus précédemment ! + + + +## Décodage + +Le *décodage* va dans l'autre sens : à partir d'indices du vocabulaire nous voulons obtenir une chaîne de caractères. Cela peut être fait avec la méthode `decode()` comme suit : + + +```py +decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014]) +print(decoded_string) +``` + +```python out +'Using a Transformer network is simple' +``` + +Notez que la méthode `decode` non seulement reconvertit les indices en *tokens* mais regroupe également les *tokens* faisant partie des mêmes mots. Le but étant de produire une phrase lisible. Ce comportement sera extrêmement utile lorsque dans la suite du cours nous utiliserons des modèles pouvant produire du nouveau texte (soit du texte généré à partir d'un *prompt*, soit pour des problèmes de séquence à séquence comme la traduction ou le résumé de texte). + +Vous devriez maintenant comprendre les opérations atomiques qu'un *tokenizer* peut gérer : tokenisation, conversion en identifiants, et reconversion des identifiants en chaîne de caractères. Cependant, nous n'avons fait qu'effleurer la partie émergée de l'iceberg. Dans la section suivante, nous allons pousser notre approche jusqu'à ses limites et voir comment les surmonter. diff --git a/chapters/fr/chapter2/5.mdx b/chapters/fr/chapter2/5.mdx new file mode 100644 index 000000000..ab3b90b1e --- /dev/null +++ b/chapters/fr/chapter2/5.mdx @@ -0,0 +1,351 @@ + + +# Manipulation de plusieurs séquences + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +{#if fw === 'pt'} + +{:else} + +{/if} + +Dans la section précédente, nous avons exploré le cas d'utilisation le plus simple : faire une inférence sur une seule séquence de petite longueur. Cependant, certaines questions émergent déjà : + +- comment gérer de plusieurs séquences ? +- comment gérer de plusieurs séquences *de longueurs différentes* ? +- les indices du vocabulaire sont-ils les seules entrées qui permettent à un modèle de bien fonctionner ? +- existe-t-il une séquence trop longue ? + +Voyons quels types de problèmes ces questions posent et comment nous pouvons les résoudre en utilisant l'API 🤗 *Transformers*. + +## Les modèles attendent un batch d'entrées + +Dans l'exercice précédent, vous avez vu comment les séquences sont traduites en listes de nombres. +Convertissons cette liste de nombres en un tenseur et envoyons-le au modèle : + +{#if fw === 'pt'} +```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." # J'ai attendu un cours d’HuggingFace toute ma vie. + +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) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." # J'ai attendu un cours d’HuggingFace toute ma vie. + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) +input_ids = tf.constant(ids) +# This line will fail. +model(input_ids) +``` + +```py out +InvalidArgumentError: Input to reshape is a tensor with 14 values, but the requested shape has 196 [Op:Reshape] +``` +{/if} + +Pourquoi cela a échoué ? Nous avons suivi les étapes du pipeline de la section 2. + +Le problème est que nous avons envoyé une seule séquence au modèle, alors que les modèles de l’API 🤗 *Transformers* attendent plusieurs phrases par défaut. Ici, nous avons essayé de faire ce que le *tokenizer* fait en coulisses lorsque nous l'avons appliqué à une `séquence`. Cependant si vous regardez de près, vous verrez qu'il n'a pas seulement converti la liste des identifiants d'entrée en un tenseur mais aussi ajouté une dimension par-dessus : + + +{#if fw === 'pt'} +```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]]) +``` +{:else} +```py +tokenized_inputs = tokenizer(sequence, return_tensors="tf") +print(tokenized_inputs["input_ids"]) +``` + +```py out + +``` +{/if} + +Essayons à nouveau en ajoutant une nouvelle dimension : + +{#if fw === 'pt'} +```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." # J'ai attendu un cours d’HuggingFace toute ma vie. + + +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) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." +# J'ai attendu un cours d’HuggingFace toute ma vie. + + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) + +input_ids = tf.constant([ids]) +print("Input IDs:", input_ids) + +output = model(input_ids) +print("Logits:", output.logits) +``` +{/if} + +Nous affichons les identifiants d'entrée ainsi que les logits résultants. Voici la sortie : + +{#if fw === 'pt'} +```python out +Input IDs: [[ 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012]] +Logits: [[-2.7276, 2.8789]] +``` +{:else} +```py out +Input IDs: tf.Tensor( +[[ 1045 1005 2310 2042 3403 2005 1037 17662 12172 2607 2026 2878 + 2166 1012]], shape=(1, 14), dtype=int32) +Logits: tf.Tensor([[-2.7276208 2.8789377]], shape=(1, 2), dtype=float32) +``` +{/if} + +Le « *batching* » est l'acte d'envoyer plusieurs phrases à travers le modèle, toutes en même temps. Si vous n'avez qu'une seule phrase, vous pouvez simplement construire un batch avec une seule séquence : + +``` +batched_ids = [ids, ids] +``` + +Il s'agit d'un batch de deux séquences identiques ! + + + +✏️ **Essayez !** Convertissez cette liste `batched_ids` en un tenseur et passez-la dans votre modèle. Vérifiez que vous obtenez les mêmes logits que précédemment (mais deux fois) ! + + + +Utiliser des *batchs* permet au modèle de fonctionner lorsque vous lui donnez plusieurs séquences. Utiliser plusieurs séquences est aussi simple que de construire un batch avec une seule séquence. Il y a cependant un deuxième problème. Lorsque vous essayez de regrouper deux phrases (ou plus), elles peuvent être de longueurs différentes. Si vous avez déjà travaillé avec des tenseurs, vous savez qu'ils doivent être de forme rectangulaire. Vous ne pourrez donc pas convertir directement la liste des identifiants d'entrée en un tenseur. Pour contourner ce problème, nous avons l'habitude de *rembourrer* (le *padding* en anglais) les entrées. + +## *Padding* des entrées + +La liste de listes suivante ne peut pas être convertie en un tenseur : + + +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200] +] +``` + +Afin de contourner ce problème, nous utilisons le *padding* pour que nos tenseurs aient une forme rectangulaire. Le *padding* permet de s'assurer que toutes nos phrases ont la même longueur en ajoutant un mot spécial appelé *padding token* aux phrases ayant moins de valeurs. Par exemple, si vous avez 10 phrases de 10 mots et 1 phrase de 20 mots, le *padding* fait en sorte que toutes les phrases aient 20 mots. Dans notre exemple, le tenseur résultant ressemble à ceci : + +```py no-format +padding_id = 100 + +batched_ids = [ + [200, 200, 200], + [200, 200, padding_id], +] +``` + +L'identifiant du jeton de padding peut être trouvé dans `tokenizer.pad_token_id`. Utilisons-le et envoyons nos deux phrases à travers le modèle premièrement individuellement puis en étant mises dans un même batch : + +{#if fw === 'pt'} +```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=) +tensor([[ 0.5803, -0.4125]], grad_fn=) +tensor([[ 1.5694, -1.3895], + [ 1.3373, -1.2163]], grad_fn=) +``` +{:else} +```py no-format +model = TFAutoModelForSequenceClassification.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(tf.constant(sequence1_ids)).logits) +print(model(tf.constant(sequence2_ids)).logits) +print(model(tf.constant(batched_ids)).logits) +``` + +```py out +tf.Tensor([[ 1.5693678 -1.3894581]], shape=(1, 2), dtype=float32) +tf.Tensor([[ 0.5803005 -0.41252428]], shape=(1, 2), dtype=float32) +tf.Tensor( +[[ 1.5693681 -1.3894582] + [ 1.3373486 -1.2163193]], shape=(2, 2), dtype=float32) +``` +{/if} + +Il y a quelque chose qui ne va pas avec les logits de notre prédiction avec les séquences mises dans un même batch. La deuxième ligne devrait être la même que les logits pour la deuxième phrase, mais nous avons des valeurs complètement différentes ! + +C'est parce que dans un *transformer* les couches d’attention *contextualisent* chaque *token*. Celles-ci prennent en compte les *tokens* de *padding* puisqu'elles analysent tous les *tokens* d'une séquence. Pour obtenir le même résultat lorsque l'on passe dans notre modèle des phrases individuelles de différentes longueurs ou un batch composé de mêmes phrases avec *padding*, nous devons dire à ces couches d'attention d'ignorer les jetons de *padding*. Ceci est fait en utilisant un masque d'attention. + + +## Masques d'attention + +Les masques d'attention sont des tenseurs ayant exactement la même forme que le tenseur d'identifiants d'entrée, remplis de 0 et de 1 : +- 1 indique que les *tokens* correspondants doivent être analysés +- 0 indique que les *tokens* correspondants ne doivent pas être analysés (c'est-à-dire qu'ils doivent être ignorés par les couches d'attention du modèle). + +Complétons l'exemple précédent avec un masque d'attention : + + +{#if fw === 'pt'} +```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=) +``` +{:else} +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200, tokenizer.pad_token_id], +] + +attention_mask = [ + [1, 1, 1], + [1, 1, 0], +] + +outputs = model(tf.constant(batched_ids), attention_mask=tf.constant(attention_mask)) +print(outputs.logits) +``` + +```py out +tf.Tensor( +[[ 1.5693681 -1.3894582 ] + [ 0.5803021 -0.41252586]], shape=(2, 2), dtype=float32) +``` +{/if} + +Nous obtenons maintenant les mêmes logits pour la deuxième phrase du batch. + +Remarquez comment la dernière valeur de la deuxième séquence est un identifiant de *padding* valant 0 dans le masque d'attention. + + + + +✏️ **Essayez !** Appliquez la tokénisation manuellement sur les deux phrases utilisées dans la section 2 (« I've been waiting for a HuggingFace course my whole life. » et « I hate this so much! »). Passez-les dans le modèle et vérifiez que vous obtenez les mêmes logits que dans la section 2. Ensuite regroupez-les en utilisant le jeton de *padding* et créez le masque d'attention approprié. Vérifiez que vous obtenez les mêmes résultats qu’en passant par le modèle ! + + + + +## Séquences plus longues + +Les *transformers* acceptent en entrée que des séquences d’une longueur limitée. La plupart des modèles traitent des séquences allant jusqu'à 512 ou 1024 *tokens* et plantent lorsqu'on leur demande de traiter des séquences plus longues. Il existe deux solutions à ce problème : + +- utiliser un modèle avec une longueur de séquence supportée plus longue, +- tronquer les séquences. + +Certains modèles sont spécialisés dans le traitement de très longues séquences comme par exemple le [Longformer](https://huggingface.co/transformers/model_doc/longformer.html) ou le [LED](https://huggingface.co/transformers/model_doc/led.html). Si vous travaillez sur une tâche qui nécessite de très longues séquences, nous vous recommandons de jeter un coup d'œil à ces modèles. + +Sinon, nous vous recommandons de tronquer vos séquences en spécifiant le paramètre `max_sequence_length` : + + +```py +sequence = sequence[:max_sequence_length] +``` diff --git a/chapters/fr/chapter2/6.mdx b/chapters/fr/chapter2/6.mdx new file mode 100644 index 000000000..f43edef28 --- /dev/null +++ b/chapters/fr/chapter2/6.mdx @@ -0,0 +1,186 @@ + + +# Tout assembler + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +Dans les dernières sections, nous avons fait de notre mieux pour effectuer la plupart du travail manuellement. Nous avons exploré le fonctionnement des *tokenizers* et examiné la tokenisation, la conversion en identifiants d'entrée, le *padding*, la troncature et les masques d'attention. + +Cependant, comme nous l'avons vu dans la section 2, l'API 🤗 *Transformers* peut gérer tout cela pour nous via une fonction dans laquelle nous allons nous plonger ici. Lorsque vous appelez votre `tokenizer` directement sur la phrase, vous récupérez des entrées qui sont prêtes à être passées dans votre modèle : + + +```py +from transformers import AutoTokenizer + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." # J'ai attendu un cours d’HuggingFace toute ma vie. + +model_inputs = tokenizer(sequence) +``` + +Ici, la variable `model_inputs` contient tout ce qui est nécessaire au bon fonctionnement d'un modèle. Pour DistilBERT, cela inclut les identifiants d'entrée ainsi que le masque d'attention. D'autres modèles qui acceptent des entrées supplémentaires sont également fournis par l'objet `tokenizer`. + +Comme nous allons le voir dans les quelques exemples ci-dessous, cette méthode est très puissante. Premièrement, elle peut tokeniser une seule séquence : + + +```py +sequence = "I've been waiting for a HuggingFace course my whole life." # J'ai attendu un cours d’HuggingFace toute ma vie. + + +model_inputs = tokenizer(sequence) +``` + +Elle gère également plusieurs séquences à la fois, sans modification de l'API : + + +```py +sequences = [ + "I've been waiting for a HuggingFace course my whole life.", + "So have I!", +] # « J'ai attendu un cours de HuggingFace toute ma vie. », « Moi aussi ! » + +model_inputs = tokenizer(sequences) +``` + +Il est possible de faire du *padding* selon plusieurs objectifs : + +```py +# Remplit les séquences jusqu'à la longueur maximale de la séquence +model_inputs = tokenizer(sequences, padding="longest") + +# Remplit les séquences jusqu'à la longueur maximale du modèle +# (512 for BERT or DistilBERT) +model_inputs = tokenizer(sequences, padding="max_length") + +# Remplit les séquences jusqu'à la longueur maximale spécifiée +model_inputs = tokenizer(sequences, padding="max_length", max_length=8) +``` + +La fonction peut également tronquer les séquences : + +```py +sequences = [ + "I've been waiting for a HuggingFace course my whole life.", + "So have I!", +] # « J'ai attendu un cours de HuggingFace toute ma vie. », « Moi aussi ! » + +# Tronque les séquences qui sont plus longues que la longueur maximale du modèle +# (512 for BERT or DistilBERT) +model_inputs = tokenizer(sequences, truncation=True) + +# Tronque les séquences qui sont plus longues que la longueur maximale spécifiée +model_inputs = tokenizer(sequences, max_length=8, truncation=True) +``` + +L'objet `tokenizer` peut gérer la conversion en des tenseurs de *frameworks* spécifiques. Ils peuvent ensuite être directement envoyés au modèle. Par exemple, dans le code suivant, nous demandons au *tokenizer* de retourner des tenseurs Pytorch lorsque l’on spécifie `"pt"`, de retourner des tenseurs TensorFlow lorsque l’on spécifie `"tf"` et des tableaux NumPy lorsque l’on indique `"np"` : + +```py +sequences = [ + "I've been waiting for a HuggingFace course my whole life.", + "So have I!", +] # « J'ai attendu un cours de HuggingFace toute ma vie. », « Moi aussi ! » + +# Retourne des tenseurs PyTorch +model_inputs = tokenizer(sequences, padding=True, return_tensors="pt") + +# Retourne des tenseurs TensorFlow +model_inputs = tokenizer(sequences, padding=True, return_tensors="tf") + +# Retourne des tableaux NumPy +model_inputs = tokenizer(sequences, padding=True, return_tensors="np") +``` + +## Jetons spéciaux + +Si nous jetons un coup d'œil aux identifiants d'entrée renvoyés par le *tokenizer*, nous verrons qu'ils sont un peu différents de ceux que nous avions précédemment : + + +```py +sequence = "I've been waiting for a HuggingFace course my whole life." # « J'ai attendu un cours de HuggingFace toute ma vie. » + +model_inputs = tokenizer(sequence) +print(model_inputs["input_ids"]) + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) +print(ids) +``` + +```python out +[101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102] +[1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012] +``` + +Un identifiant symbolique a été ajouté au début ainsi qu’un autre à la fin. Décodons les deux séquences d'identifiants ci-dessus pour voir de quoi il s'agit : + +```py +print(tokenizer.decode(model_inputs["input_ids"])) +print(tokenizer.decode(ids)) +``` + +```python out +"[CLS] i've been waiting for a huggingface course my whole life. [SEP]" +"i've been waiting for a huggingface course my whole life." +``` + +Le *tokenizer* a ajouté le mot spécial `[CLS]` au début et le mot spécial `[SEP]` à la fin. C'est parce que le modèle a été pré-entraîné avec ces mots, donc pour obtenir les mêmes résultats pour l'inférence, nous devons également les ajouter. Notez que certains modèles n'ajoutent pas de mots spéciaux, ou en ajoutent des différents. Les modèles peuvent aussi ajouter ces mots spéciaux seulement au début, ou seulement à la fin. Dans tous les cas, le *tokenizer* sait lesquels sont attendus et s'en occupe pour vous. + +## Conclusion : du *tokenizer* au modèle + +Maintenant que nous avons vu toutes les étapes individuelles que l'objet `tokenizer` utilise lorsqu'il est appliqué sur des textes, voyons une dernière fois comment il peut gérer plusieurs séquences (*padding*), de très longues séquences (*troncation*) et plusieurs types de tenseurs avec son API principale : + + +{#if fw === 'pt'} +```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) +sequences = [ + "I've been waiting for a HuggingFace course my whole life.", + "So have I!", +] # « J'ai attendu un cours de HuggingFace toute ma vie. », « Moi aussi ! » + + +tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt") +output = model(**tokens) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) +sequences = [ + "I've been waiting for a HuggingFace course my whole life.", + "So have I!", +] # « J'ai attendu un cours de HuggingFace toute ma vie. », « Moi aussi ! » + +tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="tf") +output = model(**tokens) +``` +{/if} diff --git a/chapters/fr/chapter2/7.mdx b/chapters/fr/chapter2/7.mdx new file mode 100644 index 000000000..c6fac5c9a --- /dev/null +++ b/chapters/fr/chapter2/7.mdx @@ -0,0 +1,12 @@ +# Utilisation de base terminée ! + +Bravo à vous pour avoir suivi le cours jusqu'ici ! Pour récapituler, dans ce chapitre vous avez : +- appris les blocs de construction de base d'un *transformer*, +- appris ce qui constitue un pipeline de tokenisation, +- vu comment utiliser un *transformer* en pratique, +- appris comment tirer parti d'un *tokenizer* pour convertir du texte en tenseurs compréhensibles par le modèle, +- configurer ensemble un *tokenizer* et un modèle afin de passer du texte aux prédictions, +- appris les limites des identifiants d'entrée et ce que sont que les masques d'attention, +- joué avec des méthodes de *tokenizer* polyvalentes et configurables. + +À partir de maintenant, vous devriez être en mesure de naviguer librement dans la documentation 🤗 *Transformers*. Le vocabulaire vous semblera familier et vous avez vu les méthodes que vous utiliserez la plupart du temps. diff --git a/chapters/fr/chapter2/8.mdx b/chapters/fr/chapter2/8.mdx new file mode 100644 index 000000000..e935ec26e --- /dev/null +++ b/chapters/fr/chapter2/8.mdx @@ -0,0 +1,307 @@ + + + + +# Quiz de fin de chapitre + +### 1. Quel est l'ordre du pipeline de modélisation du langage ? + + +tokenizer donne un sens à ces prédictions et les reconvertit en texte si nécessaire.", + explain: " Le modèle ne peut pas comprendre le texte ! Le tokenizer doit d'abord tokeniser le texte et le convertir en identifiants afin qu'il soit compréhensible par le modèle."}, + { + text: " Tout d'abord, le tokenizer/i>, qui traite le texte et renvoie des identifiants. Puis le modèle traite ces identifiants et produit une prédiction, qui peut être du texte.", + explain: " La prédiction du modèle ne peut pas être du texte immédiatement. Le tokenizer doit être utilisé afin de reconvertir la prédiction en texte !"}, + { + text: " Le tokenizer traite le texte et renvoie des identifiants. Le modèle traite ces identifiants et produit une prédiction. Le tokenizer peut alors être utilisé à nouveau pour reconvertir ces prédictions en texte.", + explain: " C’est correct ! Le tokenizer peut être utilisé à la fois pour la tokenisation et la dé-tokénisation.", + correct: true + } + ]} +/> + +### 2. Combien de dimensions le tenseur produit par le transformer de base possède-t-il et quelles sont-elles ? + + +transformers gèrent les batchs, même avec une seule séquence ce serait une taille de batch de 1 !" + }, + { + text: "3: la longueur de la séquence, la taille du batch et la taille cachée.", + explain: "C’est correct !", + correct: true + } + ]} +/> + +### 3. Lequel des éléments suivants est un exemple de tokenisation en sous-mots ? + + + +### 4. Qu'est-ce qu'une tête de modèle ? + +transformer de base qui redirige les tenseurs vers leurs couches correctes.", + explain: "Incorrect ! Il n'y a pas de tel composant." + }, + { + text: "Également connu sous le nom de mécanisme d'auto-attention, il adapte la représentation d'un token en fonction des autres tokens de la séquence.", + explain: "Incorrect ! La couche d'auto-attention contient des têtes d'attention mais ce ne sont pas des têtes d'adaptation." + }, + { + text: "Un composant supplémentaire, généralement constitué d'une ou plusieurs couches, pour convertir les prédictions du transformer en une sortie spécifique à la tâche.", + explain: "C'est exact. Les têtes d'adaptation, aussi appelées simplement têtes, se présentent sous différentes formes : têtes de modélisation du langage, têtes de réponse aux questions, têtes de classification des séquences, etc.", + correct: true + } + ]} +/> + +{#if fw === 'pt'} +### 5. Qu'est-ce qu'un AutoModel? + +AutoNLP product?" + }, + { + text: "An object that returns the correct architecture based on the checkpoint", + explain: "Exactly: the AutoModel only needs to know the checkpoint from which to initialize to return the correct architecture.", + correct: true + }, + { + text: "A model that automatically detects the language used for its inputs to load the correct weights", + explain: "Incorrect; while some checkpoints and models are capable of handling multiple languages, there are no built-in tools for automatic checkpoint selection according to language. You should head over to the Model Hub to find the best checkpoint for your task!" + } + ]} +/> + +{:else} +### 5. What is an AutoModel? + +checkpoints et modèles soient capables de gérer plusieurs langues, il n'existe pas d'outils intégrés pour la sélection automatique des checkpoints en fonction de la langue. Vous devez vous rendre sur le Hub des modèles pour trouver le meilleur checkpoint pour votre tâche !" + } + ]} +/> + +{/if} + +### 6. Quelles sont les techniques à connaître lors de la mise en batch de séquences de longueurs différentes ? + + +padding", + explain: "Oui, le padding est une façon correcte d'égaliser les séquences pour qu'elles tiennent dans une forme rectangulaire. Mais est-ce le seul moyen ?", + correct: true + }, + { + text: "Les masques d'attention ", + explain: "Absolument ! Les masques d'attention sont d'une importance capitale lorsqu'on manipule des séquences de longueurs différentes. Ce n'est cependant pas la seule technique à laquelle il faut faire attention.", + correct: true + } + ]} +/> + +### 7. Quel est l'intérêt d'appliquer une fonction SoftMax aux logits produits par un modèle de classification de séquences ? + + + +### 8. Autour de quelle méthode s'articule la majeure partie de l'API tokenizer ? + +encode, car elle peut encoder du texte en identifiants et des identifiants en prédictions.", + explain: "Faux ! Bien que la méthode encode existe sur les *tokenizers*, elle n'existe pas sur les modèles." + }, + { + text: "Appeler directement l'objet tokenizer", + explain: " Exactement ! La méthode __call__ du tokenizer est une méthode très puissante qui peut traiter à peu près tout. C'est également la méthode utilisée pour récupérer les prédictions d'un modèle.", + correct: true + }, + { + text: "pad", + explain: "C'est faux ! Le padding est très utile mais ce n'est qu'une partie de l'API tokenizer." + }, + { + text: "tokenize", + explain: "La méthode tokenize est est sans doute l'une des méthodes les plus utiles, mais elle ne constitue pas le cœur de l'API tokenizer." + } + ]} +/> + +### 9. Que contient la variable `result` dans cet exemple de code ? + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +result = tokenizer.tokenize("Hello!") +``` + +token.", + explain: " Absolument ! Convertissez cela en identifiants, et donnez-les à un modèle !", + correct: true + }, + { + text: "Une liste d'identifiants", + explain: "C'est faux, c'est à cela que la méthode __call__ ou la méthode convert_tokens_to_ids sert !" + }, + { + text: "Une chaîne contenant tous les tokens", + explain: "Ce serait sous-optimal car le but est de diviser la chaîne de caractères en plusieurs éléments." + } + ]} +/> + +{#if fw === 'pt'} +### 10. Y a-t-il un problème avec le code suivant ? + + +```py +from transformers import AutoTokenizer, AutoModel + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +model = AutoModel.from_pretrained("gpt2") + +encoded = tokenizer("Hey!", return_tensors="pt") +result = model(**encoded) +``` + +tokenizer qui a été entraîné avec un checkpoint différent est rarement une bonne idée. Le modèle n'a pas été entraîné pour donner du sens à la sortie de ce tokenizer donc la sortie du modèle (s'il peut même fonctionner !) n'aura aucun sens." + }, + { + text: " Le tokenizer et le modèle doivent toujours provenir du même checkpoint.", + explain: "C’est juste !", + correct: true + }, + { + text: " C'est une bonne pratique de faire du padding et de troncage avec le tokenizer car chaque entrée est un batch.", + explain: "Il est vrai que chaque entrée de modèle doit être un batch. Cependant, tronquer ou compléter cette séquence n'aurait pas nécessairement de sens puisqu'il n'y en a qu'une seule. Il s'agit là de techniques permettant de mettre en batch une liste de phrases." + } + ]} +/> + +{:else} +### 10. Y a-t-il un problème avec le code suivant ? + +```py +from transformers import AutoTokenizer, TFAutoModel + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +model = TFAutoModel.from_pretrained("gpt2") + +encoded = tokenizer("Hey!", return_tensors="pt") +result = model(**encoded) +``` + +tokenizer qui a été entraîné avec un checkpoint différent est rarement une bonne idée. Le modèle n'a pas été entraîné pour donner du sens à la sortie de ce tokenizer donc la sortie du modèle (s'il peut même fonctionner !) n'aura aucun sens." + }, + { + text: " Le tokenizer et le modèle doivent toujours provenir du même checkpoint.", + explain: "C’est juste !", + correct: true + }, + { + text: " C'est une bonne pratique de faire du padding et de troncage avec le tokenizer car chaque entrée est un batch.", + explain: "Il est vrai que chaque entrée de modèle doit être un batch. Cependant, tronquer ou compléter cette séquence n'aurait pas nécessairement de sens puisqu'il n'y en a qu'une seule. Il s'agit là de techniques permettant de mettre en batch une liste de phrases." + } + ]} +/> + +{/if} diff --git a/chapters/fr/chapter5/1.mdx b/chapters/fr/chapter5/1.mdx index 8e76cea5e..766e33082 100644 --- a/chapters/fr/chapter5/1.mdx +++ b/chapters/fr/chapter5/1.mdx @@ -1,17 +1,17 @@ # Introduction -Dans le [Chapitre 3](/course/chapter3) vous avez eu un premier aperçu de la bibliothèque 🤗 Datasets et vous avez vu qu'il y avait trois étapes principales pour affiner un modèle: +Dans le [Chapitre 3](/course/fr/chapter3) vous avez eu un premier aperçu de la bibliothèque 🤗 *Datasets* et qu'il y a trois étapes principales pour *finetuner* un modèle: -1. Chargez un jeu de données à partir de Hugging Face Hub. -2. Prétraitez les données avec `Dataset.map()`. +1. charger un jeu de données à partir du *Hub* d’Hugging Face. +2. Prétraiter les données avec `Dataset.map()`. 3. Charger et calculer des métriques. -Mais ce n'est qu'effleurer la surface de ce que 🤗 Datasets peut faire ! Dans ce chapitre, nous allons plonger profondément dans la bibliothèque. En cours de route, nous trouverons des réponses aux questions suivantes: +Mais ce n'est qu'effleurer la surface de ce que 🤗 *Datasets* peut faire ! Dans ce chapitre, nous allons plonger profondément dans cette bibliothèque. En cours de route, nous trouverons des réponses aux questions suivantes : -* Que faites-vous lorsque votre jeu de données n'est pas sur le Hub ? -* Comment pouvez-vous découper et trancher un ensemble de données ? (Et si vous avez _vraiment_ besoin d'utiliser Pandas ?) -* Que faites-vous lorsque votre ensemble de données est énorme et va faire fondre la RAM de votre ordinateur portable ? -* Qu'est-ce que c'est que le "mappage de la mémoire" et Apache Arrow ? -* Comment pouvez-vous créer votre propre ensemble de données et le pousser vers le Hub ? +* que faire lorsque votre jeu de données n'est pas sur le *Hub* ? +* comment découper et trancher un jeu de données ? (Et si on a _vraiment_ besoin d'utiliser Pandas ?) +* que faire lorsque votre jeu de données est énorme et va monopoliser la RAM de votre ordinateur portable ? +* qu'est-ce que c'est que le « *memory mapping* » et Apache Arrow ? +* comment créer votre propre jeu de données et le pousser sur le *Hub* ? -Les techniques que vous apprenez ici vous prépareront aux tâches avancées de tokenisation et de réglage fin du [Chapitre 6](/course/chapter6) et du [Chapitre 7](/course/chapter7) -- alors prenez un café et commençons ! \ No newline at end of file +Les techniques apprises dans ce chapitre vous prépareront aux tâches avancées de tokenisation et de *finetuning* du [Chapitre 6](/course/fr/chapter6) et du [Chapitre 7](/course/fr/chapter7). Alors prenez un café et commençons ! diff --git a/chapters/fr/chapter5/2.mdx b/chapters/fr/chapter5/2.mdx index 896dc8ca2..8c84d6282 100644 --- a/chapters/fr/chapter5/2.mdx +++ b/chapters/fr/chapter5/2.mdx @@ -1,4 +1,4 @@ -# Que faire si mon ensemble de données n'est pas sur le Hub ? +# Que faire si mon jeu de données n'est pas sur le *Hub* ? -Vous savez comment utiliser le [Hugging Face Hub](https://huggingface.co/datasets) pour télécharger des ensembles de données, mais vous vous retrouverez souvent à travailler avec des données stockées sur votre ordinateur portable ou sur un serveur distant. Dans cette section, nous allons vous montrer comment 🤗 Datasets peut être utilisé pour charger des ensembles de données qui ne sont pas disponibles sur le Hugging Face Hub. +Vous savez comment utiliser le [*Hub* d’Hugging Face](https://huggingface.co/datasets) pour télécharger des jeux de données mais en pratique vous vous retrouverez souvent à travailler avec des données stockées sur votre ordinateur portable ou sur un serveur distant. Dans cette section, nous allons vous montrer comment 🤗 *Datasets* peut être utilisé pour charger des jeux de données qui ne sont pas disponibles sur le *Hub* d’Hugging Face. -## Travailler avec des ensembles de données locaux et distants +## Travailler avec des jeux de données locaux et distants -🤗 Datasets fournit des scripts de chargement pour gérer le chargement des ensembles de données locaux et distants. Il prend en charge plusieurs formats de données courants, tels que : +🤗 *Datasets* fournit des scripts de chargement de jeux de données locaux et distants. Il prend en charge plusieurs formats de données courants, tels que : -| Format de données | Chargement du script | Exemple | +| Format des données | Script de chargement | Exemple | | :----------------: | :------------------: | :-----------------------------------------------------: | | CSV & TSV | `csv` | `load_dataset("csv", data_files="my_file.csv")` | | Fichiers texte | `text` | `load_dataset("text", data_files="my_file.txt")` | | JSON & Lignes JSON | `json` | `load_dataset("json", data_files="my_file.jsonl")` | -| DataFrames marinés | `pandas` | `load_dataset("pandas", data_files="my_dataframe.pkl")` | +| DataFrames en Pickle | `pandas` | `load_dataset("pandas", data_files="my_dataframe.pkl")` | -Comme indiqué dans le tableau, pour chaque format de données, nous avons juste besoin de spécifier le type de script de chargement dans la fonction `load_dataset()`, ainsi qu'un argument `data_files` qui spécifie le chemin vers un ou plusieurs fichiers. Commençons par charger un jeu de données à partir de fichiers locaux ; plus tard, nous verrons comment faire la même chose avec des fichiers distants. +Comme indiqué dans le tableau, pour chaque format de données, nous avons juste besoin de spécifier le type de script de chargement dans la fonction `load_dataset()`, ainsi qu'un argument `data_files` qui spécifie le chemin vers un ou plusieurs fichiers. Commençons par charger un jeu de données à partir de fichiers locaux puis plus tard comment faire la même chose avec des fichiers distants. ## Charger un jeu de données local -Pour cet exemple, nous utiliserons l'ensemble de données [SQuAD-it](https://github.com/crux82/squad-it/), qui est un ensemble de données à grande échelle pour répondre aux questions en Italien. +Pour cet exemple, nous utilisons le jeu de données [SQuAD-it](https://github.com/crux82/squad-it/) qui est un grand jeu de données pour la tâche de *Question Awnswering* en italien. -Les fractionnements de formation et de test sont hébergés sur GitHub, nous pouvons donc les télécharger avec une simple commande `wget` : +Les échantillons d’entraînement et de test sont hébergés sur GitHub, nous pouvons donc les télécharger avec une simple commande `wget` : ```python !wget https://github.com/crux82/squad-it/raw/master/SQuAD_it-train.json.gz !wget https://github.com/crux82/squad-it/raw/master/SQuAD_it-test.json.gz ``` -Cela téléchargera deux fichiers compressés appelés *SQuAD_it-train.json.gz* et *SQuAD_it-test.json.gz*, que nous pouvons décompresser avec la commande Linux `gzip` : +Cela télécharge deux fichiers compressés appelés *SQuAD_it-train.json.gz* et *SQuAD_it-test.json.gz* que nous pouvons décompresser avec la commande Linux `gzip` : ```python !gzip -dkv SQuAD_it-*.json.gz @@ -50,11 +50,11 @@ Nous pouvons voir que les fichiers compressés ont été remplacés par _SQuAD_i -✎ Si vous vous demandez pourquoi il y a un caractère `!` dans les commandes shell ci-dessus, c'est parce que nous les exécutons dans un cahier Jupyter. Supprimez simplement le préfixe si vous souhaitez télécharger et décompresser l'ensemble de données dans un terminal. +✎ Si vous vous demandez pourquoi il y a un caractère `!` dans les commandes shell ci-dessus, c'est parce que nous les exécutons dans un *notebook* Jupyter. Supprimez simplement le préfixe si vous souhaitez télécharger et décompresser le jeu de données dans un terminal. -Pour charger un fichier JSON avec la fonction `load_dataset()`, nous avons juste besoin de savoir si nous avons affaire à du JSON ordinaire (similaire à un dictionnaire imbriqué) ou à des lignes JSON (JSON séparé par des lignes). Comme de nombreux ensembles de données de questions-réponses, SQuAD-it utilise le format imbriqué, avec tout le texte stocké dans un champ "données". Cela signifie que nous pouvons charger le jeu de données en spécifiant l'argument `field` comme suit : +Pour charger un fichier JSON avec la fonction `load_dataset()`, nous avons juste besoin de savoir si nous avons affaire à du JSON ordinaire (similaire à un dictionnaire imbriqué) ou à des lignes JSON (JSON séparé par des lignes). Comme de nombreux jeux de données de questions-réponses, SQuAD-it utilise le format imbriqué où tout le texte est stocké dans un champ `data`. Cela signifie que nous pouvons charger le jeu de données en spécifiant l'argument `field` comme suit : ```py from datasets import load_dataset @@ -62,7 +62,7 @@ from datasets import load_dataset squad_it_dataset = load_dataset("json", data_files="SQuAD_it-train.json", field="data") ``` -Par défaut, le chargement de fichiers locaux crée un objet `DatasetDict` avec une division `train`. Nous pouvons le voir en inspectant l'objet `squad_it_dataset` : +Par défaut, le chargement de fichiers locaux crée un objet `DatasetDict` avec un échantillon `train`. Nous pouvons le voir en inspectant l'objet `squad_it_dataset` : ```py squad_it_dataset @@ -77,7 +77,7 @@ DatasetDict({ }) ``` -Cela nous montre le nombre de lignes et les noms de colonnes associés à l'ensemble d'apprentissage. Nous pouvons afficher l'un des exemples en indexant la division "train" comme suit : +Cela nous montre le nombre de lignes et les noms de colonnes associés à l’échantillon d’entraînement. Nous pouvons afficher l'un des exemples en indexant l’échantillon `train`. comme suit : ```py squad_it_dataset["train"][0] @@ -85,15 +85,15 @@ squad_it_dataset["train"][0] ```python out { - "title": "Terremoto del Sichuan del 2008", + "title": "Terremoto del Sichuan del 2008", # Séisme du Sichuan 2008 "paragraphs": [ { - "context": "Il terremoto del Sichuan del 2008 o il terremoto...", + "context": "Il terremoto del Sichuan del 2008 o il terremoto...", # Le tremblement de terre du Sichuan de 2008 ou le... "qas": [ { "answers": [{"answer_start": 29, "text": "2008"}], "id": "56cdca7862d2951400fa6826", - "question": "In quale anno si è verificato il terremoto nel Sichuan?", + "question": "In quale anno si è verificato il terremoto nel Sichuan?", # En quelle année le tremblement de terre du Sichuan a-t-il eu lieu ? }, ... ], @@ -103,7 +103,7 @@ squad_it_dataset["train"][0] } ``` -Super, nous avons chargé notre premier jeu de données local ! Mais bien que cela ait fonctionné pour l'ensemble d'entraînement, ce que nous voulons vraiment, c'est inclure à la fois les divisions `train` et `test` dans un seul objet `DatasetDict` afin que nous puissions appliquer les fonctions `Dataset.map()` sur les deux divisions à la fois . Pour ce faire, nous pouvons fournir un dictionnaire à l'argument `data_files` qui associe chaque nom de division à un fichier associé à cette division : +Super, nous avons chargé notre premier jeu de données local ! Mais ce que nous voulons vraiment, c'est inclure à la fois les échantillons `train` et `test` dans un seul objet `DatasetDict` afin que nous puissions appliquer les fonctions `Dataset.map()` sur les deux à la fois . Pour ce faire, nous pouvons fournir un dictionnaire à l'argument `data_files` qui associe chaque nom des échantillons à un fichier associé à cet échantillon : ```py data_files = {"train": "SQuAD_it-train.json", "test": "SQuAD_it-test.json"} @@ -128,24 +128,24 @@ C'est exactement ce que nous voulions. Désormais, nous pouvons appliquer divers -The `data_files` argument of the `load_dataset()` function is quite flexible and can be either a single file path, a list of file paths, or a dictionary that maps split names to file paths. You can also group files matching a specified pattern according to the rules used by the Unix shell (for example, you can group all JSON files in a directory into a single division by setting `data_files="*.json"` ). See 🤗 Datasets [documentation](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) for details. +L'argument `data_files` de la fonction `load_dataset()` est assez flexible et peut être soit un chemin de fichier unique, une liste de chemins de fichiers, ou un dictionnaire qui fait correspondre les noms des échantillons aux chemins de fichiers. Vous pouvez également regrouper les fichiers correspondant à un motif spécifié selon les règles utilisées par le shell Unix. Par exemple, vous pouvez regrouper tous les fichiers JSON d'un répertoire en une seule division en définissant `data_files="*.json"`. Voir la [documentation](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) de 🤗 *Datasets* pour plus de détails. -Les scripts de chargement dans 🤗 Datasets prend en charge la décompression automatique des fichiers d'entrée, nous aurions donc pu ignorer l'utilisation de `gzip` en pointant l'argument `data_files` directement sur les fichiers compressés : +Les scripts de chargement de 🤗 *Datasets* prennent en charge la décompression automatique des fichiers d'entrée. Nous aurions donc pu ignorer l'utilisation de `gzip` en pointant l'argument `data_files` directement sur les fichiers compressés : ```py data_files = {"train": "SQuAD_it-train.json.gz", "test": "SQuAD_it-test.json.gz"} squad_it_dataset = load_dataset("json", data_files=data_files, field="data") ``` -Cela peut être utile si vous ne souhaitez pas décompresser manuellement de nombreux fichiers GZIP. La décompression automatique s'applique également à d'autres formats courants tels que ZIP et TAR, il vous suffit donc de pointer `data_files` vers les fichiers compressés et vous êtes prêt à partir ! +Cela peut être utile si vous ne souhaitez pas décompresser manuellement de nombreux fichiers GZIP. La décompression automatique s'applique également à d'autres formats courants tels que ZIP et TAR. Il vous suffit donc de pointer `data_files` vers les fichiers compressés et vous êtes prêt à partir ! Maintenant que vous savez comment charger des fichiers locaux sur votre ordinateur portable ou de bureau, examinons le chargement de fichiers distants. ## Charger un jeu de données distant -Si vous travaillez en tant que data scientist ou codeur dans une entreprise, il y a de fortes chances que les ensembles de données que vous souhaitez analyser soient stockés sur un serveur distant. Heureusement, charger des fichiers distants est aussi simple que de charger des fichiers locaux ! Au lieu de fournir un chemin vers les fichiers locaux, nous pointons l'argument `data_files` de `load_dataset()` vers une ou plusieurs URL où les fichiers distants sont stockés. Par exemple, pour l'ensemble de données SQuAD-it hébergé sur GitHub, nous pouvons simplement faire pointer `data_files` vers les URL _SQuAD_it-*.json.gz_ comme suit : +Si vous travaillez en tant que *data scientist* ou codeur dans une entreprise, il y a de fortes chances que les juex de données que vous souhaitez analyser soient stockés sur un serveur distant. Heureusement, charger des fichiers distants est aussi simple que de charger des fichiers locaux ! Au lieu de fournir un chemin vers les fichiers locaux, nous pointons l'argument `data_files` de `load_dataset()` vers une ou plusieurs URL où les fichiers distants sont stockés. Par exemple, pour le jeux de données SQuAD-it hébergé sur GitHub, nous pouvons simplement faire pointer `data_files` vers les URL _SQuAD_it-*.json.gz_ comme suit : ```py url = "https://github.com/crux82/squad-it/raw/master/" @@ -156,12 +156,10 @@ data_files = { squad_it_dataset = load_dataset("json", data_files=data_files, field="data") ``` -Cela renvoie le même objet `DatasetDict` obtenu ci-dessus, mais nous évite de télécharger et de décompresser manuellement les fichiers _SQuAD_it-*.json.gz_. Ceci conclut notre incursion dans les différentes façons de charger des ensembles de données qui ne sont pas hébergés sur le Hugging Face Hub. Maintenant que nous avons un ensemble de données avec lequel jouer, mettons-nous la main à la pâte avec diverses techniques de gestion des données ! +Cela renvoie le même objet `DatasetDict` obtenu ci-dessus mais nous évite de télécharger et de décompresser manuellement les fichiers _SQuAD_it-*.json.gz_. Ceci conclut notre incursion dans les différentes façons de charger des jeux de données qui ne sont pas hébergés sur le *Hub* d’Hugging Face. Maintenant que nous avons un jeu de données avec lequel jouer, mettons la main à la pâte avec diverses techniques de gestion des données ! -✏️ **Essayez-le !** Choisissez un autre ensemble de données hébergé sur GitHub ou le [UCI Machine Learning Repository](https://archive.ics.uci.edu/ml/index.php) et essayez de le charger localement et à distance en utilisant les techniques présentées ci-dessus. Pour obtenir des points bonus, essayez de charger un ensemble de données stocké au format CSV ou texte (voir la [documentation](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) pour plus d'informations sur ces formats). +✏️ **Essayez !** Choisissez un autre jeu de données hébergé sur GitHub ou dans le [*UCI Machine Learning Repository*](https://archive.ics.uci.edu/ml/index.php) et essayez de le charger localement et à distance en utilisant les techniques présentées ci-dessus. Pour obtenir des points bonus, essayez de charger un jeu de données stocké au format CSV ou texte (voir la [documentation](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) pour plus d'informations sur ces formats). - - diff --git a/chapters/fr/chapter5/3.mdx b/chapters/fr/chapter5/3.mdx index 9d6a57959..455473889 100644 --- a/chapters/fr/chapter5/3.mdx +++ b/chapters/fr/chapter5/3.mdx @@ -7,24 +7,24 @@ {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/chapter5/section3.ipynb"}, ]} /> -La plupart du temps, les données avec lesquelles vous travaillez ne seront pas parfaitement préparées pour les modèles de formation. Dans cette section, nous allons explorer les différentes fonctionnalités fournies par 🤗 Datasets pour nettoyer vos ensembles de données. +La plupart du temps, les données avec lesquelles vous travaillez ne sont pas parfaitement préparées pour l’entraînements de modèles. Dans cette section, nous allons explorer les différentes fonctionnalités fournies par 🤗 *Datasets* pour nettoyer vos jeux de données. ## Trancher et découper nos données -Semblable à Pandas, 🤗 Datasets fournit plusieurs fonctions pour manipuler le contenu des objets `Dataset` et `DatasetDict`. Nous avons déjà rencontré la méthode `Dataset.map()` dans le [Chapitre 3](/course/chapter3), et dans cette section nous allons explorer certaines des autres fonctions à notre disposition. +Semblable à Pandas, 🤗 *Datasets* fournit plusieurs fonctions pour manipuler le contenu des objets `Dataset` et `DatasetDict`. Nous avons déjà rencontré la méthode `Dataset.map()` dans le [Chapitre 3](/course/fr/chapter3) et dans cette section nous allons explorer certaines des autres fonctions à notre disposition. -Pour cet exemple, nous utiliserons le [Drug Review Dataset](https://archive.ics.uci.edu/ml/datasets/Drug+Review+Dataset+%28Drugs.com%29) qui est hébergé sur [UC Irvine Machine Learning Repository] (https://archive.ics.uci.edu/ml/index.php), qui contient des avis de patients sur divers médicaments, ainsi que la condition traitée et une note de 10 étoiles sur la satisfaction du patient. +Pour cet exemple, nous utiliserons le [*Drug Review Dataset*](https://archive.ics.uci.edu/ml/datasets/Drug+Review+Dataset+%28Drugs.com%29) qui est hébergé sur [*UC Irvine Machine Learning Repository*](https://archive.ics.uci.edu/ml/index.php) et contenant des avis de patients sur divers médicaments ainsi que la condition traitée et une note de 10 étoiles sur la satisfaction du patient. -Nous devons d'abord télécharger et extraire les données, ce qui peut être fait avec les commandes `wget` et `unzip` : +Nous devons d'abord télécharger et extraire les données, ce qui peut être fait avec les commandes `wget` et `unzip` : ```py !wget "https://archive.ics.uci.edu/ml/machine-learning-databases/00462/drugsCom_raw.zip" !unzip drugsCom_raw.zip ``` -Étant donné que TSV n'est qu'une variante de CSV qui utilise des tabulations au lieu de virgules comme séparateurs, nous pouvons charger ces fichiers en utilisant le script de chargement `csv` et en spécifiant l'argument `delimiter` dans la fonction `load_dataset()` comme suit : +Étant donné que TSV n'est qu'une variante de CSV qui utilise des tabulations au lieu de virgules comme séparateurs, nous pouvons charger ces fichiers en utilisant le script de chargement `csv` et en spécifiant l'argument `delimiter` dans la fonction `load_dataset()` comme suit : ```py from datasets import load_dataset @@ -34,40 +34,40 @@ data_files = {"train": "drugsComTrain_raw.tsv", "test": "drugsComTest_raw.tsv"} drug_dataset = load_dataset("csv", data_files=data_files, delimiter="\t") ``` -Une bonne pratique lors de toute sorte d'analyse de données consiste à prélever un petit échantillon aléatoire pour avoir une idée rapide du type de données avec lesquelles vous travaillez. Dans 🤗 Datasets, nous pouvons créer un échantillon aléatoire en enchaînant les fonctions `Dataset.shuffle()` et `Dataset.select()` : +Une bonne pratique lors de toute sorte d'analyse de données consiste à prélever un petit échantillon aléatoire pour avoir une idée rapide du type de données avec lesquelles vous travaillez. Dans 🤗 *Datasets*, nous pouvons créer un échantillon aléatoire en enchaînant les fonctions `Dataset.shuffle()` et `Dataset.select()` : ```py drug_sample = drug_dataset["train"].shuffle(seed=42).select(range(1000)) -# Peek at the first few examples +# Un coup d'œil sur les premiers exemples drug_sample[:3] ``` ```python out {'Unnamed: 0': [87571, 178045, 80482], 'drugName': ['Naproxen', 'Duloxetine', 'Mobic'], - 'condition': ['Gout, Acute', 'ibromyalgia', 'Inflammatory Conditions'], - 'review': ['"like the previous person mention, I'm a strong believer of aleve, it works faster for my gout than the prescription meds I take. No more going to the doctor for refills.....Aleve works!"', - '"I have taken Cymbalta for about a year and a half for fibromyalgia pain. It is great\r\nas a pain reducer and an anti-depressant, however, the side effects outweighed \r\nany benefit I got from it. I had trouble with restlessness, being tired constantly,\r\ndizziness, dry mouth, numbness and tingling in my feet, and horrible sweating. I am\r\nbeing weaned off of it now. Went from 60 mg to 30mg and now to 15 mg. I will be\r\noff completely in about a week. The fibro pain is coming back, but I would rather deal with it than the side effects."', - '"I have been taking Mobic for over a year with no side effects other than an elevated blood pressure. I had severe knee and ankle pain which completely went away after taking Mobic. I attempted to stop the medication however pain returned after a few days."'], + 'condition': ['Gout, Acute', 'ibromyalgia', 'Inflammatory Conditions'], #['Goutte aiguë', 'ibromyalgie', 'Affections inflammatoires'] + 'review': ['"like the previous person mention, I'm a strong believer of aleve, it works faster for my gout than the prescription meds I take. No more going to the doctor for refills.....Aleve works!"', # comme la personne précédente l'a mentionné, je suis un fervent partisan de l'aleve, il fonctionne plus rapidement pour ma goutte que les médicaments sur ordonnance que je prends. Je n'ai plus besoin d'aller chez le médecin pour des renouvellements.....Aleve fonctionne !" + '"I have taken Cymbalta for about a year and a half for fibromyalgia pain. It is great\r\nas a pain reducer and an anti-depressant, however, the side effects outweighed \r\nany benefit I got from it. I had trouble with restlessness, being tired constantly,\r\ndizziness, dry mouth, numbness and tingling in my feet, and horrible sweating. I am\r\nbeing weaned off of it now. Went from 60 mg to 30mg and now to 15 mg. I will be\r\noff completely in about a week. The fibro pain is coming back, but I would rather deal with it than the side effects."', # J'ai pris du Cymbalta pendant environ un an et demi pour des douleurs de la fibromyalgie. C'est un excellent analgésique et un antidépresseur, mais les effets secondaires l'ont emporté sur tous les avantages que j'en ai tirés. J'ai eu des problèmes d'agitation, de fatigue constante, de vertiges, de bouche sèche, d'engourdissement, de picotements dans les pieds, et de transpiration horrible. Je suis en train de m'en sevrer maintenant. Je suis passée de 60 mg à 30 mg et maintenant à 15 mg. Je l'arrêterai complètement dans environ une semaine. La douleur de la fibrose revient, mais je préfère la supporter plutôt que les effets secondaires. + '"I have been taking Mobic for over a year with no side effects other than an elevated blood pressure. I had severe knee and ankle pain which completely went away after taking Mobic. I attempted to stop the medication however pain returned after a few days."'], # J'ai pris Mobic pendant plus d'un an sans effets secondaires autres qu'une pression sanguine élevée. J'avais de fortes douleurs au genou et à la cheville qui ont complètement disparu après avoir pris Mobic. J'ai essayé d'arrêter le médicament mais la douleur est revenue après quelques jours." 'rating': [9.0, 3.0, 10.0], - 'date': ['September 2, 2015', 'November 7, 2011', 'June 5, 2013'], + 'date': ['September 2, 2015', 'November 7, 2011', 'June 5, 2013'], #['2 septembre 2015', '7 novembre 2011', '5 juin 2013'] 'usefulCount': [36, 13, 128]} ``` -Notez que nous avons corrigé la graine dans `Dataset.shuffle()` à des fins de reproductibilité. `Dataset.select()` attend un itérable d'indices, nous avons donc passé `range(1000)` pour récupérer les 1 000 premiers exemples de l'ensemble de données mélangé. À partir de cet échantillon, nous pouvons déjà voir quelques bizarreries dans notre ensemble de données : +Notez que nous avons corrigé la graine dans `Dataset.shuffle()` à des fins de reproductibilité. `Dataset.select()` attend un itérable d'indices, nous avons donc passé `range(1000)` pour récupérer les 1 000 premiers exemples du jeu de données mélangé. À partir de cet échantillon, nous pouvons déjà voir quelques bizarreries dans notre jeu de données : -* La colonne "Sans nom : 0" ressemble étrangement à un identifiant anonyme pour chaque patient. -* La colonne "condition" comprend un mélange d'étiquettes en majuscules et en minuscules. -* Les avis sont de longueur variable et contiennent un mélange de séparateurs de lignes Python (`\r\n`) ainsi que des codes de caractères HTML comme `&\#039;`. +* la colonne `Unnamed: 0` ressemble étrangement à un identifiant anonyme pour chaque patient, +* la colonne `condition` comprend un mélange d'étiquettes en majuscules et en minuscules, +* les avis sont de longueur variable et contiennent un mélange de séparateurs de lignes Python (`\r\n`) ainsi que des codes de caractères HTML comme `&\#039;`. -Voyons comment nous pouvons utiliser 🤗 Datasets pour traiter chacun de ces problèmes. Pour tester l'hypothèse de l'ID patient pour la colonne `Unnamed : 0`, nous pouvons utiliser la fonction `Dataset.unique()` pour vérifier que le nombre d'ID correspond au nombre de lignes dans chaque division : +Voyons comment nous pouvons utiliser 🤗 *Datasets* pour traiter chacun de ces problèmes. Pour tester l'hypothèse de l'ID patient pour la colonne `Unnamed : 0`, nous pouvons utiliser la fonction `Dataset.unique()` pour vérifier que le nombre d'ID correspond au nombre de lignes dans chaque division : ```py for split in drug_dataset.keys(): assert len(drug_dataset[split]) == len(drug_dataset[split].unique("Unnamed: 0")) ``` -Cela semble confirmer notre hypothèse, alors nettoyons un peu l'ensemble de données en renommant la colonne `Unnamed: 0` en quelque chose d'un peu plus interprétable. Nous pouvons utiliser la fonction `DatasetDict.rename_column()` pour renommer la colonne sur les deux divisions en une seule fois : +Cela semble confirmer notre hypothèse, alors nettoyons un peu en renommant la colonne `Unnamed: 0` en quelque chose d'un peu plus interprétable. Nous pouvons utiliser la fonction `DatasetDict.rename_column()` pour renommer la colonne sur les deux divisions en une seule fois : ```py drug_dataset = drug_dataset.rename_column( @@ -91,11 +91,11 @@ DatasetDict({ -✏️ **Essayez-le !** Utilisez la fonction "Dataset.unique()" pour trouver le nombre de médicaments et de conditions uniques dans les ensembles d'entraînement et de test. +✏️ **Essayez !** Utilisez la fonction ` Dataset.unique()` pour trouver le nombre de médicaments et de conditions uniques dans les échantillons d'entraînement et de test. -Ensuite, normalisons toutes les étiquettes `condition` en utilisant `Dataset.map()`. Comme nous l'avons fait avec la tokenisation dans le [chapitre 3](/course/chapter3), nous pouvons définir une fonction simple qui peut être appliquée sur toutes les lignes de chaque division dans `drug_dataset` : +Ensuite, normalisons toutes les étiquettes `condition` en utilisant `Dataset.map()`. Comme nous l'avons fait avec la tokenisation dans le [chapitre 3](/course/fr/chapter3), nous pouvons définir une fonction simple qui peut être appliquée sur toutes les lignes de chaque division dans `drug_dataset` : ```py def lowercase_condition(example): @@ -109,26 +109,26 @@ drug_dataset.map(lowercase_condition) AttributeError: 'NoneType' object has no attribute 'lower' ``` -Oh non, nous avons rencontré un problème avec notre fonction de carte ! À partir de l'erreur, nous pouvons déduire que certaines des entrées de la colonne "condition" sont "Aucune", qui ne peuvent pas être mises en minuscules car ce ne sont pas des chaînes. Supprimons ces lignes en utilisant `Dataset.filter()`, qui fonctionne de manière similaire à `Dataset.map()` et attend une fonction qui reçoit un seul exemple de l'ensemble de données. Au lieu d'écrire une fonction explicite comme : +Oh non, nous rencontrons un problème avec notre fonction ! À partir de l'erreur, nous pouvons déduire que certaines des entrées de la colonne `condition` sont `None` ne pouvant donc pas être mises en minuscules car ce ne sont pas des chaînes. Supprimons ces lignes en utilisant `Dataset.filter()`, qui fonctionne de manière similaire à `Dataset.map()` et attend une fonction qui reçoit un seul exemple issu du jeu de données. Au lieu d'écrire une fonction explicite comme : ```py def filter_nones(x): return x["condition"] is not None ``` -puis en exécutant `drug_dataset.filter(filter_nones)`, nous pouvons le faire en une seule ligne en utilisant une _lambda function_. En Python, les fonctions lambda sont de petites fonctions que vous pouvez définir sans les nommer explicitement. Ils prennent la forme générale : +puis éxécuter `drug_dataset.filter(filter_nones)`, nous pouvons le faire en une seule ligne en utilisant une _fonction lambda_. En Python, les fonctions lambda sont de petites fonctions que vous pouvez définir sans les nommer explicitement. Ils prennent la forme générale : ``` lambda : ``` -où `lambda` est l'un des [mots clés] spéciaux de Python (https://docs.python.org/3/reference/lexical_analysis.html#keywords), `` est une liste/ensemble de valeurs séparées par des virgules qui définissent les entrées de la fonction et `` représente les opérations que vous souhaitez exécuter. Par exemple, nous pouvons définir une simple fonction lambda qui met au carré un nombre comme suit : +où `lambda` est l'un des [mots clés](https://docs.python.org/3/reference/lexical_analysis.html#keywords) spéciaux de Python, `` est une liste/ensemble de valeurs séparées par des virgules qui définissent les entrées de la fonction et `` représente les opérations que vous souhaitez exécuter. Par exemple, nous pouvons définir une simple fonction lambda qui met au carré un nombre comme suit : ``` lambda x : x * x ``` -Pour appliquer cette fonction à une entrée, nous devons l'envelopper ainsi que l'entrée entre parenthèses : +Pour appliquer cette fonction à une entrée, nous devons l'envelopper ainsi que l'entrée entre parenthèses : ```py (lambda x: x * x)(3) @@ -148,17 +148,17 @@ De même, nous pouvons définir des fonctions lambda avec plusieurs arguments en 16.0 ``` -Les fonctions Lambda sont pratiques lorsque vous souhaitez définir de petites fonctions à usage unique (pour plus d'informations à leur sujet, nous vous recommandons de lire l'excellent [tutoriel Real Python](https://realpython.com/python-lambda/) d'André Burgaud) . Dans le contexte 🤗 Datasets, nous pouvons utiliser des fonctions lambda pour définir des opérations simples de mappage et de filtrage, alors utilisons cette astuce pour éliminer les entrées "None" dans notre jeu de données : +Les fonctions lambda sont pratiques lorsque vous souhaitez définir de petites fonctions à usage unique (pour plus d'informations à leur sujet, nous vous recommandons de lire l'excellent [tutoriel Real Python](https://realpython.com/python-lambda/) d'André Burgaud) . Dans le contexte de la bibliothèque 🤗 *Datasets*, nous pouvons utiliser des fonctions lambda pour définir des opérations simples de mappage et de filtrage. Utilisons cette astuce pour éliminer les entrées `None` dans notre jeu de données : ```py drug_dataset = drug_dataset.filter(lambda x: x["condition"] is not None) ``` -Avec les entrées "None" supprimées, nous pouvons normaliser notre colonne "condition" : +Avec les entrées `None` supprimées, nous pouvons normaliser notre colonne `condition` : ```py drug_dataset = drug_dataset.map(lowercase_condition) -# Check that lowercasing worked +# Vérification que la mise en minuscule a fonctionné drug_dataset["train"]["condition"][:3] ``` @@ -170,35 +170,35 @@ drug_dataset["train"]["condition"][:3] ## Création de nouvelles colonnes -Chaque fois que vous avez affaire à des avis de clients, une bonne pratique consiste à vérifier le nombre de mots dans chaque avis. Une critique peut être un simple mot comme "Génial !" ou un essai complet avec des milliers de mots, et selon le cas d'utilisation, vous devrez gérer ces extrêmes différemment. Pour calculer le nombre de mots dans chaque révision, nous utiliserons une heuristique approximative basée sur la division de chaque texte par des espaces. +Chaque fois que vous avez affaire à des avis de clients, une bonne pratique consiste à vérifier le nombre de mots dans chaque avis. Une critique peut être un simple mot comme « Génial ! » ou un essai complet avec des milliers de mots. Selon le cas d'usage, vous devrez gérer ces extrêmes différemment. Pour calculer le nombre de mots dans chaque révision, nous utiliserons une heuristique approximative basée sur la division de chaque texte par des espaces. -Définissons une fonction simple qui compte le nombre de mots dans chaque avis : +Définissons une fonction simple qui compte le nombre de mots dans chaque avis : ```py def compute_review_length(example): return {"review_length": len(example["review"].split())} ``` -Contrairement à notre fonction `lowercase_condition()`, `compute_review_length()` renvoie un dictionnaire dont la clé ne correspond pas à l'un des noms de colonne de l'ensemble de données. Dans ce cas, lorsque `compute_review_length()` est passé à `Dataset.map()`, il sera appliqué à toutes les lignes du jeu de données pour créer une nouvelle colonne `review_length` : +Contrairement à notre fonction `lowercase_condition()`, `compute_review_length()` renvoie un dictionnaire dont la clé ne correspond pas à l'un des noms de colonne du jeu de données. Dans ce cas, lorsque `compute_review_length()` est passé à `Dataset.map()`, il est appliqué à toutes les lignes du jeu de données pour créer une nouvelle colonne `review_length` : ```py drug_dataset = drug_dataset.map(compute_review_length) -# Inspect the first training example +# Inspecter le premier exemple d'entraînement drug_dataset["train"][0] ``` ```python out {'patient_id': 206461, 'drugName': 'Valsartan', - 'condition': 'left ventricular dysfunction', - 'review': '"It has no side effect, I take it in combination of Bystolic 5 Mg and Fish Oil"', + 'condition': 'left ventricular dysfunction', # dysfonctionnement du ventricule gauche + 'review': '"It has no side effect, I take it in combination of Bystolic 5 Mg and Fish Oil"', # Il n'a aucun effet secondaire, je le prends en combinaison avec Bystolic 5 mg et de l'huile de poisson. 'rating': 9.0, - 'date': 'May 20, 2012', + 'date': 'May 20, 2012', # 20 mai 2012 'usefulCount': 27, 'review_length': 17} ``` -Comme prévu, nous pouvons voir qu'une colonne "review_length" a été ajoutée à notre ensemble d'entraînement. Nous pouvons trier cette nouvelle colonne avec `Dataset.sort()` pour voir à quoi ressemblent les valeurs extrêmes : +Comme prévu, nous pouvons voir qu'une colonne `review_length` a été ajoutée à notre jeu d'entraînement. Nous pouvons trier cette nouvelle colonne avec `Dataset.sort()` pour voir à quoi ressemblent les valeurs extrêmes : ```py drug_dataset["train"].sort("review_length")[:3] @@ -207,23 +207,23 @@ drug_dataset["train"].sort("review_length")[:3] ```python out {'patient_id': [103488, 23627, 20558], 'drugName': ['Loestrin 21 1 / 20', 'Chlorzoxazone', 'Nucynta'], - 'condition': ['birth control', 'muscle spasm', 'pain'], - 'review': ['"Excellent."', '"useless"', '"ok"'], + 'condition': ['birth control', 'muscle spasm', 'pain'], # contraception, spasme musculaire, douleur. + 'review': ['"Excellent."', '"useless"', '"ok"'], # Excellent, inutile, ok 'rating': [10.0, 1.0, 6.0], - 'date': ['November 4, 2008', 'March 24, 2017', 'August 20, 2016'], + 'date': ['November 4, 2008', 'March 24, 2017', 'August 20, 2016'], # 4 novembre 2008, 24 mars 2017, 20 août 2016 'usefulCount': [5, 2, 10], 'review_length': [1, 1, 1]} ``` -Comme nous le soupçonnions, certaines critiques ne contiennent qu'un seul mot, ce qui, bien que cela puisse convenir à l'analyse des sentiments, ne serait pas informatif si nous voulons prédire la condition. +Comme nous le soupçonnions, certaines critiques ne contiennent qu'un seul mot, ce qui, bien que cela puisse convenir à l'analyse des sentiments, n’est pas informatif si nous voulons prédire la condition. -🙋 Une autre façon d'ajouter de nouvelles colonnes à un ensemble de données consiste à utiliser la fonction `Dataset.add_column()`. Cela vous permet de fournir la colonne sous forme de liste Python ou de tableau NumPy et peut être utile dans les situations où `Dataset.map()` n'est pas bien adapté à votre analyse. +🙋 Une autre façon d'ajouter de nouvelles colonnes à un jeu de données consiste à utiliser la fonction `Dataset.add_column()`. Cela vous permet de donner la colonne sous forme de liste Python ou de tableau NumPy et peut être utile dans les situations où `Dataset.map()` n'est pas bien adapté à votre analyse. -Utilisons la fonction `Dataset.filter()` pour supprimer les avis contenant moins de 30 mots. De la même manière que nous l'avons fait avec la colonne "condition", nous pouvons filtrer les avis très courts en exigeant que les avis aient une longueur supérieure à ce seuil : +Utilisons la fonction `Dataset.filter()` pour supprimer les avis contenant moins de 30 mots. De la même manière que nous l'avons fait avec la colonne `condition`, nous pouvons filtrer les avis très courts en exigeant que les avis aient une longueur supérieure à ce seuil : ```py drug_dataset = drug_dataset.filter(lambda x: x["review_length"] > 30) @@ -234,15 +234,15 @@ print(drug_dataset.num_rows) {'train': 138514, 'test': 46108} ``` -Comme vous pouvez le constater, cela a supprimé environ 15 % des avis de nos ensembles d'entraînement et de test d'origine. +Comme vous pouvez le constater, cela a supprimé environ 15 % des avis de nos jeux d'entraînement et de test d'origine. -✏️ **Essayez-le !** Utilisez la fonction `Dataset.sort()` pour inspecter les avis avec le plus grand nombre de mots. Consultez la [documentation](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.sort) pour voir quel argument vous devez utiliser pour trier les avis par longueur dans l'ordre décroissant. +✏️ **Essayez !** Utilisez la fonction `Dataset.sort()` pour inspecter les avis avec le plus grand nombre de mots. Consultez la [documentation](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.sort) pour voir quel argument vous devez utiliser pour trier les avis par longueur dans l'ordre décroissant. -La dernière chose à laquelle nous devons faire face est la présence de codes de caractères HTML dans nos avis. Nous pouvons utiliser le module `html` de Python pour supprimer ces caractères, comme ceci : +La dernière chose à laquelle nous devons faire face est la présence de caractères HTML dans nos avis. Nous pouvons utiliser le module `html` de Python pour supprimer ces caractères, comme ceci : ```py import html @@ -255,19 +255,19 @@ html.unescape(text) "I'm a transformer called BERT" ``` -Nous utiliserons `Dataset.map()` pour démasquer tous les caractères HTML de notre corpus : +Nous utilisons `Dataset.map()` pour démasquer tous les caractères HTML de notre corpus : ```python drug_dataset = drug_dataset.map(lambda x: {"review": html.unescape(x["review"])}) ``` -Comme vous pouvez le voir, la méthode `Dataset.map()` est très utile pour le traitement des données -- et nous n'avons même pas effleuré la surface de tout ce qu'elle peut faire ! +Comme vous pouvez le voir, la méthode `Dataset.map()` est très utile pour le traitement des données. Et nous n'avons même pas effleuré la surface de tout ce qu'elle peut faire ! ## Les superpouvoirs de la méthode `map()` -La méthode `Dataset.map()` prend un argument `batched` qui, s'il est défini sur `True`, l'amène à envoyer un lot d'exemples à la fonction map en une seule fois (la taille du lot est configurable mais par défaut à 1 000). Par exemple, la fonction de carte précédente qui dégageait tout le code HTML prenait un peu de temps à s'exécuter (vous pouvez lire le temps pris dans les barres de progression). On peut accélérer cela en traitant plusieurs éléments en même temps à l'aide d'une liste en compréhension. +La méthode `Dataset.map()` prend un argument `batched` qui, s'il est défini sur `True`, l'amène à envoyer un batch d'exemples à la fonction map en une seule fois (la taille du batch est configurable mais est fixé par défaut à 1 000). Par exemple, la fonction `map()` précédente qui supprime tout le code HTML prend un peu de temps à s'exécuter (vous pouvez lire le temps pris dans les barres de progression). On peut accélérer cela en traitant plusieurs éléments en même temps à l'aide d'une compréhension de liste. -Lorsque vous spécifiez `batched=True`, la fonction reçoit un dictionnaire avec les champs de l'ensemble de données, mais chaque valeur est maintenant une _liste de valeurs_, et non plus une seule valeur. La valeur de retour de `Dataset.map()` devrait être la même : un dictionnaire avec les champs que nous voulons mettre à jour ou ajouter à notre ensemble de données, et une liste de valeurs. Par exemple, voici une autre façon de supprimer tous les caractères HTML, mais en utilisant `batched=True` : +Lorsque vous spécifiez `batched=True`, la fonction reçoit un dictionnaire avec les champs du jeu de données mais chaque valeur est maintenant une _liste de valeurs_ et non plus une seule valeur. La valeur retournée par `Dataset.map()` devrait être la même : un dictionnaire avec les champs que nous voulons mettre à jour ou ajouter à notre jeu de données, et une liste de valeurs. Par exemple, voici une autre façon de supprimer tous les caractères HTML, mais en utilisant `batched=True` : ```python new_drug_dataset = drug_dataset.map( @@ -275,9 +275,9 @@ new_drug_dataset = drug_dataset.map( ) ``` -Si vous exécutez ce code dans un notebook, vous verrez que cette commande s'exécute beaucoup plus rapidement que la précédente. Et ce n'est pas parce que nos critiques ont déjà été sans échappement HTML -- si vous ré-exécutez l'instruction de la section précédente (sans `batched=True`), cela prendra le même temps qu'avant. En effet, les compréhensions de liste sont généralement plus rapides que l'exécution du même code dans une boucle "for", et nous gagnons également en performances en accédant à de nombreux éléments en même temps au lieu d'un par un. +Si vous exécutez ce code dans un *notebook*, vous verrez que cette commande s'exécute beaucoup plus rapidement que la précédente. Et ce n'est pas parce que nos critiques ont déjà été scannées au format HTML. Si vous ré-exécutez l'instruction de la section précédente (sans `batched=True`), cela prendra le même temps qu'avant. En effet, les compréhensions de liste sont généralement plus rapides que l'exécution du même code dans une boucle `for` et nous gagnons également en performances en accédant à de nombreux éléments en même temps au lieu d'un par un. -L'utilisation de `Dataset.map()` avec `batched=True` sera essentielle pour débloquer la vitesse des tokenizers "rapides" que nous rencontrerons dans [Chapitre 6](/course/chapter6), qui peuvent rapidement tokeniser de grandes listes de textes. Par exemple, pour tokeniser toutes les revues de médicaments avec un tokenizer rapide, nous pourrions utiliser une fonction comme celle-ci : +L'utilisation de `Dataset.map()` avec `batched=True` est essentielle pour les *tokenizers rapides* que nous rencontrerons dans le [Chapitre 6](/course/fr/chapter6) et qui peuvent rapidement tokeniser de grandes listes de textes. Par exemple, pour tokeniser toutes les critiques de médicaments avec un *tokenizer* rapide nous pouvons utiliser une fonction comme celle-ci : ```python from transformers import AutoTokenizer @@ -289,32 +289,32 @@ def tokenize_function(examples): return tokenizer(examples["review"], truncation=True) ``` -Comme vous l'avez vu dans le [Chapitre 3](/course/chapter3), nous pouvons passer un ou plusieurs exemples au tokenizer, nous pouvons donc utiliser cette fonction avec ou sans `batched=True`. Profitons-en pour comparer les performances des différentes options. Dans un cahier, vous pouvez chronométrer une instruction d'une ligne en ajoutant `%time` avant la ligne de code que vous souhaitez mesurer : +Comme vous l'avez vu dans le [Chapitre 3](/course/fr/chapter3), nous pouvons passer un ou plusieurs exemples au *tokenizer*. Nous pouvons donc utiliser cette fonction avec ou sans `batched=True`. Profitons-en pour comparer les performances des différentes options. Dans un *notebook*, vous pouvez chronométrer une instruction d'une ligne en ajoutant `%time` avant la ligne de code que vous souhaitez mesurer : ```python no-format %time tokenized_dataset = drug_dataset.map(tokenize_function, batched=True) ``` -Vous pouvez également chronométrer une cellule entière en mettant `%%time` au début de la cellule. Sur le matériel sur lequel nous avons exécuté cela, il affichait 10,8 s pour cette instruction (c'est le nombre écrit après "Wall time"). +Vous pouvez également chronométrer une cellule entière en mettant `%%time` au début de la cellule. Sur le matériel sur lequel nous avons exécuté cela, cela affichait 10,8 s pour cette instruction (c'est le nombre écrit après "Wall time"). -✏️ **Essayez-le !** Exécutez la même instruction avec et sans `batched=True`, puis essayez-le avec un tokenizer lent (ajoutez `use_fast=False` dans la méthode `AutoTokenizer.from_pretrained()`) afin que vous puissiez voir quels numéros vous obtenez sur votre matériel. +✏️ **Essayez !** Exécutez la même instruction avec et sans `batched=True`, puis essayez-le avec un *tokenizer* lent (ajoutez `use_fast=False` dans la méthode `AutoTokenizer.from_pretrained()`) afin que vous puissiez voir quels temps vous obtenez sur votre matériel. -Voici les résultats que nous avons obtenus avec et sans batching, avec un tokenizer rapide et un lent : +Voici les résultats que nous avons obtenus avec et sans batching, avec un *tokenizer* rapide et un lent : -Options | Tokenizer rapide | Tokenizer lent +Options | *Tokenizer* rapide | *Tokenizer* lent :--------------:|:----------------:|:-----------------: `batched=True` | 10.8s | 4min41s `batched=False` | 59.2s | 5min3s -Cela signifie que l'utilisation d'un tokenizer rapide avec l'option `batched=True` est 30 fois plus rapide que son homologue lent sans traitement par lot -- c'est vraiment incroyable ! C'est la raison principale pour laquelle les tokenizers rapides sont la valeur par défaut lors de l'utilisation de `AutoTokenizer` (et pourquoi ils sont appelés "rapides"). Ils sont capables d'atteindre une telle accélération car dans les coulisses, le code de tokenisation est exécuté dans Rust, qui est un langage qui facilite la parallélisation de l'exécution du code. +Cela signifie que l'utilisation d'un *tokenizer* rapide avec l'option `batched=True` est 30 fois plus rapide que son homologue lent sans batch. C'est vraiment incroyable ! C'est la raison principale pour laquelle les *tokenizers* rapides sont la valeur par défaut lors de l'utilisation de `AutoTokenizer` (et pourquoi ils sont appelés « rapides »). Ils sont capables d'atteindre une telle vitesse car en coulisses le code de tokenisation est exécuté en Rust qui est un langage facilitant la parallélisation de l'exécution du code. -La parallélisation est également la raison de l'accélération de près de 6 fois obtenue par le fast tokenizer avec le traitement par lots : vous ne pouvez pas paralléliser une seule opération de tokenisation, mais lorsque vous souhaitez tokeniser de nombreux textes en même temps, vous pouvez simplement répartir l'exécution sur plusieurs processus. chacun responsable de ses propres textes. +La parallélisation est également la raison du gain de vitesse de près de 6 fois obtenue par le *tokenizer* rapide avec batch. Vous ne pouvez pas paralléliser une seule opération de tokenisation, mais lorsque vous souhaitez *tokeniser* de nombreux textes en même temps, vous pouvez simplement répartir l'exécution sur plusieurs processus. Chacun responsable de ses propres textes. -`Dataset.map()` possède également ses propres capacités de parallélisation. Comme ils ne sont pas soutenus par Rust, ils ne laisseront pas un tokenizer lent rattraper un rapide, mais ils peuvent toujours être utiles (surtout si vous utilisez un tokenizer qui n'a pas de version rapide). Pour activer le multitraitement, utilisez l'argument `num_proc` et spécifiez le nombre de processus à utiliser dans votre appel à `Dataset.map()` : +`Dataset.map()` possède aussi ses propres capacités de parallélisation. Comme elles ne sont pas soutenus par Rust, un *tokenizer* lent ne peut pas rattraper un rapide mais cela peut toujours être utile (surtout si vous utilisez un *tokenizer* qui n'a pas de version rapide). Pour activer le multitraitement, utilisez l'argument `num_proc` et spécifiez le nombre de processus à utiliser dans votre appel à `Dataset.map()` : ```py slow_tokenizer = AutoTokenizer.from_pretrained("bert-base-cased", use_fast=False) @@ -327,24 +327,24 @@ def slow_tokenize_function(examples): tokenized_dataset = drug_dataset.map(slow_tokenize_function, batched=True, num_proc=8) ``` -Vous pouvez expérimenter un peu le timing pour déterminer le nombre optimal de processus à utiliser ; dans notre cas 8 semblait produire le meilleur gain de vitesse. Voici les chiffres que nous avons obtenus avec et sans multitraitement : +Vous pouvez faire des tests pour déterminer le nombre optimal de processus à utiliser. Dans notre cas 8 semble produire le meilleur gain de vitesse. Voici les chiffres que nous avons obtenus avec et sans multitraitement : -Options | Tokenizer rapide | Tokenizer lent +Options | *Tokenizer* rapide | *Tokenizer* lent :----------------------------:|:----------------:|:---------------: `batched=True` | 10.8s | 4min41s `batched=False` | 59.2s | 5min3s `batched=True`, `num_proc=8` | 6.52s | 41.3s `batched=False`, `num_proc=8` | 9.49s | 45.2s -Ce sont des résultats beaucoup plus raisonnables pour le tokenizer lent, mais les performances du tokenizer rapide ont également été considérablement améliorées. Notez, cependant, que ce ne sera pas toujours le cas - pour les valeurs de `num_proc` autres que 8, nos tests ont montré qu'il était plus rapide d'utiliser `batched=True` sans cette option. En général, nous ne recommandons pas d'utiliser le multitraitement Python pour les tokenizers rapides avec `batched=True`. +Ce sont des résultats beaucoup plus raisonnables pour le *tokenizer* lent mais les performances du *tokenizer* rapide ont également été considérablement améliorées. Notez, cependant, que ce ne sera pas toujours le cas : pour des valeurs de `num_proc` autres que 8, nos tests ont montré qu'il était plus rapide d'utiliser `batched=True` sans cette option. En général, nous ne recommandons pas d'utiliser le multitraitement pour les *tokenizers* rapides avec `batched=True`. -Utiliser `num_proc` pour accélérer votre traitement est généralement une bonne idée, tant que la fonction que vous utilisez n'effectue pas déjà une sorte de multitraitement. +Utiliser `num_proc` pour accélérer votre traitement est généralement une bonne idée tant que la fonction que vous utilisez n'effectue pas déjà une sorte de multitraitement. -Toutes ces fonctionnalités condensées en une seule méthode sont déjà assez étonnantes, mais il y a plus ! Avec `Dataset.map()` et `batched=True` vous pouvez modifier le nombre d'éléments dans votre jeu de données. Ceci est très utile dans de nombreuses situations où vous souhaitez créer plusieurs fonctionnalités d'entraînement à partir d'un exemple, et nous devrons le faire dans le cadre du prétraitement de plusieurs des tâches NLP que nous entreprendrons dans [Chapitre 7](/course/ Chapitre 7). +Toutes ces fonctionnalités condensées en une seule méthode sont déjà assez étonnantes, mais il y a plus ! Avec `Dataset.map()` et `batched=True` vous pouvez modifier le nombre d'éléments dans votre jeu de données. Ceci est très utile dans de nombreuses situations où vous souhaitez créer plusieurs fonctionnalités d'entraînement à partir d'un exemple. Nous devrons le faire dans le cadre du prétraitement de plusieurs des tâches de traitement du langage naturel que nous entreprendrons dans le [Chapitre 7](/course/fr/chapter7). @@ -352,7 +352,7 @@ Toutes ces fonctionnalités condensées en une seule méthode sont déjà assez -Voyons comment cela fonctionne ! Ici, nous allons tokeniser nos exemples et les tronquer à une longueur maximale de 128, mais nous demanderons au tokenizer de renvoyer *tous* les morceaux des textes au lieu du premier. Cela peut être fait avec `return_overflowing_tokens=True` : +Voyons comment cela fonctionne ! Ici, nous allons tokeniser nos exemples et les tronquer à une longueur maximale de 128 mais nous demanderons au *tokenizer* de renvoyer *tous* les morceaux des textes au lieu du premier. Cela peut être fait avec `return_overflowing_tokens=True` : ```py def tokenize_and_split(examples): @@ -364,7 +364,7 @@ def tokenize_and_split(examples): ) ``` -Testons cela sur un exemple avant d'utiliser `Dataset.map()` sur l'ensemble de données : +Testons cela sur un exemple avant d'utiliser `Dataset.map()` sur le jeu de données : ```py result = tokenize_and_split(drug_dataset["train"][0]) @@ -375,7 +375,7 @@ result = tokenize_and_split(drug_dataset["train"][0]) [128, 49] ``` -Ainsi, notre premier exemple dans l'ensemble de formation est devenu deux fonctionnalités car il a été segmenté à plus que le nombre maximum de jetons que nous avons spécifié : le premier de longueur 128 et le second de longueur 49. Faisons maintenant cela pour tous les éléments du base de données! +Notre premier exemple du jeu d’entraînement est devenu deux caractéristiques car il a été segmenté à plus que le nombre maximum de *tokens* que nous avons spécifié : le premier de longueur 128 et le second de longueur 49. Faisons maintenant cela pour tous les éléments du jeu de données ! ```py tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True) @@ -385,9 +385,9 @@ tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True) ArrowInvalid: Column 1 named condition expected length 1463 but got length 1000 ``` -Oh non! Cela n'a pas fonctionné ! Pourquoi pas? L'examen du message d'erreur nous donnera un indice : il y a une incompatibilité dans les longueurs de l'une des colonnes, l'une étant de longueur 1 463 et l'autre de longueur 1 000. Si vous avez consulté la [documentation] `Dataset.map()`(https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map), vous vous souviendrez peut-être qu'il s'agit du nombre d'échantillons passés à la fonction que nous mappons ; ici, ces 1 000 exemples ont donné 1 463 nouvelles fonctionnalités, entraînant une erreur de forme. +Oh non ! Cela n'a pas fonctionné ! Pourquoi ? L'examen du message d'erreur nous donne un indice : il y a une incompatibilité dans les longueurs de l'une des colonnes. L'une étant de longueur 1 463 et l'autre de longueur 1 000. Si vous avez consulté la [documentation](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) de `Dataset.map()`, vous vous souvenez peut-être qu'il s'agit du nombre d'échantillons passés à la fonction que nous mappons. Ici, ces 1 000 exemples ont donné 1 463 nouvelles caractéristiques, entraînant une erreur de forme. -Le problème est que nous essayons de mélanger deux ensembles de données différents de tailles différentes : les colonnes `drug_dataset` auront un certain nombre d'exemples (les 1 000 dans notre erreur), mais le `tokenized_dataset` que nous construisons en aura plus (le 1 463 dans le message d'erreur). Cela ne fonctionne pas pour un `Dataset`, nous devons donc soit supprimer les colonnes de l'ancien jeu de données, soit leur donner la même taille que dans le nouveau jeu de données. Nous pouvons faire le premier avec l'argument `remove_columns` : +Le problème est que nous essayons de mélanger deux jeux de données différents de tailles différentes : les colonnes `drug_dataset` auront un certain nombre d'exemples (les 1 000 dans notre erreur), mais le `tokenized_dataset` que nous construisons en aura plus (le 1 463 dans le message d'erreur). Cela ne fonctionne pas pour un `Dataset`, nous devons donc soit supprimer les colonnes de l'ancien jeu de données, soit leur donner la même taille que dans le nouveau jeu de données. Nous pouvons faire la première option avec l'argument `remove_columns` : ```py tokenized_dataset = drug_dataset.map( @@ -395,7 +395,7 @@ tokenized_dataset = drug_dataset.map( ) ``` -Maintenant, cela fonctionne sans erreur. Nous pouvons vérifier que notre nouveau jeu de données contient beaucoup plus d'éléments que le jeu de données d'origine en comparant les longueurs : +Maintenant, cela fonctionne sans erreur. Nous pouvons vérifier que notre nouveau jeu de données contient beaucoup plus d'éléments que le jeu de données d'origine en comparant les longueurs : ```py len(tokenized_dataset["train"]), len(drug_dataset["train"]) @@ -405,7 +405,7 @@ len(tokenized_dataset["train"]), len(drug_dataset["train"]) (206772, 138514) ``` -Nous avons mentionné que nous pouvions également résoudre le problème de longueur non concordante en donnant aux anciennes colonnes la même taille que les nouvelles. Pour ce faire, nous aurons besoin du champ `overflow_to_sample_mapping` que le tokenizer renvoie lorsque nous définissons `return_overflowing_tokens=True`. Il nous donne une correspondance entre un nouvel index de fonctionnalité et l'index de l'échantillon dont il est issu. Grâce à cela, nous pouvons associer chaque clé présente dans notre jeu de données d'origine à une liste de valeurs de la bonne taille en répétant les valeurs de chaque exemple autant de fois qu'il génère de nouvelles fonctionnalités : +Nous avons mentionné que nous pouvions également résoudre le problème de longueur non concordante en donnant aux anciennes colonnes la même taille que les nouvelles. Pour ce faire, nous avons besoin du champ `overflow_to_sample_mapping` que le *tokenizer* renvoie lorsque nous définissons `return_overflowing_tokens=True`. Il nous donne une correspondance entre un nouvel index de caractéristique et l'index de l'échantillon dont il est issu. Grâce à cela, nous pouvons associer chaque clé présente dans notre jeu de données d'origine à une liste de valeurs de la bonne taille en répétant les valeurs de chaque exemple autant de fois qu'il génère de nouvelles caractéristiques : ```py def tokenize_and_split(examples): @@ -422,7 +422,7 @@ def tokenize_and_split(examples): return result ``` -Nous pouvons voir que cela fonctionne avec `Dataset.map()` sans que nous ayons besoin de supprimer les anciennes colonnes : +Nous pouvons voir que cela fonctionne avec `Dataset.map()` sans que nous ayons besoin de supprimer les anciennes colonnes : ```py tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True) @@ -442,22 +442,21 @@ DatasetDict({ }) ``` -Nous obtenons le même nombre de fonctionnalités d'entraînement qu'auparavant, mais ici nous avons conservé tous les anciens champs. Si vous en avez besoin pour un post-traitement après l'application de votre modèle, vous pouvez utiliser cette approche. +Nous obtenons le même nombre de caractéristiques d'entraînement qu'auparavant, mais ici nous avons conservé tous les anciens champs. Si vous en avez besoin pour un post-traitement après l'application de votre modèle, vous pouvez utiliser cette approche. -Vous avez maintenant vu comment 🤗 Datasets peut être utilisé pour prétraiter un ensemble de données de différentes manières. Bien que les fonctions de traitement de 🤗 Datasets couvrent la plupart de vos besoins de formation de modèles, -il peut arriver que vous deviez passer à Pandas pour accéder à des fonctionnalités plus puissantes, telles que `DataFrame.groupby()` ou des API de haut niveau pour la visualisation. Heureusement, 🤗 Datasets est conçu pour être interopérable avec des bibliothèques telles que Pandas, NumPy, PyTorch, TensorFlow et JAX. Voyons comment cela fonctionne. +Vous avez maintenant vu comment 🤗 *Datasets* peut être utilisé pour prétraiter un jeu de données de différentes manières. Bien que les fonctions de traitement de 🤗 *Datasets* couvrent la plupart de vos besoins, il peut arriver que vous deviez passer à Pandas pour accéder à des fonctionnalités plus puissantes, telles que `DataFrame.groupby()` ou des API de haut niveau pour la visualisation. Heureusement, 🤗 *Datasets* est conçu pour être interopérable avec des bibliothèques telles que Pandas, NumPy, PyTorch, TensorFlow et JAX. Voyons comment cela fonctionne. -## De `Dataset`s à `DataFrame`s et vice versa +## De `Dataset` à `DataFrame` et vice versa -Pour permettre la conversion entre diverses bibliothèques tierces, 🤗 Datasets fournit une fonction `Dataset.set_format()`. Cette fonction ne modifie que le _format de sortie_ de l'ensemble de données, vous pouvez donc facilement passer à un autre format sans affecter le _format de données_ sous-jacent, qui est Apache Arrow. Le formatage se fait sur place. Pour démontrer, convertissons notre jeu de données en Pandas : +Pour permettre la conversion entre diverses bibliothèques tierces, 🤗 *Datasets* fournit une fonction `Dataset.set_format()`. Cette fonction ne modifie que le _format de sortie_ du jeu de données. Vous pouvez donc facilement passer à un autre format sans affecter le _format de données_ sous-jacent, qui est Apache Arrow. Le formatage se fait sur place. Pour démontrer, convertissons notre jeu de données vers Pandas : ```py drug_dataset.set_format("pandas") ``` -Maintenant, lorsque nous accédons aux éléments du jeu de données, nous obtenons un `pandas.DataFrame` au lieu d'un dictionnaire : +Maintenant, lorsque nous accédons aux éléments du jeu de données, nous obtenons un `pandas.DataFrame` au lieu d'un dictionnaire : ```py drug_dataset["train"][:3] @@ -514,7 +513,7 @@ drug_dataset["train"][:3] -Créons un `pandas.DataFrame` pour l'ensemble d'entraînement en sélectionnant tous les éléments de `drug_dataset["train"]` : +Créons un `pandas.DataFrame` pour l'ensemble d'entraînement en sélectionnant tous les éléments de `drug_dataset["train"]` : ```py train_df = drug_dataset["train"][:] @@ -522,12 +521,12 @@ train_df = drug_dataset["train"][:] -🚨 Sous le capot, `Dataset.set_format()` change le format de retour pour la méthode dunder `__getitem__()` de l'ensemble de données. Cela signifie que lorsque nous voulons créer un nouvel objet comme `train_df` à partir d'un `Dataset` au format `"pandas"`, nous devons découper tout l'ensemble de données pour obtenir un `pandas.DataFrame`. Vous pouvez vérifier par vous-même que le type de `drug_dataset["train"]` est `Dataset`, quel que soit le format de sortie. +🚨 Sous le capot, `Dataset.set_format()` change le format de retour pour la méthode `__getitem__()`. Cela signifie que lorsque nous voulons créer un nouvel objet comme `train_df` à partir d'un `Dataset` au format `"pandas"`, nous devons découper tout le jeu de données pour obtenir un `pandas.DataFrame`. Vous pouvez vérifier par vous-même que le type de `drug_dataset["train"]` est `Dataset`, quel que soit le format de sortie. -De là, nous pouvons utiliser toutes les fonctionnalités Pandas que nous voulons. Par exemple, nous pouvons faire un chaînage sophistiqué pour calculer la distribution de classe parmi les entrées `condition` : +De là, nous pouvons utiliser toutes les fonctionnalités Pandas que nous voulons. Par exemple, nous pouvons faire un chaînage sophistiqué pour calculer la distribution de classe parmi les entrées `condition` : ```py frequencies = ( @@ -578,7 +577,7 @@ frequencies.head() -Et une fois que nous avons terminé notre analyse Pandas, nous pouvons toujours créer un nouvel objet `Dataset` en utilisant la fonction `Dataset.from_pandas()` comme suit : +Et une fois que nous avons terminé notre analyse Pandas, nous pouvons toujours créer un nouvel objet `Dataset` en utilisant la fonction `Dataset.from_pandas()` comme suit : ```py @@ -597,11 +596,11 @@ Dataset({ -✏️ **Essayez-le !** Calculez la note moyenne par médicament et stockez le résultat dans un nouvel ensemble de données. +✏️ **Essayez !** Calculez la note moyenne par médicament et stockez le résultat dans un nouveau jeu de données. -Ceci conclut notre visite des différentes techniques de prétraitement disponibles dans 🤗 Datasets. Pour compléter la section, créons un ensemble de validation pour préparer l'ensemble de données pour la formation d'un classificateur. Avant cela, nous allons réinitialiser le format de sortie de `drug_dataset` de `"pandas"` à `"arrow"` : +Ceci conclut notre visite des différentes techniques de prétraitement disponibles dans 🤗 *Datasets*. Pour compléter la section, créons un ensemble de validation pour préparer le jeu de données à l’entraînement d'un classifieur. Avant cela, nous allons réinitialiser le format de sortie de `drug_dataset` de `"pandas"` à `"arrow"` : ```python drug_dataset.reset_format() @@ -609,9 +608,9 @@ drug_dataset.reset_format() ## Création d'un ensemble de validation -Bien que nous ayons un jeu de test que nous pourrions utiliser pour l'évaluation, il est recommandé de ne pas toucher au jeu de test et de créer un jeu de validation séparé pendant le développement. Une fois que vous êtes satisfait des performances de vos modèles sur l'ensemble de validation, vous pouvez effectuer une dernière vérification d'intégrité sur l'ensemble de test. Ce processus permet d'atténuer le risque de dépassement de l'ensemble de test et de déploiement d'un modèle qui échoue sur des données du monde réel. +Bien que nous ayons un jeu de test que nous pourrions utiliser pour l'évaluation, il est recommandé de ne pas toucher au jeu de test et de créer un jeu de validation séparé pendant le développement. Une fois que vous êtes satisfait des performances de vos modèles sur l'ensemble de validation, vous pouvez effectuer une dernière vérification d'intégrité sur l'ensemble test. Ce processus permet d'atténuer le risque de surentraînement sur le jeu de test et de déployer un modèle qui échoue sur des données du monde réel. -🤗 Datasets fournit une fonction `Dataset.train_test_split()` basée sur la célèbre fonctionnalité de `scikit-learn`. Utilisons-le pour diviser notre ensemble d'entraînement en divisions "train" et "validation" (nous définissons l'argument "seed" pour la reproductibilité) : +🤗 *Datasets* fournit une fonction `Dataset.train_test_split()` basée sur la célèbre fonctionnalité de `scikit-learn`. Utilisons-la pour diviser notre ensemble d'entraînement `train` et `validation` (nous définissons l'argument `seed` pour la reproductibilité) : ```py drug_dataset_clean = drug_dataset["train"].train_test_split(train_size=0.8, seed=42) @@ -639,27 +638,27 @@ DatasetDict({ }) ``` -Génial, nous avons maintenant préparé un jeu de données prêt pour l'entraînement de certains modèles ! Dans la [section 5](/course/chapter5/5), nous vous montrerons comment télécharger des ensembles de données sur le Hugging Face Hub, mais pour l'instant, terminons notre analyse en examinant quelques façons d'enregistrer des ensembles de données sur votre ordinateur local. +Génial, nous avons maintenant préparé un jeu de données prêt pour l'entraînement de certains modèles ! Dans la [section 5](/course/fr/chapter5/5), nous vous montrerons comment télécharger des jeux de données sur le *Hub*. Mais pour l'instant, terminons notre analyse en examinant quelques façons d'enregistrer des jeux de données sur votre ordinateur local. ## Enregistrer un jeu de données -Bien que 🤗 Datasets mette en cache chaque jeu de données téléchargé et les opérations qui y sont effectuées, il y a des moments où vous voudrez enregistrer un jeu de données sur le disque (par exemple, au cas où le cache serait supprimé). Comme indiqué dans le tableau ci-dessous, 🤗 Datasets fournit trois fonctions principales pour enregistrer votre jeu de données dans différents formats : +Bien que 🤗 *Datasets* mette en cache chaque jeu de données téléchargé et les opérations qui y sont effectuées, il y a des moments où vous voudrez enregistrer un jeu de données sur le disque (par exemple, au cas où le cache serait supprimé). Comme indiqué dans le tableau ci-dessous, 🤗 *Datasets* fournit trois fonctions principales pour enregistrer votre jeu de données dans différents formats : | Format de données | Fonction | | :---------------: | :----------------------: | -| Flèche | `Dataset.save_to_disk()` | +| Arrow | `Dataset.save_to_disk()` | | CSV | `Dataset.to_csv()` | | JSON | `Dataset.to_json()` | -Par exemple, enregistrons notre jeu de données nettoyé au format Arrow : +Par exemple, enregistrons notre jeu de données nettoyé au format Arrow : ```py drug_dataset_clean.save_to_disk("drug-reviews") ``` -Cela créera un répertoire avec la structure suivante : +Cela créera un répertoire avec la structure suivante : ``` drug-reviews/ @@ -680,9 +679,9 @@ drug-reviews/ └── state.json ``` -où nous pouvons voir que chaque division est associée à sa propre table * dataset.arrow * et à certaines métadonnées dans * dataset_info.json * et * state.json *. Vous pouvez considérer le format Arrow comme un tableau sophistiqué de colonnes et de lignes optimisé pour la création d'applications hautes performances qui traitent et transportent de grands ensembles de données. +où nous pouvons voir que chaque division est associée à sa propre table *dataset.arrow* et à certaines métadonnées dans *dataset_info.json* et *state.json*. Vous pouvez considérer le format Arrow comme un tableau sophistiqué de colonnes et de lignes optimisé pour la création d'applications hautes performances qui traitent et transportent de grands ensembles de données. -Une fois le jeu de données enregistré, nous pouvons le charger en utilisant la fonction `load_from_disk()` comme suit : +Une fois le jeu de données enregistré, nous pouvons le charger en utilisant la fonction `load_from_disk()` comme suit : ```py from datasets import load_from_disk @@ -708,14 +707,14 @@ DatasetDict({ }) ``` -Pour les formats CSV et JSON, nous devons stocker chaque fractionnement dans un fichier séparé. Pour ce faire, vous pouvez parcourir les clés et les valeurs de l'objet "DatasetDict" : +Pour les formats CSV et JSON, nous devons stocker chaque fractionnement dans un fichier séparé. Pour ce faire, vous pouvez parcourir les clés et les valeurs de l'objet `DatasetDict` : ```py for split, dataset in drug_dataset_clean.items(): dataset.to_json(f"drug-reviews-{split}.jsonl") ``` -Cela enregistre chaque fractionnement au [format de lignes JSON] (https://jsonlines.org), où chaque ligne de l'ensemble de données est stockée sous la forme d'une seule ligne de JSON. Voici à quoi ressemble le premier exemple : +Cela enregistre chaque fractionnement au [format JSON Lines](https://jsonlines.org), où chaque ligne du jeu de données est stockée sous la forme d'une seule ligne de JSON. Voici à quoi ressemble le premier exemple : ```py !head -n 1 drug-reviews-train.jsonl @@ -725,7 +724,7 @@ Cela enregistre chaque fractionnement au [format de lignes JSON] (https://jsonli {"patient_id":141780,"drugName":"Escitalopram","condition":"depression","review":"\"I seemed to experience the regular side effects of LEXAPRO, insomnia, low sex drive, sleepiness during the day. I am taking it at night because my doctor said if it made me tired to take it at night. I assumed it would and started out taking it at night. Strange dreams, some pleasant. I was diagnosed with fibromyalgia. Seems to be helping with the pain. Have had anxiety and depression in my family, and have tried quite a few other medications that haven't worked. Only have been on it for two weeks but feel more positive in my mind, want to accomplish more in my life. Hopefully the side effects will dwindle away, worth it to stick with it from hearing others responses. Great medication.\"","rating":9.0,"date":"May 29, 2011","usefulCount":10,"review_length":125} ``` -Nous pouvons ensuite utiliser les techniques de [section 2](/course/chapter5/2) pour charger les fichiers JSON comme suit : +Nous pouvons ensuite utiliser les techniques de [section 2](/course/fr/chapter5/2) pour charger les fichiers JSON comme suit : ```py data_files = { @@ -736,9 +735,9 @@ data_files = { drug_dataset_reloaded = load_dataset("json", data_files=data_files) ``` -Et c'est tout pour notre excursion dans le data wrangling avec 🤗 Datasets ! Maintenant que nous disposons d'un ensemble de données nettoyé pour entraîner un modèle, voici quelques idées que vous pouvez essayer : +Et c'est tout pour notre excursion dans la manipulation des données avec 🤗 *Datasets* ! Maintenant que nous disposons d'un ensemble de données nettoyé pour entraîner un modèle, voici quelques idées que vous pouvez essayer : -1. Utilisez les techniques du [Chapitre 3](/course/chapter3) pour former un classificateur capable de prédire l'état du patient en fonction de l'examen du médicament. -2. Utilisez le pipeline `summarization` du [Chapitre 1](/course/chapter1) pour générer des résumés des révisions. +1. Utilisez les techniques du [Chapitre 3](/course/fr/chapter3) pour entraîner un classifieur capable de prédire l'état du patient en fonction de l'examen du médicament. +2. Utilisez le pipeline `summarization` du [Chapitre 1](/course/fr/chapter1) pour générer des résumés des révisions. -Ensuite, nous verrons comment 🤗 Datasets peut vous permettre de travailler avec d'énormes ensembles de données sans faire exploser votre ordinateur portable ! +Ensuite, nous verrons comment 🤗 *Datasets* peut vous permettre de travailler avec d'énormes jeux de données sans faire exploser votre ordinateur portable ! diff --git a/chapters/fr/chapter5/4.mdx b/chapters/fr/chapter5/4.mdx index 63ed0be44..8657e3b62 100644 --- a/chapters/fr/chapter5/4.mdx +++ b/chapters/fr/chapter5/4.mdx @@ -1,4 +1,4 @@ -# Big Data? 🤗 Datasets à la rescousse ! +# Données massives ? 🤗 *Datasets* à la rescousse ! -De nos jours, il n'est pas rare de travailler avec des ensembles de données de plusieurs gigaoctets, surtout si vous envisagez de pré-entraîner un transformateur comme BERT ou GPT-2 à partir de zéro. Dans ces cas, même _charger_ les données peut être un défi. Par exemple, le corpus WebText utilisé pour pré-entraîner GPT-2 se compose de plus de 8 millions de documents et de 40 Go de texte - le charger dans la RAM de votre ordinateur portable est susceptible de lui donner une crise cardiaque ! +De nos jours, il n'est pas rare de travailler avec des jeux de données de plusieurs gigaoctets surtout si vous envisagez de pré-entraîner un *transformer* comme BERT ou GPT-2 à partir de zéro. Dans ces cas, même _charger_ les données peut être un défi. Par exemple, le corpus WebText utilisé pour pré-entraîner GPT-2 se compose de plus de 8 millions de documents et de 40 Go de texte. Le charger dans la RAM de votre ordinateur portable est susceptible de lui donner une crise cardiaque ! -Heureusement, 🤗 Datasets a été conçu pour surmonter ces limitations. Il vous libère des problèmes de gestion de la mémoire en traitant les ensembles de données comme des fichiers _mappés en mémoire_, et des limites du disque dur en _streaming_ les entrées dans un corpus. +Heureusement, 🤗 *Datasets* a été conçu pour surmonter ces limitations. Il vous libère des problèmes de gestion de la mémoire en traitant les jeux de données comme des fichiers _mappés en mémoire_, ainsi que des limites du disque dur en faisant du _streaming_ sur les entrées dans un corpus. -Dans cette section, nous allons explorer ces fonctionnalités de 🤗 Datasets avec un énorme corpus de 825 Go connu sous le nom de [the Pile](https://pile.eleuther.ai). Commençons! +Dans cette section, nous allons explorer ces fonctionnalités de 🤗 *Datasets* avec un énorme corpus de 825 Go connu sous le nom de [The Pile](https://pile.eleuther.ai). Commençons ! -## Qu'est-ce que The Pile ? +## Qu'est-ce que *The Pile* ? -The Pile est un corpus de texte en anglais créé par [EleutherAI](https://www.eleuther.ai) pour entraîner des modèles de langage à grande échelle. Il comprend une gamme variée d'ensembles de données, couvrant des articles scientifiques, des référentiels de code GitHub et du texte Web filtré. Le corpus de formation est disponible en [morceaux de 14 Go](https://mystic.the-eye.eu/public/AI/pile/), et vous pouvez également télécharger plusieurs des [composants individuels](https://mystic .the-eye.eu/public/AI/pile_preliminary_components/). Commençons par jeter un coup d'œil à l'ensemble de données PubMed Abstracts, qui est un corpus de résumés de 15 millions de publications biomédicales sur [PubMed](https://pubmed.ncbi.nlm.nih.gov/). L'ensemble de données est au [format JSON Lines](https://jsonlines.org) et est compressé à l'aide de la bibliothèque `zstandard`, nous devons donc d'abord l'installer : +The Pile est un corpus de texte en anglais créé par [EleutherAI](https://www.eleuther.ai) pour entraîner des modèles de langage à grande échelle. Il comprend une gamme variée de jeux de données, couvrant des articles scientifiques, des référentiels de code GitHub et du texte Web filtré. Le corpus d’entraînement est disponible en [morceaux de 14 Go](https://mystic.the-eye.eu/public/AI/pile/) et vous pouvez aussi télécharger plusieurs des [composants individuels]( https://mystic.the-eye.eu/public/AI/pile_preliminary_components/). Commençons par jeter un coup d'œil au jeu de données PubMed Abstracts, qui est un corpus de résumés de 15 millions de publications biomédicales sur [PubMed](https://pubmed.ncbi.nlm.nih.gov/). Le jeu de données est au [format JSON Lines](https://jsonlines.org) et est compressé à l'aide de la bibliothèque `zstandard`. Nous devons donc d'abord installer cette bibliothèque : ```py !pip install zstandard ``` -Ensuite, nous pouvons charger le jeu de données en utilisant la méthode pour les fichiers distants que nous avons apprise dans [section 2](/course/chapter5/2) : +Ensuite, nous pouvons charger le jeu de données en utilisant la méthode pour les fichiers distants que nous avons apprise dans [section 2](/course/fr/chapter5/2) : ```py from datasets import load_dataset @@ -42,15 +42,15 @@ Dataset({ }) ``` -Nous pouvons voir qu'il y a 15 518 009 lignes et 2 colonnes dans notre ensemble de données -- c'est beaucoup ! +Nous pouvons voir qu'il y a 15 518 009 lignes et 2 colonnes dans notre jeu de données. C'est beaucoup ! -✎ Par défaut, 🤗 Datasets décompressera les fichiers nécessaires pour charger un jeu de données. Si vous souhaitez conserver de l'espace sur le disque dur, vous pouvez passer `DownloadConfig(delete_extracted=True)` à l'argument `download_config` de `load_dataset()`. Voir la [documentation](https://huggingface.co/docs/datasets/package_reference/builder_classes.html?#datasets.utils.DownloadConfig) pour plus de détails. +✎ Par défaut, 🤗 *Datasets* décompresse les fichiers nécessaires pour charger un jeu de données. Si vous souhaitez conserver de l'espace sur le disque dur, vous pouvez passer `DownloadConfig(delete_extracted=True)` à l'argument `download_config` de `load_dataset()`. Voir la [documentation](https://huggingface.co/docs/datasets/package_reference/builder_classes.html?#datasets.utils.DownloadConfig) pour plus de détails. -Inspectons le contenu du premier exemple : +Inspectons le contenu du premier exemple : ```py pubmed_dataset[0] @@ -58,25 +58,27 @@ pubmed_dataset[0] ```python out {'meta': {'pmid': 11409574, 'language': 'eng'}, - 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection.\nTo determine the prevalence of hypoxaemia in children aged under 5 years suffering acute lower respiratory infections (ALRI), the risk factors for hypoxaemia in children under 5 years of age with ALRI, and the association of hypoxaemia with an increased risk of dying in children of the same age ...'} + 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection.\nTo determine the prevalence of hypoxaemia in children aged under 5 years suffering acute lower respiratory infections (ALRI), the risk factors for hypoxaemia in children under 5 years of age with ALRI, and the association of hypoxaemia with an increased risk of dying in children of the same age ...' +# Épidémiologie de l'hypoxémie chez les enfants souffrant d'une infection aiguë des voies respiratoires inférieures. Déterminer la prévalence de l'hypoxémie chez les enfants de moins de 5 ans souffrant d'une infection aiguë des voies respiratoires inférieures (IAVI), les facteurs de risque de l'hypoxémie chez les enfants de moins de 5 ans souffrant d'une IAVI, et l'association de l'hypoxémie à un risque accru de décès chez les enfants du même âge ... +} ``` -OK, ça ressemble au résumé d'un article médical. Voyons maintenant combien de RAM nous avons utilisé pour charger le jeu de données ! +Cela ressemble au résumé d'un article médical. Voyons maintenant combien de RAM nous avons utilisé pour charger le jeu de données ! -## La magie de la cartographie mémoire +## La magie du *memory mapping* -Un moyen simple de mesurer l'utilisation de la mémoire dans Python consiste à utiliser la bibliothèque [`psutil`](https://psutil.readthedocs.io/en/latest/), qui peut être installée avec `pip` comme suit : +Un moyen simple de mesurer l'utilisation de la mémoire dans Python consiste à utiliser la bibliothèque [`psutil`](https://psutil.readthedocs.io/en/latest/) qui peut être installée avec `pip` comme suit : ```python !pip install psutil ``` -Il fournit une classe `Process` qui nous permet de vérifier l'utilisation de la mémoire du processus en cours comme suit : +Elle fournit une classe `Process` qui permet de vérifier l'utilisation de la mémoire du processus en cours : ```py import psutil -# Process.memory_info is expressed in bytes, so convert to megabytes +# Process.memory_info est exprimé en octets, donc convertir en mégaoctets print(f"RAM used: {psutil.Process().memory_info().rss / (1024 * 1024):.2f} MB") ``` @@ -84,7 +86,7 @@ print(f"RAM used: {psutil.Process().memory_info().rss / (1024 * 1024):.2f} MB") RAM used: 5678.33 MB ``` -Ici, l'attribut `rss` fait référence à la _taille de l'ensemble résident_, qui est la fraction de mémoire qu'un processus occupe dans la RAM. Cette mesure inclut également la mémoire utilisée par l'interpréteur Python et les bibliothèques que nous avons chargées, de sorte que la quantité réelle de mémoire utilisée pour charger l'ensemble de données est un peu plus petite. À titre de comparaison, voyons la taille de l'ensemble de données sur le disque, en utilisant l'attribut `dataset_size`. Comme le résultat est exprimé en octets comme précédemment, nous devons le convertir manuellement en gigaoctets : +Ici, l'attribut `rss` fait référence à la _taille de l'ensemble résident_, qui est la fraction de mémoire qu'un processus occupe dans la RAM. Cette mesure inclut également la mémoire utilisée par l'interpréteur Python et les bibliothèques que nous avons chargées, de sorte que la quantité réelle de mémoire utilisée pour charger le jeu de données est un peu plus petite. À titre de comparaison, voyons la taille du jeu de données sur le disque en utilisant l'attribut `dataset_size`. Comme le résultat est exprimé en octets comme précédemment, nous devons le convertir manuellement en gigaoctets : ```py print(f"Number of files in dataset : {pubmed_dataset.dataset_size}") @@ -97,17 +99,17 @@ Number of files in dataset : 20979437051 Dataset size (cache file) : 19.54 GB ``` -Bien - malgré sa taille de près de 20 Go, nous pouvons charger et accéder à l'ensemble de données avec beaucoup moins de RAM ! +Malgré sa taille de près de 20 Go, nous pouvons charger et accéder au jeu de données avec beaucoup moins de RAM ! -✏️ **Essayez-le !** Choisissez l'un des [sous-ensembles](https://mystic.the-eye.eu/public/AI/pile_preliminary_components/) de la Pile qui est plus grand que la RAM de votre ordinateur portable ou de bureau, chargez avec 🤗 Datasets, et mesurez la quantité de RAM utilisée. Notez que pour obtenir une mesure précise, vous devrez le faire dans un nouveau processus. Vous pouvez trouver les tailles décompressées de chaque sous-ensemble dans le tableau 1 de [the Pile paper](https://arxiv.org/abs/2101.00027). +✏️ **Essayez !** Choisissez l'un des [sous-ensembles](https://mystic.the-eye.eu/public/AI/pile_preliminary_components/) de The Pile qui est plus grand que la RAM de votre ordinateur portable ou de bureau. Chargez le avec 🤗 *Datasets* et mesurez la quantité de RAM utilisée. Notez que pour obtenir une mesure précise, vous devrez le faire dans un nouveau processus. Vous pouvez trouver les tailles décompressées de chaque sous-ensemble dans le tableau 1 du papier de [The Pile](https://arxiv.org/abs/2101.00027). -Si vous êtes familier avec les pandas, ce résultat pourrait surprendre en raison de la célèbre [règle d'or](https://wesmckinney.com/blog/apache-arrow-pandas-internals/) de Wes Kinney selon laquelle vous avez généralement besoin de 5 à 10 fois plus de RAM que la taille de votre jeu de données. Alors, comment 🤗 Datasets résout-il ce problème de gestion de la mémoire ? 🤗 Datasets traite chaque ensemble de données comme un [fichier mappé en mémoire] (https://en.wikipedia.org/wiki/Memory-mapped_file), qui fournit un mappage entre la RAM et le stockage du système de fichiers qui permet à la bibliothèque d'accéder et d'opérer sur des éléments du jeu de données sans avoir besoin de le charger entièrement en mémoire. +Si vous êtes familier avec Pandas, ce résultat pourrait surprendre en raison de la célèbre [règle d'or](https://wesmckinney.com/blog/apache-arrow-pandas-internals/) de Wes Kinney selon laquelle vous avez généralement besoin de 5 à 10 fois plus de RAM que la taille de votre jeu de données. Alors, comment 🤗 *Datasets* résout-il ce problème de gestion de la mémoire ? 🤗 *Datasets* traite chaque jeu de données comme un [fichier mappé en mémoire](https://en.wikipedia.org/wiki/Memory-mapped_file). Cela fournit un mappage entre la RAM et le stockage du système de fichiers permettant à la bibliothèque d'accéder et d'opérer sur des éléments du jeu de données sans avoir besoin de le charger entièrement en mémoire. -Les fichiers mappés en mémoire peuvent également être partagés entre plusieurs processus, ce qui permet de paralléliser des méthodes telles que `Dataset.map()` sans avoir à déplacer ou copier l'ensemble de données. Sous le capot, ces capacités sont toutes réalisées par le format de mémoire [Apache Arrow](https://arrow.apache.org) et [`pyarrow`](https://arrow.apache.org/docs/python/index .html), qui accélèrent le chargement et le traitement des données. (Pour plus de détails sur Apache Arrow et les comparaisons avec Pandas, consultez [l'article de blog de Dejan Simic](https://towardsdatascience.com/apache-arrow-read-dataframe-with-zero-memory-69634092b1a).) Pour voir ceci en action, effectuons un petit test de vitesse en itérant sur tous les éléments du jeu de données PubMed Abstracts : +Les fichiers mappés en mémoire peuvent également être partagés entre plusieurs processus ce qui permet de paralléliser des méthodes telles que `Dataset.map()` sans avoir à déplacer ou copier le jeu de données. Sous le capot, ces capacités sont toutes réalisées par le format de mémoire [Apache Arrow](https://arrow.apache.org) et [`pyarrow`](https://arrow.apache.org/docs/python/index .html), qui accélèrent le chargement et le traitement des données. (Pour plus de détails sur Apache Arrow et les comparaisons avec Pandas, consultez [l'article de blog de Dejan Simic](https://towardsdatascience.com/apache-arrow-read-dataframe-with-zero-memory-69634092b1a).) Pour voir ceci en action, effectuons un petit test de vitesse en itérant sur tous les éléments du jeu de données PubMed Abstracts : ```py import timeit @@ -129,17 +131,17 @@ print( 'Iterated over 15518009 examples (about 19.5 GB) in 64.2s, i.e. 0.304 GB/s' ``` -Ici, nous avons utilisé le module `timeit` de Python pour mesurer le temps d'exécution pris par `code_snippet`. Vous pourrez généralement itérer sur un ensemble de données à une vitesse de quelques dixièmes de Go/s à plusieurs Go/s. Cela fonctionne très bien pour la grande majorité des applications, mais vous devrez parfois travailler avec un ensemble de données trop volumineux pour être même stocké sur le disque dur de votre ordinateur portable. Par exemple, si nous essayions de télécharger la Pile dans son intégralité, nous aurions besoin de 825 Go d'espace disque libre ! Pour gérer ces cas, 🤗 Datasets fournit une fonctionnalité de streaming qui nous permet de télécharger et d'accéder aux éléments à la volée, sans avoir besoin de télécharger l'intégralité du jeu de données. Voyons comment cela fonctionne. +Ici, nous avons utilisé le module `timeit` de Python pour mesurer le temps d'exécution pris par `code_snippet`. Vous pourrez généralement itérer sur un jeu de données à une vitesse de quelques dixièmes de Go/s à plusieurs Go/s. Cela fonctionne très bien pour la grande majorité des applications, mais vous devrez parfois travailler avec un jeu de données trop volumineux pour être même stocké sur le disque dur de votre ordinateur portable. Par exemple, si nous essayions de télécharger The Pile dans son intégralité, nous aurions besoin de 825 Go d'espace disque libre ! Pour gérer ces cas, 🤗 *Datasets* fournit une fonctionnalité de streaming qui nous permet de télécharger et d'accéder aux éléments à la volée, sans avoir besoin de télécharger l'intégralité du jeu de données. Voyons comment cela fonctionne. -💡 Dans les notebooks Jupyter, vous pouvez également chronométrer les cellules à l'aide de la fonction magique [`%%timeit`](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-timeit). +💡 Dans les *notebooks* Jupyter, vous pouvez également chronométrer les cellules à l'aide de la fonction magique [`%%timeit`](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-timeit). -## Ensembles de données en continu +## Jeux de données en continu -Pour activer le streaming de l'ensemble de données, il vous suffit de passer l'argument `streaming=True` à la fonction `load_dataset()`. Par exemple, chargeons à nouveau le jeu de données PubMed Abstracts, mais en mode streaming : +Pour activer le streaming du jeu de données, il vous suffit de passer l'argument `streaming=True` à la fonction `load_dataset()`. Par exemple, chargeons à nouveau le jeu de données PubMed Abstracts mais en mode streaming : ```py pubmed_dataset_streamed = load_dataset( @@ -147,7 +149,7 @@ pubmed_dataset_streamed = load_dataset( ) ``` -Au lieu du familier `Dataset` que nous avons rencontré ailleurs dans ce chapitre, l'objet retourné avec `streaming=True` est un `IterableDataset`. Comme son nom l'indique, pour accéder aux éléments d'un `IterableDataset`, nous devons parcourir celui-ci. Nous pouvons accéder au premier élément de notre jeu de données diffusé comme suit : +Au lieu du familier `Dataset` que nous avons rencontré ailleurs dans ce chapitre, l'objet retourné avec `streaming=True` est un `IterableDataset`. Comme son nom l'indique, pour accéder aux éléments d'un `IterableDataset`, nous devons parcourir celui-ci. Nous pouvons accéder au premier élément de notre jeu de données diffusé comme suit : ```py @@ -159,7 +161,7 @@ next(iter(pubmed_dataset_streamed)) 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection.\nTo determine the prevalence of hypoxaemia in children aged under 5 years suffering acute lower respiratory infections (ALRI), the risk factors for hypoxaemia in children under 5 years of age with ALRI, and the association of hypoxaemia with an increased risk of dying in children of the same age ...'} ``` -Les éléments d'un ensemble de données diffusé en continu peuvent être traités à la volée à l'aide de `IterableDataset.map()`, ce qui est utile pendant la formation si vous avez besoin de tokeniser les entrées. Le processus est exactement le même que celui que nous avons utilisé pour tokeniser notre jeu de données dans [Chapitre 3](/course/chapter3), à la seule différence que les sorties sont renvoyées une par une : +Les éléments d'un jeu de données diffusé en continu peuvent être traités à la volée à l'aide de `IterableDataset.map()`, ce qui est utile pendant l’entraînement si vous avez besoin de tokeniser les entrées. Le processus est exactement le même que celui que nous avons utilisé pour tokeniser notre jeu de données dans [Chapitre 3](/course/fr/chapter3), à la seule différence que les sorties sont renvoyées une par une : ```py from transformers import AutoTokenizer @@ -175,11 +177,11 @@ next(iter(tokenized_dataset)) -💡 Pour accélérer la tokenisation avec le streaming, vous pouvez passer `batched=True`, comme nous l'avons vu dans la dernière section. Il traitera les exemples lot par lot ; la taille de lot par défaut est de 1 000 et peut être spécifiée avec l'argument `batch_size`. +💡 Pour accélérer la tokenisation avec le streaming, vous pouvez passer `batched=True`, comme nous l'avons vu dans la dernière section. Il traitera les exemples batch par batch. La taille de batch par défaut est de 1 000 et peut être spécifiée avec l'argument `batch_size`. -Vous pouvez également mélanger un ensemble de données diffusé en continu à l'aide de `IterableDataset.shuffle()`, mais contrairement à `Dataset.shuffle()`, cela ne mélange que les éléments dans un `buffer_size` prédéfini : +Vous pouvez également mélanger un jeu de données diffusé en continu à l'aide de `IterableDataset.shuffle()`, mais contrairement à `Dataset.shuffle()`, cela ne mélange que les éléments dans un `buffer_size` prédéfini : ```py shuffled_dataset = pubmed_dataset_streamed.shuffle(buffer_size=10_000, seed=42) @@ -188,10 +190,12 @@ next(iter(shuffled_dataset)) ```python out {'meta': {'pmid': 11410799, 'language': 'eng'}, - 'text': 'Randomized study of dose or schedule modification of granulocyte colony-stimulating factor in platinum-based chemotherapy for elderly patients with lung cancer ...'} + 'text': 'Randomized study of dose or schedule modification of granulocyte colony-stimulating factor in platinum-based chemotherapy for elderly patients with lung cancer ...' +# Étude randomisée sur la modification de la dose ou du calendrier d'administration du facteur de stimulation des colonies de granulocytes dans le cadre d'une chimiothérapie à base de platine chez les patients âgés atteints de cancer du poumon ... +} ``` -Dans cet exemple, nous avons sélectionné un exemple aléatoire parmi les 10 000 premiers exemples du tampon. Une fois qu'un exemple est accédé, sa place dans le tampon est remplie avec l'exemple suivant dans le corpus (c'est-à-dire le 10 001e exemple dans le cas ci-dessus). Vous pouvez également sélectionner des éléments d'un ensemble de données diffusé en continu à l'aide des fonctions `IterableDataset.take()` et `IterableDataset.skip()`, qui agissent de la même manière que `Dataset.select()`. Par exemple, pour sélectionner les 5 premiers exemples dans l'ensemble de données PubMed Abstracts, nous pouvons procéder comme suit : +Dans cet exemple, nous avons sélectionné un exemple aléatoire parmi les 10 000 premiers exemples du tampon. Une fois qu'un exemple est accédé, sa place dans le tampon est remplie avec l'exemple suivant dans le corpus (c'est-à-dire le 10 001e exemple dans le cas ci-dessus). Vous pouvez également sélectionner des éléments d'un jeu de données diffusé en continu à l'aide des fonctions `IterableDataset.take()` et `IterableDataset.skip()`, qui agissent de la même manière que `Dataset.select()`. Par exemple, pour sélectionner les 5 premiers exemples dans le jeu de données PubMed Abstracts, nous pouvons procéder comme suit : ```py dataset_head = pubmed_dataset_streamed.take(5) @@ -200,27 +204,32 @@ list(dataset_head) ```python out [{'meta': {'pmid': 11409574, 'language': 'eng'}, - 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection ...'}, + 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection ...' +# Épidémiologie de l'hypoxémie chez les enfants atteints d'une infection aiguë des voies respiratoires inférieures ...}, {'meta': {'pmid': 11409575, 'language': 'eng'}, - 'text': 'Clinical signs of hypoxaemia in children with acute lower respiratory infection: indicators of oxygen therapy ...'}, + 'text': 'Clinical signs of hypoxaemia in children with acute lower respiratory infection: indicators of oxygen therapy ...' +# Signes cliniques d'hypoxémie chez les enfants atteints d'une infection aiguë des voies respiratoires inférieures : indicateurs de l'oxygénothérapie ...}, {'meta': {'pmid': 11409576, 'language': 'eng'}, - 'text': "Hypoxaemia in children with severe pneumonia in Papua New Guinea ..."}, + 'text': "Hypoxaemia in children with severe pneumonia in Papua New Guinea ..." +# Hypoxémie chez les enfants atteints de pneumonie grave en Papouasie-Nouvelle-Guinée ...}, {'meta': {'pmid': 11409577, 'language': 'eng'}, - 'text': 'Oxygen concentrators and cylinders ...'}, + 'text': 'Oxygen concentrators and cylinders ...' +# Concentrateurs et bouteilles d'oxygène...}, {'meta': {'pmid': 11409578, 'language': 'eng'}, - 'text': 'Oxygen supply in rural africa: a personal experience ...'}] + 'text': 'Oxygen supply in rural africa: a personal experience ...' +# L'approvisionnement en oxygène dans les zones rurales africaines : une expérience personnelle ...}] ``` -De même, vous pouvez utiliser la fonction `IterableDataset.skip()` pour créer des fractionnements d'entraînement et de validation à partir d'un ensemble de données mélangé comme suit : +De même, vous pouvez utiliser la fonction `IterableDataset.skip()` pour créer des fractionnements d'entraînement et de validation à partir d'un jeu de données mélangé comme suit : ```py -# Skip the first 1,000 examples and include the rest in the training set +# Ignorer les 1 000 premiers exemples et inclure le reste dans l'ensemble d'apprentissage. train_dataset = shuffled_dataset.skip(1000) -# Take the first 1,000 examples for the validation set +# Prendre les 1 000 premiers exemples pour l'ensemble de validation. validation_dataset = shuffled_dataset.take(1000) ``` -Terminons notre exploration du streaming d'ensembles de données avec une application commune : combiner plusieurs ensembles de données pour créer un seul corpus. 🤗 Datasets fournit une fonction `interleave_datasets()` qui convertit une liste d'objets `IterableDataset` en un seul `IterableDataset`, où les éléments du nouveau jeu de données sont obtenus en alternant entre les exemples source. Cette fonction est particulièrement utile lorsque vous essayez de combiner de grands ensembles de données. Par exemple, diffusons le sous-ensemble FreeLaw de la pile, qui est un ensemble de données de 51 Go d'avis juridiques de tribunaux américains : +Terminons notre exploration du streaming des jeux de données avec une application commune : combiner plusieurs jeux de données pour créer un seul corpus. 🤗 *Datasets* fournit une fonction `interleave_datasets()` qui convertit une liste d'objets `IterableDataset` en un seul `IterableDataset`, où les éléments du nouveau jeu de données sont obtenus en alternant entre les exemples source. Cette fonction est particulièrement utile lorsque vous essayez de combiner de grands jeux de données. Par exemple, streamons FreeLaw, un sous-ensemble de The Pile et qui est un jeu de données de 51 Go d'avis juridiques de tribunaux américains : ```py law_dataset_streamed = load_dataset( @@ -239,7 +248,7 @@ next(iter(law_dataset_streamed)) 'text': '\n461 U.S. 238 (1983)\nOLIM ET AL.\nv.\nWAKINEKONA\nNo. 81-1581.\nSupreme Court of United States.\nArgued January 19, 1983.\nDecided April 26, 1983.\nCERTIORARI TO THE UNITED STATES COURT OF APPEALS FOR THE NINTH CIRCUIT\n*239 Michael A. Lilly, First Deputy Attorney General of Hawaii, argued the cause for petitioners. With him on the brief was James H. Dannenberg, Deputy Attorney General...'} ``` -Cet ensemble de données est suffisamment volumineux pour solliciter la RAM de la plupart des ordinateurs portables, mais nous avons pu le charger et y accéder sans transpirer ! Combinons maintenant les exemples des jeux de données FreeLaw et PubMed Abstracts avec la fonction `interleave_datasets()` : +Ce jeu de données est suffisamment volumineux pour solliciter la RAM de la plupart des ordinateurs portables, mais nous avons pu le charger et y accéder sans transpirer ! Combinons maintenant les jeux de données FreeLaw et PubMed Abstracts avec la fonction `interleave_datasets()` : ```py from itertools import islice @@ -258,9 +267,9 @@ list(islice(combined_dataset, 2)) 'text': '\n461 U.S. 238 (1983)\nOLIM ET AL.\nv.\nWAKINEKONA\nNo. 81-1581.\nSupreme Court of United States.\nArgued January 19, 1983.\nDecided April 26, 1983.\nCERTIORARI TO THE UNITED STATES COURT OF APPEALS FOR THE NINTH CIRCUIT\n*239 Michael A. Lilly, First Deputy Attorney General of Hawaii, argued the cause for petitioners. With him on the brief was James H. Dannenberg, Deputy Attorney General...'}] ``` -Ici, nous avons utilisé la fonction `islice()` du module `itertools` de Python pour sélectionner les deux premiers exemples de l'ensemble de données combiné, et nous pouvons voir qu'ils correspondent aux premiers exemples de chacun des deux ensembles de données source. +Ici, nous avons utilisé la fonction `islice()` du module `itertools` de Python pour sélectionner les deux premiers exemples du jeu de données combiné. Nous pouvons voir qu'ils correspondent aux premiers exemples de chacun des deux jeux de données source. -Enfin, si vous souhaitez diffuser le Pile dans son intégralité de 825 Go, vous pouvez récupérer tous les fichiers préparés comme suit : +Enfin, si vous souhaitez streamer The Pile dans son intégralité de 825 Go, vous pouvez récupérer tous les fichiers préparés comme suit : ```py base_url = "https://mystic.the-eye.eu/public/AI/pile/" @@ -280,8 +289,8 @@ next(iter(pile_dataset["train"])) -✏️ **Essayez-le !** Utilisez l'un des grands corpus Common Crawl comme [`mc4`](https://huggingface.co/datasets/mc4) ou [`oscar`](https://huggingface.co /datasets/oscar) pour créer un jeu de données multilingue en continu qui représente les proportions de langues parlées dans un pays de votre choix. Par exemple, les quatre langues nationales en Suisse sont l'allemand, le français, l'italien et le romanche, vous pouvez donc essayer de créer un corpus suisse en échantillonnant les sous-ensembles Oscar en fonction de leur proportion parlée. +✏️ **Essayez !** Utilisez l'un des grands corpus Common Crawl comme [`mc4`](https://huggingface.co/datasets/mc4) ou [`oscar`](https://huggingface.co/datasets/oscar) pour créer en streaming un jeu de données multilingue représentant les proportions de langues parlées dans un pays de votre choix. Par exemple, les quatre langues nationales en Suisse sont l'allemand, le français, l'italien et le romanche. Vous pouvez donc essayer de créer un corpus suisse en échantillonnant les sous-ensembles Oscar en fonction de leur proportion parlée. -Vous disposez maintenant de tous les outils dont vous avez besoin pour charger et traiter des ensembles de données de toutes formes et tailles - mais à moins que vous ne soyez exceptionnellement chanceux, il arrivera un moment dans votre parcours PNL où vous devrez réellement créer un ensemble de données pour résoudre le problème à portée de main. C'est le sujet de la section suivante ! +Vous disposez maintenant de tous les outils dont vous avez besoin pour charger et traiter des jeux de données de toutes formes et tailles. Cependant à moins que vous ne soyez exceptionnellement chanceux, il arrivera un moment dans votre cheminement en traitement du langage naturel où vous devrez réellement créer un jeu de données pour résoudre un problème donné. C'est le sujet de la section suivante ! diff --git a/chapters/fr/chapter5/5.mdx b/chapters/fr/chapter5/5.mdx index 298f69200..42a9ffa15 100644 --- a/chapters/fr/chapter5/5.mdx +++ b/chapters/fr/chapter5/5.mdx @@ -7,37 +7,37 @@ {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/chapter5/section5.ipynb"}, ]} /> -Parfois, l'ensemble de données dont vous avez besoin pour créer une application NLP n'existe pas, vous devrez donc le créer vous-même. Dans cette section, nous allons vous montrer comment créer un corpus de [problèmes GitHub](https://github.com/features/issues/), qui sont couramment utilisés pour suivre les bogues ou les fonctionnalités dans les référentiels GitHub. Ce corpus pourrait être utilisé à diverses fins, notamment : +Parfois, le jeu de données dont vous avez besoin pour créer une application de NLP n'existe pas. Vous devrez donc le créer vous-même. Dans cette section, nous allons vous montrer comment créer un corpus de [problèmes GitHub](https://github.com/features/issues/), qui sont couramment utilisés pour suivre les bogues ou les fonctionnalités dans les dépôts GitHub. Ce corpus pourrait être utilisé à diverses fins, notamment : -* Explorer combien de temps il faut pour fermer les problèmes ouverts ou les demandes d'extraction -* Entraînement d'un _classificateur multilabel_ capable d'étiqueter les problèmes avec des métadonnées basées sur la description du problème (par exemple, "bogue", "amélioration" ou "question") -* Création d'un moteur de recherche sémantique pour trouver les problèmes correspondant à la requête d'un utilisateur +* explorer combien de temps il faut pour fermer les problèmes ouverts ou les *pull requests* +* entraîner d'un _classificateur multilabel_ capable d'étiqueter les problèmes avec des métadonnées basées sur la description du problème (par exemple, "bogue", "amélioration" ou "question") +* créer un moteur de recherche sémantique pour trouver les problèmes correspondant à la requête d'un utilisateur -Ici, nous nous concentrerons sur la création du corpus, et dans la section suivante, nous aborderons l'application de recherche sémantique. Pour garder les choses méta, nous utiliserons les problèmes GitHub associés à un projet open source populaire : 🤗 Datasets ! Voyons comment obtenir les données et explorons les informations contenues dans ces problèmes. +Ici, nous nous concentrerons sur la création du corpus, et dans la section suivante, nous aborderons l'application de recherche sémantique. Pour garder les choses méta, nous utiliserons les problèmes GitHub associés à un projet open source populaire : 🤗 *Datasets* ! Voyons comment obtenir les données et explorons les informations contenues dans ces problèmes. ## Obtenir les données -Vous pouvez trouver tous les problèmes dans 🤗 Datasets en accédant à l'[onglet Problèmes] du référentiel (https://github.com/huggingface/datasets/issues). Comme le montre la capture d'écran suivante, au moment de la rédaction, il y avait 331 problèmes ouverts et 668 problèmes fermés. +Vous pouvez trouver tous les problèmes dans 🤗 *Datasets* en accédant à l'[onglet « Issues »](https://github.com/huggingface/datasets/issues) du dépôt. Comme le montre la capture d'écran suivante, au moment de la rédaction, il y avait 331 problèmes ouverts et 668 problèmes fermés.
-Les problèmes GitHub associés aux 🤗 Datasets. +The GitHub issues associated with 🤗 Datasets.
Si vous cliquez sur l'un de ces problèmes, vous constaterez qu'il contient un titre, une description et un ensemble d'étiquettes qui caractérisent le problème. Un exemple est montré dans la capture d'écran ci-dessous.
-Un problème GitHub typique dans le référentiel 🤗 Datasets. +A typical GitHub issue in the 🤗 Datasets repository.
-Pour télécharger tous les problèmes du référentiel, nous utiliserons l'[API REST GitHub](https://docs.github.com/en/rest) pour interroger le point de terminaison [`Issues`](https://docs.github. com/en/rest/reference/issues#list-repository-issues). Ce point de terminaison renvoie une liste d'objets JSON, chaque objet contenant un grand nombre de champs qui incluent le titre et la description ainsi que des métadonnées sur l'état du problème, etc. +Pour télécharger tous les problèmes du dépôt, nous utilisons l'[API REST GitHub](https://docs.github.com/en/rest) pour interroger le point de terminaison [`Issues`](https://docs.github.com/en/rest/reference/issues#list-repository-issues). Ce point de terminaison renvoie une liste d'objets JSON. Chaque objet contenant un grand nombre de champs qui incluent le titre et la description ainsi que des métadonnées sur l'état du problème, etc. -Un moyen pratique de télécharger les problèmes consiste à utiliser la bibliothèque "requests", qui est la méthode standard pour effectuer des requêtes HTTP en Python. Vous pouvez installer la bibliothèque en exécutant : +Un moyen pratique de télécharger les problèmes consiste à utiliser la bibliothèque `requests`, qui est la méthode standard pour effectuer des requêtes HTTP en Python. Vous pouvez installer la bibliothèque en exécutant : ```python !pip install requests ``` -Une fois la bibliothèque installée, vous pouvez envoyer des requêtes GET au point de terminaison `Issues` en appelant la fonction `requests.get()`. Par exemple, vous pouvez exécuter la commande suivante pour récupérer le premier numéro sur la première page : +Une fois la bibliothèque installée, vous pouvez envoyer des requêtes GET au point de terminaison `Issues` en appelant la fonction `requests.get()`. Par exemple, vous pouvez exécuter la commande suivante pour récupérer le premier numéro sur la première page : ```py import requests @@ -46,7 +46,7 @@ url = "https://api.github.com/repos/huggingface/datasets/issues?page=1&per_page= response = requests.get(url) ``` -L'objet `response` contient de nombreuses informations utiles sur la requête, y compris le code d'état HTTP : +L'objet `response` contient de nombreuses informations utiles sur la requête, y compris le code d'état HTTP : ```py response.status_code @@ -56,7 +56,7 @@ response.status_code 200 ``` -où un statut "200" signifie que la requête a réussi (vous pouvez trouver une liste des codes de statut HTTP possibles [ici](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes)). Ce qui nous intéresse vraiment, cependant, c'est le _payload_, qui peut être consulté dans différents formats comme les octets, les chaînes ou JSON. Comme nous savons que nos problèmes sont au format JSON, examinons la charge utile comme suit : +où un statut `200` signifie que la requête a réussi (vous pouvez trouver une liste des codes de statut HTTP possibles [ici](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes)). Ce qui nous intéresse vraiment, cependant, c'est le _payload_, qui peut être consulté dans différents formats comme les octets, les chaînes ou JSON. Comme nous savons que nos problèmes sont au format JSON, examinons la charge utile comme suit : ```py response.json() @@ -115,11 +115,11 @@ Waouh, ça fait beaucoup d'informations ! Nous pouvons voir des champs utiles co -✏️ **Essayez-le !** Cliquez sur quelques-unes des URL dans la charge utile JSON ci-dessus pour avoir une idée du type d'informations auxquelles chaque problème GitHub est lié. +✏️ **Essayez !** Cliquez sur quelques-unes des URL pour avoir une idée du type d'informations auxquelles chaque problème GitHub est lié. -Comme décrit dans la [documentation] GitHub(https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting), les requêtes non authentifiées sont limitées à 60 requêtes par heure. Bien que vous puissiez augmenter le paramètre de requête `per_page` pour réduire le nombre de requêtes que vous effectuez, vous atteindrez toujours la limite de débit sur tout référentiel contenant plus de quelques milliers de problèmes. Donc, à la place, vous devez suivre les [instructions] de GitHub (https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) sur la création d'un _jeton d'accès personnel_ afin que vous peut augmenter la limite de débit à 5 000 requêtes par heure. Une fois que vous avez votre jeton, vous pouvez l'inclure dans l'en-tête de la requête : +Comme décrit dans la [documentation GitHub](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting), les requêtes non authentifiées sont limitées à 60 requêtes par heure. Bien que vous puissiez augmenter le paramètre de requête `per_page` pour réduire le nombre de requêtes que vous effectuez, vous atteindrez toujours la limite de débit sur tout dépot contenant des milliers de problèmes. Donc, à la place, vous devez suivre les [instructions de GitHub](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) sur la création d'un _jeton d'accès personnel_ afin que vous peut augmenter la limite de débit à 5 000 requêtes par heure. Une fois que vous avez votre *token*, vous pouvez l'inclure dans l'en-tête de la requête : ```py GITHUB_TOKEN = xxx # Copy your GitHub token here @@ -128,11 +128,11 @@ headers = {"Authorization": f"token {GITHUB_TOKEN}"} -⚠️ Ne partagez pas un notebook avec votre `GITHUB_TOKEN` collé dedans. Nous vous recommandons de supprimer la dernière cellule une fois que vous l'avez exécutée pour éviter de divulguer accidentellement ces informations. Mieux encore, stockez le jeton dans un fichier *.env* et utilisez la [bibliothèque `python-dotenv`](https://github.com/theskumar/python-dotenv) pour le charger automatiquement pour vous en tant que variable d'environnement. +⚠️ Ne partagez pas un *notebook* avec votre `GITHUB_TOKEN` collé dedans. Nous vous recommandons de supprimer la dernière cellule une fois que vous l'avez exécutée pour éviter de divulguer accidentellement ces informations. Mieux encore, stockez le jeton dans un fichier *.env* et utilisez la [bibliothèque `python-dotenv`](https://github.com/theskumar/python-dotenv) pour le charger automatiquement pour vous en tant que variable d'environnement. -Maintenant que nous avons notre jeton d'accès, créons une fonction qui peut télécharger tous les problèmes depuis un référentiel GitHub : +Maintenant que nous avons notre jeton d'accès, créons une fonction qui peut télécharger tous les problèmes depuis un référentiel GitHub : ```py import time @@ -178,14 +178,14 @@ def fetch_issues( ) ``` -Désormais, lorsque nous appellerons `fetch_issues()`, tous les problèmes seront téléchargés par lots pour éviter de dépasser la limite de GitHub sur le nombre de requêtes par heure ; le résultat sera stocké dans un fichier _repository_name-issues.jsonl_, où chaque ligne est un objet JSON qui représente un problème. Utilisons cette fonction pour saisir tous les problèmes de 🤗 Datasets : +Désormais, lorsque nous appellerons `fetch_issues()`, tous les problèmes seront téléchargés par batchs pour éviter de dépasser la limite de GitHub sur le nombre de requêtes par heure. Le résultat sera stocké dans un fichier _repository_name-issues.jsonl_, où chaque ligne est un objet JSON qui représente un problème. Utilisons cette fonction pour saisir tous les problèmes de 🤗 *Datasets* : ```py -# Depending on your internet connection, this can take several minutes to run... +# En fonction de votre connexion Internet, l'exécution peut prendre plusieurs minutes... fetch_issues() ``` -Une fois les problèmes téléchargés, nous pouvons les charger localement en utilisant nos nouvelles compétences de [section 2](/course/chaper5/2) : +Une fois les problèmes téléchargés, nous pouvons les charger localement en utilisant nos nouvelles compétences de [section 2](/course/fr/chaper5/2) : ```py issues_dataset = load_dataset("json", data_files="datasets-issues.jsonl", split="train") @@ -199,15 +199,15 @@ Dataset({ }) ``` -Génial, nous avons créé notre premier ensemble de données à partir de rien ! Mais pourquoi y a-t-il plusieurs milliers de problèmes alors que l'[onglet Problèmes](https://github.com/huggingface/datasets/issues) du 🤗 Datasets n'affiche qu'environ 1 000 problèmes au total 🤔 ? Comme décrit dans la [documentation] GitHub(https://docs.github.com/en/rest/reference/issues#list-issues-assigned-to-the-authenticated-user), c'est parce que nous avons téléchargé tous les les demandes d'extraction également : +Génial, nous avons créé notre premier jeu de données à partir de rien ! Mais pourquoi y a-t-il plusieurs milliers de problèmes alors que l'[onglet « Issues »](https://github.com/huggingface/datasets/issues) de la librairie 🤗 *Datasets* n'affiche qu'environ 1 000 problèmes au total 🤔 ? Comme décrit dans la [documentation GitHub](https://docs.github.com/en/rest/reference/issues#list-issues-assigned-to-the-authenticated-user), c'est parce que nous avons téléchargé toutes les *pull requests* également : -> L'API REST v3 de GitHub considère chaque demande d'extraction comme un problème, mais chaque problème n'est pas une demande d'extraction. Pour cette raison, les points de terminaison "Problèmes" peuvent renvoyer à la fois des problèmes et des demandes d'extraction dans la réponse. Vous pouvez identifier les demandes d'extraction par la clé `pull_request`. Sachez que l'identifiant d'une demande d'extraction renvoyée par les points de terminaison "Problèmes" sera un identifiant de problème. +> L'API REST v3 de GitHub considère chaque *pull request* comme un problème, mais chaque problème n'est pas une *pull request*. Pour cette raison, les points de terminaison « Issues » peuvent renvoyer à la fois des problèmes et des *pull requests* dans la réponse. Vous pouvez identifier les *pull requests* par la clé `pull_request`. Sachez que l'identifiant d'une *pull request* renvoyée par les points de terminaison « Issues » sera un identifiant de problème. -Étant donné que le contenu des problèmes et des demandes d'extraction est assez différent, procédons à un prétraitement mineur pour nous permettre de les distinguer. +Étant donné que le contenu des « Issues » et des *pull request* est assez différent, procédons à un prétraitement mineur pour nous permettre de les distinguer. ## Nettoyer les données -L'extrait ci-dessus de la documentation de GitHub nous indique que la colonne "pull_request" peut être utilisée pour différencier les problèmes et les demandes d'extraction. Regardons un échantillon aléatoire pour voir quelle est la différence. Comme nous l'avons fait dans [section 3](/course/chapter5/3), nous allons enchaîner `Dataset.shuffle()` et `Dataset.select()` pour créer un échantillon aléatoire, puis compresser `html_url` et ` pull_request` afin que nous puissions comparer les différentes URL : +L'extrait ci-dessus de la documentation de GitHub nous indique que la colonne `pull_request` peut être utilisée pour différencier les *issues* et les *pull requests*. Regardons un échantillon aléatoire pour voir quelle est la différence. Comme nous l'avons fait dans [section 3](/course/fr/chapter5/3), nous allons enchaîner `Dataset.shuffle()` et `Dataset.select()` pour créer un échantillon aléatoire, puis compresser `html_url` et ` pull_request` afin que nous puissions comparer les différentes URL : ```py sample = issues_dataset.shuffle(seed=666).select(range(3)) @@ -229,7 +229,7 @@ for url, pr in zip(sample["html_url"], sample["pull_request"]): >> Pull request: {'url': 'https://api.github.com/repos/huggingface/datasets/pulls/783', 'html_url': 'https://github.com/huggingface/datasets/pull/783', 'diff_url': 'https://github.com/huggingface/datasets/pull/783.diff', 'patch_url': 'https://github.com/huggingface/datasets/pull/783.patch'} ``` -Ici, nous pouvons voir que chaque demande d'extraction est associée à diverses URL, tandis que les problèmes ordinaires ont une entrée "Aucun". Nous pouvons utiliser cette distinction pour créer une nouvelle colonne `is_pull_request` qui vérifie si le champ `pull_request` est `None` ou non : +Ici, nous pouvons voir que chaque *pull request* est associée à diverses URL, tandis que les problèmes ordinaires ont une entrée `None`. Nous pouvons utiliser cette distinction pour créer une nouvelle colonne `is_pull_request` qui vérifie si le champ `pull_request` est `None` ou non : ```py issues_dataset = issues_dataset.map( @@ -239,23 +239,23 @@ issues_dataset = issues_dataset.map( -✏️ **Essayez-le !** Calculez le temps moyen nécessaire pour résoudre les problèmes dans 🤗 Datasets. Vous pouvez trouver la fonction `Dataset.filter()` utile pour filtrer les demandes d'extraction et les problèmes ouverts, et vous pouvez utiliser la fonction `Dataset.set_format()` pour convertir l'ensemble de données en un `DataFrame` afin que vous puissiez facilement manipuler les horodatages `created_at` et `closed_at`. Pour les points bonus, calculez le temps moyen nécessaire pour fermer les demandes d'extraction. +✏️ **Essayez !** Calculez le temps moyen nécessaire pour résoudre les problèmes dans 🤗 *Datasets*. Vous pouvez trouver la fonction `Dataset.filter()` utile pour filtrer les demandes d'extraction et les problèmes ouverts. Vous pouvez utiliser la fonction `Dataset.set_format()` pour convertir le jeu de données en un `DataFrame` afin que vous puissiez facilement manipuler les horodatages `created_at` et `closed_at`. Pour les points bonus, calculez le temps moyen nécessaire pour fermer les *pull_requests*. -Bien que nous puissions continuer à nettoyer davantage l'ensemble de données en supprimant ou en renommant certaines colonnes, il est généralement recommandé de conserver l'ensemble de données aussi "brut" que possible à ce stade afin qu'il puisse être facilement utilisé dans plusieurs applications. +Bien que nous puissions continuer à nettoyer davantage le jeu de données en supprimant ou en renommant certaines colonnes, il est généralement recommandé de le conserver aussi brut que possible à ce stade afin qu'il puisse être facilement utilisé dans plusieurs applications. -Avant de pousser notre ensemble de données vers le Hugging Face Hub, traitons d'une chose qui lui manque : les commentaires associés à chaque problème et pull request. Nous les ajouterons ensuite avec - vous l'avez deviné - l'API GitHub REST ! +Avant de pousser notre jeu de données vers le *Hub* d’Hugging Face, traitons une chose manquant : les commentaires associés à chaque problème et *pull requests*. Nous les ajouterons ensuite avec l'API GitHub REST ! ## Enrichir le jeu de données -Comme le montre la capture d'écran suivante, les commentaires associés à un problème ou à une demande d'extraction fournissent une riche source d'informations, en particulier si nous souhaitons créer un moteur de recherche pour répondre aux requêtes des utilisateurs sur la bibliothèque. +Comme le montre la capture d'écran suivante, les commentaires associés à un problème ou à une *pull request* fournissent une riche source d'informations, en particulier si nous souhaitons créer un moteur de recherche pour répondre aux requêtes des utilisateurs sur la bibliothèque.
-Commentaires associés à un problème concernant 🤗 Datasets. +Comments associated with an issue about 🤗 Datasets.
-L'API REST GitHub fournit un point de terminaison [`Comments`](https://docs.github.com/en/rest/reference/issues#list-issue-comments) qui renvoie tous les commentaires associés à un numéro de problème. Testons le point de terminaison pour voir ce qu'il renvoie : +L'API REST GitHub fournit un point de terminaison [`Comments`](https://docs.github.com/en/rest/reference/issues#list-issue-comments) qui renvoie tous les commentaires associés à un numéro de problème. Testons le point de terminaison pour voir ce qu'il renvoie : ```py issue_number = 2792 @@ -295,7 +295,7 @@ response.json() 'performed_via_github_app': None}] ``` -Nous pouvons voir que le commentaire est stocké dans le champ `body`, écrivons donc une fonction simple qui renvoie tous les commentaires associés à un problème en sélectionnant le contenu `body` pour chaque élément dans `response.json()` : +Nous pouvons voir que le commentaire est stocké dans le champ `body`. Ecrivons donc une fonction simple qui renvoie tous les commentaires associés à un problème en sélectionnant le contenu `body` pour chaque élément dans `response.json()` : ```py def get_comments(issue_number): @@ -312,7 +312,7 @@ get_comments(2792) ["@albertvillanova my tests are failing here:\r\n```\r\ndataset_name = 'gooaq'\r\n\r\n def test_load_dataset(self, dataset_name):\r\n configs = self.dataset_tester.load_all_configs(dataset_name, is_local=True)[:1]\r\n> self.dataset_tester.check_load_dataset(dataset_name, configs, is_local=True, use_local_dummy_data=True)\r\n\r\ntests/test_dataset_common.py:234: \r\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \r\ntests/test_dataset_common.py:187: in check_load_dataset\r\n self.parent.assertTrue(len(dataset[split]) > 0)\r\nE AssertionError: False is not true\r\n```\r\nWhen I try loading dataset on local machine it works fine. Any suggestions on how can I avoid this error?"] ``` -Cela a l'air bien, alors utilisons `Dataset.map()` pour ajouter une nouvelle colonne `commentaires` à chaque problème de notre ensemble de données : +Cela a l'air bien. Utilisons `Dataset.map()` pour ajouter une nouvelle colonne `comments` à chaque problème de notre jeu de données : ```py # Selon votre connexion internet, cela peut prendre quelques minutes... @@ -321,17 +321,17 @@ issues_with_comments_dataset = issues_dataset.map( ) ``` -La dernière étape consiste à enregistrer l'ensemble de données augmentées avec nos données brutes afin que nous puissions les pousser toutes les deux vers le Hub : +La dernière étape consiste à enregistrer le jeu de données augmentées avec nos données brutes afin que nous puissions les pousser tous les deux vers le *Hub* : ```py issues_with_comments_dataset.to_json("issues-datasets-with-comments.jsonl") ``` -## Téléchargement de l'ensemble de données sur le Hugging Face Hub +## Téléchargement du jeu de données sur le *Hub* d’Hugging Face -Maintenant que nous avons notre jeu de données augmenté, il est temps de le pousser vers le Hub afin que nous puissions le partager avec la communauté ! Pour télécharger l'ensemble de données, nous utiliserons la [bibliothèque Hub 🤗](https://github.com/huggingface/huggingface_hub), qui nous permet d'interagir avec le hub Hugging Face via une API Python. 🤗 Hub est préinstallé avec 🤗 Transformers, nous pouvons donc l'utiliser directement. Par exemple, nous pouvons utiliser la fonction `list_datasets()` pour obtenir des informations sur tous les ensembles de données publics actuellement hébergés sur le Hub : +Maintenant que nous avons notre jeu de données augmenté, il est temps de le pousser vers le *Hub* afin que nous puissions le partager avec la communauté ! Pour télécharger le jeu de données, nous utilisons la [bibliothèque 🤗 *Hub*](https://github.com/huggingface/huggingface_hub), qui nous permet d'interagir avec le *Hub* d’Hugging Face via une API Python. 🤗 *Hub* est préinstallé avec 🤗 *Transformers*, nous pouvons donc l'utiliser directement. Par exemple, nous pouvons utiliser la fonction `list_datasets()` pour obtenir des informations sur tous les ensembles de données publics actuellement hébergés sur le *Hub*: ```py from huggingface_hub import list_datasets @@ -346,9 +346,9 @@ Number of datasets on Hub: 1487 Dataset Name: acronym_identification, Tags: ['annotations_creators:expert-generated', 'language_creators:found', 'languages:en', 'licenses:mit', 'multilinguality:monolingual', 'size_categories:10K -✏️ **Essayez-le !** Utilisez votre nom d'utilisateur et votre mot de passe Hugging Face Hub pour obtenir un jeton et créer un référentiel vide appelé "github-issues". N'oubliez pas de **n'enregistrez jamais vos informations d'identification** dans Colab ou tout autre référentiel, car ces informations peuvent être exploitées par de mauvais acteurs. +✏️ **Essayez !** Utilisez votre nom d'utilisateur et votre mot de passe Hugging Face pour obtenir un jeton et créer un dépôt vide appelé `github-issues`. N'oubliez pas de **n'enregistrez jamais vos informations d'identification** dans Colab ou tout autre référentiel car ces informations peuvent être exploitées par de mauvais individus. -Ensuite, clonons le référentiel du Hub sur notre machine locale et copions-y notre fichier d'ensemble de données. 🤗 Hub fournit une classe `Repository` pratique qui encapsule de nombreuses commandes Git courantes, donc pour cloner le référentiel distant, nous devons simplement fournir l'URL et le chemin local vers lesquels nous souhaitons cloner : +Ensuite, clonons le dépôt du Hub sur notre machine locale et copions-y notre fichier jeu de données. 🤗 *Hub* fournit une classe `Repository` pratique qui encapsule de nombreuses commandes Git courantes. Donc pour cloner le dépôt distant, nous devons simplement fournir l'URL et le chemin local vers lesquels nous souhaitons cloner : ```py from huggingface_hub import Repository @@ -392,13 +392,13 @@ repo = Repository(local_dir="github-issues", clone_from=repo_url) !cp datasets-issues-with-comments.jsonl github-issues/ ``` -Par défaut, diverses extensions de fichiers (telles que *.bin*, *.gz* et *.zip*) sont suivies avec Git LFS afin que les fichiers volumineux puissent être versionnés dans le même workflow Git. Vous pouvez trouver une liste des extensions de fichiers suivis dans le fichier *.gitattributes* du référentiel. Pour inclure le format JSON Lines dans la liste, nous pouvons exécuter la commande suivante : +Par défaut, diverses extensions de fichiers (telles que *.bin*, *.gz* et *.zip*) sont suivies avec Git LFS afin que les fichiers volumineux puissent être versionnés dans le même workflow Git. Vous pouvez trouver une liste des extensions de fichiers suivis dans le fichier *.gitattributes* du référentiel. Pour inclure le format JSON Lines dans la liste, nous pouvons exécuter la commande suivante : ```py repo.lfs_track("*.jsonl") ``` -Ensuite, nous pouvons utiliser `Repository.push_to_hub()` pour pousser l'ensemble de données vers le Hub : +Ensuite, nous pouvons utiliser `Repository.push_to_hub()` pour pousser le jeu de données vers le *Hub* : ```py repo.push_to_hub() @@ -407,10 +407,10 @@ repo.push_to_hub() Si nous naviguons vers l'URL contenue dans `repo_url`, nous devrions maintenant voir que notre fichier de jeu de données a été téléchargé.
-Notre référentiel d'ensembles de données sur le Hugging Face Hub. +Our dataset repository on the Hugging Face Hub.
-À partir de là, n'importe qui peut télécharger l'ensemble de données en fournissant simplement `load_dataset()` avec l'ID du référentiel comme argument `path` : +À partir de là, n'importe qui peut télécharger le jeu de données en fournissant simplement `load_dataset()` avec l'ID du référentiel comme argument `path` : ```py remote_dataset = load_dataset("lewtun/github-issues", split="train") @@ -424,46 +424,44 @@ Dataset({ }) ``` -Cool, nous avons poussé notre jeu de données vers le Hub et il est disponible pour que d'autres puissent l'utiliser ! Il ne reste plus qu'une chose importante à faire : ajouter une _carte de jeu de données_ qui explique comment le corpus a été créé et fournit d'autres informations utiles à la communauté. +Cool, nous avons poussé notre jeu de données vers le *Hub* et il est disponible pour que d'autres puissent l'utiliser ! Il ne reste plus qu'une chose importante à faire : ajouter une _carte de jeu de données_ qui explique comment le corpus a été créé et fournit d'autres informations utiles à la communauté. -💡 Vous pouvez également télécharger un ensemble de données sur le Hugging Face Hub directement depuis le terminal en utilisant `huggingface-cli` et un peu de magie Git. Consultez le [🤗 Datasets guide](https://huggingface.co/docs/datasets/share.html#add-a-community-dataset) pour savoir comment procéder. +💡 Vous pouvez également télécharger un jeu de données sur le *Hub* directement depuis le terminal en utilisant `huggingface-cli` et un peu de magie Git. Consultez le [guide de 🤗 *Datasets*](https://huggingface.co/docs/datasets/share.html#add-a-community-dataset) pour savoir comment procéder. -## Création d'une fiche de jeu de données +## Création d'une carte pour un jeu de données -Des ensembles de données bien documentés sont plus susceptibles d'être utiles aux autres (y compris à votre futur moi !), car ils fournissent le contexte permettant aux utilisateurs de décider si l'ensemble de données est pertinent pour leur tâche et d'évaluer les biais potentiels ou les risques associés à l'utilisation l'ensemble de données. +Des jeux de données bien documentés sont plus susceptibles d'être utiles aux autres (y compris à vous-même) car ils fournissent le contexte permettant aux utilisateurs de décider si le jeu de données est pertinent pour leur tâche et d'évaluer les biais potentiels ou les risques associés à l'utilisation du jeu de données. -Sur le Hugging Face Hub, ces informations sont stockées dans le fichier *README.md* de chaque référentiel d'ensembles de données. Il y a deux étapes principales que vous devez suivre avant de créer ce fichier : +Sur le *Hub*, ces informations sont stockées dans le fichier *README.md* de chaque dépôt de jeux de données. Il y a deux étapes principales que vous devez suivre avant de créer ce fichier : -1. Utilisez l'[application `datasets-tagging`](https://huggingface.co/datasets/tagging/) pour créer des balises de métadonnées au format YAML. Ces balises sont utilisées pour une variété de fonctionnalités de recherche sur le Hugging Face Hub et garantissent que votre ensemble de données peut être facilement trouvé par les membres de la communauté. Puisque nous avons créé un ensemble de données personnalisé ici, vous devrez cloner le référentiel `datasets-tagging` et exécuter l'application localement. Voici à quoi ressemble l'interface : +1. Utilisez l'[application `datasets-tagging`](https://huggingface.co/datasets/tagging/) pour créer des balises de métadonnées au format YAML. Ces balises sont utilisées pour une variété de fonctionnalités de recherche sur le *Hub* d’Hugging Face et garantissent que votre jeu de données peut être facilement trouvé par les membres de la communauté. Puisque nous avons créé un jeu de données personnalisé ici, vous devrez cloner le référentiel `datasets-tagging` et exécuter l'application localement. Voici à quoi ressemble l'interface :
-L'interface `datasets-tagging`. +The `datasets-tagging` interface.
-2. Lisez le [🤗 Datasets guide](https://github.com/huggingface/datasets/blob/master/templates/README_guide.md) sur la création de cartes d'ensemble de données informatives et utilisez-le comme modèle. +2. Lisez le [guide de 🤗 *Datasets*](https://github.com/huggingface/datasets/blob/master/templates/README_guide.md) sur la création des cartes informatives des jeux de données et utilisez-le comme modèle. + +Vous pouvez créer le fichier *README.md* directement sur le *Hub* et vous pouvez trouver un modèle de carte dans le dépot `lewtun/github-issues`. Une capture d'écran de la carte remplie est illustrée ci-dessous. -Vous pouvez créer le fichier *README.md* directement sur le Hub, et vous pouvez trouver un modèle de carte d'ensemble de données dans le référentiel d'ensemble de données `lewtun/github-issues`. Une capture d'écran de la carte de jeu de données remplie est illustrée ci-dessous.
-Une carte de jeu de données. +A dataset card.
-* Fichier README.md* pour votre ensemble de données de problèmes GitHub. - +✏️ **Essayez !** Utilisez l'application `dataset-tagging` et [le guide de 🤗 *Datasets*](https://github.com/huggingface/datasets/blob/master/templates/README_guide.md) pour compléter le fichier *README.md* de votre jeu de données de problèmes GitHub. -C'est ça! Nous avons vu dans cette section que la création d'un bon ensemble de données peut être assez complexe, mais heureusement, le télécharger et le partager avec la communauté ne l'est pas. Dans la section suivante, nous utiliserons notre nouvel ensemble de données pour créer un moteur de recherche sémantique avec 🤗 Deatasets qui peut faire correspondre les questions aux problèmes et commentaires les plus pertinents. +C’ets tout ! Nous avons vu dans cette section que la création d'un bon jeu de données peut être assez complexe, mais heureusement, le télécharger et le partager avec la communauté ne l'est pas. Dans la section suivante, nous utiliserons notre nouveau jeu de données pour créer un moteur de recherche sémantique avec 🤗 *Datasets* qui peut faire correspondre les questions aux problèmes et commentaires les plus pertinents. -✏️ **Essayez-le !** Suivez les étapes que nous avons suivies dans cette section pour créer un ensemble de données de problèmes GitHub pour votre bibliothèque open source préférée (choisissez autre chose que 🤗 Datasets, bien sûr !). Pour obtenir des points bonus, ajustez un classificateur multilabel pour prédire les balises présentes dans le champ "labels". +✏️ **Essayez !** Suivez les étapes que nous avons suivies dans cette section pour créer un jeu de données de problèmes GitHub pour votre bibliothèque open source préférée (choisissez autre chose que 🤗 *Datasets*, bien sûr !). Pour obtenir des points bonus, *finetunez* un classifieur multilabel pour prédire les balises présentes dans le champ `labels`. - - diff --git a/chapters/fr/chapter5/6.mdx b/chapters/fr/chapter5/6.mdx index fb055ccb8..68cf7373e 100644 --- a/chapters/fr/chapter5/6.mdx +++ b/chapters/fr/chapter5/6.mdx @@ -22,15 +22,15 @@ {/if} -Dans [section 5](/course/chapter5/5), nous avons créé un ensemble de données de problèmes et de commentaires GitHub à partir du référentiel 🤗 Datasets. Dans cette section, nous utiliserons ces informations pour créer un moteur de recherche qui peut nous aider à trouver des réponses à nos questions les plus urgentes sur la bibliothèque ! +Dans [section 5](/course/fr/chapter5/5), nous avons créé un jeu de données de problèmes et de commentaires GitHub à partir du dépôt 🤗 *Datasets*. Dans cette section, nous utilisons ces informations pour créer un moteur de recherche qui peut nous aider à trouver des réponses à nos questions les plus urgentes sur la bibliothèque ! -## Utilisation des représentations vectorielles continues pour la recherche sémantique +## Utilisation des enchâssements pour la recherche sémantique -Comme nous l'avons vu dans le [Chapitre 1](/course/chapter1), les modèles de langage basés sur Transformer représentent chaque jeton dans une étendue de texte sous la forme d'un _vecteur d'intégration_. Il s'avère que l'on peut "regrouper" les incorporations individuelles pour créer une représentation vectorielle pour des phrases entières, des paragraphes ou (dans certains cas) des documents. Ces intégrations peuvent ensuite être utilisées pour trouver des documents similaires dans le corpus en calculant la similarité du produit scalaire (ou une autre métrique de similarité) entre chaque intégration et en renvoyant les documents avec le plus grand chevauchement. +Comme nous l'avons vu dans le [Chapitre 1](/course/fr/chapter1), les modèles de langage basés sur les *transformers* représentent chaque *token* dans une étendue de texte sous la forme d'un _enchâssement_. Il s'avère que l'on peut regrouper les enchâssements individuels pour créer une représentation vectorielle pour des phrases entières, des paragraphes ou (dans certains cas) des documents. Ces enchâssements peuvent ensuite être utilisés pour trouver des documents similaires dans le corpus en calculant la similarité du produit scalaire (ou une autre métrique de similarité) entre chaque enchâssement et en renvoyant les documents avec le plus grand chevauchement. -Dans cette section, nous utiliserons les incorporations pour développer un moteur de recherche sémantique. Ces moteurs de recherche offrent plusieurs avantages par rapport aux approches conventionnelles basées sur la correspondance des mots-clés dans une requête avec les documents. +Dans cette section, nous utilisons les enchâssements pour développer un moteur de recherche sémantique. Ces moteurs de recherche offrent plusieurs avantages par rapport aux approches conventionnelles basées sur la correspondance des mots-clés dans une requête avec les documents.
Recherche sémantique. @@ -39,7 +39,7 @@ Dans cette section, nous utiliserons les incorporations pour développer un mote ## Chargement et préparation du jeu de données -La première chose que nous devons faire est de télécharger notre ensemble de données de problèmes GitHub, alors utilisons la bibliothèque 🤗 Hub pour résoudre l'URL où notre fichier est stocké sur le Hugging Face Hub : +La première chose que nous devons faire est de télécharger notre jeu de données de problèmes GitHub. Utilisons la bibliothèque 🤗 *Hub* pour résoudre l'URL où notre fichier est stocké sur le *Hib* d’Hugging Face : ```py from huggingface_hub import hf_hub_url @@ -51,7 +51,7 @@ data_files = hf_hub_url( ) ``` -Avec l'URL stockée dans `data_files`, nous pouvons ensuite charger le jeu de données distant en utilisant la méthode introduite dans [section 2](/course/chapter5/2) : +Avec l'URL stocké dans `data_files`, nous pouvons ensuite charger le jeu de données distant en utilisant la méthode introduite dans [section 2](/course/fr/chapter5/2) : ```py from datasets import load_dataset @@ -67,7 +67,7 @@ Dataset({ }) ``` -Ici, nous avons spécifié la division `train` par défaut dans `load_dataset()`, de sorte qu'elle renvoie un `Dataset` au lieu d'un `DatasetDict`. La première chose à faire est de filtrer les demandes d'extraction, car celles-ci ont tendance à être rarement utilisées pour répondre aux requêtes des utilisateurs et introduiront du bruit dans notre moteur de recherche. Comme cela devrait être familier maintenant, nous pouvons utiliser la fonction `Dataset.filter()` pour exclure ces lignes de notre ensemble de données. Pendant que nous y sommes, filtrons également les lignes sans commentaires, car celles-ci ne fournissent aucune réponse aux requêtes des utilisateurs : +Ici, nous avons spécifié l’échantillon `train` par défaut dans `load_dataset()`, de sorte que cela renvoie un `Dataset` au lieu d'un `DatasetDict`. La première chose à faire est de filtrer les *pull requests* car celles-ci ont tendance à être rarement utilisées pour répondre aux requêtes des utilisateurs et introduiront du bruit dans notre moteur de recherche. Comme cela devrait être familier maintenant, nous pouvons utiliser la fonction `Dataset.filter()` pour exclure ces lignes de notre jeu de données. Pendant que nous y sommes, filtrons également les lignes sans commentaires, car celles-ci ne fournissent aucune réponse aux requêtes des utilisateurs : ```py issues_dataset = issues_dataset.filter( @@ -83,7 +83,7 @@ Dataset({ }) ``` -Nous pouvons voir qu'il y a beaucoup de colonnes dans notre ensemble de données, dont la plupart n'ont pas besoin de construire notre moteur de recherche. Du point de vue de la recherche, les colonnes les plus informatives sont `title`, `body` et `comments`, tandis que `html_url` nous fournit un lien vers le problème source. Utilisons la fonction `Dataset.remove_columns()` pour supprimer le reste : +Nous pouvons voir qu'il y a beaucoup de colonnes dans notre jeu de données, dont la plupart n'ont pas besoin de construire notre moteur de recherche. Du point de vue de la recherche, les colonnes les plus informatives sont `title`, `body` et `comments`, tandis que `html_url` nous fournit un lien vers le problème source. Utilisons la fonction `Dataset.remove_columns()` pour supprimer le reste : ```py columns = issues_dataset.column_names @@ -100,14 +100,14 @@ Dataset({ }) ``` -Pour créer nos intégrations, nous ajouterons à chaque commentaire le titre et le corps du problème, car ces champs contiennent souvent des informations contextuelles utiles. Étant donné que notre colonne `comments` est actuellement une liste de commentaires pour chaque problème, nous devons "éclater" la colonne afin que chaque ligne se compose d'un tuple `(html_url, title, body, comment)`. Dans Pandas, nous pouvons le faire avec la fonction [`DataFrame.explode()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.explode.html), qui crée une nouvelle ligne pour chaque élément dans une colonne de type liste, tout en répliquant toutes les autres valeurs de colonne. Pour voir cela en action, passons d'abord au format "DataFrame" de Pandas : +Pour créer nos enchâssements, nous ajoutons à chaque commentaire le titre et le corps du problème, car ces champs contiennent des informations contextuelles utiles. Étant donné que notre colonne `comments` est actuellement une liste de commentaires pour chaque problème, nous devons « éclater » la colonne afin que chaque ligne se compose d'un *tuple* `(html_url, title, body, comment)`. Dans Pandas, nous pouvons le faire avec la fonction [`DataFrame.explode()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.explode.html), qui crée une nouvelle ligne pour chaque élément dans une colonne de type liste, tout en répliquant toutes les autres valeurs de colonne. Pour voir cela en action, passons d'abord au format `DataFrame` de Pandas : ```py issues_dataset.set_format("pandas") df = issues_dataset[:] ``` -Si nous inspectons la première ligne de ce `DataFrame`, nous pouvons voir qu'il y a quatre commentaires associés à ce problème : +Si nous inspectons la première ligne de ce `DataFrame`, nous pouvons voir qu'il y a quatre commentaires associés à ce problème : ```py df["comments"][0].tolist() @@ -169,7 +169,7 @@ comments_df.head(4) -Génial, nous pouvons voir que les lignes ont été répliquées, avec la colonne "commentaires" contenant les commentaires individuels ! Maintenant que nous en avons fini avec Pandas, nous pouvons rapidement revenir à un `Dataset` en chargeant le `DataFrame` en mémoire : +Génial, nous pouvons voir que les lignes ont été répliquées, avec la colonne `comments` contenant les commentaires individuels ! Maintenant que nous en avons fini avec Pandas, nous pouvons rapidement revenir à un `Dataset` en chargeant le `DataFrame` en mémoire : ```py from datasets import Dataset @@ -185,16 +185,16 @@ Dataset({ }) ``` -D'accord, cela nous a donné quelques milliers de commentaires avec lesquels travailler ! +D'accord, cela nous a donné quelques milliers de commentaires avec lesquels travailler ! -✏️ **Essayez-le !** Voyez si vous pouvez utiliser `Dataset.map()` pour exploser la colonne `comments` de `issues_dataset` _sans_ recourir à l'utilisation de Pandas. C'est un peu délicat; vous pourriez trouver la section ["Batch mapping"](https://huggingface.co/docs/datasets/v1.12.1/about_map_batch.html?batch-mapping#batch-mapping) de la documentation 🤗 Datasets utile pour cette tâche. +✏️ **Essayez !** Voyez si vous pouvez utiliser `Dataset.map()` pour exploser la colonne `comments` de `issues_dataset` _sans_ recourir à l'utilisation de Pandas. C'est un peu délicat. La section [« Batch mapping »](https://huggingface.co/docs/datasets/v1.12.1/about_map_batch.html?batch-mapping#batch-mapping) de la documentation 🤗 *Datasets* peut être utile pour cette tâche. -Maintenant que nous avons un commentaire par ligne, créons une nouvelle colonne `comments_length` contenant le nombre de mots par commentaire : +Maintenant que nous avons un commentaire par ligne, créons une nouvelle colonne `comments_length` contenant le nombre de mots par commentaire : ```py comments_dataset = comments_dataset.map( @@ -202,7 +202,7 @@ comments_dataset = comments_dataset.map( ) ``` -Nous pouvons utiliser cette nouvelle colonne pour filtrer les commentaires courts, qui incluent généralement des éléments tels que "cc @lewtun" ou "Merci !" qui ne sont pas pertinents pour notre moteur de recherche. Il n'y a pas de nombre précis à sélectionner pour le filtre, mais environ 15 mots semblent être un bon début : +Nous pouvons utiliser cette nouvelle colonne pour filtrer les commentaires courts incluant généralement des éléments tels que « cc @lewtun » ou « Merci ! » qui ne sont pas pertinents pour notre moteur de recherche. Il n'y a pas de nombre précis à sélectionner pour le filtre mais 15 mots semblent être un bon début : ```py comments_dataset = comments_dataset.filter(lambda x: x["comment_length"] > 15) @@ -216,7 +216,7 @@ Dataset({ }) ``` -Après avoir un peu nettoyé notre ensemble de données, concaténons le titre, la description et les commentaires du problème dans une nouvelle colonne "texte". Comme d'habitude, nous allons écrire une fonction simple que nous pouvons passer à `Dataset.map()` : +Après avoir un peu nettoyé notre jeu de données, concaténons le titre, la description et les commentaires du problème dans une nouvelle colonne `text`. Comme d'habitude, nous allons écrire une fonction simple que nous pouvons passer à `Dataset.map()` : ```py def concatenate_text(examples): @@ -232,11 +232,11 @@ def concatenate_text(examples): comments_dataset = comments_dataset.map(concatenate_text) ``` -Nous sommes enfin prêts à créer des embeddings ! Nous allons jeter un coup d'oeil. +Nous sommes enfin prêts à créer des enchâssements ! Jetons un coup d'œil. -## Création d'incorporations de texte +## Création d’enchâssements pour les textes -Nous avons vu dans [Chapitre 2](/course/chapter2) que nous pouvons obtenir des incorporations de jetons en utilisant la classe `AutoModel`. Tout ce que nous avons à faire est de choisir un point de contrôle approprié à partir duquel charger le modèle. Heureusement, il existe une bibliothèque appelée `sentence-transformers` dédiée à la création d'incorporations. Comme décrit dans la [documentation] de la bibliothèque (https://www.sbert.net/examples/applications/semantic-search/README.html#symmetric-vs-asymmetric-semantic-search), notre cas d'utilisation est un exemple de _asymmetric recherche sémantique_ car nous avons une requête courte dont nous aimerions trouver la réponse dans un document plus long, comme un commentaire sur un problème. Le [tableau de présentation des modèles] (https://www.sbert.net/docs/pretrained_models.html#model-overview) pratique de la documentation indique que le point de contrôle `multi-qa-mpnet-base-dot-v1` a le meilleures performances pour la recherche sémantique, nous l'utiliserons donc pour notre application. Nous allons également charger le tokenizer en utilisant le même point de contrôle : +Nous avons vu dans [Chapitre 2](/course/fr/chapter2) que nous pouvons obtenir des enchâssements de *tokens* en utilisant la classe `AutoModel`. Tout ce que nous avons à faire est de choisir un *checkpoint* approprié à partir duquel charger le modèle. Heureusement, il existe une bibliothèque appelée `sentence-transformers` dédiée à la création d’enchâssements. Comme décrit dans la [documentation de la bibliothèque](https://www.sbert.net/examples/applications/semantic-search/README.html#symmetric-vs-asymmetric-semantic-search), notre cas d'utilisation est un exemple de _recherche sémantique asymétrique_. En effet, nous avons une requête courte dont nous aimerions trouver la réponse dans un document plus long, par exemple un commentaire à un problème. Le [tableau de présentation des modèles](https://www.sbert.net/docs/pretrained_models.html#model-overview) de la documentation indique que le *checkpoint* `multi-qa-mpnet-base-dot-v1` a les meilleures performances pour la recherche sémantique. Utilisons donc le pour notre application. Nous allons également charger le *tokenizer* en utilisant le même *checkpoint* : {#if fw === 'pt'} @@ -248,7 +248,7 @@ tokenizer = AutoTokenizer.from_pretrained(model_ckpt) model = AutoModel.from_pretrained(model_ckpt) ``` -Pour accélérer le processus d'intégration, il est utile de placer le modèle et les entrées sur un périphérique GPU, alors faisons-le maintenant : +Pour accélérer le processus, il est utile de placer le modèle et les entrées sur un périphérique GPU, alors faisons-le maintenant : ```py import torch @@ -267,18 +267,18 @@ tokenizer = AutoTokenizer.from_pretrained(model_ckpt) model = TFAutoModel.from_pretrained(model_ckpt, from_pt=True) ``` -Notez que nous avons défini `from_pt=True` comme argument de la méthode `from_pretrained()`. C'est parce que le point de contrôle `multi-qa-mpnet-base-dot-v1` n'a que des poids PyTorch, donc définir `from_pt=True` les convertira automatiquement au format TensorFlow pour nous. Comme vous pouvez le voir, il est très simple de passer d'un framework à l'autre dans 🤗 Transformers ! +Notez que nous avons défini `from_pt=True` comme argument de la méthode `from_pretrained()`. C'est parce que le point de contrôle `multi-qa-mpnet-base-dot-v1` n'a que des poids PyTorch. Donc définir `from_pt=True` converti automatiquement au format TensorFlow pour nous. Comme vous pouvez le voir, il est très simple de passer d'un *framework* à l'autre dans 🤗 *Transformers* ! {/if} -Comme nous l'avons mentionné précédemment, nous aimerions représenter chaque entrée dans notre corpus de problèmes GitHub comme un vecteur unique, nous devons donc "regrouper" ou faire la moyenne de nos incorporations de jetons d'une manière ou d'une autre. Une approche populaire consiste à effectuer un * regroupement CLS * sur les sorties de notre modèle, où nous collectons simplement le dernier état caché pour le jeton spécial `[CLS]`. La fonction suivante fait l'affaire pour nous : +Comme nous l'avons mentionné précédemment, nous aimerions représenter chaque entrée dans notre corpus de problèmes GitHub comme un vecteur unique. Nous devons donc regrouper ou faire la moyenne de nos enchâssements de *tokens* d'une manière ou d'une autre. Une approche populaire consiste à effectuer un *regroupement CLS* sur les sorties de notre modèle, où nous collectons simplement le dernier état caché pour le *token* spécial `[CLS]`. La fonction suivante fait ça pour nous : ```py def cls_pooling(model_output): return model_output.last_hidden_state[:, 0] ``` -Ensuite, nous allons créer une fonction d'assistance qui va tokeniser une liste de documents, placer les tenseurs sur le GPU, les alimenter au modèle et enfin appliquer le regroupement CLS aux sorties : +Ensuite, nous allons créer une fonction utile qui va tokeniser une liste de documents, placer les tenseurs dans le GPU, les donner au modèle et enfin appliquer le regroupement CLS aux sorties : {#if fw === 'pt'} @@ -292,7 +292,7 @@ def get_embeddings(text_list): return cls_pooling(model_output) ``` -Nous pouvons tester le fonctionnement de la fonction en lui fournissant la première entrée de texte dans notre corpus et en inspectant la forme de sortie : +Nous pouvons tester le fonctionnement de la fonction en lui donnant la première entrée textuelle de notre corpus et en inspectant la forme de sortie : ```py embedding = get_embeddings(comments_dataset["text"][0]) @@ -303,7 +303,7 @@ embedding.shape torch.Size([1, 768]) ``` -Super, nous avons converti la première entrée de notre corpus en un vecteur à 768 dimensions ! Nous pouvons utiliser `Dataset.map()` pour appliquer notre fonction `get_embeddings()` à chaque ligne de notre corpus, créons donc une nouvelle colonne `embeddings` comme suit : +Super ! Nous avons converti la première entrée de notre corpus en un vecteur à 768 dimensions. Nous pouvons utiliser `Dataset.map()` pour appliquer notre fonction `get_embeddings()` à chaque ligne de notre corpus. Créons donc une nouvelle colonne `embeddings` comme suit : ```py embeddings_dataset = comments_dataset.map( @@ -323,7 +323,7 @@ def get_embeddings(text_list): return cls_pooling(model_output) ``` -Nous pouvons tester le fonctionnement de la fonction en lui fournissant la première entrée de texte dans notre corpus et en inspectant la forme de sortie : +Nous pouvons tester le fonctionnement de la fonction en lui donnant la première entrée textuelle de notre corpus et en inspectant la forme de sortie : ```py embedding = get_embeddings(comments_dataset["text"][0]) @@ -334,7 +334,7 @@ embedding.shape TensorShape([1, 768]) ``` -Super, nous avons converti la première entrée de notre corpus en un vecteur à 768 dimensions ! Nous pouvons utiliser `Dataset.map()` pour appliquer notre fonction `get_embeddings()` à chaque ligne de notre corpus, créons donc une nouvelle colonne `embeddings` comme suit : +Super ! Nous avons converti la première entrée de notre corpus en un vecteur à 768 dimensions. Nous pouvons utiliser `Dataset.map()` pour appliquer notre fonction `get_embeddings()` à chaque ligne de notre corpus. Créons donc une nouvelle colonne `embeddings` comme suit : ```py embeddings_dataset = comments_dataset.map( @@ -345,19 +345,19 @@ embeddings_dataset = comments_dataset.map( {/if} -Notez que nous avons converti les intégrations en tableaux NumPy -- c'est parce que 🤗 Datasets nécessite ce format lorsque nous essayons de les indexer avec FAISS, ce que nous ferons ensuite. +Notez que nous avons converti les enchâssements en tableaux NumPy. C'est parce que 🤗 *Datasets* nécessite ce format lorsque nous essayons de les indexer avec FAISS, ce que nous ferons ensuite. ## Utilisation de FAISS pour une recherche de similarité efficace -Maintenant que nous avons un ensemble de données d'incorporations, nous avons besoin d'un moyen de les rechercher. Pour ce faire, nous utiliserons une structure de données spéciale dans 🤗 Datasets appelée _FAISS index_. [FAISS](https://faiss.ai/) (abréviation de Facebook AI Similarity Search) est une bibliothèque qui fournit des algorithmes efficaces pour rechercher et regrouper rapidement des vecteurs d'intégration. +Maintenant que nous avons un jeu de données d'incorporations, nous avons besoin d'un moyen de les rechercher. Pour ce faire, nous utiliserons une structure de données spéciale dans 🤗 *Datasets* appelée _FAISS index_. [FAISS](https://faiss.ai/) (abréviation de Facebook AI Similarity Search) est une bibliothèque qui fournit des algorithmes efficaces pour rechercher et regrouper rapidement des vecteurs d'intégration. -L'idée de base derrière FAISS est de créer une structure de données spéciale appelée un _index_ qui permet de trouver quels plongements sont similaires à un plongement d'entrée. Créer un index FAISS dans 🤗 Datasets est simple -- nous utilisons la fonction `Dataset.add_faiss_index()` et spécifions quelle colonne de notre jeu de données nous aimerions indexer : +L'idée de base derrière FAISS est de créer une structure de données spéciale appelée un _index_ qui permet de trouver quels plongements sont similaires à un plongement d'entrée. Créer un index FAISS dans 🤗 *Datasets* est simple -- nous utilisons la fonction `Dataset.add_faiss_index()` et spécifions quelle colonne de notre jeu de données nous aimerions indexer : ```py embeddings_dataset.add_faiss_index(column="embeddings") ``` -Nous pouvons maintenant effectuer des requêtes sur cet index en effectuant une recherche de voisin le plus proche avec la fonction `Dataset.get_nearest_examples()`. Testons cela en intégrant d'abord une question comme suit : +Nous pouvons maintenant effectuer des requêtes sur cet index en effectuant une recherche des voisins les plus proches avec la fonction `Dataset.get_nearest_examples()`. Testons cela en enchâssant d'abord une question comme suit : {#if fw === 'pt'} @@ -385,7 +385,7 @@ question_embedding.shape {/if} -Tout comme avec les documents, nous avons maintenant un vecteur de 768 dimensions représentant la requête, que nous pouvons comparer à l'ensemble du corpus pour trouver les plongements les plus similaires : +Tout comme avec les documents, nous avons maintenant un vecteur de 768 dimensions représentant la requête. Nous pouvons le comparer à l’ensemble du corpus pour trouver les enchâssements les plus similaires : ```py scores, samples = embeddings_dataset.get_nearest_examples( @@ -393,7 +393,7 @@ scores, samples = embeddings_dataset.get_nearest_examples( ) ``` -La fonction `Dataset.get_nearest_examples()` renvoie un tuple de scores qui classent le chevauchement entre la requête et le document, et un ensemble correspondant d'échantillons (ici, les 5 meilleures correspondances). Collectons-les dans un `pandas.DataFrame` afin de pouvoir les trier facilement : +La fonction `Dataset.get_nearest_examples()` renvoie un *tuple* de scores qui classent le chevauchement entre la requête et le document, et un jeu correspondant d'échantillons (ici, les 5 meilleures correspondances). Collectons-les dans un `pandas.DataFrame` afin de pouvoir les trier facilement : ```py import pandas as pd @@ -403,7 +403,7 @@ samples_df["scores"] = scores samples_df.sort_values("scores", ascending=False, inplace=True) ``` -Nous pouvons maintenant parcourir les premières lignes pour voir dans quelle mesure notre requête correspond aux commentaires disponibles : +Nous pouvons maintenant parcourir les premières lignes pour voir dans quelle mesure notre requête correspond aux commentaires disponibles : ```py for _, row in samples_df.iterrows(): @@ -521,10 +521,10 @@ URL: https://github.com/huggingface/datasets/issues/824 """ ``` -Pas mal! Notre deuxième résultat semble correspondre à la requête. +Pas mal ! Notre deuxième résultat semble correspondre à la requête. -✏️ **Essayez-le !** Créez votre propre requête et voyez si vous pouvez trouver une réponse dans les documents récupérés. Vous devrez peut-être augmenter le paramètre `k` dans `Dataset.get_nearest_examples()` pour élargir la recherche. +✏️ **Essayez !** Créez votre propre requête et voyez si vous pouvez trouver une réponse dans les documents récupérés. Vous devrez peut-être augmenter le paramètre `k` dans `Dataset.get_nearest_examples()` pour élargir la recherche. - \ No newline at end of file + diff --git a/chapters/fr/chapter5/7.mdx b/chapters/fr/chapter5/7.mdx index a4da397e5..5321adb82 100644 --- a/chapters/fr/chapter5/7.mdx +++ b/chapters/fr/chapter5/7.mdx @@ -1,11 +1,10 @@ -# 🤗 Datasets, vérifié ! +# 🤗 *Datasets*, vérifié ! -Eh bien, ce fut toute une visite de la 🤗 Datasets -- félicitations pour être arrivé jusqu'ici ! Avec les connaissances que vous avez acquises dans ce chapitre, vous devriez être en mesure de : +Eh bien, ce fut une sacrée visite de la bibliothèque 🤗 *Datasets*. Félicitations d’être arrivé jusqu'ici ! Avec les connaissances que vous avez acquises dans ce chapitre, vous devriez être en mesure de : +- charger des jeux de données depuis n'importe où, que ce soit le *Hub* d’Hugging Face, votre ordinateur portable ou un serveur distant de votre entreprise. +- manipuler vos données en utilisant un mélange des fonctions Dataset.map() et Dataset.filter(). +- passer rapidement d'un format de données à un autre, comme Pandas et NumPy, en utilisant Dataset.set_format(). +- créer votre propre jeu de données et l’envoyer vers le *Hub*. +- enchâsser vos documents en utilisant un *transformer* et construire un moteur de recherche sémantique en utilisant FAISS. -- Chargez des ensembles de données de n'importe où, que ce soit le Hugging Face Hub, votre ordinateur portable ou un serveur distant de votre entreprise. -- Démêlez vos données en utilisant un mélange des fonctions `Dataset.map()` et `Dataset.filter()`. -- Basculez rapidement entre les formats de données comme Pandas et NumPy en utilisant `Dataset.set_format()`. -- Créez votre propre ensemble de données et transférez-le vers le Hugging Face Hub. -- Intégrez vos documents à l'aide d'un modèle Transformer et créez un moteur de recherche sémantique à l'aide de FAISS. - -Dans le [Chapitre 7](/course/chapter7), nous mettrons tout cela à profit en approfondissant les principales tâches de la PNL pour lesquelles les modèles Transformer sont parfaits. Avant de vous lancer, mettez à l'épreuve vos connaissances sur 🤗 Datasets avec un quiz rapide ! +Dans le [Chapter 7](/course/fr/chapter7), nous mettrons tout cela à profit en plongeant dans les tâches de traitement du langage neturel de base pour lesquelles les *transformers* sont parfaits. Avant cela mettez vos connaissances sur la librairie 🤗 *Datasets* à l'épreuve avec un petit quiz ! diff --git a/chapters/fr/chapter5/8.mdx b/chapters/fr/chapter5/8.mdx index 19bb1d08a..e61777100 100644 --- a/chapters/fr/chapter5/8.mdx +++ b/chapters/fr/chapter5/8.mdx @@ -2,33 +2,33 @@ # Quiz de fin de chapitre -Ce chapitre a couvert beaucoup de terrain! Ne vous inquiétez pas si vous n'avez pas saisi tous les détails ; les prochains chapitres vous aideront à comprendre comment les choses fonctionnent sous le capot. +Ce chapitre a couvert beaucoup de terrain ! Ne vous inquiétez pas si vous n'avez pas saisi tous les détails, les chapitres suivants vous aideront à comprendre comment les choses fonctionnent sous le capot. Avant de poursuivre, testons ce que vous avez appris dans ce chapitre. -### 1. La fonction `load_dataset()` dans 🤗 Datasets vous permet de charger un jeu de données depuis lequel des emplacements suivants ? +### 1. La fonction `load_dataset()` dans 🤗 *Datasets* vous permet de charger un jeu de données depuis lequel des emplacements suivants ? data_files de load_dataset() pour charger les jeux de données locaux.", + text: "Localement, par exemple depuis son ordinateur portable", + explain: "Correct ! Vous pouvez passer les chemins des fichiers locaux à l'argument data_files de load_dataset() pour charger les jeux de données locaux.", correct: true }, { - text: "Le hub du visage étreignant", - explain: "Correct! Vous pouvez charger des ensembles de données sur le Hub en fournissant l'ID de l'ensemble de données, par ex. load_dataset('emotion').", + text: "Le Hub> d’Hugging Face", + explain: "Correct ! Vous pouvez charger des jeux de données sur le Hub> en fournissant l'ID du jeu de données. Par exemple : load_dataset('emotion').", correct: true }, { text: "Un serveur distant", - explain: "Correct! Vous pouvez passer des URL à l'argument data_files de load_dataset() pour charger des fichiers distants.", + explain: "Correct ! Vous pouvez passer des URLs à l'argument data_files de load_dataset() pour charger des fichiers distants.", correct: true }, ]} /> -### 2. Supposons que vous chargiez l'une des tâches GLUE comme suit : +### 2. Supposons que vous chargiez l'une des tâches du jeu de données GLUE comme suit : ```py from datasets import load_dataset @@ -36,89 +36,89 @@ from datasets import load_dataset dataset = load_dataset("glue", "mrpc", split="train") ``` -Laquelle des commandes suivantes produira un échantillon aléatoire de 50 éléments à partir de `dataset` ? +Laquelle des commandes suivantes produira un échantillon aléatoire de 50 éléments à partir de `dataset` ? dataset.sample(50)", - explain: "Ceci est incorrect -- il n'y a pas de méthode Dataset.sample()." + explain: "Ceci est incorrect, il n'y a pas de méthode Dataset.sample()." }, { text: "dataset.shuffle().select(range(50))", - explain: "Correct! Comme vous l'avez vu dans ce chapitre, vous mélangez d'abord l'ensemble de données, puis sélectionnez les échantillons à partir de celui-ci.", + explain: "Correct ! Comme vous l'avez vu dans ce chapitre, vous mélangez d'abord le jeu de données puis sélectionnez les échantillons à partir de celui-ci.", correct: true }, { text: "dataset.select(range(50)).shuffle()", - explain: "Ceci est incorrect - bien que le code s'exécute, il ne mélange que les 50 premiers éléments de l'ensemble de données." + explain: "Ceci est incorrect. Bien que le code s'exécute, il ne mélange que les 50 premiers éléments du jeu de données." } ]} /> -### 3. Supposons que vous disposiez d'un ensemble de données sur les animaux domestiques appelé "pets_dataset", qui comporte une colonne "name" indiquant le nom de chaque animal. Parmi les approches suivantes, laquelle vous permettrait de filtrer l'ensemble de données pour tous les animaux dont le nom commence par la lettre "L" ? +### 3. Supposons que vous disposiez d'un jeu de données sur les animaux domestiques appelé `pets_dataset` qui comporte une colonne `name` indiquant le nom de chaque animal. Parmi les approches suivantes, laquelle vous permettrait de filtrer le jeu de données pour tous les animaux dont le nom commence par la lettre « L » ? pets_dataset.filter(lambda x : x['name'].startswith('L'))", - explain: "Correct! L'utilisation d'une fonction Python lambda pour ces filtres rapides est une excellente idée. Pouvez-vous penser à une autre solution?", + explain: "Correct ! L'utilisation d'une fonction Python lambda pour ces filtres rapides est une excellente idée. Pouvez-vous penser à une autre solution ?", correct: true }, { text: "pets_dataset.filter(lambda x['name'].startswith('L'))", - explain: "Ceci est incorrect -- une fonction lambda prend la forme générale lambda *arguments* : *expression*, vous devez donc fournir des arguments dans ce cas." + explain: "Ceci est incorrect. Une fonction lambda prend la forme générale lambda *arguments* : *expression*, vous devez donc fournir des arguments dans ce cas." }, { - text: "Créez une fonction comme def filter_names(x): return x['name'].startswith('L') et exécutez pets_dataset.filter(filter_names).", - explain: "Correct! Tout comme avec Dataset.map(), vous pouvez passer des fonctions explicites à Dataset.filter(). Ceci est utile lorsque vous avez une logique complexe qui ne convient pas à une fonction lambda courte. Parmi les autres solutions, laquelle fonctionnerait ?", + text: "Créer une fonction comme def filter_names(x): return x['name'].startswith('L') et exécuter pets_dataset.filter(filter_names).", + explain: "Correct ! Tout comme avec Dataset.map(), vous pouvez passer des fonctions explicites à Dataset.filter(). Ceci est utile lorsque vous avez une logique complexe qui ne convient pas à une fonction lambda courte. Parmi les autres solutions, laquelle fonctionnerait ?", correct: true } ]} /> -### 4. Qu'est-ce que la cartographie mémoire ? +### 4. Qu'est-ce que le *memory mapping* ? mapping entre la RAM CPU et GPU", + explain: "Ce n'est pas ça, réessayez !", }, { - text: "Un mappage entre la RAM et le stockage du système de fichiers", - explain: "Correct! 🤗 Datasets traite chaque ensemble de données comme un fichier mappé en mémoire. Cela permet à la bibliothèque d'accéder et d'opérer sur des éléments de l'ensemble de données sans avoir à le charger complètement en mémoire.", + text: "Un mappaging entre la RAM et le stockage du système de fichiers", + explain: "Correct ! 🤗 Datasets traite chaque jeu de données comme un fichier mappé en mémoire. Cela permet à la bibliothèque d'accéder et d'opérer sur des éléments du jeu de données sans avoir à le charger complètement en mémoire.", correct: true }, { - text: "Un mappage entre deux fichiers dans le cache 🤗 Datasets", - explain: "Ce n'est pas correct - réessayez !" + text: "Un mappaging entre deux fichiers dans le cache 🤗 Datasets", + explain: "Ce n'est pas correct, réessayez !" } ]} /> -### 5. Parmi les éléments suivants, lesquels sont les principaux avantages du mappage mémoire ? +### 5. Parmi les éléments suivants, lesquels sont les principaux avantages du *memory mapping* ? Datasets d'être extrêmement rapide. Ce n'est cependant pas le seul avantage.", correct: true }, { text: "Les applications peuvent accéder à des segments de données dans un fichier extrêmement volumineux sans avoir à lire tout le fichier dans la RAM au préalable.", - explain: "Correct! Cela permet à 🤗 Datasets de charger des ensembles de données de plusieurs gigaoctets sur votre ordinateur portable sans faire exploser votre CPU. Quel autre avantage le mappage mémoire offre-t-il ?", + explain: "Correct ! Cela permet à 🤗 Datasets de charger des jeux de données de plusieurs Go sur votre ordinateur portable sans faire exploser votre CPU. Quel autre avantage cette technique offre-t-elle ?", correct: true }, { - text: "Il consomme moins d'énergie, donc votre batterie dure plus longtemps.", - explain: "Ce n'est pas correct - réessayez !" + text: "Cela consomme moins d'énergie, donc votre batterie dure plus longtemps.", + explain: "Ce n'est pas correct, réessayez !" } ]} /> -### 6. Pourquoi le code suivant échoue-t-il ? +### 6. Pourquoi le code suivant échoue-t-il ? ```py from datasets import load_dataset @@ -130,38 +130,38 @@ dataset[0] IterableDataset.", - explain: "Correct! Un IterableDataset est un générateur, pas un conteneur, vous devez donc accéder à ses éléments en utilisant next(iter(dataset)).", + explain: "Correct! Un IterableDataset est un générateur, pas un conteneur. Vous devez donc accéder à ses éléments en utilisant next(iter(dataset)).", correct: true }, { - text: "L'ensemble de données allocine n'a pas de division train.", - explain: "Ceci est incorrect - consultez la [fiche de l'ensemble de données allocine](https://huggingface.co/datasets/allocine) sur le Hub pour voir quelles divisions elle contient." + text: "Le jeu de données allocine n'a pas d’échantillon train.", + explain: "Ceci est incorrect. Consultez la [fiche d’ allocine](https://huggingface.co/datasets/allocine) sur le Hub pour voir quels échantillons il contient." } ]} /> -### 7. Parmi les avantages suivants, lesquels sont les principaux avantages de la création d'une fiche d'ensemble de données ? +### 7. Parmi les avantages suivants, lesquels sont les principaux pour la création d'une fiche pour les jeux de données ? -### 9. Pour la recherche sémantique asymétrique, vous avez généralement : +### 9. Pour la recherche sémantique asymétrique, vous avez généralement : -### 10. Puis-je utiliser 🤗 Datasets pour charger des données à utiliser dans d'autres domaines, comme le traitement de la parole ? +### 10. Puis-je utiliser 🤗 *Datasets* pour charger des données à utiliser dans d'autres domaines, comme le traitement de la parole ? MNIST dataset sur le Hub pour un exemple de vision par ordinateur." + explain: "Ceci est incorrect. 🤗 Datasets prend actuellement en charge les données tabulaires, l'audio et la vision par ordinateur. Consultez le jeu de donnéesMNIST sur le Hub pour un exemple de vision par ordinateur." }, { text: "Oui", - explain: "Correct! Découvrez les développements passionnants avec la parole et la vision dans la bibliothèque 🤗 Transformers pour voir comment 🤗 Datasets est utilisé dans ces domaines.", + explain: "Correct ! Découvrez les développements passionnants concernant la parole et la vision dans la bibliothèque 🤗 Transformers pour voir comment 🤗 Datasets est utilisé dans ces domaines.", correct : true }, ]} From e763d899199ad86cc639a02f652f40bf09002217 Mon Sep 17 00:00:00 2001 From: Cherdsak Kingkan Date: Wed, 13 Apr 2022 21:23:29 +0700 Subject: [PATCH 37/73] [th] Translated Chapter2/1 (#83) * Finish chapter2/1 * Update _toctree.yml --- chapters/th/_toctree.yml | 7 ++++++- chapters/th/chapter2/1.mdx | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 chapters/th/chapter2/1.mdx diff --git a/chapters/th/_toctree.yml b/chapters/th/_toctree.yml index 39b7a199d..ffd290a33 100644 --- a/chapters/th/_toctree.yml +++ b/chapters/th/_toctree.yml @@ -8,6 +8,11 @@ - local: chapter1/1 title: บทนำ +- title: 2. การใช้ 🤗 Transformers + sections: + - local: chapter2/1 + title: บทนำ + - title: 3. การ fine-tune โมเดลที่ผ่านการเทรนมาแล้ว (pretrained model) sections: - local: chapter3/1 @@ -27,4 +32,4 @@ title: จบพาร์ทที่ 1! - local: chapter4/6 title: คำถามท้ายบท - quiz: 4 \ No newline at end of file + quiz: 4 diff --git a/chapters/th/chapter2/1.mdx b/chapters/th/chapter2/1.mdx new file mode 100644 index 000000000..8c354032d --- /dev/null +++ b/chapters/th/chapter2/1.mdx @@ -0,0 +1,19 @@ +# บทนำ + +อย่างที่คุณเห็นใน [Chapter 1](/course/chapter1), โดยปกติแล้วโมเดล Transformer นั้นจะมีขนาดใหญ่มาก การเทรนและการใช้งานโมเดลเหล่านี้ที่มีตัวแปร (parameters) เป็นล้านไปจนถึง *หมื่นล้าน* ตัวแปรนั้นเป็นเรื่องที่ค่อนข้างซับซ้อน นอกจากนั้นแล้วการที่มีโมเดลใหม่ๆปล่อยออกมาเกือบทุกวันและแต่ละโมเดลก็มีวิธีการสร้าง (implementation) เป็นของตัวเอง ดังนั้นการจะลองทุกโมเดลนั้นไม่ใช่เรื่องที่ง่ายเลย +🤗 Transformers library สร้างขึ้นมาเพื่อแก้ปัญหานี้ จุดประสงค์ก็คือ การทำให้ไม่ว่าจะโมเดล Transformer ใดก็ตามสามารถโหลด, เทรน, และบันทึก ได้ด้วยการใช้ API เพียงอันเดียว จุดเด่นหลักๆของ library ประกอบด้วย + +- **ใช้งานง่าย**: การดาวน์โหลด, การโหลด, และการใช้งานโมเดล NLP ที่ประสิทธิภาพดีที่สุด (state-of-the-art) สำหรับการอนุมาน (inference) นั้นสามารถทำได้ด้วยโค้ดเพียง 2 บรรทัด +- **ความยืดหยุ่น**: โดยแก่นแท้แล้วทุกโมเดลนั้นก็เป็นเพียคลาส `nn.Module` ง่ายๆของ PyTorch หรือ `tf.keras.Model` ของ TensorFlow และสามารถถูกจัดการได้เหมือนโมเดลอื่นๆ ใน machine learning (ML) frameworks นั้นๆ +- **ความเรียบง่าย**: การประกาศ abstractions ใดๆข้ามไปมาใน libraries นั้นน้อยมากๆ แนวคิดหลัก (core concept) ก็คือ "ทุกอย่างอยู่ในไฟล์เดียว (All in one file)" เช่น ขั้นตอนการเรียนรู้ของโมเดลใน forward pass นั้นสามารถประกาศทั้งหมดได้ในไฟล์เดียว ดังนั้นตัวโค้ดนั้นสามารถเป็นที่เข้าใจและแก้ไขได้ในตัวมันเอง + +จุดเด่นข้อสุดท้ายนี่เองที่ทำให้ 🤗 Transformers ต่างจาก ML libraries อื่นๆ โมเดลต่างๆไม่ได้ถูกสร้างขึ้นมาจากโมดูลต่างๆที่ต้องแชร์ข้ามไฟล์กันไปมา แต่กลับกัน แต่ละโมเดลจะมี layers ของตัวเอง +นอกจากจะทำให้โมเดลเข้าถึงและเข้าใจได้ง่ายแล้ว ยังทำให้คุณสามารถทดลองโมเดลๆหนึ่งโดยที่ไม่กระทบโมเดลอื่นๆ + +บทนี้จะเริ่มด้วยตัวอย่างแบบ end-to-end ซึ่งเราจะใช้โมเดลและ tokenizer ร่วมกันเพื่อทำซ้ำ(เลียนแบบ) ฟังก์ชัน `pipeline()` จากที่เรียนใน [Chapter 1](/course/chapter1) หลังจากนั้นเราจะมาเรียนเกี่ยวกับ API ของโมเดล โดยเราจะเจาะลึกในคลาสของโมเดลและการตั้งค่า (configuration) และจะแสดงวิธีการโหลดโมเดลและกระบวนการที่โมเดลทำการทำนายผลจากชุดข้อมูลเชิงตัวเลข ว่าทำอย่างไร + +หลังจากนั้นเราจะไปดูกันที่ tokenizer API ซึ่งเป็นอีกหนึ่งส่วนประกอบหลักของฟังก์ชัน `pipeline()`, Tokenizers จะรับผิดชอบการประมวลขั้นแรกและขั้นสุดท้าย ซึ่งก็คือ การแปลงข้อมูลที่เป็นข้อความให้เป็นข้อมูลเชิงตัวเลข เพื่อใช้กับ neural network, และการแปลงข้อมูลกลับไปเป็นตัวอักษร ในกรณีที่จำเป็น และสุดท้ายเราจะแสดงวิธีการจัดการกับการส่งข้อความทีละหลายๆประโยคแบบที่เตรียมไว้เป็นชุดๆ (batch) ไปยังโมเดล และปิดท้ายด้วยฟังก์ชัน `tokenizer()` + + +⚠️ เพื่อให้ได้ประโยชน์สูงสุดจากคุณลักษณะเด่นทั้งหมดที่มีใน Model Hub และ 🤗 Transformers, เราแนะนำให้คุณ สร้างบัญชี. + \ No newline at end of file From b660ef8fa9b801f17d9f23b3ce422c235c1f6423 Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Fri, 1 Apr 2022 15:29:05 +0900 Subject: [PATCH 38/73] ko-chapter1/1 --- chapters/ko/chapter1/1.mdx | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/chapters/ko/chapter1/1.mdx b/chapters/ko/chapter1/1.mdx index 3bfb81f49..92fda2f4f 100644 --- a/chapters/ko/chapter1/1.mdx +++ b/chapters/ko/chapter1/1.mdx @@ -4,40 +4,40 @@ -이번 강의에서는 [Hugging Face](https://huggingface.co/) 환경의 라이브러리([🤗 Transformers](https://github.com/huggingface/transformers), [🤗 Datasets](https://github.com/huggingface/datasets), [🤗 Tokenizers](https://github.com/huggingface/tokenizers), [🤗 Accelerate](https://github.com/huggingface/accelerate))와 [Hugging Face Hub](https://huggingface.co/models) 를 이용해 자연어 처리(NLP)에 대해 배워보겠습니다. (무료 강의에 광고도 없는건 비밀입니다!) +이번 강의에서는 [Hugging Face](https://huggingface.co/) 환경의 라이브러리([🤗 Transformers](https://github.com/huggingface/transformers), [🤗 Datasets](https://github.com/huggingface/datasets), [🤗 Tokenizers](https://github.com/huggingface/tokenizers), [🤗 Accelerate](https://github.com/huggingface/accelerate))와 [Hugging Face Hub](https://huggingface.co/models) 를 이용해 자연어 처리(NLP)에 대해 배워보겠습니다. (무료 강의에 광고도 없는건 비밀이에요!) ## 무엇을 배우나요? 강의 개요 훑어보기:
-Brief overview of the chapters of the course. - +Brief overview of the chapters of the course. +
-- 챕터 1~4에서는 🤗 Transformers 라이브러리의 핵심 개념에 대해 소개합니다. 이 부분을 마치면 트랜스포머 모델의 동작 원리를 이해하실 수 있고, [Hugging Face Hub](https://huggingface.co/models)에서 모델을 사용하여 데이터셋으로 미세 조정(fine-tune)한 후 Hub에 모델을 공유하는 방법까지 터득하게 될 것입니다! -- 챕터 5~8은 본격적으로 고전 NLP 업무를 수행하기 앞서, 🤗 Datasets와 🤗 Tokenizers의 기초에 대해 알아봅니다. 이 부분을 모두 학습하시면 일반적인 NLP 문제를 스스로 해낼 수 있게 됩니다. -- 챕터 9~12에서는 트랜스포머 모델이 NLP 문제를 넘어, 음성 처리 및 컴퓨터 비전에 어떻게 활용되는지 탐구합니다. 이 과정에서 모델 데모를 구축하고 공유하는 방법과 이를 프로덕션 환경에 최적화하는 방법을 공부합니다. 이러한 과정을 거쳐서, 여러분들은 거의 모든 기계 학습(머신 러닝) 문제에 🤗 Transformers를 적용할 준비를 갖추게 됩니다! +- 단원 1~4에서는 🤗 Transformers 라이브러리의 핵심 개념에 대해 소개합니다. 이번 강의 끝무렵에 아마 여러분들은 트랜스포머 모델이 어떻게 동작하는지 터득하게 될거고, [Hugging Face Hub](https://huggingface.co/models)에서 모델을 사용하고 데이터셋으로 fine-tune하고 Hub에 여러분의 모델을 공유하는 방법까지 알게 될 것입니다! +- 단원 5~8은 본격적으로 전형적인 NLP 작업을 하기 앞서, 🤗 Datasets와 🤗 Tokenizers의 기초를 다룹니다. 이 부분을 모두 학습하면 여러분들은 가장 일반적인 NLP 문제를 스스로 해낼 수 있습니다. +- 단원 9~12에서는 NLP를 넘어, 트랜스포머 모델이 음성 처리 및 컴퓨터 비전에 어떻게 활용되는지 탐구합니다. 이 과정에서 여러분들의 모델 데모를 구축하고 공유하는 방법 및 이를 프로덕션 환경에 최적화하는 방법을 배우게 됩니다. 최종적으로, 여러분들은 (거의) 모든 머신 러닝 문제에 🤗 Transformers를 적용할 준비를 갖추게 됩니다! 이번 강의는: -* 파이썬에 대한 기초 지식이 필요합니다 -* [DeepLearning.AI](https://www.deeplearning.ai/) 의 프로그램이나 [fast.ai's](https://www.fast.ai/) [Practical Deep Learning for Coders](https://course.fast.ai/) 와 같은 딥러닝에 대한 기초 강의를 듣고 수강하면 더욱 효과적입니다 -* [PyTorch](https://pytorch.org/) , [TensorFlow](https://www.tensorflow.org/) 에 대한 선수 지식이 필요하지는 않지만, 이에 익숙하시다면 도움이 될 것입니다 +- 파이썬에 대한 기초 지식이 필요합니다 +- [DeepLearning.AI](https://www.deeplearning.ai/) 의 프로그램이나 [fast.ai's](https://www.fast.ai/) [Practical Deep Learning for Coders](https://course.fast.ai/) 와 같은 딥러닝에 대한 기초 강의를 듣고 수강하면 더욱 효과적입니다 +- [PyTorch](https://pytorch.org/) , [TensorFlow](https://www.tensorflow.org/) 에 대한 선수 지식이 필요하지 않지만, 이에 익숙하다면 도움이 될 것입니다 -본 강의를 모두 수강한 후, DeepLearning.AI의 [Natural Language Processing Specialization](https://www.coursera.org/specializations/natural-language-processing?utm_source=deeplearning-ai&utm_medium=institutions&utm_campaign=20211011-nlp-2-hugging_face-page-nlp-refresh)을 학습하시길 권장드립니다. 해당 과정에서는 Naive Bayes, LSTM과 같은 알아두면 너무나 유용한 더 넓은 범위의 전통 NLP 모델에 대해 학습할 수 있습니다! +본 강의를 모두 수강한 후, [DeepLearning.AI](http://deeplearning.ai/)의 [Natural Language Processing Specialization](https://www.coursera.org/specializations/natural-language-processing?utm_source=deeplearning-ai&utm_medium=institutions&utm_campaign=20211011-nlp-2-hugging_face-page-nlp-refresh)을 살펴보시길 권장드립니다. 해당 과정에서는 Naive Bayes, LSTM과 같은 알아두면 너무나 유용한 더 넓은 범위의 전통 NLP 모델에 대해 학습할 수 있습니다! ## 우리가 누구일까요? 저자 소개: -**Matthew Carrigan**은 Hugging Face의 머신 러닝 엔지니어입니다. 현재 아일랜드 더블린에 살고 있으며, 이전에는 [Parse.ly](http://parse.ly/) 에서 ML 엔지니어로, 그 전에는 Trinity Collge Dublin에서 박사 과정 이후 연구원으로 근무했습니다. 사람이 기존 인공지능 아키텍쳐를 확장하여 사람 수준에는 도달하지 못할거라고 생각하지만, 그럼에도 불멸 로봇(immortality robot)에 대해 큰 기대를 갖고 있습니다. +**Matthew Carrigan**은 Hugging Face의 머신 러닝 엔지니어입니다. 현재 아일랜드 더블린에 살고 있으며, 이전에는 [Parse.ly](http://parse.ly/) 에서 ML 엔지니어로, 그 전에는 Trinity Collge Dublin에서 박사 과정 이후 연구원으로 근무했습니다. 우리가 기존 인공지능 아키텍쳐를 확장하여 사람 수준에는 도달하지 못할거라고 생각하지만, 그럼에도 불로장생 로봇에 대해 큰 기대를 갖고 있습니다. -**Lysandre Debut**는 Hugging Face의 머신 러닝 엔지니어이며 초창기부터 🤗 Transformers 라이브러리 작업을 함께 했습니다. 아주 사용하기 쉬운 API를 개발하여 모두가 NLP를 쉽게 사용할 수 있도록 하는 목표를 갖고 있습니다. +**Lysandre Debut**는 Hugging Face의 머신 러닝 엔지니어이며 초창기부터 🤗 Transformers 라이브러리 작업을 함께 했습니다. 아주 간단한 API를 개발하여 모두가 NLP를 쉽게 사용할 수 있도록 하는 목표를 갖고 있습니다. **Sylvain Gugger**는 Hugging Face의 리서치 엔지니어로 🤗 Transformers 라이브러리의 주요 관리자 중 한명입니다. 이전에 [fast.ai](http://fast.ai/) 에서 리서치 사이언티스트로 있었으며 Jeremy Howard와 함께 *[Deep Learning for Coders with fastai and PyTorch](https://learning.oreilly.com/library/view/deep-learning-for/9781492045519/)* 를 저술했습니다. 적은 리소스에서도 모델이 빠르게 학습되도록 기술을 디자인하고 개선하여 딥러닝에 보다 쉽게 접근할 수 있도록 하는 것을 리서치의 가장 큰 목표로 삼고 있습니다. -**Merve Noyan**은 Hugging Face의 개발자 애드보케이트로, 모두에게 평등한 민주적인 머신 러닝 생태계를 만드는 목표를 갖고 있으며, 개발툴 작업 및 주변 컨텐츠 구축 작업을 담당하고 있습니다. +**Merve Noyan**은 Hugging Face의 개발자 애드보케이트로, 모두를 위한 민주적인 머신 러닝 생태계를 만들고자 개발툴 작업 및 주변 컨텐츠 구축 작업을 담당합니다. **Lucile Saulnier**은 Hugging Face의 ML 엔지니어로 오픈 소스 툴 사용에 대한 개발 및 지원을 담당합니다. 자연어 처리 분야에서 협업 학습, BigScience등과 같은 다양한 리서치 프로젝트에도 활발히 참여하고 있습니다. @@ -45,8 +45,8 @@ **Leandro von Werra**는 Hugging Face 오픈소스 팀의 머신 러닝 엔지니어이자 곧 출간될 [O’Reilly book on Transformers](https://www.oreilly.com/library/view/natural-language-processing/9781098103231/)의 공동 저자입니다. 모든 머신 러닝 스택에서의 작업을 통해 수 년간 NLP 프로젝트를 프로덕션으로 들여온 경력자입니다. -시작할 준비가 되셨나요? 이번 챕터에서 다룰 내용은 다음과 같습니다: +시작할 준비가 되셨나요? 이번 단원에서 다룰 내용은 다음과 같습니다: - 텍스트 생성 및 분류와 같은 NLP 문제를 푸는 `pipeline()` 함수 사용법 - 트랜스포머 모델 구조 -- 인코더(encoder), 디코더(decoder), 인코더-디코더(encoder-decoder)의 구조와 용례 \ No newline at end of file +- 인코더(encoder), 디코더(decoder), 인코더-디코더(encoder-decoder) 구조의 구조와 용례 \ No newline at end of file From 5fadfc2e6f300f191fd3a20aaa70de8bda612dd5 Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Fri, 1 Apr 2022 15:30:23 +0900 Subject: [PATCH 39/73] ko _toctree.yml created --- chapters/ko/_toctree.yml | 154 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 149 insertions(+), 5 deletions(-) diff --git a/chapters/ko/_toctree.yml b/chapters/ko/_toctree.yml index fe4e110ef..db8e22827 100644 --- a/chapters/ko/_toctree.yml +++ b/chapters/ko/_toctree.yml @@ -1,7 +1,7 @@ -- title: 0. 초기 설정 +- title: 0. Setup sections: - local: chapter0/1 - title: 강의 소개 + title: Introduction - title: 1. 트랜스포머 모델 sections: @@ -20,10 +20,154 @@ - local: chapter1/7 title: 시퀀스-투-시퀀스 모델 - local: chapter1/8 - title: 편향과 한계 + title: 편견과 한계점 - local: chapter1/9 - title: 단원 정리 + title: 정리 - local: chapter1/10 title: 단원 마무리 퀴즈 quiz: 1 - \ No newline at end of file + +- title: 2. Using 🤗 Transformers + sections: + - local: chapter2/1 + title: Introduction + - local: chapter2/2 + title: Behind the pipeline + - local: chapter2/3 + title: Models + - local: chapter2/4 + title: Tokenizers + - local: chapter2/5 + title: Handling multiple sequences + - local: chapter2/6 + title: Putting it all together + - local: chapter2/7 + title: Basic usage completed! + - local: chapter2/8 + title: End-of-chapter quiz + quiz: 2 + +- title: 3. Fine-tuning a pretrained model + sections: + - local: chapter3/1 + title: Introduction + - local: chapter3/2 + title: Processing the data + - local: chapter3/3 + title: Fine-tuning a model with the Trainer API or Keras + local_fw: { pt: chapter3/3, tf: chapter3/3_tf } + - local: chapter3/4 + title: A full training + - local: chapter3/5 + title: Fine-tuning, Check! + - local: chapter3/6 + title: End-of-chapter quiz + quiz: 3 + +- title: 4. Sharing models and tokenizers + sections: + - local: chapter4/1 + title: The Hugging Face Hub + - local: chapter4/2 + title: Using pretrained models + - local: chapter4/3 + title: Sharing pretrained models + - local: chapter4/4 + title: Building a model card + - local: chapter4/5 + title: Part 1 completed! + - local: chapter4/6 + title: End-of-chapter quiz + quiz: 4 + +- title: 5. The 🤗 Datasets library + sections: + - local: chapter5/1 + title: Introduction + - local: chapter5/2 + title: What if my dataset isn't on the Hub? + - local: chapter5/3 + title: Time to slice and dice + - local: chapter5/4 + title: Big data? 🤗 Datasets to the rescue! + - local: chapter5/5 + title: Creating your own dataset + - local: chapter5/6 + title: Semantic search with FAISS + - local: chapter5/7 + title: 🤗 Datasets, check! + - local: chapter5/8 + title: End-of-chapter quiz + quiz: 5 + +- title: 6. The 🤗 Tokenizers library + sections: + - local: chapter6/1 + title: Introduction + - local: chapter6/2 + title: Training a new tokenizer from an old one + - local: chapter6/3 + title: Fast tokenizers' special powers + - local: chapter6/3b + title: Fast tokenizers in the QA pipeline + - local: chapter6/4 + title: Normalization and pre-tokenization + - local: chapter6/5 + title: Byte-Pair Encoding tokenization + - local: chapter6/6 + title: WordPiece tokenization + - local: chapter6/7 + title: Unigram tokenization + - local: chapter6/8 + title: Building a tokenizer, block by block + - local: chapter6/9 + title: Tokenizers, check! + - local: chapter6/10 + title: End-of-chapter quiz + quiz: 6 + +- title: 7. Main NLP tasks + sections: + - local: chapter7/1 + title: Introduction + - local: chapter7/2 + title: Token classification + - local: chapter7/3 + title: Fine-tuning a masked language model + - local: chapter7/4 + title: Translation + - local: chapter7/5 + title: Summarization + - local: chapter7/6 + title: Training a causal language model from scratch + - local: chapter7/7 + title: Question answering + - local: chapter7/8 + title: Mastering NLP + - local: chapter7/9 + title: End-of-chapter quiz + quiz: 7 + +- title: 8. How to ask for help + sections: + - local: chapter8/1 + title: Introduction + - local: chapter8/2 + title: What to do when you get an error + - local: chapter8/3 + title: Asking for help on the forums + - local: chapter8/4 + title: Debugging the training pipeline + local_fw: { pt: chapter8/4, tf: chapter8/4_tf } + - local: chapter8/5 + title: How to write a good issue + - local: chapter8/6 + title: Part 2 completed! + - local: chapter8/7 + title: End-of-chapter quiz + quiz: 8 + +- title: Hugging Face Course Event + sections: + - local: event/1 + title: Part 2 Release Event From 2900cd4ec0ce14cdd44e3b4640e352a1f5a497b5 Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Sat, 2 Apr 2022 23:55:54 +0900 Subject: [PATCH 40/73] Fix the issue #80 --- chapters/ko/_toctree.yml | 155 ++------------------------------------- 1 file changed, 5 insertions(+), 150 deletions(-) diff --git a/chapters/ko/_toctree.yml b/chapters/ko/_toctree.yml index db8e22827..0bdd36db3 100644 --- a/chapters/ko/_toctree.yml +++ b/chapters/ko/_toctree.yml @@ -1,7 +1,7 @@ -- title: 0. Setup +- title: 0. 초기 설정 sections: - local: chapter0/1 - title: Introduction + title: 강의 소개 - title: 1. 트랜스포머 모델 sections: @@ -20,154 +20,9 @@ - local: chapter1/7 title: 시퀀스-투-시퀀스 모델 - local: chapter1/8 - title: 편견과 한계점 + title: 편향과 한계 - local: chapter1/9 - title: 정리 + title: 단원 정리 - local: chapter1/10 title: 단원 마무리 퀴즈 - quiz: 1 - -- title: 2. Using 🤗 Transformers - sections: - - local: chapter2/1 - title: Introduction - - local: chapter2/2 - title: Behind the pipeline - - local: chapter2/3 - title: Models - - local: chapter2/4 - title: Tokenizers - - local: chapter2/5 - title: Handling multiple sequences - - local: chapter2/6 - title: Putting it all together - - local: chapter2/7 - title: Basic usage completed! - - local: chapter2/8 - title: End-of-chapter quiz - quiz: 2 - -- title: 3. Fine-tuning a pretrained model - sections: - - local: chapter3/1 - title: Introduction - - local: chapter3/2 - title: Processing the data - - local: chapter3/3 - title: Fine-tuning a model with the Trainer API or Keras - local_fw: { pt: chapter3/3, tf: chapter3/3_tf } - - local: chapter3/4 - title: A full training - - local: chapter3/5 - title: Fine-tuning, Check! - - local: chapter3/6 - title: End-of-chapter quiz - quiz: 3 - -- title: 4. Sharing models and tokenizers - sections: - - local: chapter4/1 - title: The Hugging Face Hub - - local: chapter4/2 - title: Using pretrained models - - local: chapter4/3 - title: Sharing pretrained models - - local: chapter4/4 - title: Building a model card - - local: chapter4/5 - title: Part 1 completed! - - local: chapter4/6 - title: End-of-chapter quiz - quiz: 4 - -- title: 5. The 🤗 Datasets library - sections: - - local: chapter5/1 - title: Introduction - - local: chapter5/2 - title: What if my dataset isn't on the Hub? - - local: chapter5/3 - title: Time to slice and dice - - local: chapter5/4 - title: Big data? 🤗 Datasets to the rescue! - - local: chapter5/5 - title: Creating your own dataset - - local: chapter5/6 - title: Semantic search with FAISS - - local: chapter5/7 - title: 🤗 Datasets, check! - - local: chapter5/8 - title: End-of-chapter quiz - quiz: 5 - -- title: 6. The 🤗 Tokenizers library - sections: - - local: chapter6/1 - title: Introduction - - local: chapter6/2 - title: Training a new tokenizer from an old one - - local: chapter6/3 - title: Fast tokenizers' special powers - - local: chapter6/3b - title: Fast tokenizers in the QA pipeline - - local: chapter6/4 - title: Normalization and pre-tokenization - - local: chapter6/5 - title: Byte-Pair Encoding tokenization - - local: chapter6/6 - title: WordPiece tokenization - - local: chapter6/7 - title: Unigram tokenization - - local: chapter6/8 - title: Building a tokenizer, block by block - - local: chapter6/9 - title: Tokenizers, check! - - local: chapter6/10 - title: End-of-chapter quiz - quiz: 6 - -- title: 7. Main NLP tasks - sections: - - local: chapter7/1 - title: Introduction - - local: chapter7/2 - title: Token classification - - local: chapter7/3 - title: Fine-tuning a masked language model - - local: chapter7/4 - title: Translation - - local: chapter7/5 - title: Summarization - - local: chapter7/6 - title: Training a causal language model from scratch - - local: chapter7/7 - title: Question answering - - local: chapter7/8 - title: Mastering NLP - - local: chapter7/9 - title: End-of-chapter quiz - quiz: 7 - -- title: 8. How to ask for help - sections: - - local: chapter8/1 - title: Introduction - - local: chapter8/2 - title: What to do when you get an error - - local: chapter8/3 - title: Asking for help on the forums - - local: chapter8/4 - title: Debugging the training pipeline - local_fw: { pt: chapter8/4, tf: chapter8/4_tf } - - local: chapter8/5 - title: How to write a good issue - - local: chapter8/6 - title: Part 2 completed! - - local: chapter8/7 - title: End-of-chapter quiz - quiz: 8 - -- title: Hugging Face Course Event - sections: - - local: event/1 - title: Part 2 Release Event + quiz: 1 \ No newline at end of file From 8f422b749d500512259a7be67b34d5f8d2005c79 Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Sat, 2 Apr 2022 23:56:44 +0900 Subject: [PATCH 41/73] Single expression changed --- chapters/ko/chapter1/1.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ko/chapter1/1.mdx b/chapters/ko/chapter1/1.mdx index 92fda2f4f..8628ea321 100644 --- a/chapters/ko/chapter1/1.mdx +++ b/chapters/ko/chapter1/1.mdx @@ -31,7 +31,7 @@ 저자 소개: -**Matthew Carrigan**은 Hugging Face의 머신 러닝 엔지니어입니다. 현재 아일랜드 더블린에 살고 있으며, 이전에는 [Parse.ly](http://parse.ly/) 에서 ML 엔지니어로, 그 전에는 Trinity Collge Dublin에서 박사 과정 이후 연구원으로 근무했습니다. 우리가 기존 인공지능 아키텍쳐를 확장하여 사람 수준에는 도달하지 못할거라고 생각하지만, 그럼에도 불로장생 로봇에 대해 큰 기대를 갖고 있습니다. +**Matthew Carrigan**은 Hugging Face의 머신 러닝 엔지니어입니다. 현재 아일랜드 더블린에 살고 있으며, 이전에는 [Parse.ly](http://parse.ly/) 에서 ML 엔지니어로, 그 전에는 Trinity Collge Dublin에서 박사 과정 이후 연구원으로 근무했습니다. 우리가 기존 인공지능 아키텍쳐를 확장하여 사람 수준에는 도달하지 못할거라고 생각하지만, 그럼에도 불멸 로봇(immortality robot)에 대해 큰 기대를 갖고 있습니다. **Lysandre Debut**는 Hugging Face의 머신 러닝 엔지니어이며 초창기부터 🤗 Transformers 라이브러리 작업을 함께 했습니다. 아주 간단한 API를 개발하여 모두가 NLP를 쉽게 사용할 수 있도록 하는 목표를 갖고 있습니다. From 9830ec4f1f00253843c3a2c8d8f583e7bae1acde Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Sat, 2 Apr 2022 23:57:17 +0900 Subject: [PATCH 42/73] ko/chapter1 finished --- chapters/ko/chapter1/10.mdx | 361 ++++++++++++++++++------------------ chapters/ko/chapter1/2.mdx | 8 +- chapters/ko/chapter1/3.mdx | 152 ++++++++------- chapters/ko/chapter1/4.mdx | 86 ++++----- chapters/ko/chapter1/5.mdx | 2 +- chapters/ko/chapter1/6.mdx | 2 +- chapters/ko/chapter1/7.mdx | 2 +- chapters/ko/chapter1/8.mdx | 18 +- chapters/ko/chapter1/9.mdx | 4 +- 9 files changed, 327 insertions(+), 308 deletions(-) diff --git a/chapters/ko/chapter1/10.mdx b/chapters/ko/chapter1/10.mdx index a05bd4c3b..69cf78baf 100644 --- a/chapters/ko/chapter1/10.mdx +++ b/chapters/ko/chapter1/10.mdx @@ -2,253 +2,252 @@ # 단원 마무리 퀴즈 -이번 챕터에서는 정말 많은 내용들을 다뤘습니다! 그러니 모든 세부 사항을 다 이해하지 못했다고 해서 좌절하지 마세요. 다음 챕터에서 다루는 내용은 내부 작동 방식을 이해하는 데에 도움이 될거에요. - -그래도 우선, 이번 챕터에서 배운 내용에 대해 확인해보는 시간을 갖도록 하겠습니다! +이번 단원에서는 정말 많은 내용을 다뤘습니다! 그러니 모든 디테일을 이해하지 못했다고 해서 좌절하지 마세요. 다음 단원은 내부 작동 방식을 이해하는 데에 도움이 될거에요. +그래도 우선, 이번 단원에서 배운 내용에 대해 확인해보는 시간을 갖도록 하겠습니다! ### 1. Hub에서 `roberta-large-mnli` 체크포인트를 검색해 보세요. 이 모델은 어떤 작업을 수행하나요? - roberta-large-mnli page." - }, - { - text: "텍스트 분류", - explain: "더 정확하게 말하면, 이 모델은 두 문장이 논리적으로 타당한지 세 가지 레이블(모순, 함의, 중립)로 분류합니다. 이러한 문제를 자연어 추론(natural language inference)이라고 부릅니다.", - correct: true - }, - { - text: "텍스트 생성", - explain: "이 페이지를 다시 확인하세요 roberta-large-mnli page." - } - ]} +choices={[ +{ +text: "요약", +explain: "이 페이지를 다시 확인하세요 roberta-large-mnli page." +}, +{ +text: "텍스트 분류", +explain: "더 정확하게 말하면, 이 모델은 두 문장이 논리적으로 타당한지 세 가지 레이블(모순, 함의, 중립)로 분류합니다. 이러한 문제를 자연어 추론(natural language inference)이라고 부릅니다.", +correct: true +}, +{ +text: "텍스트 생성", +explain: "이 페이지를 다시 확인하세요 roberta-large-mnli page." +} +]} /> ### 2. 다음 코드는 무엇을 반환하나요? -```py +``` from transformers import pipeline ner = pipeline("ner", grouped_entities=True) ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") + ``` sentiment-analysis 파이프라인에 대한 설명입니다." - }, - { - text: "이 문장을 완성할, 생성 텍스트를 반환합니다.", - explain: "오답입니다 — 이는 text-generation 파이프라인에 대한 설명입니다.", - }, - { - text: "사람, 기관, 장소 등을 나타내는 단어들을 반환합니다.", - explain: "이 뿐만 아니라, grouped_entities=True를 사용해 \"Hugging Face\"와 같이 같은 개체에 해당하는 단어들을 그룹화해줍니다.", - correct: true - } - ]} +choices={[ +{ +text: "문장에 대해 \"positive\" 혹은 \"negative\" 로 분류한 레이블과 함께 분류 점수를 반환합니다.", +explain: "This is incorrect — this would be a sentiment-analysis pipeline." +}, +{ +text: "이 문장을 완성할, 생성 텍스트를 반환합니다.", +explain: "This is incorrect — it would be a text-generation pipeline.", +}, +{ +text: "사람, 기관, 장소 등을 나타내는 단어들을 반환합니다.", +explain: "Furthermore, with grouped_entities=True, it will group together the words belonging to the same entity, like \"Hugging Face\".", +correct: true +} +]} /> ### 3. 다음 예제 코드에서 ... 대신 무엇이 들어가야 할까요? -```py +``` from transformers import pipeline filler = pipeline("fill-mask", model="bert-base-cased") result = filler("...") + ``` ", - explain: "오답입니다. 여기 bert-base-cased 모델 카드를 보시고 다시 도전해보세요." - }, - { - text: "[MASK]", - explain: "정답! 이 모델의 마스크 토큰은 [MASK]입니다.", - correct: true - }, - { - text: "man", - explain: "오답입니다. 이 파이프라인은 마스킹된 단어를 채워야하기니까 어딘가에는 마스크 토큰이 있어야겠죠?" - } - ]} +choices={[ +{ +text: "", +explain: "오답입니다. 여기 bert-base-cased 모델 카드를 보시고 다시 도전해보세요." +}, +{ +text: "[MASK]", +explain: "정답! 이 모델의 마스크 토큰은 [MASK]입니다.", +correct: true +}, +{ +text: "man", +explain: "오답입니다. 이 pipeline은 마스킹된 단어를 채워야하기에 어딘가에는 마스크 토큰이 있어야겠죠?" +} +]} /> -### 4. 다음 코드가 실행되지 않는 이유는 무엇일까요? +### 4. 다음 코드가 작동하지 않는 이유가 무엇일까요? -```py +``` from transformers import pipeline classifier = pipeline("zero-shot-classification") result = classifier("This is a course about the Transformers library") + ``` candidate_labels=[...].", - correct: true - }, - { - text: "한 문장이 아니라, 여러 문장을 파이프라인에 넣어주어야 합니다.", - explain: "틀렸지만, 다른 파이프라인과 마찬가지로 제대로 사용한다면 물론 여러 리스트의 문장도 입력으로 넣어줄 수 있습니다." - }, - { - text: "늘 그렇듯 🤗 Transformers 라이브러리가 또 고장난거 아닌가요?", - explain: "못 들은 걸로 하겠습니다!" - }, - { - text: "위의 문장은 너무 짧아서, 더 긴 문장을 입력해야 합니다.", - explain: "오답입니다. 매우 긴 텍스트는 파이프라인에서 처리할 때 잘리게 되는 것을 명심하세요." - } - ]} +choices={[ +{ +text: "해당 텍스트를 분류하기 위해서는 pipeline에 레이블을 넣어주어야 합니다.", +explain: "맞습니다 — 제대로 작동시키기 위해 다음 코드가 필요합니다. candidate_labels=[...].", +correct: true +}, +{ +text: "한 문장이 아니라, 여러 문장을 pipeline에 넣어주어야 합니다.", +explain: "틀렸지만, 다른 pipeline과 마찬가지로 제대로 사용한다면 물론 여러 리스트의 문장도 입력으로 넣어줄 수 있습니다." +}, +{ +text: "늘 그렇듯 🤗 Transformers 라이브러리가 또 고장난거 아닌가요?", +explain: "못 들은 걸로 하겠습니다!" +}, +{ +text: "위의 문장은 너무 짧아서, 더 긴 문장을 입력해야 합니다.", +explain: "오답입니다. 매우 긴 텍스트는 pipeline에서 처리할 때 잘리게 되는 것을 명심하세요." +} +]} /> -### 5. "전이 학습(transfer learning)"이란 무엇을 의미하나요? +### 5. "전이 학습(transfer learning)"이 무엇인가요? -### 6. 언어 모델은 일반적으로 사전 학습시에 레이블을 필요로 하지 않습니다. 이 문장은 참일까요 거짓일까요? - +### 6. 언어 모델은 일반적으로 사전 학습시에 레이블이 필요하지 않습니다. 이 문장은 참일까요 거짓일까요? 자가 지도(self-supervised) 방식입니다. 이는 다음 단어 예측 혹은 마스킹 된 단어 채우기 등과 같이 입력으로부터 자동으로 레이블을 생성하는 것을 의미합니다.", - correct: true - }, - { - text: "거짓", - explain: "정답이 아닙니다." - } - ]} +choices={[ +{ +text: "참", +explain: "사전 학습 과정은 일반적으로 자가 지도(self-supervised) 방식입니다. 이는 다음 단어 예측 혹은 마스킹 된 단어 채우기 등과 같이 입력으로부터 자동으로 레이블을 생성하는 것을 의미합니다.", +correct: true +}, +{ +text: "거짓", +explain: "정답이 아닙니다." +} +]} /> ### 7. 다음 중 “모델(model)”, “구조(architecture)”, “가중치(weights)”에 대해 가장 잘 설명한 것을 고르세요. - -### 8. 다음 중 어떤 모델이 텍스트를 생성하여 프롬프트(prompt)를 완성시키는 데에 가장 적합할까요? +### 8. 다음 중 어떤 모델이 텍스트를 생성하여 프롬트(prompt)를 완성시키는 데에 가장 적합할까요? ### 9. 다음 중 어떤 모델이 텍스트 요약에 가장 적합할까요? ### 10. 다음 중 어떤 모델이 입력 텍스트를 특정 레이블로 분류하는 데에 가장 적합할까요? ### 11. 다음 중 모델이 편향성(bias)을 갖게 되는 데에 가장 가능성 있는 원인을 모두 고르세요. +choices={[ +{ +text: "모델은 사전 학습 모델의 미세 조정된 버전이고, 여기서 편향성이 따라오게 됩니다.", +explain: "전이 학습 시 사용되는 사전 학습 모델의 편향성이 미세 조정된 모델로도 전달됩니다.", +correct: true +}, +{ +text: "모델 학습에 사용된 데이터가 편향되어 있습니다.", +explain: "이는 가장 분명한 편향의 원인이지만, 유일한 원인은 아닙니다.", +correct: true +}, +{ +text: "모델이 최적화한 메트릭(metric)이 편향되어 있습니다.", +explain: "모델 학습 방식은 편향이 발생되는 불분명한 원인 중 하나입니다. 모델은 어떤 메트릭을 고르든 아무 생각 없이 그에 맞춰 최적화를 합니다.", +correct: true +} +]} +/> \ No newline at end of file diff --git a/chapters/ko/chapter1/2.mdx b/chapters/ko/chapter1/2.mdx index ca5d62dc8..3dc873652 100644 --- a/chapters/ko/chapter1/2.mdx +++ b/chapters/ko/chapter1/2.mdx @@ -1,10 +1,10 @@ # 자연어 처리(Natural Language Processing) -트랜스포머 모델을 공부하기에 앞서 자연어 처리(NLP)가 무엇인지, 그리고 왜 NLP가 중요한지 빠르고 간단하게 살펴보겠습니다. +트랜스포머 모델을 공부하기에 앞서 자연어 처리(NLP)가 무엇인지, 그리고 왜 NLP가 중요한지 빠르고 간단하게 살펴볼게요. ## NLP가 무엇인가요? -NLP(Natural Language Processing)란 사람의 언어와 관련된 모든 것을 이해하는 데에 중점을 둔 언어학 및 기계 학습(머신 러닝) 분야를 말합니다. NLP의 목적은 단순히 하나의 개별 단어를 이해하는 것을 넘어, 해당 단어들의 문맥을 이해하는 것입니다. +NLP(Natural Language Processing)란 사람의 언어와 관련된 모든 것을 이해하는 데에 중점을 둔 언어학 및 머신 러닝 분야를 말합니다. NLP의 목적은 단순히 하나의 개별 단어를 이해하는 것을 넘어, 해당 단어들의 문맥을 이해하는 것입니다. 아래는 가장 일반적인 NLP 작업과 그 예시입니다: @@ -14,8 +14,8 @@ NLP(Natural Language Processing)란 사람의 언어와 관련된 모든 것을 - **텍스트 안에서 정답 추출하기**: 지문과 질의가 주어질 때 지문에 주어진 정보를 이용해 질의에 대한 정답 추출하기 - **입력 텍스트로부터 새로운 문장 생성하기**: 입력 텍스트를 다른 언어로 번역하거나, 요약하기 -하지만 NLP는 위와 같은 텍스트 처리에만 제한되지 않습니다. NLP에서는 오디오 샘플의 스크립트 생성 및 이미지의 설명문 생성과 같이 음성 인식과 컴퓨터 비전 분야에서의 까다로운 문제 또한 다룹니다. +하지만 NLP는 위와 같이 텍스트에만 제한되지 않습니다. NLP에서는 오디오 샘플의 스크립트 및 이미지의 설명문 생성과 같이 음성 인식과 컴퓨터 비전 분야에서의 까다로운 문제도 다룹니다. ## 왜 NLP가 어렵나요? -컴퓨터와 사람은 서로 정보를 처리하는 방식이 다릅니다. 이를테면, “나는 배고파”라는 문장을 읽을 때 우리는 바로 그 의미를 이해할 수 있습니다. 마찬가지로 사람은 “나는 배고파”, “나 슬퍼”와 같은 문장 쌍이 주어질 때, 두 문장이 얼마나 유사한지 쉽게 판단할 수 있습니다. 그러나, 기계 학습 모델은 사람만큼 이를 쉽게 할 수 없습니다. 우선 모델이 텍스트를 학습할 수 있도록 텍스트가 처리 과정을 거쳐야 하는데, 사람의 언어 체계는 매우 복잡하기 때문에 이러한 처리가 어떻게 이루어져야 하는지 면밀히 고민해야 합니다. 따라서 텍스트 표현 방법과 관련한 수많은 연구가 진행되어 왔고, 다음 챕터에서 그 중 몇 가지 방법들을 소개해드리겠습니다. \ No newline at end of file +컴퓨터와 사람은 서로 정보를 처리하는 방식이 다릅니다. 이를테면, “나는 배고파”라는 문장을 읽을 때 우리는 바로 그 의미를 이해할 수 있습니다. 마찬가지로 “나는 배고파”, “나 슬퍼”와 같은 문장 쌍이 주어질 때, 두 문장이 얼마나 유사한지 쉽게 판단할 수 있습니다. 그러나, 머신 러닝(ML) 모델은 사람만큼 이를 쉽게 할 수 없습니다. 우선 모델이 텍스트를 학습할 수 있도록 텍스트가 처리 과정을 거쳐야 하는데, 사람의 언어 체계는 매우 복잡하기 때문에 이러한 처리가 어떻게 이루어져야 하는지 면밀히 생각해야 합니다. 따라서 텍스트 표현 방법과 관련한 수많은 연구가 진행되어 왔고, 다음 단원에서 여러분들에게 그 중 몇 가지 방법들을 소개해드리겠습니다. \ No newline at end of file diff --git a/chapters/ko/chapter1/3.mdx b/chapters/ko/chapter1/3.mdx index f32892430..cd82ed78d 100644 --- a/chapters/ko/chapter1/3.mdx +++ b/chapters/ko/chapter1/3.mdx @@ -1,74 +1,78 @@ # 트랜스포머로 무엇을 할 수 있나요? 이번 장에서는 트랜스포머(Transformer) 모델을 사용해 무엇을 할 수 있는지 같이 살펴보고, 🤗 Transformers 라이브러리 툴의 첫 사용을 `pipeline()` 함수와 함께 시작하겠습니다. -👀 오른쪽 상단에 Open in Colab 버튼이 보이시나요? 버튼을 클릭하면 이번 장에서 사용한 모든 코드 샘플들을 Google Colab notebook을 통해 열 수 있습니다. 이런 버튼을 예제 코드를 포함하는 모든 단원에서 발견하실 수 있습니다. +👀 오른쪽 상단에 Open in Colab 버튼이 보이시나요? 버튼을 클릭하면 이번 장에서 사용한 모든 코드 샘플들을 Google Colab notebook을 통해 열 수 있습니다. 이 버튼은 예제 코드를 포함하는 모든 장에서 나타날 거에요. 로컬 환경에서 예제 코드를 실행하려면 setup을 살펴보세요. ## 트랜스포머는 어디에나 있어요! -트랜스포머 모델은 이전 단원에서 언급한 작업과 같은 모든 NLP 문제를 해결하기 위해 사용됩니다. 아래와 같이 Hugging Face와 트랜스포머 모델을 이용하고 다시 모델을 공유하여 커뮤니티에 기여하는 많은 기업과 기관이 있습니다: +트랜스포머 모델은 이전 단원에서 언급한 작업과 같은 모든 NLP 문제를 해결하기 위해 사용됩니다. 아래에 Hugging Face와 트랜스포머 모델을 이용하고 다시 모델을 공유하여 커뮤니티에 기여하는 기업과 기관들이 보이네요: -Companies using Hugging Face +Companies using Hugging Face -[🤗 Transformers 라이브러리](https://github.com/huggingface/transformers)는 이렇게 공유한 모델을 사용하고 구축하는 기능들을 제공합니다. [Model Hub](https://huggingface.co/models)에서는 모두가 다운로드 받아 쓸 수 있는 수 천 개의 사전 학습된 모델들이 여러분을 기다리고 있습니다. 여러분만의 모델을 Hub에 업로드하는 것 또한 가능합니다! +[🤗 Transformers library](https://github.com/huggingface/transformers)는 이렇게 공유한 모델을 사용하고 구축하는 기능들을 제공합니다. [Model Hub](https://huggingface.co/models)에서는 모두가 다운로드 받아 쓸 수 있는 수 천 개의 사전 학습된 모델들이 여러분을 기다리고 있습니다. 여러분만의 모델을 Hub에 업로드하는 것 또한 가능합니다! -⚠️ The Hugging Face Hub에는 트랜스포머 모델만 있지 않아요. 누구든지 어떠한 종류의 모델이나 데이터를 공유할 수 있습니다! Create a huggingface.co 링크에서 계정을 만들고 모든 기능을 사용해보세요! + +⚠️ The Hugging Face Hub에는 트랜스포머 모델만 있지 않아요. 누구든지 어떠한 종류의 모델이나 데이터를 공유할 수 있답니다! Create a huggingface.co 링크에서 계정을 만들고 모든 기능을 사용해보세요! 트랜스포머 모델 안에서 무슨 일이 벌어지는지 알아보기 전에, 트랜스포머가 NLP 문제 해결에 어떻게 사용되는지 몇 가지 흥미로운 예시들을 살펴보겠습니다. -## 파이프라인으로 작업하기 +## Pipeline으로 작업하기 🤗 Transformers 라이브러리의 가장 기본 객체는 `pipeline()` 함수입니다. 이 함수는 모델에 있어서 필수 과정인 전처리와 후처리 과정을 모델과 연결하고, 우리가 바로 어떠한 텍스트 입력을 넣든 원하는 답을 얻을 수 있도록 합니다: -```python +``` from transformers import pipeline classifier = pipeline("sentiment-analysis") classifier("I've been waiting for a HuggingFace course my whole life.") + ``` -```python out +``` [{'label': 'POSITIVE', 'score': 0.9598047137260437}] + ``` -아래와 같이 여러 문장을 함께 넣을 수도 있습니다! +아래와 같이 여러 문장을 동시에 넣을 수도 있습니다! -```python +``` classifier( ["I've been waiting for a HuggingFace course my whole life.", "I hate this so much!"] ) + ``` -```python out +``` [{'label': 'POSITIVE', 'score': 0.9598047137260437}, {'label': 'NEGATIVE', 'score': 0.9994558095932007}] + ``` -기본적으로 이 파이프라인은 영어 감정 분석에 미세 조정(fine-tune)된 사전 학습 모델을 선택하여 넣게 됩니다. 여기서 `classifier` 객체를 생성할 때 모델이 다운로드 되며 캐싱(caching)이 이루어지때문에, 재실행 시에는 캐싱된 모델을 사용하게 되어 모델을 다시 다운로드 하지 않습니다. +기본적으로 이 pipeline은 영어 감정 분석에 미세 조정(fine-tune)된 사전 학습 모델을 선택합니다. 여기서 `classifier` 객체를 생성할 때 모델이 다운로드 되며 캐싱(caching)이 이루어지는데, 재실행 시 캐싱된 모델을 사용하게 되어 모델을 다시 다운로드 하지 않습니다. -텍스트를 파이프라인에 넣을 때 다음과 같은 세 가지 주요 과정을 거칩니다: +텍스트를 pipeline에 넣을 때 다음과 같은 세 가지 주요 과정을 거칩니다: 1. 텍스트가 모델이 이해할 수 있는 형태로 전처리 과정을 거칩니다. 2. 전처리된 입력이 모델 입력으로 들어갑니다. 3. 모델의 예측값이 후처리를 거쳐, 사람이 이해할 수 있는 형태로 반환됩니다. - -현재까지 사용할 수 있는 파이프라인([available pipelines](https://huggingface.co/transformers/main_classes/pipelines.html))은 다음과 같습니다: +현재까지 사용할 수 있는 pipeline([available pipelines](https://huggingface.co/transformers/main_classes/pipelines.html))은 다음과 같습니다: - `feature-extraction` : 특징 추출 (텍스트에 대한 벡터 표현 추출) - `fill-mask` : 마스크 채우기 @@ -80,13 +84,13 @@ classifier( - `translation` : 번역 - `zero-shot-classification` : 제로샷 분류 -이 중 몇 가지를 같이 살펴보도록 하겠습니다! +이 중 몇 가지를 같이 살펴볼까요? ## 제로샷 분류(Zero-shot classification) -레이블이 없는 텍스트를 분류하는 더 까다로운 과제부터 시작하겠습니다. 텍스트에 레이블을 다는 것은 시간이 많이 소요되고 도메인 지식이 필요하기 때문에 이러한 작업은 실제 프로젝트에서 아주 흔한 상황입니다. 이러한 상황에서 `zero-shot-classification` 파이프라인은 매우 유용합니다. 제로샷 파이프라인은 사전 학습된 모델에 의존하지 않고도 분류 작업에 사용할 레이블을 특정할 수 있도록 합니다. 위의 예시에서 모델이 긍정(positive)과 부정(negative)의 두 레이블을 분류하는 샘플을 살펴보았는데, 제로샷 파이프라인을 통해서는 어떠한 레이블 세트에 대해서도 분류 작업을 수행할 수 있습니다. +레이블이 없는 텍스트를 분류하는 더 까다로운 과제부터 시작하겠습니다. 텍스트에 레이블을 다는 것은 시간이 많이 소요되고 도메인 지식이 필요하기 때문에 이러한 작업은 실제 프로젝트에서 아주 흔한 상황입니다. 이러한 상황에서 `zero-shot-classification` pipeline은 매우 유용합니다. 제로샷 pipeline은 사전 학습된 모델에 의존하지 않고도 분류 작업에 사용할 레이블을 특정할 수 있도록 합니다. 위의 예시에서 모델이 긍정(positive)과 부정(negative)의 두 레이블을 분류하는 샘플을 살펴보았는데, 제로샷 pipeline을 통해서는 어떠한 레이블 세트에 대해서도 분류 작업을 수행할 수 있습니다. -```python +``` from transformers import pipeline classifier = pipeline("zero-shot-classification") @@ -94,58 +98,60 @@ classifier( "This is a course about the Transformers library", candidate_labels=["education", "politics", "business"], ) + ``` -```python out +``` {'sequence': 'This is a course about the Transformers library', 'labels': ['education', 'business', 'politics'], 'scores': [0.8445963859558105, 0.111976258456707, 0.043427448719739914]} + ``` -이러한 파이프라인이 제로샷(zero-shot)이라 불리는 이유는 여러분의 데이터에 맞춰 미세 조정(fine-tune)하지 않고도 바로 작업에 사용할 수 있기 때문입니다. 제로샷은 여러분이 원하는 어떠한 분류 레이블에 대해서도 확률 점수를 즉시 반환합니다. +이러한 pipeline이 제로샷(zero-shot)이라 불리는 이유는 여러분의 데이터에 미세 조정(fine-tune)하지 않고도 사용할 수 있기 때문입니다. 제로샷은 여러분이 원하는 어떠한 레이블 목록에 대해서도 확률 점수를 바로 반환합니다. -✏️ **직접 해보기!** 여러분이 직접 작성한 시퀀스와 레이블을 사용해 모델이 어떻게 동작하는지 확인해보세요. +**✏️ 직접 해보기!** 여러분만의 시퀀스와 레이블로 모델이 어떻게 동작하는지 확인해보세요. - ## 텍스트 생성(Text generation) -지금부터 파이프라인을 사용해 텍스트를 생성하는 방법을 알아보겠습니다. 여기서의 핵심은 프롬트를 모델에 제공하면 모델이 나머지 텍스트를 생성하여 이를 자동으로 완성하는 것입니다. 이는 스마트폰의 텍스트 자동 완성 기능과 유사합니다. 텍스트 생성에는 랜덤하게 결과를 생성하는 과정이 포함되어 있어서 여러분이 아래와 같이 동일하게 입력을 넣어도 매번 다른 결과가 나올 수 있습니다. +지금부터 pipeline을 사용해 텍스트를 생성하는 방법을 알아보겠습니다. 여기서의 핵심은 프롬트를 모델에 제공하면 모델이 나머지 텍스트를 생성하여 이를 자동으로 완성하는 것입니다. 이는 스마트폰의 텍스트 자동 완성 기능과 유사합니다. 텍스트 생성에는 랜덤하게 결과를 생성하는 과정이 포함되어 있어서 여러분이 아래와 같이 동일하게 입력을 넣어도 매번 다른 결과가 나올 수 있습니다. -```python +``` from transformers import pipeline generator = pipeline("text-generation") generator("In this course, we will teach you how to") + ``` -```python out +``` [{'generated_text': 'In this course, we will teach you how to understand and use ' 'data flow and data interchange when handling user data. We ' 'will be working with one or more of the most commonly used ' 'data flows — data flows of various types, as seen by the ' 'HTTP'}] + ``` -`num_return_sequences`라는 인자(argument)를 통해 몇 개의 서로 다른 출력 결과를 생성할지 정할 수 있고, `max_length` 인자를 통해 출력 텍스트의 총 길이를 설정할 수 있습니다. +`num_return_sequences` 인자(argument)를 통해 몇 개의 다른 출력 결과를 생성할지 조절할 수 있고, `max_length` 인자를 통해 출력 텍스트의 총 길이를 설정할 수 있습니다. -✏️ **직접 해보기!** `num_return_sequences` 와 `max_length` 인자를 설정해 15개의 단어를 가진 서로 다른 두 개의 문장을 출력해보세요. +**✏️ 직접 해보기!** `num_return_sequences` 와 `max_length` 인자를 설정해 15 단어의 서로 다른 두 개의 문장을 출력해보세요. +## Pipeline에 Hub의 모델 적용하기 -## 파이프라인에 Hub의 모델 적용하기 - -지금까지 예제들은 해당 작업에 대해 기본 모델들을 사용했지만, 특정 모델을 Hub에서 선택해 텍스트 생성과 같은 특정 작업에 대한 파이프라인에서도 사용할 수 있습니다. [Model Hub](https://huggingface.co/models) 페이지의 화면 왼쪽에 태그를 클릭하여 태그명에 해당하는 작업을 지원하는 모델을 확인할 수 있습니다. 이 때, [다음](https://huggingface.co/models?pipeline_tag=text-generation)과 같은 페이지로 이동하게 됩니다. +지금까지 예제들은 해당 작업에 대해 기본 모델들을 사용했지만, 특정 모델을 Hub에서 선택해 텍스트 생성과 같은 특정 작업에 대한 파이프라인에서도 사용할 수 있습니다. [Model Hub](https://huggingface.co/models) 페이지의 화면 왼쪽에 태그를 클릭하여 해당 태그 내용 작업을 지원하는 모델을 확인할 수 있습니다. [다음](https://huggingface.co/models?pipeline_tag=text-generation)과 같은 페이지로 이동하게 됩니다. -함께 [`distilgpt2`](https://huggingface.co/distilgpt2) 모델을 사용해보겠습니다! 위 예제에서 사용한 파이프라인에서 모델을 아래와 같이 로드 할 수 있습니다: +함께 `[distilgpt2](https://huggingface.co/distilgpt2)` 모델을 사용해봐요! 위의 예제에서 사용한 pipeline에서 아래와 같이 로드 할 수 있습니다: -```python +``` from transformers import pipeline generator = pipeline("text-generation", model="distilgpt2") @@ -154,44 +160,47 @@ generator( max_length=30, num_return_sequences=2, ) + ``` -```python out +``` [{'generated_text': 'In this course, we will teach you how to manipulate the world and ' 'move your mental and physical capabilities to your advantage.'}, {'generated_text': 'In this course, we will teach you how to become an expert and ' 'practice realtime, and with a hands on experience on both real ' 'time and real'}] + ``` -언어 태그를 클릭하여 해당 언어를 지원하고 생성하는 모델을 보다 구체적으로 검색할 수 있습니다. Model Hub에는 다양한 언어를 처리하는 다국어 모델의 체크포인트(모델의 파라미터 값) 또한 포함하고 있습니다. +언어 태그를 클릭하여 해당 언어를 지원 및 생성하는 모델을 구체적으로 검색할 수 있습니다. Model Hub에는 다양한 언어를 지원하는 다국어 모델의 체크포인트(모델의 파라미터 값) 또한 포함하고 있습니다. -모델을 클릭하면 온라인상에서 바로 사용 가능한 위젯을 확인할 수 있고, 이를 통해 모델을 직접 다운로드 받기 전에 모델의 기능을 빠르게 테스트 해볼 수 있습니다. +모델을 클릭하여 선택하면 온라인에서 바로 사용이 가능한 위젯을 확인할 수 있고, 이를 통해 모델을 다운로드 받기 전에 모델의 기능을 빠르게 테스트 해볼 수 있습니다. -✏️ **직접 해보기!** 영어를 제외한 다른 언어를 생성하는 모델을 검색해보세요. 위젯을 자유롭게 다뤄 보시고 파이프라인을 사용해보세요! +**✏️ 직접 해보기!** 영어를 제외한 다른 언어를 생성하는 모델을 검색해보세요. 위젯을 자유롭게 사용해 보시고 pipeline을 사용해보세요! ### 추론(Inference) API -모든 모델들은 [Hugging Face 웹사이트](https://huggingface.co/)에서 제공하는 추론 API를 통해 여러분의 브라우저상에서 직접 테스트할 수 있습니다. 이 페이지 링크로 접속해 직접 작성하신 텍스트를 입력하시면 모델의 입력 데이터를 처리 결과를 확인할 수 있습니다. +모든 모델들은 Hugging Face [웹사이트](https://huggingface.co/)에서 제공하는 추론 API를 통해 여러분의 브라우저상에서 직접 테스트가 가능합니다. 이 페이지를 통해 직접 나만의 텍스트를 입력하고 모델이 입력 데이터를 처리하는걸 구경하며 모델을 갖고 놀 수 있습니다. -위젯을 구동하는 추론 API는 간편한 워크플로우를 가능하게 하는 유료 버전의 제품으로도 이용 가능합니다. 자세한 사항은 [가격 정책 페이지](https://huggingface.co/pricing)를 참고해주세요. +위젯을 구동하는 추론 API는 간편한 워크플로우를 가능하게 하는 유료 버전의 제품으로도 이용 가능합니다. 자세한 사항은 [가격 페이지](https://huggingface.co/pricing)를 참고해주세요. ## 마스크 채우기(Mask filling) -다음으로 사용해볼 파이프라인은 마스크 채우기(`fill-mask`)입니다. 이 작업의 핵심 아이디어는 주어진 텍스트의 빈칸을 채우기입니다: +다음으로 사용해볼 pipeline은 마스크 채우기(`fill-mask`)입니다. 이 작업의 핵심 아이디어는 주어진 텍스트의 빈칸을 채우기입니다: -```python +``` from transformers import pipeline unmasker = pipeline("fill-mask") unmasker("This course will teach you all about models.", top_k=2) + ``` -```python out +``` [{'sequence': 'This course will teach you all about mathematical models.', 'score': 0.19619831442832947, 'token': 30412, @@ -200,49 +209,52 @@ unmasker("This course will teach you all about models.", top_k=2) 'score': 0.04052725434303284, 'token': 38163, 'token_str': ' computational'}] + ``` -상위 몇 개의 높은 확률을 띠는 토큰을 출력할지 `top_k` 인자를 통해 조절합니다. 여기서 모델이 특이한 `` 단어를 채우는 것을 주목하세요. 이를 마스크 토큰(mask token)이라고 부릅니다. 다른 마스크 채우기 모델들은 다른 형태의 마스크 토큰을 사용할 수 있기 때문에 다른 모델을 탐색할 때 항상 해당 모델의 마스크 단어가 무엇인지 확인해야 합니다. 위젯에서 사용되는 마스크 단어를 보고 이를 확인할 수 있습니다. +몇 개의 가능성 있는 토큰을 표시할지 `top_k` 인자를 통해 조절합니다. 여기서 모델이 특이한 `` 단어를 채우는 것을 주목하세요. 이는 마스크 토큰(mask token)이라고 부릅니다. 다른 마스크 채우기 모델들은 다른 형태의 마스크 토큰을 사용할 수 있어서 다른 모델을 탐색할 때 항상 마스크 단어를 확인해야 합니다. 위젯에서 사용되는 마스크 단어를 보고 이를 확인해 볼 수 있습니다. -✏️ **직접 해보기!** Hub에서 `bert-base-cased`를 검색해 보고 추론 API 위젯을 통해 모델의 마스크 단어가 무엇인지 확인해 보세요. 이 모델이 위의 `pipeline` 예제에서 사용한 문장에 대해 어떻게 예측하나요? +**✏️ 직접 해보기!** Hub에서 `bert-base-cased` 를 검색해 보고 Inference API 위젯으로 마스크 단어를 확인해 보세요. 이 모델이 위의 `pipeline` 예제에서 사용한 문장에 대해 어떻게 예측하나요? ## 개체명 인식(Named entity recognition) -모델이 입력 텍스트의 어느 부분이 사람, 장소, 기관 등과 같은 개체에 해당하는지 찾는 작업을 개체명 인식(NER)이라고 합니다. 예제를 통해 확인해 봅시다: +개체명 인식(NER)은 모델이 입력 텍스트의 어느 부분이 사람, 장소, 기관 등과 같은 개체에 해당하는지 찾는 작업입니다. 예제를 통해 확인해 봅시다: -```python +``` from transformers import pipeline ner = pipeline("ner", grouped_entities=True) ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") + ``` -```python out +``` [{'entity_group': 'PER', 'score': 0.99816, 'word': 'Sylvain', 'start': 11, 'end': 18}, {'entity_group': 'ORG', 'score': 0.97960, 'word': 'Hugging Face', 'start': 33, 'end': 45}, {'entity_group': 'LOC', 'score': 0.99321, 'word': 'Brooklyn', 'start': 49, 'end': 57} ] + ``` 모델이 정확하게 Sylvain을 사람(PER)으로, Hugging Face를 기관(ORG)으로, Brooklyn을 장소(LOC)으로 예측했네요! -파이프라인을 생성하는 함수에 `grouped_entities=True` 옵션을 전달하면 파이프라인이 같은 개체에 해당하는 문장 부분을 다시 그룹화합니다. 이 옵션을 설정하면 모델은 여러 단어로 구성된 단어임에도 “Hugging”과 “Face”를 하나의 기관으로 정확히 분류하게 됩니다. 다음 챕터에서도 확인하겠지만, 놀랍게도 전처리 과정에서 각 단어들은 더 작은 부분으로 쪼개집니다. 예를 들어 `Sylvain` 이라는 단어는 `S`, `##yl`, `##va`, `##in` 이렇게 네 조각으로 쪼개집니다. 후처리 단계에서 파이프라인은 이 조각들을 멋지게 재그룹화합니다. +Pipeline을 생성하는 함수에 `grouped_entities=True` 옵션을 전달하면 pipeline이 같은 개체에 해당하는 문장 부분을 다시 그룹화합니다. 이 경우 모델은 여러 단어로 구성된 단어임에도 “Hugging”과 “Face”를 하나의 기관으로 정확히 분류하게 됩니다. 다음 단원에서도 확인하겠지만, 놀랍게도 전처리 과정에서 각 단어들은 더 작은 부분으로 쪼개지게 됩니다. 예를 들어 `Sylvain` 이라는 단어는 `S`, `##yl`, `##va`, `##in` 이렇게 네 조각으로 쪼개집니다. 후처리 단계에서 pipeline은 이 조각들을 멋지게 재그룹화합니다. -✏️ **직접 해보기!** Model Hub에서 영어 품사 태깅(part-of-speech tagging, 줄여서 POS)이 가능한 모델을 찾아보세요. 이 모델이 위의 예시 문장으로 무엇을 예측하나요? +**✏️ 직접 해보기!** Model Hub에서 영어 품사 태깅(part-of-speech tagging, 줄여서 POS)이 가능한 모델을 찾아보세요. 이 모델이 위의 예시 문장으로 무엇을 예측하나요? ## 질의 응답(Question-answering) -질의 응답(`question-answering`) 파이프라인은 주어진 지문(context)의 정보를 활용하여 질문에 대한 답을 하는 태스크입니다: +질의 응답(`question-answering`) pipeline은 주어진 지문(context)의 정보를 활용하여 질문에 답을 합니다: -```python +``` from transformers import pipeline question_answerer = pipeline("question-answering") @@ -250,19 +262,21 @@ question_answerer( question="Where do I work?", context="My name is Sylvain and I work at Hugging Face in Brooklyn", ) + ``` -```python out +``` {'score': 0.6385916471481323, 'start': 33, 'end': 45, 'answer': 'Hugging Face'} + ``` -본 파이프라인은 답을 새롭게 생성하는 방식이 아닌, 주어진 지문 내에서 정답을 추출하는 방식임을 잘 기억하세요. +본 pipeline은 답을 새롭게 생성하지 않고 주어진 지문에서 정답을 추출하는 방식임을 잘 기억하세요. ## 요약(Summarization) -요약(Summarization)은 참조 텍스트의 모든(혹은 대부분의) 중요한 특징을 그대로 유지한 채 텍스트를 짧게 줄이는 작업입니다. 아래 예제를 확인하세요: +요약은 참조 텍스트의 모든(혹은 대부분) 중요한 특징을 유지한 채로 텍스트를 짧게 줄이는 작업입니다. 아래 예제를 확인하세요: -```python +``` from transformers import pipeline summarizer = pipeline("summarization") @@ -288,9 +302,10 @@ summarizer( and a lack of well-educated engineers. """ ) + ``` -```python out +``` [{'summary_text': ' America has changed dramatically during recent years . The ' 'number of engineering graduates in the U.S. has declined in ' 'traditional engineering disciplines such as mechanical, civil ' @@ -298,31 +313,38 @@ summarizer( 'developing economies such as China and India, as well as other ' 'industrial countries in Europe and Asia, continue to encourage ' 'and advance engineering .'}] + ``` -텍스트 생성에서와 마찬가지로 `max_length` 와 `min_length` 를 미리 설정할 수 있습니다. +텍스트 생성과 마찬가지로 `max_length` 와 `min_length` 를 정할 수 있습니다. ## 번역(Translation) -번역(Translation)의 경우 `"translation_en_to_fr"` 와 같이 태스크명에 해당하는 언어 쌍을 넣어준다면 기본 모델을 사용할 수 있지만, 더 간단하게 [Model Hub](https://huggingface.co/models)에서 원하는 모델을 선택해 사용하는 방법이 있습니다. 아래에서는 프랑스어에서 영어로 번역을 시도해 보겠습니다: +For translation, you can use a default model if you provide a language pair in the task name (such as `"translation_en_to_fr"`), but the easiest way is to pick the model you want to use on the [Model Hub](https://huggingface.co/models). Here we'll try translating from French to English: + +번역의 경우 (`"translation_en_to_fr"` 와 같이) 작업명에 언어 쌍을 넣어준다면 기본 모델을 사용할 수 있지만, [Model Hub](https://huggingface.co/models)에서 원하는 모델을 고르는 방식이 가장 간단합니다. 여기서는 프랑스어에서 영어로 번역을 시도해 보겠습니다: -```python +``` from transformers import pipeline translator = pipeline("translation", model="Helsinki-NLP/opus-mt-fr-en") translator("Ce cours est produit par Hugging Face.") + ``` -```python out +``` [{'translation_text': 'This course is produced by Hugging Face.'}] + ``` 텍스트 생성 및 요약에서와 마찬가지로, `max_length` 혹은 `min_length` 를 지정하여 결과를 출력할 수 있습니다. -✏️ **직접 해보기!** 다른 언어를 지원하는 번역 모델을 검색해보고 위의 문장을 몇 가지 다른 언어들로 번역해 봅시다. +**✏️ 직접 해보기!** 다른 언어의 번역 모델을 검색해보고 위의 문장을 몇 가지 다른 언어들로 번역해 봅시다. -지금까지 보여드린 파이프라인들은 대부분 특정 작업을 위해 프로그래밍된 데모용 파이프라인으로, 여러 태스크를 동시에 지원하지는 않습니다. 다음 단원에서는 `pipeline()` 함수 내부를 살펴보고 그 동작 방식을 직접 설계하는 방법에 대해 다루겠습니다. \ No newline at end of file +The pipelines shown so far are mostly for demonstrative purposes. They were programmed for specific tasks and cannot perform variations of them. In the next chapter, you'll learn what's inside a `pipeline()` function and how to customize its behavior. + +지금까지 보여드린 pipeline들은 대부분 특정 작업을 위해 프로그래밍된, 다양한 변형 작업을 수행할 수 없는 데모용 pipeline입니다. 다음 단원에서는 `pipeline()` 함수 내부를 살펴보고 그 동작을 사용자가 직접 설계하는 방법을 다루겠습니다. \ No newline at end of file diff --git a/chapters/ko/chapter1/4.mdx b/chapters/ko/chapter1/4.mdx index 96456fab5..b8b552039 100644 --- a/chapters/ko/chapter1/4.mdx +++ b/chapters/ko/chapter1/4.mdx @@ -7,25 +7,22 @@ 아래에 트랜스포머 모델의 (짧은) 역사 중 주요한 지점을 나타냈습니다:
-A brief chronology of Transformers models. - +A brief chronology of Transformers models. +
[Transformer architecture](https://arxiv.org/abs/1706.03762)는 2017년 6월에 처음 소개되었습니다. 처음 연구 목적은 번역 작업 수행이었습니다. 이후로 다음과 같이 줄줄이 막강한 모델들이 세상에 등장했습니다: - **2018년 6월**: [GPT](https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf), 최초로 사전 학습된 트랜스포머 모델로 다양한 NLP 작업에 미세 조정(fine-tune)되도록 사용되었으며 SOTA(state-of-the-art) 성능 달성 - - **2018년 10월**: [BERT](https://arxiv.org/abs/1810.04805), 또 다른 거대 사전 학습 언어 모델로, 더 좋은 문장 요약을 위해 설계 (이번 단원과 다음 단원에서 더 자세히 알아봐요!) - - **2019년 2월**: [GPT-2](https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf), 더 좋은 성능(그리고 더 큰) 버전의 GPT로, 윤리적 문제로 인해 즉시 공개되지 못하였음 - - **2019년 10월**: [DistilBERT](https://arxiv.org/abs/1910.01108), BERT의 60% 빠른 속도에 메모리 측면에서 40% 가볍지만 BERT 성능의 97%를 재현하는 경량화 버전의 BERT - - **2019년 10월**: [BART](https://arxiv.org/abs/1910.13461) 와 [T5](https://arxiv.org/abs/1910.10683), 동일한 구조의 (처음으로) 원본 트랜스포머 모델의 구조를 그대로 따른 두 거대 사전학습 언어 모델 - - **2020년 5월**, [GPT-3](https://arxiv.org/abs/2005.14165), 미세 조정 없이도 (zero-shot learning이라 부름) 다양한 작업을 훌륭하게 수행하는 GPT-2의 더 큰 버전 -위 리스트는 단순히 여러 종류의 트랜스포머 모델들 중 몇몇을 강조하기 위한 목록입니다. 넓은 관점에서 트랜스포머 모델은 아래와 같이 세 개의 카테고리로 묶을 수 있습니다: +This list is far from comprehensive, and is just meant to highlight a few of the different kinds of Transformer models. Broadly, they can be grouped into three categories: + +위 리스트는 단순히 서로 다른 종류의 트랜스포머 모델들 중 몇몇을 강조하기 위한 목록일 뿐, 포괄적이지 않습니다. 넓은 관점에서 트랜스포머 모델은 아래와 같이 세 카테고리로 그룹화 할 수 있습니다: - GPT-계열 (*Auto-regressive* 트랜스포머 모델로도 불림) - BERT-계열 (*Auto-encoding* 트랜스포머 모델로도 불림) @@ -37,45 +34,44 @@ 위에 언급한 모델(GPT, BERT, BART, T5 등)들은 *언어 모델(language model)*로서 학습 되었습니다. 다르게 말하면 이 모델들은 스스로 지도하는 방식으로 수많은 텍스트에 대해 학습된 모델들입니다. 이러한 자가 지도 학습(self-supervised learning)은 학습의 목적이 모델 입력으로부터 자동으로 계산되는 방식을 말합니다. 결국 사람이 데이터에 레이블을 달지 않아도 학습이 가능한 것입니다! -이러한 종류의 모델은 학습한 언어에 대해 통계 기반의 방식으로 이해를 하지만, 이는 몇몇 실생활 문제에 적합하지 않습니다. 그렇기 때문에 사전 학습된 모델은 *전이 학습(transfer learning)*이라 불리는 과정을 거칩니다. 이 과정에서 모델은 특정 작업에 맞춰 지도적(supervised)인 방법, 즉 사람이 레이블을 추가한 데이터를 사용하는 방법으로 미세 조정(fine-tune)이 이루어지는 단계를 거칩니다. +이러한 종류의 모델은 학습한 언어에 대해 통계 기반의 이해를 생성하지만 이는 몇몇 실생활 문제에 적합하지 않습니다. 이러한 이유로 사전 학습된 모델은 *전이 학습(transfer learning)*이라 불리는 과정을 거칩니다. 이 과정에서 모델은 특정 작업에 맞춰 지도적(supervised)인 방법, 즉 사람이 레이블을 추가한 데이터를 사용하는 방법으로 미세 조정(fine-tune)이 이루어지며 하나의 예시로 문장 내에서 이전 *n*개의 단어를 읽고 다음에 올 단어를 에측하는 문제를 들 수 있습니다. 이를 과거와 현재의 입력 정보를 이용하는 방식(미래에 올 입력 정보는 이용하지 않습니다)이기 때문에 *인과적 언어 모델링(causal language modeling)*이라고 부릅니다.
-Example of causal language modeling in which the next word from a sentence is predicted. - +Example of causal language modeling in which the next word from a sentence is predicted. +
다른 예시로 *마스크 언어 모델링(masked language modeling)*을 들 수 있습니다. 여기서 모델은 문장 내에 마스킹 된 단어를 예측합니다.
-Example of masked language modeling in which a masked word from a sentence is predicted. - +Example of masked language modeling in which a masked word from a sentence is predicted. +
## 트랜스포머는 거대 모델입니다 -(DistilBERT와 같은 몇몇 예외를 제외하고) 모델의 성능을 향상시키는 일반적인 전략은 사전 학습에 사용하는 "모델과 데이터의 크기를 늘리기" 입니다. +(DistilBERT와 같은 몇몇 예외를 제외하고) 모델의 성능을 향상시키는 일반적인 전략은 사전 학습에 사용하는 모델의 크기와 데이터의 양을 늘리는 방식입니다.
-Number of parameters of recent Transformers models +Number of parameters of recent Transformers models
불행히도 아주 아주 큰 모델의 경우, 학습을 위해 어마무시한 양의 데이터를 필요로 하여 시간과 컴퓨팅 리소스 관점에서 비용이 매우 많이 듭니다. 아래 그래프에서 볼 수 있듯이 이는 환경 오염 문제로 이어지기도 합니다.
-The carbon footprint of a large language model. - +The carbon footprint of a large language model. +
-위 비디오는 사전 학습 과정이 환경에 끼치는 부정적 영향을 꾸준히 줄이기 위해 노력하는 한 팀의 (초거대) 언어 모델 프로젝트를 소개합니다. 최적의 하이퍼파라미터를 찾기 위한 수많은 시도에는 아직 많은 여정이 남아 있습니다. - -매번 리서치 팀, 학생 기관, 기업 등등이 밑바닥부터 모델을 학습시킨다고 생각해보세요. 이는 결국 정말 어마어마한 양의 글로벌 비용으로 이어질 것입니다! +위 비디오는 사전 학습 과정이 환경에 끼치는 부정적 영향을 꾸준히 줄이기 위해 노력하는 팀의 (초거대) 언어 모델 프로젝트를 소개합니다. 최적의 하이퍼파라미터를 찾기 위한 수많은 시도에는 아직 많은 여정이 남았습니다. -이제 왜 언어 모델을 공유하는 것이 중요한지 아시겠나요? 학습 가중치를 공유하고, 이미 학습시킨 가중치에 이를 차곡차곡 쌓아 올리는 방식으로 커뮤니티의 컴퓨팅 비용과 탄소 발자국을 줄일 수 있기 때문입니다. +매번 리서치 팀, 학생 기관, 기업 등등이 밑바닥부터 모델을 학습시킨다고 생각해보세요. 정말 어마어마한 글로벌 비용으로 이어지겠죠? +이제 왜 언어 모델을 공유하는 것이 중요한지 아시겠죠? 학습된 가중치를 공유하고, 이미 학습된 가중치에 이를 차곡차곡 쌓아 올리는 방식으로 커뮤니티의 컴퓨팅 비용과 탄소 발자국을 줄일 수 있습니다. ## 전이 학습(Transfer Learning) @@ -84,23 +80,23 @@ *사전 학습(Pretraining)*시에는 모델을 밑바닥부터 학습시키게 됩니다. 모델 가중치를 랜덤하게 초기화하고 사전 지식 없이 학습을 시작합니다.
-The pretraining of a language model is costly in both time and money. - +The pretraining of a language model is costly in both time and money. +
-이러한 사전 학습 과정은 엄청난 양의 데이터로 이루어지기 때문에 방대한 양의 코퍼스 데이터와 수 주 씩 걸리는 학습 시간을 필요로 하기도 합니다. +이러한 사전 학습은 엄청난 양의 데이터로 이루어지기 때문에 방대한 양의 코퍼스 데이터와 수 주 씩 걸리는 학습 시간을 필요로 하기도 합니다. -반면에 *미세 조정(Fine-tuning)*이란 모델이 모두 사전 학습을 마친 **이후에** 하는 학습을 의미합니다. 미세 조정을 하기 위해서 우선 사전 학습된 언어 모델을 가져오고, 여러분이 할 작업에 특화된 데이터셋을 이용해 추가 학습을 수행합니다. 잠깐만요, 그냥 한번에 최종 태스크에 맞춰 학습시키면 안될까요? 이렇게 하는 데에는 몇 가지 이유가 있습니다: +하지만 *미세 조정(Fine-tuning)*은 모델이 사전 학습된 **이후에** 하는 학습을 의미합니다. 미세 조정을 하기 위해서 우선 사전 학습된 언어 모델을 가져오고, 여러분이 할 작업에 특화된 데이터셋을 이용해 추가 학습을 수행합니다. 잠깐만요, 그냥 한번에 최종 태스크에 맞춰 학습시키면 안될까요? 이렇게 하는 데에는 몇 가지 이유가 있습니다: -- 사전 학습된 모델은 이미 미세 조정 데이터셋과 유사한 데이터셋으로 학습이 이루어진 상태입니다. 결국 모델이 사전 학습시에 얻은 지식(이를테면, NLP 문제에서 사전 학습된 모델이 얻게 되는 언어의 통계적 이해)을 십분 활용해 미세 조정에 활용할 수 있게 됩니다. +- 사전 학습된 모델은 이미 미세 조정 데이터셋과 유사한 데이터셋으로 학습이 이루어진 상태입니다. 결국 모델이 사전 학습시에 얻은 지식(이를테면, NLP 문제에서 사전 학습된 모델이 얻게 되는 통계적 이해)을 십분 활용해 미세 조정에 활용할 수 있게 됩니다. - 사전 학습된 모델은 이미 방대한 데이터로 학습되었기 떄문에 미세 조정에서는 원하는 성능을 얻기까지 적은 양의 데이터만 필요로 하게 됩니다. - 위와 같은 이유로, 원하는 성능을 얻기까지 적은 시간과 리소스만 필요하게 됩니다. 예시로, 영어로 사전 학습된 모델을 활용해 arXiv 코퍼스로 미세 조정하여 과학/연구 기반 모델을 만들 수 있습니다. 이 때 미세 조정에는 적은 양의 데이터만 필요할 것입니다. 여기서 사전 학습 과정에서 얻은 지식이 “전이”되었다고 하여 *전이 학습(transfer learning)*이라 부릅니다.
-The fine-tuning of a language model is cheaper than pretraining in both time and money. - +The fine-tuning of a language model is cheaper than pretraining in both time and money. +
모델의 미세 조정은 이렇게 시간, 데이터, 경제, 그리고 환경 비용 측면에서 훨씬 저렴합니다. 뿐만 아니라 전체 사전 학습 과정보다 제약이 적기 때문에 다양한 방식의 미세 조정을 쉽고 빠르게 반복할 수 있습니다. @@ -113,23 +109,23 @@ -## 구조 소개 +## Introduction 모델은 기본적으로 두 개의 블럭으로 이루어져 있습니다: -* **인코더 (왼쪽)**: 인코더는 입력을 받아 입력(혹은 입력의 특징)을 구축합니다. 이는 인코더 모델이 입력을 이해하는 데에 최적화되어 있음을 의미합니다. -* **디코더 (오른쪽)**: 디코더는 인코더의 (특징) 표현과 또 다른 입력을 활용해 타겟 시퀀스를 생성합니다. 이는 디코더 모델이 출력을 생성하는 데에 최적화되어 있음을 의미합니다. +- **인코더 (왼쪽)**: 인코더는 입력을 받아 입력(혹은 입력의 특징)을 구축합니다. 이는 인코더 모델이 입력을 이해하는 데에 최적화되어 있음을 의미합니다. +- **디코더 (오른쪽)**: 디코더는 인코더의 (특징) 표현과 또 다른 입력을 활용해 타겟 시퀀스를 생성합니다. 이는 디코더 모델이 출력을 생성하는 데에 최적화되어 있음을 의미합니다.
-Architecture of a Transformers models - +Architecture of a Transformers models +
트랜스포머 모델의 각 파트는 태스크에 따라 다음과 같이 개별적으로 쓰일 수도 있습니다: -* **인코더 모델(Encoder-only models)**: 문장 분류, 개체명 인식과 같이 입력에 대한 높은 이해를 요구하는 작업에 특화 -* **디코더 모델(Decoder-only models)**: 텍스트 생성과 같이 생성 관련 작업에 특화 -* **인코더-디코더(Encoder-decoder) 모델 또는 시퀀스-투-시퀀스 (Sequence-to-sequence) 모델**: 번역, 요약과 같이 입력을 필요로 하는 생성 관련 작업에 특화 +- **인코더 모델(Encoder-only models)**: 문장 분류, 개체명 인식과 같이 입력에 대한 높은 이해를 요구하는 작업에 특화 +- **디코더 모델(Decoder-only models)**: 텍스트 생성과 같이 생성 관련 작업에 특화 +- **인코더-디코더(Encoder-decoder) 모델 또는 시퀀스-투-시퀀스 (Sequence-to-sequence) 모델**: 번역, 요약과 같이 입력을 필요로 하는 생성 관련 작업에 특화 다음 단원들에서 각각의 구조에 대해 더 깊게 살펴보도록 하겠습니다. @@ -137,23 +133,23 @@ 트랜스포머 모델의 중요한 특징은 *어텐션 레이어(attention layers)*라 불리는 특수한 레이어로 구성되었다는 점입니다. 사실, 트랜스포머 구조를 처음 소개한 논문 제목마저 ["Attention Is All You Need"](https://arxiv.org/abs/1706.03762)입니다! 어텐션 레이어의 디테일에 대해서는 추후 강의에서 자세히 다루겠지만, 우선은 이 레이어가 단어의 표현을 다룰 때 입력으로 넣어준 문장의 특정 단어에 어텐션(주의)을 기울이고 특정 단어는 무시하도록 알려준다는 사실을 기억하셔야 합니다. -이러한 상황을 설명하기 위해 영어 텍스트를 프랑스어로 번역하는 작업을 생각해 보겠습니다. “You like this course”라는 입력이 주어지면 번역 모델은 “like”라는 단어를 알맞게 번역하기 위해 인접한 단어 “You”에도 주의를 기울입니다. 이는 프랑스어의 동사 “like”가 문맥에 따라 다른 의미로 해석되기 때문입니다. 그러나 문장의 나머지 단어들은 이 단어를 번역하는 데에 크게 유용하지 않습니다. 같은 맥락에서 “this”를 번역할 때, 이 단어는 연결 명사가 남성형이거나 여성형이냐에 따라 다르게 해석될 수 있기 때문에 모델은 “course”라는 단어에 주의를 기울입니다. 여기서도 문장의 나머지 다른 단어들은 “this”의 의미를 해석하는 데에 크게 중요하지 않습니다. 더 복잡한 문법의 문장에서 모델은 문장의 각 단어를 적절히 번역하기 위해 더 멀리 떨어진 단어들에 대해서도 주의를 기울여야 합니다. +이러한 상황을 설명하기 위해 영어 텍스트를 프랑스어로 번역하는 작업을 생각해봅시다. “You like this course”라는 입력이 주어지면 번역 모델은 “like”라는 단어를 알맞게 번역하기 위해 인접한 단어 “You”에도 주의를 기울입니다. 이는 프랑스어의 동사 “like”가 문맥에 따라 다른 의미로 해석되기 때문입니다. 그러나 문장의 나머지 단어들은 이 단어를 번역하는 데에 크게 유용하지 않습니다. 같은 맥락에서 “this”를 번역할 때, 이 단어는 연결 명사가 남성형이거나 여성형이냐에 따라 다르게 해석될 수 있기 때문에 모델은 “course”라는 단어에 주의를 기울입니다. 여기서도 문장의 나머지 다른 단어들은 “this”의 의미를 해석하는 데에 크게 중요하지 않습니다. 더 복잡한 문법의 문장에서 모델은 문장의 각 단어를 적절히 번역하기 위해 더 멀리 떨어진 단어들에 대해서도 주의를 기울여야 합니다. 이와 동일한 개념이 자연어의 모든 문제에 적용됩니다. 단어는 그 자체로도 의미를 갖지만 문맥상 앞뒤의 다른 단어정보를 알게 되면 의미가 달라지기도 하죠. 지금까지 어텐션 레이어가 무엇인지 알아보았으니 트랜스포머 구조에 대해 살펴보겠습니다. -## 원본 구조 +## 원본 구조 The original architecture 트랜스포머 구조는 처음에 번역을 위해 만들어졌습니다. 학습시에 인코더는 특정 언어의 입력 문장을 받고, 동시에 디코더는 타겟 언어로된 동일한 의미의 문장을 받습니다. 인코더에서 어텐션 레이어는 문장 내의 모든 단어를 활요할 수 있습니다(방금 보았듯이 주어진 단어의 번역은 문장의 전후를 살펴보아야 하니까요). 반면, 디코더는 순차적으로 작동하기 때문에 문장 내에서 이미 번역이 이루어진 부분에만 주의를 기울일 수 밖에 없습니다. 이로 인해 현재 생성(번역)되고 있는 단어의 앞에 단어들만 이용할 수 있죠. 예시로, 번역된 타겟의 처음 세 단어를 예측해 놨을 때, 이 결과를 디코더로 넘기면 디코더는 인코더로부터 받은 모든 입력 정보를 함께 이용해 네 번째 올 단어를 예측하는 것입니다. 모델이 타겟 문장에 대한 액세스(access)가 있는 상황에서, 훈련 속도를 높이기 위해 디코더는 전체 타겟을 제공하지만 뒤에 올 단어들을 사용할 수 없습니다. (모델이 두 번째 올 단어를 예측하기 위해 두 번째 위치 단어를 접근할 수 있다면 예측이 의미없어지겠죠?) 예를 들어, 네 번째 단어를 예측할 때 어텐션 레이어는 1~3 번째 단어에만 액세스하도록 합니다. -원래 처음 트랜스포머의 구조는 아래와 같이 왼쪽에는 인코더, 오른쪽에는 디코더가 있는 형태를 지닙니다: +원본의 트랜스포머 구조는 아래와 같이 왼쪽에는 인코더, 오른쪽에는 디코더가 있는 형태를 지닙니다:
-Architecture of a Transformers models - +Architecture of a Transformers models +
디코더 블럭의 첫 번째 어텐션 레이어는 모든 이전의 디코더 입력에 대해 주의를 기울이지만, 두 번째 어텐션 레이어는 인코더의 출력만 사용하는 점을 주목하세요. 이로써 디코더는 전체 입력 문장에 액세스하여 현재 올 단어를 잘 예측하게 되는 것입니다. 이는 서로 다른 언어는 서로 다른 어순을 갖거나 문장의 뒷부분에 등장하는 문맥이 주어진 단어의 가장 적합한 번역을 결정할 수 있기 때문에 매우 유용합니다. @@ -164,8 +160,8 @@ 트랜스포머 모델을 본격적으로 공부하기 앞서, 모델(models)과 함께 *구조(architectures)*와 *체크포인트(checkpoints)*라는 단어를 들으시게 될겁니다. 이 셋은 아래와 같이 조금 다른 의미를 갖고 있습니다: -* **구조(Architecture)**: 모델의 뼈대를 의미하는 용어로, 모델 내부의 각 레이어와 각 연산 작용들을 의미합니다. -* **체크포인트(Checkpoints)**: 주어진 구조(architecture)에 적용될 가중치들을 의미합니다. -* **모델(Model)**: 사실 모델은 “구조”나 “가중치”만큼 구체적이지 않은, 다소 뭉뚱그려 사용되는 용어입니다. 이 강의에서는 모호함을 피하기 위해 *구조(architecture)*와 *체크포인트(checkpoint)*를 구분해서 사용하도록 하겠습니다. +- **구조(Architecture)**: 모델의 뼈대를 의미하는 용어로, 모델 내부의 각 레이어와 각 연산 작용들을 의미합니다. +- 체크포인트(**Checkpoints)**: 주어진 구조(architecture)에 적용될 가중치들을 의미합니다. +- 모델(**Model)**: 사실 모델은 “구조”나 “가중치”만큼 구체적이지 않은 두루뭉실한 용어입니다. 이 강의에서는 모호함을 피하기 위해 *구조(architecture)*와 *체크포인트(checkpoint)*를 구분해서 사용하도록 하겠습니다. -예를 들면, BERT는 구조에 해당하고, Google 팀이 최초 공개에서 내놓은 학습 가중치 셋인 `bert-base-cased`는 체크포인에 해당합니다. 그렇지만 “BERT 모델”, “`bert-base-cased` 모델” 등과 같이 구분하지 않고 사용하기도 합니다. +예를 들어, BERT는 구조인 반면, Google 팀이 최초 공개에서 내놓은 학습된 가중치 모음인 `bert-base-cased` 는 체크포인트입니다. 그치만 “BERT 모델”, “`bert-base-cased` 모델” 등과 같이 혼용해도 괜찮습니다. \ No newline at end of file diff --git a/chapters/ko/chapter1/5.mdx b/chapters/ko/chapter1/5.mdx index 3c133aea8..755310f6c 100644 --- a/chapters/ko/chapter1/5.mdx +++ b/chapters/ko/chapter1/5.mdx @@ -14,4 +14,4 @@ - [BERT](https://huggingface.co/transformers/model_doc/bert.html) - [DistilBERT](https://huggingface.co/transformers/model_doc/distilbert.html) - [ELECTRA](https://huggingface.co/transformers/model_doc/electra.html) -- [RoBERTa](https://huggingface.co/transformers/model_doc/roberta.html) +- [RoBERTa](https://huggingface.co/transformers/model_doc/roberta.html) \ No newline at end of file diff --git a/chapters/ko/chapter1/6.mdx b/chapters/ko/chapter1/6.mdx index 121403b4d..4f8f0afa8 100644 --- a/chapters/ko/chapter1/6.mdx +++ b/chapters/ko/chapter1/6.mdx @@ -13,4 +13,4 @@ - [CTRL](https://huggingface.co/transformers/model_doc/ctrl.html) - [GPT](https://huggingface.co/transformers/model_doc/gpt.html) - [GPT-2](https://huggingface.co/transformers/model_doc/gpt2.html) -- [Transformer XL](https://huggingface.co/transformers/model_doc/transformerxl.html) +- [Transformer XL](https://huggingface.co/transformers/model_doc/transformerxl.html) \ No newline at end of file diff --git a/chapters/ko/chapter1/7.mdx b/chapters/ko/chapter1/7.mdx index 98aad86e9..2cca23686 100644 --- a/chapters/ko/chapter1/7.mdx +++ b/chapters/ko/chapter1/7.mdx @@ -2,7 +2,7 @@ -인코더-디코더 모델(Encoder-decoder models) (*시퀀스-투-시퀀스 모델(sequence-to-sequence models)*로 부르기도 합니다)은 트랜스포머 구조의 인코더, 디코더 둘을 모두 사용합니다. 각 단계마다, 인코더의 어텐션 레이어는 초기 문장의 모든 단어에 액세스 할 수 있는 반면, 디코더의 어텐션 레이어는 주어진 단어 앞에 위치한 단어들에만 액세스 할 수 있습니다. +인코더-디코더 모델(Encoder-decoder models)로도 불리는 *시퀀스-투-시퀀스 모델(sequence-to-sequence models)*은 트랜스포머 구조의 인코더, 디코더 둘을 모두 사용합니다. 각 단계마다, 인코더의 어텐션 레이어는 초기 문장의 모든 단어에 액세스 할 수 있는 반면, 디코더의 어텐션 레이어는 주어진 단어 앞에 위치한 단어들에만 액세스 할 수 있습니다. 이러한 모델의 사전 학습은 인코더 혹은 디코더 모델의 방식을 모두 사용할 수 있지만 조금 더 복잡합니다. 이를테면, [T5](https://huggingface.co/t5-base)는 (여러 단어를 포함하기도 하는) 임의의 텍스트 범위를 하나의 특수 마스크 토큰으로 바꾸고 마스크 단어를 대체할 텍스트를 예측하는 방식으로 사전 학습 되었습니다. diff --git a/chapters/ko/chapter1/8.mdx b/chapters/ko/chapter1/8.mdx index edbd32548..919cadd54 100644 --- a/chapters/ko/chapter1/8.mdx +++ b/chapters/ko/chapter1/8.mdx @@ -1,17 +1,17 @@ # 편향과 한계 사전 학습된 혹은 미세 조정된 모델을 프로덕션 단계에서 사용하실 계획이라면, 이러한 모델들은 강력한 툴이지만 한계가 있음을 반드시 명심하셔야 합니다. 가장 큰 한계점은 리서처들이 무수히 많은 양의 데이터를 사전 학습에 사용하기 위해, 인터넷상에서 모을 수 있는 양질의 데이터와 함께 그렇지 않은 데이터까지 수집했을 가능성이 있다는 것입니다. -이를 빠르게 보여드리기 위해 `fill-mask` 파이프라인에 BERT 모델을 연결한 예제를 다시 살펴보겠습니다: +이를 빠르게 보여드리기 위해 `fill-mask` pipeline에 BERT 모델을 연결한 예제를 다시 살펴보겠습니다: -```python +``` from transformers import pipeline unmasker = pipeline("fill-mask", model="bert-base-uncased") @@ -20,13 +20,15 @@ print([r["token_str"] for r in result]) result = unmasker("This woman works as a [MASK].") print([r["token_str"] for r in result]) + ``` -```python out +``` ['lawyer', 'carpenter', 'doctor', 'waiter', 'mechanic'] ['nurse', 'waitress', 'teacher', 'maid', 'prostitute'] + ``` -주어의 성별만 바꾼 두 문장에서 빠진 단어를 채울 때, 모델은 성별과 관계 없는 공통 답변(waiter/waitress)을 하나만 내놓았습니다. 다른 답변들은 일반적으로 특정 성별에 편향된 답변이었습니다. 이를테면, 모델은 매춘이라는 단어와 연관된 상위 5개의 단어에 “여성”과 “일”을 포함시켰습니다. BERT가 전체 인터넷 상의 텍스트를 이용하여 사전 학습된 것이 아니라 [English Wikipedia](https://huggingface.co/datasets/wikipedia) 와 [BookCorpus](https://huggingface.co/datasets/bookcorpus) 같이 상당히 중립적인 데이터를 이용해 사전 학습 되었음에도 불구하고 이러한 현상이 일어납니다. +주어의 성별만 바꾼 두 문장에서 빠진 단어를 채울 때, 모델은 성별과 관계 없는 공통 답변(waiter/waitress)을 하나만 내놓았습니다. 다른 답변들은 일반적으로 특정 성별에 편향된 답변이었습니다. 이를테면, 모델은 매춘이라는 단어와 연관된 상위 5개의 단어에 “여성”과 “일”을 포함시켰습니다. BERT가 전체 인터넷 상의 텍스트를 이용하여 사전 학습된 것이 아니라 [English Wikipedia](https://huggingface.co/datasets/wikipedia) 와 [BookCorpus](https://huggingface.co/datasets/bookcorpus) 같이 상당히 중립적인 데이터를 이용하여 사전 학습 되었음에도 불구하고 이러한 현상이 일어납니다. 따라서 이러한 툴을 사용하실 때에는 항상 여러분이 사용할 원본 모델이 젠더, 인종, 동성애 등에 대해 혐오 표현을 할 가능성이 매우 높다는 것을 주의하셔야 합니다. 이러한 모델은 미세 조정을 거쳐도 내제된 편향성을 없애지 못합니다. \ No newline at end of file diff --git a/chapters/ko/chapter1/9.mdx b/chapters/ko/chapter1/9.mdx index 191b5654d..3ebcd1701 100644 --- a/chapters/ko/chapter1/9.mdx +++ b/chapters/ko/chapter1/9.mdx @@ -1,8 +1,8 @@ # 단원 정리 -이번 단원에서는 🤗 Transformers의 하이레벨 함수인 `pipeline()` 를 사용하여 다양한 NLP 문제에 대한 접근 방식을 배웠습니다. 그리고 Hub에서 모델을 검색하여 사용하는 방법, 추론 API를 이용해 브라우저 상에서 바로 모델을 테스트 하는 방법 또한 알아보았습니다. +이번 단원에서는 🤗 Transformers의 하이레벨 함수인 `pipeline()` 를 사용하여 다양한 NLP 문제에 대한 접근 방식을 학습했습니다. 그리고 Hub에서 모델을 검색 및 사용하는 방법, Inference API를 이용해 브라우저 상에서 바로 모델을 테스트 하는 방법 또한 알아보았습니다. -지금까지 트랜스포머 모델의 대략작인 동작 방식과, 전이 학습(transfer learning) 및 미세 조정(fine-tuning)의 중요성에 알아보았습니다. 핵심은 어떤 문제를 풀고싶냐에 따라 전체 모델 구조를 다 사용하거나 인코더, 디코더만 사용할 수도 있다는 것입니다. 아래 표는 이를 요약해서 보여주고 있습니다: +지금까지 트랜스포머 모델의 대략작인 동작 방식과, 전이 학습(transfer learning)과 미세 조정(fine-tuning)의 중요성에 알아보았습니다. 핵심은 어떤 문제를 풀고싶냐에 따라 전체 모델 구조를 다 사용하거나 인코더, 디코더만 사용할 수도 있다는 것입니다. 아래 표는 이를 요약해서 보여주고 있습니다: | Model | Examples | Tasks | | --- | --- | --- | From 5d5fa1c57726e18807a3cdee8c24d4249a4ba5a4 Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Sat, 2 Apr 2022 23:57:56 +0900 Subject: [PATCH 43/73] ko/chapter0 finished --- chapters/ko/chapter0/1.mdx | 54 +++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/chapters/ko/chapter0/1.mdx b/chapters/ko/chapter0/1.mdx index 0a8dd7735..6ab7c8e23 100644 --- a/chapters/ko/chapter0/1.mdx +++ b/chapters/ko/chapter0/1.mdx @@ -1,34 +1,34 @@ -# 강의 소개 +# Introduction -Hugging Face 강의에 오신 여러분들 환영합니다! 이번 강의 소개에서는 작업 환경 설정에 대해 안내드리겠습니다. 방금 막 이번 과정을 시작하셨다면 먼저 [Chapter 1](/course/chapter1) 내용을 살펴보고 돌아오신 뒤, 환경을 설정하여 코드를 직접 실행해보시길 추천드립니다. +Welcome to the Hugging Face course! This introduction will guide you through setting up a working environment. If you're just starting the course, we recommend you first take a look at [Chapter 1](/course/chapter1), then come back and set up your environment so you can try the code yourself. -이번 과정에서 사용할 모든 라이브러리는 파이썬 패키지를 통해 사용할 수 있으므로 여기서는 파이썬 환경 설정 방법 및 필요한 라이브러리 설치 방법을 보여드리겠습니다. +All the libraries that we'll be using in this course are available as Python packages, so here we'll show you how to set up a Python environment and install the specific libraries you'll need. -작업 환경 설정 방법으로 Colab 노트북을 이용한 방법과 파이썬 가상 환경을 이용한 방법, 두 가지를 다룰 것이고 둘 중 더 마음이 가는 방식을 자유롭게 선택하셔도 됩니다. 입문자의 경우 Colab 노트북을 이용하시길 강력하게 추천합니다. +We'll cover two ways of setting up your working environment, using a Colab notebook or a Python virtual environment. Feel free to choose the one that resonates with you the most. For beginners, we strongly recommend that you get started by using a Colab notebook. -여기서 Windows 환경에 대해서는 다루지 않기 때문에 Windows에서 실행 중이시면 Colab 노트북을 이용해 아래 과정을 따라가 주시길 권장드립니다. Linux 혹은 macOS를 실행 중이시라면 어떤 방식을 택해도 무방합니다. +Note that we will not be covering the Windows system. If you're running on Windows, we recommend following along using a Colab notebook. If you're using a Linux distribution or macOS, you can use either approach described here. -대부분의 강의는 여러분이 Hugging Face 계정이 있다는 것을 전제로 하기 때문에 지금 바로 계정을 생성하시길 추천드립니다: [계정 생성하기](https://huggingface.co/join) +Most of the course relies on you having a Hugging Face account. We recommend creating one now: [create an account](https://huggingface.co/join). -## Google Colab 노트북 사용하기 +## Using a Google Colab notebook -Colab 노트북은 가장 쉬운 설정 방식입니다. 브라우저에 Colab 노트북을 켜고 바로 코딩을 시작하시면 됩니다! +Using a Colab notebook is the simplest possible setup; boot up a notebook in your browser and get straight to coding! -Colab에 익숙하지 않으시다면 [introduction](https://colab.research.google.com/notebooks/intro.ipynb) 링크를 따라 시작하시길 권장드립니다. Colab에서는 GPU, TPU와 같은 가속 하드웨어를 사용할 수 있으며 적은 양의 워크로드에 대해서는 무료입니다. +If you're not familiar with Colab, we recommend you start by following the [introduction](https://colab.research.google.com/notebooks/intro.ipynb). Colab allows you to use some accelerating hardware, like GPUs or TPUs, and it is free for smaller workloads. -Colab과 친숙해 지셨다면 새로운 노트북을 생성하여 아래와 같이 시작합니다: +Once you're comfortable moving around in Colab, create a new notebook and get started with the setup:
An empty colab notebook
-다음으로, 이번 강의에서 사용할 라이브러리를 설치합니다. 설치에는 파이썬 패키지 관리자인 `pip` 를 사용하도록 하겠습니다. 노트북 파일에서는 시스템 명령어 앞에 `!` 를 붙여 실행시킬 수 있으므로, 아래와 같이 🤗 Transformers 라이브러리를 설치할 수 있습니다: +The next step is to install the libraries that we'll be using in this course. We'll use `pip` for the installation, which is the package manager for Python. In notebooks, you can run system commands by preceding them with the `!` character, so you can install the 🤗 Transformers library as follows: ``` !pip install transformers ``` -이제 파이썬 런타임에 패키지를 가져와 패키지가 제대로 설치되었는지 확인해보겠습니다: +You can make sure the package was correctly installed by importing it within your Python runtime: ``` import transformers @@ -38,38 +38,38 @@ import transformers A gif showing the result of the two commands above: installation and import
-위의 방식으로는 아주 가벼운 버전의 🤗 Transformers가 설치되고, 이는 PyTorch나 TensorFlow와 같은 특정 기계학습 프레임워크를 포함하지 않습니다. 하지만 본 강의에서는 이 라이브러리의 아주 다양한 기능들을 사용할 예정이므로, 아래의 명령어를 통해 대부분의 예제에 필요한 종속성(dependency)을 제공하는 개발 버전을 설치하시길 바랍니다: +This installs a very light version of 🤗 Transformers. In particular, no specific machine learning frameworks (like PyTorch or TensorFlow) are installed. Since we'll be using a lot of different features of the library, we recommend installing the development version, which comes with all the required dependencies for pretty much any imaginable use case: ``` !pip install transformers[sentencepiece] ``` -설치에 시간이 조금 걸리지만 곧 강의를 위한 준비가 모두 끝납니다! +This will take a bit of time, but then you'll be ready to go for the rest of the course! -## 파이썬 가상 환경 사용하기 +## Using a Python virtual environment -파이썬 가상 환경 사용을 원하신다면 먼저 파이썬을 설치해야 합니다. 이 [가이드](https://realpython.com/installing-python/)를 따라 설치를 진행하실 수 있습니다. +If you prefer to use a Python virtual environment, the first step is to install Python on your system. We recommend following [this guide](https://realpython.com/installing-python/) to get started. -파이썬 설치가 완료되면 터미널에서 파이썬 명령어를 실행할 수 있습니다. 다음 단계로 넘어가기 전에, 다음과 같은 명령어를 실행하여 설치가 잘 되었는지 확인하세요: `python --version`. 이 때 시스템에 사용할 수 있는 파이썬 버전을 출력되어야 합니다. +Once you have Python installed, you should be able to run Python commands in your terminal. You can start by running the following command to ensure that it is correctly installed before proceeding to the next steps: `python --version`. This should print out the Python version now available on your system. -터미널에서 `python --version` 과 같은 파이썬 명령어를 실행하면, 명령어를 실행하는 프로그램을 시스템의 “메인(main)” 파이썬으로 생각해야 합니다. 이 메인 파이썬은 어떤 패키지도 설치하지 않은 상태로 유지하면서, 작업 중인 각 어플리케이션마다 별도의 환경을 생성하여 이용하는 것을 권장합니다. 이렇게 하면, 각 어플리케이션은 각각의 의존성 및 패키지를 갖게 되어 다른 어플리케이션과의 잠재적 호환성 문제를 피할 수 있습니다. +When running a Python command in your terminal, such as `python --version`, you should think of the program running your command as the "main" Python on your system. We recommend keeping this main installation free of any packages, and using it to create separate environments for each application you work on — this way, each application can have its own dependencies and packages, and you won't need to worry about potential compatibility issues with other applications. -파이썬에서 이는 [*가상 환경*](https://docs.python.org/3/tutorial/venv.html)을 통해 완수됩니다. 가상 환경은 자체 포함 디렉토리 트리로, 각 트리는 어플리케이션에게 필요한 모든 패키지와 함께 특정 파이썬 버전에 대한 파이썬 설치를 포함합니다. 이러한 가상 환경을 생성하는 방법은 여러 툴을 통해 할 수 있지만, 여기서는 공식 파이썬 패키지인 `[venv](https://docs.python.org/3/library/venv.html#module-venv)` 를 통해 생성해 보겠습니다. +In Python this is done with [*virtual environments*](https://docs.python.org/3/tutorial/venv.html), which are self-contained directory trees that each contain a Python installation with a particular Python version alongside all the packages the application needs. Creating such a virtual environment can be done with a number of different tools, but we'll use the official Python package for that purpose, which is called [`venv`](https://docs.python.org/3/library/venv.html#module-venv). -먼저, 어플리케이션을 넣어줄 디렉토리를 생성합니다. 예를 들어, 홈 디렉토리의 *transformers-course*와 같은 이름의 디렉토리를 만들어 봅시다: +First, create the directory you'd like your application to live in — for example, you might want to make a new directory called *transformers-course* at the root of your home directory: ``` mkdir ~/transformers-course cd ~/transformers-course ``` -디렉토리 내부에서, 파이썬 `venv` 모듈을 사용하여 가상 환경을 생성합니다: +From inside this directory, create a virtual environment using the Python `venv` module: ``` python -m venv .env ``` -원래 아무것도 없던 빈 폴더에 *.env*라는 디렉토리가 생기게 됩니다: +You should now have a directory called *.env* in your otherwise empty folder: ``` ls -a @@ -79,7 +79,7 @@ ls -a . .. .env ``` -`activate` 스크립트를 통해 가상 환경으로 접속할 수 있고, `deactivate` 를 통해 가상 환경 밖으로 나올 수 있습니다: +You can jump in and out of your virtual environment with the `activate` and `deactivate` scripts: ``` # Activate the virtual environment @@ -89,7 +89,7 @@ source .env/bin/activate source .env/bin/deactivate ``` -환경이 제대로 활성화 되었는지 `which python` 명령어를 실행하여 확인해 봅시다. 아래와 같이 가상 환경을 보여준다면 제대로 활성화가 것입니다! +You can make sure that the environment is activated by running the `which python` command: if it points to the virtual environment, then you have successfully activated it! ``` which python @@ -99,12 +99,12 @@ which python /home//transformers-course/.env/bin/python ``` -### 의존성(dependencies) 설치하기 +### Installing dependencies -Google Colab 사용법에서와 마찬가지로 다음 단계로 넘어가기 위해 패키지를 설치해야 합니다. 여기서도, `pip` 패키지 관리자를 통해 🤗 Transformers 개발 버전을 설치할 수 있습니다: +As in the previous section on using Google Colab instances, you'll now need to install the packages required to continue. Again, you can install the development version of 🤗 Transformers using the `pip` package manager: ``` pip install "transformers[sentencepiece]" ``` -이제 모든 환경 설정을 마치고 시작할 준비가 되었습니다! +You're now all set up and ready to go! From c07f2ee8e60813533849f49170138008e67f6b2b Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Sun, 3 Apr 2022 00:20:08 +0900 Subject: [PATCH 44/73] ko/chapter0 finished --- chapters/ko/chapter0/1.mdx | 73 ++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/chapters/ko/chapter0/1.mdx b/chapters/ko/chapter0/1.mdx index 6ab7c8e23..eaf1f232b 100644 --- a/chapters/ko/chapter0/1.mdx +++ b/chapters/ko/chapter0/1.mdx @@ -1,85 +1,92 @@ -# Introduction +# 강의 소개 -Welcome to the Hugging Face course! This introduction will guide you through setting up a working environment. If you're just starting the course, we recommend you first take a look at [Chapter 1](/course/chapter1), then come back and set up your environment so you can try the code yourself. +Hugging Face 강의에 오신 여러분들 환영합니다! 이번 강의 소개에서는 작업 환경 설정에 대해 안내드리겠습니다. 방금 막 이번 과정을 시작하셨다면 먼저 [Chapter 1](notion://www.notion.so/course/chapter1) 내용을 살펴보고 돌아오신 뒤, 환경을 설정하여 코드를 직접 실행해보시길 추천드립니다. -All the libraries that we'll be using in this course are available as Python packages, so here we'll show you how to set up a Python environment and install the specific libraries you'll need. +이번 과정에서 사용할 모든 라이브러리는 파이썬 패키지를 통해 사용할 수 있으므로 여기서는 파이썬 환경 설정 방법 및 필요한 라이브러리 설치 방법을 보여드리겠습니다. -We'll cover two ways of setting up your working environment, using a Colab notebook or a Python virtual environment. Feel free to choose the one that resonates with you the most. For beginners, we strongly recommend that you get started by using a Colab notebook. +작업 환경 설정 방법으로 Colab 노트북을 이용한 방법과 파이썬 가상 환경을 이용한 방법, 두 가지를 다룰 것이고 둘 중 더 마음이 가는 방식을 자유롭게 선택하셔도 됩니다. 입문자의 경우 Colab 노트북을 이용하시길 강력하게 추천합니다. -Note that we will not be covering the Windows system. If you're running on Windows, we recommend following along using a Colab notebook. If you're using a Linux distribution or macOS, you can use either approach described here. +여기서 Windows 환경에 대해서는 다루지 않기 때문에 Windows에서 실행 중이시면 Colab 노트북을 이용해 아래 과정을 따라가 주시길 권장드립니다. Linux 혹은 macOS를 실행 중이시라면 어떤 방식을 택해도 무방합니다. -Most of the course relies on you having a Hugging Face account. We recommend creating one now: [create an account](https://huggingface.co/join). +대부분의 강의는 여러분이 Hugging Face 계정이 있다는 것을 전제로 하기 때문에 지금 바로 계정을 생성하시길 추천드립니다: [계정 생성하기](https://huggingface.co/join) -## Using a Google Colab notebook +## Google Colab 노트북 사용하기 -Using a Colab notebook is the simplest possible setup; boot up a notebook in your browser and get straight to coding! +Colab 노트북은 가장 쉬운 설정 방식입니다. 브라우저에 노트북을 켜고 망설이지 말고 바로 코딩을 시작하세요! -If you're not familiar with Colab, we recommend you start by following the [introduction](https://colab.research.google.com/notebooks/intro.ipynb). Colab allows you to use some accelerating hardware, like GPUs or TPUs, and it is free for smaller workloads. +Colab에 익숙하지 않으시다면 [introduction](https://colab.research.google.com/notebooks/intro.ipynb) 링크를 따라 시작하시길 권장드립니다. Colab에서는 GPU, TPU와 같은 가속 하드웨어를 사용할 수 있으며 적은 양의 워크로드에 대해서는 무료입니다. -Once you're comfortable moving around in Colab, create a new notebook and get started with the setup: +Colab과 친숙해지셨다면 새로운 노트북을 생성하여 아래 설정을 시작하세요:
-An empty colab notebook +An empty colab notebook
-The next step is to install the libraries that we'll be using in this course. We'll use `pip` for the installation, which is the package manager for Python. In notebooks, you can run system commands by preceding them with the `!` character, so you can install the 🤗 Transformers library as follows: +다음은 이번 강의에서 사용할 라이브러리를 설치할 단계입니다. 설치에는 파이썬 패키지 관리자인 `pip` 를 사용하도록 하겠습니다. 노트북 파일에서 시스템 명령어 앞에 문자 `!` 를 붙여 실행시킬 수 있고, 아래와 같이 🤗 Transformers 라이브러리를 설치할 수 있습니다: ``` !pip install transformers + ``` -You can make sure the package was correctly installed by importing it within your Python runtime: +이제 파이썬 런타임에 패키지를 가져와 패키지가 제대로 설치되었는지 확인해보겠습니다: ``` import transformers + ```
-A gif showing the result of the two commands above: installation and import +A gif showing the result of the two commands above: installation and import
-This installs a very light version of 🤗 Transformers. In particular, no specific machine learning frameworks (like PyTorch or TensorFlow) are installed. Since we'll be using a lot of different features of the library, we recommend installing the development version, which comes with all the required dependencies for pretty much any imaginable use case: +위의 방식으로는 PyTorch나 TensorFlow와 같은 특정 머신 러닝 프레임워크를 포함하지 않는, 아주 가벼운 버전의 🤗 Transformers가 설치됩니다. 본 강의에서는 라이브러리의 수많은 다양한 기능들을 사용합니다. 따라서, 실상 거의 모든 예제에 필요한 종속성(dependency)을 제공하는 개발 버전을 설치하시길 바랍니다: ``` !pip install transformers[sentencepiece] + ``` -This will take a bit of time, but then you'll be ready to go for the rest of the course! +설치에 시간이 조금 걸리겠지만 이제 나머지 강의를 위한 준비를 모두 마쳤습니다! -## Using a Python virtual environment +## 파이썬 가상 환경 사용하기 -If you prefer to use a Python virtual environment, the first step is to install Python on your system. We recommend following [this guide](https://realpython.com/installing-python/) to get started. +파이썬 가상 환경 사용을 원하신다면 우선 시스템에 파이썬을 설치해야 합니다. 이 [가이드](https://realpython.com/installing-python/)를 따라 시작해보세요. -Once you have Python installed, you should be able to run Python commands in your terminal. You can start by running the following command to ensure that it is correctly installed before proceeding to the next steps: `python --version`. This should print out the Python version now available on your system. +파이썬 설치가 완료되면 터미널에서 파이썬 명령어를 실행할 수 있습니다. 다음 단계로 넘어가기 전에, 다음과 같은 명령어를 실행하여 설치가 잘 되었는지 확인하세요: `python --version`. 이 때 시스템에 사용할 수 있는 파이썬 버전을 출력되어야 합니다. -When running a Python command in your terminal, such as `python --version`, you should think of the program running your command as the "main" Python on your system. We recommend keeping this main installation free of any packages, and using it to create separate environments for each application you work on — this way, each application can have its own dependencies and packages, and you won't need to worry about potential compatibility issues with other applications. +터미널에서 `python --version` 과 같은 파이썬 명령어를 실행하면, 명령어를 실행하는 프로그램을 시스템의 “메인(main)” 파이썬으로 생각해야 합니다. 이 메인 설치에 패키지를 설치하지 않은 채로 놔두시고, 이를 작업 중인 각 어플리케이션에 별도의 환경을 생성하는 데에 이용하는 것을 추천드립니다. 이렇게 하면, 각 어플리케이션은 각각의 의존성과 패키지를 갖게 되어 서로 다른 어플리케이션과 추후에 호환성 문제로부터 자유롭게 됩니다. -In Python this is done with [*virtual environments*](https://docs.python.org/3/tutorial/venv.html), which are self-contained directory trees that each contain a Python installation with a particular Python version alongside all the packages the application needs. Creating such a virtual environment can be done with a number of different tools, but we'll use the official Python package for that purpose, which is called [`venv`](https://docs.python.org/3/library/venv.html#module-venv). +파이썬에서 이는 *[가상 환경](https://docs.python.org/3/tutorial/venv.html)*을 통해 완수됩니다. 가상 환경은 자체 포함 디렉토리 트리로, 각 트리는 어플리케이션에게 필요한 모든 패키지와 함께 특정 파이썬 버전에 대한 파이썬 설치를 포함합니다. 이러한 가상 환경을 생성하는 방법은 여러 툴을 통해 할 수 있지만, 여기서는 공식 파이썬 패키지인 `[venv](https://docs.python.org/3/library/venv.html#module-venv)` 를 통해 생성해 보겠습니다. -First, create the directory you'd like your application to live in — for example, you might want to make a new directory called *transformers-course* at the root of your home directory: +먼저, 여러분의 어플리케이션을 넣어줄 디렉토리를 생성하세요. 예를 들어, 여러분의 홈 디렉토리의 *transformers-course*와 같은 이름의 디렉토리를 만들어 볼까요?: ``` mkdir ~/transformers-course cd ~/transformers-course + ``` -From inside this directory, create a virtual environment using the Python `venv` module: +디렉토리 내부에서, 파이썬 `venv` 모듈을 사용하여 가상 환경을 생성합니다: ``` python -m venv .env + ``` -You should now have a directory called *.env* in your otherwise empty folder: +원래 아무것도 없던 빈 폴더에 *.env*라는 디렉토리가 생기게 됩니다: ``` ls -a + ``` -```out +``` . .. .env + ``` -You can jump in and out of your virtual environment with the `activate` and `deactivate` scripts: +`activate` 스크립트를 통해 가상 환경으로 접속할 수 있고, `deactivate` 를 통해 가상 환경 밖으로 나올 수 있습니다: ``` # Activate the virtual environment @@ -87,24 +94,28 @@ source .env/bin/activate # Deactivate the virtual environment source .env/bin/deactivate + ``` -You can make sure that the environment is activated by running the `which python` command: if it points to the virtual environment, then you have successfully activated it! +환경이 제대로 활성화 되는지 `which python` 명령어를 실행하여 확인해보세요. 아래와 같이 가상 환경을 가리킨다면 활성화가 완료된 것입니다! ``` which python + ``` -```out +``` /home//transformers-course/.env/bin/python + ``` -### Installing dependencies +### 의존성(dependencies) 설치하기 -As in the previous section on using Google Colab instances, you'll now need to install the packages required to continue. Again, you can install the development version of 🤗 Transformers using the `pip` package manager: +Google Colab 사용법에서와 마찬가지로 다음 단계로 넘어가기 위해 패키지를 설치해야 합니다. 여기서도, `pip` 패키지 관리자를 통해 🤗 Transformers 개발 버전을 설치할 수 있습니다: ``` pip install "transformers[sentencepiece]" + ``` -You're now all set up and ready to go! +이제 모든 설정이 끝났고 시작할 준비를 마쳤습니다! \ No newline at end of file From 44654de0e6e2b1a09462d4391d8a2e0910a7f54b Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Sun, 3 Apr 2022 22:28:49 +0900 Subject: [PATCH 45/73] reviewed by @bzantium ko/chapter0 --- chapters/ko/chapter0/1.mdx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/chapters/ko/chapter0/1.mdx b/chapters/ko/chapter0/1.mdx index eaf1f232b..051bb609c 100644 --- a/chapters/ko/chapter0/1.mdx +++ b/chapters/ko/chapter0/1.mdx @@ -12,17 +12,17 @@ Hugging Face 강의에 오신 여러분들 환영합니다! 이번 강의 소개 ## Google Colab 노트북 사용하기 -Colab 노트북은 가장 쉬운 설정 방식입니다. 브라우저에 노트북을 켜고 망설이지 말고 바로 코딩을 시작하세요! +Colab 노트북은 가장 쉬운 설정 방식입니다. 브라우저에 Colab 노트북을 켜고 바로 코딩을 시작하시면 됩니다! Colab에 익숙하지 않으시다면 [introduction](https://colab.research.google.com/notebooks/intro.ipynb) 링크를 따라 시작하시길 권장드립니다. Colab에서는 GPU, TPU와 같은 가속 하드웨어를 사용할 수 있으며 적은 양의 워크로드에 대해서는 무료입니다. -Colab과 친숙해지셨다면 새로운 노트북을 생성하여 아래 설정을 시작하세요: +Colab과 친숙해 지셨다면 새로운 노트북을 생성하여 아래와 같이 시작합니다:
An empty colab notebook
-다음은 이번 강의에서 사용할 라이브러리를 설치할 단계입니다. 설치에는 파이썬 패키지 관리자인 `pip` 를 사용하도록 하겠습니다. 노트북 파일에서 시스템 명령어 앞에 문자 `!` 를 붙여 실행시킬 수 있고, 아래와 같이 🤗 Transformers 라이브러리를 설치할 수 있습니다: +다음으로, 이번 강의에서 사용할 라이브러리를 설치합니다. 설치에는 파이썬 패키지 관리자인 `pip` 를 사용하도록 하겠습니다. 노트북 파일에서는 시스템 명령어 앞에 `!` 를 붙여 실행시킬 수 있으므로, 아래와 같이 🤗 Transformers 라이브러리를 설치할 수 있습니다: ``` !pip install transformers @@ -40,7 +40,7 @@ import transformers A gif showing the result of the two commands above: installation and import -위의 방식으로는 PyTorch나 TensorFlow와 같은 특정 머신 러닝 프레임워크를 포함하지 않는, 아주 가벼운 버전의 🤗 Transformers가 설치됩니다. 본 강의에서는 라이브러리의 수많은 다양한 기능들을 사용합니다. 따라서, 실상 거의 모든 예제에 필요한 종속성(dependency)을 제공하는 개발 버전을 설치하시길 바랍니다: +위의 방식으로는 PyTorch나 TensorFlow와 같은 특정 기계학습 프레임워크를 포함하지 않는, 아주 가벼운 버전의 🤗 Transformers가 설치됩니다. 본 강의에서는 이 라이브러리의 많고 다양한 기능들을 사용할 예정이므로, 거의 모든 예제에 필요한 종속성(dependency)을 제공하는 개발 버전을 아래의 명령어를 통해 설치하시길 바랍니다: ``` !pip install transformers[sentencepiece] @@ -51,15 +51,15 @@ import transformers ## 파이썬 가상 환경 사용하기 -파이썬 가상 환경 사용을 원하신다면 우선 시스템에 파이썬을 설치해야 합니다. 이 [가이드](https://realpython.com/installing-python/)를 따라 시작해보세요. +파이썬 가상 환경 사용을 원하신다면 먼저 파이썬을 설치해야 합니다. 이 [가이드](https://realpython.com/installing-python/)를 따라 시작하면 됩니다. 파이썬 설치가 완료되면 터미널에서 파이썬 명령어를 실행할 수 있습니다. 다음 단계로 넘어가기 전에, 다음과 같은 명령어를 실행하여 설치가 잘 되었는지 확인하세요: `python --version`. 이 때 시스템에 사용할 수 있는 파이썬 버전을 출력되어야 합니다. -터미널에서 `python --version` 과 같은 파이썬 명령어를 실행하면, 명령어를 실행하는 프로그램을 시스템의 “메인(main)” 파이썬으로 생각해야 합니다. 이 메인 설치에 패키지를 설치하지 않은 채로 놔두시고, 이를 작업 중인 각 어플리케이션에 별도의 환경을 생성하는 데에 이용하는 것을 추천드립니다. 이렇게 하면, 각 어플리케이션은 각각의 의존성과 패키지를 갖게 되어 서로 다른 어플리케이션과 추후에 호환성 문제로부터 자유롭게 됩니다. +터미널에서 `python --version` 과 같은 파이썬 명령어를 실행하면, 명령어를 실행하는 프로그램을 시스템의 “메인(main)” 파이썬으로 생각해야 합니다. 이 메인 파이썬은 어떤 패키지도 설치하지 않은 상태로 유지하면서, 작업 중인 각 어플리케이션마다 별도의 환경을 생성하여 이용하는 것을 권장합니다. 이렇게 하면, 각 어플리케이션은 각각의 의존성 및 패키지를 갖게 되어 다른 어플리케이션과의 잠재적 호환성 문제를 피할 수 있습니다. 파이썬에서 이는 *[가상 환경](https://docs.python.org/3/tutorial/venv.html)*을 통해 완수됩니다. 가상 환경은 자체 포함 디렉토리 트리로, 각 트리는 어플리케이션에게 필요한 모든 패키지와 함께 특정 파이썬 버전에 대한 파이썬 설치를 포함합니다. 이러한 가상 환경을 생성하는 방법은 여러 툴을 통해 할 수 있지만, 여기서는 공식 파이썬 패키지인 `[venv](https://docs.python.org/3/library/venv.html#module-venv)` 를 통해 생성해 보겠습니다. -먼저, 여러분의 어플리케이션을 넣어줄 디렉토리를 생성하세요. 예를 들어, 여러분의 홈 디렉토리의 *transformers-course*와 같은 이름의 디렉토리를 만들어 볼까요?: +먼저, 어플리케이션을 넣어줄 디렉토리를 생성합니다. 예를 들어, 홈 디렉토리의 *transformers-course*와 같은 이름의 디렉토리를 만들어 봅시다: ``` mkdir ~/transformers-course @@ -97,7 +97,7 @@ source .env/bin/deactivate ``` -환경이 제대로 활성화 되는지 `which python` 명령어를 실행하여 확인해보세요. 아래와 같이 가상 환경을 가리킨다면 활성화가 완료된 것입니다! +환경이 제대로 활성화 되었는지 `which python` 명령어를 실행하여 확인해 봅시다. 아래와 같이 가상 환경을 보여준다면 제대로 활성화가 것입니다! ``` which python @@ -118,4 +118,4 @@ pip install "transformers[sentencepiece]" ``` -이제 모든 설정이 끝났고 시작할 준비를 마쳤습니다! \ No newline at end of file +이제 모든 환경 설정믈 마치고 시작할 준비가 되었습니다! \ No newline at end of file From 46d6de24dbfc537f18a69a0a9cd55cfae8aa5cfd Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Sun, 3 Apr 2022 22:44:13 +0900 Subject: [PATCH 46/73] reviewed by @bzantium chapter0 & fixed typo --- chapters/ko/chapter0/1.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ko/chapter0/1.mdx b/chapters/ko/chapter0/1.mdx index 051bb609c..194a396ee 100644 --- a/chapters/ko/chapter0/1.mdx +++ b/chapters/ko/chapter0/1.mdx @@ -118,4 +118,4 @@ pip install "transformers[sentencepiece]" ``` -이제 모든 환경 설정믈 마치고 시작할 준비가 되었습니다! \ No newline at end of file +이제 모든 환경 설정을 마치고 시작할 준비가 되었습니다! \ No newline at end of file From 08dc39b29f8be150b8c5d9e9b6dda947c72c6985 Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Sun, 3 Apr 2022 22:45:34 +0900 Subject: [PATCH 47/73] reviewed by @rainmaker712 --- chapters/ko/chapter1/1.mdx | 2 +- chapters/ko/chapter1/10.mdx | 16 ++++++++-------- chapters/ko/chapter1/2.mdx | 4 ++-- chapters/ko/chapter1/3.mdx | 34 +++++++++++++++------------------- chapters/ko/chapter1/4.mdx | 2 -- chapters/ko/chapter1/8.mdx | 2 +- 6 files changed, 27 insertions(+), 33 deletions(-) diff --git a/chapters/ko/chapter1/1.mdx b/chapters/ko/chapter1/1.mdx index 8628ea321..7ed285c2a 100644 --- a/chapters/ko/chapter1/1.mdx +++ b/chapters/ko/chapter1/1.mdx @@ -17,7 +17,7 @@ - 단원 1~4에서는 🤗 Transformers 라이브러리의 핵심 개념에 대해 소개합니다. 이번 강의 끝무렵에 아마 여러분들은 트랜스포머 모델이 어떻게 동작하는지 터득하게 될거고, [Hugging Face Hub](https://huggingface.co/models)에서 모델을 사용하고 데이터셋으로 fine-tune하고 Hub에 여러분의 모델을 공유하는 방법까지 알게 될 것입니다! - 단원 5~8은 본격적으로 전형적인 NLP 작업을 하기 앞서, 🤗 Datasets와 🤗 Tokenizers의 기초를 다룹니다. 이 부분을 모두 학습하면 여러분들은 가장 일반적인 NLP 문제를 스스로 해낼 수 있습니다. -- 단원 9~12에서는 NLP를 넘어, 트랜스포머 모델이 음성 처리 및 컴퓨터 비전에 어떻게 활용되는지 탐구합니다. 이 과정에서 여러분들의 모델 데모를 구축하고 공유하는 방법 및 이를 프로덕션 환경에 최적화하는 방법을 배우게 됩니다. 최종적으로, 여러분들은 (거의) 모든 머신 러닝 문제에 🤗 Transformers를 적용할 준비를 갖추게 됩니다! +- 단원 9~12에서는 NLP를 넘어, 트랜스포머 모델이 음성 처리 및 컴퓨터 비전에 어떻게 활용되는지 탐구합니다. 이 과정에서 여러분들의 모델 데모를 구축하고 공유하는 방법 및 이를 프로덕션 환경에 최적화하는 방법을 배우게 됩니다. 최종적으로, 여러분들은 거의 모든 기계 학습(머신 러닝) 문제에 🤗 Transformers를 적용할 준비를 갖추게 됩니다! 이번 강의는: diff --git a/chapters/ko/chapter1/10.mdx b/chapters/ko/chapter1/10.mdx index 69cf78baf..bcbe320a5 100644 --- a/chapters/ko/chapter1/10.mdx +++ b/chapters/ko/chapter1/10.mdx @@ -40,15 +40,15 @@ ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") choices={[ { text: "문장에 대해 \"positive\" 혹은 \"negative\" 로 분류한 레이블과 함께 분류 점수를 반환합니다.", -explain: "This is incorrect — this would be a sentiment-analysis pipeline." +explain: "오답입니다 — 이는 sentiment-analysis 파이프라인에 대한 설명입니다." }, { text: "이 문장을 완성할, 생성 텍스트를 반환합니다.", -explain: "This is incorrect — it would be a text-generation pipeline.", +explain: "오답입니다 — 이는 text-generation 파이프라인에 대한 설명입니다.", }, { text: "사람, 기관, 장소 등을 나타내는 단어들을 반환합니다.", -explain: "Furthermore, with grouped_entities=True, it will group together the words belonging to the same entity, like \"Hugging Face\".", +explain: "이 뿐만 아니라, grouped_entities=True를 사용해 \"Hugging Face\"와 같이 같은 개체에 해당하는 단어들을 그룹화해줍니다.", correct: true } ]} @@ -77,7 +77,7 @@ correct: true }, { text: "man", -explain: "오답입니다. 이 pipeline은 마스킹된 단어를 채워야하기에 어딘가에는 마스크 토큰이 있어야겠죠?" +explain: "오답입니다. 이 파이프라인은 마스킹된 단어를 채워야하기에 어딘가에는 마스크 토큰이 있어야겠죠?" } ]} /> @@ -95,13 +95,13 @@ result = classifier("This is a course about the Transformers library") candidate_labels=[...].", correct: true }, { -text: "한 문장이 아니라, 여러 문장을 pipeline에 넣어주어야 합니다.", -explain: "틀렸지만, 다른 pipeline과 마찬가지로 제대로 사용한다면 물론 여러 리스트의 문장도 입력으로 넣어줄 수 있습니다." +text: "한 문장이 아니라, 여러 문장을 파이프라인에 넣어주어야 합니다.", +explain: "틀렸지만, 다른 파이프라인과 마찬가지로 제대로 사용한다면 물론 여러 리스트의 문장도 입력으로 넣어줄 수 있습니다." }, { text: "늘 그렇듯 🤗 Transformers 라이브러리가 또 고장난거 아닌가요?", @@ -109,7 +109,7 @@ explain: "못 들은 걸로 하겠습니다!" }, { text: "위의 문장은 너무 짧아서, 더 긴 문장을 입력해야 합니다.", -explain: "오답입니다. 매우 긴 텍스트는 pipeline에서 처리할 때 잘리게 되는 것을 명심하세요." +explain: "오답입니다. 매우 긴 텍스트는 파이프라인에서 처리할 때 잘리게 되는 것을 명심하세요." } ]} /> diff --git a/chapters/ko/chapter1/2.mdx b/chapters/ko/chapter1/2.mdx index 3dc873652..2a9426aa7 100644 --- a/chapters/ko/chapter1/2.mdx +++ b/chapters/ko/chapter1/2.mdx @@ -4,7 +4,7 @@ ## NLP가 무엇인가요? -NLP(Natural Language Processing)란 사람의 언어와 관련된 모든 것을 이해하는 데에 중점을 둔 언어학 및 머신 러닝 분야를 말합니다. NLP의 목적은 단순히 하나의 개별 단어를 이해하는 것을 넘어, 해당 단어들의 문맥을 이해하는 것입니다. +NLP(Natural Language Processing)란 사람의 언어와 관련된 모든 것을 이해하는 데에 중점을 둔 언어학 및 기계 학습(머신 러닝) 분야를 말합니다. NLP의 목적은 단순히 하나의 개별 단어를 이해하는 것을 넘어, 해당 단어들의 문맥을 이해하는 것입니다. 아래는 가장 일반적인 NLP 작업과 그 예시입니다: @@ -18,4 +18,4 @@ NLP(Natural Language Processing)란 사람의 언어와 관련된 모든 것을 ## 왜 NLP가 어렵나요? -컴퓨터와 사람은 서로 정보를 처리하는 방식이 다릅니다. 이를테면, “나는 배고파”라는 문장을 읽을 때 우리는 바로 그 의미를 이해할 수 있습니다. 마찬가지로 “나는 배고파”, “나 슬퍼”와 같은 문장 쌍이 주어질 때, 두 문장이 얼마나 유사한지 쉽게 판단할 수 있습니다. 그러나, 머신 러닝(ML) 모델은 사람만큼 이를 쉽게 할 수 없습니다. 우선 모델이 텍스트를 학습할 수 있도록 텍스트가 처리 과정을 거쳐야 하는데, 사람의 언어 체계는 매우 복잡하기 때문에 이러한 처리가 어떻게 이루어져야 하는지 면밀히 생각해야 합니다. 따라서 텍스트 표현 방법과 관련한 수많은 연구가 진행되어 왔고, 다음 단원에서 여러분들에게 그 중 몇 가지 방법들을 소개해드리겠습니다. \ No newline at end of file +컴퓨터와 사람은 서로 정보를 처리하는 방식이 다릅니다. 이를테면, “나는 배고파”라는 문장을 읽을 때 우리는 바로 그 의미를 이해할 수 있습니다. 마찬가지로 “나는 배고파”, “나 슬퍼”와 같은 문장 쌍이 주어질 때, 두 문장이 얼마나 유사한지 쉽게 판단할 수 있습니다. 그러나, 기계 학습 모델은 사람만큼 이를 쉽게 할 수 없습니다. 우선 모델이 텍스트를 학습할 수 있도록 텍스트가 처리 과정을 거쳐야 하는데, 사람의 언어 체계는 매우 복잡하기 때문에 이러한 처리가 어떻게 이루어져야 하는지 면밀히 생각해야 합니다. 따라서 텍스트 표현 방법과 관련한 수많은 연구가 진행되어 왔고, 다음 단원에서 여러분들에게 그 중 몇 가지 방법들을 소개해드리겠습니다. \ No newline at end of file diff --git a/chapters/ko/chapter1/3.mdx b/chapters/ko/chapter1/3.mdx index cd82ed78d..72a22f741 100644 --- a/chapters/ko/chapter1/3.mdx +++ b/chapters/ko/chapter1/3.mdx @@ -30,7 +30,7 @@ options={[ 트랜스포머 모델 안에서 무슨 일이 벌어지는지 알아보기 전에, 트랜스포머가 NLP 문제 해결에 어떻게 사용되는지 몇 가지 흥미로운 예시들을 살펴보겠습니다. -## Pipeline으로 작업하기 +## 파이프라인으로 작업하기 @@ -64,15 +64,15 @@ classifier( ``` -기본적으로 이 pipeline은 영어 감정 분석에 미세 조정(fine-tune)된 사전 학습 모델을 선택합니다. 여기서 `classifier` 객체를 생성할 때 모델이 다운로드 되며 캐싱(caching)이 이루어지는데, 재실행 시 캐싱된 모델을 사용하게 되어 모델을 다시 다운로드 하지 않습니다. +기본적으로 이 파이프라인은 영어 감정 분석에 미세 조정(fine-tune)된 사전 학습 모델을 선택합니다. 여기서 `classifier` 객체를 생성할 때 모델이 다운로드 되며 캐싱(caching)이 이루어지는데, 재실행 시 캐싱된 모델을 사용하게 되어 모델을 다시 다운로드 하지 않습니다. -텍스트를 pipeline에 넣을 때 다음과 같은 세 가지 주요 과정을 거칩니다: +텍스트를 파이프라인에 넣을 때 다음과 같은 세 가지 주요 과정을 거칩니다: 1. 텍스트가 모델이 이해할 수 있는 형태로 전처리 과정을 거칩니다. 2. 전처리된 입력이 모델 입력으로 들어갑니다. 3. 모델의 예측값이 후처리를 거쳐, 사람이 이해할 수 있는 형태로 반환됩니다. -현재까지 사용할 수 있는 pipeline([available pipelines](https://huggingface.co/transformers/main_classes/pipelines.html))은 다음과 같습니다: +현재까지 사용할 수 있는 파이프라인([available pipelines](https://huggingface.co/transformers/main_classes/pipelines.html))은 다음과 같습니다: - `feature-extraction` : 특징 추출 (텍스트에 대한 벡터 표현 추출) - `fill-mask` : 마스크 채우기 @@ -88,7 +88,7 @@ classifier( ## 제로샷 분류(Zero-shot classification) -레이블이 없는 텍스트를 분류하는 더 까다로운 과제부터 시작하겠습니다. 텍스트에 레이블을 다는 것은 시간이 많이 소요되고 도메인 지식이 필요하기 때문에 이러한 작업은 실제 프로젝트에서 아주 흔한 상황입니다. 이러한 상황에서 `zero-shot-classification` pipeline은 매우 유용합니다. 제로샷 pipeline은 사전 학습된 모델에 의존하지 않고도 분류 작업에 사용할 레이블을 특정할 수 있도록 합니다. 위의 예시에서 모델이 긍정(positive)과 부정(negative)의 두 레이블을 분류하는 샘플을 살펴보았는데, 제로샷 pipeline을 통해서는 어떠한 레이블 세트에 대해서도 분류 작업을 수행할 수 있습니다. +레이블이 없는 텍스트를 분류하는 더 까다로운 과제부터 시작하겠습니다. 텍스트에 레이블을 다는 것은 시간이 많이 소요되고 도메인 지식이 필요하기 때문에 이러한 작업은 실제 프로젝트에서 아주 흔한 상황입니다. 이러한 상황에서 `zero-shot-classification` 파이프라인은 매우 유용합니다. 제로샷 파이프라인은 사전 학습된 모델에 의존하지 않고도 분류 작업에 사용할 레이블을 특정할 수 있도록 합니다. 위의 예시에서 모델이 긍정(positive)과 부정(negative)의 두 레이블을 분류하는 샘플을 살펴보았는데, 제로샷 파이프라인을 통해서는 어떠한 레이블 세트에 대해서도 분류 작업을 수행할 수 있습니다. ``` from transformers import pipeline @@ -108,7 +108,7 @@ classifier( ``` -이러한 pipeline이 제로샷(zero-shot)이라 불리는 이유는 여러분의 데이터에 미세 조정(fine-tune)하지 않고도 사용할 수 있기 때문입니다. 제로샷은 여러분이 원하는 어떠한 레이블 목록에 대해서도 확률 점수를 바로 반환합니다. +이러한 파이프라인이 제로샷(zero-shot)이라 불리는 이유는 여러분의 데이터에 미세 조정(fine-tune)하지 않고도 사용할 수 있기 때문입니다. 제로샷은 여러분이 원하는 어떠한 레이블 목록에 대해서도 확률 점수를 바로 반환합니다. @@ -118,7 +118,7 @@ classifier( ## 텍스트 생성(Text generation) -지금부터 pipeline을 사용해 텍스트를 생성하는 방법을 알아보겠습니다. 여기서의 핵심은 프롬트를 모델에 제공하면 모델이 나머지 텍스트를 생성하여 이를 자동으로 완성하는 것입니다. 이는 스마트폰의 텍스트 자동 완성 기능과 유사합니다. 텍스트 생성에는 랜덤하게 결과를 생성하는 과정이 포함되어 있어서 여러분이 아래와 같이 동일하게 입력을 넣어도 매번 다른 결과가 나올 수 있습니다. +지금부터 파이프라인을 사용해 텍스트를 생성하는 방법을 알아보겠습니다. 여기서의 핵심은 프롬트를 모델에 제공하면 모델이 나머지 텍스트를 생성하여 이를 자동으로 완성하는 것입니다. 이는 스마트폰의 텍스트 자동 완성 기능과 유사합니다. 텍스트 생성에는 랜덤하게 결과를 생성하는 과정이 포함되어 있어서 여러분이 아래와 같이 동일하게 입력을 넣어도 매번 다른 결과가 나올 수 있습니다. ``` from transformers import pipeline @@ -145,11 +145,11 @@ generator("In this course, we will teach you how to") -## Pipeline에 Hub의 모델 적용하기 +## 파이프라인에 Hub의 모델 적용하기 지금까지 예제들은 해당 작업에 대해 기본 모델들을 사용했지만, 특정 모델을 Hub에서 선택해 텍스트 생성과 같은 특정 작업에 대한 파이프라인에서도 사용할 수 있습니다. [Model Hub](https://huggingface.co/models) 페이지의 화면 왼쪽에 태그를 클릭하여 해당 태그 내용 작업을 지원하는 모델을 확인할 수 있습니다. [다음](https://huggingface.co/models?pipeline_tag=text-generation)과 같은 페이지로 이동하게 됩니다. -함께 `[distilgpt2](https://huggingface.co/distilgpt2)` 모델을 사용해봐요! 위의 예제에서 사용한 pipeline에서 아래와 같이 로드 할 수 있습니다: +함께 `[distilgpt2](https://huggingface.co/distilgpt2)` 모델을 사용해봐요! 위의 예제에서 사용한 파이프라인에서 아래와 같이 로드 할 수 있습니다: ``` from transformers import pipeline @@ -178,7 +178,7 @@ generator( -**✏️ 직접 해보기!** 영어를 제외한 다른 언어를 생성하는 모델을 검색해보세요. 위젯을 자유롭게 사용해 보시고 pipeline을 사용해보세요! +**✏️ 직접 해보기!** 영어를 제외한 다른 언어를 생성하는 모델을 검색해보세요. 위젯을 자유롭게 사용해 보시고 파이프라인을 사용해보세요! @@ -190,7 +190,7 @@ generator( ## 마스크 채우기(Mask filling) -다음으로 사용해볼 pipeline은 마스크 채우기(`fill-mask`)입니다. 이 작업의 핵심 아이디어는 주어진 텍스트의 빈칸을 채우기입니다: +다음으로 사용해볼 파이프라인은 마스크 채우기(`fill-mask`)입니다. 이 작업의 핵심 아이디어는 주어진 텍스트의 빈칸을 채우기입니다: ``` from transformers import pipeline @@ -242,7 +242,7 @@ ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") 모델이 정확하게 Sylvain을 사람(PER)으로, Hugging Face를 기관(ORG)으로, Brooklyn을 장소(LOC)으로 예측했네요! -Pipeline을 생성하는 함수에 `grouped_entities=True` 옵션을 전달하면 pipeline이 같은 개체에 해당하는 문장 부분을 다시 그룹화합니다. 이 경우 모델은 여러 단어로 구성된 단어임에도 “Hugging”과 “Face”를 하나의 기관으로 정확히 분류하게 됩니다. 다음 단원에서도 확인하겠지만, 놀랍게도 전처리 과정에서 각 단어들은 더 작은 부분으로 쪼개지게 됩니다. 예를 들어 `Sylvain` 이라는 단어는 `S`, `##yl`, `##va`, `##in` 이렇게 네 조각으로 쪼개집니다. 후처리 단계에서 pipeline은 이 조각들을 멋지게 재그룹화합니다. +파이프라인을 생성하는 함수에 `grouped_entities=True` 옵션을 전달하면 파이프라인이 같은 개체에 해당하는 문장 부분을 다시 그룹화합니다. 이 경우 모델은 여러 단어로 구성된 단어임에도 “Hugging”과 “Face”를 하나의 기관으로 정확히 분류하게 됩니다. 다음 단원에서도 확인하겠지만, 놀랍게도 전처리 과정에서 각 단어들은 더 작은 부분으로 쪼개지게 됩니다. 예를 들어 `Sylvain` 이라는 단어는 `S`, `##yl`, `##va`, `##in` 이렇게 네 조각으로 쪼개집니다. 후처리 단계에서 파이프라인은 이 조각들을 멋지게 재그룹화합니다. @@ -252,7 +252,7 @@ Pipeline을 생성하는 함수에 `grouped_entities=True` 옵션을 전달하 ## 질의 응답(Question-answering) -질의 응답(`question-answering`) pipeline은 주어진 지문(context)의 정보를 활용하여 질문에 답을 합니다: +질의 응답(`question-answering`) 파이프라인은 주어진 지문(context)의 정보를 활용하여 질문에 답을 합니다: ``` from transformers import pipeline @@ -270,7 +270,7 @@ question_answerer( ``` -본 pipeline은 답을 새롭게 생성하지 않고 주어진 지문에서 정답을 추출하는 방식임을 잘 기억하세요. +본 파이프라인은 답을 새롭게 생성하지 않고 주어진 지문에서 정답을 추출하는 방식임을 잘 기억하세요. ## 요약(Summarization) @@ -320,8 +320,6 @@ summarizer( ## 번역(Translation) -For translation, you can use a default model if you provide a language pair in the task name (such as `"translation_en_to_fr"`), but the easiest way is to pick the model you want to use on the [Model Hub](https://huggingface.co/models). Here we'll try translating from French to English: - 번역의 경우 (`"translation_en_to_fr"` 와 같이) 작업명에 언어 쌍을 넣어준다면 기본 모델을 사용할 수 있지만, [Model Hub](https://huggingface.co/models)에서 원하는 모델을 고르는 방식이 가장 간단합니다. 여기서는 프랑스어에서 영어로 번역을 시도해 보겠습니다: ``` @@ -345,6 +343,4 @@ translator("Ce cours est produit par Hugging Face.") -The pipelines shown so far are mostly for demonstrative purposes. They were programmed for specific tasks and cannot perform variations of them. In the next chapter, you'll learn what's inside a `pipeline()` function and how to customize its behavior. - -지금까지 보여드린 pipeline들은 대부분 특정 작업을 위해 프로그래밍된, 다양한 변형 작업을 수행할 수 없는 데모용 pipeline입니다. 다음 단원에서는 `pipeline()` 함수 내부를 살펴보고 그 동작을 사용자가 직접 설계하는 방법을 다루겠습니다. \ No newline at end of file +지금까지 보여드린 파이프라인들은 대부분 특정 작업을 위해 프로그래밍된, 다양한 변형 작업을 수행할 수 없는 데모용 파이프라인입니다. 다음 단원에서는 `pipeline()` 함수 내부를 살펴보고 그 동작을 사용자가 직접 설계하는 방법을 다루겠습니다. \ No newline at end of file diff --git a/chapters/ko/chapter1/4.mdx b/chapters/ko/chapter1/4.mdx index b8b552039..3b041e435 100644 --- a/chapters/ko/chapter1/4.mdx +++ b/chapters/ko/chapter1/4.mdx @@ -20,8 +20,6 @@ - **2019년 10월**: [BART](https://arxiv.org/abs/1910.13461) 와 [T5](https://arxiv.org/abs/1910.10683), 동일한 구조의 (처음으로) 원본 트랜스포머 모델의 구조를 그대로 따른 두 거대 사전학습 언어 모델 - **2020년 5월**, [GPT-3](https://arxiv.org/abs/2005.14165), 미세 조정 없이도 (zero-shot learning이라 부름) 다양한 작업을 훌륭하게 수행하는 GPT-2의 더 큰 버전 -This list is far from comprehensive, and is just meant to highlight a few of the different kinds of Transformer models. Broadly, they can be grouped into three categories: - 위 리스트는 단순히 서로 다른 종류의 트랜스포머 모델들 중 몇몇을 강조하기 위한 목록일 뿐, 포괄적이지 않습니다. 넓은 관점에서 트랜스포머 모델은 아래와 같이 세 카테고리로 그룹화 할 수 있습니다: - GPT-계열 (*Auto-regressive* 트랜스포머 모델로도 불림) diff --git a/chapters/ko/chapter1/8.mdx b/chapters/ko/chapter1/8.mdx index 919cadd54..1466b0fbe 100644 --- a/chapters/ko/chapter1/8.mdx +++ b/chapters/ko/chapter1/8.mdx @@ -9,7 +9,7 @@ options={[ 사전 학습된 혹은 미세 조정된 모델을 프로덕션 단계에서 사용하실 계획이라면, 이러한 모델들은 강력한 툴이지만 한계가 있음을 반드시 명심하셔야 합니다. 가장 큰 한계점은 리서처들이 무수히 많은 양의 데이터를 사전 학습에 사용하기 위해, 인터넷상에서 모을 수 있는 양질의 데이터와 함께 그렇지 않은 데이터까지 수집했을 가능성이 있다는 것입니다. -이를 빠르게 보여드리기 위해 `fill-mask` pipeline에 BERT 모델을 연결한 예제를 다시 살펴보겠습니다: +이를 빠르게 보여드리기 위해 `fill-mask` 파이프라인에 BERT 모델을 연결한 예제를 다시 살펴보겠습니다: ``` from transformers import pipeline From 98501f6c629b68a19318ea7db109f1302fdcaac6 Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Sun, 3 Apr 2022 22:56:43 +0900 Subject: [PATCH 48/73] maximize Korean expressions --- chapters/ko/chapter1/1.mdx | 2 +- chapters/ko/chapter1/10.mdx | 2 +- chapters/ko/chapter1/3.mdx | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/chapters/ko/chapter1/1.mdx b/chapters/ko/chapter1/1.mdx index 7ed285c2a..3a657a966 100644 --- a/chapters/ko/chapter1/1.mdx +++ b/chapters/ko/chapter1/1.mdx @@ -15,7 +15,7 @@ -- 단원 1~4에서는 🤗 Transformers 라이브러리의 핵심 개념에 대해 소개합니다. 이번 강의 끝무렵에 아마 여러분들은 트랜스포머 모델이 어떻게 동작하는지 터득하게 될거고, [Hugging Face Hub](https://huggingface.co/models)에서 모델을 사용하고 데이터셋으로 fine-tune하고 Hub에 여러분의 모델을 공유하는 방법까지 알게 될 것입니다! +- 단원 1~4에서는 🤗 Transformers 라이브러리의 핵심 개념에 대해 소개합니다. 이번 강의 끝무렵에 아마 여러분들은 트랜스포머 모델이 어떻게 동작하는지 터득하게 될거고, [Hugging Face Hub](https://huggingface.co/models)에서 모델을 사용하고 데이터셋으로 미세 조정(fine-tune)하고 Hub에 여러분의 모델을 공유하는 방법까지 알게 될 것입니다! - 단원 5~8은 본격적으로 전형적인 NLP 작업을 하기 앞서, 🤗 Datasets와 🤗 Tokenizers의 기초를 다룹니다. 이 부분을 모두 학습하면 여러분들은 가장 일반적인 NLP 문제를 스스로 해낼 수 있습니다. - 단원 9~12에서는 NLP를 넘어, 트랜스포머 모델이 음성 처리 및 컴퓨터 비전에 어떻게 활용되는지 탐구합니다. 이 과정에서 여러분들의 모델 데모를 구축하고 공유하는 방법 및 이를 프로덕션 환경에 최적화하는 방법을 배우게 됩니다. 최종적으로, 여러분들은 거의 모든 기계 학습(머신 러닝) 문제에 🤗 Transformers를 적용할 준비를 갖추게 됩니다! diff --git a/chapters/ko/chapter1/10.mdx b/chapters/ko/chapter1/10.mdx index bcbe320a5..ae80692e5 100644 --- a/chapters/ko/chapter1/10.mdx +++ b/chapters/ko/chapter1/10.mdx @@ -2,7 +2,7 @@ # 단원 마무리 퀴즈 -이번 단원에서는 정말 많은 내용을 다뤘습니다! 그러니 모든 디테일을 이해하지 못했다고 해서 좌절하지 마세요. 다음 단원은 내부 작동 방식을 이해하는 데에 도움이 될거에요. +이번 챕터에서는 정말 많은 내용들을 다뤘습니다! 그러니 모든 디테일을 이해하지 못했다고 해서 좌절하지 마세요. 다음 단원은 내부 작동 방식을 이해하는 데에 도움이 될거에요. 그래도 우선, 이번 단원에서 배운 내용에 대해 확인해보는 시간을 갖도록 하겠습니다! diff --git a/chapters/ko/chapter1/3.mdx b/chapters/ko/chapter1/3.mdx index 72a22f741..ae47531b2 100644 --- a/chapters/ko/chapter1/3.mdx +++ b/chapters/ko/chapter1/3.mdx @@ -21,7 +21,7 @@ options={[ Companies using Hugging Face -[🤗 Transformers library](https://github.com/huggingface/transformers)는 이렇게 공유한 모델을 사용하고 구축하는 기능들을 제공합니다. [Model Hub](https://huggingface.co/models)에서는 모두가 다운로드 받아 쓸 수 있는 수 천 개의 사전 학습된 모델들이 여러분을 기다리고 있습니다. 여러분만의 모델을 Hub에 업로드하는 것 또한 가능합니다! +[🤗 Transformers 라이브러리](https://github.com/huggingface/transformers)는 이렇게 공유한 모델을 사용하고 구축하는 기능들을 제공합니다. [Model Hub](https://huggingface.co/models)에서는 모두가 다운로드 받아 쓸 수 있는 수 천 개의 사전 학습된 모델들이 여러분을 기다리고 있습니다. 여러분만의 모델을 Hub에 업로드하는 것 또한 가능합니다! @@ -184,9 +184,9 @@ generator( ### 추론(Inference) API -모든 모델들은 Hugging Face [웹사이트](https://huggingface.co/)에서 제공하는 추론 API를 통해 여러분의 브라우저상에서 직접 테스트가 가능합니다. 이 페이지를 통해 직접 나만의 텍스트를 입력하고 모델이 입력 데이터를 처리하는걸 구경하며 모델을 갖고 놀 수 있습니다. +모든 모델들은 [Hugging Face 웹사이트](https://huggingface.co/)에서 제공하는 추론 API를 통해 여러분의 브라우저상에서 직접 테스트가 가능합니다. 이 페이지를 통해 직접 나만의 텍스트를 입력하고 모델이 입력 데이터를 처리하는걸 구경하며 모델을 갖고 놀 수 있습니다. -위젯을 구동하는 추론 API는 간편한 워크플로우를 가능하게 하는 유료 버전의 제품으로도 이용 가능합니다. 자세한 사항은 [가격 페이지](https://huggingface.co/pricing)를 참고해주세요. +위젯을 구동하는 추론 API는 간편한 워크플로우를 가능하게 하는 유료 버전의 제품으로도 이용 가능합니다. 자세한 사항은 [가격 정책 페이지](https://huggingface.co/pricing)를 참고해주세요. ## 마스크 채우기(Mask filling) From 5204d77fde1f8e19f5b9a4f45286756deee68750 Mon Sep 17 00:00:00 2001 From: m_khandaker Date: Mon, 4 Apr 2022 16:34:51 +0900 Subject: [PATCH 49/73] [Chapter 1] bangla traslation initial commit --- chapters/bn/chapter0/1.mdx | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/chapters/bn/chapter0/1.mdx b/chapters/bn/chapter0/1.mdx index ab323044e..be248acba 100644 --- a/chapters/bn/chapter0/1.mdx +++ b/chapters/bn/chapter0/1.mdx @@ -14,15 +14,15 @@ Colab নোটবুক বা পাইথন virtual environment ব্যব Colab নোটবুক ব্যবহার করার সবচেয়ে সহজ সেটআপ হচ্ছে ব্রাউজারে একটি নোটবুক ওপেন করুন এবং সরাসরি কোডিং এ যান! -আপনি যদি Colab-এর সাথে পরিচিত না হন তাহলে আমরা আপনাকে [Colab পরিচয়](https://colab.research.google.com/notebooks/intro.ipynb) অনুসরণ করে শুরু করার পরামর্শ দিচ্ছি। Colab আপনাকে কিছু এক্সেলারেসন হার্ডওয়্যার ব্যবহার করতে দেয়, যেমন GPUs বা TPUs যা ছোট ওয়ার্ক লোডের জন্য ফ্রি। +আপনি যদি Colab-এর সাথে পরিচিত না হন তাহলে আমরা আপনাকে [পরিচয়](https://colab.research.google.com/notebooks/intro.ipynb) অনুসরণ করে শুরু করার পরামর্শ দিচ্ছি। Colab আপনাকে কিছু এক্সেলারেসন হার্ডওয়্যার ব্যবহার করতে দেয়, যেমন GPUs বা TPUs এবং এটি ছোট ওয়ার্ক লোডের জন্য ফ্রি। -Colab-এর উপর আপানার হাত চলে আসলে একটি নতুন নোটবুক ওপেন করে সেট-আপ শুরু করুন: +Colab-এর আপানার হাত চলে আসলে, একটি নতুন নোটবুক ওপেন করে সেট-আপ শুরু করুন:
-An empty colab notebook +An empty colab notebook
-পরবর্তী ধাপে আমরা এই কোর্সে ব্যবহার হবে এমন লাইব্রেরিগুলি ইনস্টল করা দেখাবো। আমরা ইনস্টলেশনের জন্য পাইথনের প্যাকেজ ম্যানেজার `pip` ব্যবহার করব। নোটবুকগুলিতে, আপনি `!` অক্ষর দিয়ে আগে সিস্টেম কমান্ড চালাতে পারবেন। যেমন ধরুন, নিচের কমান্ডটি দিয়ে 🤗 Transformers লাইব্রেরি ইনস্টল করতে পারবেন: +পরবর্তী ধাপে আমরা এই কোর্সে ব্যবহার হবে এমন লাইব্রেরিগুলি ইনস্টল করা দেখাবো। আমরা ইনস্টলেশনের জন্য `pip` ব্যবহার করব, যা পাইথনের প্যাকেজ ম্যানেজার। নোটবুকগুলিতে, আপনি `!` অক্ষর দিয়ে আগে সিস্টেম কমান্ড চালাতে পারবেন। যেমন ধরুন, নিচের কমান্ডটি দিয়ে 🤗 Transformers লাইব্রেরি ইনস্টল করতে পারবেন: ``` !pip install transformers @@ -50,11 +50,11 @@ import transformers আপনি যদি পাইথন virtual environment ব্যবহার করতে পছন্দ করেন, প্রথম ধাপ হল আপনার সিস্টেমে পাইথন ইনস্টল করা। শুরু করার জন্য আমরা [এই নির্দেশিকা](https://realpython.com/installing-python/) অনুসরণ করার পরামর্শ দিচ্ছি। -একবার আপনি পাইথন ইনস্টল করলে, আপনি আপনার টার্মিনালে পাইথন কমান্ড চালাতে সক্ষম হবেন। পরবর্তী ধাপে যাওয়ার আগে এটি সঠিকভাবে ইনস্টল করা হয়েছে তা নিশ্চিত করতে আপনি নিম্নলিখিত কমান্ডটি চালিয়ে শুরু করতে পারেন: `python --version`। এটি আপনার সিস্টেমে ইনস্টল হওয়া পাইথন সংস্করণটি প্রিন্ট করা উচিত। +একবার আপনি পাইথন ইনস্টল করলে, আপনি আপনার টার্মিনালে পাইথন কমান্ড চালাতে সক্ষম হবেন। পরবর্তী ধাপে যাওয়ার আগে এটি সঠিকভাবে ইনস্টল করা হয়েছে তা নিশ্চিত করতে আপনি নিম্নলিখিত কমান্ডটি চালিয়ে শুরু করতে পারেন: `python --version`। এটি আপনার সিস্টেমে উপলব্ধ পাইথন সংস্করণটি প্রিন্ট করা উচিত। -আপনার টার্মিনালে পাইথন কমান্ড চালানোর সময়, যেমন `python --version`, আপানাকে ভাবতে হবে যে এটি "main" পাইথন প্রোগ্রাম যা আপানার কমান্ড টিকে রান করছে। আমরা এই মূল ইনস্টলেশনটিকে যেকোন প্যাকেজ ইনস্টল থেকে মুক্ত রাখার সুপারিশ করি। এ আপনি যখন আলাদা অ্যাপ্লিকেশনে কাজ করবেন তখন তার জন্য আলাদা virtual environment তৈরি করতে এই পাইথন ইনস্টলেশনটিকে ব্যবহার করবেন। এতে করে প্রতিটি অ্যাপ্লিকেশনের নিজস্ব ডিপেন্ডেন্সি এবং প্যাকেজ আলাদা থাকবে এবং অন্যান্য অ্যাপ্লিকেশনের সাথে এর সম্ভাব্য কম্পাটিবিলটি নিয়ে আপানকে সমস্যায় করতে হবে না। +আপনার টার্মিনালে পাইথন কমান্ড চালানোর সময়, যেমন `python --version`, আপনার সিস্টেমে "main" পাইথন হিসাবে আপনার কমান্ডটি চালানোর প্রোগ্রামটিকে ভাবতে হবে। আমরা এই মূল ইনস্টলেশনটিকে যেকোন প্যাকেজ ইনস্টল থেকে মুক্ত রাখার সুপারিশ করি। এ আপনি যখন আলাদা অ্যাপ্লিকেশনে কাজ করবেঙ তখন তার জন্য আলাদা virtual environment তৈরি করতে এই পাইথন ইনস্টলেশনটিকে ব্যবহার করবেন। এতে করে প্রতিটি অ্যাপ্লিকেশনের নিজস্ব ডিপেন্ডেন্সি এবং প্যাকেজ আলাদা থাকবে এবং অন্যান্য অ্যাপ্লিকেশনের সাথে এর সম্ভাব্য কম্পাটিবিলটি নিয়ে আপানকে সমস্যায় করতে হবে না। -পাইথনে এটি [*virtual environments*](https://docs.python.org/3/tutorial/venv.html) দিয়ে করা হয়, যেটি স্বয়ংসম্পূর্ণ ডিরেক্টরি ট্রি। যার প্রত্যেকটিতে এপ্লিকেশনের প্রয়োজনীয় সমস্ত প্যাকেজের পাশাপাশি একটি নির্দিষ্ট পাইথন ভার্শনের পাইথন ইনস্টলেশন আছে। এই ধরনের একটি virtual environments বিভিন্ন ভাবে তৈরি করা যেতে পারে। তবে আমরা এর জন্য অফিসিয়াল পাইথন প্যাকেজ ব্যবহার করব, যাকে বলা হয় [`venv`](https://docs.python.org/3/library) /venv.html#module-venv)। +পাইথনে এটি [*virtual environments*](https://docs.python.org/3/tutorial/venv.html) দিয়ে করা হয়, যেটি স্বয়ংসম্পূর্ণ ডিরেক্টরি ট্রি। যার প্রত্যেকটিতে এপ্লিকেশন প্রয়োজনীয় সমস্ত প্যাকেজের পাশাপাশি একটি নির্দিষ্ট পাইথন ভার্শনের পাইথন ইনস্টলেশন আছে। এই ধরনের একটি virtual environments তৈরি করা বিভিন্ন ভাবে করা যেতে পারে। তবে আমরা এর জন্য অফিসিয়াল পাইথন প্যাকেজ ব্যবহার করব, যাকে বলা হয় [`venv`](https://docs.python.org/3/library) /venv.html#module-venv)। প্রথমে, আপনি যে ডিরেক্টরিটি আপনার অ্যাপ্লিকেশনটিতে রাখতে চান তা তৈরি করুন — উদাহরণস্বরূপ, আপনি আপনার হোম ডিরেক্টরির বা ফোল্ডার ভেতর *transformers-course* নামে একটি নতুন ডিরেক্টরি তৈরি করতে চাইতে পারেন: @@ -76,11 +76,12 @@ ls -a ``` ```out -. .. .env +. .. .env ``` +আপনি এখন virtual environment টি `activate` করতে বা `deactivate` নিচের কমান্ড গুলো ব্যবহার করতে পারেন। +``` -আপনি এখন virtual environment টি `activate` করতে বা `deactivate` নিচের কমান্ড গুলো ব্যবহার করতে পারেন। ``` # virtual environment টি activate করার কমান্ড @@ -109,4 +110,4 @@ which python pip install "transformers[sentencepiece]" ```` -আপনি এখন শুরু করা জন্য সম্পূর্ণ প্রস্তুত! +আপনি এখন শুরু করা জন্য সম্পূর্ণ প্রস্তুত! \ No newline at end of file From 0d393cc7b3510321c239a58018ddd9647fdb1a7b Mon Sep 17 00:00:00 2001 From: "Md. Al-Amin Khandaker" Date: Mon, 4 Apr 2022 16:41:12 +0900 Subject: [PATCH 50/73] Update 1.mdx update and fix formating --- chapters/bn/chapter0/1.mdx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/chapters/bn/chapter0/1.mdx b/chapters/bn/chapter0/1.mdx index be248acba..ac094fab3 100644 --- a/chapters/bn/chapter0/1.mdx +++ b/chapters/bn/chapter0/1.mdx @@ -76,12 +76,11 @@ ls -a ``` ```out -. .. .env +. .. .env ``` -আপনি এখন virtual environment টি `activate` করতে বা `deactivate` নিচের কমান্ড গুলো ব্যবহার করতে পারেন। -``` +আপনি এখন virtual environment টি `activate` করতে বা `deactivate` নিচের কমান্ড গুলো ব্যবহার করতে পারেন। ``` # virtual environment টি activate করার কমান্ড @@ -110,4 +109,4 @@ which python pip install "transformers[sentencepiece]" ```` -আপনি এখন শুরু করা জন্য সম্পূর্ণ প্রস্তুত! \ No newline at end of file +আপনি এখন শুরু করা জন্য সম্পূর্ণ প্রস্তুত! From 6dcc9b84ee7aa9fdd707f1e8dfb0660a1008a63e Mon Sep 17 00:00:00 2001 From: m_khandaker Date: Mon, 4 Apr 2022 20:49:03 +0900 Subject: [PATCH 51/73] Fix formating and typos --- chapters/bn/_toctree.yml | 173 ++++++++++++++++++++++++++++++++++++- chapters/bn/chapter0/1.mdx | 12 +-- 2 files changed, 177 insertions(+), 8 deletions(-) diff --git a/chapters/bn/_toctree.yml b/chapters/bn/_toctree.yml index 6be05c074..6c1a4730c 100644 --- a/chapters/bn/_toctree.yml +++ b/chapters/bn/_toctree.yml @@ -1,4 +1,173 @@ -- title: 0. সেটআপ +- title: 0. Setup sections: - local: chapter0/1 - title: ভূমিকা + title: Introduction + +- title: 1. Transformer models + sections: + - local: chapter1/1 + title: Introduction + - local: chapter1/2 + title: Natural Language Processing + - local: chapter1/3 + title: Transformers, what can they do? + - local: chapter1/4 + title: How do Transformers work? + - local: chapter1/5 + title: Encoder models + - local: chapter1/6 + title: Decoder models + - local: chapter1/7 + title: Sequence-to-sequence models + - local: chapter1/8 + title: Bias and limitations + - local: chapter1/9 + title: Summary + - local: chapter1/10 + title: End-of-chapter quiz + quiz: 1 + +- title: 2. Using 🤗 Transformers + sections: + - local: chapter2/1 + title: Introduction + - local: chapter2/2 + title: Behind the pipeline + - local: chapter2/3 + title: Models + - local: chapter2/4 + title: Tokenizers + - local: chapter2/5 + title: Handling multiple sequences + - local: chapter2/6 + title: Putting it all together + - local: chapter2/7 + title: Basic usage completed! + - local: chapter2/8 + title: End-of-chapter quiz + quiz: 2 + +- title: 3. Fine-tuning a pretrained model + sections: + - local: chapter3/1 + title: Introduction + - local: chapter3/2 + title: Processing the data + - local: chapter3/3 + title: Fine-tuning a model with the Trainer API or Keras + local_fw: { pt: chapter3/3, tf: chapter3/3_tf } + - local: chapter3/4 + title: A full training + - local: chapter3/5 + title: Fine-tuning, Check! + - local: chapter3/6 + title: End-of-chapter quiz + quiz: 3 + +- title: 4. Sharing models and tokenizers + sections: + - local: chapter4/1 + title: The Hugging Face Hub + - local: chapter4/2 + title: Using pretrained models + - local: chapter4/3 + title: Sharing pretrained models + - local: chapter4/4 + title: Building a model card + - local: chapter4/5 + title: Part 1 completed! + - local: chapter4/6 + title: End-of-chapter quiz + quiz: 4 + +- title: 5. The 🤗 Datasets library + sections: + - local: chapter5/1 + title: Introduction + - local: chapter5/2 + title: What if my dataset isn't on the Hub? + - local: chapter5/3 + title: Time to slice and dice + - local: chapter5/4 + title: Big data? 🤗 Datasets to the rescue! + - local: chapter5/5 + title: Creating your own dataset + - local: chapter5/6 + title: Semantic search with FAISS + - local: chapter5/7 + title: 🤗 Datasets, check! + - local: chapter5/8 + title: End-of-chapter quiz + quiz: 5 + +- title: 6. The 🤗 Tokenizers library + sections: + - local: chapter6/1 + title: Introduction + - local: chapter6/2 + title: Training a new tokenizer from an old one + - local: chapter6/3 + title: Fast tokenizers' special powers + - local: chapter6/3b + title: Fast tokenizers in the QA pipeline + - local: chapter6/4 + title: Normalization and pre-tokenization + - local: chapter6/5 + title: Byte-Pair Encoding tokenization + - local: chapter6/6 + title: WordPiece tokenization + - local: chapter6/7 + title: Unigram tokenization + - local: chapter6/8 + title: Building a tokenizer, block by block + - local: chapter6/9 + title: Tokenizers, check! + - local: chapter6/10 + title: End-of-chapter quiz + quiz: 6 + +- title: 7. Main NLP tasks + sections: + - local: chapter7/1 + title: Introduction + - local: chapter7/2 + title: Token classification + - local: chapter7/3 + title: Fine-tuning a masked language model + - local: chapter7/4 + title: Translation + - local: chapter7/5 + title: Summarization + - local: chapter7/6 + title: Training a causal language model from scratch + - local: chapter7/7 + title: Question answering + - local: chapter7/8 + title: Mastering NLP + - local: chapter7/9 + title: End-of-chapter quiz + quiz: 7 + +- title: 8. How to ask for help + sections: + - local: chapter8/1 + title: Introduction + - local: chapter8/2 + title: What to do when you get an error + - local: chapter8/3 + title: Asking for help on the forums + - local: chapter8/4 + title: Debugging the training pipeline + local_fw: { pt: chapter8/4, tf: chapter8/4_tf } + - local: chapter8/5 + title: How to write a good issue + - local: chapter8/6 + title: Part 2 completed! + - local: chapter8/7 + title: End-of-chapter quiz + quiz: 8 + +- title: Hugging Face Course Event + sections: + - local: event/1 + title: Part 2 Release Event diff --git a/chapters/bn/chapter0/1.mdx b/chapters/bn/chapter0/1.mdx index ac094fab3..b1e5879df 100644 --- a/chapters/bn/chapter0/1.mdx +++ b/chapters/bn/chapter0/1.mdx @@ -14,15 +14,15 @@ Colab নোটবুক বা পাইথন virtual environment ব্যব Colab নোটবুক ব্যবহার করার সবচেয়ে সহজ সেটআপ হচ্ছে ব্রাউজারে একটি নোটবুক ওপেন করুন এবং সরাসরি কোডিং এ যান! -আপনি যদি Colab-এর সাথে পরিচিত না হন তাহলে আমরা আপনাকে [পরিচয়](https://colab.research.google.com/notebooks/intro.ipynb) অনুসরণ করে শুরু করার পরামর্শ দিচ্ছি। Colab আপনাকে কিছু এক্সেলারেসন হার্ডওয়্যার ব্যবহার করতে দেয়, যেমন GPUs বা TPUs এবং এটি ছোট ওয়ার্ক লোডের জন্য ফ্রি। +আপনি যদি Colab-এর সাথে পরিচিত না হন তাহলে আমরা আপনাকে [Colab পরিচয়](https://colab.research.google.com/notebooks/intro.ipynb) অনুসরণ করে শুরু করার পরামর্শ দিচ্ছি। Colab আপনাকে কিছু এক্সেলারেসন হার্ডওয়্যার ব্যবহার করতে দেয়, যেমন GPUs বা TPUs যা ছোট ওয়ার্ক লোডের জন্য ফ্রি। -Colab-এর আপানার হাত চলে আসলে, একটি নতুন নোটবুক ওপেন করে সেট-আপ শুরু করুন: +Colab-এর উপর আপানার হাত চলে আসলে একটি নতুন নোটবুক ওপেন করে সেট-আপ শুরু করুন:
An empty colab notebook
-পরবর্তী ধাপে আমরা এই কোর্সে ব্যবহার হবে এমন লাইব্রেরিগুলি ইনস্টল করা দেখাবো। আমরা ইনস্টলেশনের জন্য `pip` ব্যবহার করব, যা পাইথনের প্যাকেজ ম্যানেজার। নোটবুকগুলিতে, আপনি `!` অক্ষর দিয়ে আগে সিস্টেম কমান্ড চালাতে পারবেন। যেমন ধরুন, নিচের কমান্ডটি দিয়ে 🤗 Transformers লাইব্রেরি ইনস্টল করতে পারবেন: +পরবর্তী ধাপে আমরা এই কোর্সে ব্যবহার হবে এমন লাইব্রেরিগুলি ইনস্টল করা দেখাবো। আমরা ইনস্টলেশনের জন্য পাইথনের প্যাকেজ ম্যানেজার `pip` ব্যবহার করব। নোটবুকগুলিতে, আপনি `!` অক্ষর দিয়ে আগে সিস্টেম কমান্ড চালাতে পারবেন। যেমন ধরুন, নিচের কমান্ডটি দিয়ে 🤗 Transformers লাইব্রেরি ইনস্টল করতে পারবেন: ``` !pip install transformers @@ -50,11 +50,11 @@ import transformers আপনি যদি পাইথন virtual environment ব্যবহার করতে পছন্দ করেন, প্রথম ধাপ হল আপনার সিস্টেমে পাইথন ইনস্টল করা। শুরু করার জন্য আমরা [এই নির্দেশিকা](https://realpython.com/installing-python/) অনুসরণ করার পরামর্শ দিচ্ছি। -একবার আপনি পাইথন ইনস্টল করলে, আপনি আপনার টার্মিনালে পাইথন কমান্ড চালাতে সক্ষম হবেন। পরবর্তী ধাপে যাওয়ার আগে এটি সঠিকভাবে ইনস্টল করা হয়েছে তা নিশ্চিত করতে আপনি নিম্নলিখিত কমান্ডটি চালিয়ে শুরু করতে পারেন: `python --version`। এটি আপনার সিস্টেমে উপলব্ধ পাইথন সংস্করণটি প্রিন্ট করা উচিত। +একবার আপনি পাইথন ইনস্টল করলে, আপনি আপনার টার্মিনালে পাইথন কমান্ড চালাতে সক্ষম হবেন। পরবর্তী ধাপে যাওয়ার আগে এটি সঠিকভাবে ইনস্টল করা হয়েছে তা নিশ্চিত করতে আপনি নিম্নলিখিত কমান্ডটি চালিয়ে শুরু করতে পারেন: `python --version`। এটি আপনার সিস্টেমে ইনস্টল হওয়া পাইথন সংস্করণটি প্রিন্ট করা উচিত। -আপনার টার্মিনালে পাইথন কমান্ড চালানোর সময়, যেমন `python --version`, আপনার সিস্টেমে "main" পাইথন হিসাবে আপনার কমান্ডটি চালানোর প্রোগ্রামটিকে ভাবতে হবে। আমরা এই মূল ইনস্টলেশনটিকে যেকোন প্যাকেজ ইনস্টল থেকে মুক্ত রাখার সুপারিশ করি। এ আপনি যখন আলাদা অ্যাপ্লিকেশনে কাজ করবেঙ তখন তার জন্য আলাদা virtual environment তৈরি করতে এই পাইথন ইনস্টলেশনটিকে ব্যবহার করবেন। এতে করে প্রতিটি অ্যাপ্লিকেশনের নিজস্ব ডিপেন্ডেন্সি এবং প্যাকেজ আলাদা থাকবে এবং অন্যান্য অ্যাপ্লিকেশনের সাথে এর সম্ভাব্য কম্পাটিবিলটি নিয়ে আপানকে সমস্যায় করতে হবে না। +আপনার টার্মিনালে পাইথন কমান্ড চালানোর সময়, যেমন `python --version`, আপানাকে ভাবতে হবে যে এটি "main" পাইথন প্রোগ্রাম যা আপানার কমান্ড টিকে রান করছে। আমরা এই মূল ইনস্টলেশনটিকে যেকোন প্যাকেজ ইনস্টল থেকে মুক্ত রাখার সুপারিশ করি। এ আপনি যখন আলাদা অ্যাপ্লিকেশনে কাজ করবেন তখন তার জন্য আলাদা virtual environment তৈরি করতে এই পাইথন ইনস্টলেশনটিকে ব্যবহার করবেন। এতে করে প্রতিটি অ্যাপ্লিকেশনের নিজস্ব ডিপেন্ডেন্সি এবং প্যাকেজ আলাদা থাকবে এবং অন্যান্য অ্যাপ্লিকেশনের সাথে এর সম্ভাব্য কম্পাটিবিলটি নিয়ে আপানকে সমস্যায় করতে হবে না। -পাইথনে এটি [*virtual environments*](https://docs.python.org/3/tutorial/venv.html) দিয়ে করা হয়, যেটি স্বয়ংসম্পূর্ণ ডিরেক্টরি ট্রি। যার প্রত্যেকটিতে এপ্লিকেশন প্রয়োজনীয় সমস্ত প্যাকেজের পাশাপাশি একটি নির্দিষ্ট পাইথন ভার্শনের পাইথন ইনস্টলেশন আছে। এই ধরনের একটি virtual environments তৈরি করা বিভিন্ন ভাবে করা যেতে পারে। তবে আমরা এর জন্য অফিসিয়াল পাইথন প্যাকেজ ব্যবহার করব, যাকে বলা হয় [`venv`](https://docs.python.org/3/library) /venv.html#module-venv)। +পাইথনে এটি [*virtual environments*](https://docs.python.org/3/tutorial/venv.html) দিয়ে করা হয়, যেটি স্বয়ংসম্পূর্ণ ডিরেক্টরি ট্রি। যার প্রত্যেকটিতে এপ্লিকেশনের প্রয়োজনীয় সমস্ত প্যাকেজের পাশাপাশি একটি নির্দিষ্ট পাইথন ভার্শনের পাইথন ইনস্টলেশন আছে। এই ধরনের একটি virtual environments বিভিন্ন ভাবে তৈরি করা যেতে পারে। তবে আমরা এর জন্য অফিসিয়াল পাইথন প্যাকেজ ব্যবহার করব, যাকে বলা হয় [`venv`](https://docs.python.org/3/library) /venv.html#module-venv)। প্রথমে, আপনি যে ডিরেক্টরিটি আপনার অ্যাপ্লিকেশনটিতে রাখতে চান তা তৈরি করুন — উদাহরণস্বরূপ, আপনি আপনার হোম ডিরেক্টরির বা ফোল্ডার ভেতর *transformers-course* নামে একটি নতুন ডিরেক্টরি তৈরি করতে চাইতে পারেন: From 9126deda5119d71dc54ea53ca63171d5ed928f26 Mon Sep 17 00:00:00 2001 From: m_khandaker Date: Mon, 4 Apr 2022 21:41:41 +0900 Subject: [PATCH 52/73] translate _toctree.yml 0-1 chapter --- chapters/bn/_toctree.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/chapters/bn/_toctree.yml b/chapters/bn/_toctree.yml index 6c1a4730c..fb1fabec5 100644 --- a/chapters/bn/_toctree.yml +++ b/chapters/bn/_toctree.yml @@ -1,30 +1,30 @@ -- title: 0. Setup +- title: 0. সেটআপ sections: - local: chapter0/1 - title: Introduction + title: ভূমিকা -- title: 1. Transformer models +- title: 1. ট্রান্সফরমার মডেল sections: - local: chapter1/1 - title: Introduction + title: ভূমিকা - local: chapter1/2 - title: Natural Language Processing + title: ন্যাচারাল ল্যঙ্গুএজ প্রসেসিং - local: chapter1/3 - title: Transformers, what can they do? + title: ট্রান্সফরমার, কি করতে পারে? - local: chapter1/4 - title: How do Transformers work? + title: ট্রান্সফরমার কিভাবে কাজ করে? - local: chapter1/5 - title: Encoder models + title: এনকোডার মডেল - local: chapter1/6 - title: Decoder models + title: ডিকোডার মডেল - local: chapter1/7 - title: Sequence-to-sequence models + title: সিকোয়েন্স টু সিকোয়েন্স মডেল - local: chapter1/8 - title: Bias and limitations + title: পক্ষপাত এবং সীমাবদ্ধতা (বায়াস এবং লিমিটেশন) - local: chapter1/9 - title: Summary + title: সারসংক্ষেপ - local: chapter1/10 - title: End-of-chapter quiz + title: অধ্যায়ের শেষ কুইজ quiz: 1 - title: 2. Using 🤗 Transformers From 5fe21cee360befe8d849971462436b3f44a99d2f Mon Sep 17 00:00:00 2001 From: Lewis Tunstall Date: Mon, 4 Apr 2022 15:47:58 +0200 Subject: [PATCH 53/73] Add Korean to CI --- .github/workflows/build_documentation.yml | 2 +- .github/workflows/build_pr_documentation.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_documentation.yml b/.github/workflows/build_documentation.yml index a7714c94a..0ea12e682 100644 --- a/.github/workflows/build_documentation.yml +++ b/.github/workflows/build_documentation.yml @@ -14,6 +14,6 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: bn en es fa fr he ko pt ru th tr + languages: en es fr he ko pt th tr secrets: token: ${{ secrets.HUGGINGFACE_PUSH }} \ No newline at end of file diff --git a/.github/workflows/build_pr_documentation.yml b/.github/workflows/build_pr_documentation.yml index f7b92f51d..8fcd7524d 100644 --- a/.github/workflows/build_pr_documentation.yml +++ b/.github/workflows/build_pr_documentation.yml @@ -16,5 +16,5 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: bn en es fa fr he ko pt ru th tr + languages: en es fr he ko pt th tr hub_base_path: https://moon-ci-docs.huggingface.co/course \ No newline at end of file From 810db399944354010234fd9efa54db25ba58deee Mon Sep 17 00:00:00 2001 From: m_khandaker Date: Tue, 5 Apr 2022 22:41:38 +0900 Subject: [PATCH 54/73] remove translation from sec titles not yet translated --- chapters/bn/_toctree.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/chapters/bn/_toctree.yml b/chapters/bn/_toctree.yml index fb1fabec5..b04da2c14 100644 --- a/chapters/bn/_toctree.yml +++ b/chapters/bn/_toctree.yml @@ -6,25 +6,25 @@ - title: 1. ট্রান্সফরমার মডেল sections: - local: chapter1/1 - title: ভূমিকা + title: Introduction - local: chapter1/2 - title: ন্যাচারাল ল্যঙ্গুএজ প্রসেসিং + title: Natural Language Processing - local: chapter1/3 - title: ট্রান্সফরমার, কি করতে পারে? + title: Transformers, what can they do? - local: chapter1/4 - title: ট্রান্সফরমার কিভাবে কাজ করে? + title: How do Transformers work? - local: chapter1/5 - title: এনকোডার মডেল + title: Encoder models - local: chapter1/6 - title: ডিকোডার মডেল + title: Decoder models - local: chapter1/7 - title: সিকোয়েন্স টু সিকোয়েন্স মডেল + title: Sequence-to-sequence models - local: chapter1/8 - title: পক্ষপাত এবং সীমাবদ্ধতা (বায়াস এবং লিমিটেশন) + title: Bias and limitations - local: chapter1/9 - title: সারসংক্ষেপ + title: Summary - local: chapter1/10 - title: অধ্যায়ের শেষ কুইজ + title: End-of-chapter quiz quiz: 1 - title: 2. Using 🤗 Transformers From 5fc58d03ccb114caa0d7737793d33f614dd2c309 Mon Sep 17 00:00:00 2001 From: Lewis Tunstall Date: Tue, 5 Apr 2022 15:55:49 +0200 Subject: [PATCH 55/73] Add authors [th ru] --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 2b70941d7..a10534eef 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ This repo contains the content that's used to create the **[Hugging Face course] | Language | Source | Authors | |:-------------------------------------------------------|:-----------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [English](https://huggingface.co/course/en/chapter1/1) | [`chapters/en`](https://github.com/huggingface/course/tree/main/chapters/en) | [@sgugger](https://github.com/sgugger), [@lewtun](https://github.com/lewtun), [@LysandreJik](https://github.com/LysandreJik), [@Rocketknight1](https://github.com/Rocketknight1), [@sashavor](https://github.com/sashavor), [@osanseviero](https://github.com/osanseviero), [@SaulLu](https://github.com/SaulLu), [@lvwerra](https://github.com/lvwerra) | -| [Korean](https://huggingface.co/course/ko/chapter1/1) (WIP) | [`chapters/ko`](https://github.com/huggingface/course/tree/main/chapters/ko) | [@Doohae](https://github.com/Doohae) | | [Russian](https://huggingface.co/course/ru/chapter1/1) (WIP) | [`chapters/ru`](https://github.com/huggingface/course/tree/main/chapters/ru) | [@pdumin](https://github.com/pdumin) | | [Spanish](https://huggingface.co/course/es/chapter1/1) (WIP) | [`chapters/es`](https://github.com/huggingface/course/tree/main/chapters/es) | [@camartinezbu](https://github.com/camartinezbu) | | [Thai](https://huggingface.co/course/th/chapter1/1) (WIP) | [`chapters/th`](https://github.com/huggingface/course/tree/main/chapters/th) | [@peeraponw](https://github.com/peeraponw), [@a-krirk](https://github.com/a-krirk), [@jomariya23156](https://github.com/jomariya23156) | From 41c466ab3176f69e4506b33badb29ffb22f546e7 Mon Sep 17 00:00:00 2001 From: m_khandaker Date: Tue, 5 Apr 2022 23:55:23 +0900 Subject: [PATCH 56/73] [FIX] _toctree.yml --- chapters/bn/_toctree.yml | 169 --------------------------------------- 1 file changed, 169 deletions(-) diff --git a/chapters/bn/_toctree.yml b/chapters/bn/_toctree.yml index b04da2c14..6be05c074 100644 --- a/chapters/bn/_toctree.yml +++ b/chapters/bn/_toctree.yml @@ -2,172 +2,3 @@ sections: - local: chapter0/1 title: ভূমিকা - -- title: 1. ট্রান্সফরমার মডেল - sections: - - local: chapter1/1 - title: Introduction - - local: chapter1/2 - title: Natural Language Processing - - local: chapter1/3 - title: Transformers, what can they do? - - local: chapter1/4 - title: How do Transformers work? - - local: chapter1/5 - title: Encoder models - - local: chapter1/6 - title: Decoder models - - local: chapter1/7 - title: Sequence-to-sequence models - - local: chapter1/8 - title: Bias and limitations - - local: chapter1/9 - title: Summary - - local: chapter1/10 - title: End-of-chapter quiz - quiz: 1 - -- title: 2. Using 🤗 Transformers - sections: - - local: chapter2/1 - title: Introduction - - local: chapter2/2 - title: Behind the pipeline - - local: chapter2/3 - title: Models - - local: chapter2/4 - title: Tokenizers - - local: chapter2/5 - title: Handling multiple sequences - - local: chapter2/6 - title: Putting it all together - - local: chapter2/7 - title: Basic usage completed! - - local: chapter2/8 - title: End-of-chapter quiz - quiz: 2 - -- title: 3. Fine-tuning a pretrained model - sections: - - local: chapter3/1 - title: Introduction - - local: chapter3/2 - title: Processing the data - - local: chapter3/3 - title: Fine-tuning a model with the Trainer API or Keras - local_fw: { pt: chapter3/3, tf: chapter3/3_tf } - - local: chapter3/4 - title: A full training - - local: chapter3/5 - title: Fine-tuning, Check! - - local: chapter3/6 - title: End-of-chapter quiz - quiz: 3 - -- title: 4. Sharing models and tokenizers - sections: - - local: chapter4/1 - title: The Hugging Face Hub - - local: chapter4/2 - title: Using pretrained models - - local: chapter4/3 - title: Sharing pretrained models - - local: chapter4/4 - title: Building a model card - - local: chapter4/5 - title: Part 1 completed! - - local: chapter4/6 - title: End-of-chapter quiz - quiz: 4 - -- title: 5. The 🤗 Datasets library - sections: - - local: chapter5/1 - title: Introduction - - local: chapter5/2 - title: What if my dataset isn't on the Hub? - - local: chapter5/3 - title: Time to slice and dice - - local: chapter5/4 - title: Big data? 🤗 Datasets to the rescue! - - local: chapter5/5 - title: Creating your own dataset - - local: chapter5/6 - title: Semantic search with FAISS - - local: chapter5/7 - title: 🤗 Datasets, check! - - local: chapter5/8 - title: End-of-chapter quiz - quiz: 5 - -- title: 6. The 🤗 Tokenizers library - sections: - - local: chapter6/1 - title: Introduction - - local: chapter6/2 - title: Training a new tokenizer from an old one - - local: chapter6/3 - title: Fast tokenizers' special powers - - local: chapter6/3b - title: Fast tokenizers in the QA pipeline - - local: chapter6/4 - title: Normalization and pre-tokenization - - local: chapter6/5 - title: Byte-Pair Encoding tokenization - - local: chapter6/6 - title: WordPiece tokenization - - local: chapter6/7 - title: Unigram tokenization - - local: chapter6/8 - title: Building a tokenizer, block by block - - local: chapter6/9 - title: Tokenizers, check! - - local: chapter6/10 - title: End-of-chapter quiz - quiz: 6 - -- title: 7. Main NLP tasks - sections: - - local: chapter7/1 - title: Introduction - - local: chapter7/2 - title: Token classification - - local: chapter7/3 - title: Fine-tuning a masked language model - - local: chapter7/4 - title: Translation - - local: chapter7/5 - title: Summarization - - local: chapter7/6 - title: Training a causal language model from scratch - - local: chapter7/7 - title: Question answering - - local: chapter7/8 - title: Mastering NLP - - local: chapter7/9 - title: End-of-chapter quiz - quiz: 7 - -- title: 8. How to ask for help - sections: - - local: chapter8/1 - title: Introduction - - local: chapter8/2 - title: What to do when you get an error - - local: chapter8/3 - title: Asking for help on the forums - - local: chapter8/4 - title: Debugging the training pipeline - local_fw: { pt: chapter8/4, tf: chapter8/4_tf } - - local: chapter8/5 - title: How to write a good issue - - local: chapter8/6 - title: Part 2 completed! - - local: chapter8/7 - title: End-of-chapter quiz - quiz: 8 - -- title: Hugging Face Course Event - sections: - - local: event/1 - title: Part 2 Release Event From 5a9ac2a07bb3973f23fb12dbdc28dc65bcdaac31 Mon Sep 17 00:00:00 2001 From: "Md. Al-Amin Khandaker" Date: Wed, 6 Apr 2022 00:42:18 +0900 Subject: [PATCH 57/73] Update chapters/bn/chapter0/1.mdx [FIX] syntax formatting Co-authored-by: lewtun --- chapters/bn/chapter0/1.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/bn/chapter0/1.mdx b/chapters/bn/chapter0/1.mdx index b1e5879df..ab323044e 100644 --- a/chapters/bn/chapter0/1.mdx +++ b/chapters/bn/chapter0/1.mdx @@ -19,7 +19,7 @@ Colab নোটবুক ব্যবহার করার সবচেয় Colab-এর উপর আপানার হাত চলে আসলে একটি নতুন নোটবুক ওপেন করে সেট-আপ শুরু করুন:
-An empty colab notebook +An empty colab notebook
পরবর্তী ধাপে আমরা এই কোর্সে ব্যবহার হবে এমন লাইব্রেরিগুলি ইনস্টল করা দেখাবো। আমরা ইনস্টলেশনের জন্য পাইথনের প্যাকেজ ম্যানেজার `pip` ব্যবহার করব। নোটবুকগুলিতে, আপনি `!` অক্ষর দিয়ে আগে সিস্টেম কমান্ড চালাতে পারবেন। যেমন ধরুন, নিচের কমান্ডটি দিয়ে 🤗 Transformers লাইব্রেরি ইনস্টল করতে পারবেন: From 69edf60c2e53768b8ba4bfd96be8e0bf39f0d311 Mon Sep 17 00:00:00 2001 From: DOOHAE JUNG Date: Wed, 6 Apr 2022 01:52:48 +0900 Subject: [PATCH 58/73] tag typos & indentation & unnatural expressions --- chapters/ko/_toctree.yml | 3 +- chapters/ko/chapter0/1.mdx | 31 +--- chapters/ko/chapter1/1.mdx | 30 +-- chapters/ko/chapter1/10.mdx | 361 ++++++++++++++++++------------------ chapters/ko/chapter1/2.mdx | 6 +- chapters/ko/chapter1/3.mdx | 130 ++++++------- chapters/ko/chapter1/4.mdx | 84 +++++---- chapters/ko/chapter1/5.mdx | 2 +- chapters/ko/chapter1/6.mdx | 2 +- chapters/ko/chapter1/7.mdx | 2 +- chapters/ko/chapter1/8.mdx | 16 +- chapters/ko/chapter1/9.mdx | 4 +- 12 files changed, 324 insertions(+), 347 deletions(-) diff --git a/chapters/ko/_toctree.yml b/chapters/ko/_toctree.yml index 0bdd36db3..fe4e110ef 100644 --- a/chapters/ko/_toctree.yml +++ b/chapters/ko/_toctree.yml @@ -25,4 +25,5 @@ title: 단원 정리 - local: chapter1/10 title: 단원 마무리 퀴즈 - quiz: 1 \ No newline at end of file + quiz: 1 + \ No newline at end of file diff --git a/chapters/ko/chapter0/1.mdx b/chapters/ko/chapter0/1.mdx index 194a396ee..0a8dd7735 100644 --- a/chapters/ko/chapter0/1.mdx +++ b/chapters/ko/chapter0/1.mdx @@ -1,6 +1,6 @@ # 강의 소개 -Hugging Face 강의에 오신 여러분들 환영합니다! 이번 강의 소개에서는 작업 환경 설정에 대해 안내드리겠습니다. 방금 막 이번 과정을 시작하셨다면 먼저 [Chapter 1](notion://www.notion.so/course/chapter1) 내용을 살펴보고 돌아오신 뒤, 환경을 설정하여 코드를 직접 실행해보시길 추천드립니다. +Hugging Face 강의에 오신 여러분들 환영합니다! 이번 강의 소개에서는 작업 환경 설정에 대해 안내드리겠습니다. 방금 막 이번 과정을 시작하셨다면 먼저 [Chapter 1](/course/chapter1) 내용을 살펴보고 돌아오신 뒤, 환경을 설정하여 코드를 직접 실행해보시길 추천드립니다. 이번 과정에서 사용할 모든 라이브러리는 파이썬 패키지를 통해 사용할 수 있으므로 여기서는 파이썬 환경 설정 방법 및 필요한 라이브러리 설치 방법을 보여드리겠습니다. @@ -19,71 +19,64 @@ Colab에 익숙하지 않으시다면 [introduction](https://colab.research.goog Colab과 친숙해 지셨다면 새로운 노트북을 생성하여 아래와 같이 시작합니다:
-An empty colab notebook +An empty colab notebook
다음으로, 이번 강의에서 사용할 라이브러리를 설치합니다. 설치에는 파이썬 패키지 관리자인 `pip` 를 사용하도록 하겠습니다. 노트북 파일에서는 시스템 명령어 앞에 `!` 를 붙여 실행시킬 수 있으므로, 아래와 같이 🤗 Transformers 라이브러리를 설치할 수 있습니다: ``` !pip install transformers - ``` 이제 파이썬 런타임에 패키지를 가져와 패키지가 제대로 설치되었는지 확인해보겠습니다: ``` import transformers - ```
-A gif showing the result of the two commands above: installation and import +A gif showing the result of the two commands above: installation and import
-위의 방식으로는 PyTorch나 TensorFlow와 같은 특정 기계학습 프레임워크를 포함하지 않는, 아주 가벼운 버전의 🤗 Transformers가 설치됩니다. 본 강의에서는 이 라이브러리의 많고 다양한 기능들을 사용할 예정이므로, 거의 모든 예제에 필요한 종속성(dependency)을 제공하는 개발 버전을 아래의 명령어를 통해 설치하시길 바랍니다: +위의 방식으로는 아주 가벼운 버전의 🤗 Transformers가 설치되고, 이는 PyTorch나 TensorFlow와 같은 특정 기계학습 프레임워크를 포함하지 않습니다. 하지만 본 강의에서는 이 라이브러리의 아주 다양한 기능들을 사용할 예정이므로, 아래의 명령어를 통해 대부분의 예제에 필요한 종속성(dependency)을 제공하는 개발 버전을 설치하시길 바랍니다: ``` !pip install transformers[sentencepiece] - ``` -설치에 시간이 조금 걸리겠지만 이제 나머지 강의를 위한 준비를 모두 마쳤습니다! +설치에 시간이 조금 걸리지만 곧 강의를 위한 준비가 모두 끝납니다! ## 파이썬 가상 환경 사용하기 -파이썬 가상 환경 사용을 원하신다면 먼저 파이썬을 설치해야 합니다. 이 [가이드](https://realpython.com/installing-python/)를 따라 시작하면 됩니다. +파이썬 가상 환경 사용을 원하신다면 먼저 파이썬을 설치해야 합니다. 이 [가이드](https://realpython.com/installing-python/)를 따라 설치를 진행하실 수 있습니다. 파이썬 설치가 완료되면 터미널에서 파이썬 명령어를 실행할 수 있습니다. 다음 단계로 넘어가기 전에, 다음과 같은 명령어를 실행하여 설치가 잘 되었는지 확인하세요: `python --version`. 이 때 시스템에 사용할 수 있는 파이썬 버전을 출력되어야 합니다. 터미널에서 `python --version` 과 같은 파이썬 명령어를 실행하면, 명령어를 실행하는 프로그램을 시스템의 “메인(main)” 파이썬으로 생각해야 합니다. 이 메인 파이썬은 어떤 패키지도 설치하지 않은 상태로 유지하면서, 작업 중인 각 어플리케이션마다 별도의 환경을 생성하여 이용하는 것을 권장합니다. 이렇게 하면, 각 어플리케이션은 각각의 의존성 및 패키지를 갖게 되어 다른 어플리케이션과의 잠재적 호환성 문제를 피할 수 있습니다. -파이썬에서 이는 *[가상 환경](https://docs.python.org/3/tutorial/venv.html)*을 통해 완수됩니다. 가상 환경은 자체 포함 디렉토리 트리로, 각 트리는 어플리케이션에게 필요한 모든 패키지와 함께 특정 파이썬 버전에 대한 파이썬 설치를 포함합니다. 이러한 가상 환경을 생성하는 방법은 여러 툴을 통해 할 수 있지만, 여기서는 공식 파이썬 패키지인 `[venv](https://docs.python.org/3/library/venv.html#module-venv)` 를 통해 생성해 보겠습니다. +파이썬에서 이는 [*가상 환경*](https://docs.python.org/3/tutorial/venv.html)을 통해 완수됩니다. 가상 환경은 자체 포함 디렉토리 트리로, 각 트리는 어플리케이션에게 필요한 모든 패키지와 함께 특정 파이썬 버전에 대한 파이썬 설치를 포함합니다. 이러한 가상 환경을 생성하는 방법은 여러 툴을 통해 할 수 있지만, 여기서는 공식 파이썬 패키지인 `[venv](https://docs.python.org/3/library/venv.html#module-venv)` 를 통해 생성해 보겠습니다. 먼저, 어플리케이션을 넣어줄 디렉토리를 생성합니다. 예를 들어, 홈 디렉토리의 *transformers-course*와 같은 이름의 디렉토리를 만들어 봅시다: ``` mkdir ~/transformers-course cd ~/transformers-course - ``` 디렉토리 내부에서, 파이썬 `venv` 모듈을 사용하여 가상 환경을 생성합니다: ``` python -m venv .env - ``` 원래 아무것도 없던 빈 폴더에 *.env*라는 디렉토리가 생기게 됩니다: ``` ls -a - ``` -``` +```out . .. .env - ``` `activate` 스크립트를 통해 가상 환경으로 접속할 수 있고, `deactivate` 를 통해 가상 환경 밖으로 나올 수 있습니다: @@ -94,19 +87,16 @@ source .env/bin/activate # Deactivate the virtual environment source .env/bin/deactivate - ``` 환경이 제대로 활성화 되었는지 `which python` 명령어를 실행하여 확인해 봅시다. 아래와 같이 가상 환경을 보여준다면 제대로 활성화가 것입니다! ``` which python - ``` -``` +```out /home//transformers-course/.env/bin/python - ``` ### 의존성(dependencies) 설치하기 @@ -115,7 +105,6 @@ Google Colab 사용법에서와 마찬가지로 다음 단계로 넘어가기 ``` pip install "transformers[sentencepiece]" - ``` -이제 모든 환경 설정을 마치고 시작할 준비가 되었습니다! \ No newline at end of file +이제 모든 환경 설정을 마치고 시작할 준비가 되었습니다! diff --git a/chapters/ko/chapter1/1.mdx b/chapters/ko/chapter1/1.mdx index 3a657a966..3bfb81f49 100644 --- a/chapters/ko/chapter1/1.mdx +++ b/chapters/ko/chapter1/1.mdx @@ -4,40 +4,40 @@ -이번 강의에서는 [Hugging Face](https://huggingface.co/) 환경의 라이브러리([🤗 Transformers](https://github.com/huggingface/transformers), [🤗 Datasets](https://github.com/huggingface/datasets), [🤗 Tokenizers](https://github.com/huggingface/tokenizers), [🤗 Accelerate](https://github.com/huggingface/accelerate))와 [Hugging Face Hub](https://huggingface.co/models) 를 이용해 자연어 처리(NLP)에 대해 배워보겠습니다. (무료 강의에 광고도 없는건 비밀이에요!) +이번 강의에서는 [Hugging Face](https://huggingface.co/) 환경의 라이브러리([🤗 Transformers](https://github.com/huggingface/transformers), [🤗 Datasets](https://github.com/huggingface/datasets), [🤗 Tokenizers](https://github.com/huggingface/tokenizers), [🤗 Accelerate](https://github.com/huggingface/accelerate))와 [Hugging Face Hub](https://huggingface.co/models) 를 이용해 자연어 처리(NLP)에 대해 배워보겠습니다. (무료 강의에 광고도 없는건 비밀입니다!) ## 무엇을 배우나요? 강의 개요 훑어보기:
-Brief overview of the chapters of the course. - +Brief overview of the chapters of the course. +
-- 단원 1~4에서는 🤗 Transformers 라이브러리의 핵심 개념에 대해 소개합니다. 이번 강의 끝무렵에 아마 여러분들은 트랜스포머 모델이 어떻게 동작하는지 터득하게 될거고, [Hugging Face Hub](https://huggingface.co/models)에서 모델을 사용하고 데이터셋으로 미세 조정(fine-tune)하고 Hub에 여러분의 모델을 공유하는 방법까지 알게 될 것입니다! -- 단원 5~8은 본격적으로 전형적인 NLP 작업을 하기 앞서, 🤗 Datasets와 🤗 Tokenizers의 기초를 다룹니다. 이 부분을 모두 학습하면 여러분들은 가장 일반적인 NLP 문제를 스스로 해낼 수 있습니다. -- 단원 9~12에서는 NLP를 넘어, 트랜스포머 모델이 음성 처리 및 컴퓨터 비전에 어떻게 활용되는지 탐구합니다. 이 과정에서 여러분들의 모델 데모를 구축하고 공유하는 방법 및 이를 프로덕션 환경에 최적화하는 방법을 배우게 됩니다. 최종적으로, 여러분들은 거의 모든 기계 학습(머신 러닝) 문제에 🤗 Transformers를 적용할 준비를 갖추게 됩니다! +- 챕터 1~4에서는 🤗 Transformers 라이브러리의 핵심 개념에 대해 소개합니다. 이 부분을 마치면 트랜스포머 모델의 동작 원리를 이해하실 수 있고, [Hugging Face Hub](https://huggingface.co/models)에서 모델을 사용하여 데이터셋으로 미세 조정(fine-tune)한 후 Hub에 모델을 공유하는 방법까지 터득하게 될 것입니다! +- 챕터 5~8은 본격적으로 고전 NLP 업무를 수행하기 앞서, 🤗 Datasets와 🤗 Tokenizers의 기초에 대해 알아봅니다. 이 부분을 모두 학습하시면 일반적인 NLP 문제를 스스로 해낼 수 있게 됩니다. +- 챕터 9~12에서는 트랜스포머 모델이 NLP 문제를 넘어, 음성 처리 및 컴퓨터 비전에 어떻게 활용되는지 탐구합니다. 이 과정에서 모델 데모를 구축하고 공유하는 방법과 이를 프로덕션 환경에 최적화하는 방법을 공부합니다. 이러한 과정을 거쳐서, 여러분들은 거의 모든 기계 학습(머신 러닝) 문제에 🤗 Transformers를 적용할 준비를 갖추게 됩니다! 이번 강의는: -- 파이썬에 대한 기초 지식이 필요합니다 -- [DeepLearning.AI](https://www.deeplearning.ai/) 의 프로그램이나 [fast.ai's](https://www.fast.ai/) [Practical Deep Learning for Coders](https://course.fast.ai/) 와 같은 딥러닝에 대한 기초 강의를 듣고 수강하면 더욱 효과적입니다 -- [PyTorch](https://pytorch.org/) , [TensorFlow](https://www.tensorflow.org/) 에 대한 선수 지식이 필요하지 않지만, 이에 익숙하다면 도움이 될 것입니다 +* 파이썬에 대한 기초 지식이 필요합니다 +* [DeepLearning.AI](https://www.deeplearning.ai/) 의 프로그램이나 [fast.ai's](https://www.fast.ai/) [Practical Deep Learning for Coders](https://course.fast.ai/) 와 같은 딥러닝에 대한 기초 강의를 듣고 수강하면 더욱 효과적입니다 +* [PyTorch](https://pytorch.org/) , [TensorFlow](https://www.tensorflow.org/) 에 대한 선수 지식이 필요하지는 않지만, 이에 익숙하시다면 도움이 될 것입니다 -본 강의를 모두 수강한 후, [DeepLearning.AI](http://deeplearning.ai/)의 [Natural Language Processing Specialization](https://www.coursera.org/specializations/natural-language-processing?utm_source=deeplearning-ai&utm_medium=institutions&utm_campaign=20211011-nlp-2-hugging_face-page-nlp-refresh)을 살펴보시길 권장드립니다. 해당 과정에서는 Naive Bayes, LSTM과 같은 알아두면 너무나 유용한 더 넓은 범위의 전통 NLP 모델에 대해 학습할 수 있습니다! +본 강의를 모두 수강한 후, DeepLearning.AI의 [Natural Language Processing Specialization](https://www.coursera.org/specializations/natural-language-processing?utm_source=deeplearning-ai&utm_medium=institutions&utm_campaign=20211011-nlp-2-hugging_face-page-nlp-refresh)을 학습하시길 권장드립니다. 해당 과정에서는 Naive Bayes, LSTM과 같은 알아두면 너무나 유용한 더 넓은 범위의 전통 NLP 모델에 대해 학습할 수 있습니다! ## 우리가 누구일까요? 저자 소개: -**Matthew Carrigan**은 Hugging Face의 머신 러닝 엔지니어입니다. 현재 아일랜드 더블린에 살고 있으며, 이전에는 [Parse.ly](http://parse.ly/) 에서 ML 엔지니어로, 그 전에는 Trinity Collge Dublin에서 박사 과정 이후 연구원으로 근무했습니다. 우리가 기존 인공지능 아키텍쳐를 확장하여 사람 수준에는 도달하지 못할거라고 생각하지만, 그럼에도 불멸 로봇(immortality robot)에 대해 큰 기대를 갖고 있습니다. +**Matthew Carrigan**은 Hugging Face의 머신 러닝 엔지니어입니다. 현재 아일랜드 더블린에 살고 있으며, 이전에는 [Parse.ly](http://parse.ly/) 에서 ML 엔지니어로, 그 전에는 Trinity Collge Dublin에서 박사 과정 이후 연구원으로 근무했습니다. 사람이 기존 인공지능 아키텍쳐를 확장하여 사람 수준에는 도달하지 못할거라고 생각하지만, 그럼에도 불멸 로봇(immortality robot)에 대해 큰 기대를 갖고 있습니다. -**Lysandre Debut**는 Hugging Face의 머신 러닝 엔지니어이며 초창기부터 🤗 Transformers 라이브러리 작업을 함께 했습니다. 아주 간단한 API를 개발하여 모두가 NLP를 쉽게 사용할 수 있도록 하는 목표를 갖고 있습니다. +**Lysandre Debut**는 Hugging Face의 머신 러닝 엔지니어이며 초창기부터 🤗 Transformers 라이브러리 작업을 함께 했습니다. 아주 사용하기 쉬운 API를 개발하여 모두가 NLP를 쉽게 사용할 수 있도록 하는 목표를 갖고 있습니다. **Sylvain Gugger**는 Hugging Face의 리서치 엔지니어로 🤗 Transformers 라이브러리의 주요 관리자 중 한명입니다. 이전에 [fast.ai](http://fast.ai/) 에서 리서치 사이언티스트로 있었으며 Jeremy Howard와 함께 *[Deep Learning for Coders with fastai and PyTorch](https://learning.oreilly.com/library/view/deep-learning-for/9781492045519/)* 를 저술했습니다. 적은 리소스에서도 모델이 빠르게 학습되도록 기술을 디자인하고 개선하여 딥러닝에 보다 쉽게 접근할 수 있도록 하는 것을 리서치의 가장 큰 목표로 삼고 있습니다. -**Merve Noyan**은 Hugging Face의 개발자 애드보케이트로, 모두를 위한 민주적인 머신 러닝 생태계를 만들고자 개발툴 작업 및 주변 컨텐츠 구축 작업을 담당합니다. +**Merve Noyan**은 Hugging Face의 개발자 애드보케이트로, 모두에게 평등한 민주적인 머신 러닝 생태계를 만드는 목표를 갖고 있으며, 개발툴 작업 및 주변 컨텐츠 구축 작업을 담당하고 있습니다. **Lucile Saulnier**은 Hugging Face의 ML 엔지니어로 오픈 소스 툴 사용에 대한 개발 및 지원을 담당합니다. 자연어 처리 분야에서 협업 학습, BigScience등과 같은 다양한 리서치 프로젝트에도 활발히 참여하고 있습니다. @@ -45,8 +45,8 @@ **Leandro von Werra**는 Hugging Face 오픈소스 팀의 머신 러닝 엔지니어이자 곧 출간될 [O’Reilly book on Transformers](https://www.oreilly.com/library/view/natural-language-processing/9781098103231/)의 공동 저자입니다. 모든 머신 러닝 스택에서의 작업을 통해 수 년간 NLP 프로젝트를 프로덕션으로 들여온 경력자입니다. -시작할 준비가 되셨나요? 이번 단원에서 다룰 내용은 다음과 같습니다: +시작할 준비가 되셨나요? 이번 챕터에서 다룰 내용은 다음과 같습니다: - 텍스트 생성 및 분류와 같은 NLP 문제를 푸는 `pipeline()` 함수 사용법 - 트랜스포머 모델 구조 -- 인코더(encoder), 디코더(decoder), 인코더-디코더(encoder-decoder) 구조의 구조와 용례 \ No newline at end of file +- 인코더(encoder), 디코더(decoder), 인코더-디코더(encoder-decoder)의 구조와 용례 \ No newline at end of file diff --git a/chapters/ko/chapter1/10.mdx b/chapters/ko/chapter1/10.mdx index ae80692e5..a05bd4c3b 100644 --- a/chapters/ko/chapter1/10.mdx +++ b/chapters/ko/chapter1/10.mdx @@ -2,252 +2,253 @@ # 단원 마무리 퀴즈 -이번 챕터에서는 정말 많은 내용들을 다뤘습니다! 그러니 모든 디테일을 이해하지 못했다고 해서 좌절하지 마세요. 다음 단원은 내부 작동 방식을 이해하는 데에 도움이 될거에요. +이번 챕터에서는 정말 많은 내용들을 다뤘습니다! 그러니 모든 세부 사항을 다 이해하지 못했다고 해서 좌절하지 마세요. 다음 챕터에서 다루는 내용은 내부 작동 방식을 이해하는 데에 도움이 될거에요. + +그래도 우선, 이번 챕터에서 배운 내용에 대해 확인해보는 시간을 갖도록 하겠습니다! -그래도 우선, 이번 단원에서 배운 내용에 대해 확인해보는 시간을 갖도록 하겠습니다! ### 1. Hub에서 `roberta-large-mnli` 체크포인트를 검색해 보세요. 이 모델은 어떤 작업을 수행하나요? + roberta-large-mnli page." -}, -{ -text: "텍스트 분류", -explain: "더 정확하게 말하면, 이 모델은 두 문장이 논리적으로 타당한지 세 가지 레이블(모순, 함의, 중립)로 분류합니다. 이러한 문제를 자연어 추론(natural language inference)이라고 부릅니다.", -correct: true -}, -{ -text: "텍스트 생성", -explain: "이 페이지를 다시 확인하세요 roberta-large-mnli page." -} -]} + choices={[ + { + text: "요약", + explain: "이 페이지를 다시 확인하세요 roberta-large-mnli page." + }, + { + text: "텍스트 분류", + explain: "더 정확하게 말하면, 이 모델은 두 문장이 논리적으로 타당한지 세 가지 레이블(모순, 함의, 중립)로 분류합니다. 이러한 문제를 자연어 추론(natural language inference)이라고 부릅니다.", + correct: true + }, + { + text: "텍스트 생성", + explain: "이 페이지를 다시 확인하세요 roberta-large-mnli page." + } + ]} /> ### 2. 다음 코드는 무엇을 반환하나요? -``` +```py from transformers import pipeline ner = pipeline("ner", grouped_entities=True) ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") - ``` sentiment-analysis 파이프라인에 대한 설명입니다." -}, -{ -text: "이 문장을 완성할, 생성 텍스트를 반환합니다.", -explain: "오답입니다 — 이는 text-generation 파이프라인에 대한 설명입니다.", -}, -{ -text: "사람, 기관, 장소 등을 나타내는 단어들을 반환합니다.", -explain: "이 뿐만 아니라, grouped_entities=True를 사용해 \"Hugging Face\"와 같이 같은 개체에 해당하는 단어들을 그룹화해줍니다.", -correct: true -} -]} + choices={[ + { + text: "문장에 대해 \"positive\" 혹은 \"negative\" 로 분류한 레이블과 함께 분류 점수를 반환합니다.", + explain: "오답입니다 — 이는 sentiment-analysis 파이프라인에 대한 설명입니다." + }, + { + text: "이 문장을 완성할, 생성 텍스트를 반환합니다.", + explain: "오답입니다 — 이는 text-generation 파이프라인에 대한 설명입니다.", + }, + { + text: "사람, 기관, 장소 등을 나타내는 단어들을 반환합니다.", + explain: "이 뿐만 아니라, grouped_entities=True를 사용해 \"Hugging Face\"와 같이 같은 개체에 해당하는 단어들을 그룹화해줍니다.", + correct: true + } + ]} /> ### 3. 다음 예제 코드에서 ... 대신 무엇이 들어가야 할까요? -``` +```py from transformers import pipeline filler = pipeline("fill-mask", model="bert-base-cased") result = filler("...") - ``` ", -explain: "오답입니다. 여기 bert-base-cased 모델 카드를 보시고 다시 도전해보세요." -}, -{ -text: "[MASK]", -explain: "정답! 이 모델의 마스크 토큰은 [MASK]입니다.", -correct: true -}, -{ -text: "man", -explain: "오답입니다. 이 파이프라인은 마스킹된 단어를 채워야하기에 어딘가에는 마스크 토큰이 있어야겠죠?" -} -]} + choices={[ + { + text: "", + explain: "오답입니다. 여기 bert-base-cased 모델 카드를 보시고 다시 도전해보세요." + }, + { + text: "[MASK]", + explain: "정답! 이 모델의 마스크 토큰은 [MASK]입니다.", + correct: true + }, + { + text: "man", + explain: "오답입니다. 이 파이프라인은 마스킹된 단어를 채워야하기니까 어딘가에는 마스크 토큰이 있어야겠죠?" + } + ]} /> -### 4. 다음 코드가 작동하지 않는 이유가 무엇일까요? +### 4. 다음 코드가 실행되지 않는 이유는 무엇일까요? -``` +```py from transformers import pipeline classifier = pipeline("zero-shot-classification") result = classifier("This is a course about the Transformers library") - ``` candidate_labels=[...].", -correct: true -}, -{ -text: "한 문장이 아니라, 여러 문장을 파이프라인에 넣어주어야 합니다.", -explain: "틀렸지만, 다른 파이프라인과 마찬가지로 제대로 사용한다면 물론 여러 리스트의 문장도 입력으로 넣어줄 수 있습니다." -}, -{ -text: "늘 그렇듯 🤗 Transformers 라이브러리가 또 고장난거 아닌가요?", -explain: "못 들은 걸로 하겠습니다!" -}, -{ -text: "위의 문장은 너무 짧아서, 더 긴 문장을 입력해야 합니다.", -explain: "오답입니다. 매우 긴 텍스트는 파이프라인에서 처리할 때 잘리게 되는 것을 명심하세요." -} -]} + choices={[ + { + text: "해당 텍스트를 분류하기 위해서는 파이프라인에 레이블을 넣어주어야 합니다.", + explain: "맞습니다 — 제대로 작동시키기 위해 다음 코드가 필요합니다. candidate_labels=[...].", + correct: true + }, + { + text: "한 문장이 아니라, 여러 문장을 파이프라인에 넣어주어야 합니다.", + explain: "틀렸지만, 다른 파이프라인과 마찬가지로 제대로 사용한다면 물론 여러 리스트의 문장도 입력으로 넣어줄 수 있습니다." + }, + { + text: "늘 그렇듯 🤗 Transformers 라이브러리가 또 고장난거 아닌가요?", + explain: "못 들은 걸로 하겠습니다!" + }, + { + text: "위의 문장은 너무 짧아서, 더 긴 문장을 입력해야 합니다.", + explain: "오답입니다. 매우 긴 텍스트는 파이프라인에서 처리할 때 잘리게 되는 것을 명심하세요." + } + ]} /> -### 5. "전이 학습(transfer learning)"이 무엇인가요? +### 5. "전이 학습(transfer learning)"이란 무엇을 의미하나요? -### 6. 언어 모델은 일반적으로 사전 학습시에 레이블이 필요하지 않습니다. 이 문장은 참일까요 거짓일까요? +### 6. 언어 모델은 일반적으로 사전 학습시에 레이블을 필요로 하지 않습니다. 이 문장은 참일까요 거짓일까요? + 자가 지도(self-supervised) 방식입니다. 이는 다음 단어 예측 혹은 마스킹 된 단어 채우기 등과 같이 입력으로부터 자동으로 레이블을 생성하는 것을 의미합니다.", -correct: true -}, -{ -text: "거짓", -explain: "정답이 아닙니다." -} -]} + choices={[ + { + text: "참", + explain: "사전 학습 과정은 일반적으로 자가 지도(self-supervised) 방식입니다. 이는 다음 단어 예측 혹은 마스킹 된 단어 채우기 등과 같이 입력으로부터 자동으로 레이블을 생성하는 것을 의미합니다.", + correct: true + }, + { + text: "거짓", + explain: "정답이 아닙니다." + } + ]} /> ### 7. 다음 중 “모델(model)”, “구조(architecture)”, “가중치(weights)”에 대해 가장 잘 설명한 것을 고르세요. -### 8. 다음 중 어떤 모델이 텍스트를 생성하여 프롬트(prompt)를 완성시키는 데에 가장 적합할까요? + +### 8. 다음 중 어떤 모델이 텍스트를 생성하여 프롬프트(prompt)를 완성시키는 데에 가장 적합할까요? ### 9. 다음 중 어떤 모델이 텍스트 요약에 가장 적합할까요? ### 10. 다음 중 어떤 모델이 입력 텍스트를 특정 레이블로 분류하는 데에 가장 적합할까요? ### 11. 다음 중 모델이 편향성(bias)을 갖게 되는 데에 가장 가능성 있는 원인을 모두 고르세요. \ No newline at end of file + choices={[ + { + text: "모델은 사전 학습 모델의 미세 조정된 버전이고, 여기서 편향성이 따라오게 됩니다.", + explain: "전이 학습 시 사용되는 사전 학습 모델의 편향성이 미세 조정된 모델로도 전달됩니다.", + correct: true + }, + { + text: "모델 학습에 사용된 데이터가 편향되어 있습니다.", + explain: "이는 가장 분명한 편향의 원인이지만, 유일한 원인은 아닙니다.", + correct: true + }, + { + text: "모델이 최적화한 메트릭(metric)이 편향되어 있습니다.", + explain: "모델 학습 방식은 편향이 발생되는 불분명한 원인 중 하나입니다. 모델은 어떤 메트릭을 고르든 아무 생각 없이 그에 맞춰 최적화를 합니다.", + correct: true + } + ]} +/> diff --git a/chapters/ko/chapter1/2.mdx b/chapters/ko/chapter1/2.mdx index 2a9426aa7..ca5d62dc8 100644 --- a/chapters/ko/chapter1/2.mdx +++ b/chapters/ko/chapter1/2.mdx @@ -1,6 +1,6 @@ # 자연어 처리(Natural Language Processing) -트랜스포머 모델을 공부하기에 앞서 자연어 처리(NLP)가 무엇인지, 그리고 왜 NLP가 중요한지 빠르고 간단하게 살펴볼게요. +트랜스포머 모델을 공부하기에 앞서 자연어 처리(NLP)가 무엇인지, 그리고 왜 NLP가 중요한지 빠르고 간단하게 살펴보겠습니다. ## NLP가 무엇인가요? @@ -14,8 +14,8 @@ NLP(Natural Language Processing)란 사람의 언어와 관련된 모든 것을 - **텍스트 안에서 정답 추출하기**: 지문과 질의가 주어질 때 지문에 주어진 정보를 이용해 질의에 대한 정답 추출하기 - **입력 텍스트로부터 새로운 문장 생성하기**: 입력 텍스트를 다른 언어로 번역하거나, 요약하기 -하지만 NLP는 위와 같이 텍스트에만 제한되지 않습니다. NLP에서는 오디오 샘플의 스크립트 및 이미지의 설명문 생성과 같이 음성 인식과 컴퓨터 비전 분야에서의 까다로운 문제도 다룹니다. +하지만 NLP는 위와 같은 텍스트 처리에만 제한되지 않습니다. NLP에서는 오디오 샘플의 스크립트 생성 및 이미지의 설명문 생성과 같이 음성 인식과 컴퓨터 비전 분야에서의 까다로운 문제 또한 다룹니다. ## 왜 NLP가 어렵나요? -컴퓨터와 사람은 서로 정보를 처리하는 방식이 다릅니다. 이를테면, “나는 배고파”라는 문장을 읽을 때 우리는 바로 그 의미를 이해할 수 있습니다. 마찬가지로 “나는 배고파”, “나 슬퍼”와 같은 문장 쌍이 주어질 때, 두 문장이 얼마나 유사한지 쉽게 판단할 수 있습니다. 그러나, 기계 학습 모델은 사람만큼 이를 쉽게 할 수 없습니다. 우선 모델이 텍스트를 학습할 수 있도록 텍스트가 처리 과정을 거쳐야 하는데, 사람의 언어 체계는 매우 복잡하기 때문에 이러한 처리가 어떻게 이루어져야 하는지 면밀히 생각해야 합니다. 따라서 텍스트 표현 방법과 관련한 수많은 연구가 진행되어 왔고, 다음 단원에서 여러분들에게 그 중 몇 가지 방법들을 소개해드리겠습니다. \ No newline at end of file +컴퓨터와 사람은 서로 정보를 처리하는 방식이 다릅니다. 이를테면, “나는 배고파”라는 문장을 읽을 때 우리는 바로 그 의미를 이해할 수 있습니다. 마찬가지로 사람은 “나는 배고파”, “나 슬퍼”와 같은 문장 쌍이 주어질 때, 두 문장이 얼마나 유사한지 쉽게 판단할 수 있습니다. 그러나, 기계 학습 모델은 사람만큼 이를 쉽게 할 수 없습니다. 우선 모델이 텍스트를 학습할 수 있도록 텍스트가 처리 과정을 거쳐야 하는데, 사람의 언어 체계는 매우 복잡하기 때문에 이러한 처리가 어떻게 이루어져야 하는지 면밀히 고민해야 합니다. 따라서 텍스트 표현 방법과 관련한 수많은 연구가 진행되어 왔고, 다음 챕터에서 그 중 몇 가지 방법들을 소개해드리겠습니다. \ No newline at end of file diff --git a/chapters/ko/chapter1/3.mdx b/chapters/ko/chapter1/3.mdx index ae47531b2..f32892430 100644 --- a/chapters/ko/chapter1/3.mdx +++ b/chapters/ko/chapter1/3.mdx @@ -1,31 +1,30 @@ # 트랜스포머로 무엇을 할 수 있나요? 이번 장에서는 트랜스포머(Transformer) 모델을 사용해 무엇을 할 수 있는지 같이 살펴보고, 🤗 Transformers 라이브러리 툴의 첫 사용을 `pipeline()` 함수와 함께 시작하겠습니다. -👀 오른쪽 상단에 Open in Colab 버튼이 보이시나요? 버튼을 클릭하면 이번 장에서 사용한 모든 코드 샘플들을 Google Colab notebook을 통해 열 수 있습니다. 이 버튼은 예제 코드를 포함하는 모든 장에서 나타날 거에요. +👀 오른쪽 상단에 Open in Colab 버튼이 보이시나요? 버튼을 클릭하면 이번 장에서 사용한 모든 코드 샘플들을 Google Colab notebook을 통해 열 수 있습니다. 이런 버튼을 예제 코드를 포함하는 모든 단원에서 발견하실 수 있습니다. 로컬 환경에서 예제 코드를 실행하려면 setup을 살펴보세요. ## 트랜스포머는 어디에나 있어요! -트랜스포머 모델은 이전 단원에서 언급한 작업과 같은 모든 NLP 문제를 해결하기 위해 사용됩니다. 아래에 Hugging Face와 트랜스포머 모델을 이용하고 다시 모델을 공유하여 커뮤니티에 기여하는 기업과 기관들이 보이네요: +트랜스포머 모델은 이전 단원에서 언급한 작업과 같은 모든 NLP 문제를 해결하기 위해 사용됩니다. 아래와 같이 Hugging Face와 트랜스포머 모델을 이용하고 다시 모델을 공유하여 커뮤니티에 기여하는 많은 기업과 기관이 있습니다: -Companies using Hugging Face +Companies using Hugging Face [🤗 Transformers 라이브러리](https://github.com/huggingface/transformers)는 이렇게 공유한 모델을 사용하고 구축하는 기능들을 제공합니다. [Model Hub](https://huggingface.co/models)에서는 모두가 다운로드 받아 쓸 수 있는 수 천 개의 사전 학습된 모델들이 여러분을 기다리고 있습니다. 여러분만의 모델을 Hub에 업로드하는 것 또한 가능합니다! - -⚠️ The Hugging Face Hub에는 트랜스포머 모델만 있지 않아요. 누구든지 어떠한 종류의 모델이나 데이터를 공유할 수 있답니다! Create a huggingface.co 링크에서 계정을 만들고 모든 기능을 사용해보세요! +⚠️ The Hugging Face Hub에는 트랜스포머 모델만 있지 않아요. 누구든지 어떠한 종류의 모델이나 데이터를 공유할 수 있습니다! Create a huggingface.co 링크에서 계정을 만들고 모든 기능을 사용해보세요! 트랜스포머 모델 안에서 무슨 일이 벌어지는지 알아보기 전에, 트랜스포머가 NLP 문제 해결에 어떻게 사용되는지 몇 가지 흥미로운 예시들을 살펴보겠습니다. @@ -36,35 +35,31 @@ options={[ 🤗 Transformers 라이브러리의 가장 기본 객체는 `pipeline()` 함수입니다. 이 함수는 모델에 있어서 필수 과정인 전처리와 후처리 과정을 모델과 연결하고, 우리가 바로 어떠한 텍스트 입력을 넣든 원하는 답을 얻을 수 있도록 합니다: -``` +```python from transformers import pipeline classifier = pipeline("sentiment-analysis") classifier("I've been waiting for a HuggingFace course my whole life.") - ``` -``` +```python out [{'label': 'POSITIVE', 'score': 0.9598047137260437}] - ``` -아래와 같이 여러 문장을 동시에 넣을 수도 있습니다! +아래와 같이 여러 문장을 함께 넣을 수도 있습니다! -``` +```python classifier( ["I've been waiting for a HuggingFace course my whole life.", "I hate this so much!"] ) - ``` -``` +```python out [{'label': 'POSITIVE', 'score': 0.9598047137260437}, {'label': 'NEGATIVE', 'score': 0.9994558095932007}] - ``` -기본적으로 이 파이프라인은 영어 감정 분석에 미세 조정(fine-tune)된 사전 학습 모델을 선택합니다. 여기서 `classifier` 객체를 생성할 때 모델이 다운로드 되며 캐싱(caching)이 이루어지는데, 재실행 시 캐싱된 모델을 사용하게 되어 모델을 다시 다운로드 하지 않습니다. +기본적으로 이 파이프라인은 영어 감정 분석에 미세 조정(fine-tune)된 사전 학습 모델을 선택하여 넣게 됩니다. 여기서 `classifier` 객체를 생성할 때 모델이 다운로드 되며 캐싱(caching)이 이루어지때문에, 재실행 시에는 캐싱된 모델을 사용하게 되어 모델을 다시 다운로드 하지 않습니다. 텍스트를 파이프라인에 넣을 때 다음과 같은 세 가지 주요 과정을 거칩니다: @@ -72,6 +67,7 @@ classifier( 2. 전처리된 입력이 모델 입력으로 들어갑니다. 3. 모델의 예측값이 후처리를 거쳐, 사람이 이해할 수 있는 형태로 반환됩니다. + 현재까지 사용할 수 있는 파이프라인([available pipelines](https://huggingface.co/transformers/main_classes/pipelines.html))은 다음과 같습니다: - `feature-extraction` : 특징 추출 (텍스트에 대한 벡터 표현 추출) @@ -84,13 +80,13 @@ classifier( - `translation` : 번역 - `zero-shot-classification` : 제로샷 분류 -이 중 몇 가지를 같이 살펴볼까요? +이 중 몇 가지를 같이 살펴보도록 하겠습니다! ## 제로샷 분류(Zero-shot classification) 레이블이 없는 텍스트를 분류하는 더 까다로운 과제부터 시작하겠습니다. 텍스트에 레이블을 다는 것은 시간이 많이 소요되고 도메인 지식이 필요하기 때문에 이러한 작업은 실제 프로젝트에서 아주 흔한 상황입니다. 이러한 상황에서 `zero-shot-classification` 파이프라인은 매우 유용합니다. 제로샷 파이프라인은 사전 학습된 모델에 의존하지 않고도 분류 작업에 사용할 레이블을 특정할 수 있도록 합니다. 위의 예시에서 모델이 긍정(positive)과 부정(negative)의 두 레이블을 분류하는 샘플을 살펴보았는데, 제로샷 파이프라인을 통해서는 어떠한 레이블 세트에 대해서도 분류 작업을 수행할 수 있습니다. -``` +```python from transformers import pipeline classifier = pipeline("zero-shot-classification") @@ -98,60 +94,58 @@ classifier( "This is a course about the Transformers library", candidate_labels=["education", "politics", "business"], ) - ``` -``` +```python out {'sequence': 'This is a course about the Transformers library', 'labels': ['education', 'business', 'politics'], 'scores': [0.8445963859558105, 0.111976258456707, 0.043427448719739914]} - ``` -이러한 파이프라인이 제로샷(zero-shot)이라 불리는 이유는 여러분의 데이터에 미세 조정(fine-tune)하지 않고도 사용할 수 있기 때문입니다. 제로샷은 여러분이 원하는 어떠한 레이블 목록에 대해서도 확률 점수를 바로 반환합니다. +이러한 파이프라인이 제로샷(zero-shot)이라 불리는 이유는 여러분의 데이터에 맞춰 미세 조정(fine-tune)하지 않고도 바로 작업에 사용할 수 있기 때문입니다. 제로샷은 여러분이 원하는 어떠한 분류 레이블에 대해서도 확률 점수를 즉시 반환합니다. -**✏️ 직접 해보기!** 여러분만의 시퀀스와 레이블로 모델이 어떻게 동작하는지 확인해보세요. +✏️ **직접 해보기!** 여러분이 직접 작성한 시퀀스와 레이블을 사용해 모델이 어떻게 동작하는지 확인해보세요. + ## 텍스트 생성(Text generation) 지금부터 파이프라인을 사용해 텍스트를 생성하는 방법을 알아보겠습니다. 여기서의 핵심은 프롬트를 모델에 제공하면 모델이 나머지 텍스트를 생성하여 이를 자동으로 완성하는 것입니다. 이는 스마트폰의 텍스트 자동 완성 기능과 유사합니다. 텍스트 생성에는 랜덤하게 결과를 생성하는 과정이 포함되어 있어서 여러분이 아래와 같이 동일하게 입력을 넣어도 매번 다른 결과가 나올 수 있습니다. -``` +```python from transformers import pipeline generator = pipeline("text-generation") generator("In this course, we will teach you how to") - ``` -``` +```python out [{'generated_text': 'In this course, we will teach you how to understand and use ' 'data flow and data interchange when handling user data. We ' 'will be working with one or more of the most commonly used ' 'data flows — data flows of various types, as seen by the ' 'HTTP'}] - ``` -`num_return_sequences` 인자(argument)를 통해 몇 개의 다른 출력 결과를 생성할지 조절할 수 있고, `max_length` 인자를 통해 출력 텍스트의 총 길이를 설정할 수 있습니다. +`num_return_sequences`라는 인자(argument)를 통해 몇 개의 서로 다른 출력 결과를 생성할지 정할 수 있고, `max_length` 인자를 통해 출력 텍스트의 총 길이를 설정할 수 있습니다. -**✏️ 직접 해보기!** `num_return_sequences` 와 `max_length` 인자를 설정해 15 단어의 서로 다른 두 개의 문장을 출력해보세요. +✏️ **직접 해보기!** `num_return_sequences` 와 `max_length` 인자를 설정해 15개의 단어를 가진 서로 다른 두 개의 문장을 출력해보세요. + ## 파이프라인에 Hub의 모델 적용하기 -지금까지 예제들은 해당 작업에 대해 기본 모델들을 사용했지만, 특정 모델을 Hub에서 선택해 텍스트 생성과 같은 특정 작업에 대한 파이프라인에서도 사용할 수 있습니다. [Model Hub](https://huggingface.co/models) 페이지의 화면 왼쪽에 태그를 클릭하여 해당 태그 내용 작업을 지원하는 모델을 확인할 수 있습니다. [다음](https://huggingface.co/models?pipeline_tag=text-generation)과 같은 페이지로 이동하게 됩니다. +지금까지 예제들은 해당 작업에 대해 기본 모델들을 사용했지만, 특정 모델을 Hub에서 선택해 텍스트 생성과 같은 특정 작업에 대한 파이프라인에서도 사용할 수 있습니다. [Model Hub](https://huggingface.co/models) 페이지의 화면 왼쪽에 태그를 클릭하여 태그명에 해당하는 작업을 지원하는 모델을 확인할 수 있습니다. 이 때, [다음](https://huggingface.co/models?pipeline_tag=text-generation)과 같은 페이지로 이동하게 됩니다. -함께 `[distilgpt2](https://huggingface.co/distilgpt2)` 모델을 사용해봐요! 위의 예제에서 사용한 파이프라인에서 아래와 같이 로드 할 수 있습니다: +함께 [`distilgpt2`](https://huggingface.co/distilgpt2) 모델을 사용해보겠습니다! 위 예제에서 사용한 파이프라인에서 모델을 아래와 같이 로드 할 수 있습니다: -``` +```python from transformers import pipeline generator = pipeline("text-generation", model="distilgpt2") @@ -160,31 +154,29 @@ generator( max_length=30, num_return_sequences=2, ) - ``` -``` +```python out [{'generated_text': 'In this course, we will teach you how to manipulate the world and ' 'move your mental and physical capabilities to your advantage.'}, {'generated_text': 'In this course, we will teach you how to become an expert and ' 'practice realtime, and with a hands on experience on both real ' 'time and real'}] - ``` -언어 태그를 클릭하여 해당 언어를 지원 및 생성하는 모델을 구체적으로 검색할 수 있습니다. Model Hub에는 다양한 언어를 지원하는 다국어 모델의 체크포인트(모델의 파라미터 값) 또한 포함하고 있습니다. +언어 태그를 클릭하여 해당 언어를 지원하고 생성하는 모델을 보다 구체적으로 검색할 수 있습니다. Model Hub에는 다양한 언어를 처리하는 다국어 모델의 체크포인트(모델의 파라미터 값) 또한 포함하고 있습니다. -모델을 클릭하여 선택하면 온라인에서 바로 사용이 가능한 위젯을 확인할 수 있고, 이를 통해 모델을 다운로드 받기 전에 모델의 기능을 빠르게 테스트 해볼 수 있습니다. +모델을 클릭하면 온라인상에서 바로 사용 가능한 위젯을 확인할 수 있고, 이를 통해 모델을 직접 다운로드 받기 전에 모델의 기능을 빠르게 테스트 해볼 수 있습니다. -**✏️ 직접 해보기!** 영어를 제외한 다른 언어를 생성하는 모델을 검색해보세요. 위젯을 자유롭게 사용해 보시고 파이프라인을 사용해보세요! +✏️ **직접 해보기!** 영어를 제외한 다른 언어를 생성하는 모델을 검색해보세요. 위젯을 자유롭게 다뤄 보시고 파이프라인을 사용해보세요! ### 추론(Inference) API -모든 모델들은 [Hugging Face 웹사이트](https://huggingface.co/)에서 제공하는 추론 API를 통해 여러분의 브라우저상에서 직접 테스트가 가능합니다. 이 페이지를 통해 직접 나만의 텍스트를 입력하고 모델이 입력 데이터를 처리하는걸 구경하며 모델을 갖고 놀 수 있습니다. +모든 모델들은 [Hugging Face 웹사이트](https://huggingface.co/)에서 제공하는 추론 API를 통해 여러분의 브라우저상에서 직접 테스트할 수 있습니다. 이 페이지 링크로 접속해 직접 작성하신 텍스트를 입력하시면 모델의 입력 데이터를 처리 결과를 확인할 수 있습니다. 위젯을 구동하는 추론 API는 간편한 워크플로우를 가능하게 하는 유료 버전의 제품으로도 이용 가능합니다. 자세한 사항은 [가격 정책 페이지](https://huggingface.co/pricing)를 참고해주세요. @@ -192,15 +184,14 @@ generator( 다음으로 사용해볼 파이프라인은 마스크 채우기(`fill-mask`)입니다. 이 작업의 핵심 아이디어는 주어진 텍스트의 빈칸을 채우기입니다: -``` +```python from transformers import pipeline unmasker = pipeline("fill-mask") unmasker("This course will teach you all about models.", top_k=2) - ``` -``` +```python out [{'sequence': 'This course will teach you all about mathematical models.', 'score': 0.19619831442832947, 'token': 30412, @@ -209,52 +200,49 @@ unmasker("This course will teach you all about models.", top_k=2) 'score': 0.04052725434303284, 'token': 38163, 'token_str': ' computational'}] - ``` -몇 개의 가능성 있는 토큰을 표시할지 `top_k` 인자를 통해 조절합니다. 여기서 모델이 특이한 `` 단어를 채우는 것을 주목하세요. 이는 마스크 토큰(mask token)이라고 부릅니다. 다른 마스크 채우기 모델들은 다른 형태의 마스크 토큰을 사용할 수 있어서 다른 모델을 탐색할 때 항상 마스크 단어를 확인해야 합니다. 위젯에서 사용되는 마스크 단어를 보고 이를 확인해 볼 수 있습니다. +상위 몇 개의 높은 확률을 띠는 토큰을 출력할지 `top_k` 인자를 통해 조절합니다. 여기서 모델이 특이한 `` 단어를 채우는 것을 주목하세요. 이를 마스크 토큰(mask token)이라고 부릅니다. 다른 마스크 채우기 모델들은 다른 형태의 마스크 토큰을 사용할 수 있기 때문에 다른 모델을 탐색할 때 항상 해당 모델의 마스크 단어가 무엇인지 확인해야 합니다. 위젯에서 사용되는 마스크 단어를 보고 이를 확인할 수 있습니다. -**✏️ 직접 해보기!** Hub에서 `bert-base-cased` 를 검색해 보고 Inference API 위젯으로 마스크 단어를 확인해 보세요. 이 모델이 위의 `pipeline` 예제에서 사용한 문장에 대해 어떻게 예측하나요? +✏️ **직접 해보기!** Hub에서 `bert-base-cased`를 검색해 보고 추론 API 위젯을 통해 모델의 마스크 단어가 무엇인지 확인해 보세요. 이 모델이 위의 `pipeline` 예제에서 사용한 문장에 대해 어떻게 예측하나요? ## 개체명 인식(Named entity recognition) -개체명 인식(NER)은 모델이 입력 텍스트의 어느 부분이 사람, 장소, 기관 등과 같은 개체에 해당하는지 찾는 작업입니다. 예제를 통해 확인해 봅시다: +모델이 입력 텍스트의 어느 부분이 사람, 장소, 기관 등과 같은 개체에 해당하는지 찾는 작업을 개체명 인식(NER)이라고 합니다. 예제를 통해 확인해 봅시다: -``` +```python from transformers import pipeline ner = pipeline("ner", grouped_entities=True) ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") - ``` -``` +```python out [{'entity_group': 'PER', 'score': 0.99816, 'word': 'Sylvain', 'start': 11, 'end': 18}, {'entity_group': 'ORG', 'score': 0.97960, 'word': 'Hugging Face', 'start': 33, 'end': 45}, {'entity_group': 'LOC', 'score': 0.99321, 'word': 'Brooklyn', 'start': 49, 'end': 57} ] - ``` 모델이 정확하게 Sylvain을 사람(PER)으로, Hugging Face를 기관(ORG)으로, Brooklyn을 장소(LOC)으로 예측했네요! -파이프라인을 생성하는 함수에 `grouped_entities=True` 옵션을 전달하면 파이프라인이 같은 개체에 해당하는 문장 부분을 다시 그룹화합니다. 이 경우 모델은 여러 단어로 구성된 단어임에도 “Hugging”과 “Face”를 하나의 기관으로 정확히 분류하게 됩니다. 다음 단원에서도 확인하겠지만, 놀랍게도 전처리 과정에서 각 단어들은 더 작은 부분으로 쪼개지게 됩니다. 예를 들어 `Sylvain` 이라는 단어는 `S`, `##yl`, `##va`, `##in` 이렇게 네 조각으로 쪼개집니다. 후처리 단계에서 파이프라인은 이 조각들을 멋지게 재그룹화합니다. +파이프라인을 생성하는 함수에 `grouped_entities=True` 옵션을 전달하면 파이프라인이 같은 개체에 해당하는 문장 부분을 다시 그룹화합니다. 이 옵션을 설정하면 모델은 여러 단어로 구성된 단어임에도 “Hugging”과 “Face”를 하나의 기관으로 정확히 분류하게 됩니다. 다음 챕터에서도 확인하겠지만, 놀랍게도 전처리 과정에서 각 단어들은 더 작은 부분으로 쪼개집니다. 예를 들어 `Sylvain` 이라는 단어는 `S`, `##yl`, `##va`, `##in` 이렇게 네 조각으로 쪼개집니다. 후처리 단계에서 파이프라인은 이 조각들을 멋지게 재그룹화합니다. -**✏️ 직접 해보기!** Model Hub에서 영어 품사 태깅(part-of-speech tagging, 줄여서 POS)이 가능한 모델을 찾아보세요. 이 모델이 위의 예시 문장으로 무엇을 예측하나요? +✏️ **직접 해보기!** Model Hub에서 영어 품사 태깅(part-of-speech tagging, 줄여서 POS)이 가능한 모델을 찾아보세요. 이 모델이 위의 예시 문장으로 무엇을 예측하나요? ## 질의 응답(Question-answering) -질의 응답(`question-answering`) 파이프라인은 주어진 지문(context)의 정보를 활용하여 질문에 답을 합니다: +질의 응답(`question-answering`) 파이프라인은 주어진 지문(context)의 정보를 활용하여 질문에 대한 답을 하는 태스크입니다: -``` +```python from transformers import pipeline question_answerer = pipeline("question-answering") @@ -262,21 +250,19 @@ question_answerer( question="Where do I work?", context="My name is Sylvain and I work at Hugging Face in Brooklyn", ) - ``` -``` +```python out {'score': 0.6385916471481323, 'start': 33, 'end': 45, 'answer': 'Hugging Face'} - ``` -본 파이프라인은 답을 새롭게 생성하지 않고 주어진 지문에서 정답을 추출하는 방식임을 잘 기억하세요. +본 파이프라인은 답을 새롭게 생성하는 방식이 아닌, 주어진 지문 내에서 정답을 추출하는 방식임을 잘 기억하세요. ## 요약(Summarization) -요약은 참조 텍스트의 모든(혹은 대부분) 중요한 특징을 유지한 채로 텍스트를 짧게 줄이는 작업입니다. 아래 예제를 확인하세요: +요약(Summarization)은 참조 텍스트의 모든(혹은 대부분의) 중요한 특징을 그대로 유지한 채 텍스트를 짧게 줄이는 작업입니다. 아래 예제를 확인하세요: -``` +```python from transformers import pipeline summarizer = pipeline("summarization") @@ -302,10 +288,9 @@ summarizer( and a lack of well-educated engineers. """ ) - ``` -``` +```python out [{'summary_text': ' America has changed dramatically during recent years . The ' 'number of engineering graduates in the U.S. has declined in ' 'traditional engineering disciplines such as mechanical, civil ' @@ -313,34 +298,31 @@ summarizer( 'developing economies such as China and India, as well as other ' 'industrial countries in Europe and Asia, continue to encourage ' 'and advance engineering .'}] - ``` -텍스트 생성과 마찬가지로 `max_length` 와 `min_length` 를 정할 수 있습니다. +텍스트 생성에서와 마찬가지로 `max_length` 와 `min_length` 를 미리 설정할 수 있습니다. ## 번역(Translation) -번역의 경우 (`"translation_en_to_fr"` 와 같이) 작업명에 언어 쌍을 넣어준다면 기본 모델을 사용할 수 있지만, [Model Hub](https://huggingface.co/models)에서 원하는 모델을 고르는 방식이 가장 간단합니다. 여기서는 프랑스어에서 영어로 번역을 시도해 보겠습니다: +번역(Translation)의 경우 `"translation_en_to_fr"` 와 같이 태스크명에 해당하는 언어 쌍을 넣어준다면 기본 모델을 사용할 수 있지만, 더 간단하게 [Model Hub](https://huggingface.co/models)에서 원하는 모델을 선택해 사용하는 방법이 있습니다. 아래에서는 프랑스어에서 영어로 번역을 시도해 보겠습니다: -``` +```python from transformers import pipeline translator = pipeline("translation", model="Helsinki-NLP/opus-mt-fr-en") translator("Ce cours est produit par Hugging Face.") - ``` -``` +```python out [{'translation_text': 'This course is produced by Hugging Face.'}] - ``` 텍스트 생성 및 요약에서와 마찬가지로, `max_length` 혹은 `min_length` 를 지정하여 결과를 출력할 수 있습니다. -**✏️ 직접 해보기!** 다른 언어의 번역 모델을 검색해보고 위의 문장을 몇 가지 다른 언어들로 번역해 봅시다. +✏️ **직접 해보기!** 다른 언어를 지원하는 번역 모델을 검색해보고 위의 문장을 몇 가지 다른 언어들로 번역해 봅시다. -지금까지 보여드린 파이프라인들은 대부분 특정 작업을 위해 프로그래밍된, 다양한 변형 작업을 수행할 수 없는 데모용 파이프라인입니다. 다음 단원에서는 `pipeline()` 함수 내부를 살펴보고 그 동작을 사용자가 직접 설계하는 방법을 다루겠습니다. \ No newline at end of file +지금까지 보여드린 파이프라인들은 대부분 특정 작업을 위해 프로그래밍된 데모용 파이프라인으로, 여러 태스크를 동시에 지원하지는 않습니다. 다음 단원에서는 `pipeline()` 함수 내부를 살펴보고 그 동작 방식을 직접 설계하는 방법에 대해 다루겠습니다. \ No newline at end of file diff --git a/chapters/ko/chapter1/4.mdx b/chapters/ko/chapter1/4.mdx index 3b041e435..96456fab5 100644 --- a/chapters/ko/chapter1/4.mdx +++ b/chapters/ko/chapter1/4.mdx @@ -7,20 +7,25 @@ 아래에 트랜스포머 모델의 (짧은) 역사 중 주요한 지점을 나타냈습니다:
-A brief chronology of Transformers models. - +A brief chronology of Transformers models. +
[Transformer architecture](https://arxiv.org/abs/1706.03762)는 2017년 6월에 처음 소개되었습니다. 처음 연구 목적은 번역 작업 수행이었습니다. 이후로 다음과 같이 줄줄이 막강한 모델들이 세상에 등장했습니다: - **2018년 6월**: [GPT](https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf), 최초로 사전 학습된 트랜스포머 모델로 다양한 NLP 작업에 미세 조정(fine-tune)되도록 사용되었으며 SOTA(state-of-the-art) 성능 달성 + - **2018년 10월**: [BERT](https://arxiv.org/abs/1810.04805), 또 다른 거대 사전 학습 언어 모델로, 더 좋은 문장 요약을 위해 설계 (이번 단원과 다음 단원에서 더 자세히 알아봐요!) + - **2019년 2월**: [GPT-2](https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf), 더 좋은 성능(그리고 더 큰) 버전의 GPT로, 윤리적 문제로 인해 즉시 공개되지 못하였음 + - **2019년 10월**: [DistilBERT](https://arxiv.org/abs/1910.01108), BERT의 60% 빠른 속도에 메모리 측면에서 40% 가볍지만 BERT 성능의 97%를 재현하는 경량화 버전의 BERT + - **2019년 10월**: [BART](https://arxiv.org/abs/1910.13461) 와 [T5](https://arxiv.org/abs/1910.10683), 동일한 구조의 (처음으로) 원본 트랜스포머 모델의 구조를 그대로 따른 두 거대 사전학습 언어 모델 + - **2020년 5월**, [GPT-3](https://arxiv.org/abs/2005.14165), 미세 조정 없이도 (zero-shot learning이라 부름) 다양한 작업을 훌륭하게 수행하는 GPT-2의 더 큰 버전 -위 리스트는 단순히 서로 다른 종류의 트랜스포머 모델들 중 몇몇을 강조하기 위한 목록일 뿐, 포괄적이지 않습니다. 넓은 관점에서 트랜스포머 모델은 아래와 같이 세 카테고리로 그룹화 할 수 있습니다: +위 리스트는 단순히 여러 종류의 트랜스포머 모델들 중 몇몇을 강조하기 위한 목록입니다. 넓은 관점에서 트랜스포머 모델은 아래와 같이 세 개의 카테고리로 묶을 수 있습니다: - GPT-계열 (*Auto-regressive* 트랜스포머 모델로도 불림) - BERT-계열 (*Auto-encoding* 트랜스포머 모델로도 불림) @@ -32,44 +37,45 @@ 위에 언급한 모델(GPT, BERT, BART, T5 등)들은 *언어 모델(language model)*로서 학습 되었습니다. 다르게 말하면 이 모델들은 스스로 지도하는 방식으로 수많은 텍스트에 대해 학습된 모델들입니다. 이러한 자가 지도 학습(self-supervised learning)은 학습의 목적이 모델 입력으로부터 자동으로 계산되는 방식을 말합니다. 결국 사람이 데이터에 레이블을 달지 않아도 학습이 가능한 것입니다! -이러한 종류의 모델은 학습한 언어에 대해 통계 기반의 이해를 생성하지만 이는 몇몇 실생활 문제에 적합하지 않습니다. 이러한 이유로 사전 학습된 모델은 *전이 학습(transfer learning)*이라 불리는 과정을 거칩니다. 이 과정에서 모델은 특정 작업에 맞춰 지도적(supervised)인 방법, 즉 사람이 레이블을 추가한 데이터를 사용하는 방법으로 미세 조정(fine-tune)이 이루어지며 +이러한 종류의 모델은 학습한 언어에 대해 통계 기반의 방식으로 이해를 하지만, 이는 몇몇 실생활 문제에 적합하지 않습니다. 그렇기 때문에 사전 학습된 모델은 *전이 학습(transfer learning)*이라 불리는 과정을 거칩니다. 이 과정에서 모델은 특정 작업에 맞춰 지도적(supervised)인 방법, 즉 사람이 레이블을 추가한 데이터를 사용하는 방법으로 미세 조정(fine-tune)이 이루어지는 단계를 거칩니다. 하나의 예시로 문장 내에서 이전 *n*개의 단어를 읽고 다음에 올 단어를 에측하는 문제를 들 수 있습니다. 이를 과거와 현재의 입력 정보를 이용하는 방식(미래에 올 입력 정보는 이용하지 않습니다)이기 때문에 *인과적 언어 모델링(causal language modeling)*이라고 부릅니다.
-Example of causal language modeling in which the next word from a sentence is predicted. - +Example of causal language modeling in which the next word from a sentence is predicted. +
다른 예시로 *마스크 언어 모델링(masked language modeling)*을 들 수 있습니다. 여기서 모델은 문장 내에 마스킹 된 단어를 예측합니다.
-Example of masked language modeling in which a masked word from a sentence is predicted. - +Example of masked language modeling in which a masked word from a sentence is predicted. +
## 트랜스포머는 거대 모델입니다 -(DistilBERT와 같은 몇몇 예외를 제외하고) 모델의 성능을 향상시키는 일반적인 전략은 사전 학습에 사용하는 모델의 크기와 데이터의 양을 늘리는 방식입니다. +(DistilBERT와 같은 몇몇 예외를 제외하고) 모델의 성능을 향상시키는 일반적인 전략은 사전 학습에 사용하는 "모델과 데이터의 크기를 늘리기" 입니다.
-Number of parameters of recent Transformers models +Number of parameters of recent Transformers models
불행히도 아주 아주 큰 모델의 경우, 학습을 위해 어마무시한 양의 데이터를 필요로 하여 시간과 컴퓨팅 리소스 관점에서 비용이 매우 많이 듭니다. 아래 그래프에서 볼 수 있듯이 이는 환경 오염 문제로 이어지기도 합니다.
-The carbon footprint of a large language model. - +The carbon footprint of a large language model. +
-위 비디오는 사전 학습 과정이 환경에 끼치는 부정적 영향을 꾸준히 줄이기 위해 노력하는 팀의 (초거대) 언어 모델 프로젝트를 소개합니다. 최적의 하이퍼파라미터를 찾기 위한 수많은 시도에는 아직 많은 여정이 남았습니다. +위 비디오는 사전 학습 과정이 환경에 끼치는 부정적 영향을 꾸준히 줄이기 위해 노력하는 한 팀의 (초거대) 언어 모델 프로젝트를 소개합니다. 최적의 하이퍼파라미터를 찾기 위한 수많은 시도에는 아직 많은 여정이 남아 있습니다. + +매번 리서치 팀, 학생 기관, 기업 등등이 밑바닥부터 모델을 학습시킨다고 생각해보세요. 이는 결국 정말 어마어마한 양의 글로벌 비용으로 이어질 것입니다! -매번 리서치 팀, 학생 기관, 기업 등등이 밑바닥부터 모델을 학습시킨다고 생각해보세요. 정말 어마어마한 글로벌 비용으로 이어지겠죠? +이제 왜 언어 모델을 공유하는 것이 중요한지 아시겠나요? 학습 가중치를 공유하고, 이미 학습시킨 가중치에 이를 차곡차곡 쌓아 올리는 방식으로 커뮤니티의 컴퓨팅 비용과 탄소 발자국을 줄일 수 있기 때문입니다. -이제 왜 언어 모델을 공유하는 것이 중요한지 아시겠죠? 학습된 가중치를 공유하고, 이미 학습된 가중치에 이를 차곡차곡 쌓아 올리는 방식으로 커뮤니티의 컴퓨팅 비용과 탄소 발자국을 줄일 수 있습니다. ## 전이 학습(Transfer Learning) @@ -78,23 +84,23 @@ *사전 학습(Pretraining)*시에는 모델을 밑바닥부터 학습시키게 됩니다. 모델 가중치를 랜덤하게 초기화하고 사전 지식 없이 학습을 시작합니다.
-The pretraining of a language model is costly in both time and money. - +The pretraining of a language model is costly in both time and money. +
-이러한 사전 학습은 엄청난 양의 데이터로 이루어지기 때문에 방대한 양의 코퍼스 데이터와 수 주 씩 걸리는 학습 시간을 필요로 하기도 합니다. +이러한 사전 학습 과정은 엄청난 양의 데이터로 이루어지기 때문에 방대한 양의 코퍼스 데이터와 수 주 씩 걸리는 학습 시간을 필요로 하기도 합니다. -하지만 *미세 조정(Fine-tuning)*은 모델이 사전 학습된 **이후에** 하는 학습을 의미합니다. 미세 조정을 하기 위해서 우선 사전 학습된 언어 모델을 가져오고, 여러분이 할 작업에 특화된 데이터셋을 이용해 추가 학습을 수행합니다. 잠깐만요, 그냥 한번에 최종 태스크에 맞춰 학습시키면 안될까요? 이렇게 하는 데에는 몇 가지 이유가 있습니다: +반면에 *미세 조정(Fine-tuning)*이란 모델이 모두 사전 학습을 마친 **이후에** 하는 학습을 의미합니다. 미세 조정을 하기 위해서 우선 사전 학습된 언어 모델을 가져오고, 여러분이 할 작업에 특화된 데이터셋을 이용해 추가 학습을 수행합니다. 잠깐만요, 그냥 한번에 최종 태스크에 맞춰 학습시키면 안될까요? 이렇게 하는 데에는 몇 가지 이유가 있습니다: -- 사전 학습된 모델은 이미 미세 조정 데이터셋과 유사한 데이터셋으로 학습이 이루어진 상태입니다. 결국 모델이 사전 학습시에 얻은 지식(이를테면, NLP 문제에서 사전 학습된 모델이 얻게 되는 통계적 이해)을 십분 활용해 미세 조정에 활용할 수 있게 됩니다. +- 사전 학습된 모델은 이미 미세 조정 데이터셋과 유사한 데이터셋으로 학습이 이루어진 상태입니다. 결국 모델이 사전 학습시에 얻은 지식(이를테면, NLP 문제에서 사전 학습된 모델이 얻게 되는 언어의 통계적 이해)을 십분 활용해 미세 조정에 활용할 수 있게 됩니다. - 사전 학습된 모델은 이미 방대한 데이터로 학습되었기 떄문에 미세 조정에서는 원하는 성능을 얻기까지 적은 양의 데이터만 필요로 하게 됩니다. - 위와 같은 이유로, 원하는 성능을 얻기까지 적은 시간과 리소스만 필요하게 됩니다. 예시로, 영어로 사전 학습된 모델을 활용해 arXiv 코퍼스로 미세 조정하여 과학/연구 기반 모델을 만들 수 있습니다. 이 때 미세 조정에는 적은 양의 데이터만 필요할 것입니다. 여기서 사전 학습 과정에서 얻은 지식이 “전이”되었다고 하여 *전이 학습(transfer learning)*이라 부릅니다.
-The fine-tuning of a language model is cheaper than pretraining in both time and money. - +The fine-tuning of a language model is cheaper than pretraining in both time and money. +
모델의 미세 조정은 이렇게 시간, 데이터, 경제, 그리고 환경 비용 측면에서 훨씬 저렴합니다. 뿐만 아니라 전체 사전 학습 과정보다 제약이 적기 때문에 다양한 방식의 미세 조정을 쉽고 빠르게 반복할 수 있습니다. @@ -107,23 +113,23 @@ -## Introduction +## 구조 소개 모델은 기본적으로 두 개의 블럭으로 이루어져 있습니다: -- **인코더 (왼쪽)**: 인코더는 입력을 받아 입력(혹은 입력의 특징)을 구축합니다. 이는 인코더 모델이 입력을 이해하는 데에 최적화되어 있음을 의미합니다. -- **디코더 (오른쪽)**: 디코더는 인코더의 (특징) 표현과 또 다른 입력을 활용해 타겟 시퀀스를 생성합니다. 이는 디코더 모델이 출력을 생성하는 데에 최적화되어 있음을 의미합니다. +* **인코더 (왼쪽)**: 인코더는 입력을 받아 입력(혹은 입력의 특징)을 구축합니다. 이는 인코더 모델이 입력을 이해하는 데에 최적화되어 있음을 의미합니다. +* **디코더 (오른쪽)**: 디코더는 인코더의 (특징) 표현과 또 다른 입력을 활용해 타겟 시퀀스를 생성합니다. 이는 디코더 모델이 출력을 생성하는 데에 최적화되어 있음을 의미합니다.
-Architecture of a Transformers models - +Architecture of a Transformers models +
트랜스포머 모델의 각 파트는 태스크에 따라 다음과 같이 개별적으로 쓰일 수도 있습니다: -- **인코더 모델(Encoder-only models)**: 문장 분류, 개체명 인식과 같이 입력에 대한 높은 이해를 요구하는 작업에 특화 -- **디코더 모델(Decoder-only models)**: 텍스트 생성과 같이 생성 관련 작업에 특화 -- **인코더-디코더(Encoder-decoder) 모델 또는 시퀀스-투-시퀀스 (Sequence-to-sequence) 모델**: 번역, 요약과 같이 입력을 필요로 하는 생성 관련 작업에 특화 +* **인코더 모델(Encoder-only models)**: 문장 분류, 개체명 인식과 같이 입력에 대한 높은 이해를 요구하는 작업에 특화 +* **디코더 모델(Decoder-only models)**: 텍스트 생성과 같이 생성 관련 작업에 특화 +* **인코더-디코더(Encoder-decoder) 모델 또는 시퀀스-투-시퀀스 (Sequence-to-sequence) 모델**: 번역, 요약과 같이 입력을 필요로 하는 생성 관련 작업에 특화 다음 단원들에서 각각의 구조에 대해 더 깊게 살펴보도록 하겠습니다. @@ -131,23 +137,23 @@ 트랜스포머 모델의 중요한 특징은 *어텐션 레이어(attention layers)*라 불리는 특수한 레이어로 구성되었다는 점입니다. 사실, 트랜스포머 구조를 처음 소개한 논문 제목마저 ["Attention Is All You Need"](https://arxiv.org/abs/1706.03762)입니다! 어텐션 레이어의 디테일에 대해서는 추후 강의에서 자세히 다루겠지만, 우선은 이 레이어가 단어의 표현을 다룰 때 입력으로 넣어준 문장의 특정 단어에 어텐션(주의)을 기울이고 특정 단어는 무시하도록 알려준다는 사실을 기억하셔야 합니다. -이러한 상황을 설명하기 위해 영어 텍스트를 프랑스어로 번역하는 작업을 생각해봅시다. “You like this course”라는 입력이 주어지면 번역 모델은 “like”라는 단어를 알맞게 번역하기 위해 인접한 단어 “You”에도 주의를 기울입니다. 이는 프랑스어의 동사 “like”가 문맥에 따라 다른 의미로 해석되기 때문입니다. 그러나 문장의 나머지 단어들은 이 단어를 번역하는 데에 크게 유용하지 않습니다. 같은 맥락에서 “this”를 번역할 때, 이 단어는 연결 명사가 남성형이거나 여성형이냐에 따라 다르게 해석될 수 있기 때문에 모델은 “course”라는 단어에 주의를 기울입니다. 여기서도 문장의 나머지 다른 단어들은 “this”의 의미를 해석하는 데에 크게 중요하지 않습니다. 더 복잡한 문법의 문장에서 모델은 문장의 각 단어를 적절히 번역하기 위해 더 멀리 떨어진 단어들에 대해서도 주의를 기울여야 합니다. +이러한 상황을 설명하기 위해 영어 텍스트를 프랑스어로 번역하는 작업을 생각해 보겠습니다. “You like this course”라는 입력이 주어지면 번역 모델은 “like”라는 단어를 알맞게 번역하기 위해 인접한 단어 “You”에도 주의를 기울입니다. 이는 프랑스어의 동사 “like”가 문맥에 따라 다른 의미로 해석되기 때문입니다. 그러나 문장의 나머지 단어들은 이 단어를 번역하는 데에 크게 유용하지 않습니다. 같은 맥락에서 “this”를 번역할 때, 이 단어는 연결 명사가 남성형이거나 여성형이냐에 따라 다르게 해석될 수 있기 때문에 모델은 “course”라는 단어에 주의를 기울입니다. 여기서도 문장의 나머지 다른 단어들은 “this”의 의미를 해석하는 데에 크게 중요하지 않습니다. 더 복잡한 문법의 문장에서 모델은 문장의 각 단어를 적절히 번역하기 위해 더 멀리 떨어진 단어들에 대해서도 주의를 기울여야 합니다. 이와 동일한 개념이 자연어의 모든 문제에 적용됩니다. 단어는 그 자체로도 의미를 갖지만 문맥상 앞뒤의 다른 단어정보를 알게 되면 의미가 달라지기도 하죠. 지금까지 어텐션 레이어가 무엇인지 알아보았으니 트랜스포머 구조에 대해 살펴보겠습니다. -## 원본 구조 The original architecture +## 원본 구조 트랜스포머 구조는 처음에 번역을 위해 만들어졌습니다. 학습시에 인코더는 특정 언어의 입력 문장을 받고, 동시에 디코더는 타겟 언어로된 동일한 의미의 문장을 받습니다. 인코더에서 어텐션 레이어는 문장 내의 모든 단어를 활요할 수 있습니다(방금 보았듯이 주어진 단어의 번역은 문장의 전후를 살펴보아야 하니까요). 반면, 디코더는 순차적으로 작동하기 때문에 문장 내에서 이미 번역이 이루어진 부분에만 주의를 기울일 수 밖에 없습니다. 이로 인해 현재 생성(번역)되고 있는 단어의 앞에 단어들만 이용할 수 있죠. 예시로, 번역된 타겟의 처음 세 단어를 예측해 놨을 때, 이 결과를 디코더로 넘기면 디코더는 인코더로부터 받은 모든 입력 정보를 함께 이용해 네 번째 올 단어를 예측하는 것입니다. 모델이 타겟 문장에 대한 액세스(access)가 있는 상황에서, 훈련 속도를 높이기 위해 디코더는 전체 타겟을 제공하지만 뒤에 올 단어들을 사용할 수 없습니다. (모델이 두 번째 올 단어를 예측하기 위해 두 번째 위치 단어를 접근할 수 있다면 예측이 의미없어지겠죠?) 예를 들어, 네 번째 단어를 예측할 때 어텐션 레이어는 1~3 번째 단어에만 액세스하도록 합니다. -원본의 트랜스포머 구조는 아래와 같이 왼쪽에는 인코더, 오른쪽에는 디코더가 있는 형태를 지닙니다: +원래 처음 트랜스포머의 구조는 아래와 같이 왼쪽에는 인코더, 오른쪽에는 디코더가 있는 형태를 지닙니다:
-Architecture of a Transformers models - +Architecture of a Transformers models +
디코더 블럭의 첫 번째 어텐션 레이어는 모든 이전의 디코더 입력에 대해 주의를 기울이지만, 두 번째 어텐션 레이어는 인코더의 출력만 사용하는 점을 주목하세요. 이로써 디코더는 전체 입력 문장에 액세스하여 현재 올 단어를 잘 예측하게 되는 것입니다. 이는 서로 다른 언어는 서로 다른 어순을 갖거나 문장의 뒷부분에 등장하는 문맥이 주어진 단어의 가장 적합한 번역을 결정할 수 있기 때문에 매우 유용합니다. @@ -158,8 +164,8 @@ 트랜스포머 모델을 본격적으로 공부하기 앞서, 모델(models)과 함께 *구조(architectures)*와 *체크포인트(checkpoints)*라는 단어를 들으시게 될겁니다. 이 셋은 아래와 같이 조금 다른 의미를 갖고 있습니다: -- **구조(Architecture)**: 모델의 뼈대를 의미하는 용어로, 모델 내부의 각 레이어와 각 연산 작용들을 의미합니다. -- 체크포인트(**Checkpoints)**: 주어진 구조(architecture)에 적용될 가중치들을 의미합니다. -- 모델(**Model)**: 사실 모델은 “구조”나 “가중치”만큼 구체적이지 않은 두루뭉실한 용어입니다. 이 강의에서는 모호함을 피하기 위해 *구조(architecture)*와 *체크포인트(checkpoint)*를 구분해서 사용하도록 하겠습니다. +* **구조(Architecture)**: 모델의 뼈대를 의미하는 용어로, 모델 내부의 각 레이어와 각 연산 작용들을 의미합니다. +* **체크포인트(Checkpoints)**: 주어진 구조(architecture)에 적용될 가중치들을 의미합니다. +* **모델(Model)**: 사실 모델은 “구조”나 “가중치”만큼 구체적이지 않은, 다소 뭉뚱그려 사용되는 용어입니다. 이 강의에서는 모호함을 피하기 위해 *구조(architecture)*와 *체크포인트(checkpoint)*를 구분해서 사용하도록 하겠습니다. -예를 들어, BERT는 구조인 반면, Google 팀이 최초 공개에서 내놓은 학습된 가중치 모음인 `bert-base-cased` 는 체크포인트입니다. 그치만 “BERT 모델”, “`bert-base-cased` 모델” 등과 같이 혼용해도 괜찮습니다. \ No newline at end of file +예를 들면, BERT는 구조에 해당하고, Google 팀이 최초 공개에서 내놓은 학습 가중치 셋인 `bert-base-cased`는 체크포인에 해당합니다. 그렇지만 “BERT 모델”, “`bert-base-cased` 모델” 등과 같이 구분하지 않고 사용하기도 합니다. diff --git a/chapters/ko/chapter1/5.mdx b/chapters/ko/chapter1/5.mdx index 755310f6c..3c133aea8 100644 --- a/chapters/ko/chapter1/5.mdx +++ b/chapters/ko/chapter1/5.mdx @@ -14,4 +14,4 @@ - [BERT](https://huggingface.co/transformers/model_doc/bert.html) - [DistilBERT](https://huggingface.co/transformers/model_doc/distilbert.html) - [ELECTRA](https://huggingface.co/transformers/model_doc/electra.html) -- [RoBERTa](https://huggingface.co/transformers/model_doc/roberta.html) \ No newline at end of file +- [RoBERTa](https://huggingface.co/transformers/model_doc/roberta.html) diff --git a/chapters/ko/chapter1/6.mdx b/chapters/ko/chapter1/6.mdx index 4f8f0afa8..121403b4d 100644 --- a/chapters/ko/chapter1/6.mdx +++ b/chapters/ko/chapter1/6.mdx @@ -13,4 +13,4 @@ - [CTRL](https://huggingface.co/transformers/model_doc/ctrl.html) - [GPT](https://huggingface.co/transformers/model_doc/gpt.html) - [GPT-2](https://huggingface.co/transformers/model_doc/gpt2.html) -- [Transformer XL](https://huggingface.co/transformers/model_doc/transformerxl.html) \ No newline at end of file +- [Transformer XL](https://huggingface.co/transformers/model_doc/transformerxl.html) diff --git a/chapters/ko/chapter1/7.mdx b/chapters/ko/chapter1/7.mdx index 2cca23686..98aad86e9 100644 --- a/chapters/ko/chapter1/7.mdx +++ b/chapters/ko/chapter1/7.mdx @@ -2,7 +2,7 @@ -인코더-디코더 모델(Encoder-decoder models)로도 불리는 *시퀀스-투-시퀀스 모델(sequence-to-sequence models)*은 트랜스포머 구조의 인코더, 디코더 둘을 모두 사용합니다. 각 단계마다, 인코더의 어텐션 레이어는 초기 문장의 모든 단어에 액세스 할 수 있는 반면, 디코더의 어텐션 레이어는 주어진 단어 앞에 위치한 단어들에만 액세스 할 수 있습니다. +인코더-디코더 모델(Encoder-decoder models) (*시퀀스-투-시퀀스 모델(sequence-to-sequence models)*로 부르기도 합니다)은 트랜스포머 구조의 인코더, 디코더 둘을 모두 사용합니다. 각 단계마다, 인코더의 어텐션 레이어는 초기 문장의 모든 단어에 액세스 할 수 있는 반면, 디코더의 어텐션 레이어는 주어진 단어 앞에 위치한 단어들에만 액세스 할 수 있습니다. 이러한 모델의 사전 학습은 인코더 혹은 디코더 모델의 방식을 모두 사용할 수 있지만 조금 더 복잡합니다. 이를테면, [T5](https://huggingface.co/t5-base)는 (여러 단어를 포함하기도 하는) 임의의 텍스트 범위를 하나의 특수 마스크 토큰으로 바꾸고 마스크 단어를 대체할 텍스트를 예측하는 방식으로 사전 학습 되었습니다. diff --git a/chapters/ko/chapter1/8.mdx b/chapters/ko/chapter1/8.mdx index 1466b0fbe..edbd32548 100644 --- a/chapters/ko/chapter1/8.mdx +++ b/chapters/ko/chapter1/8.mdx @@ -1,17 +1,17 @@ # 편향과 한계 사전 학습된 혹은 미세 조정된 모델을 프로덕션 단계에서 사용하실 계획이라면, 이러한 모델들은 강력한 툴이지만 한계가 있음을 반드시 명심하셔야 합니다. 가장 큰 한계점은 리서처들이 무수히 많은 양의 데이터를 사전 학습에 사용하기 위해, 인터넷상에서 모을 수 있는 양질의 데이터와 함께 그렇지 않은 데이터까지 수집했을 가능성이 있다는 것입니다. 이를 빠르게 보여드리기 위해 `fill-mask` 파이프라인에 BERT 모델을 연결한 예제를 다시 살펴보겠습니다: -``` +```python from transformers import pipeline unmasker = pipeline("fill-mask", model="bert-base-uncased") @@ -20,15 +20,13 @@ print([r["token_str"] for r in result]) result = unmasker("This woman works as a [MASK].") print([r["token_str"] for r in result]) - ``` -``` +```python out ['lawyer', 'carpenter', 'doctor', 'waiter', 'mechanic'] ['nurse', 'waitress', 'teacher', 'maid', 'prostitute'] - ``` -주어의 성별만 바꾼 두 문장에서 빠진 단어를 채울 때, 모델은 성별과 관계 없는 공통 답변(waiter/waitress)을 하나만 내놓았습니다. 다른 답변들은 일반적으로 특정 성별에 편향된 답변이었습니다. 이를테면, 모델은 매춘이라는 단어와 연관된 상위 5개의 단어에 “여성”과 “일”을 포함시켰습니다. BERT가 전체 인터넷 상의 텍스트를 이용하여 사전 학습된 것이 아니라 [English Wikipedia](https://huggingface.co/datasets/wikipedia) 와 [BookCorpus](https://huggingface.co/datasets/bookcorpus) 같이 상당히 중립적인 데이터를 이용하여 사전 학습 되었음에도 불구하고 이러한 현상이 일어납니다. +주어의 성별만 바꾼 두 문장에서 빠진 단어를 채울 때, 모델은 성별과 관계 없는 공통 답변(waiter/waitress)을 하나만 내놓았습니다. 다른 답변들은 일반적으로 특정 성별에 편향된 답변이었습니다. 이를테면, 모델은 매춘이라는 단어와 연관된 상위 5개의 단어에 “여성”과 “일”을 포함시켰습니다. BERT가 전체 인터넷 상의 텍스트를 이용하여 사전 학습된 것이 아니라 [English Wikipedia](https://huggingface.co/datasets/wikipedia) 와 [BookCorpus](https://huggingface.co/datasets/bookcorpus) 같이 상당히 중립적인 데이터를 이용해 사전 학습 되었음에도 불구하고 이러한 현상이 일어납니다. 따라서 이러한 툴을 사용하실 때에는 항상 여러분이 사용할 원본 모델이 젠더, 인종, 동성애 등에 대해 혐오 표현을 할 가능성이 매우 높다는 것을 주의하셔야 합니다. 이러한 모델은 미세 조정을 거쳐도 내제된 편향성을 없애지 못합니다. \ No newline at end of file diff --git a/chapters/ko/chapter1/9.mdx b/chapters/ko/chapter1/9.mdx index 3ebcd1701..191b5654d 100644 --- a/chapters/ko/chapter1/9.mdx +++ b/chapters/ko/chapter1/9.mdx @@ -1,8 +1,8 @@ # 단원 정리 -이번 단원에서는 🤗 Transformers의 하이레벨 함수인 `pipeline()` 를 사용하여 다양한 NLP 문제에 대한 접근 방식을 학습했습니다. 그리고 Hub에서 모델을 검색 및 사용하는 방법, Inference API를 이용해 브라우저 상에서 바로 모델을 테스트 하는 방법 또한 알아보았습니다. +이번 단원에서는 🤗 Transformers의 하이레벨 함수인 `pipeline()` 를 사용하여 다양한 NLP 문제에 대한 접근 방식을 배웠습니다. 그리고 Hub에서 모델을 검색하여 사용하는 방법, 추론 API를 이용해 브라우저 상에서 바로 모델을 테스트 하는 방법 또한 알아보았습니다. -지금까지 트랜스포머 모델의 대략작인 동작 방식과, 전이 학습(transfer learning)과 미세 조정(fine-tuning)의 중요성에 알아보았습니다. 핵심은 어떤 문제를 풀고싶냐에 따라 전체 모델 구조를 다 사용하거나 인코더, 디코더만 사용할 수도 있다는 것입니다. 아래 표는 이를 요약해서 보여주고 있습니다: +지금까지 트랜스포머 모델의 대략작인 동작 방식과, 전이 학습(transfer learning) 및 미세 조정(fine-tuning)의 중요성에 알아보았습니다. 핵심은 어떤 문제를 풀고싶냐에 따라 전체 모델 구조를 다 사용하거나 인코더, 디코더만 사용할 수도 있다는 것입니다. 아래 표는 이를 요약해서 보여주고 있습니다: | Model | Examples | Tasks | | --- | --- | --- | From ec1b5d9c2b6ac14156baf6c2150d40f71895d24d Mon Sep 17 00:00:00 2001 From: ftarlaci <18291571+ftarlaci@users.noreply.github.com> Date: Tue, 5 Apr 2022 15:30:57 -0500 Subject: [PATCH 59/73] modified toctree.yml for chapter1/2 --- chapters/tr/_toctree.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/tr/_toctree.yml b/chapters/tr/_toctree.yml index 7c06284a4..5d84b3422 100644 --- a/chapters/tr/_toctree.yml +++ b/chapters/tr/_toctree.yml @@ -4,7 +4,7 @@ title: Giriş -- title: 1. Transformer modelleri +- title: 1. Transormer modelleri sections: - local: chapter1/2 title: Doğal Dil İşleme From 6723a3f88108e7cd44697c9d57a28e5de0fc2ebb Mon Sep 17 00:00:00 2001 From: ftarlaci <18291571+ftarlaci@users.noreply.github.com> Date: Tue, 5 Apr 2022 15:36:17 -0500 Subject: [PATCH 60/73] modified toctree.yml for chapter1/2 & fix typo --- chapters/tr/_toctree.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/tr/_toctree.yml b/chapters/tr/_toctree.yml index 5d84b3422..7c06284a4 100644 --- a/chapters/tr/_toctree.yml +++ b/chapters/tr/_toctree.yml @@ -4,7 +4,7 @@ title: Giriş -- title: 1. Transormer modelleri +- title: 1. Transformer modelleri sections: - local: chapter1/2 title: Doğal Dil İşleme From 90fbf37101c66235aa26e50c503cfa14f6d50aa8 Mon Sep 17 00:00:00 2001 From: Lewis Tunstall Date: Mon, 11 Apr 2022 10:28:10 +0200 Subject: [PATCH 61/73] Add Bengali to CI --- .github/workflows/build_documentation.yml | 2 +- .github/workflows/build_pr_documentation.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_documentation.yml b/.github/workflows/build_documentation.yml index 0ea12e682..a7714c94a 100644 --- a/.github/workflows/build_documentation.yml +++ b/.github/workflows/build_documentation.yml @@ -14,6 +14,6 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: en es fr he ko pt th tr + languages: bn en es fa fr he ko pt ru th tr secrets: token: ${{ secrets.HUGGINGFACE_PUSH }} \ No newline at end of file diff --git a/.github/workflows/build_pr_documentation.yml b/.github/workflows/build_pr_documentation.yml index 8fcd7524d..f7b92f51d 100644 --- a/.github/workflows/build_pr_documentation.yml +++ b/.github/workflows/build_pr_documentation.yml @@ -16,5 +16,5 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: en es fr he ko pt th tr + languages: bn en es fa fr he ko pt ru th tr hub_base_path: https://moon-ci-docs.huggingface.co/course \ No newline at end of file From e82904fc4ee810d5a010e2d65582c37ee9e2b93d Mon Sep 17 00:00:00 2001 From: Lewis Tunstall Date: Mon, 11 Apr 2022 10:28:31 +0200 Subject: [PATCH 62/73] Update author list --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a10534eef..2b70941d7 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ This repo contains the content that's used to create the **[Hugging Face course] | Language | Source | Authors | |:-------------------------------------------------------|:-----------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [English](https://huggingface.co/course/en/chapter1/1) | [`chapters/en`](https://github.com/huggingface/course/tree/main/chapters/en) | [@sgugger](https://github.com/sgugger), [@lewtun](https://github.com/lewtun), [@LysandreJik](https://github.com/LysandreJik), [@Rocketknight1](https://github.com/Rocketknight1), [@sashavor](https://github.com/sashavor), [@osanseviero](https://github.com/osanseviero), [@SaulLu](https://github.com/SaulLu), [@lvwerra](https://github.com/lvwerra) | +| [Korean](https://huggingface.co/course/ko/chapter1/1) (WIP) | [`chapters/ko`](https://github.com/huggingface/course/tree/main/chapters/ko) | [@Doohae](https://github.com/Doohae) | | [Russian](https://huggingface.co/course/ru/chapter1/1) (WIP) | [`chapters/ru`](https://github.com/huggingface/course/tree/main/chapters/ru) | [@pdumin](https://github.com/pdumin) | | [Spanish](https://huggingface.co/course/es/chapter1/1) (WIP) | [`chapters/es`](https://github.com/huggingface/course/tree/main/chapters/es) | [@camartinezbu](https://github.com/camartinezbu) | | [Thai](https://huggingface.co/course/th/chapter1/1) (WIP) | [`chapters/th`](https://github.com/huggingface/course/tree/main/chapters/th) | [@peeraponw](https://github.com/peeraponw), [@a-krirk](https://github.com/a-krirk), [@jomariya23156](https://github.com/jomariya23156) | From 9dcf5dac7e949f9e14e0adf5085e8c5abeca3555 Mon Sep 17 00:00:00 2001 From: Jose M Munoz Date: Mon, 11 Apr 2022 09:18:16 -0500 Subject: [PATCH 63/73] =?UTF-8?q?Adding=20translations=20for=202/4=20and?= =?UTF-8?q?=202/5=20=F0=9F=9A=80=20(#74)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adding translations for 2/4 and 2/5 🚀 * Remove English content Co-authored-by: lewtun --- chapters/es/_toctree.yml | 7 + chapters/es/chapter2/4.mdx | 235 ++++++++++++++++++++++++++ chapters/es/chapter2/5.mdx | 332 +++++++++++++++++++++++++++++++++++++ 3 files changed, 574 insertions(+) create mode 100644 chapters/es/chapter2/4.mdx create mode 100644 chapters/es/chapter2/5.mdx diff --git a/chapters/es/_toctree.yml b/chapters/es/_toctree.yml index 5ee96568f..2cdc73523 100644 --- a/chapters/es/_toctree.yml +++ b/chapters/es/_toctree.yml @@ -26,3 +26,10 @@ - local: chapter1/10 title: Quiz de final de capítulo quiz: 1 + +- title: 2. Usando Transformers 🤗 + sections: + - local: chapter2/4 + title: Tokenizadores + - local: chapter2/5 + title: Manejando Secuencias Múltiples diff --git a/chapters/es/chapter2/4.mdx b/chapters/es/chapter2/4.mdx new file mode 100644 index 000000000..7a3b40160 --- /dev/null +++ b/chapters/es/chapter2/4.mdx @@ -0,0 +1,235 @@ + + +# Tokenizadores + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + + + +Los tokenizadores son uno de los componentes fundamentales del pipeline en NLP. Sirven para traducir texto en datos que los modelos puedan procesar; es decir, de texto a valores numéricos. En esta sección veremos en qué se fundamenta todo el proceso de tokenizado. + +En las tareas de NLP, los datos generalmente ingresan como texto crudo. Por ejemplo: +``` +Jim Henson era un titiritero +``` + +Sin embargo, necesitamos una forma de convertir el texto crudo a valores numéricos para los modelos. Eso es precisamente lo que hacen los tokenizadores, y existe una variedad de formas en que puede hacerse. El objetivo final es obetener valores que sean cortos pero muy significativos para el modelo. + +Veamos algunos algoritmos de tokenización, e intentemos atacar algunas preguntas que puedas tener. + +## Tokenización Word-based + + + +El primer tokenizador que nos ocurre es el _word-based_ (_basado-en-palabras_). Es generalmente sencillo, con pocas normas, y generalmente da buenos resultados. Por ejemplo, en la imagen a continuación separamos el texto en palabras y buscamos una representación numérica. +
+ Un ejemplo de tokenizador _word-based_. + +
+ +Existen varias formas de separar el texto. Por ejempĺo, podríamos usar los espacios para tokenizar usando Python y la función `split()`. + +```py +tokenized_text = "Jim Henson era un titiritero".split() +print(tokenized_text) +``` + +```python out +['Jim', 'Henson', 'era', 'un', 'titiritero'] +``` +También hay variaciones de tokenizadores de palabras que tienen reglas adicionales para la puntuación. Con este tipo de tokenizador, podemos acabar con unos "vocabularios" bastante grandes, donde un vocabulario se define por el número total de tokens independientes que tenemos en nuestro corpus. + +A cada palabra se le asigna un ID, empezando por 0 y subiendo hasta el tamaño del vocabulario. El modelo utiliza estos ID para identificar cada palabra. + +Si queremos cubrir completamente un idioma con un tokenizador basado en palabras, necesitaremos tener un identificador para cada palabra del idioma, lo que generará una enorme cantidad de tokens. Por ejemplo, hay más de 500.000 palabras en el idioma inglés, por lo que para construir un mapa de cada palabra a un identificador de entrada necesitaríamos hacer un seguimiento de esa cantidad de identificadores. Además, palabras como "perro" se representan de forma diferente a palabras como "perros", y el modelo no tendrá forma de saber que "perro" y "perros" son similares: identificará las dos palabras como no relacionadas. Lo mismo ocurre con otras palabras similares, como "correr" y "corriendo", que el modelo no verá inicialmente como similares. + +Por último, necesitamos un token personalizado para representar palabras que no están en nuestro vocabulario. Esto se conoce como el token "desconocido", a menudo representado como "[UNK]" o "<unk>". Generalmente, si el tokenizador está produciendo muchos de estos tokens es una mala señal, ya que no fue capaz de recuperar una representación de alguna palabra y está perdiendo información en el proceso. El objetivo al elaborar el vocabulario es hacerlo de tal manera que el tokenizador tokenice el menor número de palabras posibles en tokens desconocidos. + +Una forma de reducir la cantidad de tokens desconocidos es ir un poco más allá, utilizando un tokenizador _word-based_. + +## Tokenización Character-based + + + +Character-based tokenizers split the text into characters, rather than words. This has two primary benefits: +Un tokenizador _character-based_ separa el texto en caracteres, y no en palabras. Conllevando dos beneficios principales: + +- Obtenemos un vocabulario mucho más corto. +- Habrá muchos menos tokens por fuera del vocabulatio conocido. + +No obstante, pueden surgir incovenientes por los espacios en blanco y signos de puntuación. + +
+ Ejemplo de tokenizador basado en palabras. + +
+ +Así, este método tampoco es perfecto. Dada que la representación se construyó con caracteres, uno podría pensar intuitivamente que resulta menos significativo: Cada una de las palabras no significa mucho por separado, mientras que las palabras sí. Sin embargo, eso es dependiente del idioma. Por ejemplo en Chino, cada uno de los caracteres conlleva más información que en un idioma latino. + +Otro aspecto a considerar es que terminamos con una gran cantidad de tokens que el modelo debe procesar, mientras que en el caso del tokenizador _word-based_, un token representa una palabra, en la representación de caracteres fácilmente puede necesitar más de 10 tokens. + +Para obtener lo mejor de ambos mundos, podemos usar una combinación de las técnicas: la tokenización por *subword tokenization*. + +## Tokenización por Subword + + + +Los algoritmos de tokenización de subpalabras se basan en el principio de que las palabras de uso frecuente no deben dividirse, mientras que las palabras raras deben descomponerse en subpalabras significativas. + +Por ejemplo, "extrañamente" podría considerarse una palabra rara y podría descomponerse en "extraña" y "mente". Es probable que ambas aparezcan con más frecuencia como subpalabras independientes, mientras que al mismo tiempo el significado de "extrañamente" se mantiene por el significado compuesto de "extraña" y "mente". + +Este es un ejemplo que muestra cómo un algoritmo de tokenización de subpalabras tokenizaría la secuencia "Let's do tokenization!": + +
+ Un tokenizador basado en subpalabras. + +
+ +Estas subpalabras terminan aportando mucho significado semántico: por ejemplo, en el ejemplo anterior, "tokenización" se dividió en "token" y "ización", dos tokens que tienen un significado semántico y a la vez son eficientes en cuanto al espacio (sólo se necesitan dos tokens para representar una palabra larga). Esto nos permite tener una cobertura relativamente buena con vocabularios pequeños y casi sin tokens desconocidos. + +Este enfoque es especialmente útil en algunos idimas como el turco, donde se pueden formar palabras complejas (casi) arbitrariamente largas encadenando subpalabras. + +### Y más! + +Como es lógico, existen muchas más técnicas. Por nombrar algunas: + +- Byte-level BPE (a nivel de bytes), como usa GPT-2 +- WordPiece, usado por BERT +- SentencePiece or Unigram (pedazo de sentencia o unigrama), como se usa en los modelos multilengua + +A este punto, deberías tener conocimientos suficientes sobre el funcionamiento de los tokenizadores para empezar a utilizar la API. + +## Cargando y guardando + +Cargar y guardar tokenizadores es tan sencillo como lo es con los modelos. En realidad, se basa en los mismos dos métodos: `from_pretrained()` y `save_pretrained()`. Estos métodos cargarán o guardarán el algoritmo utilizado por el tokenizador (un poco como la *arquitectura* del modelo) así como su vocabulario (un poco como los *pesos* del modelo). + +La carga del tokenizador BERT entrenado con el mismo punto de control que BERT se realiza de la misma manera que la carga del modelo, excepto que utilizamos la clase `BertTokenizer`: + +```py +from transformers import BertTokenizer + +tokenizer = BertTokenizer.from_pretrained("bert-base-cased") +``` + +{#if fw === 'pt'} +Al igual que `AutoModel`, la clase `AutoTokenizer` tomará la clase de tokenizador adecuada en la biblioteca basada en el nombre del punto de control, y se puede utilizar directamente con cualquier punto de control: + +{:else} +Al igual que `TFAutoModel`, la clase `AutoTokenizer` tomará la clase de tokenizador adecuada en la biblioteca basada en el nombre del punto de control, y se puede utilizar directamente con cualquier punto de control: + +{/if} + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +``` + +Ahora podemos utilizar el tokenizador como se muestra en la sección anterior: + +```python +tokenizer("Using a Transformer network is simple") +``` + +```python out +{'input_ids': [101, 7993, 170, 11303, 1200, 2443, 1110, 3014, 102], + 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0], + 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]} +``` +Guardar un tokenizador es idéntico a guardar un modelo: + +```py +tokenizer.save_pretrained("directorio_en_mi_computador") +``` + +Hablaremos más sobre `token_type_ids` en el [Capítulo 3](/course/chapter3), y explicaremos la clave `attention_mask` un poco más tarde. Primero, veamos cómo se generan los `input_ids`. Para ello, tendremos que ver los métodos intermedios del tokenizador. + +## Encoding + + + +La traducción de texto a números se conoce como _codificación_. La codificación se realiza en un proceso de dos pasos: la tokenización, seguida de la conversión a IDs de entrada. + +Como hemos visto, el primer paso es dividir el texto en palabras (o partes de palabras, símbolos de puntuación, etc.), normalmente llamadas *tokens*. Hay múltiples reglas que pueden gobernar ese proceso, por lo que necesitamos instanciar el tokenizador usando el nombre del modelo, para asegurarnos de que usamos las mismas reglas que se usaron cuando se preentrenó el modelo. + +El segundo paso es convertir esos tokens en números, para poder construir un tensor con ellos y alimentar el modelo. Para ello, el tokenizador tiene un *vocabulario*, que es la parte que descargamos cuando lo instanciamos con el método `from_pretrained()`. De nuevo, necesitamos usar el mismo vocabulario que se usó cuando el modelo fue preentrenado. + +Para entender mejor los dos pasos, los exploraremos por separado. Ten en cuenta que utilizaremos algunos métodos que realizan partes del proceso de tokenización por separado para mostrarte los resultados intermedios de esos pasos, pero en la práctica, deberías llamar al tokenizador directamente en tus _inputs_ (como se muestra en la sección 2). + +### Tokenization + +El proceso de tokenización se realiza mediante el método `tokenize()` del tokenizador: + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") + +sequence = "Using a Transformer network is simple" +tokens = tokenizer.tokenize(sequence) + +print(tokens) +``` + +La salida de este método es una lista de cadenas, o tokens: + +```python out +['Using', 'a', 'transform', '##er', 'network', 'is', 'simple'] +``` + +Este tokenizador es un tokenizador de subpalabras: divide las palabras hasta obtener tokens que puedan ser representados por su vocabulario. Este es el caso de `transformer`, que se divide en dos tokens: `transform` y `##er`. + +### De tokens a IDs de entrada + +La conversión a IDs de entrada se hace con el método del tokenizador `convert_tokens_to_ids()`: +```py +ids = tokenizer.convert_tokens_to_ids(tokens) + +print(ids) +``` + +```python out +[7993, 170, 11303, 1200, 2443, 1110, 3014] +``` + +Estos resultados, una vez convertidos en el tensor del marco apropiado, pueden utilizarse como entradas de un modelo, como se ha visto anteriormente en este capítulo. + + + +✏️ **Try it out!** Replica los dos últimos pasos (tokenización y conversión a IDs de entrada) en las frases de entrada que utilizamos en la sección 2 ("Llevo toda la vida esperando un curso de HuggingFace" y "¡Odio tanto esto!"). Comprueba que obtienes los mismos ID de entrada que obtuvimos antes! + + + +## Decodificación + +La *decodificación* va al revés: a partir de los índices del vocabulario, queremos obtener una cadena. Esto se puede hacer con el método `decode()` de la siguiente manera: + +```py +decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014]) +print(decoded_string) +``` + +```python out +'Using a Transformer network is simple' +``` +Notemos que el método `decode` no sólo convierte los índices de nuevo en tokens, sino que también agrupa los tokens que formaban parte de las mismas palabras para producir una frase legible. Este comportamiento será extremadamente útil cuando utilicemos modelos que predigan texto nuevo (ya sea texto generado a partir de una indicación, o para problemas de secuencia a secuencia como la traducción o el resumen). + +A estas alturas deberías entender las operaciones atómicas que un tokenizador puede manejar: tokenización, conversión a IDs, y conversión de IDs de vuelta a una cadena. Sin embargo, sólo hemos rozado la punta del iceberg. En la siguiente sección, llevaremos nuestro enfoque a sus límites y echaremos un vistazo a cómo superarlos. \ No newline at end of file diff --git a/chapters/es/chapter2/5.mdx b/chapters/es/chapter2/5.mdx new file mode 100644 index 000000000..606f9bc89 --- /dev/null +++ b/chapters/es/chapter2/5.mdx @@ -0,0 +1,332 @@ + + +# Manejando Secuencias Múltiples + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +{#if fw === 'pt'} + +{:else} + +{/if} + +En la sección anterior, hemos explorado el caso de uso más sencillo: hacer inferencia sobre una única secuencia de poca longitud. Sin embargo, surgen algunas preguntas: + +- ¿Cómo manejamos las secuencias múltiples? +- ¿Cómo manejamos las secuencias múltiples *de diferentes longitudes*? +- ¿Son los índices de vocabulario las únicas entradas que permiten que un modelo funcione bien? +- ¿Existe una secuencia demasiado larga? + +Veamos qué tipo de problemas plantean estas preguntas, y cómo podemos resolverlos utilizando la API de Transformers 🤗. + +## Los modelos esperan Baches de entrada + +En el ejercicio anterior has visto cómo las secuencias se traducen en listas de números. Convirtamos esta lista de números en un tensor y enviémoslo al modelo: + +{#if fw === 'pt'} +```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) +# Esta línea va a fallar: +model(input_ids) +``` + +```python out +IndexError: Dimension out of range (expected to be in range of [-1, 0], but got 1) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.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 = tf.constant(ids) +# Esta línea va a fallar: +model(input_ids) +``` + +```py out +InvalidArgumentError: Input to reshape is a tensor with 14 values, but the requested shape has 196 [Op:Reshape] +``` +{/if} +¡Oh, no! ¿Por qué ha fallado esto? "Hemos seguido los pasos de la tubería en la sección 2. + +El problema es que enviamos una sola secuencia al modelo, mientras que los modelos de 🤗 Transformers esperan múltiples frases por defecto. Aquí tratamos de hacer todo lo que el tokenizador hizo detrás de escena cuando lo aplicamos a una `secuencia`, pero si te fijas bien, verás que no sólo convirtió la lista de IDs de entrada en un tensor, sino que le agregó una dimensión encima: + +{#if fw === 'pt'} +```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]]) +``` +{:else} +```py +tokenized_inputs = tokenizer(sequence, return_tensors="tf") +print(tokenized_inputs["input_ids"]) +``` + +```py out + +``` +{/if} +Intentémoslo de nuevo y añadamos una nueva dimensión encima: + + +{#if fw === 'pt'} +```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) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.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 = tf.constant([ids]) +print("Input IDs:", input_ids) + +output = model(input_ids) +print("Logits:", output.logits) +``` +{/if} +Imprimimos los IDs de entrada así como los logits resultantes - aquí está la salida: + +{#if fw === 'pt'} +```python out +Input IDs: [[ 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012]] +Logits: [[-2.7276, 2.8789]] +``` +{:else} +```py out +Input IDs: tf.Tensor( +[[ 1045 1005 2310 2042 3403 2005 1037 17662 12172 2607 2026 2878 + 2166 1012]], shape=(1, 14), dtype=int32) +Logits: tf.Tensor([[-2.7276208 2.8789377]], shape=(1, 2), dtype=float32) +``` +{/if} +*El "batching"* es el acto de enviar varias frases a través del modelo, todas a la vez. Si sólo tienes una frase, puedes construir un lote con una sola secuencia: + +``` +batched_ids = [ids, ids] +``` + +Se trata de un lote de dos secuencias idénticas. + + + +✏️ **Try it out!** Convierte esta lista `batched_ids` en un tensor y pásalo por tu modelo. Comprueba que obtienes los mismos logits que antes (¡pero dos veces!). + + + +La creación de lotes permite que el modelo funcione cuando lo alimentas con múltiples sentencias. Utilizar varias secuencias es tan sencillo como crear un lote con una sola secuencia. Sin embargo, hay un segundo problema. Cuando se trata de agrupar dos (o más) frases, éstas pueden ser de diferente longitud. Si alguna vez ha trabajado con tensores, sabrá que deben tener forma rectangular, por lo que no podrá convertir la lista de IDs de entrada en un tensor directamente. Para evitar este problema, usamos el *padding* para las entradas. + +## Padding a las entradas + +La siguiente lista de listas no se puede convertir en un tensor: + +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200] +] +``` +Para solucionar esto, utilizaremos *padding* para que nuestros tensores tengan una forma rectangular. El acolchado asegura que todas nuestras sentencias tengan la misma longitud añadiendo una palabra especial llamada *padding token* a las sentencias con menos valores. Por ejemplo, si tienes 10 frases con 10 palabras y 1 frase con 20 palabras, el relleno asegurará que todas las frases tengan 20 palabras. En nuestro ejemplo, el tensor resultante tiene este aspecto: + +```py no-format +padding_id = 100 + +batched_ids = [ + [200, 200, 200], + [200, 200, padding_id], +] +``` +El ID del *padding token* se puede encontrar en `tokenizer.pad_token_id`. Usémoslo y enviemos nuestras dos sentencias a través del modelo de forma individual y por lotes: + + +{#if fw === 'pt'} +```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=) +tensor([[ 0.5803, -0.4125]], grad_fn=) +tensor([[ 1.5694, -1.3895], + [ 1.3373, -1.2163]], grad_fn=) +``` +{:else} +```py no-format +model = TFAutoModelForSequenceClassification.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(tf.constant(sequence1_ids)).logits) +print(model(tf.constant(sequence2_ids)).logits) +print(model(tf.constant(batched_ids)).logits) +``` + +```py out +tf.Tensor([[ 1.5693678 -1.3894581]], shape=(1, 2), dtype=float32) +tf.Tensor([[ 0.5803005 -0.41252428]], shape=(1, 2), dtype=float32) +tf.Tensor( +[[ 1.5693681 -1.3894582] + [ 1.3373486 -1.2163193]], shape=(2, 2), dtype=float32) +``` +{/if} + +Hay un problema con los logits en nuestras predicciones por lotes: la segunda fila debería ser la misma que los logits de la segunda frase, ¡pero tenemos valores completamente diferentes! + +Esto se debe a que la característica clave de los modelos Transformer son las capas de atención que *contextualizan* cada token. Éstas tendrán en cuenta los tokens de relleno, ya que atienden a todos los tokens de una secuencia. Para obtener el mismo resultado al pasar oraciones individuales de diferente longitud por el modelo o al pasar un lote con las mismas oraciones y el padding aplicado, tenemos que decirles a esas capas de atención que ignoren los tokens de padding. Esto se hace utilizando una máscara de atención. + +## Máscaras de atención + +*Las máscaras de atención* son tensores con la misma forma que el tensor de IDs de entrada, rellenados con 0s y 1s: los 1s indican que los tokens correspondientes deben ser atendidos, y los 0s indican que los tokens correspondientes no deben ser atendidos (es decir, deben ser ignorados por las capas de atención del modelo). + +{#if fw === 'pt'} +```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=) +``` +{:else} +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200, tokenizer.pad_token_id], +] + +attention_mask = [ + [1, 1, 1], + [1, 1, 0], +] + +outputs = model(tf.constant(batched_ids), attention_mask=tf.constant(attention_mask)) +print(outputs.logits) +``` + +```py out +tf.Tensor( +[[ 1.5693681 -1.3894582 ] + [ 0.5803021 -0.41252586]], shape=(2, 2), dtype=float32) +``` +{/if} + +Ahora obtenemos los mismos logits para la segunda frase del lote. + +Podemos ver que el último valor de la segunda secuencia es un ID de relleno, que es un valor 0 en la máscara de atención. + + + +✏️ **Try it out!** Aplique la tokenización manualmente a las dos frases utilizadas en la sección 2 ("Llevo toda la vida esperando un curso de HuggingFace" y "¡Odio tanto esto!"). Páselas por el modelo y compruebe que obtiene los mismos logits que en la sección 2. Ahora júntalos usando el token de relleno, y luego crea la máscara de atención adecuada. Comprueba que obtienes los mismos resultados al pasarlos por el modelo. + + + +## Secuencias largas + +Con los modelos Transformer, hay un límite en la longitud de las secuencias que podemos pasar a los modelos. La mayoría de los modelos manejan secuencias de hasta 512 o 1024 tokens, y se bloquean cuando se les pide que procesen secuencias más largas. Hay dos soluciones a este problema: + +- Usar un modelo que soporte secuencias largas +- Truncar tus secuencias + +Los modelos tienen diferentes longitudes de secuencia soportadas, y algunos se especializan en el manejo de secuencias muy largas. Un ejemplo es [Longformer](https://huggingface.co/transformers/model_doc/longformer.html) y otro es [LED](https://huggingface.co/transformers/model_doc/led.html). Si estás trabajando en una tarea que requiere secuencias muy largas, te recomendamos que eches un vistazo a esos modelos. + +En caso contrario, le recomendamos que trunque sus secuencias especificando el parámetro `max_sequence_length`: + +```py +sequence = sequence[:max_sequence_length] +``` From 8e8e5c1189ac8c722495ed5b3116b960e31761a0 Mon Sep 17 00:00:00 2001 From: svv73 <88366711+svv73@users.noreply.github.com> Date: Tue, 12 Apr 2022 12:48:05 +0400 Subject: [PATCH 64/73] Translation to Russian (#97) * translation of chapter 2/section 1 * add section 1 / chapter 2 to _toctree.yml --- chapters/ru/_toctree.yml | 5 +++++ chapters/ru/chapter2/1.mdx | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 chapters/ru/chapter2/1.mdx diff --git a/chapters/ru/_toctree.yml b/chapters/ru/_toctree.yml index e597bd2e0..b8a26b63b 100644 --- a/chapters/ru/_toctree.yml +++ b/chapters/ru/_toctree.yml @@ -11,3 +11,8 @@ title: Обработка естесственного языка - local: chapter1/3 title: Трансформеры, на что они способны? + +- title: 2. Использование библиотеки 🤗 Transformers + sections: + - local: chapter2/1 + title: Введение \ No newline at end of file diff --git a/chapters/ru/chapter2/1.mdx b/chapters/ru/chapter2/1.mdx new file mode 100644 index 000000000..99dbd07b6 --- /dev/null +++ b/chapters/ru/chapter2/1.mdx @@ -0,0 +1,19 @@ +# Введение + +Как вы могли заметить в [Главе 1](/course/chapter1), модели трансформеров обычно бывают очень большие. Обучение и развертывание таких моделей с миллионами и даже десятками *миллиардов* параметров является сложной задачей. Кроме того, новые модели выпускаются почти ежедневно, и каждая из них имеет собственную реализацию, опробовать их все — непростая задача. + +Библиотека 🤗 Transformers была создана для решения этой проблемы. Её цель — предоставить единый API, с помощью которого можно загружать, обучать и сохранять любую модель трансформера. Основными функциями библиотеки являются: + +- **Удобство в использовании**: Скачивание, загрузку и использование современной модели NLP для вывода данных, можно выполнять всего двумя строками кода. +- **Гибкость**: По своей сути все модели представляют собой простые классы библиотек PyTorch `nn.Module` или TensorFlow `tf.keras.Model` и могут обрабатываться, как и любые другие модели, в соответствующих средах машинного обучения (МО). +- **Простота**: В библиотеке практически не используются абстракции. "Все в одном файле" является основной концепцией: прямой проход модели полностью определяется в одном файле, так что сам код понятен, но при этом доступен для взлома. + +Последняя особенность сильно отличает библиотеку 🤗 Transformers от других библиотек машинного обучения. Модели не строятся на модулях, которые являются общими для всех файлов; вместо этого каждая модель имеет свои собственные слои. Это не только делает модели более доступными и понятными, но и позволяет легко экспериментировать с одной моделью, не затрагивая другие. + +Эта глава начнается со сквозного примера, в котором мы используем модель и токенизатор вместе, чтобы воспроизвести функцию `pipeline()` представленную в [Главе 1](/course/chapter1). Далее мы обсудим API модели: углубимся в классы модели и конфигурации и покажем, как загружать модель и как она обрабатывает числовые входные данные для получения прогнозов. + +Затем мы рассмотрим API токенизатора, который является другим основным компонентом функции `pipeline()`. Токенизаторы берут на себя первый и последний этапы обработки, обрабатывая преобразование текста в числовые входные данные для нейронной сети и обратное преобразование в текст, когда это необходимо. Наконец, мы покажем вам, как обработывается передача нескольких предложений в модель с помощью подготовленных пакетов, а затем завершим все это более детальным рассмотрением высокоуровневой функции `tokenizer()`. + + +⚠️ Чтобы воспользоваться всеми функциями, доступными в Model Hub и 🤗 Transformers, мы рекомендуем создать учетную запись. + \ No newline at end of file From a02f0a4bd1d4606f1ee20f81ddbea7c2bee9ca9b Mon Sep 17 00:00:00 2001 From: Vedant Pandya Date: Tue, 12 Apr 2022 14:39:14 +0530 Subject: [PATCH 65/73] Translation of Chapter0 to Hindi (#86) * Hindi?Chapter0-Part_1 * Hindi/Chapter0-Part_2 --- chapters/hi/_toctree.yml | 9 +++ chapters/hi/chapter0/1.mdx | 110 +++++++++++++++++++++++++++++++++++++ chapters/hi/chapter1/1.mdx | 51 +++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 chapters/hi/_toctree.yml create mode 100644 chapters/hi/chapter0/1.mdx create mode 100644 chapters/hi/chapter1/1.mdx diff --git a/chapters/hi/_toctree.yml b/chapters/hi/_toctree.yml new file mode 100644 index 000000000..86dd2c5bd --- /dev/null +++ b/chapters/hi/_toctree.yml @@ -0,0 +1,9 @@ +- title: 0. स्थापना + sections: + - local: chapter0/1 + title: परिचय + +- title: 1. ट्रांसफार्मर मॉडल + sections: + - local: chapter1/1 + title: परिचय diff --git a/chapters/hi/chapter0/1.mdx b/chapters/hi/chapter0/1.mdx new file mode 100644 index 000000000..7fef3c4bf --- /dev/null +++ b/chapters/hi/chapter0/1.mdx @@ -0,0 +1,110 @@ +# परिचय + +हगिंग फेस में आपका स्वागत है! यह परिचय कार्य वातावरण स्थापित करने में आपका मार्गदर्शन करेगा। यदि आप अभी पाठ्यक्रम शुरू कर रहे हैं, तो हम अनुशंसा करते हैं कि आप पहले [अध्याय 1](course/chapter1) पर एक नज़र डालें, फिर वापस आएं और अपना वातावरण सेट करें ताकि आप कोड को स्वयं आज़मा सकें। + +इस पाठ्यक्रम में हम जिन सभी पुस्तकालयों का उपयोग करेंगे, वे पायथन पैकेज के रूप में उपलब्ध हैं, इसलिए यहां हम आपको दिखाएंगे कि पायथन वातावरण कैसे स्थापित करें और विशिष्ट पुस्तकालयों को स्थापित करें जिनकी आपको आवश्यकता होगी। + +हम आपके कार्य परिवेश को स्थापित करने के दो तरीकों को कवर करेंगे, एक Colab नोटबुक या एक पायथन आभासी वातावरण का उपयोग करके। बेझिझक वह चुनें जो आपके साथ सबसे अधिक प्रतिध्वनित हो। शुरुआती लोगों के लिए, हम दृढ़ता से अनुशंसा करते हैं कि आप Colab नोटबुक का उपयोग करके शुरुआत करें। + +ध्यान दें कि हम विंडोज सिस्टम को कवर नहीं करेंगे। यदि आप Windows पर चल रहे हैं, तो हम अनुशंसा करते हैं कि Colab नोटबुक का उपयोग करने के साथ-साथ अनुसरण करें। यदि आप Linux वितरण या macOS का उपयोग कर रहे हैं, तो आप यहाँ वर्णित किसी भी दृष्टिकोण का उपयोग कर सकते हैं। + +अधिकांश पाठ्यक्रम आपके हगिंग फेस खाते पर निर्भर करता है। हम अभी एक बनाने की सलाह देते हैं: [एक खाता बनाएँ](https://huggingface.co/join)। + +## Google Colab नोटबुक का उपयोग करना + +Colab नोटबुक का उपयोग करना सबसे आसान संभव सेटअप है; अपने ब्राउज़र में एक नोटबुक बूट करें और सीधे कोडिंग पर जाएं! + +यदि आप Colab से परिचित नहीं हैं, तो हम अनुशंसा करते हैं कि आप [परिचय](https://colab.research.google.com/notebooks/intro.ipynb) का पालन करके शुरुआत करें। Colab आपको GPU या TPU जैसे कुछ त्वरित हार्डवेयर का उपयोग करने की अनुमति देता है, और यह छोटे कार्यभार के लिए मुफ़्त है। + +एक बार जब आप Colab में घूमने में सहज हो जाएं, तो एक नई नोटबुक बनाएं और स्थापना के साथ आरंभ करें: +
+ एक खाली Colab नोटबुक +
+ +अगला चरण उन पुस्तकालयों को स्थापित करना है जिनका हम इस पाठ्यक्रम में उपयोग करेंगे। हम स्थापना के लिए `pip` का उपयोग करेंगे, जो कि पायथन के लिए पैकेज मैनेजर है। नोटबुक्स में, आप `!` वर्ण से पहले सिस्टम कमांड चला सकते हैं, इसलिए आप ट्रान्सफ़ॉर्मर लाइब्रेरी को निम्नानुसार स्थापित कर सकते हैं: +अगला चरण उन पुस्तकालयों को स्थापित करना है जिनका हम इस पाठ्यक्रम में उपयोग करेंगे। हम स्थापना के लिए `pip` का उपयोग करेंगे, जो कि पायथन के लिए पैकेज मैनेजर है। नोटबुक्स में, आप `!` वर्ण से पहले सिस्टम कमांड चला सकते हैं, इसलिए आप :hugs: ट्रान्सफ़ॉर्मर लाइब्रेरी को निम्नानुसार स्थापित कर सकते हैं: + +``` +!pip install transformers +``` + +आप यह सुनिश्चित कर सकते हैं कि पैकेज आपके पायथन रनटाइम के भीतर आयात करके सही ढंग से स्थापित किया गया है: + +``` +import transformers +``` + +
+ उपरोक्त दो आदेशों का परिणाम दिखाने वाला एक GIF: स्थापना और आयात +
+ +यह :hugs: ट्रांसफॉर्मर का एक बहुत हल्का संस्करण स्थापित करता है। विशेष रूप से, कोई विशिष्ट मशीन लर्निंग फ्रेमवर्क (जैसे PyTorch या TensorFlow) स्थापित नहीं हैं। चूंकि हम पुस्तकालय की कई अलग-अलग विशेषताओं का उपयोग करेंगे, हम विकास संस्करण को स्थापित करने की सलाह देते हैं, जो किसी भी कल्पनाशील उपयोग के मामले के लिए सभी आवश्यक निर्भरताओं के साथ आता है: + +``` +!pip install transformers[sentencepiece] +``` + +इसमें थोड़ा समय लगेगा, लेकिन फिर आप बाकी पाठ्यक्रम के लिए तैयार हो जाएंगे। + +## पायथन आभासी वातावरण का उपयोग करना + +यदि आप एक पायथन आभासी वातावरण का उपयोग करना पसंद करते हैं, तो पहला कदम आपके सिस्टम पर पायथन को स्थापित करना है। हम आरंभ करने के लिए [इस गाइड](https://realpython.com/installing-python/) का पालन करने की सलाह देते हैं। + +एक बार जब आप पायथन स्थापित कर लेते हैं, तो आपको अपने टर्मिनल में पायथन आदेश चलाने में सक्षम होना चाहिए। अगले चरण पर आगे बढ़ने से पहले यह सुनिश्चित करने के लिए कि यह सही ढंग से स्थापित है, आप निम्न आदेश चलाकर प्रारंभ कर सकते हैं: `python --version`. यह आपके सिस्टम पर अब उपलब्ध पायथन संस्करण को प्रिंट करना चाहिए। + +अपने टर्मिनल में पायथन आदेश चलाते समय, जैसे `python --version` आदेश को चलाने वाले प्रोग्राम को अपने सिस्टम में "main" पायथन के रूप में सोचना चाहिए। हम अनुशंसा करते हैं कि इस मुख्य स्थापना को किसी भी पैकेज से मुक्त रखें, और इसका उपयोग प्रत्येक एप्लिकेशन के लिए अलग वातावरण बनाने के लिए करें, जिस पर आप काम कर रहे हैं - इस तरह, प्रत्येक एप्लिकेशन की अपनी निर्भरताएं और पैकेज होंगे, और आपको अन्य एप्लिकेशन के साथ संभावित संगतता समस्याओं के बारे में चिंता करने की आवश्यकता नहीं होगी। + +पायथन में यह [आभासी वातावरण](https://docs.python.org/3/tutorial/venv.html) के साथ किया जाता है, जो स्व-निहित निर्देशिका ट्री हैं जिनमें से प्रत्येक में एक विशेष पायथन संस्करण के साथ एक पायथन स्थापना होती है, जिसमें सभी पैकेजों के साथ एप्लिकेशन की आवश्यकता होती है। इस तरह के आभासी वातावरण का निर्माण कई अलग-अलग उपकरणों के साथ किया जा सकता है, लेकिन हम उस उद्देश्य के लिए आधिकारिक पायथन पैकेज का उपयोग करेंगे, जिसे कहा जाता है [`venv`](https://docs.python.org/3/library/venv.html#module-venv)। + +सबसे पहले, एक निर्देशिका बनाएं जिसमें आप अपने आवेदन में रहना चाहते हैं - उदाहरण के लिए, आप अपनी होम निर्देशिका के मूल में *transformers-course* नामक एक नई निर्देशिका बनाना चाहेंगे: + +``` +mkdir ~/transformers-course +cd ~/transformers-course +``` + +इस निर्देशिका के अंदर, पायथन `venv` मॉड्यूल का उपयोग करके एक आभासी वातावरण बनाएं: + +``` +python3 -m venv .env +``` + +अब आपके पास आपके अन्यथा खाली फ़ोल्डर में *.env* नामक एक निर्देशिका होनी चाहिए: + +``` +ls -a +``` + +```out +. .. .env +``` + +आप 'activate' और 'deactivate' स्क्रिप्ट के साथ अपने आभासी वातावरण में और बाहर कूद सकते हैं: + +``` +# Activate the virtual environment +source .env/bin/activate + +# Deactivate the virtual environment +source .env/bin/deactivate +``` + +आप यह सुनिश्चित कर सकते हैं कि `which python` आदेश चलाकर कौन सा पर्यावरण सक्रिय है: यदि यह आभासी वातावरण की ओर इशारा करता है, तो आपने इसे सफलतापूर्वक सक्रिय कर दिया है! + +``` +which python +``` + +```out +/home//transformers-course/.env/bin/python +``` + +## निर्भरता स्थापित करना + +Google Colab इंस्टेंस का उपयोग करने पर पिछले अनुभाग की तरह, अब आपको जारी रखने के लिए आवश्यक पैकेजों को स्थापित करने की आवश्यकता होगी। फिर से, आप `pip` पैकेज मैनेजर का उपयोग करके :hugs: ट्रांसफॉर्मर के विकास संस्करण को स्थापित कर सकते हैं: + +``` +pip install "transformers[sentencepiece]" +``` + +अब आप पूरी तरह से तैयार हैं! \ No newline at end of file diff --git a/chapters/hi/chapter1/1.mdx b/chapters/hi/chapter1/1.mdx new file mode 100644 index 000000000..3107062cc --- /dev/null +++ b/chapters/hi/chapter1/1.mdx @@ -0,0 +1,51 @@ +# परिचय + +## :hugs: पाठ्यक्रम में आपका स्वागत है! + + + +यह पाठ्यक्रम आपको [Hugging Face](https://huggingface.co) पारिस्थितिकी तंत्र - [:hugs: ट्रान्सफ़ॉर्मर](https://github.com/huggingface/transformers), [:hugs: डेटासेट](https://github.com/huggingface/datasets), [:hugs: टोकनीज़र](https://github.com/huggingface/tokenizers), तथा [:hugs: एक्सेलेरेट](https://github.com/huggingface/accelerate) - इसके साथ ही [हगिंग फेस हब](https://huggingface.co/models) पुस्तकालयों का उपयोग करके प्राकृतिक भाषा प्रसंस्करण (एनएलपी) के बारे में सिखाएगा। यह पूरी तरह से मुफ़्त है और विज्ञापनों के बिना है। + +## क्या उम्मीद करें? + +यहां पाठ्यक्रम का संक्षिप्त विवरण दिया गया है। + +
+ Brief overview of the chapters of the course. + +
+ +- अध्याय 1 से 4 :hugs: ट्रान्सफ़ॉर्मर पुस्तकालय की मुख्य अवधारणाओं का परिचय प्रदान करते हैं। पाठ्यक्रम के इस भाग के अंत तक, आप इस बात से परिचित होंगे कि ट्रांसफार्मर मॉडल कैसे काम करते हैं और [हगिंग फेस हब](https://huggingface.co/models) से मॉडल का उपयोग करना जानते हैं, इसे ठीक करें। डेटासेट पर, और हब पर अपने परिणाम साझा करें! +- अध्याय 5 से 8 क्लासिक एनएलपी कार्यों में गोता लगाने से पहले :hugs: डेटासेट और :hugs: टोकनाइज़र की मूल बातें सिखाते हैं। इस भाग के अंत तक, आप सबसे आम एनएलपी समस्याओं से स्वयं निपटने में सक्षम होंगे। +- अध्याय 9 से 12 एनएलपी से आगे जाते हैं और यह पता लगाते हैं कि भाषा प्रसंस्करण और कंप्यूटर दृष्टि में कार्यों से निपटने के लिए ट्रांसफार्मर मॉडल का उपयोग कैसे किया जा सकता है। साथ ही, आप सीखेंगे कि अपने मॉडलों के डेमो कैसे बनाएं और साझा करें, और उन्हें उत्पादन परिवेशों के लिए अनुकूलित करें। इस भाग के अंत तक, आप (लगभग) किसी भी मशीन सीखने की समस्या के लिए :hugs: ट्रांसफॉर्मर लगाने के लिए तैयार होंगे! + +यह पाठ्यक्रम के लिए: + +* पायथन के अच्छे ज्ञान की आवश्यकता है +* प्रारंभिक गहन शिक्षण पाठ्यक्रम, जैसे [fast.ai के](https://www.fast.ai/) [कोडर्स के लिए प्रैक्टिकल डीप लर्निंग](https://course.fast.ai/) के बाद लेना बेहतर है। +* पूर्व [PyTorch](https://pytorch.org/) या [TensorFlow](https://www.tensorflow.org/) ज्ञान की अपेक्षा नहीं करता है, हालांकि इनमें से किसी के साथ कुछ परिचित होने से मदद मिलेगी। + +आपके द्वारा इस पाठ्यक्रम को पूरा करने के बाद, हम आपको DeepLearning.AI की [प्राकृतिक भाषा संसाधन विशेषज्ञता](https://www.coursera.org/specializations/natural-language-processing?utm_source=deeplearning-ai&utm_medium=institutes&utm_campaign=20211011-nlp-2-hugging_face-page-nlp-refresh) की जाँच करने की सलाह देते हैं। जो पारंपरिक NLP मॉडल जैसे कि Naive Bayes और LSTMs की एक विस्तृत श्रृंखला को कवर करता है, जो अच्छी तरह से जानने योग्य हैं! + +## हम कौन हैं? + +लेखक के बारे में: + +**मैथ्यू कैरिगन** हगिंग फेस में मशीन लर्निंग इंजीनियर हैं। वह डबलिन, आयरलैंड में रहता है, और पहले Parse.ly में एक एमएल इंजीनियर के रूप में काम करता था और उससे पहले ट्रिनिटी कॉलेज डबलिन में पोस्ट-डॉक्टरेट शोधकर्ता के रूप में काम करता था। वह विश्वास नहीं कर सकता कि हम मौजूदा आर्किटेक्चर को स्केल करके एजीआई तक पहुंचने जा रहे हैं, लेकिन रोबोट अमरता की परवाह किए बिना उच्च उम्मीदें हैं। + +**लिसेंड्रे डेब्यू** हगिंग फेस में एक मशीन लर्निंग इंजीनियर है और बहुत प्रारंभिक विकास चरणों के बाद से :hugs: ट्रांसफॉर्मर्स लाइब्रेरी पर काम कर रहा है। उनका उद्देश्य एक बहुत ही सरल एपीआई के साथ उपकरण विकसित करके एनएलपी को सभी के लिए सुलभ बनाना है। + +**सिल्वेन गुगर** हगिंग फेस में एक रिसर्च इंजीनियर हैं और :hugs: ट्रान्सफ़ॉर्मर्स लाइब्रेरी के मुख्य अनुरक्षकों में से एक हैं। पहले वे fast.ai में एक शोध वैज्ञानिक थे, और उन्होंने _[डीप लर्निंग फॉर कोडर्स विद फास्टाई और पायटॉर्च](https://learning.oreilly.com/library/view/deep-learning-for/9781492045519/) का सह-लेखन किया जेरेमी हॉवर्ड के साथ। उनके शोध का मुख्य फोकस तकनीकों को डिजाइन और सुधार करके गहन शिक्षण को और अधिक सुलभ बनाने पर है जो मॉडल को सीमित संसाधनों पर तेजी से प्रशिक्षित करने की अनुमति देता है। + +**मर्व नोयान** हगिंग फेस में एक डेवलपर एडवोकेट है, जो सभी के लिए मशीन लर्निंग का लोकतंत्रीकरण करने के लिए टूल विकसित करने और उनके आसपास सामग्री बनाने पर काम कर रहे है। + +**ल्यूसिले शाॅलनियर** हगिंग फेस में एक मशीन लर्निंग इंजीनियर है, जो ओपन-सोर्स टूल के उपयोग का विकास और समर्थन करता है। वह सहयोगात्मक प्रशिक्षण और बिगसाइंस जैसे प्राकृतिक भाषा प्रसंस्करण के क्षेत्र में कई शोध परियोजनाओं में भी सक्रिय रूप से शामिल हैं। + +**लुईस ट्यूनस्टाल** हगिंग फेस में एक मशीन लर्निंग इंजीनियर है, जो ओपन-सोर्स टूल विकसित करने और उन्हें व्यापक समुदाय के लिए सुलभ बनाने पर केंद्रित है। वह आगामी [ओ'रेली बुक ऑन ट्रांसफॉर्मर्स](https://www.oreilly.com/library/view/natural-language-processing/9781098103231/) के सह-लेखक भी हैं। + +**लिंड्रो वॉन वेरा** हगिंग फेस की ओपन-सोर्स टीम में मशीन लर्निंग इंजीनियर हैं और आगामी [ओ'रेली बुक ऑन ट्रांसफॉर्मर्स](https://www.oreilly.com/library/view/natural-language-processing/9781098103231/) के सह-लेखक भी हैं। पूरे मशीन लर्निंग स्टैक में काम करके एनएलपी परियोजनाओं को उत्पादन में लाने के लिए उनके पास कई वर्षों का औद्योगिक अनुभव है। + +क्या आप तैयार हैं? इस अध्याय में आप सीखेंगे: +* पाठ निर्माण और वर्गीकरण जैसे एनएलपी कार्यों को हल करने के लिए `pipeline()` फ़ंक्शन का उपयोग कैसे करें +* ट्रांसफार्मर आर्किटेक्चर के बारे में +* एन्कोडर, डिकोडर और एन्कोडर-डिकोडर आर्किटेक्चर के बीच अंतर कैसे करें और उपयोग करें From 1bd43b604c90f65ed1db07705e24ccc5710eb6bc Mon Sep 17 00:00:00 2001 From: Bahram Shamshiri Date: Tue, 12 Apr 2022 16:33:26 +0430 Subject: [PATCH 66/73] Chapter 0 Persian Translation First Draft (#95) * merged branch0 into main. no toctree yet. * updated toctree. * Updated the glossary with terms from chapter0. * Second draft in collab w/ @schoobani. Added empty chapter1 for preview. * Glossary typo fix. --- chapters/fa/_toctree.yml | 10 +++ chapters/fa/chapter0/1.mdx | 149 +++++++++++++++++++++++++++++++++++++ chapters/fa/chapter1/1.mdx | 7 ++ chapters/fa/glossary/1.mdx | 85 ++++++++++++++++++--- 4 files changed, 241 insertions(+), 10 deletions(-) create mode 100644 chapters/fa/chapter0/1.mdx create mode 100644 chapters/fa/chapter1/1.mdx diff --git a/chapters/fa/_toctree.yml b/chapters/fa/_toctree.yml index c3b653696..179c9d87a 100644 --- a/chapters/fa/_toctree.yml +++ b/chapters/fa/_toctree.yml @@ -1,3 +1,13 @@ +- title: راه‌اندازی + sections: + - local: chapter0/1 + title: مقدمه + +- title: ۱- مدل‌های ترنسفورمر + sections: + - local: chapter1/1 + title: مقدمه + - title: ۲- بکارگیری ترنسفورمرهای هاگینگ‌فیس sections: - local: chapter2/1 diff --git a/chapters/fa/chapter0/1.mdx b/chapters/fa/chapter0/1.mdx new file mode 100644 index 000000000..d46295940 --- /dev/null +++ b/chapters/fa/chapter0/1.mdx @@ -0,0 +1,149 @@ +
+# مقدمه + + +به دوره‌ی آموزشی هاگینگ‌فیس خوش آمدید! این مقدمه شما را در طی مراحل راه‌اندازی محیط کار راهنمایی می‌کند. اگر تازه این دوره را شروع کرده‌اید، پیشنهاد می‌کنیم ابتدا نگاهی به [فصل اول](/course/chapter1) بیاندازید و سپس به این بخش بازگشته تا محیط کاری را راه‌اندازی کنید و بتوانید خودتان کد را اجرا کنید. + +همه کتابخانه‌هایی که در این دوره‌ی آموزشی استفاده خواهیم کرد، پکیج‌های پایتون هستند. در این بخش می‌بینیم که چگونه باید محیط کار پایتون را راه‌اندازی نموده و کتابخانه‌های مورد نیاز را نصب کنید. + +ما دو شیوه راه‌اندازی محیط کار، یکی استفاده از نوت‌بوک کولَب و دیگری استفاده از محیط مجازی پایتون را نشان خواهیم داد. می‌توانید هرکدام را که می‌خواهید انتخاب کنید. اگر تازه‌کارها هستید، توصیه مؤکد داریم که از نوت‌بوک کولَب استفاده کنید. + +توجه کنید که به محیط ویندوز نخواهیم پرداخت. اگر از ویندوز استفاده می‌کنید توصیه می‌کنیم از نوت‌بوک‌های کولَب استفاده کنید. اگر از سیستم‌عامل مک یا یکی از توزیع‌های لینوکس استفاده می‌کنید می‌توانید هر‌کدام از روش‌هایی که در اینجا ارائه می‌کنیم را دنبال کنید. + +برای طی بخش زیادی از این دوره نیاز به حساب کاربری ‌هاگینگ‌فیس‌ دارید. پیشنهاد می‌کنیم همین الان [حساب خود را بسازید](https://huggingface.co/join). + +

استفاده از نوت‌بوک‌ کولَب گوگل

+ +استفاده از نوت‌بوک کولَب ساده‌ترین راه شروع است. در مرورگر خود نوت‌بوکی جدید باز کرده و بلافاصله شروع به کد زدن کنید! + +اگر با کولَب آشنایی ندارید پیشنهاد می‌کنیم از این [راهنما](https://colab.research.google.com/notebooks/intro.ipynb) استفاده کنید. کولَب به شما امکان استفاده از سخت‌افزار‌‌‌های شتاب‌دهنده مانند GPU یا TPU می‌‌دهد و استفاده از آن برای محاسبات سبک رایگان است. + +وقتی که با محیط کاربری کولَب آشنا شدید، نوت‌بوکی جدید بسازید و مراحل راه‌اندازی را شروع کنید. +
+ +
+An empty colab notebook +
+
+ +قدم اول نصب کتابخانه‌هایی است که در این دوره استفاده خواهیم کرد. برای نصب کتابخانه‌ها از `pip` استفاده می‌کنیم که پکیج‌منیجر پایتون است. در فضای نوت‌بوک، برای اجرای دستورهای سیستمی، کافی است علامت `!` را به ابتدای خط اضافه کنید. برای نصب کتابخانه ترنسفورمرهای هاگینگ‌فیس این دستور را اجرا کنید: + +
+ + ``` + !pip install transformers + ``` + +
+ +برای اطمینان از نصب صحیح این پکیج، آن را ایمپورت کنید: + +
+ + ``` + import transformers + ``` + +
+ +
+
+A gif showing the result of the two commands above: installation and import +
+
+ +این دستور نسخه‌ای بسیار کم حجم از ترنسفورمرهای هاگینگ‌فیس را نصب می‌کند بدون آنکه فریمورک‌ یادگیری ماشین مشخصی مانند پایتورچ یا تنسورفلو را اضافه کند. با توجه به اینکه ما از بسیاری از قابلیت‌های مختلف این کتابخانه استفاده خواهیم کرد، پیشنهاد می‌کنیم نسخه توسعه‌ی این کتابخانه، که حاوی تمام پکیج‌های وابسته برای تقریبا همه مسائل قابل تصور است، را نصب کنید: + +
+ + ``` + !pip install transformers[sentencepiece] + ``` + +
+ +اجرای این فرمان کمی بیشتر طول می‌کشد ولی برای طی بقیه دوره نیازی به نصب پکیج دیگری نخواهید داشت! + +

استفاده از محیط مجازی پایتون

+ +اگر ترجیح می‌دهید از یکی از محیط‌های مجازی پایتون استفاده کنید، اولین مرحله نصب پایتون روی سیستم‌تان است. پیشنهاد می‌کنیم از این [راهنما](https://realpython.com/installing-python/) استفاده کنید. +اگر پایتون را نصب کردید، می‌توانید فرمان‌های پایتون را در ترمینال اجرا کنید. قبل از اینکه به سراغ مراحل بعدی بروید، با اجرای دستور `python --version` از نصب صحیح پایتون مطمئن شوید. این دستور، نسخه‌ی پایتون نصب شده روی سیستم‌تان را نمایش می‌دهد. + + +زمانی که فرمان‌های پایتون را در ترمینال اجرا می کنید، نسخه "اصلی” پایتون روی سیستم خود را درگیر می کنید. توصیه می کنیم این نسخه‌ را تمیز نگه دارید و هیچ پکیج اضافه‌ای روی آن نصب نکنید، بلکه از آن صرفا برای ایجاد محیط‌های مجازی دیگر و برای پروژه‌های مختلف استفاده کنید. با این روش هر پروژه می‌تواند وابستگی‌های مخصوص به خود را داشته‌باشد و دیگر نیازی نیست نگران ناسازگاری‌‌‌های احتمالی میان پکیج‌های نصب شده برای پروژه‌های مختلف باشید. + +این کار در پایتون با استفاده از [محیط‌های مجازی](https://docs.python.org/3/tutorial/venv.html) انجام می‌شود. محیط مجازی، پوشه ای قائم به خود روی فایل‌سیستم است که محتوی نسخه‌ای مشخص از پایتون به همراه تمام پکیج‌های مورد استفاده در پروژه‌ای خاص است. ساخت این پوشه با ابزارهای مختلفی امکان‌پذیر است. ما در اینجا از ابزار رسمی پایتون به نام [`venv`](https://docs.python.org/3/library/venv.html#module-venv) استفاده می‌کنیم. + +ابتدا پوشه‌ای جدید برای پروژه خود ایجاد کنید. برای مثال پوشه‌ای به نام transformers-course زیر پوشه‌ی خانه خودتان در فایل‌سیستم بسازید: + +
+ + ``` + mkdir ~/transformers-course + cd ~/transformers-course + ``` + +
+ +درون این پوشه، با استفاده از ماژول `venv` پایتون، محیط مجازی خود را بسازید: + +
+ + ``` + python -m venv .env + ``` + +
+ +حالا می‌بایست زیر پوشه پروژه شما تنها یک پوشه دیگر به نام .env وجود داشته باشد. + +
+ + ``` + ls -a + . .. .env + ``` + +
+ +برای ورود و خروج از محیط مجازی پروژه خود از اسکریپت‌های activate و deactivate استفاده کنید: + +
+ + ``` + \# Activate the virtual environment + source .env/bin/activate + + \# Deactivate the virtual environment + source .env/bin/deactivate + ``` + +
+ + +‌با اجرای دستور `which python` از فعال شدن محیط مجازی خود اطمینان حاصل کنید. اگر این دستور به آدرس محیط مجازی جدید اشاره کند، با موفقیت این محیط را فعال کرده‌اید. + +
+ + ``` + which python + /home/<user>/transformers-course/.env/bin/python + ``` + +
+ +

نصب وابستگی‌ها

+ +مانند آنچه در بخش استفاده از گوگل کولَب گفتیم، اکنون باید پکیج‌های موردنیاز برای ادامه دوره را نصب کنید. می‌توانید نسخه توسعه‌ی پکیج ترنسفورمرهای هاگینگ‌فیس را با استفاده از پکیج‌منیجر `pip` نصب کنید: + +
+ + ``` + pip install "transformers[sentencepiece]" + ``` + +
+ +شما تمام مراحل راه‌اندازی را طی کرده و آماده شروع دوره هستید! + +
diff --git a/chapters/fa/chapter1/1.mdx b/chapters/fa/chapter1/1.mdx new file mode 100644 index 000000000..03e429b99 --- /dev/null +++ b/chapters/fa/chapter1/1.mdx @@ -0,0 +1,7 @@ +
+# مقدمه + + +به دوره‌ی آموزشی هاگینگ‌فیس خوش آمدید! + +
diff --git a/chapters/fa/glossary/1.mdx b/chapters/fa/glossary/1.mdx index 8f5229155..8587b671b 100644 --- a/chapters/fa/glossary/1.mdx +++ b/chapters/fa/glossary/1.mdx @@ -27,30 +27,95 @@ | Configuration | تنظیمات | | Batch | بتچ | | Model Hub | Model Hub | +| Course | دوره‌ی آموزشی | +| Working Environment | محیط کار | +| Workspace | فضای کار | +| Setup | راه‌اندازی | +| Create | ایجاد یا ساختن | +| Code | کد | +| Package | پکیج‌ | +| Python | پایتون | +| Colab Notebook | نوت‌بوک کولَب | +| Google | گوگل | +| Windows | ویندوز | +| macOS | سیستم‌عامل مک | +| Distribution | توزیع | +| Linux | لینوکس | +| Workload | محاسبه، محاسبات | +| Package Manager | پکیج‌منیجر | +| Command | دستور یا فرمان | +| Feature | قابلیت‌ | +| Development | توسعه نرم‌افزار | +| Dependency | وابسته، وابستگی | +| Virtual Environment | محیط مجازی | +| Terminal | ترمینال | +| Incompatibility | ناسازگاری | +| Self-Contained | قائم به خود یا بدون وابستگی خارجی؟ | +| Script | اسکریپت‌ | +| Feature | قابلیت | +| Folder | پوشه | -Acronyms: +معادل‌هایی که استفاده نمی‌کنیم: -| معادل در منبع | معادل در ترجمه | +| معادل در منبع | معادل اشتباه در ترجمه | |-----------------------|------------------| -| NLP | NLP | -| API | API | +| Application, as in an app and not as in apply | کاربرد | -Convenience Acronyms: +کلمات مخفف: | معادل در منبع | معادل در ترجمه | |-----------------------|------------------| +| NLP | NLP | +| API | API | +| GPU | GPU | +| TPU | TPU | | ML | یادگیری ماشین | + +املای مورد استفاده کلمات فارسی: + +|ارائه| + - * Used in chapter1/page2 to loosely mean 'running' the model. If used anywhere else to exact technical meaning we could go with 'استنتاج' probably? But that sounds archaic to me. -- Don't translate industry-accepted acronyms. -- Translate acronyms used for convenience in English to full Persian form. -- Transliterate brand names to minimize mixing of Persian and English - characters, which makes for a fragmentary text. This should be a Persian text - with some English words sprinkled in, only when really necessary. +- Don't translate industry-accepted acronyms. e.g. TPU or GPU. + +- Translate acronyms used for convenience in English to full Persian form. e.g. ML + +- Keep voice active and consistent. Don't overdo it but try to avoid a passive voice. + +- Refer and contribute to the glossary frequently to stay on top of the latest + choices we make. This minimizes the amount of editing that is required. + +- Keep POV consistent. + +- Smaller sentences are better sentences. Apply with nuance. + +- If translating a technical word, keep the choice of Persian equivalent consistent. + If workspace is mohit-e-kari don't just switch to faza-ye-kari. This ofc + does not apply for non-technical choices, as in those cases variety actually + helps keep the text engaging. + +- This is merely a translation. Don't add any technical/contextual information + not present in the original text. Also don't leave stuff out. The creative + choices in composing this information were the original authors' to make. + Our creative choices are in doing a quality translation. + +- Note on translating indefinite articles(a, an) to Persian. Persian syntax does + not have these. Common problem in translations is using + the equivalent of 'One'("Yek", "Yeki") as a direct word-for-word substitute + which makes for ugly Persian. Be creative with Persian word order to avoid this. + + For example, the sentence "we use a library" should be translated as + "ما از کتابخانه‌ای استفاده می‌کنیم" and not "ما از یک کتابخانه استفاده می‌کنیم". + "Yek" here implies a number(1) to the Persian reader, but the original text + was emphasizing the indefinite nature of the library and not its count. + +- Be exact when choosing equivalents for technical words. Package is package. + Library is library. Don't mix and match. From 303e83e9c19f1cbe2466d98f35dec0ddb2054604 Mon Sep 17 00:00:00 2001 From: Giyaseddin Bayrak <34009210+giyaseddin@users.noreply.github.com> Date: Tue, 12 Apr 2022 15:06:10 +0300 Subject: [PATCH 67/73] Translation of Chapter0 (setup) to Arabic (#104) * Add AR translation for `introduction` * Fix alignment & format * Add Arabic to CI build --- .github/workflows/build_documentation.yml | 2 +- .github/workflows/build_pr_documentation.yml | 4 +- chapters/ar/_toctree.yml | 4 + chapters/ar/chapter0/1.mdx | 136 +++++++++++++++++++ 4 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 chapters/ar/_toctree.yml create mode 100644 chapters/ar/chapter0/1.mdx diff --git a/.github/workflows/build_documentation.yml b/.github/workflows/build_documentation.yml index a7714c94a..a03061dc8 100644 --- a/.github/workflows/build_documentation.yml +++ b/.github/workflows/build_documentation.yml @@ -14,6 +14,6 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: bn en es fa fr he ko pt ru th tr + languages: ar bn en es fa fr he ko pt ru th tr secrets: token: ${{ secrets.HUGGINGFACE_PUSH }} \ No newline at end of file diff --git a/.github/workflows/build_pr_documentation.yml b/.github/workflows/build_pr_documentation.yml index f7b92f51d..84af57f75 100644 --- a/.github/workflows/build_pr_documentation.yml +++ b/.github/workflows/build_pr_documentation.yml @@ -16,5 +16,5 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: bn en es fa fr he ko pt ru th tr - hub_base_path: https://moon-ci-docs.huggingface.co/course \ No newline at end of file + languages: ar bn en es fa fr he ko pt ru th tr + hub_base_path: https://moon-ci-docs.huggingface.co/course diff --git a/chapters/ar/_toctree.yml b/chapters/ar/_toctree.yml new file mode 100644 index 000000000..b9e6467fd --- /dev/null +++ b/chapters/ar/_toctree.yml @@ -0,0 +1,4 @@ +- title: 0.الإعداد + sections: + - local: chapter0/1 + title: مقدمة diff --git a/chapters/ar/chapter0/1.mdx b/chapters/ar/chapter0/1.mdx new file mode 100644 index 000000000..7951b9d94 --- /dev/null +++ b/chapters/ar/chapter0/1.mdx @@ -0,0 +1,136 @@ +
+ +# مقدمة + +مرحبًا بك في دورة Hugging Face! ستساعدك هذه المقدمة خلال إعداد بيئة العمل. إذا كنت قد بدأت الدورة للتو، فننصحك أولاً بإلقاء نظرة على [الفصل 1](/course/chapter1)، ثم العودة وإعداد بيئتك حتى تتمكن من تجربة الكود بنفسك. + +تتوفر جميع المكتبات التي سنستخدمها في هذه الدورة التدريبية على شكل حزم (Package) Python، لذلك سنوضح لك هنا كيفية إعداد بيئة Python وتثبيت المكتبات المحددة التي ستحتاج إليها. + +سنغطي طريقتين لإعداد بيئة العمل الخاصة بك، باستخدام دفتر Colab أو بيئة Python الافتراضية. لا تتردد في اختيار البيئة التي تناسبك أكثر.نوصي المبتدئين بشدة أن يبدأوا باستخدام دفتر Colab. + +لاحظ أننا لن نغطي نظام Windows. إذا كنت تعمل على نظام Windows، فإننا نوصي بمتابعة استخدام دفتر Colab. إذا كنت تستخدم توزيعة Linux أو macOS، فيمكنك استخدام أي من الطريقتين الموضحتين هنا. + +تعتمد معظم الدورة على امتلاكك لحساب Hugging Face. نوصي بإنشاء حساب الآن: [إنشاء حساب](https://huggingface.co/join). + +## استخدام دفتر Google Colab + +يعد استخدام دفتر Colab أبسط إعداد ممكن؛ فقط قم بتشغيل دفتر Colab في متصفحك ابدأ مباشرة بالبرمجة! + +إذا لم تكن معتادًا على Colab، نوصيك بالبدء باتباع [المقدمة](https://colab.research.google.com/notebooks/intro.ipynb). يتيح لك Colab استخدام بعض أجهزة التسريع، مثل GPUs أو TPUs، وهو مجاني في حال تشغيل مهمات خفيفة. + +بمجرد أن تشعر بالأريحية في التنقل في Colab، أنشئ دفتر ملاحظات جديدًا وابدأ في الإعداد: + +
+An empty colab notebook +
+ +الخطوة التالية هي تثبيت المكتبات التي سنستخدمها في هذه الدورة. سنستخدم `pip` للتثبيت، وهو مدير الحزم لPython. حتى تتمكن من تثبيت مكتبة 🤗 Transformers يمكنك تشغيل أوامر النظام عن طريق تسبقها بالحرف `!` في دفتر Colab, على النحو التالي: + +
+ +``` +!pip install transformers +``` + +
+يمكنك التأكد من تثبيت الحزمة بشكل صحيح عن طريق استيرادها (import) خلال وقت تشغيل Python: +
+ +``` +import transformers +``` + +
+A gif showing the result of the two commands above: installation and import +
+ +
+هذا يثبت نسخة خفيفة جدا من مكتبة 🤗 Transformers. أي أنه لم يتم تثبيت أي إطارات عمل محددة للتعلم الآلي (مثل PyTorch أو TensorFlow). نوصي بتثبيت "إصدار التطوير" للمكتبة لأننا سوف نستخدم الكثير من الميزات المختلفة, و هذا الإصدار يأتي مع جميع التبعيات المطلوبة تقريباً لأي حالة استخدام يمكن تخيلها: + +
+ +``` +!pip install transformers[sentencepiece] +``` + +
+سيستغرق هذا بعض الوقت، لكنك ستكون جاهزًا بعد ذلك لبقية الدورة! + +## استخدام بيئة Python افتراضية + +إذا كنت تفضل استخدام بيئة Python الافتراضية، فإن الخطوة الأولى هي تثبيت Python على نظامك. للبدء, نوصي باتباع [دليل الإرشادات هذا](https://realpython.com/installing-python/). + +بمجرد تثبيت Python، يجب أن تكون قادرًا على تشغيل أوامر Python في الجهاز المستخدم. للتأكد من تثبيته بشكل صحيح قبل المتابعة إلى الخطوات التالية يمكنك البدء بتشغيل الأمر التالي: `python --version`. يجب أن يطبع هذا إصدار Python المتاح الآن على نظامك. + +عند تشغيل أمر Python في الجهاز المستخدم، مثل `python --version`، يجب أن تفكر في البرنامج الذي يقوم بتشغيل الأمر الخاص بك باعتباره Python "الرئيسي" على نظامك. نوصي بالحفاظ على هذا التثبيت الرئيسي خاليًا من أي حزم، واستخدامه لإنشاء بيئات منفصلة لكل تطبيق تعمل عليه, وبهذه الطريقة، يمكن لكل تطبيق أن يكون له تبعيات وحزم خاصة به، ولن تقلق بشأن مشكلات التوافق المحتملة مع تطبيقات أخرى. + +في Python، يتم ذلك باستخدام [* البيئات الافتراضية *](https://docs.python.org/3/tutorial/venv.html)، وهي عبارة عن تفرعات من المجلدات كل منها قائم بحد ذاته, ويحتوي كل منها على Python مثبت بإصدار معين بالإضافة إلى جميع الحزم التي يحتاجها التطبيق. يمكن إنشاء مثل هذه البيئة الافتراضية باستخدام عدد من الأدوات المختلفة ، لكننا سنستخدم حزمة Python الرسمية لهذا الغرض، والتي تسمى [`venv`](https://docs.python.org/3/library/venv.html#module-venv). + +أولاً، قم بإنشاء المجلد الذي تريد أن يتواجد فيه التطبيق الخاص بك -على سبيل المثال، قد ترغب في إنشاء مجلد جديد يسمى *transformers-course* في المجلد الرئيسي للدورة: +
+ +``` +mkdir ~/transformers-course +cd ~/transformers-course +``` + +
+ +من داخل هذا المجلد، أنشئ بيئة افتراضية باستخدام وحدة Python `venv`: + +
+ +``` +python -m venv .env +``` + +
+يجب أن يكون لديك الآن مجلد يسمى *.env* في المجلد الفارغ الخاص بك: +
+ +``` +ls -a +``` + +```out +. .. .env +``` + +
+يمكنك الدخول والخروج من بيئتك الافتراضية باستخدام أوامر "التنشيط" و "إلغاء التنشيط": +
+ +``` +# Activate the virtual environment +source .env/bin/activate + +# Deactivate the virtual environment +source .env/bin/deactivate +``` + +
+يمكنك التأكد من تنشيط البيئة عن طريق تشغيل الأمر `which python`: إذا كان يشير إلى البيئة الافتراضية، فقد قمت بتنشيطها بنجاح! +
+ +``` +which python +``` + +```out +/home//transformers-course/.env/bin/python +``` + +
+ +### تثبيت التبعيات + +كما في القسم السابق حول استخدام مثيلات Google Colab، ستحتاج الآن إلى تثبيت الحزم المطلوبة للمتابعة. مرة أخرى، يمكنك تثبيت إصدار التطوير من 🤗 Transformers باستخدام مدير الحزم `pip`: +
+ +``` +pip install "transformers[sentencepiece]" +``` + +
+أنت الآن جاهز تمامًا للانطلاق! +
From 51d1a527f88504087c895b15acc8a3f4b4b4275c Mon Sep 17 00:00:00 2001 From: Pavel <60391448+pdumin@users.noreply.github.com> Date: Tue, 12 Apr 2022 18:28:57 +0300 Subject: [PATCH 68/73] Russian - Chapter 1 finished (#98) * 01/4 start * 1/4 finished * 1/5 finished * 1/5 update toc * 1/6 finished * 1/7 finished * 1/8 finished * 1/9 finished * 1/4 fix * toc update --- chapters/ru/_toctree.yml | 18 +++- chapters/ru/chapter1/4.mdx | 173 +++++++++++++++++++++++++++++++++++++ chapters/ru/chapter1/5.mdx | 17 ++++ chapters/ru/chapter1/6.mdx | 16 ++++ chapters/ru/chapter1/7.mdx | 16 ++++ chapters/ru/chapter1/8.mdx | 33 +++++++ chapters/ru/chapter1/9.mdx | 12 +++ 7 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 chapters/ru/chapter1/4.mdx create mode 100644 chapters/ru/chapter1/5.mdx create mode 100644 chapters/ru/chapter1/6.mdx create mode 100644 chapters/ru/chapter1/7.mdx create mode 100644 chapters/ru/chapter1/8.mdx create mode 100644 chapters/ru/chapter1/9.mdx diff --git a/chapters/ru/_toctree.yml b/chapters/ru/_toctree.yml index b8a26b63b..895b7475c 100644 --- a/chapters/ru/_toctree.yml +++ b/chapters/ru/_toctree.yml @@ -3,7 +3,7 @@ - local: chapter0/1 title: Введение -- title: 1. Transformer models +- title: 1. Трансформеры sections: - local: chapter1/1 title: Введение @@ -11,8 +11,22 @@ title: Обработка естесственного языка - local: chapter1/3 title: Трансформеры, на что они способны? + - local: chapter1/4 + title: Как работают трансформеры? + - local: chapter1/5 + title: Модели энкодеров + - local: chapter1/6 + title: Модели декодеров + - local: chapter1/7 + title: Модели "seq2seq" + - local: chapter1/8 + title: Предвзятости и ограничения + - local: chapter1/9 + title: Итоги + - title: 2. Использование библиотеки 🤗 Transformers sections: - local: chapter2/1 - title: Введение \ No newline at end of file + title: Введение + diff --git a/chapters/ru/chapter1/4.mdx b/chapters/ru/chapter1/4.mdx new file mode 100644 index 000000000..3c901acd4 --- /dev/null +++ b/chapters/ru/chapter1/4.mdx @@ -0,0 +1,173 @@ +# Как работают трансформеры? + +В этом разделе мы посмотрим в общих чертах на то, как работают трансфореры. + +## Немного истории + +Здесь приведены несколько ссылок на (короткую) историю трансформеров: + +
+A brief chronology of Transformers models. + +
+ +[Архитектура трансформеров](https://arxiv.org/abs/1706.03762) была опубликована в июне 2017. Основной фокус оригинального исследования был сосредоточен на задачах перевода. Эта публикация повлекла за собой несколько влиятельных моделей: + +- **Июнь 2018**: [GPT](https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf), первая предобученная модель, часто используется процедура тонкой настройки (fine-tuning) и применение для различных NLP-задач с последующим получением результатов высокого качества. + +- **Октябрь 2018**: [BERT](https://arxiv.org/abs/1810.04805), другая большая предобученная модель, была разработана для для получения хороших саммаризаций предложений (больше мы узнаем об этом в следующей главе!) + +- **Февраль 2019**: [GPT-2](https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf), улучшенная (и более объемная) версия GPT, которая не была сразу опубликована по этическим соображениям + +- **Октябрь 2019**: [DistilBERT](https://arxiv.org/abs/1910.01108), «дистиллированная» версия BERT, которая на 60% быстрее и на 40% менее объемная, однако сохраняющая 97% производительности BERT + +- **Октябрь 2019**: [BART](https://arxiv.org/abs/1910.13461) and [T5](https://arxiv.org/abs/1910.10683), две больших модели, повторяющие архитектуру классического трансформера + +- **Май 2020**, [GPT-3](https://arxiv.org/abs/2005.14165), еще более крупная версия GPT-2, способная хорошо справляться с различными задачами без необходимости fine-tuning (так называемое _zero-shot learning_) + +Этот список далеко не полный, он всего лишь призван выделить несколько разновидностей моделей трансформеров. +В широком смысле трансформеры могут быть классифицированы на три типа: +- GPT-подобные модели (также часто называемые _авторегрессионные_ трансформеры) +- BERT-подобные модели (также часто называемые _автокодирующие_ трансформеры (_auto-encoding_)) +- тип BART/T5 модели (также часто называются модели класса _последовательность-последовательность_ (_sequence2sequence, seq2seq_)) + +Мы рассмотри эти семейства более глубоко позже. + +## Трансформеры - языковые модели + +Все модели трансформеров, упомянутые выше (GPT, BERT, BART, T5, etc.) обучены как *языковые модели*. Это означает, что они обучены на огромном количестве текста в технике самостоятельного обучения (self-supervised learning). Самостоятельное обучение - это такой способ обучения, в котором цель обучения автоматически вычислятся на основе входных данных. Это означает, что люди не должны размечать данные! + +Такой тип моделей реализует статистическое понимание языка, на котором он был обучен, но он не очень полезен для конкретных практических задач. Из-за этого базовая предварительно обученная модель потом подвергается процедуре, называемой *трансферным обучением*. В ходе этого процесса модель настраивается под конкретные наблюдения, т. е. с размеченными человеком данными конкретной задачи. + +В качестве примера можно привести предсказание следующего слова в предложении на основе *n* предыдущих слов. Это называется *каузальным языковым моделированием*, потому что модель зависит от прошлых и текущих слов, но не от будущих. + + +
+Example of causal language modeling in which the next word from a sentence is predicted. + +
+ +Другой пример - *максированная языковая модель*, которая предсказывает замаскированное слово в предложении. + +
+Example of masked language modeling in which a masked word from a sentence is predicted. + +
+ +## Трансформеры - большие модели + +За исключением нескольких моделей (например, DistilBERT), общий подход к достижению высокого качества заключается в увеличении размера моделей и увеличении количества данных для обучения. + +
+Number of parameters of recent Transformers models +
+ +К сожалению, обучение модели, особенно большой, требует большого количества данных. Это приводит к увеличению времени и вычислительных потребностей. Это воздействует даже на окружающую среду, что можно увидеть графике ниже. + +
+The carbon footprint of a large language model. + +
+ + + +Это продемонстрировано командой разработчиков на примере очень большой модели. Команда сознательно пытающется уменьшить воздействие предобучения на окружающую среду. Углеродный следу от проведения множества экспериментов для получения лучших гиперпараметров будет еще выше. + +Представьте себе, что каждый раз, когда исследовательская группа, студенческая организация или компания хотят обучить модель, они делают это с нуля. Это привело бы к огромным, ненужным глобальным затратам! + +Вот почему совместное использование языковых моделей имеет первостепенное значение: совместное использование обученных весов и построение на основе уже обученных весов снижает общую стоимость вычислений и углеродный след сообщества. + +## Трансферное обучение + + + +*Предобучение* - это процесс обучения модели с нуля: веса модели случайным образом инициализируются, после начинается обучение без предварительных настроек. + +
+The pretraining of a language model is costly in both time and money. + +
+ +Предобучение обычно происходит на огромных наборах данных, сам процесс может занять несколько недель. + +*Fine-tuning*, с другой стороны, это обучение, проведенной *после* того, как модель была предобучена. Для проведения fine-tuning вы сначала должны выбрать предобученную языковую модель, а после провести обучение на данных собственной задачи. Стойте -- почему не обучить модель сразу же на данных конкретной задачи? Этому есть несколько причин: + +* Предобученная модель уже обучена на датасете, который имеет много сходств с датасетом для fine-tuning. Процесс тонкой настройки может использовать знания, которые были получены моделью в процессе предобучения (например, в задачах NLP предварительно обученная модель будет иметь представление о статистических закономерностях языка, который вы используете в своей задаче). + +* Так как предобученная модель уже "видела" много данных, процесс тонкой настройки требует меньшего количества данных для получения приемлемых результатов. + +* По этой же причине требуется и намного меньше времени для получения хороших результатов. + +Например, можно использовать предварительно обученную на английском языке модель, а затем провести ее fine-tuning на корпусе arXiv, в результате чего получится научно-исследовательская модель. Для тонкой настройки потребуется лишь ограниченный объем данных: знания, которые приобрела предварительно обученная модель, «передаются» (осуществляют трансфер), отсюда и термин «трансферное обучение». + +
+The fine-tuning of a language model is cheaper than pretraining in both time and money. + +
+ +Таким образом, тонкая настройка модели требует меньше времени, данных, финансовых и экологических затрат. Также быстрее и проще перебирать различные схемы тонкой настройки, поскольку обучение требует меньше усилий, чем полное предварительное обучение. + +Этот процесс также даст лучшие результаты, чем обучение с нуля (если только у вас нет большого количества данных), поэтому вы всегда должны пытаться использовать предобученную модель — модель, максимально приближенную к поставленной задаче, а потом дообучить ее. + +## Общая архитектура + +В этом разделе мы рассмотрим общую архитектуру модели трансформера. Не беспокойтесь, если вы не понимаете некоторых понятий; далее есть подробные разделы, посвященные каждому из компонентов. + + + +## Введение + +Модель состоит из двух блоков: + +* **Encoder (слева)** (кодировщик, энкодер): энкодер получает входные данные и строит их репрезентацию (формирует признаки). Это означает, модель нацелена на "понимание" входных данных. +* **Декодер (справа)** (декодировщик, декодер): декодер использует репрезентации (признаки) энкодера с другими входными данными для создания нужной последовательности. Это означает, что модель нацелена на генерацию выходных данных. + +
+Architecture of a Transformers models + +
+ +Каждая из этих частей может быть использована отдельно, это зависит от задачи: + +* **Encoder-модели**: полезны для задач, требющих понимания входных данных, таких как классификация предложений и распознавание именованных сущностей. +* **Decoder-модели**: полезны для генеративных задач, таких как генерация текста. +* **Encoder-decoder модели** или **seq2seq-модели**: полезны в генеративных задачах, требущих входных данных. Например: перевод или саммаризация текста. + +Мы изучим эти архитектуры глубже в следующих разделах. + +## Слой внимания или attention + +Ключевой особенностью трансформеров является наличие в архитектуре специального слоя, называемого слоем внимания или attention'ом. Статья, в которой была описана архитектура трансформера, называлась["Attention Is All You Need"](https://arxiv.org/abs/1706.03762) ("Внимание - все, что вам нужно")! Мы изучим детали этого слоя позже. На текущий момент мы сформулируем механизм его работы так: attention-слой помогает модели "обращать внимание" на одни слова в поданном на вход предложении, а другие слова в той или иной степени игнорировать. И это происходит в процессе анализа каждого слова. + +Чтобы поместить это в контекст, рассмотрим задачу перевода текста с английского на французский язык. Для предложения "You like this course", модель должна будет также учитывать соседнее слово "You", чтобы получить правильный перевод слова "like", потому что во французском языке глагол "like" спрягается по-разному в зависимости от подлежащего. Однако остальная часть предложения бесполезна для перевода этого слова. В том же духе при переводе "like" также необходимо будет обратить внимание на слово "course", потому что "this" переводится по-разному в зависимости от того, стоит ли ассоциированное существительное в мужском или женском роде. Опять же, другие слова в предложении не будут иметь значения для перевода "this". С более сложными предложениями (и более сложными грамматическими правилами) модели потребуется уделять особое внимание словам, которые могут оказаться дальше в предложении, чтобы правильно перевести каждое слово. + +Такая же концепция применима к любой задаче, связанной с обработкой естесственного языка: слово само по себе имеет некоторое значение, однако значение очень часто зависит от контекста, которым может являться слово (или слова), стоящие вокруг искомого слова. + +Теперь, когда вы знакомы с идеей attention в целом, посмотрим поближе на архитектуру всего трансформера. + +## Первоначальная архитектура + +Архитектура трансформера изначально была разработана для перевода. Во время обучения энкодер получает входные данные (предложения) на определенном языке, а декодер получает те же предложения на желаемом целевом языке. В энкодере слои внимания могут использовать все слова в предложении (поскольку, как мы только что видели, перевод данного слова может зависеть от того, что в предложении находится после и перед ним). Декодер, в свою очерель, работает последовательно и может обращать внимание только на слова в предложении, которые он уже перевел (то есть только на слова перед генерируемым в данный момент словом). Например, когда мы предсказали первые три слова переведенной цели, мы передаем их декодеру, который затем использует все входные данные энкодера, чтобы попытаться предсказать четвертое слово. + +Чтобы ускорить процесс во время обучения (когда модель имеет доступ к целевым предложениям), декодер получает целевое предложение полностью, но ему не разрешается использовать будущие слова (если он имел доступ к слову в позиции 2 при попытке предсказать слово на позиции 2, задача не будет сложной!). Например, при попытке предсказать четвертое слово уровень внимания будет иметь доступ только к словам в позициях с 1 по 3. + +Первоначальная архитектура Transformer выглядела так: энкодер слева и декодер справа: + +
+Architecture of a Transformers models + +
+ +Обратите внимание, что первый уровень внимания в блоке декодера обращает внимание на все (прошлые) входные данные декодера, а второй уровень внимания использует выходные данные первого энкодера. Таким образом, он может получить доступ ко всему входному предложению, чтобы наилучшим образом предсказать текущее слово. Это очень полезно, так как разные языки могут иметь грамматические правила, которые располагают слова в разном порядке, или некоторый контекст, предоставленный в предложении далеко от текущего слова. Конекст может быть полезен для определения наилучшего перевода данного слова. + +*Attention-mask* (маска внимания) также может использоваться в энкодере/декодере, чтобы модель не обращала внимания на некоторые специальные слова — например, специальное несуществующее слово-заполнитель (служебный токен), используемое для придания всем входным данным одинаковой длины при группировке предложений. + +## Архитектуры и контрольные точки + +По мере погружения в трансформеры, вы будете встречать термины *архитектуры* и *контрольные точки* (checkpoints) в смысле *модели*. Эти термины имеют разный смысл: + +**Архитектура** - скелет модели -- слои, связи и операции, которые выполняются в модели. +**Контрольная точка** - веса модели, которые могут быть загружены для конкретной архитектуры. +**Модель** - зонтичный термин, который может означать и архитектуру, и веса для конкретной архитектуры. В этом курсе мы будем точнее использовать термины *архитектуры* и *чекпоинт*, если это будет важно для лучшего понимания. + +Например, BERT - это архитектура, а `bert-base-cased` - набор весов, подготовленный Google к первому выпуску BERT'а, - это чекпоинт. Однако можно сказать и "модель BERT", и "модель bert-base-cased". diff --git a/chapters/ru/chapter1/5.mdx b/chapters/ru/chapter1/5.mdx new file mode 100644 index 000000000..7e4dc8b1a --- /dev/null +++ b/chapters/ru/chapter1/5.mdx @@ -0,0 +1,17 @@ +# Модели энкодеров + + + +Энкодеры используют только компонент кодировщика трансформера. На каждом этапе слой внимания может использовать все слова исходного предложения. Эти модели часто характеризуют как имеющие двунаправленное внимание ("bi-directional attention"), и часто называют моделями *автоэнкодеров*. + +Предварительное обучение этих моделей обычно заключаетс в том, чтобы как-то исказить данное предложение (например, путем маскировки в нем случайных слов) и поставить перед моделью задачу найти или восстановить исходное предложение. + +Энкодеры лучше всего подходят для задач, требующих _понимания_ всего предложения, таких как классификация предложений, распознавание именованных сущностей (и, в более общем смысле, классификация слов) и ответы на вопросы с извлечением информации из контекста. + +К представителям этого семейства моделей относятся: + +- [ALBERT](https://huggingface.co/transformers/model_doc/albert.html) +- [BERT](https://huggingface.co/transformers/model_doc/bert.html) +- [DistilBERT](https://huggingface.co/transformers/model_doc/distilbert.html) +- [ELECTRA](https://huggingface.co/transformers/model_doc/electra.html) +- [RoBERTa](https://huggingface.co/transformers/model_doc/roberta.html) diff --git a/chapters/ru/chapter1/6.mdx b/chapters/ru/chapter1/6.mdx new file mode 100644 index 000000000..d9ca11089 --- /dev/null +++ b/chapters/ru/chapter1/6.mdx @@ -0,0 +1,16 @@ +# Модели декодеров + + + +Декодировщики используют только компонент декодер трансформера. На каждом этапе для текущего слова слой внимания может получить доступ только к словам, которые были расположены до текущего в предложении. Такие модели часто называются *авторегрессионными моделями*. + +Процесс предобучения декодеров обычно заключается в предсказании следующего слова в предложении. ё + +Такие модели лучше всего подходят для задач, связанных с генерацией текста. + +Представителями этого семейства моделей являются: + +- [CTRL](https://huggingface.co/transformers/model_doc/ctrl.html) +- [GPT](https://huggingface.co/transformers/model_doc/gpt.html) +- [GPT-2](https://huggingface.co/transformers/model_doc/gpt2.html) +- [Transformer XL](https://huggingface.co/transformers/model_doc/transformerxl.html) diff --git a/chapters/ru/chapter1/7.mdx b/chapters/ru/chapter1/7.mdx new file mode 100644 index 000000000..730b8f96f --- /dev/null +++ b/chapters/ru/chapter1/7.mdx @@ -0,0 +1,16 @@ +# Модели вида "seq2seq" + + + +Энкодер-декодер модели (также называемые *sequence-to-sequence models*) используют обе части трансформера. На каждом этапе слой внимания энкодера получает доступ ко всем словам в исходной последовательности, тогда как слой внимания декодера получает доступ только к тем словам, которые позиционированы до текущего слова. + +Предобучение таких моделей может быть проведено по аналогии с процессом предобучения энкодера или декодера, но обычно это происходит сложнее. Например, модель [T5](https://huggingface.co/t5-base) была предобучена путем замены случайных фрагментов текста (фрагменты могут содержать несколько слов) на специальную маску, цель модели - предсказать текст, который заменила маска. + +Модели seq2seq лучше всего подходят для задач генерации новых предложений, зависящих от входного массива данных, например: саммаризация текста, перевод или генерация ответов на вопросы. + +Представителями этого семейства являются: + +- [BART](https://huggingface.co/transformers/model_doc/bart.html) +- [mBART](https://huggingface.co/transformers/model_doc/mbart.html) +- [Marian](https://huggingface.co/transformers/model_doc/marian.html) +- [T5](https://huggingface.co/transformers/model_doc/t5.html) diff --git a/chapters/ru/chapter1/8.mdx b/chapters/ru/chapter1/8.mdx new file mode 100644 index 000000000..05d3b724d --- /dev/null +++ b/chapters/ru/chapter1/8.mdx @@ -0,0 +1,33 @@ +# Предвзятости и ограничения + + + +Если вы намерены использовать предварительно обученную модель или точно настроенную версию в рабочей среде, имейте в виду, что, хотя эти модели являются мощными инструментами, они имеют ограничения. Самая большая из них заключается в том, что для предварительной подготовки на больших объемах данных исследователи часто очищают весь контент, который они могут найти, беря как лучшее, так и худшее из того, что доступно в Интернете. + +Для иллюстрации вернемся к примеру пайплайна `fill-mask` с моделью BERT: + +```python +from transformers import pipeline + +unmasker = pipeline("fill-mask", model="bert-base-uncased") +result = unmasker("This man works as a [MASK].") +print([r["token_str"] for r in result]) + +result = unmasker("This woman works as a [MASK].") +print([r["token_str"] for r in result]) +``` + +```python out +['lawyer', 'carpenter', 'doctor', 'waiter', 'mechanic'] +['nurse', 'waitress', 'teacher', 'maid', 'prostitute'] +``` + +На просьбу вставить пропущенное слово в этих двух предложениях модель дает только один ответ без гендерной принадлежности (официант/официантка). Другие рабочие профессии обычно ассоциируются с одним конкретным полом — и да, проститутка попала в топ-5 вариантов, которые модель ассоциирует с "женщиной" и "работой". Это происходит даже несмотря на то, что BERT — одна из редких моделей трансформеров, созданная не путем сбора данных со всего Интернета, а с использованием явно нейтральных данных (он обучен на [английской Википедии](https://huggingface.co/datasets/wikipedia) и наборе данных [BookCorpus](https://huggingface.co/datasets/bookcorpus). + +Поэтому, когда вы используете эти инструменты, вам нужно помнить, что исходная модель, которую вы используете, может очень легко генерировать сексистский, расистский или гомофобный контент. Тонкая настройка модели на ваших данных не избавит вас от этой внутренней предвзятости. + diff --git a/chapters/ru/chapter1/9.mdx b/chapters/ru/chapter1/9.mdx new file mode 100644 index 000000000..730712e4e --- /dev/null +++ b/chapters/ru/chapter1/9.mdx @@ -0,0 +1,12 @@ +# Итоги + +В этой главе вы увидели, как подходить к различным задачам NLP, используя высокоуровневую функцию `pipeline()` из библиотеки 🤗 Transformers. Вы также увидели, как искать и использовать модели в Hub, а также как использовать Inference API для тестирования моделей прямо в браузере. + +Мы обсудили, как трансформеры работают на высоком уровне, и поговорили о важности трансферного обучения и тонкой настройки. Ключевым аспектом является то, что вы можете использовать всю архитектуру или только энкодер или декодер, в зависимости от того, какую задачу вы хотите решить. Следующая таблица резюмирует это: + + +| Модель | Примеры | Задачи | +|-----------------|--------------------------------------------|----------------------------------------------------------------------------------| +| Энкодер | ALBERT, BERT, DistilBERT, ELECTRA, RoBERTa | Классификация предложений, распознавание именованных сущностей, генерация ответов на вопросы с извлечением информации | +| Декодер | CTRL, GPT, GPT-2, Transformer XL | Генерация текста | +| Энкодер-декодер | BART, T5, Marian, mBART | Саммаризация, перевод, генеративный подход к ответам на вопросы | From 433f6457d5098a6b368227f0964acfe7c783b871 Mon Sep 17 00:00:00 2001 From: 1375626371 <40328311+1375626371@users.noreply.github.com> Date: Wed, 13 Apr 2022 17:58:59 +0800 Subject: [PATCH 69/73] Chinese - Chapter 1 finished (#113) * Chinese - Chapter 1 finished * Add zh to the languages field Co-authored-by: petrichor1122 <87262598+petrichor1122@users.noreply.github.com> Co-authored-by: zhlhyx <95976146+zhlhyx@users.noreply.github.com> --- .github/workflows/build_documentation.yml | 2 +- .github/workflows/build_pr_documentation.yml | 2 +- chapters/zh/_toctree.yml | 23 ++ chapters/zh/chapter1/1.mdx | 52 ++++ chapters/zh/chapter1/10.mdx | 253 ++++++++++++++++ chapters/zh/chapter1/2.mdx | 20 ++ chapters/zh/chapter1/3.mdx | 287 +++++++++++++++++++ chapters/zh/chapter1/4.mdx | 172 +++++++++++ chapters/zh/chapter1/5.mdx | 17 ++ chapters/zh/chapter1/6.mdx | 17 ++ chapters/zh/chapter1/7.mdx | 16 ++ chapters/zh/chapter1/8.mdx | 31 ++ chapters/zh/chapter1/9.mdx | 11 + 13 files changed, 901 insertions(+), 2 deletions(-) create mode 100644 chapters/zh/_toctree.yml create mode 100644 chapters/zh/chapter1/1.mdx create mode 100644 chapters/zh/chapter1/10.mdx create mode 100644 chapters/zh/chapter1/2.mdx create mode 100644 chapters/zh/chapter1/3.mdx create mode 100644 chapters/zh/chapter1/4.mdx create mode 100644 chapters/zh/chapter1/5.mdx create mode 100644 chapters/zh/chapter1/6.mdx create mode 100644 chapters/zh/chapter1/7.mdx create mode 100644 chapters/zh/chapter1/8.mdx create mode 100644 chapters/zh/chapter1/9.mdx diff --git a/.github/workflows/build_documentation.yml b/.github/workflows/build_documentation.yml index a03061dc8..8e0f0b7e9 100644 --- a/.github/workflows/build_documentation.yml +++ b/.github/workflows/build_documentation.yml @@ -14,6 +14,6 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: ar bn en es fa fr he ko pt ru th tr + languages: ar bn en es fa fr he ko pt ru th tr zh secrets: token: ${{ secrets.HUGGINGFACE_PUSH }} \ No newline at end of file diff --git a/.github/workflows/build_pr_documentation.yml b/.github/workflows/build_pr_documentation.yml index 84af57f75..ff5039db9 100644 --- a/.github/workflows/build_pr_documentation.yml +++ b/.github/workflows/build_pr_documentation.yml @@ -16,5 +16,5 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: ar bn en es fa fr he ko pt ru th tr + languages: ar bn en es fa fr he ko pt ru th tr zh hub_base_path: https://moon-ci-docs.huggingface.co/course diff --git a/chapters/zh/_toctree.yml b/chapters/zh/_toctree.yml new file mode 100644 index 000000000..453fc5e99 --- /dev/null +++ b/chapters/zh/_toctree.yml @@ -0,0 +1,23 @@ +- title: 1. Transformer 模型 + sections: + - local: chapter1/1 + title: 章节简介 + - local: chapter1/2 + title: 自然语言处理 + - local: chapter1/3 + title: Transformers能做什么? + - local: chapter1/4 + title: Transformers 是如何工作的? + - local: chapter1/5 + title: 编码器模型 + - local: chapter1/6 + title: 解码器模型 + - local: chapter1/7 + title: 序列到序列模型 + - local: chapter1/8 + title: 偏见和局限性 + - local: chapter1/9 + title: 总结 + - local: chapter1/10 + title: 章末小测验 + quiz: 1 \ No newline at end of file diff --git a/chapters/zh/chapter1/1.mdx b/chapters/zh/chapter1/1.mdx new file mode 100644 index 000000000..68e6a14c7 --- /dev/null +++ b/chapters/zh/chapter1/1.mdx @@ -0,0 +1,52 @@ +# 简介 + +## 欢迎来到🤗课程 + + + +本课程将使用 Hugging Face 生态系统中的库——🤗 Transformers、🤗 Datasets、🤗 Tokenizers 和 🤗 Accelerate——以及 Hugging Face Hub 教你自然语言处理 (NLP)。它是完全免费的,并且没有广告。 + + +## 有什么是值得期待的? + +以下是课程的简要概述: + +
+Brief overview of the chapters of the course. + +
+ +- 第 1 章到第 4 章介绍了 🤗 Transformers 库的主要概念。在本课程的这一部分结束时,您将熟悉 Transformer 模型的工作原理,并将了解如何使用 [Hugging Face Hub](https://huggingface.co/models) 中的模型,在数据集上对其进行微调,并在 Hub 上分享您的结果。 +- 第 5 章到第 8 章在深入研究经典 NLP 任务之前,教授 🤗 Datasets和 🤗 Tokenizers的基础知识。在本部分结束时,您将能够自己解决最常见的 NLP 问题。 +- 第 9 章到第 12 章更加深入,探讨了如何使用 Transformer 模型处理语音处理和计算机视觉中的任务。在此过程中,您将学习如何构建和分享模型,并针对生产环境对其进行优化。在这部分结束时,您将准备好将🤗 Transformers 应用于(几乎)任何机器学习问题! + +这个课程: + +* 需要良好的 Python 知识 +* 最好先学习深度学习入门课程,例如[DeepLearning.AI](https://www.deeplearning.ai/) 提供的 [fast.ai实用深度学习教程](https://course.fast.ai/) +* 不需要事先具备 [PyTorch](https://pytorch.org/) 或 [TensorFlow](https://www.tensorflow.org/) 知识,虽然熟悉其中任何一个都会对huggingface的学习有所帮助 + +完成本课程后,我们建议您查看 [DeepLearning.AI的自然语言处理系列课程](https://www.coursera.org/specializations/natural-language-processing?utm_source=deeplearning-ai&utm_medium=institutions&utm_campaign=20211011-nlp-2-hugging_face-page-nlp-refresh),其中涵盖了广泛的传统 NLP 模型,如朴素贝叶斯和 LSTM,这些模型非常值得了解! + +## 我们是谁? + +关于作者: + +**Matthew Carrigan** 是 Hugging Face 的机器学习工程师。他住在爱尔兰都柏林,之前在 Parse.ly 担任机器学习工程师,在此之前,他在Trinity College Dublin担任博士后研究员。他不相信我们会通过扩展现有架构来实现 AGI,但无论如何都对机器人充满希望。 + +**Lysandre Debut** 是 Hugging Face 的机器学习工程师,从早期的开发阶段就一直致力于 🤗 Transformers 库。他的目标是通过使用非常简单的 API 开发工具,让每个人都可以使用 NLP。 + +**Sylvain Gugger** 是 Hugging Face 的一名研究工程师,也是 🤗Transformers库的核心维护者之一。此前,他是 fast.ai 的一名研究科学家,他与Jeremy Howard 共同编写了[Deep Learning for Coders with fastai and Py Torch](https://learning.oreilly.com/library/view/deep-learning-for/9781492045519/)。他的主要研究重点是通过设计和改进允许模型在有限资源上快速训练的技术,使深度学习更容易普及。 + +**Merve Noyan** 是 Hugging Face 的开发者倡导者,致力于开发工具并围绕它们构建内容,以使每个人的机器学习平民化。 + +**Lucile Saulnier** 是 Hugging Face 的机器学习工程师,负责开发和支持开源工具的使用。她还积极参与了自然语言处理领域的许多研究项目,例如协作训练和 BigScience。 + +**Lewis Tunstall** 是 Hugging Face 的机器学习工程师,专注于开发开源工具并使更广泛的社区可以使用它们。他也是即将出版的一本书[O’Reilly book on Transformers](https://www.oreilly.com/library/view/natural-language-processing/9781098103231/)的作者之一。 + +**Leandro von Werra** 是 Hugging Face 开源团队的机器学习工程师,也是即将出版的一本书[O’Reilly book on Transformers](https://www.oreilly.com/library/view/natural-language-processing/9781098103231/)的作者之一。他拥有多年的行业经验,通过在整个机器学习堆栈中工作,将 NLP 项目投入生产。 + +你准备好了吗?在本章中,您将学习: +* 如何使用 `pipeline()` 函数解决文本生成、分类等NLP任务 +* 关于 Transformer 架构 +* 如何区分编码器、解码器和编码器-解码器架构和用例 diff --git a/chapters/zh/chapter1/10.mdx b/chapters/zh/chapter1/10.mdx new file mode 100644 index 000000000..23f768115 --- /dev/null +++ b/chapters/zh/chapter1/10.mdx @@ -0,0 +1,253 @@ + + +# 章末小测试 + +这一章涵盖了很多内容! 如果有一些不太明白的地方,请不要担心; 下一章将帮助你了解这些模块在底层是如何工作的。 + +让我们来测试一下你在这一章学到了什么! + +### 1. 探索 Hub 并寻找 `roberta-large-mnli` checkpoint。 它可以完成什么类型的任务? + + +roberta-large-mnli 页面回顾一下." + }, + { + text: "文本分类", + explain: "更准确地说,它对两个句子在三个标签(矛盾、无关、相近)之间的逻辑链接进行分类——这项任务也称为自然语言推理.", + correct: true + }, + { + text: "文本生成", + explain: "点击前往roberta-large-mnli 页面回顾一下." + } + ]} +/> + +### 2. 下面的代码将会返回什么结果? + +```py +from transformers import pipeline + +ner = pipeline("ner", grouped_entities=True) +ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") +``` + +sentiment-analysis pipeline将会返回这些." + }, + { + text: "它将返回一个生成的文本来完成这句话。", + explain: "这个选项是不对的 — text-generation pipeline将会返回这些.", + }, + { + text: "它将返回代表人员、组织或位置的单词。", + explain: "此外,使用 grouped_entities=True,它会将属于同一实体的单词组合在一起,例如“Hugging Face”。", + correct: true + } + ]} +/> + +### 3. 在此代码示例中...的地方应该填写什么? + +```py +from transformers import pipeline + +filler = pipeline("fill-mask", model="bert-base-cased") +result = filler("...") +``` + + has been waiting for you.", + explain: "这个选项是不对的。 请查看 bert-base-cased 模型卡片,然后再尝试找找错在哪里。" + }, + { + text: "This [MASK] has been waiting for you.", + explain: "正解! 这个模型的mask的掩码是[MASK].", + correct: true + }, + { + text: "This man has been waiting for you.", + explain: "这个选项是不对的。 这个pipeline的作用是填充经过mask的文字,因此它需要在输入的文本中存在mask的token。" + } + ]} +/> + +### 4. 为什么这段代码会无法运行? + +```py +from transformers import pipeline + +classifier = pipeline("zero-shot-classification") +result = classifier("This is a course about the Transformers library") +``` + +candidate_labels=[...].", + correct: true + }, + { + text: "这个pipeline需要多个句子,而不仅仅是一个。", + explain: "这个选项是不对的。尽管正确使用时,此pipeline可以同时处理多个句子(与所有其他pipeline一样)。" + }, + { + text: "像往常一样,🤗 Transformers库出故障了。", + explain: "对此,我们不予置评!" + }, + { + text: "该pipeline需要更长的输入; 这个句子太短了。", + explain: "这个选项是不对的。 不过请注意,在这个pipeline处理时,太长的文本将被截断。" + } + ]} +/> + +### 5. “迁移学习”是什么意思? + + + +### 6. 语言模型在预训练时通常不需要标签,这样的说法是否正确。 + + +自监督,这意味着标签是根据输入自动创建的(例如:预测下一个单词或填充一些[MARSK]单词)。", + correct: true + }, + { + text: "错误", + explain: "这不是一个正确的答案。" + } + ]} +/> + + +### 7. 选择最能描述“模型(model)”、“架构(architecture)”和“权重(weights)”的句子。 + + + +### 8. 你将使用以下哪种类型的模型来根据输入的提示生成文本? + + + +### 9. 你会使用哪些类型的模型来生成文本的摘要? + + + +### 10. 你会使用哪一种类型的模型来根据特定的标签对文本输入进行分类? + + + +### 11. 模型中观察到的偏见有哪些可能的来源? + + diff --git a/chapters/zh/chapter1/2.mdx b/chapters/zh/chapter1/2.mdx new file mode 100644 index 000000000..1b5ee0ea6 --- /dev/null +++ b/chapters/zh/chapter1/2.mdx @@ -0,0 +1,20 @@ +# 自然语言处理 + +在进入 Transformer 模型之前,让我们快速概述一下自然语言处理是什么以及我们为什么这么重视它。 + +## 什么是自然语言处理? + +NLP 是语言学和机器学习交叉领域,专注于理解与人类语言相关的一切。 NLP 任务的目标不仅是单独理解单个单词,而且是能够理解这些单词的上下文。 + +以下是常见 NLP 任务的列表,每个任务都有一些示例: + +- **对整个句子进行分类**: 获取评论的情绪,检测电子邮件是否为垃圾邮件,确定句子在语法上是否正确或两个句子在逻辑上是否相关 +- **对句子中的每个词进行分类**: 识别句子的语法成分(名词、动词、形容词)或命名实体(人、地点、组织) +- **生成文本内容**: 用自动生成的文本完成提示,用屏蔽词填充文本中的空白 +- **从文本中提取答案**: 给定问题和上下文,根据上下文中提供的信息提取问题的答案 +- **从输入文本生成新句子**: 将文本翻译成另一种语言,总结文本 + +NLP 不仅限于书面文本。它还解决了语音识别和计算机视觉中的复杂挑战,例如生成音频样本的转录或图像描述。 +## 为什么具有挑战性? + +计算机处理信息的方式与人类不同。例如,当我们读到“我饿了”这句话时,我们很容易理解它的意思。同样,给定两个句子,例如“我很饿”和“我很伤心”,我们可以轻松确定它们的相似程度。对于机器学习 (ML) 模型,此类任务更加困难。文本需要以一种使模型能够从中学习的方式进行处理。而且由于语言很复杂,我们需要仔细考虑必须如何进行这种处理。关于如何表示文本已经做了很多研究,我们将在下一章中介绍一些方法。 \ No newline at end of file diff --git a/chapters/zh/chapter1/3.mdx b/chapters/zh/chapter1/3.mdx new file mode 100644 index 000000000..076263ba4 --- /dev/null +++ b/chapters/zh/chapter1/3.mdx @@ -0,0 +1,287 @@ +# Transformers能做什么? + + + +在本节中,我们将看看 Transformer 模型可以做什么,并使用 🤗 Transformers 库中的第一个工具:pipeline() 函数。 + +👀 看到那个右上角的 在Colab中打开的按钮了吗? 单击它就可以打开一个包含本节所有代码示例的 Google Colab 笔记本。 每一个有实例代码的小节都会有它。 + +如果您想在本地运行示例,我们建议您查看准备. + + +## Transformer被应用于各个方面! +Transformer 模型用于解决各种 NLP 任务,就像上一节中提到的那样。以下是一些使用 Hugging Face 和 Transformer 模型的公司和组织,他们也通过分享他们的模型回馈社区: + +![使用 Hugging Face 的公司](https://huggingface.co/course/static/chapter1/companies.PNG) +[🤗 Transformers 库](https://github.com/huggingface/transformers)提供了创建和使用这些共享模型的功能。[模型中心(hub)](https://huggingface.co/models)包含数千个任何人都可以下载和使用的预训练模型。您还可以将自己的模型上传到 Hub! + + +⚠️ Hugging Face Hub 不限于 Transformer 模型。任何人都可以分享他们想要的任何类型的模型或数据集!创建一个 Huggingface.co 帐户(https://huggingface.co/join)以使用所有可用功能! + + +在深入研究 Transformer 模型的底层工作原理之前,让我们先看几个示例,看看它们如何用于解决一些有趣的 NLP 问题。 + +## 使用pipelines + + +(这里有一个视频,但是国内可能打不开,译者注) + + +🤗 Transformers 库中最基本的对象是 **pipeline()** 函数。它将模型与其必要的预处理和后处理步骤连接起来,使我们能够通过直接输入任何文本并获得最终的答案: + +```python +from transformers import pipeline + +classifier = pipeline("sentiment-analysis") +classifier("I've been waiting for a HuggingFace course my whole life.") +``` +```python out +[{'label': 'POSITIVE', 'score': 0.9598047137260437}] +``` + + +我们也可以多传几句! +```python +classifier( + ["I've been waiting for a HuggingFace course my whole life.", "I hate this so much!"] +) +``` +```python out +[{'label': 'POSITIVE', 'score': 0.9598047137260437}, + {'label': 'NEGATIVE', 'score': 0.9994558095932007}] +``` +默认情况下,此pipeline选择一个特定的预训练模型,该模型已针对英语情感分析进行了微调。创建**分类器**对象时,将下载并缓存模型。如果您重新运行该命令,则将使用缓存的模型,无需再次下载模型。 + +将一些文本传递到pipeline时涉及三个主要步骤: + +1. 文本被预处理为模型可以理解的格式。 +2. 预处理的输入被传递给模型。 +3. 模型处理后输出最终人类可以理解的结果。 + +目前[可用的一些pipeline](https://huggingface.co/transformers/main_classes/pipelines.html)是: + +* **特征提取**(获取文本的向量表示) +* **填充空缺** +* **ner**(命名实体识别) +* **问答** +* **情感分析** +* **文本摘要** +* **文本生成** +* **翻译** +* **零样本分类** + +让我们来看看其中的一些吧! + +## 零样本分类 +我们将首先处理一项非常具挑战性的任务,我们需要对尚未标记的文本进行分类。这是实际项目中的常见场景,因为注释文本通常很耗时并且需要领域专业知识。对于这项任务**zero-shot-classification**pipeline非常强大:它允许您直接指定用于分类的标签,因此您不必依赖预训练模型的标签。下面的模型展示了如何使用这两个标签将句子分类为正面或负面——但也可以使用您喜欢的任何其他标签集对文本进行分类。 + +```python +from transformers import pipeline + +classifier = pipeline("zero-shot-classification") +classifier( + "This is a course about the Transformers library", + candidate_labels=["education", "politics", "business"], +) +``` +```python out +{'sequence': 'This is a course about the Transformers library', + 'labels': ['education', 'business', 'politics'], + 'scores': [0.8445963859558105, 0.111976258456707, 0.043427448719739914]} +``` + +此pipeline称为zero-shot,因为您不需要对数据上的模型进行微调即可使用它。它可以直接返回您想要的任何标签列表的概率分数! + +✏️**快来试试吧!**使用您自己的序列和标签,看看模型的行为。 + + +## 文本生成 +现在让我们看看如何使用pipeline来生成一些文本。这里的主要使用方法是您提供一个提示,模型将通过生成剩余的文本来自动完成整段话。这类似于许多手机上的预测文本功能。文本生成涉及随机性,因此如果您没有得到相同的如下所示的结果,这是正常的。 + +```python +from transformers import pipeline + +generator = pipeline("text-generation") +generator("In this course, we will teach you how to") +``` +```python out +[{'generated_text': 'In this course, we will teach you how to understand and use ' + 'data flow and data interchange when handling user data. We ' + 'will be working with one or more of the most commonly used ' + 'data flows — data flows of various types, as seen by the ' + 'HTTP'}] +``` +您可以使用参数 **num_return_sequences** 控制生成多少个不同的序列,并使用参数 **max_length** 控制输出文本的总长度。 + + +✏️**快来试试吧!**使用 num_return_sequences 和 max_length 参数生成两个句子,每个句子 15 个单词。 + + +## 在pipeline中使用 Hub 中的其他模型 +前面的示例使用了默认模型,但您也可以从 Hub 中选择特定模型以在特定任务的pipeline中使用 - 例如,文本生成。转到[模型中心(hub)](https://huggingface.co/models)并单击左侧的相应标签将会只显示该任务支持的模型。[例如这样](https://huggingface.co/models?pipeline_tag=text-generation)。 + +让我们试试 [**distilgpt2**](https://huggingface.co/distilgpt2) 模型吧!以下是如何在与以前相同的pipeline中加载它: + +```python +from transformers import pipeline + +generator = pipeline("text-generation", model="distilgpt2") +generator( + "In this course, we will teach you how to", + max_length=30, + num_return_sequences=2, +) +``` +```python out +[{'generated_text': 'In this course, we will teach you how to manipulate the world and ' + 'move your mental and physical capabilities to your advantage.'}, + {'generated_text': 'In this course, we will teach you how to become an expert and ' + 'practice realtime, and with a hands on experience on both real ' + 'time and real'}] +``` +您可以通过单击语言标签来筛选搜索结果,然后选择另一种文本生成模型的模型。模型中心(hub)甚至包含支持多种语言的多语言模型。 + +通过单击选择模型后,您会看到有一个小组件,可让您直接在线试用。通过这种方式,您可以在下载之前快速测试模型的功能。 + +✏️**快来试试吧!**使用标签筛选查找另一种语言的文本生成模型。使用小组件测试并在pipeline中使用它! + + +## 推理 API +所有模型都可以使用 Inference API 直接通过浏览器进行测试,该 API 可在 [Hugging Face 网站](https://huggingface.co/)上找到。通过输入自定义文本并观察模型的输出,您可以直接在此页面上使用模型。 + +小组件形式的推理 API 也可作为付费产品使用,如果您的工作流程需要它,它会派上用场。有关更多详细信息,请参阅[定价页面](https://huggingface.co/pricing)。 + +## Mask filling +您将尝试的下一个pipeline是 **fill-mask**。此任务的想法是填充给定文本中的空白: +```python +from transformers import pipeline + +unmasker = pipeline("fill-mask") +unmasker("This course will teach you all about models.", top_k=2) +``` +```python out +[{'sequence': 'This course will teach you all about mathematical models.', + 'score': 0.19619831442832947, + 'token': 30412, + 'token_str': ' mathematical'}, + {'sequence': 'This course will teach you all about computational models.', + 'score': 0.04052725434303284, + 'token': 38163, + 'token_str': ' computational'}] +``` +**top_k** 参数控制要显示的结果有多少种。请注意,这里模型填充了特殊的< **mask** >词,它通常被称为掩码标记。其他掩码填充模型可能有不同的掩码标记,因此在探索其他模型时要验证正确的掩码字是什么。检查它的一种方法是查看小组件中使用的掩码。 + + +✏️**快来试试吧!**在 Hub 上搜索基于 bert 的模型并在推理 API 小组件中找到它的掩码。这个模型对上面pipeline示例中的句子预测了什么? + + +## 命名实体识别 +命名实体识别 (NER) 是一项任务,其中模型必须找到输入文本的哪些部分对应于诸如人员、位置或组织之类的实体。让我们看一个例子: +```python +from transformers import pipeline + +ner = pipeline("ner", grouped_entities=True) +ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") +``` +```python out +[{'entity_group': 'PER', 'score': 0.99816, 'word': 'Sylvain', 'start': 11, 'end': 18}, + {'entity_group': 'ORG', 'score': 0.97960, 'word': 'Hugging Face', 'start': 33, 'end': 45}, + {'entity_group': 'LOC', 'score': 0.99321, 'word': 'Brooklyn', 'start': 49, 'end': 57} +] +``` +在这里,模型正确地识别出 Sylvain 是一个人 (PER),Hugging Face 是一个组织 (ORG),而布鲁克林是一个位置 (LOC)。 + +我们在pipeline创建函数中传递选项 **grouped_entities=True** 以告诉pipeline将对应于同一实体的句子部分重新组合在一起:这里模型正确地将“Hugging”和“Face”分组为一个组织,即使名称由多个词组成。事实上,正如我们即将在下一章看到的,预处理甚至会将一些单词分成更小的部分。例如,**Sylvain** 分割为了四部分:**S、##yl、##va** 和 **##in**。在后处理步骤中,pipeline成功地重新组合了这些部分。 + + +✏️**快来试试吧!**在模型中心(hub)搜索能够用英语进行词性标注(通常缩写为 POS)的模型。这个模型对上面例子中的句子预测了什么? + + +## 问答系统 +问答pipeline使用来自给定上下文的信息回答问题: +```python +from transformers import pipeline + +question_answerer = pipeline("question-answering") +question_answerer( + question="Where do I work?", + context="My name is Sylvain and I work at Hugging Face in Brooklyn", +) +``` +```python out +{'score': 0.6385916471481323, 'start': 33, 'end': 45, 'answer': 'Hugging Face'} +klyn", +) + +``` +请注意,此pipeline通过从提供的上下文中提取信息来工作;它不会凭空生成答案。 + +## 文本摘要 +文本摘要是将文本缩减为较短文本的任务,同时保留文本中的主要(重要)信息。下面是一个例子: + +```python +from transformers import pipeline + +summarizer = pipeline("summarization") +summarizer( + """ + America has changed dramatically during recent years. Not only has the number of + graduates in traditional engineering disciplines such as mechanical, civil, + electrical, chemical, and aeronautical engineering declined, but in most of + the premier American universities engineering curricula now concentrate on + and encourage largely the study of engineering science. As a result, there + are declining offerings in engineering subjects dealing with infrastructure, + the environment, and related issues, and greater concentration on high + technology subjects, largely supporting increasingly complex scientific + developments. While the latter is important, it should not be at the expense + of more traditional engineering. + + Rapidly developing economies such as China and India, as well as other + industrial countries in Europe and Asia, continue to encourage and advance + the teaching of engineering. Both China and India, respectively, graduate + six and eight times as many traditional engineers as does the United States. + Other industrial countries at minimum maintain their output, while America + suffers an increasingly serious decline in the number of engineering graduates + and a lack of well-educated engineers. +""" +) +``` +```python out +[{'summary_text': ' America has changed dramatically during recent years . The ' + 'number of engineering graduates in the U.S. has declined in ' + 'traditional engineering disciplines such as mechanical, civil ' + ', electrical, chemical, and aeronautical engineering . Rapidly ' + 'developing economies such as China and India, as well as other ' + 'industrial countries in Europe and Asia, continue to encourage ' + 'and advance engineering .'}] +``` +与文本生成一样,您指定结果的 **max_length** 或 **min_length**。 + +## 翻译 +对于翻译,如果您在任务名称中提供语言对(例如“**translation_en_to_fr**”),则可以使用默认模型,但最简单的方法是在[模型中心(hub)](https://huggingface.co/models)选择要使用的模型。在这里,我们将尝试从法语翻译成英语: + +```python +from transformers import pipeline + +translator = pipeline("translation", model="Helsinki-NLP/opus-mt-fr-en") +translator("Ce cours est produit par Hugging Face.") +``` +```python out +[{'translation_text': 'This course is produced by Hugging Face.'}] + +``` + +与文本生成和摘要一样,您可以指定结果的 **max_length** 或 **min_length**。 + + + +✏️**快来试试吧!**搜索其他语言的翻译模型,尝试将前一句翻译成几种不同的语言。 + + + +到目前为止显示的pipeline主要用于演示目的。它们是为特定任务而编程的,不能对他们进行自定义的修改。在下一章中,您将了解 **pipeline()** 函数内部的内容以及如何进行自定义的修改。 \ No newline at end of file diff --git a/chapters/zh/chapter1/4.mdx b/chapters/zh/chapter1/4.mdx new file mode 100644 index 000000000..45641e71e --- /dev/null +++ b/chapters/zh/chapter1/4.mdx @@ -0,0 +1,172 @@ +# Transformers 是如何工作的? + +在本节中,我们将深入了解 Transformer 模型的架构。 + +## 一点Transformers的发展历史 + +以下是 Transformer 模型(简短)历史中的一些关键节点: + +
+A brief chronology of Transformers models. + +
+ +[Transformer 架构](https://arxiv.org/abs/1706.03762) 于 2017 年 6 月推出。原本研究的重点是翻译任务。随后推出了几个有影响力的模型,包括 + +- **2018 年 6 月**: [GPT](https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf), 第一个预训练的 Transformer 模型,用于各种 NLP 任务并获得极好的结果 + +- **2018 年 10 月**: [BERT](https://arxiv.org/abs/1810.04805), 另一个大型预训练模型,该模型旨在生成更好的句子摘要(下一章将详细介绍!) + +- **2019 年 2 月**: [GPT-2](https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf), GPT 的改进(并且更大)版本,由于道德问题没有立即公开发布 + +- **2019 年 10 月**: [DistilBERT](https://arxiv.org/abs/1910.01108), BERT 的提炼版本,速度提高 60%,内存减轻 40%,但仍保留 BERT 97% 的性能 + +- **2019 年 10 月**: [BART](https://arxiv.org/abs/1910.13461) 和 [T5](https://arxiv.org/abs/1910.10683), 两个使用与原始 Transformer 模型相同架构的大型预训练模型(第一个这样做) + +- **2020 年 5 月**, [GPT-3](https://arxiv.org/abs/2005.14165), GPT-2 的更大版本,无需微调即可在各种任务上表现良好(称为零样本学习) + +这个列表并不全面,只是为了突出一些不同类型的 Transformer 模型。大体上,它们可以分为三类: + +- GPT-like (也被称作自回归Transformer模型) +- BERT-like (也被称作自动编码Transformer模型) +- BART/T5-like (也被称作序列到序列的 Transformer模型) + +稍后我们将更深入地探讨这些分类。 + +## Transformers是语言模型 + +上面提到的所有 Transformer 模型(GPT、BERT、BART、T5 等)都被训练为语言模型。这意味着他们已经以无监督学习的方式接受了大量原始文本的训练。无监督学习是一种训练类型,其中目标是根据模型的输入自动计算的。这意味着不需要人工来标记数据! + +这种类型的模型可以对其训练过的语言进行统计理解,但对于特定的实际任务并不是很有用。因此,一般的预训练模型会经历一个称为*迁移学习*的过程。在此过程中,模型在给定任务上以监督方式(即使用人工注释标签)进行微调。 + +任务的一个例子是阅读 *n* 个单词的句子,预测下一个单词。这被称为因果语言建模,因为输出取决于过去和现在的输入。 + +
+Example of causal language modeling in which the next word from a sentence is predicted. + +
+ +另一个例子是*遮罩语言建模*,该模型预测句子中的遮住的词。 + +
+Example of masked language modeling in which a masked word from a sentence is predicted. + +
+ +## Transformer是大模型 + +除了一些特例(如 DistilBERT)外,实现更好性能的一般策略是增加模型的大小以及预训练的数据量。 + +
+Number of parameters of recent Transformers models +
+ +不幸的是,训练模型,尤其是大型模型,需要大量的数据,时间和计算资源。它甚至会对环境产生影响,如下图所示。 + +
+The carbon footprint of a large language model. + +
+ + + +Transformers是由一个团队领导的(非常大的)模型项目,该团队试图减少预训练对环境的影响,通过运行大量试验以获得最佳超参数。 + +想象一下,如果每次一个研究团队、一个学生组织或一家公司想要训练一个模型,都从头开始训练的。这将导致巨大的、不必要的浪费! + +这就是为什么共享语言模型至关重要:共享经过训练的权重,当遇见新的需求时在预训练的权重之上进行微调,可以降低训练模型训练的算力和时间消耗,降低全球的总体计算成本和碳排放。 + + +## 迁移学习 + + + +*预训练是*训练模型前的一个操作:随机初始化权重,在没有任何先验知识的情况下开始训练。 + +
+The pretraining of a language model is costly in both time and money. + +
+ +这种预训练通常是在非常大量的数据上进行的。因此,它需要大量的数据,而且训练可能需要几周的时间。 + +另一方面,*微调*是在模型经过预训练后完成的训练。要执行微调,首先需要获取一个经过预训练的语言模型,然后使用特定于任务的数据集执行额外的训练。等等,为什么不直接为最后的任务而训练呢?有几个原因: + +* 预训练模型已经在与微调数据集有一些相似之处的数据集上进行了训练。因此,微调过程能够利用模型在预训练期间获得的知识(例如,对于NLP问题,预训练模型将对您在任务中使用的语言有某种统计规律上的理解)。 +* 由于预训练模型已经在大量数据上进行了训练,因此微调需要更少的数据来获得不错的结果。 +* 出于同样的原因,获得好结果所需的时间和资源要少得多 + +例如,可以利用英语的预训练过的模型,然后在arXiv语料库上对其进行微调,从而形成一个基于科学/研究的模型。微调只需要有限的数据量:预训练模型获得的知识可以“迁移”到目标任务上,因此被称为*迁移学习*。 + +
+The fine-tuning of a language model is cheaper than pretraining in both time and money. + +
+ +因此,微调模型具有较低的时间、数据、财务和环境成本。迭代不同的微调方案也更快、更容易,因为与完整的预训练相比,训练的约束更少。 + +这个过程也会比从头开始的训练(除非你有很多数据)取得更好的效果,这就是为什么你应该总是尝试利用一个预训练的模型--一个尽可能接近你手头的任务的模型--并对其进行微调。 + +## 一般的体系结构 +在这一部分,我们将介绍Transformer模型的一般架构。如果你不理解其中的一些概念,不要担心;下文将详细介绍每个组件。 + + + +## 介绍 + +该模型主要由两个块组成: + +* **Encoder (左侧)**: 编码器接收输入并构建其表示(其特征)。这意味着对模型进行了优化,以从输入中获得理解。 +* **Decoder (右侧)**: 解码器使用编码器的表示(特征)以及其他输入来生成目标序列。这意味着该模型已针对生成输出进行了优化。 + +
+Architecture of a Transformers models + +
+ +这些部件中的每一个都可以独立使用,具体取决于任务: + +* **Encoder-only models**: 适用于需要理解输入的任务,如句子分类和命名实体识别。 +* **Decoder-only models**: 适用于生成任务,如文本生成。 +* **Encoder-decoder models** 或者 **sequence-to-sequence models**: 适用于需要根据输入进行生成的任务,如翻译或摘要。 + +在后面的部分中,我们将单独地深入研究这些体系结构。 + +## 注意力层 + +Transformer模型的一个关键特性是*注意力层*。事实上,介绍Transformer架构的文章的标题是[“注意力就是你所需要的”](https://arxiv.org/abs/1706.03762)! 我们将在课程的后面更加深入地探索注意力层;现在,您需要知道的是,这一层将告诉模型在处理每个单词的表示时,要特别重视您传递给它的句子中的某些单词(并且或多或少地忽略其他单词)。 + +把它放在语境中,考虑将文本从英语翻译成法语的任务。在输入“You like this course”的情况下,翻译模型还需要注意相邻的单词“You”,以获得单词“like”的正确翻译,因为在法语中,动词“like”的变化取决于主题。然而,句子的其余部分对于该词的翻译没有用处。同样,在翻译“this”时,模型也需要注意“course”一词,因为“this”的翻译不同,取决于相关名词是单数还是复数。同样,句子中的其他单词对于“this”的翻译也不重要。对于更复杂的句子(以及更复杂的语法规则),模型需要特别注意可能出现在句子中更远位置的单词,以便正确地翻译每个单词。 + +同样的概念也适用于与自然语言相关的任何任务:一个词本身有一个含义,但这个含义受语境的影响很大,语境可以是研究该词之前或之后的任何其他词(或多个词)。 + +现在您已经了解了注意力层的含义,让我们更仔细地了解Transformer架构。 + +## 原始的结构 + +Transformer架构最初是为翻译而设计的。在训练期间,编码器接收特定语言的输入(句子),而解码器需要输出对应语言的翻译。在编码器中,注意力层可以使用一个句子中的所有单词(正如我们刚才看到的,给定单词的翻译可以取决于它在句子中的其他单词)。然而,解码器是按顺序工作的,并且只能注意它已经翻译过的句子中的单词。例如,当我们预测了翻译目标的前三个单词时,我们将它们提供给解码器,然后解码器使用编码器的所有输入来尝试预测第四个单词。 + +为了在训练过程中加快速度(当模型可以访问目标句子时),解码器会被输入整个目标,但不允许获取到要翻译的单词(如果它在尝试预测位置2的单词时可以访问位置2的单词,解码器就会偷懒,直接输出那个单词,从而无法学习到正确的语言关系!)。例如,当试图预测第4个单词时,注意力层只能获取位置1到3的单词。 + +最初的Transformer架构如下所示,编码器位于左侧,解码器位于右侧: + +
+Architecture of a Transformers models + +
+ +注意,解码器块中的第一个注意力层关联到解码器的所有(过去的)输入,但是第二注意力层使用编码器的输出。因此,它可以访问整个输入句子,以最好地预测当前单词。这是非常有用的,因为不同的语言可以有语法规则将单词按不同的顺序排列,或者句子后面提供的一些上下文可能有助于确定给定单词的最佳翻译。 + +也可以在编码器/解码器中使用*注意力遮罩层*,以防止模型注意某些特殊单词。例如,在批处理句子时,填充特殊词使所有句子的长度一致。 + +## 架构与参数 + +在本课程中,当我们深入探讨Transformers模型时,您将看到 +架构、参数和模型 +。 这些术语的含义略有不同: + +* **架构**: 这是模型的骨架 -- 每个层的定义以及模型中发生的每个操作。 +* **Checkpoints**: 这些是将在给架构中结构中加载的权重。 +* **模型**: 这是一个笼统的术语,没有“架构”或“参数”那么精确:它可以指两者。为了避免歧义,本课程使用将使用架构和参数。 + +例如,BERT是一个架构,而 `bert-base-cased`, 这是谷歌团队为BERT的第一个版本训练的一组权重参数,是一个参数。我们可以说“BERT模型”和"`bert-base-cased`模型." diff --git a/chapters/zh/chapter1/5.mdx b/chapters/zh/chapter1/5.mdx new file mode 100644 index 000000000..7aa765ec2 --- /dev/null +++ b/chapters/zh/chapter1/5.mdx @@ -0,0 +1,17 @@ +# “编码器”模型 + + + +“编码器”模型指仅使用编码器的Transformer模型。在每个阶段,注意力层都可以获取初始句子中的所有单词。这些模型通常具有“双向”注意力,被称为自编码模型。 + +这些模型的预训练通常围绕着以某种方式破坏给定的句子(例如:通过随机遮盖其中的单词),并让模型寻找或重建给定的句子。 + +“编码器”模型最适合于需要理解完整句子的任务,例如:句子分类、命名实体识别(以及更普遍的单词分类)和阅读理解后回答问题。 + +该系列模型的典型代表有: + +- [ALBERT](https://huggingface.co/transformers/model_doc/albert.html) +- [BERT](https://huggingface.co/transformers/model_doc/bert.html) +- [DistilBERT](https://huggingface.co/transformers/model_doc/distilbert.html) +- [ELECTRA](https://huggingface.co/transformers/model_doc/electra.html) +- [RoBERTa](https://huggingface.co/transformers/model_doc/roberta.html) diff --git a/chapters/zh/chapter1/6.mdx b/chapters/zh/chapter1/6.mdx new file mode 100644 index 000000000..2de4c44a6 --- /dev/null +++ b/chapters/zh/chapter1/6.mdx @@ -0,0 +1,17 @@ +# “解码器”模型 + + + +“解码器”模型通常指仅使用解码器的Transformer模型。在每个阶段,对于给定的单词,注意力层只能获取到句子中位于将要预测单词前面的单词。这些模型通常被称为自回归模型。 + +“解码器”模型的预训练通常围绕预测句子中的下一个单词进行。 + +这些模型最适合于涉及文本生成的任务。 + +该系列模型的典型代表有: + + +- [CTRL](https://huggingface.co/transformers/model_doc/ctrl.html) +- [GPT](https://huggingface.co/transformers/model_doc/gpt.html) +- [GPT-2](https://huggingface.co/transformers/model_doc/gpt2.html) +- [Transformer XL](https://huggingface.co/transformers/model_doc/transformerxl.html) diff --git a/chapters/zh/chapter1/7.mdx b/chapters/zh/chapter1/7.mdx new file mode 100644 index 000000000..99dc00eea --- /dev/null +++ b/chapters/zh/chapter1/7.mdx @@ -0,0 +1,16 @@ +# 序列到序列模型 + + + +编码器-解码器模型(也称为序列到序列模型)同时使用Transformer架构的编码器和解码器两个部分。在每个阶段,编码器的注意力层可以访问初始句子中的所有单词,而解码器的注意力层只能访问位于输入中将要预测单词前面的单词。 + +这些模型的预训练可以使用训练编码器或解码器模型的方式来完成,但通常涉及更复杂的内容。例如,[T5](https://huggingface.co/t5-base)通过将文本的随机跨度(可以包含多个单词)替换为单个特殊单词来进行预训练,然后目标是预测该掩码单词替换的文本。 + +序列到序列模型最适合于围绕根据给定输入生成新句子的任务,如摘要、翻译或生成性问答。 + +该系列模型的典型代表有: + +- [BART](https://huggingface.co/transformers/model_doc/bart.html) +- [mBART](https://huggingface.co/transformers/model_doc/mbart.html) +- [Marian](https://huggingface.co/transformers/model_doc/marian.html) +- [T5](https://huggingface.co/transformers/model_doc/t5.html) diff --git a/chapters/zh/chapter1/8.mdx b/chapters/zh/chapter1/8.mdx new file mode 100644 index 000000000..707731892 --- /dev/null +++ b/chapters/zh/chapter1/8.mdx @@ -0,0 +1,31 @@ +# Bias and limitations + + + +如果您打算在正式的项目中使用经过预训练或经过微调的模型。请注意:虽然这些模型是很强大,但它们也有局限性。其中最大的一个问题是,为了对大量数据进行预训练,研究人员通常会搜集所有他们能找到的内容,中间可能夹带一些意识形态或者价值观的刻板印象。 + +为了快速解释清楚这个问题,让我们回到一个使用BERT模型的pipeline的例子: + +```python +from transformers import pipeline + +unmasker = pipeline("fill-mask", model="bert-base-uncased") +result = unmasker("This man works as a [MASK].") +print([r["token_str"] for r in result]) + +result = unmasker("This woman works as a [MASK].") +print([r["token_str"] for r in result]) +``` + +```python out +['lawyer', 'carpenter', 'doctor', 'waiter', 'mechanic'] +['nurse', 'waitress', 'teacher', 'maid', 'prostitute'] +``` +当要求模型填写这两句话中缺少的单词时,模型给出的答案中,只有一个与性别无关(服务员/女服务员)。其他职业通常与某一特定性别相关,妓女最终进入了模型中与“女人”和“工作”相关的前五位。尽管BERT是使用经过筛选和清洗后,明显中立的数据集上建立的的Transformer模型,而不是通过从互联网上搜集数据(它是在[Wikipedia 英文](https://huggingface.co/datasets/wikipedia)和[BookCorpus](https://huggingface.co/datasets/bookcorpus)数据集)。 + +因此,当您使用这些工具时,您需要记住,使用的原始模型的时候,很容易生成性别歧视、种族主义或恐同内容。这种固有偏见不会随着微调模型而使消失。 \ No newline at end of file diff --git a/chapters/zh/chapter1/9.mdx b/chapters/zh/chapter1/9.mdx new file mode 100644 index 000000000..16c5ab6ad --- /dev/null +++ b/chapters/zh/chapter1/9.mdx @@ -0,0 +1,11 @@ +# 总结 + +在本章中,您了解了如何使用来自🤗Transformers的函数pipeline()处理不同的NLP任务。您还了解了如何在模型中心(hub)中搜索和使用模型,以及如何使用推理API直接在浏览器中测试模型。 + +我们讨论了Transformer模型如何在应用层上工作,并讨论了迁移学习和微调的重要性。您可以使用完整的体系结构,也可以仅使用编码器或解码器,具体取决于您要解决的任务类型。下表总结了这一点: + +| 模型 | 示例 | 任务| +| ---- | ---- |----| +| 编码器 | ALBERT, BERT, DistilBERT, ELECTRA, RoBERTa |句子分类、命名实体识别、从文本中提取答案| +| 解码器 | CTRL, GPT, GPT-2, Transformer XL |文本生成| +| 编码器-解码器 | BART, T5, Marian, mBART |文本摘要、翻译、生成问题的回答| \ No newline at end of file From 1d1a7a56369728665c7980c6c2cfd01e83bba143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gustavo=20A=2E=20Amorim?= Date: Wed, 13 Apr 2022 10:57:07 -0300 Subject: [PATCH 70/73] [PT] Translation of chapter 2 (#107) * add PT translate to 2.1 * add PT translate to 2.2 * add portuguese translation to 2.3 * WIP portuguese translation to 2.4 * add portuguese translation to 2.4 * add portuguese translation to 2.5 * add portuguese translation to 2.6 * add _toctree infos Co-authored-by: lewtun --- chapters/pt/_toctree.yml | 19 ++ chapters/pt/chapter2/1.mdx | 20 +++ chapters/pt/chapter2/2.mdx | 354 +++++++++++++++++++++++++++++++++++++ chapters/pt/chapter2/3.mdx | 229 ++++++++++++++++++++++++ chapters/pt/chapter2/4.mdx | 248 ++++++++++++++++++++++++++ chapters/pt/chapter2/5.mdx | 340 +++++++++++++++++++++++++++++++++++ chapters/pt/chapter2/6.mdx | 167 +++++++++++++++++ chapters/pt/chapter2/7.mdx | 13 ++ chapters/pt/chapter2/8.mdx | 305 ++++++++++++++++++++++++++++++++ 9 files changed, 1695 insertions(+) create mode 100644 chapters/pt/chapter2/1.mdx create mode 100644 chapters/pt/chapter2/2.mdx create mode 100644 chapters/pt/chapter2/3.mdx create mode 100644 chapters/pt/chapter2/4.mdx create mode 100644 chapters/pt/chapter2/5.mdx create mode 100644 chapters/pt/chapter2/6.mdx create mode 100644 chapters/pt/chapter2/7.mdx create mode 100644 chapters/pt/chapter2/8.mdx diff --git a/chapters/pt/_toctree.yml b/chapters/pt/_toctree.yml index 00b2efaf4..dd1bb1a5f 100644 --- a/chapters/pt/_toctree.yml +++ b/chapters/pt/_toctree.yml @@ -2,3 +2,22 @@ sections: - local: chapter0/1 title: Introdução +- title: 2. Usando 🤗 Transformers + sections: + - local: chapter2/1 + title: Introdução + - local: chapter2/2 + title: Por dentro da função pipeline + - local: chapter2/3 + title: Modelos + - local: chapter2/4 + title: Tokenizers + - local: chapter2/5 + title: Tratando sequências múltiplas + - local: chapter2/6 + title: Colocando tudo junto + - local: chapter2/7 + title: Uso básico concluído! + - local: chapter2/8 + title: Questionário de fim de capítulo + quiz: 2 diff --git a/chapters/pt/chapter2/1.mdx b/chapters/pt/chapter2/1.mdx new file mode 100644 index 000000000..4bc8850d5 --- /dev/null +++ b/chapters/pt/chapter2/1.mdx @@ -0,0 +1,20 @@ +# Introdução + +Como você viu no [Capitulo 1](/course/pt/chapter1), normalmente modelos Transformers são muito grandes. Com milhões a dezenas de *bilhões* de parâmetros, o treinamento e o deploy destes modelos é uma tarefa complicado. Além disso, com novos modelos sendo lançados quase diariamente e cada um tendo sua própria implementação, experimentá-los a todos não é tarefa fácil. + +A biblioteca 🤗 Transformers foi criado para resolver este problema. Seu objetivo é fornecer uma API única através do qual qualquer modelo Transformer possa ser carregado, treinado e salvo. As principais características da biblioteca são: + +- **Fácil de usar**: Baixar, carregar e usar um modelo de processamento natural de linguagem (PNL) de última geração para inferência pode ser feito em apenas duas linhas de código +- **Flexibilidade**: Em sua essência, todos os modelos são uma simples classe PyTorch `nn.Module` ou TensorFlow `tf.keras.Model` e podem ser tratadas como qualquer outro modelo em seus respectivos frameworks de machine learning (ML). +- **Simplicidade**: Quase nenhuma abstração é feita em toda a biblioteca. O "Tudo em um arquivo" é um conceito principal: o "passe para frente" de um modelo é inteiramente definido em um único arquivo, de modo que o código em si seja compreensível e hackeável. + +Esta última característica torna 🤗 Transformers bem diferente de outras bibliotecas ML que modelos e/ou configurações são compartilhados entre arquivos; em vez disso, cada modelo tem suas próprias camadas. Além de tornar os modelos mais acessíveis e compreensíveis, isto permite que você experimente facilmente um modelo sem afetar outros. + +Este capítulo começará com um exemplo de ponta a ponta onde usamos um modelo e um tokenizer juntos para replicar a função `pipeline()` introduzida no [Capitulo 1](/course/pt/chapter1). A seguir, discutiremos o modelo da API: onde veremos profundamente as classes de modelo e configuração, além de mostrar como carregar um modelo e como ele processa as entradas numéricas para as previsões de saída. + +Depois veremos a API do tokenizer, que é o outro componente principal da função `pipeline()`. Os Tokenizers cuidam da primeira e da última etapa do processamento, cuidando da conversão de texto para entradas numéricas para a rede neural, e da conversão de volta ao texto quando for necessário. Por fim, mostraremos a você como lidar com o envio de várias frases através de um modelo em um batch preparado, depois olharemos tudo mais atentamente a função de alto nível `tokenizer()`. + + + +⚠️ Para beneficiar-se de todos os recursos disponíveis com o Model Hub e 🤗 Transformers, recomendamos criar uma conta. + \ No newline at end of file diff --git a/chapters/pt/chapter2/2.mdx b/chapters/pt/chapter2/2.mdx new file mode 100644 index 000000000..88c9a068e --- /dev/null +++ b/chapters/pt/chapter2/2.mdx @@ -0,0 +1,354 @@ + + +# Por dentro da função pipeline + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + + +Esta é a primeira seção onde o conteúdo é ligeiramente diferente, dependendo se você usa PyTorch e TensorFlow. Para selecionar a plataforma que você prefere, basta alterar no botão no topo. + + +{#if fw === 'pt'} + +{:else} + +{/if} + +Vamos começar com um exemplo completo, dando uma olhada no que acontece dentro da função quando executamos o seguinte código no [Capítulo 1](/course/pt/chapter1): + +```python +from transformers import pipeline + +classifier = pipeline("sentiment-analysis") +classifier( + [ + "I've been waiting for a HuggingFace course my whole life.", + "I hate this so much!", + ] +) +``` + +tendo o resultado: + +```python out +[{'label': 'POSITIVE', 'score': 0.9598047137260437}, + {'label': 'NEGATIVE', 'score': 0.9994558095932007}] +``` + +Como visto no [Capítulo 1](/course/pt/chapter1), este pipeline agrupa os três passos: o pré-processamento, passagem das entradas através do modelo, e o pós-processamento: + +
+O pipeline NLP completa: tokenização do texto, conversão para IDs, e inferência através do Transformer e pela 'cabeça' do modelo. + +
+ +Vamos rever rapidamente cada um deles. + +## Pré-processamento com o tokenizer + +Como outras redes neurais, os Transformers não podem processar texto bruto diretamente, portanto, o primeiro passo do nosso pipeline é converter as entradas de texto em números que o modelo possa fazer sentido. Para fazer isso, usamos um *tokenizer*, que será responsável por: + +- Dividir a entrada em palavras, sub-palavras ou símbolos (como pontuação) que são chamados de *tokens*. +- Mapeando cada ficha para um número inteiro +- Adicionando entradas adicionais que podem ser úteis ao modelo + +Todo esse pré-processamento precisa ser feito exatamente da mesma forma que quando o modelo foi pré-treinado, então precisamos primeiro baixar essas informações do [Model Hub](https://huggingface.co/models). Para isso, utilizamos a classe `AutoTokenizer` e seu método `from_pretrained()`. Utilizando o nome do ponto de verificação de nosso modelo, ele irá buscar automaticamente os dados associados ao tokenizer do modelo e armazená-los em cache (portanto, ele só é baixado na primeira vez que você executar o código abaixo). + +Desde que o checkpoint default do pipeline `sentiment-analysis` é `distilbert-base-uncased-finetuned-sst-2-english` (você pode ver o card do modelo [aqui](https://huggingface.co/distilbert-base-uncased-finetuned-sst-2-english)), então executamos o seguinte: + +```python +from transformers import AutoTokenizer + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +``` + +Assim que tivermos o tokenizer, podemos passar diretamente nossas frases para ele e receberemos de volta um dicionário que está pronto para alimentar nosso modelo! A única coisa que falta fazer é converter a lista de identificações de entrada em tensores. + +Você pode usar 🤗 Transformers sem ter que se preocupar com qual estrutura ML é usada como backend; pode ser PyTorch ou TensorFlow, ou Flax para alguns modelos. Entretanto, os Transformers só aceitam *tensores* como entrada. Se esta é a primeira vez que você ouve falar de tensores, você pode pensar neles como matrizes da NumPy. Uma matriz NumPy pode ser um escalar (0D), um vetor (1D), uma matriz (2D), ou ter mais dimensões. É efetivamente um tensor; os tensores de outras estruturas ML comportam-se de forma semelhante, e geralmente são tão simples de instanciar como os arrays da NumPy. + +Para especificar o tipo de tensores que queremos recuperar (PyTorch, TensorFlow ou NumPy), utilizamos o argumento `return_tensors`: + +{#if fw === 'pt'} +```python +raw_inputs = [ + "I've been waiting for a HuggingFace course my whole life.", + "I hate this so much!", +] +inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="pt") +print(inputs) +``` +{:else} +```python +raw_inputs = [ + "I've been waiting for a HuggingFace course my whole life.", + "I hate this so much!", +] +inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="tf") +print(inputs) +``` +{/if} + +Não se preocupe ainda com o truncamento e o padding; explicaremos isso mais tarde. As principais coisas a lembrar aqui são que você pode passar uma frase ou uma lista de frases, bem como especificar o tipo de tensores que você quer recuperar (se nenhum tipo for passado, você receberá uma lista de listas como resultado). + +{#if fw === 'pt'} + +Eis como são os resultados como tensores PyTorch: + +```python out +{ + 'input_ids': tensor([ + [ 101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102], + [ 101, 1045, 5223, 2023, 2061, 2172, 999, 102, 0, 0, 0, 0, 0, 0, 0, 0] + ]), + 'attention_mask': tensor([ + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ]) +} +``` +{:else} + +Eis como são os resultados como tensores TensorFlow: + +```python out +{ + 'input_ids': , + 'attention_mask': +} +``` +{/if} + +A saída em si é um dicionário contendo duas chaves, `input_ids' e `attention_mask'. O `input_ids' contém duas linhas de inteiros (uma para cada frase) que são os identificadores únicos dos tokens em cada frase. Explicaremos o que é a "máscara de atenção" (attention mask) mais adiante neste capítulo. + +## Indo adianta pelo modelo + +{#if fw === 'pt'} +Podemos baixar nosso modelo pré-treinado da mesma forma que fizemos com nosso tokenizer. 🤗 Transformers fornece uma classe `AutoModel` que também tem um método `from_pretrained()`: + +```python +from transformers import AutoModel + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = AutoModel.from_pretrained(checkpoint) +``` +{:else} +Podemos baixar nosso modelo pré-treinado da mesma forma que fizemos com nosso tokenizer. 🤗 Transformers fornece uma classe "TFAutoModel" que também tem um método "from_pretrained": + + +```python +from transformers import TFAutoModel + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = TFAutoModel.from_pretrained(checkpoint) +``` +{/if} + +Neste trecho de código, fizemos o download do mesmo checkpoint que usamos anteriormente em nosso pipeline (já deveria estar em cache) e instanciamos um modelo com ele. + +Esta arquitetura contém apenas o módulo base do Transformer: dadas algumas entradas, ele produz o que chamaremos de *hidden states* (estados ocultos), também conhecidos como *features* (características). Para cada modelo de entrada, recuperaremos um vetor de alta dimensionalidade representando a **compreensão contextual dessa entrada pelo Transformer***. + +Se isto não faz sentido, não se preocupe com isso. Explicaremos tudo isso mais tarde. + +Embora estes hidden states possam ser úteis por si mesmos, eles geralmente são entradas para outra parte do modelo, conhecida como *head* (cabeça). No [Capítulo 1](/course/pt/chapter1), as diferentes tarefas poderiam ter sido realizadas com a mesma arquitetura, mas cada uma destas tarefas teria uma head diferente associada a ela. + +### Um vetor de alta dimensionalidade? + +A saída vetorial pelo módulo do Transformer é geralmente grande. Geralmente tem três dimensões: + +- **Tamanho do lote** (Batch size): O número de sequências processadas de cada vez (2 em nosso exemplo). +- **Tamanho da sequencia** (Sequence length): O comprimento da representação numérica da sequência (16 em nosso exemplo). +- **Tamanho oculto** (Hidden size): A dimensão vetorial de cada modelo de entrada. + +Diz-se que é "de alta dimensionalidade" por causa do último valor. O tamanho oculto pode ser muito grande (768 é comum para modelos menores, e em modelos maiores isto pode chegar a 3072 ou mais). + +Podemos ver isso se alimentarmos os inputs que pré-processamos para nosso modelo: + +{#if fw === 'pt'} +```python +outputs = model(**inputs) +print(outputs.last_hidden_state.shape) +``` + +```python out +torch.Size([2, 16, 768]) +``` +{:else} +```py +outputs = model(inputs) +print(outputs.last_hidden_state.shape) +``` + +```python out +(2, 16, 768) +``` +{/if} + +Observe que as saídas dos 🤗 Transformer se comportam como 'tuplas nomeadas' (namedtuple) ou dicionários. Você pode acessar os elementos por atributos (como fizemos) ou por chave (`outputs["last_hidden_state"]`), ou mesmo por índice se você souber exatamente onde o que está procurando (`outputs[0]`). + +### Cabeça do modelo (model heads): Fazendo sentido a partir dos números + +As *heads* do modelo usam o vetor de alta dimensionalidade dos hidden states como entrada e os projetam em uma dimensão diferente. Eles são geralmente compostos de uma ou algumas camadas lineares: + +
+Uma rede Transformer ao lado de sua head. + +
+ +A saída do Transformer é enviada diretamente para a *head* do modelo a ser processado. + +Neste diagrama, o modelo é representado por sua camada de embeddings (vetores) e pelas camadas subsequentes. A camada de embeddings converte cada ID de entrada na entrada tokenizada em um vetor que representa o token associado. As camadas subsequentes manipulam esses vetores usando o mecanismo de atenção para produzir a representação final das sentenças. + +Há muitas arquiteturas diferentes disponíveis no 🤗 Transformers, com cada uma projetada em torno de uma tarefa específica. Aqui está uma lista por **algumas** destas tarefas: + +- `*Model` (recuperar os hidden states) +- `*ForCausalLM` +- `*ForMaskedLM` +- `*ForMultipleChoice` +- `*ForQuestionAnswering` +- `*ForSequenceClassification` +- `*ForTokenClassification` +- e outros 🤗 + +{#if fw === 'pt'} +Para nosso exemplo, precisaremos de um modelo com uma *head* de classificação em sequencia (para poder classificar as sentenças como positivas ou negativas). Portanto, não utilizaremos a classe `AutoModel`, mas sim, a classe `AutoModelForSequenceClassification`: + +```python +from transformers import AutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) +outputs = model(**inputs) +``` +{:else} +Para nosso exemplo, precisaremos de um modelo com uma *head* de classificação em sequencia (para poder classificar as sentenças como positivas ou negativas). Portanto, não utilizaremos a classe `TFAutoModel`, mas sim, a classe `TFAutoModelForSequenceClassification`: + +```python +from transformers import TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) +outputs = model(inputs) +``` +{/if} + +Agora se observarmos o tamanho dos nossos inputs, a dimensionalidade será muito menor: a *head* do modelo toma como entrada os vetores de alta dimensionalidade que vimos anteriormente, e os vetores de saída contendo dois valores (um por label): + +```python +print(outputs.logits.shape) +``` + +{#if fw === 'pt'} +```python out +torch.Size([2, 2]) +``` +{:else} +```python out +(2, 2) +``` +{/if} + +Como temos apenas duas sentenças e duas labels, o resultado que obtemos de nosso modelo é de tamanho 2 x 2. + +## Pós-processamento da saída + +Os valores que obtemos como resultado de nosso modelo não fazem necessariamente sentido sozinhos. Vamos dar uma olhada: + +```python +print(outputs.logits) +``` + +{#if fw === 'pt'} +```python out +tensor([[-1.5607, 1.6123], + [ 4.1692, -3.3464]], grad_fn=) +``` +{:else} +```python out + +``` +{/if} + +Nosso modelo previu `[-1.5607, 1.6123]` para a primeira frase e `[ 4.1692, -3.3464]` para a segunda. Essas não são probabilidades, mas *logits*, a pontuação bruta e não normalizada produzida pela última camada do modelo. Para serem convertidos em probabilidades, eles precisam passar por uma camada [SoftMax](https://en.wikipedia.org/wiki/Softmax_function) (todas saídas dos 🤗 Transformers produzem *logits*, já que a função de *loss* (perda) para treinamento geralmente fundirá a última função de ativação, como SoftMax, com a função de *loss* real, por exemplo a *cross entropy*): + +{#if fw === 'pt'} +```py +import torch + +predictions = torch.nn.functional.softmax(outputs.logits, dim=-1) +print(predictions) +``` +{:else} +```py +import tensorflow as tf + +predictions = tf.math.softmax(outputs.logits, axis=-1) +print(predictions) +``` +{/if} + +{#if fw === 'pt'} +```python out +tensor([[4.0195e-02, 9.5980e-01], + [9.9946e-01, 5.4418e-04]], grad_fn=) +``` +{:else} +```python out +tf.Tensor( +[[4.01951671e-02 9.59804833e-01] + [9.9945587e-01 5.4418424e-04]], shape=(2, 2), dtype=float32) +``` +{/if} + +Agora podemos ver que o modelo previu `[0.0402, 0.9598]` para a primeira frase e `[0.9995, 0.0005]` para a segunda. Estas são pontuações de probabilidade reconhecíveis. + +Para obter as etiquetas correspondentes a cada posição, podemos inspecionar o atributo `id2label` da configuração do modelo (mais sobre isso na próxima seção): + +```python +model.config.id2label +``` + +```python out +{0: 'NEGATIVE', 1: 'POSITIVE'} +``` + +Agora podemos concluir que o modelo previu o seguinte: + +- A primeira frase: NEGATIVE: 0.0402, POSITIVE: 0.9598 +- Segunda frase: NEGATIVE: 0.9995, POSITIVE: 0.0005 + +Reproduzimos com sucesso as três etapas do pipeline: o pré-processamento, passagem das entradas através do modelo, e o pós-processamento! Agora, vamos levar algum tempo para mergulhar mais fundo em cada uma dessas etapas. + + + +✏️ **Experimente!** Escolha duas (ou mais) textos próprios e passe-os através do pipeline `sentiment-analysis`. Em seguida, replique as etapas que você mesmo viu aqui e verifique se você obtém os mesmos resultados! + + diff --git a/chapters/pt/chapter2/3.mdx b/chapters/pt/chapter2/3.mdx new file mode 100644 index 000000000..634cc3a6e --- /dev/null +++ b/chapters/pt/chapter2/3.mdx @@ -0,0 +1,229 @@ + + +# Modelos + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +{#if fw === 'pt'} + +{:else} + +{/if} + +{#if fw === 'pt'} +Nesta seção, vamos analisar mais de perto a criação e a utilização de um modelo. Vamos utilizar a classe `AutoModel`, que é útil quando você quer instanciar qualquer modelo a partir de um checkpoint. + +A classe `AutoModel` e todas as classes filhas são na verdade simples wrapper sobre a grande variedade de modelos disponíveis na biblioteca. É um wrapper inteligente, pois pode automaticamente "adivinhar" a arquitetura apropriada do modelo para seu checkpoint, e então instancia um modelo com esta arquitetura. + +{:else} +Nesta seção, vamos analisar mais de perto a criação e a utilização de um modelo. Vamos utilizar a classe `TFAutoModel`, que é útil quando você quer instanciar qualquer modelo a partir de um checkpoint. + +A classe `TFAutoModel` e todas as classes filhas são na verdade simples wrapper sobre a grande variedade de modelos disponíveis na biblioteca. É um wrapper inteligente, pois pode automaticamente "adivinhar" a arquitetura apropriada do modelo para seu checkpoint, e então instancia um modelo com esta arquitetura. + +{/if} + +Entretanto, se você conhece o tipo de modelo que deseja usar, pode usar diretamente a classe que define sua arquitetura. Vamos dar uma olhada em como isto funciona com um modelo BERT. + +## Criando um Transformer + +A primeira coisa que precisamos fazer para inicializar um modelo BERT é carregar um objeto de configuração: + +{#if fw === 'pt'} +```py +from transformers import BertConfig, BertModel + +# Construindo a configuração +config = BertConfig() + +# Construindo o modelo a partir da configuração +model = BertModel(config) +``` +{:else} +```py +from transformers import BertConfig, TFBertModel + +# Construindo a configuração +config = BertConfig() + +# Construindo o modelo a partir da configuração +model = TFBertModel(config) +``` +{/if} + +A configuração contém muitos atributos que são usados para construir o modelo: + +```py +print(config) +``` + +```python out +BertConfig { + [...] + "hidden_size": 768, + "intermediate_size": 3072, + "max_position_embeddings": 512, + "num_attention_heads": 12, + "num_hidden_layers": 12, + [...] +} +``` + +Embora você ainda não tenha visto o que todos esses atributos fazem, você deve reconhecer alguns deles: o atributo `hidden_size` define o tamanho do vetor `hidden_states`, e o `num_hidden_layers` define o número de camadas que o Transformer possui. + + +### Diferentes métodos de inicializar o modelo + +A criação de um modelo a partir da configuração padrão o inicializa com valores aleatórios: + +{#if fw === 'pt'} +```py +from transformers import BertConfig, BertModel + +config = BertConfig() +model = BertModel(config) + +# O modelo é inicializado aleatoriamente! +``` +{:else} +```py +from transformers import BertConfig, TFBertModel + +config = BertConfig() +model = TFBertModel(config) + +# O modelo é inicializado aleatoriamente! +``` +{/if} + +O modelo pode ser utilizado neste estado, mas produzirá saídas errôneas; ele precisa ser treinado primeiro. Poderíamos treinar o modelo a partir do zero na tarefa em mãos, mas como você viu em [Capítulo 1](/course/pt/chapter1), isto exigiria muito tempo e muitos dados, e teria um impacto ambiental não negligenciável. Para evitar esforços desnecessários e duplicados, normalmente é possível compartilhar e reutilizar modelos que já foram treinados. + +Carregar um Transformer já treinado é simples - podemos fazer isso utilizando o método `from_pretrained()`: + +{#if fw === 'pt'} +```py +from transformers import BertModel + +model = BertModel.from_pretrained("bert-base-cased") +``` + +Como você viu anteriormente, poderíamos substituir o `BertModel` pela classe equivalente ao `AutoModel`. Faremos isto de agora em diante, pois isto produz um código generalista a partir de um checkpoint; se seu código funciona para checkpoint, ele deve funcionar perfeitamente com outro. Isto se aplica mesmo que a arquitetura seja diferente, desde que o checkpoint tenha sido treinado para uma tarefa semelhante (por exemplo, uma tarefa de análise de sentimento). + +{:else} +```py +from transformers import TFBertModel + +model = TFBertModel.from_pretrained("bert-base-cased") +``` + +Como você viu anteriormente, poderíamos substituir o `TFBertModel` pela classe equivalente ao `TFAutoModel`. Faremos isto de agora em diante, pois isto produz um código generalista a partir de um checkpoint; se seu código funciona para checkpoint, ele deve funcionar perfeitamente com outro. Isto se aplica mesmo que a arquitetura seja diferente, desde que o checkpoint tenha sido treinado para uma tarefa semelhante (por exemplo, uma tarefa de análise de sentimento). + + +{/if} + +No exemplo de código acima não utilizamos `BertConfig`, e em vez disso carregamos um modelo pré-treinado através do identificador `bert-base-cased`. Este é um checkpoint do modelo que foi treinado pelos próprios autores do BERT; você pode encontrar mais detalhes sobre ele em seu [model card](https://huggingface.co/bert-base-cased). + +Este modelo agora é inicializado com todos os pesos do checkpoint. Ele pode ser usado diretamente para inferência sobre as tarefas nas quais foi treinado, e também pode ser *fine-tuned* (aperfeiçoado) em uma nova tarefa. Treinando com pesos pré-treinados e não do zero, podemos rapidamente alcançar bons resultados. + +Os pesos foram baixados e armazenados em cache (logo, para as futuras chamadas do método `from_pretrained()` não será realizado o download novamente) em sua respectiva pasta, que tem como padrão o path *~/.cache/huggingface/transformers*. Você pode personalizar sua pasta de cache definindo a variável de ambiente `HF_HOME`. + +O identificador usado para carregar o modelo pode ser o identificador de qualquer modelo no Model Hub, desde que seja compatível com a arquitetura BERT. A lista completa dos checkpoints BERT disponíveis podem ser encontrada [aqui].https://huggingface.co/models?filter=bert). + +### Métodos para salvar/armazenar o modelo + +Salvar um modelo é tão fácil quanto carregar um - utilizamos o método `save_pretrained()`, que é análogo ao método `from_pretrained()`: + +```py +model.save_pretrained("path_no_seu_computador") +``` + +Isto salva dois arquivos em seu disco: + +{#if fw === 'pt'} +``` +ls path_no_seu_computador + +config.json pytorch_model.bin +``` +{:else} +``` +ls path_no_seu_computador + +config.json tf_model.h5 +``` +{/if} + +Se você der uma olhada no arquivo *config.json*, você reconhecerá os atributos necessários para construir a arquitetura modelo. Este arquivo também contém alguns metadados, como a origem do checkpoint e a versão 🤗 Transformers que você estava usando quando salvou o checkpoint pela última vez. + +{#if fw === 'pt'} +O arquivo *pytorch_model.bin* é conhecido como o *dicionário de estado*; ele contém todos os pesos do seu modelo. Os dois arquivos andam de mãos dadas; a configuração é necessária para conhecer a arquitetura de seu modelo, enquanto os pesos do modelo são os parâmetros de seu modelo. + +{:else} +O arquivo *tf_model.h5* é conhecido como o *dicionário de estado*; ele contém todos os pesos do seu modelo. Os dois arquivos andam de mãos dadas; a configuração é necessária para conhecer a arquitetura de seu modelo, enquanto os pesos do modelo são os parâmetros de seu modelo. + +{/if} + +## Usando um modelo de Transformer para inferência + +Agora que você sabe como carregar e salvar um modelo, vamos tentar usá-lo para fazer algumas predições. Os Transformers só podem processar números - números que o tokenizer gera. Mas antes de discutirmos os tokenizers, vamos explorar quais entradas o modelo aceita. + +Os Tokenizers podem se encarregar de lançar as entradas nos tensores da estrutura apropriada, mas para ajudá-lo a entender o que está acontecendo, vamos dar uma rápida olhada no que deve ser feito antes de enviar as entradas para o modelo. + +Digamos que temos um par de sequências: + +```py +sequences = ["Hello!", "Cool.", "Nice!"] +``` + +O tokenizer os converte em índices de vocabulário que são normalmente chamados de *IDs de entrada*. Cada sequência é agora uma lista de números! A saída resultante é: + +```py no-format +encoded_sequences = [ + [101, 7592, 999, 102], + [101, 4658, 1012, 102], + [101, 3835, 999, 102], +] +``` + +Esta é uma lista de sequências codificadas: uma lista de listas. Os tensores só aceitam shapes (tamanhos) retangulares (pense em matrizes). Esta "matriz" já é de forma retangular, portanto, convertê-la em um tensor é fácil: + +{#if fw === 'pt'} +```py +import torch + +model_inputs = torch.tensor(encoded_sequences) +``` +{:else} +```py +import tensorflow as tf + +model_inputs = tf.constant(encoded_sequences) +``` +{/if} + +### Usando os tensores como entradas para o modelo + +Fazer uso dos tensores com o modelo é extremamente simples - chamamos apenas o modelo com os inputs: + +```py +output = model(model_inputs) +``` + +Embora o modelo aceite muitos argumentos diferentes, apenas os IDs de entrada são necessários. Explicaremos o que os outros argumentos fazem e quando eles são necessários mais tarde, mas primeiro precisamos olhar mais de perto os tokenizers que constroem as entradas que um Transformer pode compreender. diff --git a/chapters/pt/chapter2/4.mdx b/chapters/pt/chapter2/4.mdx new file mode 100644 index 000000000..7b2f70ff6 --- /dev/null +++ b/chapters/pt/chapter2/4.mdx @@ -0,0 +1,248 @@ + + +# Tokenizers + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + + + +Os Tokenizers são um dos componentes centrais do pipeline da PNL. Eles têm um propósito: traduzir texto em dados que podem ser processados pelo modelo. Os modelos só podem processar números, portanto os tokenizers precisam converter nossas entradas de texto em dados numéricos. Nesta seção, vamos explorar exatamente o que acontece no pipeline de tokenização. + +Nas tarefas de PNL, os dados que são geralmente processados são texto bruto. Aqui está um exemplo de tal texto: + +``` +Jim Henson was a puppeteer +``` + +Entretanto, os modelos só podem processar números, portanto, precisamos encontrar uma maneira de converter o texto bruto em números. Isto é o que os tokenizers fazem, e há muitas maneiras de se fazer isso. O objetivo é encontrar a representação mais significativa - ou seja, a que faz mais sentido para o modelo - e, se possível, a menor representação. + +Vamos dar uma olhada em alguns exemplos de algoritmos de tokenização, e tentar responder algumas das perguntas que você possa ter sobre tokenização. + +## Baseado em palavras (word-based) + + + +O primeiro tipo de tokenizer que me vem à mente é _baseado em palavras_. É geralmente muito fácil de instalar e usar com apenas algumas regras, e muitas vezes produz resultados decentes. Por exemplo, na imagem abaixo, o objetivo é dividir o texto bruto em palavras e encontrar uma representação numérica para cada uma delas: + +
+ Um exemplo de tokenização baseado em palavras. + +
+ +Há diferentes maneiras de dividir o texto. Por exemplo, poderíamos utilizar o espaço em branco para simbolizar o texto em palavras, usando a função `split()` do Python: + +```py +tokenized_text = "Jim Henson was a puppeteer".split() +print(tokenized_text) +``` + +```python out +['Jim', 'Henson', 'was', 'a', 'puppeteer'] +``` + +Há também variações de tokenizers de palavras que têm regras extras para pontuação. Com este tipo de tokenizer, podemos terminar com alguns "vocabulários" bem grandes, onde um vocabulário é definido pelo número total de tokens independentes que tem no texto de exemplo. + +A cada palavra é atribuída uma identificação, começando em 0 e indo até o tamanho do vocabulário. O modelo utiliza estas identificações para identificar cada palavra. + +Se quisermos cobrir completamente um idioma com um tokenizer baseado em palavras, precisaremos ter um identificador para cada palavra no idioma, o que gerará uma enorme quantidade de tokens. Por exemplo, existem mais de 500.000 palavras no idioma inglês, portanto, para construir um mapa a partir de cada palavra para um ID de entrada, precisaríamos manter um registro desse grande número de IDs. Além disso, palavras como "dog" são representadas de forma diferente de palavras como "dogs", e o modelo inicialmente não terá como saber que "dog" e "dogs" são semelhantes: ele identificará as duas palavras como não relacionadas. O mesmo se aplica a outras palavras semelhantes, como "run" e "running", que o modelo não verá inicialmente como sendo semelhantes. + + +Finalmente, precisamos de token personalizada para representar palavras que não estão em nosso vocabulário. Isto é conhecido como o símbolo "unknown" (desconhecido), frequentemente representado como "[UNK]" ou "<unk>". Geralmente é um mau sinal se você vê que o tokenizer está produzindo muitos desses tokens, pois não foi capaz de recuperar uma representação sensata de uma palavra e você está perdendo informações ao longo do caminho. O objetivo ao elaborar o vocabulário é fazê-lo de tal forma que o tokenizer transforme o menor número possível de palavras no token desconhecido. + +Uma maneira de reduzir a quantidade de tokens desconhecidas é ir um nível mais fundo, usando um tokenizer _baseado em caracteres_. + +## Baseado em caracteres (Character-based) + + + +Os tokenizers baseados em caracteres dividem o texto em caracteres, ao invés de palavras. Isto tem dois benefícios principais: + +- O vocabulário será muito menor; +- Há muito menos tokes fora de vocabulário (desconhecidas), uma vez que cada palavra pode ser construída a partir de personagens. + +Mas também aqui surgem algumas questões sobre os espaços e à pontuação: + +
+ Um exemplo de tokenização baseado em caracteres. + +
+ +Esta abordagem também não é perfeita. Como a representação agora é baseada em caracteres e não em palavras, pode-se argumentar que, intuitivamente, ela é menos significativa: cada caractere não significa muito por si só, ao contrario do caso das palavras. No entanto, isto novamente difere de acordo com o idioma; em chinês, por exemplo, cada caractere traz mais informações do que um caractere em um idioma latino. + +Outra coisa a considerar é que acabaremos com uma quantidade muito grande de tokens a serem processadas por nosso modelo: enquanto uma palavra seria apenas um único token com um tokenizer baseado em palavras, ela pode facilmente se transformar em 10 ou mais tokens quando convertida em caracteres. + + +Para obter o melhor dos dois mundos, podemos usar uma terceira técnica que combina as duas abordagens: *Tokenização por sub-palavras*. + +## Tokenização por sub-palavras (Subword tokenization) + + + +Algoritmos de tokenização de sub-palavras baseiam-se no princípio de que palavras frequentemente usadas não devem ser divididas em sub-palavras menores, mas palavras raras devem ser decompostas em sub-palavras significativas. + +Por exemplo, "irritantemente" poderia ser considerado uma palavra rara e poderia ser decomposto em "irritante" e "mente". É provável que ambas apareçam mais frequentemente como sub-palavras isoladas, enquanto ao mesmo tempo o significado de "irritantemente" é mantido pelo significado composto de "irritante" e "mente". + +Aqui está um exemplo que mostra como um algoritmo de tokenização de uma sub-palavra indicaria a sequência "Let's do tokenization! + +
+ Exemplo de algoritmo de tokenização por sub-palavras. + +
+ +Estas sub-palavras acabam fornecendo muito significado semântico: por exemplo, no exemplo acima "tokenization" foi dividido em "token" e "ization", dois tokens que têm um significado semântico enquanto são eficientes em termos de espaço (apenas dois tokens são necessários para representar uma palavra longa). Isto nos permite ter uma cobertura relativamente boa com pequenos vocabulários, e perto de nenhum token desconhecido. + + +Esta abordagem é especialmente útil em idiomas aglutinativos como o turco, onde é possível formar palavras (quase) arbitrariamente longas e complexas, encadeando sub-palavras. + +### E outros! + +Sem surpresas, há muito mais técnicas por aí. Para citar algumas: + +- Byte-level BPE, utilizada no GPT-2 +- WordPiece, utilizada em BERT +- SentencePiece ou Unigram, como as utilizadas em vários modelos multilíngue + +Agora você deve ter conhecimento suficiente de como funcionam os tokenizers para começar a utilizar a API. + +## Carregando e salvando + +Carregando e salvando tokenizers é tão simples quanto com os modelos. Na verdade, ele se baseia nos mesmos dois métodos: `from_pretrained()` e `save_pretrained()`. Estes métodos irão carregar ou salvar o algoritmo utilizado pelo tokenizer (um pouco como a *arquitetura* do modelo), bem como seu vocabulário (um pouco como os *pesos* do modelo). + +O carregamento do tokenizer BERT treinado com o mesmo checkpoint do BERT é feito da mesma forma que o carregamento do modelo, exceto que utilizamos a classe `BertTokenizer`: + +```py +from transformers import BertTokenizer + +tokenizer = BertTokenizer.from_pretrained("bert-base-cased") +``` + +{#if fw === 'pt'} +Similar ao `AutoModel`, a classe `AutoTokenizer` ira carregar a classe tokenizer apropriada na biblioteca com base no nome do checkpoint, e pode ser utilizada diretamente com qualquer checkpoint: + +{:else} +Similar ao `TFAutoModel`, a classe `AutoTokenizer` ira carregar a classe tokenizer apropriada na biblioteca com base no nome do checkpoint, e pode ser utilizada diretamente com qualquer checkpoint: + +{/if} + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +``` + +Agora podemos usar o tokenizer, como mostrado na seção anterior: + +```python +tokenizer("Using a Transformer network is simple") +``` + +```python out +{'input_ids': [101, 7993, 170, 11303, 1200, 2443, 1110, 3014, 102], + 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0], + 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]} +``` + +Salvar um tokenizer é idêntico a salvar um modelo: + +```py +tokenizer.save_pretrained("directory_on_my_computer") +``` + + +Falaremos mais sobre `token_type_ids' no [Capítulo 3](/course/pt/chapter3), e explicaremos a `attention_mask' um pouco mais tarde. Primeiro, vamos ver como os `input_ids` são gerados. Para fazer isso, precisaremos olhar os métodos intermediários do tokenizer. + + +## Encoding + + + +Traduzir texto para números é conhecido como _encoding_. O encoding é feito em um processo de duas etapas: a tokenização, seguida pela conversão para IDs de entrada. + +Como vimos, o primeiro passo é dividir o texto em palavras (ou partes de palavras, símbolos de pontuação, etc.), normalmente chamadas de *tokens*. Há várias regras que podem guiar esse processo, e é por isso que precisamos instanciar o tokenizer usando o nome do modelo, para nos certificarmos de usar as mesmas regras que foram usadas quando o modelo foi pré-treinado. + +O segundo passo é converter esses tokens em números, para que possamos construir um tensor a partir deles e alimentá-los com o modelo. Para isso, o tokenizer tem um *vocabulário* (vocabulary), que é a parte que realizamos o download quando o instanciamos com o método `from_pretrained()`. Mais uma vez, precisamos utilizar o mesmo vocabulário utilizado quando o modelo foi pré-treinado. + +Para entender melhor os dois passos, vamos explorá-los separadamente. Note que usaremos alguns métodos que executam partes da pipeline de tokenização separadamente para mostrar os resultados intermediários dessas etapas, mas na prática, você deve chamar o tokenizer diretamente em suas entradas (como mostrado na seção 2). + +### Tokenização + +O processo de tokenization é feito através do método `tokenize()` do tokenizer: + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") + +sequence = "Using a Transformer network is simple" +tokens = tokenizer.tokenize(sequence) + +print(tokens) +``` + +A saída deste método é uma lista de strings, ou tokens: + +```python out +['Using', 'a', 'transform', '##er', 'network', 'is', 'simple'] +``` + +Este tokenizer é um tokenizer de sub-palavras: ele divide as palavras até obter tokens que podem ser representadas por seu vocabulário. É o caso aqui do "transformer", que é dividido em dois tokens: "transform" e "##er". + +### Desde os tokens até IDs de entrada + +A conversão para IDs de entrada é feita pelo método de tokenização `convert_tokens_to_ids()`: + +```py +ids = tokenizer.convert_tokens_to_ids(tokens) + +print(ids) +``` + +```python out +[7993, 170, 11303, 1200, 2443, 1110, 3014] +``` + +Estas saídas, uma vez convertidas no tensor com a estrutura apropriada, podem então ser usadas como entradas para um modelo como visto anteriormente neste capítulo. + + + +✏️ **Experimente realizar isso!** Replicar os dois últimos passos (tokenização e conversão para IDs de entrada) nas frases de entrada que usamos na seção 2 ("I've been waiting for a HuggingFace course my whole life." e "I hate this so much!"). Verifique se você recebe os mesmos IDs de entrada que recebemos antes! + + + +## Decoding + +*Decoding* vai pela direção ao contrário: a partir de índices de vocabulário, queremos obter uma string. Isto pode ser feito com o método `decode()` da seguinte forma: + + +```py +decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014]) +print(decoded_string) +``` + +```python out +'Using a Transformer network is simple' +``` + +Observe que o método `decode` não apenas converte os índices em tokens, mas também agrupa os tokens que fizeram parte das mesmas palavras para produzir uma frase legível. Este comportamento será extremamente útil quando utilizamos modelos que preveem um novo texto (seja texto gerado a partir de um prompt, ou para problemas de _sequence-to-sequence_ como tradução ou sumarização). + + + +Até agora você já deve entender as operações atômicas que um tokenizer pode lidar: tokenização, conversão para IDs, e conversão de IDs de volta para uma string. Entretanto, acabamos de começar a ver a ponta do iceberg. Na seção seguinte, vamos nos aproximar de seus limites e dar uma olhada em como superá-los. \ No newline at end of file diff --git a/chapters/pt/chapter2/5.mdx b/chapters/pt/chapter2/5.mdx new file mode 100644 index 000000000..9b45c2c47 --- /dev/null +++ b/chapters/pt/chapter2/5.mdx @@ -0,0 +1,340 @@ + + +# Tratando sequências múltiplas + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +{#if fw === 'pt'} + +{:else} + +{/if} + +Na seção anterior, exploramos os casos mais simples de uso: fazer inferência sobre uma única sequência de pequeno comprimento. No entanto, surgem algumas questões: + +- Como nós tratamos diversas sequências? +- Como nós tratamos diversas sequências *de diferentes tamanhos*? +- Os índices de vocabulário são as únicas entradas que permitem que um modelo funcione bem? +- Existe uma sequência muito longa? + +Vamos ver que tipos de problemas estas questões colocam, e como podemos resolvê-los usando a API do 🤗 Transformers. + +## Modelos esperam um batch de entradas + +No exercício anterior, você viu como as sequências são traduzidas em listas de números. Vamos converter esta lista de números em um tensor e enviá-la para o modelo: + +{#if fw === 'pt'} +```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) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.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 = tf.constant(ids) +# This line will fail. +model(input_ids) +``` + +```py out +InvalidArgumentError: Input to reshape is a tensor with 14 values, but the requested shape has 196 [Op:Reshape] +``` +{/if} + +Oh não! Por que isso falhou? "Seguimos os passos do pipeline na seção 2. + +O problema é que enviamos uma única sequência para o modelo, enquanto que os 🤗 transformers esperam várias sentenças por padrão. Aqui tentamos fazer tudo o que o tokenizer fez nos bastidores quando o aplicamos a uma `sequência`, mas se você olhar com atenção, verá que ele não apenas converteu a lista de IDs de entrada em um tensor, mas acrescentou uma dimensão em cima dele: + +{#if fw === 'pt'} +```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]]) +``` +{:else} +```py +tokenized_inputs = tokenizer(sequence, return_tensors="tf") +print(tokenized_inputs["input_ids"]) +``` + +```py out + +``` +{/if} + +Vamos tentar novamente e acrescentar uma nova dimensão: + +{#if fw === 'pt'} +```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) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.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 = tf.constant([ids]) +print("Input IDs:", input_ids) + +output = model(input_ids) +print("Logits:", output.logits) +``` +{/if} + +Printamos os IDs de entrada assim como os logits resultantes - aqui está a saída: + +{#if fw === 'pt'} +```python out +Input IDs: [[ 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012]] +Logits: [[-2.7276, 2.8789]] +``` +{:else} +```py out +Input IDs: tf.Tensor( +[[ 1045 1005 2310 2042 3403 2005 1037 17662 12172 2607 2026 2878 + 2166 1012]], shape=(1, 14), dtype=int32) +Logits: tf.Tensor([[-2.7276208 2.8789377]], shape=(1, 2), dtype=float32) +``` +{/if} + +*Batching* é o ato de enviar múltiplas sentenças através do modelo, todas de uma só vez. Se você tiver apenas uma frase, você pode apenas construir um lote com uma única sequência: + +``` +batched_ids = [ids, ids] +``` + +Este é um lote de duas sequências idênticas! + + + +✏️ **Experimente!** Converta esta lista de `batched_ids` em um tensor e passe-a através de seu modelo. Verifique se você obtém os mesmos logits que antes (mas duas vezes)! + + + +O Batching permite que o modelo funcione quando você o alimenta com várias frases. Usar várias sequências é tão simples quanto construir um lote com uma única sequência. Há uma segunda questão, no entanto. Quando você está tentando agrupar duas (ou mais) sentenças, elas podem ser de comprimentos diferentes. Se você já trabalhou com tensores antes, você sabe que eles precisam ser de forma retangular, então você não será capaz de converter a lista de IDs de entrada em um tensor diretamente. Para contornar este problema, normalmente realizamos uma *padronização* (padding) nas entradas. + + +## Realizando padding nas entradas + +A seguinte lista de listas não pode ser convertida em um tensor: + +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200] +] +``` + +Para contornar isso, usaremos *padding* para fazer com que nossos tensores tenham uma forma retangular. O padding garante que todas as nossas frases tenham o mesmo comprimento, acrescentando uma palavra especial chamada *padding token* às frases com menos valores. Por exemplo, se você tiver 10 frases com 10 palavras e 1 frase com 20 palavras, o padding garantirá que todas as frases tenham 20 palavras. Em nosso exemplo, o tensor resultante se parece com isto: + + +```py no-format +padding_id = 100 + +batched_ids = [ + [200, 200, 200], + [200, 200, padding_id], +] +``` + +O padding do ID token pode ser encontrada em `tokenizer.pad_token_id`. Vamos utilizá-lo e enviar nossas duas frases através do modelo individualmente e agrupadas em batches: + +{#if fw === 'pt'} +```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=) +tensor([[ 0.5803, -0.4125]], grad_fn=) +tensor([[ 1.5694, -1.3895], + [ 1.3373, -1.2163]], grad_fn=) +``` +{:else} +```py no-format +model = TFAutoModelForSequenceClassification.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(tf.constant(sequence1_ids)).logits) +print(model(tf.constant(sequence2_ids)).logits) +print(model(tf.constant(batched_ids)).logits) +``` + +```py out +tf.Tensor([[ 1.5693678 -1.3894581]], shape=(1, 2), dtype=float32) +tf.Tensor([[ 0.5803005 -0.41252428]], shape=(1, 2), dtype=float32) +tf.Tensor( +[[ 1.5693681 -1.3894582] + [ 1.3373486 -1.2163193]], shape=(2, 2), dtype=float32) +``` +{/if} + +Há algo errado com os logits em nossas predições em batches: a segunda fileira deveria ser a mesma que os logits para a segunda frase, mas temos valores completamente diferentes! + +Isto porque a característica chave dos Transformer são as camadas de atenção que *contextualizam* cada token. Estes levarão em conta os tokens de padding, uma vez que atendem a todos os tokens de uma sequência. Para obter o mesmo resultado ao passar frases individuais de diferentes comprimentos pelo modelo ou ao passar um batch com as mesmas frases e os paddings aplicados, precisamos dizer a essas camadas de atenção para ignorar os tokens de padding. Isto é feito com o uso de uma máscara de atenção (*attention mask*). + +## Attention masks + +*Attention masks* são tensores com a mesma forma exata do tensor de IDs de entrada, preenchidos com 0s e 1s: 1s indicam que os tokens correspondentes devem ser atendidas, e 0s indicam que os tokens correspondentes não devem ser atendidas (ou seja, devem ser ignoradas pelas camadas de atenção do modelo). + +Vamos completar o exemplo anterior com uma máscara de atenção: + +{#if fw === 'pt'} +```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=) +``` +{:else} +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200, tokenizer.pad_token_id], +] + +attention_mask = [ + [1, 1, 1], + [1, 1, 0], +] + +outputs = model(tf.constant(batched_ids), attention_mask=tf.constant(attention_mask)) +print(outputs.logits) +``` + +```py out +tf.Tensor( +[[ 1.5693681 -1.3894582 ] + [ 0.5803021 -0.41252586]], shape=(2, 2), dtype=float32) +``` +{/if} + +Agora obtemos os mesmos logits para a segunda frase do batch. + +Observe como o último valor da segunda sequência é um ID de padding, que é um valor 0 na máscara de atenção. + + + +✏️ **Experimente!** Aplique a tokenização manualmente nas duas frases usadas na seção 2 ("I've been waiting for a HuggingFace course my whole life." e "I hate this so much!"). Passe-as através do modelo e verifique se você obtém os mesmos logits que na seção 2. Agora, agrupe-os usando o token de padding e depois crie a máscara de atenção adequada. Verifique que você obtenha os mesmos resultados ao passar pelo modelo! + + + +## Sequências mais longas + +Com os Transformer, há um limite para os comprimentos das sequências, podemos passar os modelos. A maioria dos modelos manipula sequências de até 512 ou 1024 tokens, e se chocará quando solicitados a processar sequências mais longas. Há duas soluções para este problema: + +- Use um modelo com suporte a um comprimento mais longo de sequência. +- Trunque suas sequências. + +Os modelos têm diferentes comprimentos de sequência suportados, e alguns são especializados no tratamento de sequências muito longas. O [Longformer](https://huggingface.co/transformers/model_doc/longformer.html) é um exemplo, e outro exemplo é o [LED](https://huggingface.co/transformers/model_doc/led.html). Se você estiver trabalhando em uma tarefa que requer sequências muito longas, recomendamos que você dê uma olhada nesses modelos. + +Caso contrário, recomendamos que você trunque suas sequências, especificando o parâmetro `max_sequence_length`: + +```py +sequence = sequence[:max_sequence_length] +``` diff --git a/chapters/pt/chapter2/6.mdx b/chapters/pt/chapter2/6.mdx new file mode 100644 index 000000000..a1ba25c38 --- /dev/null +++ b/chapters/pt/chapter2/6.mdx @@ -0,0 +1,167 @@ + + +# Colocando tudo junto + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +Nas últimas seções, temos feito o nosso melhor para fazer a maior parte do trabalho à mão. Exploramos como funcionam os tokenizers e analisamos a tokenização, conversão para IDs de entrada, padding, truncagem e máscaras de atenção. + +Entretanto, como vimos na seção 2, a API dos 🤗 Transformers pode tratar de tudo isso para nós com uma função de alto nível, na qual mergulharemos aqui. Quando você chama seu `tokenizer` diretamente na frase, você recebe de volta entradas que estão prontas para passar pelo seu modelo: + +```py +from transformers import AutoTokenizer + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." + +model_inputs = tokenizer(sequence) +``` + +Aqui, a variável `model_inputs` contém tudo o que é necessário para que um modelo funcione bem. Para DistilBERT, isso inclui os IDs de entrada, bem como a máscara de atenção. Outros modelos que aceitam entradas adicionais também terão essas saídas pelo objeto `tokenizer`. + +Como veremos em alguns exemplos abaixo, este método é muito poderoso. Primeiro, ele pode simbolizar uma única sequência: + +```py +sequence = "I've been waiting for a HuggingFace course my whole life." + +model_inputs = tokenizer(sequence) +``` + +Também lida com várias sequências de cada vez, sem nenhuma mudança na API: + +```py +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +model_inputs = tokenizer(sequences) +``` + +Ela pode ser aplicada de acordo com vários objetivos: + +```py +# Irá preencher as sequências até o comprimento máximo da sequência +model_inputs = tokenizer(sequences, padding="longest") + +# Irá preencher as sequências até o comprimento máximo do modelo +# (512 para o modelo BERT ou DistilBERT) +model_inputs = tokenizer(sequences, padding="max_length") + +# Irá preencher as sequências até o comprimento máximo especificado +model_inputs = tokenizer(sequences, padding="max_length", max_length=8) +``` + +Também pode truncar sequências: + +```py +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +# Irá preencher as sequências até o comprimento máximo do modelo +# (512 para o modelo BERT ou DistilBERT) +model_inputs = tokenizer(sequences, truncation=True) + +# Truncará as sequências que são mais longas do que o comprimento máximo especificado +model_inputs = tokenizer(sequences, max_length=8, truncation=True) +``` + +O objeto `tokenizer` pode lidar com a conversão para tensores de estrutura específicos, que podem então ser enviados diretamente para o modelo. Por exemplo, na seguinte amostra de código, estamos solicitando que o tokenizer retorne tensores de diferentes estruturas - `"pt"` retorna tensores PyTorch, `"tf"` retorna tensores TensorFlow, e `"np"` retorna arrays NumPy: + +```py +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +# Retorna tensores PyTorch +model_inputs = tokenizer(sequences, padding=True, return_tensors="pt") + +# Retorna tensores TensorFlow +model_inputs = tokenizer(sequences, padding=True, return_tensors="tf") + +# Retorna NumPy arrays +model_inputs = tokenizer(sequences, padding=True, return_tensors="np") +``` + +## Tokens especiais + +Se dermos uma olhada nos IDs de entrada devolvidos pelo tokenizer, veremos que eles são um pouco diferentes do que tínhamos anteriormente: + +```py +sequence = "I've been waiting for a HuggingFace course my whole life." + +model_inputs = tokenizer(sequence) +print(model_inputs["input_ids"]) + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) +print(ids) +``` + +```python out +[101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102] +[1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012] +``` + + +Um token ID foi adicionada no início e uma no final. Vamos decodificar as duas sequências de IDs acima para ver do que se trata: + + +```py +print(tokenizer.decode(model_inputs["input_ids"])) +print(tokenizer.decode(ids)) +``` + +```python out +"[CLS] i've been waiting for a huggingface course my whole life. [SEP]" +"i've been waiting for a huggingface course my whole life." +``` + +O tokenizer acrescentou a palavra especial `[CLS]` no início e a palavra especial `[SEP]` no final. Isto porque o modelo foi pré-treinado com esses, então para obter os mesmos resultados para inferência, precisamos adicioná-los também. Note que alguns modelos não acrescentam palavras especiais, ou acrescentam palavras diferentes; os modelos também podem acrescentar estas palavras especiais apenas no início, ou apenas no final. Em qualquer caso, o tokenizer sabe quais são as palavras que são esperadas e tratará disso para você. + + +## Do tokenizer ao modelo + +Agora que já vimos todos os passos individuais que o objeto `tokenizer` utiliza quando aplicado em textos, vamos ver uma última vez como ele pode lidar com múltiplas sequências (padding!), sequências muito longas (truncagem!), e múltiplos tipos de tensores com seu API principal: + +{#if fw === 'pt'} +```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) +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt") +output = model(**tokens) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="tf") +output = model(**tokens) +``` +{/if} diff --git a/chapters/pt/chapter2/7.mdx b/chapters/pt/chapter2/7.mdx new file mode 100644 index 000000000..2b2f1df5a --- /dev/null +++ b/chapters/pt/chapter2/7.mdx @@ -0,0 +1,13 @@ +# Uso básico concluído! + +Ótimo trabalho seguindo o curso até aqui! Recapitulando, neste capítulo, você: + +- Aprendeu os elementos básicos de um modelo Transformer. +- Aprendeu que compõe o pipeline de tokenização. +- Vou como utilizar um transformer na prática. +- Aprendeu como aproveitar um tokenizer para converter texto em tensores que são compreensíveis pelo modelo. +- Montar um tokenizer e um modelo juntos para ir do texto às previsões. +- Aprendeu as limitações dos IDs de entrada e aprendeu sobre máscaras de atenção. +- Testou os métodos de tokenizer versáteis e configuráveis. + +De agora em diante, você deve ser capaz de navegar livremente pelos documentos dos 🤗 transformers: o vocabulário soará familiar, e você já viu os métodos que utilizará na maior parte do tempo. diff --git a/chapters/pt/chapter2/8.mdx b/chapters/pt/chapter2/8.mdx new file mode 100644 index 000000000..00a283ad3 --- /dev/null +++ b/chapters/pt/chapter2/8.mdx @@ -0,0 +1,305 @@ + + + + +# Questionário de fim de capítulo + +### 1. Qual é a ordem do pipeline para a modelagem de linguagem? + + + +### 2. Quantas dimensões tem o tensor do Transformer de base, e quais são elas? + + + +### 3. Qual dos seguintes é um exemplo de Tokenização por sub-palavras? + + + +### 4. O que é uma *model head*? + + + +{#if fw === 'pt'} +### 5. O que seria um `AutoModel`? + +AutoNLP?" + }, + { + text: "Um objeto que devolve a arquitetura correta com base em um checkpoint", + explain: "Exatamente: o AutoModel só precisa saber o checkpoint para saber como inicializar então devolver a arquitetura correta.", + correct: true + }, + { + text: "Um modelo que detecta automaticamente a linguagem utilizada para suas entradas a fim de carregar os pesos corretos", + explain: "Incorreto; embora alguns checkpoints e modelos sejam capazes de lidar com vários idiomas, não há ferramentas embutidas para seleção automática de checkpoints de acordo com o idioma. Você deve ir para o Model Hub para encontrar o melhor checkpoint para realizar sua tarefa!" + } + ]} +/> + +{:else} +### 5. O que seria um `TFAutoModel`? + +AutoNLP?" + }, + { + text: "Um objeto que devolve a arquitetura correta com base em um checkpoint", + explain: "Exatamente: o TFAutoModel só precisa saber o checkpoint para saber como inicializar então devolver a arquitetura correta.", + correct: true + }, + { + text: "Um modelo que detecta automaticamente a linguagem utilizada para suas entradas a fim de carregar os pesos corretos", + explain: "Incorreto; embora alguns checkpoints e modelos sejam capazes de lidar com vários idiomas, não há ferramentas embutidas para seleção automática de checkpoints de acordo com o idioma. Você deve ir para o Model Hub para encontrar o melhor checkpoint para realizar sua tarefa!" + } + ]} +/> + +{/if} + +### 6. Quais são as técnicas a serem observadas quando realizar batches com sequências de diferentes tamanhos? + + + +### 7. Qual é o objetivo de aplicar uma função SoftMax à saída de logits para um modelo de classificação sequencial?? + + + +### 8. Qual é o método core da API tokenizer? + +encode, pois pode codificar texto em IDs e IDs em predições", + explain: "Errado! O método encode existe na tokenização, porém não existe nos modelos." + }, + { + text: "Chamando diretamente o objeto de tokenização (tokenizer).", + explain: "Exatamente! O método __call__ do tokenizer é um método muito poderoso que pode lidar com praticamente qualquer coisa. É também o método usado para recuperar as predições de um modelo.", + correct: true + }, + { + text: "padding", + explain: "Errado! O padding é muito útil, mas é apenas uma parte da API do tokenizer." + }, + { + text: "tokenize", + explain: "O método tokenize é indiscutivelmente um dos métodos mais úteis, mas não é o núcleo do API do tokenizer." + } + ]} +/> + +### 9. O que a variável `result` contém nesta pedaço de código? + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +result = tokenizer.tokenize("Hello!") +``` + +__call__ ou convert_tokens_to_ids!" + }, + { + text: "Uma string contendo todos os tokens ", + explain: "Isto seria subótimo, pois o objetivo é dividir a string em vários tokens." + } + ]} +/> + +{#if fw === 'pt'} +### 10. Tem algo errado com o código abaixo? + +```py +from transformers import AutoTokenizer, AutoModel + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +model = AutoModel.from_pretrained("gpt2") + +encoded = tokenizer("Hey!", return_tensors="pt") +result = model(**encoded) +``` + + + +{:else} +### 10. Tem algo errado com o código abaixo? + +```py +from transformers import AutoTokenizer, TFAutoModel + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +model = TFAutoModel.from_pretrained("gpt2") + +encoded = tokenizer("Hey!", return_tensors="pt") +result = model(**encoded) +``` + + + +{/if} From 0a3880d12e072397baa11e8b8b23088faed48783 Mon Sep 17 00:00:00 2001 From: lbourdois <58078086+lbourdois@users.noreply.github.com> Date: Wed, 13 Apr 2022 15:58:55 +0200 Subject: [PATCH 71/73] [FR] Translation of chapter 2 & event + Review of chapters 0 & 5 (#106) * Update _toctree.yml Add chapter 2 + little fix of chapter 5 * Update 1.mdx Review of chapter 0 * Create 1.mdx * Create 2.mdx * Create 3.mdx * Create 4.mdx * Create 5.mdx * Create 6.mdx * Create 7.mdx * Create 8.mdx * Update 8.mdx Since AutoNLP has recently been renamed to AutoTrain, let me make the correction on the English file * Update 1.mdx Review of chapter 5/1 * Update 2.mdx Review of chapter 5/2 * Update 3.mdx Review of chapter 5/3 * Update 4.mdx Review of chapter 5/4 * Update 5.mdx Review of chapter 5/5 * Update 6.mdx Review of chapter 5/6 * Update 7.mdx Review of chapter 5/7 * Update 8.mdx Review of chapter 5/8 * Create 1.mdx event's translation * Update _toctree.yml add event to the tree * Update _toctree.yml deletion of the files that pose a problem to pass the checks, will be resubmitted in another PR * Delete 1.mdx deletion of the files that pose a problem to pass the checks, will be resubmitted in another PR * make style correction * Update _toctree.yml the - * Fix spacing Co-authored-by: Lewis Tunstall --- chapters/en/chapter2/8.mdx | 2 +- chapters/fr/_toctree.yml | 26 ++- chapters/fr/chapter0/1.mdx | 35 ++-- chapters/fr/chapter2/1.mdx | 24 +++ chapters/fr/chapter2/2.mdx | 344 ++++++++++++++++++++++++++++++++++++ chapters/fr/chapter2/3.mdx | 231 ++++++++++++++++++++++++ chapters/fr/chapter2/4.mdx | 253 ++++++++++++++++++++++++++ chapters/fr/chapter2/5.mdx | 351 +++++++++++++++++++++++++++++++++++++ chapters/fr/chapter2/6.mdx | 186 ++++++++++++++++++++ chapters/fr/chapter2/7.mdx | 12 ++ chapters/fr/chapter2/8.mdx | 307 ++++++++++++++++++++++++++++++++ chapters/fr/chapter5/1.mdx | 20 +-- chapters/fr/chapter5/2.mdx | 50 +++--- chapters/fr/chapter5/3.mdx | 197 +++++++++++---------- chapters/fr/chapter5/4.mdx | 99 ++++++----- chapters/fr/chapter5/5.mdx | 124 +++++++------ chapters/fr/chapter5/6.mdx | 74 ++++---- chapters/fr/chapter5/7.mdx | 17 +- chapters/fr/chapter5/8.mdx | 104 +++++------ 19 files changed, 2095 insertions(+), 361 deletions(-) create mode 100644 chapters/fr/chapter2/1.mdx create mode 100644 chapters/fr/chapter2/2.mdx create mode 100644 chapters/fr/chapter2/3.mdx create mode 100644 chapters/fr/chapter2/4.mdx create mode 100644 chapters/fr/chapter2/5.mdx create mode 100644 chapters/fr/chapter2/6.mdx create mode 100644 chapters/fr/chapter2/7.mdx create mode 100644 chapters/fr/chapter2/8.mdx diff --git a/chapters/en/chapter2/8.mdx b/chapters/en/chapter2/8.mdx index 43f0a8c9c..ef07b0b31 100644 --- a/chapters/en/chapter2/8.mdx +++ b/chapters/en/chapter2/8.mdx @@ -105,7 +105,7 @@ choices={[ { text: "A model that automatically trains on your data", - explain: "Incorrect. Are you mistaking this with our AutoNLP product?" + explain: "Incorrect. Are you mistaking this with our AutoTrain product?" }, { text: "An object that returns the correct architecture based on the checkpoint", diff --git a/chapters/fr/_toctree.yml b/chapters/fr/_toctree.yml index ad9953b2d..ab363315c 100644 --- a/chapters/fr/_toctree.yml +++ b/chapters/fr/_toctree.yml @@ -3,16 +3,36 @@ - local: chapter0/1 title: Introduction +- title: 2. Utilisation de 🤗 Transformers + sections: + - local: chapter2/1 + title: Introduction + - local: chapter2/2 + title: Derrière le pipeline + - local: chapter2/3 + title: Modèles + - local: chapter2/4 + title: Tokenizers + - local: chapter2/5 + title: Manipulation de plusieurs séquences + - local: chapter2/6 + title: Tout assembler + - local: chapter2/7 + title: Utilisation de base terminée ! + - local: chapter2/8 + title: Quiz de fin de chapitre + quiz: 2 + - title: 5. La bibliothèque 🤗 Datasets sections: - local: chapter5/1 title: Introduction - local: chapter5/2 - title: Que faire si mon ensemble de données n'est pas sur le Hub ? + title: Que faire si mon jeu de données n'est pas sur le Hub ? - local: chapter5/3 title: Il est temps de trancher et de découper - local: chapter5/4 - title: Big Data? 🤗 Des jeux de données à la rescousse ! + title: Données massives ? 🤗 Des jeux de données à la rescousse ! - local: chapter5/5 title: Création de votre propre jeu de données - local: chapter5/6 @@ -21,4 +41,4 @@ title: 🤗 Datasets, vérifié ! - local: chapter5/8 title: Quiz de fin de chapitre - quiz: 5 \ No newline at end of file + quiz: 5 diff --git a/chapters/fr/chapter0/1.mdx b/chapters/fr/chapter0/1.mdx index 14aa13313..3dd008c1a 100644 --- a/chapters/fr/chapter0/1.mdx +++ b/chapters/fr/chapter0/1.mdx @@ -1,28 +1,29 @@ # Introduction -Bienvenue au cours Hugging Face ! Cette introduction vous guidera dans la mise en place d'un environnement de travail. Si vous venez de commencer le cours, nous vous recommandons de consulter d'abord le [Chapitre 1](/course/chapter1), puis de revenir et de configurer votre environnement afin de pouvoir essayer le code vous-même. +Bienvenue au cours d'Hugging Face ! Cette introduction est là pour vous guider dans la mise en place d'un environnement de travail. Si vous venez de commencer le cours, nous vous recommandons de consulter d'abord le [Chapitre 1](/course/fr/chapter1) puis de revenir et de configurer votre environnement afin de pouvoir essayer le code vous-même. -Toutes les bibliothèques que nous utiliserons dans ce cours sont disponibles sous forme de packages Python. Nous allons donc vous montrer comment configurer un environnement Python et installer les bibliothèques spécifiques dont vous aurez besoin. +Toutes les bibliothèques que nous utiliserons dans ce cours sont disponibles sous forme de *packages* Python. Nous allons donc vous montrer comment configurer un environnement Python et installer les bibliothèques spécifiques dont vous aurez besoin. -Nous aborderons deux façons de configurer votre environnement de travail, en utilisant un notebook google Colab ou un environnement virtuel Python. N'hésitez pas à choisir celle qui vous convient le mieux. Pour les débutants, nous vous recommandons vivement de commencer par utiliser un notebook google colab. +Nous aborderons deux façons de configurer votre environnement de travail : soit en utilisant un *notebook* Google Colab, soit en utilisant un environnement virtuel Python. N'hésitez pas à choisir celle qui vous convient le mieux. Pour les débutants, nous vous recommandons vivement de commencer en utilisant un *notebook* Google Colab. -Notez que nous ne couvrirons pas le système Windows. Si vous travaillez sous Windows, nous vous recommandons de suivre le cours en utilisant un cahier Colab. Si vous utilisez une distribution Linux ou macOS, vous pouvez utiliser l'une des deux approches décrites ici. +Notez que nous ne couvrirons pas le système Windows. Si vous travaillez sous Windows, nous vous recommandons de suivre le cours en utilisant un *notebook* Google Colab. Si vous utilisez une distribution Linux ou macOS, vous pouvez utiliser l'une des deux approches décrites ci-dessous. -La plupart du cours repose sur le fait que vous ayez un compte Hugging Face. Nous vous recommandons d'en créer un dès maintenant :[créer un compte](https://huggingface.co/join). +La plupart du cours repose sur le fait que vous ayez un compte Hugging Face. Si vous n'en disposez pas d'un, nous vous recommandons d'en créer un dès maintenant : [créer un compte](https://huggingface.co/join). -## Utilisatoin d'un notebook Google Colab +## Utilisatoin d'un *notebook* Google Colab -L'utilisation d'un notebook google Colab est la configuration la plus simple possible ; démarrez un notebook colab dans votre navigateur et passez directement au codage ! +L'utilisation d'un *notebook* Google Colab est la configuration la plus simple possible. Démarrez un *notebook* dans votre navigateur et passez directement au codage ! -Si vous n'êtes pas familier avec Colab, nous vous recommandons de commencer par suivre les [introduction](https://colab.research.google.com/notebooks/intro.ipynb).Colab vous permet d'utiliser du matériel d'accélération, comme les GPU ou les TPU, et il est gratuit pour les petites charges de travail. +Si vous n'êtes pas familier avec Colab, nous vous recommandons de commencer par suivre l'[introduction](https://colab.research.google.com/notebooks/intro.ipynb). Colab vous permet d'utiliser du matériel comme les GPUs ou les TPUs et est gratuit pour les petites charges de travail. -Une fois que vous vous sentez à l'aise dans Colab, créez un nouveau notebook et commencez à le configurer : +Une fois que vous vous sentez suffisamment à l'aise avec Colab, créez un nouveau *notebook* et commencez à le configurer :
An empty colab notebook
-L'étape suivante consiste à installer les bibliothèques que nous allons utiliser dans ce cours. Nous utiliserons `pip` pour l'installation, qui est le gestionnaire de paquets pour Python. Dans les notebooks, vous pouvez exécuter des commandes système en les faisant précéder du caractère `!`, vous pouvez donc installer la bibliothèque 🤗 Transformers comme suit : +L'étape suivante consiste à installer les bibliothèques que nous allons utiliser dans ce cours. Nous utiliserons `pip` pour l'installation qui est le gestionnaire de *packages* pour Python. Dans les *notebooks*, vous pouvez exécuter des commandes système en les faisant précéder du caractère `!`. Vous pouvez donc installer la bibliothèque 🤗 *Transformers* comme suit : + ``` !pip install transformers ``` @@ -37,22 +38,24 @@ import transformers A gif showing the result of the two commands above: installation and import -Cela installe une version très légère de 🤗 Transformers. En particulier, aucun framework d'apprentissage automatique spécifique (comme PyTorch ou TensorFlow) n'est installé. Comme nous utiliserons de nombreuses fonctionnalités différentes de la bibliothèque, nous recommandons d'installer la version de développement, qui est livrée avec toutes les dépendances requises pour à peu près tous les cas d'utilisation imaginables : +Cela installe une version très légère de 🤗 *Transformers*. En particulier, aucun *framework* d'apprentissage automatique spécifique (comme PyTorch ou TensorFlow) n'est installé. Comme nous utiliserons de nombreuses fonctionnalités différentes de la bibliothèque, nous recommandons d'installer la version de développement qui est livrée avec toutes les dépendances requises pour à peu près tous les cas d'utilisation imaginables : ``` !pip install transformers[sentencepiece] ``` + Cela prendra un peu de temps, mais vous serez alors prêt pour le reste du cours ! + ## Utilisation d'un environnement virtuel Python Si vous préférez utiliser un environnement virtuel Python, la première étape consiste à installer Python sur votre système. Nous vous recommandons de suivre [ce guide](https://realpython.com/installing-python/) pour commencer. -Une fois que Python est installé, vous devriez être en mesure d'exécuter des commandes Python dans votre terminal. Vous pouvez commencer par exécuter la commande suivante pour vous assurer qu'il est correctement installé avant de passer aux étapes suivantes : `python --version`. Cette commande devrait vous indiquer la version de Python disponible sur votre système. +Une fois Python installé, vous devriez être en mesure d'exécuter des commandes Python dans votre terminal. Vous pouvez commencer par exécuter la commande suivante pour vous assurer qu'il est correctement installé avant de passer aux étapes suivantes : `python --version`. Cette commande devrait vous indiquer la version de Python disponible sur votre système. -Lorsque vous exécutez une commande Python dans votre terminal, comme `python --version`, vous devez considérer le programme qui exécute votre commande comme la fonction "main" Python sur votre système. Nous vous recommandons de garder cette installation principale libre de tout paquet, et de l'utiliser pour créer des environnements séparés pour chaque application sur laquelle vous travaillez - de cette façon, chaque application peut avoir ses propres dépendances et paquets, et vous n'aurez pas à vous soucier de problèmes potentiels de compatibilité avec d'autres applications. +Lorsque vous exécutez une commande Python dans votre terminal, comme `python --version`, vous devez considérer le programme qui exécute votre commande comme la fonction « main » Python sur votre système. Nous vous recommandons de garder cette installation principale libre de tout *package* et de l'utiliser pour créer des environnements séparés pour chaque application sur laquelle vous travaillez. De cette façon, chaque application peut avoir ses propres dépendances et *packages*, et vous n'aurez pas à vous soucier de problèmes potentiels de compatibilité avec d'autres applications. -En Python, cela se fait avec les [*environnements virtuels*](https://docs.python.org/3/tutorial/venv.html), qui sont des arbres de répertoires autonomes contenant chacun une installation Python avec une version particulière de Python ainsi que tous les paquets dont l'application a besoin. La création d'un tel environnement virtuel peut se faire à l'aide d'un certain nombre d'outils différents, mais nous utiliserons le paquetage officiel de Python à cette fin, qui s'appelle [`venv`](https://docs.python.org/3/library/venv.html#module-venv). +En Python, cela se fait avec les [*environnements virtuels*](https://docs.python.org/3/tutorial/venv.html), qui sont des arbres de répertoires autonomes contenant chacun une installation Python avec une version particulière de Python ainsi que tous les *packages* dont l'application a besoin. La création d'un tel environnement virtuel peut se faire à l'aide d'un certain nombre d'outils différents, mais nous utiliserons le *package* officiel de Python : [`venv`](https://docs.python.org/3/library/venv.html#module-venv). Tout d'abord, créez le répertoire dans lequel vous souhaitez que votre application se trouve. Par exemple, vous pouvez créer un nouveau répertoire appelé *transformers-course* à la racine de votre répertoire personnel : ``` @@ -98,10 +101,10 @@ which python ### Installation des dépendances -Comme dans la section précédente sur l'utilisation des instances Google Colab, vous devez maintenant installer les packages requis pour continuer. Encore une fois, vous pouvez installer la version de développement de 🤗 Transformers à l'aide du gestionnaire de packages `pip` : +Comme dans la section précédente sur l'utilisation des instances Google Colab, vous devez maintenant installer les *packages* requis pour continuer. Encore une fois, vous pouvez installer la version de développement de 🤗 *Transformers* à l'aide du gestionnaire de packages `pip` : ``` pip install "transformers[sentencepiece]" ``` -Vous êtes maintenant prêt ! \ No newline at end of file +Vous êtes maintenant prêt ! diff --git a/chapters/fr/chapter2/1.mdx b/chapters/fr/chapter2/1.mdx new file mode 100644 index 000000000..bf0c05190 --- /dev/null +++ b/chapters/fr/chapter2/1.mdx @@ -0,0 +1,24 @@ +# Introduction + +Comme vous l'avez vu dans le [Chapitre 1](/course/fr/chapter1), les *transformers* sont généralement très grands. Pouvant aller de plusieurs millions à des dizaines de milliards de paramètres, l'entraînement et le déploiement de ces modèles est une entreprise compliquée. De plus, avec de nouveaux modèles publiés presque quotidiennement et ayant chacun sa propre implémentation, les essayer tous n'est pas une tâche facile. + +La bibliothèque 🤗 *Transformers* a été créée pour résoudre ce problème. Son objectif est de fournir une API unique à travers laquelle tout modèle de *transformers* peut être chargé, entraîné et sauvegardé. Les principales caractéristiques de la bibliothèque sont : + +- **la facilité d'utilisation** : en seulement deux lignes de code il est possible de télécharger, charger et utiliser un modèle de NLP à l'état de l'art pour faire de l'inférence, +- **la flexibilité** : au fond, tous les modèles sont de simples classes PyTorch `nn.Module` ou TensorFlow `tf.keras.Model` et peuvent être manipulés comme n'importe quel autre modèle dans leurs *frameworks* d'apprentissage automatique respectifs, +- **la simplicité** : pratiquement aucune abstraction n'est faite dans la bibliothèque. Avoir tout dans un fichier est un concept central : la passe avant d'un modèle est entièrement définie dans un seul fichier afin que le code lui-même soit compréhensible et piratable. + +Cette dernière caractéristique rend 🤗 *Transformers* très différent des autres bibliothèques d'apprentissage automatique. +Les modèles ne sont pas construits sur des modules partagés entre plusieurs fichiers. Au lieu de cela, chaque modèle possède ses propres couches. +En plus de rendre les modèles plus accessibles et compréhensibles, cela vous permet d'expérimenter des choses facilement sur un modèle sans affecter les autres. + +Ce chapitre commence par un exemple de bout en bout où nous utilisons un modèle et un *tokenizer* ensemble pour reproduire la fonction `pipeline()` introduite dans le [Chapitre 1](/course/chapter1). +Ensuite, nous aborderons l'API *model* : nous nous plongerons dans les classes de modèle et de configuration, nous verrons comment charger un modèle et enfin comment il traite les entrées numériques pour produire des prédictions. + +Nous examinerons ensuite l'API *tokenizer* qui est l'autre composant principal de la fonction `pipeline()`. +Les *tokenizers* s'occupent de la première et de la dernière étape du traitement en gérant la conversion du texte en entrées numériques pour le réseau neuronal et la reconversion en texte lorsqu'elle est nécessaire. +Enfin, nous montrerons comment gérer l'envoi de plusieurs phrases à travers un modèle dans un batch préparé et nous conclurons le tout en examinant de plus près la fonction `tokenizer()`. + + +⚠️ Afin de bénéficier de toutes les fonctionnalités disponibles avec le Model Hub et le 🤗 *Transformers*, nous vous recommandons de créer un compte. + diff --git a/chapters/fr/chapter2/2.mdx b/chapters/fr/chapter2/2.mdx new file mode 100644 index 000000000..f53b1e891 --- /dev/null +++ b/chapters/fr/chapter2/2.mdx @@ -0,0 +1,344 @@ + + +# Derrière le pipeline + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + + +Il s'agit de la première section dont le contenu est légèrement différent selon que vous utilisez PyTorch ou TensorFlow. Cliquez sur le bouton situé au-dessus du titre pour sélectionner la plateforme que vous préférez ! + + +{#if fw === 'pt'} + +{:else} + +{/if} + +Commençons par un exemple complet en regardant ce qui s'est passé en coulisses lorsque nous avons exécuté le code suivant dans le [Chapitre 1](/course/chapter1) : + +```python +from transformers import pipeline + +classifier = pipeline("sentiment-analysis") +classifier( + [ + "I've been waiting for a HuggingFace course my whole life.", # J'ai attendu un cours de HuggingFace toute ma vie. + "I hate this so much!", # Je déteste tellement ça ! + ] +) +``` + +la sortie : + +```python out +[{'label': 'POSITIVE', 'score': 0.9598047137260437}, + {'label': 'NEGATIVE', 'score': 0.9994558095932007}] +``` + +Comme nous l'avons vu dans le [Chapitre 1](/course/fr/chapter1), ce pipeline regroupe trois étapes : le prétraitement, le passage des entrées dans le modèle et le post-traitement : + +
+The full NLP pipeline: tokenization of text, conversion to IDs, and inference through the Transformer model and the model head. + +
+ +Passons rapidement en revue chacun de ces éléments. + +## Prétraitement avec un *tokenizer* + +Comme d'autres réseaux de neurones, les *transformers* ne peuvent pas traiter directement le texte brut, donc la première étape de notre pipeline est de convertir les entrées textuelles en nombres afin que le modèle puisse les comprendre. Pour ce faire, nous utilisons un *tokenizer*, qui sera responsable de : +- diviser l'entrée en mots, sous-mots, ou symboles (comme la ponctuation) qui sont appelés *tokens*, +- associer chaque *token* à un nombre entier, +- ajouter des entrées supplémentaires qui peuvent être utiles au modèle. + +Tout ce prétraitement doit être effectué exactement de la même manière que celui appliqué lors du pré-entraînement du modèle. Nous devons donc d'abord télécharger ces informations depuis le [*Model Hub*](https://huggingface.co/models). Pour ce faire, nous utilisons la classe `AutoTokenizer` et sa méthode `from_pretrained()`. En utilisant le nom du *checkpoint* de notre modèle, elle va automatiquement récupérer les données associées au *tokenizer* du modèle et les mettre en cache (afin qu'elles ne soient téléchargées que la première fois que vous exécutez le code ci-dessous). + +Puisque le *checkpoint* par défaut du pipeline `sentiment-analysis` (analyse de sentiment) est `distilbert-base-uncased-finetuned-sst-2-english` (vous pouvez voir la carte de ce modèle [ici](https://huggingface.co/distilbert-base-uncased-finetuned-sst-2-english)), nous exécutons ce qui suit : + +```python +from transformers import AutoTokenizer + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +``` + +Une fois que nous avons le *tokenizer* nous pouvons lui passer directement nos phrases et obtenir un dictionnaire prêt à être donné à notre modèle ! La seule chose qui reste à faire est de convertir en tenseurs la liste des identifiants d'entrée. + +Vous pouvez utiliser 🤗 *Transformers* sans avoir à vous soucier du *framework* utilisé comme *backend*. Il peut s'agir de PyTorch, de TensorFlow ou de Flax pour certains modèles. Cependant, les *transformers* n'acceptent que les *tenseurs* en entrée. Si c'est la première fois que vous entendez parler de tenseurs, vous pouvez les considérer comme des tableaux NumPy. Un tableau NumPy peut être un scalaire (0D), un vecteur (1D), une matrice (2D), ou avoir davantage de dimensions. Les tenseurs des autres *frameworks* d'apprentissage machine se comportent de manière similaire et sont généralement aussi simples à instancier que les tableaux NumPy. + +Pour spécifier le type de tenseurs que nous voulons récupérer (PyTorch, TensorFlow, ou simplement NumPy), nous utilisons l'argument `return_tensors` : + +{#if fw === 'pt'} +```python +raw_inputs = [ + "I've been waiting for a HuggingFace course my whole life.", # J'ai attendu un cours de HuggingFace toute ma vie. + "I hate this so much!", # Je déteste tellement ça ! +] +inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="pt") +print(inputs) +``` +{:else} +```python +raw_inputs = [ + "I've been waiting for a HuggingFace course my whole life.", # J'ai attendu un cours de HuggingFace toute ma vie. + "I hate this so much!", # Je déteste tellement ça ! +] +inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="tf") +print(inputs) +``` +{/if} + +Ne vous préoccupez pas encore du remplissage (*padding*) et de la troncature, nous les expliquerons plus tard. Les principales choses à retenir ici sont que vous pouvez passer une phrase ou une liste de phrases, ainsi que spécifier le type de tenseurs que vous voulez récupérer (si aucun type n'est passé, par défaut vous obtiendrez une liste de listes comme résultat). + +{#if fw === 'pt'} + +Voici à quoi ressemblent les résultats sous forme de tenseurs PyTorch : + +```python out +{ + 'input_ids': tensor([ + [ 101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102], + [ 101, 1045, 5223, 2023, 2061, 2172, 999, 102, 0, 0, 0, 0, 0, 0, 0, 0] + ]), + 'attention_mask': tensor([ + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ]) +} +``` +{:else} + +Voici à quoi ressemblent les résultats sous forme de tenseurs TensorFlow : + +```python out +{ + 'input_ids': , + 'attention_mask': +} +``` +{/if} + +La sortie elle-même est un dictionnaire contenant deux clés : `input_ids` et `attention_mask`. `input_ids` contient deux lignes d'entiers (une pour chaque phrase) qui sont les identifiants uniques des *tokens* dans chaque phrase. Nous expliquerons ce qu'est l'`attention_mask` plus tard dans ce chapitre. + +## Passage au modèle + +{#if fw === 'pt'} +Nous pouvons télécharger notre modèle prétraîné de la même manière que nous l'avons fait avec notre *tokenizer*. 🤗 *Transformers* fournit une classe `AutoModel` qui possède également une méthode `from_pretrained()` : + +```python +from transformers import AutoModel + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = AutoModel.from_pretrained(checkpoint) +``` +{:else} +Nous pouvons télécharger notre modèle prétraîné de la même manière que nous l'avons fait avec notre *tokenizer*. 🤗 *Transformers* fournit une classe `TFAutoModel` qui possède également une méthode `from_pretrained()` : + +```python +from transformers import TFAutoModel + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = TFAutoModel.from_pretrained(checkpoint) +``` +{/if} + +Dans cet extrait de code, nous avons téléchargé le même *checkpoint* que nous avons utilisé dans notre pipeline auparavant (il devrait en fait avoir déjà été mis en cache) et instancié un modèle avec lui. + +Cette architecture ne contient que le module de *transformer* de base : étant donné certaines entrées, il produit ce que nous appellerons des *états cachés*,également connus sous le nom de *caractéristiques*. +Pour chaque entrée du modèle, nous récupérons un vecteur en grande dimension représentant la **compréhension contextuelle de cette entrée par le *transformer***. + +Si cela ne fait pas sens, ne vous inquiétez pas. Nous expliquons tout plus tard. + +Bien que ces états cachés puissent être utiles en eux-mêmes, ils sont généralement les entrées d'une autre partie du modèle, connue sous le nom de *tête*. Dans le [Chapitre 1](/course/fr/chapter1), les différentes tâches auraient pu être réalisées avec la même architecture mais en ayant chacune d'elles une tête différente. + +### Un vecteur de grande dimension ? + +Le vecteur produit en sortie par le *transformer* est généralement de grande dimension. Il a généralement trois dimensions : + +- **la taille du lot** : le nombre de séquences traitées à la fois (2 dans notre exemple), +- **la longueur de la séquence** : la longueur de la représentation numérique de la séquence (16 dans notre exemple), +- **la taille cachée** : la dimension du vecteur de chaque entrée du modèle. + +On dit qu'il est de « grande dimension » en raison de la dernière valeur. La taille cachée peut être très grande (généralement 768 pour les petits modèles et pour les grands modèles cela peut atteindre 3072 voire plus). + +Nous pouvons le constater si nous alimentons notre modèle avec les entrées que nous avons prétraitées : + + +{#if fw === 'pt'} +```python +outputs = model(**inputs) +print(outputs.last_hidden_state.shape) +``` + +```python out +torch.Size([2, 16, 768]) +``` +{:else} +```py +outputs = model(inputs) +print(outputs.last_hidden_state.shape) +``` + +```python out +(2, 16, 768) +``` +{/if} + +Notez que les sorties des modèles de la bibliothèque 🤗 Transformers se comportent comme des `namedtuples` ou des dictionnaires. Vous pouvez accéder aux éléments par attributs (comme nous l'avons fait), par clé (`outputs["last_hidden_state"]`), ou même par l’index si vous savez exactement où se trouve la chose que vous cherchez (`outputs[0]`). + +### Les têtes des modèles : donner du sens aux chiffres +Les têtes des modèles prennent en entrée le vecteur de grande dimension des états cachés et le projettent sur une autre dimension. Elles sont généralement composées d'une ou de quelques couches linéaires : +
+A Transformer network alongside its head. + +
+ +La sortie du *transformer* est envoyée directement à la tête du modèle pour être traitée. +Dans ce diagramme, le modèle est représenté par sa couche d’enchâssement et les couches suivantes. La couche d’enchâssement convertit chaque identifiant d'entrée dans l'entrée tokenisée en un vecteur qui représente le *token* associé. Les couches suivantes manipulent ces vecteurs en utilisant le mécanisme d'attention pour produire la représentation finale des phrases. +Il existe de nombreuses architectures différentes disponibles dans la bibliothèque 🤗 *Transformers*, chacune étant conçue autour de la prise en charge d'une tâche spécifique. En voici une liste non exhaustive : +- `*Model` (récupérer les états cachés) +- `*ForCausalLM` +- `*ForMaskedLM` +- `*ForMultipleChoice` +- `*ForQuestionAnswering` +- `*ForSequenceClassification` +- `*ForTokenClassification` +- et autres 🤗 + +{#if fw === 'pt'} +Pour notre exemple, nous avons besoin d'un modèle avec une tête de classification de séquence (pour pouvoir classer les phrases comme positives ou négatives). Donc, nous n'utilisons pas réellement la classe `AutoModel` mais plutôt `AutoModelForSequenceClassification` : +```python +from transformers import AutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) +outputs = model(**inputs) +``` +{:else} +Pour notre exemple, nous avons besoin d'un modèle avec une tête de classification de séquence (pour pouvoir classer les phrases comme positives ou négatives). Donc, nous n'utilisons pas réellement la classe ` TFAutoModel` mais plutôt ` TFAutoModelForSequenceClassification` : +```python +from transformers import TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) +outputs = model(inputs) +``` +{/if} + +Maintenant, si nous examinons la forme de nos entrées, la dimensionnalité est beaucoup plus faible. La tête du modèle prend en entrée les vecteurs de grande dimension que nous avons vus précédemment et elle produit des vecteurs contenant deux valeurs (une par étiquette) : +```python +print(outputs.logits.shape) +``` + +{#if fw === 'pt'} +```python out +torch.Size([2, 2]) +``` +{:else} +```python out +(2, 2) +``` +{/if} + +Comme nous n'avons que deux phrases et deux étiquettes, le résultat que nous obtenons est de forme 2 x 2 + +## Post-traitement de la sortie + +Les valeurs que nous obtenons en sortie de notre modèle n'ont pas nécessairement de sens en elles-mêmes. Jetons-y un coup d'oeil : + +```python +print(outputs.logits) +``` + +{#if fw === 'pt'} +```python out +tensor([[-1.5607, 1.6123], + [ 4.1692, -3.3464]], grad_fn=) +``` +{:else} +```python out + +``` +{/if} + +Notre modèle a prédit `[-1.5607, 1.6123]` pour la première phrase et `[ 4.1692, -3.3464]` pour la seconde. Ce ne sont pas des probabilités mais des *logits*, les scores bruts, non normalisés, produits par la dernière couche du modèle. Pour être convertis en probabilités, ils doivent passer par une couche [SoftMax](https://fr.wikipedia.org/wiki/Fonction_softmax) (tous les modèles de la bibliotèque 🤗 Transformers sortent les logits car la fonction de perte de l'entraînement fusionne généralement la dernière fonction d'activation, comme la SoftMax, avec la fonction de perte réelle, comme l'entropie croisée) : + +{#if fw === 'pt'} +```py +import torch + +predictions = torch.nn.functional.softmax(outputs.logits, dim=-1) +print(predictions) +``` +{:else} +```py +import tensorflow as tf + +predictions = tf.math.softmax(outputs.logits, axis=-1) +print(predictions) +``` +{/if} + +{#if fw === 'pt'} +```python out +tensor([[4.0195e-02, 9.5980e-01], + [9.9946e-01, 5.4418e-04]], grad_fn=) +``` +{:else} +```python out +tf.Tensor( +[[4.01951671e-02 9.59804833e-01] + [9.9945587e-01 5.4418424e-04]], shape=(2, 2), dtype=float32) +``` +{/if} + +Maintenant nous pouvons voir que le modèle a prédit `[0.0402, 0.9598]` pour la première phrase et `[0.9995, 0.0005]` pour la seconde. Ce sont des scores de probabilité reconnaissables. + +Pour obtenir les étiquettes correspondant à chaque position, nous pouvons inspecter l'attribut `id2label` de la configuration du modèle (plus de détails dans la section suivante) : + +```python +model.config.id2label +``` + +```python out +{0: 'NEGATIVE', 1: 'POSITIVE'} +``` + +Nous pouvons maintenant conclure que le modèle a prédit ce qui suit : + +- première phrase : NEGATIVE: 0.0402, POSITIVE: 0.9598 +- deuxième phrase : NEGATIVE: 0.9995, POSITIVE: 0.0005 + +Nous avons reproduit avec succès les trois étapes du pipeline : prétraitement avec les *tokenizers*, passage des entrées dans le modèle et post-traitement ! Prenons maintenant le temps de nous plonger plus profondément dans chacune de ces étapes. + + +✏️ **Essayez !** Choisissez deux (ou plus) textes de votre choix (en anglais) et faites-les passer par le pipeline `sentiment-analysis`. Reproduisez ensuite vous-même les étapes vues ici et vérifiez que vous obtenez les mêmes résultats ! + diff --git a/chapters/fr/chapter2/3.mdx b/chapters/fr/chapter2/3.mdx new file mode 100644 index 000000000..96e555191 --- /dev/null +++ b/chapters/fr/chapter2/3.mdx @@ -0,0 +1,231 @@ + + +# Les modèles + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +{#if fw === 'pt'} + +{:else} + +{/if} + +{#if fw === 'pt'} +Dans cette section, nous allons examiner de plus près la création et l'utilisation d'un modèle. Nous utiliserons la classe `AutoModel` qui est pratique lorsque vous voulez instancier n'importe quel modèle à partir d'un checkpoint. + +La classe `AutoModel` et toutes les classes apparentées sont en fait de simples *wrappers* sur la grande variété de modèles disponibles dans la bibliothèque. C'est une enveloppe intelligente car elle peut automatiquement deviner l'architecture appropriée pour votre *checkpoint* et ensuite instancier un modèle avec cette architecture. + +{:else} +Dans cette section, nous allons examiner de plus près la création et l'utilisation d'un modèle. Nous utiliserons la classe `TFAutoModel` qui est pratique lorsque vous voulez instancier n'importe quel modèle à partir d'un checkpoint. + +La classe `TFAutoModel` et toutes les classes apparentées sont en fait de simples *wrappers* sur la grande variété de modèles disponibles dans la bibliothèque. C'est une enveloppe intelligente car elle peut automatiquement deviner l'architecture appropriée pour votre *checkpoint* et ensuite instancier un modèle avec cette architecture. + +{/if} + +Cependant, si vous connaissez le type de modèle que vous voulez utiliser, vous pouvez utiliser directement la classe qui définit son architecture. Voyons comment cela fonctionne avec un modèle BERT. + +## Création d’un *transformer* + +La première chose que nous devons faire pour initialiser un modèle BERT est de charger un objet configuration : + +{#if fw === 'pt'} +```py +from transformers import BertConfig, BertModel + +# Construire la configuration +config = BertConfig() + +# Construire le modèle à partir de la configuration +model = BertModel(config) +``` +{:else} +```py +from transformers import BertConfig, TFBertModel + +# Construire la configuration +config = BertConfig() + +# Construire le modèle à partir de la configuration +model = TFBertModel(config) +``` +{/if} + +La configuration contient de nombreux attributs qui sont utilisés pour construire le modèle : +```py +print(config) +``` + +```python out +BertConfig { + [...] + "hidden_size": 768, + "intermediate_size": 3072, + "max_position_embeddings": 512, + "num_attention_heads": 12, + "num_hidden_layers": 12, + [...] +} +``` + +Bien que vous n'ayez pas encore vu ce que font tous ces attributs, vous devriez en reconnaître certains : l'attribut `hidden_size` définit la taille du vecteur `hidden_states`, et `num_hidden_layers` définit le nombre de couches que le *transformer* possède. + +### Différentes méthodes de chargement + +Un modèle créé à partir de la configuration par défaut est initialisé avec des valeurs aléatoires : + + +{#if fw === 'pt'} +```py +from transformers import BertConfig, BertModel + +config = BertConfig() +model = BertModel(config) + +# Le modèle est initialisé de façon aléatoire ! +``` +{:else} +```py +from transformers import BertConfig, TFBertModel + +config = BertConfig() +model = TFBertModel(config) + +# Le modèle est initialisé de façon aléatoire ! +``` +{/if} + +Le modèle peut être utilisé tel quel mais il produira du charabia. En effet, il doit d'abord être entraîné. Nous pourrions entraîner le modèle à partir de zéro sur la tâche qui nous intéresse mais comme vous l'avez vu dans le [Chapitre 1](/course/fr/chapter1) cela nécessiterait beaucoup de temps et de données. De plus cela aurait un impact environnemental non négligeable. Pour éviter les efforts inutiles et redondants, il est impératif de pouvoir partager et réutiliser les modèles qui ont déjà été entraînés. + +Charger un *transformer* qui a déjà été entraîné est simple : nous pouvons le faire en utilisant la méthode `from_pretrained()` : + + +{#if fw === 'pt'} +```py +from transformers import BertModel + +model = BertModel.from_pretrained("bert-base-cased") +``` + +Comme vu précédemment, nous pouvons remplacer `BertModel` par la classe équivalente `AutoModel`. A partir de maintenant nous ferons cela car cela produit un code agnostique *checkpoint*, c’est-à-dire que si votre code fonctionne pour un *checkpoint* donné, il devrait fonctionner sans problème avec un autre. Cela s'applique même si l'architecture est différente du moment que le *checkpoint* a été entraîné pour une tâche similaire (par exemple, une tâche d'analyse de sentiments). + +{:else} +```py +from transformers import TFBertModel + +model = TFBertModel.from_pretrained("bert-base-cased") +``` + +Comme vu précédemment, nous pouvons remplacer `TFBertModel` par la classe équivalente `TFAutoModel`. A partir de maintenant nous ferons cela car cela produit un code agnostique *checkpoint*, c’est-à-dire que si votre code fonctionne pour un *checkpoint* donné, il devrait fonctionner sans problème avec un autre. Cela s'applique même si l'architecture est différente du moment que le *checkpoint* a été entraîné pour une tâche similaire (par exemple, une tâche d'analyse de sentiments). + +{/if} + +Dans l'exemple de code ci-dessus, nous n'avons pas utilisé `BertConfig` et avons à la place chargé un modèle pré-entraîné via l'identifiant `bert-base-cased`. Il s'agit d'un *checkpoint* qui a été entraîné par les auteurs de BERT eux-mêmes. Vous pouvez trouver davantage de détails à son sujet dans la [fiche du modèle](https://huggingface.co/bert-base-cased). + +Ce modèle est maintenant initialisé avec tous les poids du *checkpoint*. Il peut être utilisé directement pour l'inférence sur les tâches sur lesquelles il a été entraîné. Il peut également être *finetuné* sur une nouvelle tâche. En entraînant avec des poids pré-entraînés plutôt qu'à partir de zéro, nous pouvons rapidement obtenir de bons résultats. + +Les poids ont été téléchargés et mis en cache (afin que les futurs appels à la méthode `from_pretrained()` ne les retéléchargent pas) dans le dossier cache, qui est par défaut *~/.cache/huggingface/transformers*. Vous pouvez personnaliser votre dossier de cache en définissant la variable d'environnement `HF_HOME`. + +L'identifiant utilisé pour charger le modèle peut être l'identifiant de n'importe quel modèle sur le *Model Hub* du moment qu'il est compatible avec l'architecture BERT. La liste complète des *checkpoints* de BERT disponibles peut être trouvée [ici](https://huggingface.co/models?filter=bert). + +### Méthodes de sauvegarde + +Sauvegarder un modèle est aussi facile que d'en charger un. Nous utilisons la méthode `save_pretrained()`, qui est analogue à la méthode `from_pretrained()` : + + +```py +model.save_pretrained("directory_on_my_computer") +``` + +Cela enregistre deux fichiers sur votre disque : + +{#if fw === 'pt'} +``` +ls directory_on_my_computer + +config.json pytorch_model.bin +``` +{:else} +``` +ls directory_on_my_computer + +config.json tf_model.h5 +``` +{/if} + +Si vous jetez un coup d'œil au fichier *config.json*, vous reconnaîtrez les attributs nécessaires pour construire l'architecture du modèle. Ce fichier contient également certaines métadonnées, comme l'origine du *checkpoint* et la version de la bibliothèque 🤗 *Transformers* que vous utilisiez lors du dernier enregistrement du point *checkpoint*. + +{#if fw === 'pt'} +Le fichier *pytorch_model.bin* est connu comme le *dictionnaire d'état*. Il contient tous les poids de votre modèle. Les deux fichiers vont de pair : la configuration est nécessaire pour connaître l'architecture de votre modèle, tandis que les poids du modèle sont les paramètres de votre modèle. + +{:else} +Le fichier *tf_model.h5* est connu comme le *dictionnaire d'état*. Il contient tous les poids de votre modèle. Les deux fichiers vont de pair : la configuration est nécessaire pour connaître l'architecture de votre modèle, tandis que les poids du modèle sont les paramètres de votre modèle. + +{/if} + +### Utilisation d'un *transformer* pour l'inférence + +Maintenant que vous savez comment charger et sauvegarder un modèle, essayons de l'utiliser pour faire quelques prédictions. Les *transformers* ne peuvent traiter que des nombres. Des nombres que le *tokenizer* génère. Mais avant de parler des *tokenizers*, explorons les entrées que le modèle accepte. + +Les *tokenizers* se chargent de passer les entrées vers les tenseurs du *framework* approprié. Pour vous aider à comprendre ce qui se passe, jetons un coup d'œil rapide à ce qui doit être fait avant d'envoyer les entrées au modèle. + +Disons que nous avons les séquences suivantes : + + +```py +sequences = ["Hello!", "Cool.", "Nice!"] +``` + +Le *tokenizer* les convertit en indices de vocabulaire qui sont généralement appelés *input IDs*. Chaque séquence est maintenant une liste de nombres ! La sortie résultante est : + +```py no-format +encoded_sequences = [ + [101, 7592, 999, 102], + [101, 4658, 1012, 102], + [101, 3835, 999, 102], +] +``` + +Il s'agit d'une liste de séquences encodées : une liste de listes. Les tenseurs n'acceptent que des formes rectangulaires (pensez aux matrices). Ce « tableau » est déjà de forme rectangulaire, donc le convertir en tenseur est facile : + +{#if fw === 'pt'} +```py +import torch + +model_inputs = torch.tensor(encoded_sequences) +``` +{:else} +```py +import tensorflow as tf + +model_inputs = tf.constant(encoded_sequences) +``` +{/if} + +### Utilisation des tenseurs comme entrées du modèle + +L'utilisation des tenseurs avec le modèle est extrêmement simple, il suffit d'appeler le modèle avec les entrées : + + +```py +output = model(model_inputs) +``` + +Bien que le modèle accepte un grand nombre d'arguments différents, seuls les identifiants d'entrée sont nécessaires. Nous expliquerons plus tard ce que font les autres arguments et quand ils sont nécessaires. Avant cela, regardons de plus près les *tokenizers*, cet outil qui construit les entrées qu'un *transformer* peut comprendre. diff --git a/chapters/fr/chapter2/4.mdx b/chapters/fr/chapter2/4.mdx new file mode 100644 index 000000000..a8fb7e3e7 --- /dev/null +++ b/chapters/fr/chapter2/4.mdx @@ -0,0 +1,253 @@ + + +# Les *tokenizers* + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + + + +Les *tokenizers* sont l'un des principaux composants du pipeline de NLP. Ils ont un seul objectif : traduire le texte en données pouvant être traitées par le modèle. Les modèles ne pouvant traiter que des nombres, les *tokenizers* doivent convertir nos entrées textuelles en données numériques. Dans cette section, nous allons explorer ce qui se passe exactement dans le pipeline de tokénisation. + +Dans les tâches de NLP, les données traitées sont généralement du texte brut. Voici un exemple de ce type de texte : + + +``` +Jim Henson was a puppeteer # Jim Henson était un marionnettiste. +``` + +Les modèles ne pouvant traiter que des nombres, nous devons trouver un moyen de convertir le texte brut en nombres. C'est ce que font les *tokenizers* et il existe de nombreuses façons de procéder. L'objectif est de trouver la représentation la plus significative, c'est-à-dire celle qui a le plus de sens pour le modèle, et si possible qui soit la plus petite. + +Voyons quelques exemples d'algorithmes de tokénisation et essayons de répondre à certaines des questions que vous pouvez vous poser à ce sujet. + +## *Tokenizer* basé sur les mots + + + + +Le premier type de *tokenizer* qui vient à l'esprit est celui basé sur les mots. Il est généralement très facile à utiliser et configurable avec seulement quelques règles. Il donne souvent des résultats décents. Par exemple, dans l'image ci-dessous, l'objectif est de diviser le texte brut en mots et de trouver une représentation numérique pour chacun d'eux : + +
+ An example of word-based tokenization. + +
+ +Il existe différentes façons de diviser le texte. Par exemple, nous pouvons utiliser les espaces pour segmenter le texte en mots en appliquant la fonction `split()` de Python : + +```py +tokenized_text = "Jim Henson was a puppeteer".split() +print(tokenized_text) +``` + +```python out +['Jim', 'Henson', 'was', 'a', 'puppeteer'] # ['Jim', 'Henson', était, 'un', 'marionnettiste'] +``` + +Il existe également des variantes des *tokenizers* basés sur les mots qui ont des règles supplémentaires pour la ponctuation. Avec ce type de *tokenizers* nous pouvons nous retrouver avec des « vocabulaires » assez larges, où un vocabulaire est défini par le nombre total de *tokens* indépendants que nous avons dans notre corpus. + +Un identifiant est attribué à chaque mot, en commençant par 0 et en allant jusqu'à la taille du vocabulaire. Le modèle utilise ces identifiants pour identifier chaque mot. + +Si nous voulons couvrir complètement une langue avec un *tokenizer* basé sur les mots, nous devons avoir un identifiant pour chaque mot de la langue que nous traitons, ce qui génére une énorme quantité de *tokens*. Par exemple, il y a plus de 500 000 mots dans la langue anglaise. Ainsi pour associer chaque mot à un identifiant, nous devrions garder la trace d'autant d'identifiants. De plus, des mots comme « chien » sont représentés différemment de mots comme « chiens ». Le modèle n'a initialement aucun moyen de savoir que « chien » et « chiens » sont similaires : il identifie les deux mots comme non apparentés. Il en va de même pour d'autres mots similaires, comme « maison » et « maisonnette » que le modèle ne considérera pas comme similaires au départ. + +Enfin, nous avons besoin d'un *token* personnalisé pour représenter les mots qui ne font pas partie de notre vocabulaire. C'est ce qu'on appelle le *token* « inconnu » souvent représenté par « [UNK] » (de l’anglais « unknown ») ou « <unk> ; ». C'est généralement un mauvais signe si vous constatez que le *tokenizer* produit un nombre important de ce jeton spécial. Cela signifie qu’il n'a pas été en mesure de récupérer une représentation sensée d'un mot et que vous perdez des informations en cours de route. L'objectif de l'élaboration du vocabulaire est de faire en sorte que le *tokenizer* transforme le moins de mots possible en *token* inconnu. + +Une façon de réduire la quantité de *tokens* inconnus est d'aller un niveau plus profond, en utilisant un *tokenizer* basé sur les caractères. + + +## *Tokenizer* basé sur les caractères + + + +Les *tokenizers* basés sur les caractères divisent le texte en caractères, plutôt qu'en mots. Cela présente deux avantages principaux : + +- le vocabulaire est beaucoup plus petit +- il y a beaucoup moins de *tokens* hors vocabulaire (inconnus) puisque chaque mot peut être construit à partir de caractères. + +Mais là aussi, des questions se posent concernant les espaces et la ponctuation : + + +
+ An example of character-based tokenization. + +
+ +Cette approche n'est pas non plus parfaite. Puisque la représentation est maintenant basée sur des caractères plutôt que sur des mots, on pourrait dire intuitivement qu’elle est moins significative : chaque caractère ne signifie pas grand-chose en soi, alors que c'est le cas pour les mots. Toutefois, là encore, cela diffère selon la langue. En chinois, par exemple, chaque caractère est porteur de plus d'informations qu'un caractère dans une langue latine. + +Un autre élément à prendre en compte est que nous nous retrouverons avec une très grande quantité de *tokens* à traiter par notre modèle. Alors qu’avec un *tokenizer* basé sur les mots, pour un mot donné on aurait qu'un seul *token*, avec un *tokenizer* basé sur les caractères, cela peut facilement se transformer en 10 *tokens* voire plus. + +Pour obtenir le meilleur des deux mondes, nous pouvons utiliser une troisième technique qui combine les deux approches : la *tokénisation en sous-mots*. + + +## Tokénisation en sous-mots + + + +Les algorithmes de tokenisation en sous-mots reposent sur le principe selon lequel les mots fréquemment utilisés ne doivent pas être divisés en sous-mots plus petits, mais les mots rares doivent être décomposés en sous-mots significatifs. + +Par exemple, le mot « maisonnette » peut être considéré comme un mot rare et peut être décomposé en « maison » et « ette ». Ces deux mots sont susceptibles d'apparaître plus fréquemment en tant que sous-mots autonomes, alors qu'en même temps le sens de « maison » est conservé par le sens composite de « maison » et « ette ». + +Voici un exemple montrant comment un algorithme de tokenisation en sous-mots tokeniserait la séquence « Let's do tokenization ! » : + + +
+ A subword tokenization algorithm. + +
+ +Ces sous-mots finissent par fournir beaucoup de sens sémantique. Par exemple, ci-dessus, « tokenization » a été divisé en « token » et « ization » : deux *tokens* qui ont un sens sémantique tout en étant peu encombrants (seuls deux *tokens* sont nécessaires pour représenter un long mot). Cela nous permet d'avoir une couverture relativement bonne avec de petits vocabulaires et presque aucun *token* inconnu. + +Cette approche est particulièrement utile dans les langues agglutinantes comme le turc, où l'on peut former des mots complexes (presque) arbitrairement longs en enchaînant des sous-mots. + + +### Et plus encore ! + +Il existe de nombreuses autres techniques. Pour n'en citer que quelques-unes : + +- le Byte-level BPE utilisé par exemple dans le GPT-2 +- le WordPiece utilisé par exemple dans BERT +- SentencePiece ou Unigram, utilisés dans plusieurs modèles multilingues. + +Vous devriez maintenant avoir une connaissance suffisante du fonctionnement des tokenizers pour commencer à utiliser l'API. + + +## Chargement et sauvegarde + +Le chargement et la sauvegarde des *tokenizers* est aussi simple que pour les modèles. En fait, c'est basé sur les deux mêmes méthodes : `from_pretrained()` et `save_pretrained()`. Ces méthodes vont charger ou sauvegarder l'algorithme utilisé par le *tokenizer* (un peu comme l'*architecture* du modèle) ainsi que son vocabulaire (un peu comme les *poids* du modèle). + +Le chargement du *tokenizer* de BERT entraîné avec le même *checkpoint* que BERT se fait de la même manière que le chargement du modèle, sauf que nous utilisons la classe `BertTokenizer` : + + +```py +from transformers import BertTokenizer + +tokenizer = BertTokenizer.from_pretrained("bert-base-cased") +``` + +{#if fw === 'pt'} +Similaire à `AutoModel`, la classe `AutoTokenizer` récupère la classe de *tokenizer* appropriée dans la bibliothèque basée sur le nom du *checkpoint*. Elle peut être utilisée directement avec n'importe quel *checkpoint* : + +{:else} +Similaire à `TFAutoModel`, la classe `AutoTokenizer` récupère la classe de *tokenizer* appropriée dans la bibliothèque basée sur le nom du *checkpoint*. Elle peut être utilisée directement avec n'importe quel *checkpoint* : + +{/if} + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +``` + +Nous pouvons à présent utiliser le *tokenizer* comme indiqué dans la section précédente : + +```python +tokenizer("Using a Transformer network is simple") +``` + +```python out +{'input_ids': [101, 7993, 170, 11303, 1200, 2443, 1110, 3014, 102], + 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0], + 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]} +``` + +La sauvegarde d'un tokenizer est identique à celle d'un modèle : + +```py +tokenizer.save_pretrained("directory_on_my_computer") +``` + +Nous parlerons plus en détail des `token_type_ids` au [Chapitre 3](/course/fr/chapter3) et nous expliquerons la clé `attention_mask` un peu plus tard. Tout d'abord, voyons comment les `input_ids` sont générés. Pour ce faire, nous devons examiner les méthodes intermédiaires du *tokenizer*. + +## Encodage + + + + +La traduction d'un texte en chiffres est connue sous le nom d’*encodage*. L'encodage se fait en deux étapes : la tokenisation, suivie de la conversion en identifiants d'entrée. + +Comme nous l'avons vu, la première étape consiste à diviser le texte en mots (ou parties de mots, symboles de ponctuation, etc.), généralement appelés *tokens*. De nombreuses règles peuvent régir ce processus. C'est pourquoi nous devons instancier le *tokenizer* en utilisant le nom du modèle afin de nous assurer que nous utilisons les mêmes règles que celles utilisées lors du pré-entraînement du modèle. + +La deuxième étape consiste à convertir ces *tokens* en nombres afin de construire un tenseur à partir de ceux-ci ainsi que de les transmettre au modèle. Pour ce faire, le *tokenizer* possède un *vocabulaire*, qui est la partie que nous téléchargeons lorsque nous l'instancions avec la méthode `from_pretrained()`. Encore une fois, nous devons utiliser le même vocabulaire que celui utilisé lors du pré-entraînement du modèle. + +Pour mieux comprendre les deux étapes, nous allons les explorer séparément. A noter que nous utilisons des méthodes effectuant séparément des parties du pipeline de tokenisation afin de montrer les résultats intermédiaires de ces étapes. Néanmoins, en pratique, il faut appeler le *tokenizer* directement sur vos entrées (comme indiqué dans la section 2). + +### Tokenisation + +Le processus de tokenisation est effectué par la méthode `tokenize()` du *tokenizer* : + + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") + +sequence = "Using a Transformer network is simple" +tokens = tokenizer.tokenize(sequence) + +print(tokens) +``` + +La sortie de cette méthode est une liste de chaînes de caractères ou de *tokens* : + +```python out +['Using', 'a', 'transform', '##er', 'network', 'is', 'simple'] +``` + +Ce *tokenizer* est un *tokenizer* de sous-mots : il découpe les mots jusqu'à obtenir des *tokens* qui peuvent être représentés par son vocabulaire. C'est le cas ici avec `transformer` qui est divisé en deux *tokens* : `transform` et `##er`. + +### De *tokens* aux identifiants d'entrée + +La conversion en identifiants d'entrée est gérée par la méthode `convert_tokens_to_ids()` du *tokenizer* : + + +```py +ids = tokenizer.convert_tokens_to_ids(tokens) + +print(ids) +``` + +```python out +[7993, 170, 11303, 1200, 2443, 1110, 3014] +``` + +Une fois converties en tenseur dans le *framework* approprié, ces sorties peuvent ensuite être utilisées comme entrées d'un modèle, comme nous l'avons vu précédemment dans ce chapitre. + + + +✏️ **Essayez !** Reproduisez les deux dernières étapes (tokénisation et conversion en identifiants d'entrée) sur les phrases des entrées que nous avons utilisées dans la section 2 (« I've been waiting for a HuggingFace course my whole life. » et « I hate this so much! »). Vérifiez que vous obtenez les mêmes identifiants d'entrée que nous avons obtenus précédemment ! + + + +## Décodage + +Le *décodage* va dans l'autre sens : à partir d'indices du vocabulaire nous voulons obtenir une chaîne de caractères. Cela peut être fait avec la méthode `decode()` comme suit : + + +```py +decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014]) +print(decoded_string) +``` + +```python out +'Using a Transformer network is simple' +``` + +Notez que la méthode `decode` non seulement reconvertit les indices en *tokens* mais regroupe également les *tokens* faisant partie des mêmes mots. Le but étant de produire une phrase lisible. Ce comportement sera extrêmement utile lorsque dans la suite du cours nous utiliserons des modèles pouvant produire du nouveau texte (soit du texte généré à partir d'un *prompt*, soit pour des problèmes de séquence à séquence comme la traduction ou le résumé de texte). + +Vous devriez maintenant comprendre les opérations atomiques qu'un *tokenizer* peut gérer : tokenisation, conversion en identifiants, et reconversion des identifiants en chaîne de caractères. Cependant, nous n'avons fait qu'effleurer la partie émergée de l'iceberg. Dans la section suivante, nous allons pousser notre approche jusqu'à ses limites et voir comment les surmonter. diff --git a/chapters/fr/chapter2/5.mdx b/chapters/fr/chapter2/5.mdx new file mode 100644 index 000000000..ab3b90b1e --- /dev/null +++ b/chapters/fr/chapter2/5.mdx @@ -0,0 +1,351 @@ + + +# Manipulation de plusieurs séquences + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +{#if fw === 'pt'} + +{:else} + +{/if} + +Dans la section précédente, nous avons exploré le cas d'utilisation le plus simple : faire une inférence sur une seule séquence de petite longueur. Cependant, certaines questions émergent déjà : + +- comment gérer de plusieurs séquences ? +- comment gérer de plusieurs séquences *de longueurs différentes* ? +- les indices du vocabulaire sont-ils les seules entrées qui permettent à un modèle de bien fonctionner ? +- existe-t-il une séquence trop longue ? + +Voyons quels types de problèmes ces questions posent et comment nous pouvons les résoudre en utilisant l'API 🤗 *Transformers*. + +## Les modèles attendent un batch d'entrées + +Dans l'exercice précédent, vous avez vu comment les séquences sont traduites en listes de nombres. +Convertissons cette liste de nombres en un tenseur et envoyons-le au modèle : + +{#if fw === 'pt'} +```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." # J'ai attendu un cours d’HuggingFace toute ma vie. + +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) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." # J'ai attendu un cours d’HuggingFace toute ma vie. + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) +input_ids = tf.constant(ids) +# This line will fail. +model(input_ids) +``` + +```py out +InvalidArgumentError: Input to reshape is a tensor with 14 values, but the requested shape has 196 [Op:Reshape] +``` +{/if} + +Pourquoi cela a échoué ? Nous avons suivi les étapes du pipeline de la section 2. + +Le problème est que nous avons envoyé une seule séquence au modèle, alors que les modèles de l’API 🤗 *Transformers* attendent plusieurs phrases par défaut. Ici, nous avons essayé de faire ce que le *tokenizer* fait en coulisses lorsque nous l'avons appliqué à une `séquence`. Cependant si vous regardez de près, vous verrez qu'il n'a pas seulement converti la liste des identifiants d'entrée en un tenseur mais aussi ajouté une dimension par-dessus : + + +{#if fw === 'pt'} +```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]]) +``` +{:else} +```py +tokenized_inputs = tokenizer(sequence, return_tensors="tf") +print(tokenized_inputs["input_ids"]) +``` + +```py out + +``` +{/if} + +Essayons à nouveau en ajoutant une nouvelle dimension : + +{#if fw === 'pt'} +```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." # J'ai attendu un cours d’HuggingFace toute ma vie. + + +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) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." +# J'ai attendu un cours d’HuggingFace toute ma vie. + + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) + +input_ids = tf.constant([ids]) +print("Input IDs:", input_ids) + +output = model(input_ids) +print("Logits:", output.logits) +``` +{/if} + +Nous affichons les identifiants d'entrée ainsi que les logits résultants. Voici la sortie : + +{#if fw === 'pt'} +```python out +Input IDs: [[ 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012]] +Logits: [[-2.7276, 2.8789]] +``` +{:else} +```py out +Input IDs: tf.Tensor( +[[ 1045 1005 2310 2042 3403 2005 1037 17662 12172 2607 2026 2878 + 2166 1012]], shape=(1, 14), dtype=int32) +Logits: tf.Tensor([[-2.7276208 2.8789377]], shape=(1, 2), dtype=float32) +``` +{/if} + +Le « *batching* » est l'acte d'envoyer plusieurs phrases à travers le modèle, toutes en même temps. Si vous n'avez qu'une seule phrase, vous pouvez simplement construire un batch avec une seule séquence : + +``` +batched_ids = [ids, ids] +``` + +Il s'agit d'un batch de deux séquences identiques ! + + + +✏️ **Essayez !** Convertissez cette liste `batched_ids` en un tenseur et passez-la dans votre modèle. Vérifiez que vous obtenez les mêmes logits que précédemment (mais deux fois) ! + + + +Utiliser des *batchs* permet au modèle de fonctionner lorsque vous lui donnez plusieurs séquences. Utiliser plusieurs séquences est aussi simple que de construire un batch avec une seule séquence. Il y a cependant un deuxième problème. Lorsque vous essayez de regrouper deux phrases (ou plus), elles peuvent être de longueurs différentes. Si vous avez déjà travaillé avec des tenseurs, vous savez qu'ils doivent être de forme rectangulaire. Vous ne pourrez donc pas convertir directement la liste des identifiants d'entrée en un tenseur. Pour contourner ce problème, nous avons l'habitude de *rembourrer* (le *padding* en anglais) les entrées. + +## *Padding* des entrées + +La liste de listes suivante ne peut pas être convertie en un tenseur : + + +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200] +] +``` + +Afin de contourner ce problème, nous utilisons le *padding* pour que nos tenseurs aient une forme rectangulaire. Le *padding* permet de s'assurer que toutes nos phrases ont la même longueur en ajoutant un mot spécial appelé *padding token* aux phrases ayant moins de valeurs. Par exemple, si vous avez 10 phrases de 10 mots et 1 phrase de 20 mots, le *padding* fait en sorte que toutes les phrases aient 20 mots. Dans notre exemple, le tenseur résultant ressemble à ceci : + +```py no-format +padding_id = 100 + +batched_ids = [ + [200, 200, 200], + [200, 200, padding_id], +] +``` + +L'identifiant du jeton de padding peut être trouvé dans `tokenizer.pad_token_id`. Utilisons-le et envoyons nos deux phrases à travers le modèle premièrement individuellement puis en étant mises dans un même batch : + +{#if fw === 'pt'} +```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=) +tensor([[ 0.5803, -0.4125]], grad_fn=) +tensor([[ 1.5694, -1.3895], + [ 1.3373, -1.2163]], grad_fn=) +``` +{:else} +```py no-format +model = TFAutoModelForSequenceClassification.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(tf.constant(sequence1_ids)).logits) +print(model(tf.constant(sequence2_ids)).logits) +print(model(tf.constant(batched_ids)).logits) +``` + +```py out +tf.Tensor([[ 1.5693678 -1.3894581]], shape=(1, 2), dtype=float32) +tf.Tensor([[ 0.5803005 -0.41252428]], shape=(1, 2), dtype=float32) +tf.Tensor( +[[ 1.5693681 -1.3894582] + [ 1.3373486 -1.2163193]], shape=(2, 2), dtype=float32) +``` +{/if} + +Il y a quelque chose qui ne va pas avec les logits de notre prédiction avec les séquences mises dans un même batch. La deuxième ligne devrait être la même que les logits pour la deuxième phrase, mais nous avons des valeurs complètement différentes ! + +C'est parce que dans un *transformer* les couches d’attention *contextualisent* chaque *token*. Celles-ci prennent en compte les *tokens* de *padding* puisqu'elles analysent tous les *tokens* d'une séquence. Pour obtenir le même résultat lorsque l'on passe dans notre modèle des phrases individuelles de différentes longueurs ou un batch composé de mêmes phrases avec *padding*, nous devons dire à ces couches d'attention d'ignorer les jetons de *padding*. Ceci est fait en utilisant un masque d'attention. + + +## Masques d'attention + +Les masques d'attention sont des tenseurs ayant exactement la même forme que le tenseur d'identifiants d'entrée, remplis de 0 et de 1 : +- 1 indique que les *tokens* correspondants doivent être analysés +- 0 indique que les *tokens* correspondants ne doivent pas être analysés (c'est-à-dire qu'ils doivent être ignorés par les couches d'attention du modèle). + +Complétons l'exemple précédent avec un masque d'attention : + + +{#if fw === 'pt'} +```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=) +``` +{:else} +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200, tokenizer.pad_token_id], +] + +attention_mask = [ + [1, 1, 1], + [1, 1, 0], +] + +outputs = model(tf.constant(batched_ids), attention_mask=tf.constant(attention_mask)) +print(outputs.logits) +``` + +```py out +tf.Tensor( +[[ 1.5693681 -1.3894582 ] + [ 0.5803021 -0.41252586]], shape=(2, 2), dtype=float32) +``` +{/if} + +Nous obtenons maintenant les mêmes logits pour la deuxième phrase du batch. + +Remarquez comment la dernière valeur de la deuxième séquence est un identifiant de *padding* valant 0 dans le masque d'attention. + + + + +✏️ **Essayez !** Appliquez la tokénisation manuellement sur les deux phrases utilisées dans la section 2 (« I've been waiting for a HuggingFace course my whole life. » et « I hate this so much! »). Passez-les dans le modèle et vérifiez que vous obtenez les mêmes logits que dans la section 2. Ensuite regroupez-les en utilisant le jeton de *padding* et créez le masque d'attention approprié. Vérifiez que vous obtenez les mêmes résultats qu’en passant par le modèle ! + + + + +## Séquences plus longues + +Les *transformers* acceptent en entrée que des séquences d’une longueur limitée. La plupart des modèles traitent des séquences allant jusqu'à 512 ou 1024 *tokens* et plantent lorsqu'on leur demande de traiter des séquences plus longues. Il existe deux solutions à ce problème : + +- utiliser un modèle avec une longueur de séquence supportée plus longue, +- tronquer les séquences. + +Certains modèles sont spécialisés dans le traitement de très longues séquences comme par exemple le [Longformer](https://huggingface.co/transformers/model_doc/longformer.html) ou le [LED](https://huggingface.co/transformers/model_doc/led.html). Si vous travaillez sur une tâche qui nécessite de très longues séquences, nous vous recommandons de jeter un coup d'œil à ces modèles. + +Sinon, nous vous recommandons de tronquer vos séquences en spécifiant le paramètre `max_sequence_length` : + + +```py +sequence = sequence[:max_sequence_length] +``` diff --git a/chapters/fr/chapter2/6.mdx b/chapters/fr/chapter2/6.mdx new file mode 100644 index 000000000..f43edef28 --- /dev/null +++ b/chapters/fr/chapter2/6.mdx @@ -0,0 +1,186 @@ + + +# Tout assembler + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +Dans les dernières sections, nous avons fait de notre mieux pour effectuer la plupart du travail manuellement. Nous avons exploré le fonctionnement des *tokenizers* et examiné la tokenisation, la conversion en identifiants d'entrée, le *padding*, la troncature et les masques d'attention. + +Cependant, comme nous l'avons vu dans la section 2, l'API 🤗 *Transformers* peut gérer tout cela pour nous via une fonction dans laquelle nous allons nous plonger ici. Lorsque vous appelez votre `tokenizer` directement sur la phrase, vous récupérez des entrées qui sont prêtes à être passées dans votre modèle : + + +```py +from transformers import AutoTokenizer + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." # J'ai attendu un cours d’HuggingFace toute ma vie. + +model_inputs = tokenizer(sequence) +``` + +Ici, la variable `model_inputs` contient tout ce qui est nécessaire au bon fonctionnement d'un modèle. Pour DistilBERT, cela inclut les identifiants d'entrée ainsi que le masque d'attention. D'autres modèles qui acceptent des entrées supplémentaires sont également fournis par l'objet `tokenizer`. + +Comme nous allons le voir dans les quelques exemples ci-dessous, cette méthode est très puissante. Premièrement, elle peut tokeniser une seule séquence : + + +```py +sequence = "I've been waiting for a HuggingFace course my whole life." # J'ai attendu un cours d’HuggingFace toute ma vie. + + +model_inputs = tokenizer(sequence) +``` + +Elle gère également plusieurs séquences à la fois, sans modification de l'API : + + +```py +sequences = [ + "I've been waiting for a HuggingFace course my whole life.", + "So have I!", +] # « J'ai attendu un cours de HuggingFace toute ma vie. », « Moi aussi ! » + +model_inputs = tokenizer(sequences) +``` + +Il est possible de faire du *padding* selon plusieurs objectifs : + +```py +# Remplit les séquences jusqu'à la longueur maximale de la séquence +model_inputs = tokenizer(sequences, padding="longest") + +# Remplit les séquences jusqu'à la longueur maximale du modèle +# (512 for BERT or DistilBERT) +model_inputs = tokenizer(sequences, padding="max_length") + +# Remplit les séquences jusqu'à la longueur maximale spécifiée +model_inputs = tokenizer(sequences, padding="max_length", max_length=8) +``` + +La fonction peut également tronquer les séquences : + +```py +sequences = [ + "I've been waiting for a HuggingFace course my whole life.", + "So have I!", +] # « J'ai attendu un cours de HuggingFace toute ma vie. », « Moi aussi ! » + +# Tronque les séquences qui sont plus longues que la longueur maximale du modèle +# (512 for BERT or DistilBERT) +model_inputs = tokenizer(sequences, truncation=True) + +# Tronque les séquences qui sont plus longues que la longueur maximale spécifiée +model_inputs = tokenizer(sequences, max_length=8, truncation=True) +``` + +L'objet `tokenizer` peut gérer la conversion en des tenseurs de *frameworks* spécifiques. Ils peuvent ensuite être directement envoyés au modèle. Par exemple, dans le code suivant, nous demandons au *tokenizer* de retourner des tenseurs Pytorch lorsque l’on spécifie `"pt"`, de retourner des tenseurs TensorFlow lorsque l’on spécifie `"tf"` et des tableaux NumPy lorsque l’on indique `"np"` : + +```py +sequences = [ + "I've been waiting for a HuggingFace course my whole life.", + "So have I!", +] # « J'ai attendu un cours de HuggingFace toute ma vie. », « Moi aussi ! » + +# Retourne des tenseurs PyTorch +model_inputs = tokenizer(sequences, padding=True, return_tensors="pt") + +# Retourne des tenseurs TensorFlow +model_inputs = tokenizer(sequences, padding=True, return_tensors="tf") + +# Retourne des tableaux NumPy +model_inputs = tokenizer(sequences, padding=True, return_tensors="np") +``` + +## Jetons spéciaux + +Si nous jetons un coup d'œil aux identifiants d'entrée renvoyés par le *tokenizer*, nous verrons qu'ils sont un peu différents de ceux que nous avions précédemment : + + +```py +sequence = "I've been waiting for a HuggingFace course my whole life." # « J'ai attendu un cours de HuggingFace toute ma vie. » + +model_inputs = tokenizer(sequence) +print(model_inputs["input_ids"]) + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) +print(ids) +``` + +```python out +[101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102] +[1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012] +``` + +Un identifiant symbolique a été ajouté au début ainsi qu’un autre à la fin. Décodons les deux séquences d'identifiants ci-dessus pour voir de quoi il s'agit : + +```py +print(tokenizer.decode(model_inputs["input_ids"])) +print(tokenizer.decode(ids)) +``` + +```python out +"[CLS] i've been waiting for a huggingface course my whole life. [SEP]" +"i've been waiting for a huggingface course my whole life." +``` + +Le *tokenizer* a ajouté le mot spécial `[CLS]` au début et le mot spécial `[SEP]` à la fin. C'est parce que le modèle a été pré-entraîné avec ces mots, donc pour obtenir les mêmes résultats pour l'inférence, nous devons également les ajouter. Notez que certains modèles n'ajoutent pas de mots spéciaux, ou en ajoutent des différents. Les modèles peuvent aussi ajouter ces mots spéciaux seulement au début, ou seulement à la fin. Dans tous les cas, le *tokenizer* sait lesquels sont attendus et s'en occupe pour vous. + +## Conclusion : du *tokenizer* au modèle + +Maintenant que nous avons vu toutes les étapes individuelles que l'objet `tokenizer` utilise lorsqu'il est appliqué sur des textes, voyons une dernière fois comment il peut gérer plusieurs séquences (*padding*), de très longues séquences (*troncation*) et plusieurs types de tenseurs avec son API principale : + + +{#if fw === 'pt'} +```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) +sequences = [ + "I've been waiting for a HuggingFace course my whole life.", + "So have I!", +] # « J'ai attendu un cours de HuggingFace toute ma vie. », « Moi aussi ! » + + +tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt") +output = model(**tokens) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) +sequences = [ + "I've been waiting for a HuggingFace course my whole life.", + "So have I!", +] # « J'ai attendu un cours de HuggingFace toute ma vie. », « Moi aussi ! » + +tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="tf") +output = model(**tokens) +``` +{/if} diff --git a/chapters/fr/chapter2/7.mdx b/chapters/fr/chapter2/7.mdx new file mode 100644 index 000000000..c6fac5c9a --- /dev/null +++ b/chapters/fr/chapter2/7.mdx @@ -0,0 +1,12 @@ +# Utilisation de base terminée ! + +Bravo à vous pour avoir suivi le cours jusqu'ici ! Pour récapituler, dans ce chapitre vous avez : +- appris les blocs de construction de base d'un *transformer*, +- appris ce qui constitue un pipeline de tokenisation, +- vu comment utiliser un *transformer* en pratique, +- appris comment tirer parti d'un *tokenizer* pour convertir du texte en tenseurs compréhensibles par le modèle, +- configurer ensemble un *tokenizer* et un modèle afin de passer du texte aux prédictions, +- appris les limites des identifiants d'entrée et ce que sont que les masques d'attention, +- joué avec des méthodes de *tokenizer* polyvalentes et configurables. + +À partir de maintenant, vous devriez être en mesure de naviguer librement dans la documentation 🤗 *Transformers*. Le vocabulaire vous semblera familier et vous avez vu les méthodes que vous utiliserez la plupart du temps. diff --git a/chapters/fr/chapter2/8.mdx b/chapters/fr/chapter2/8.mdx new file mode 100644 index 000000000..e935ec26e --- /dev/null +++ b/chapters/fr/chapter2/8.mdx @@ -0,0 +1,307 @@ + + + + +# Quiz de fin de chapitre + +### 1. Quel est l'ordre du pipeline de modélisation du langage ? + + +tokenizer donne un sens à ces prédictions et les reconvertit en texte si nécessaire.", + explain: " Le modèle ne peut pas comprendre le texte ! Le tokenizer doit d'abord tokeniser le texte et le convertir en identifiants afin qu'il soit compréhensible par le modèle."}, + { + text: " Tout d'abord, le tokenizer/i>, qui traite le texte et renvoie des identifiants. Puis le modèle traite ces identifiants et produit une prédiction, qui peut être du texte.", + explain: " La prédiction du modèle ne peut pas être du texte immédiatement. Le tokenizer doit être utilisé afin de reconvertir la prédiction en texte !"}, + { + text: " Le tokenizer traite le texte et renvoie des identifiants. Le modèle traite ces identifiants et produit une prédiction. Le tokenizer peut alors être utilisé à nouveau pour reconvertir ces prédictions en texte.", + explain: " C’est correct ! Le tokenizer peut être utilisé à la fois pour la tokenisation et la dé-tokénisation.", + correct: true + } + ]} +/> + +### 2. Combien de dimensions le tenseur produit par le transformer de base possède-t-il et quelles sont-elles ? + + +transformers gèrent les batchs, même avec une seule séquence ce serait une taille de batch de 1 !" + }, + { + text: "3: la longueur de la séquence, la taille du batch et la taille cachée.", + explain: "C’est correct !", + correct: true + } + ]} +/> + +### 3. Lequel des éléments suivants est un exemple de tokenisation en sous-mots ? + + + +### 4. Qu'est-ce qu'une tête de modèle ? + +transformer de base qui redirige les tenseurs vers leurs couches correctes.", + explain: "Incorrect ! Il n'y a pas de tel composant." + }, + { + text: "Également connu sous le nom de mécanisme d'auto-attention, il adapte la représentation d'un token en fonction des autres tokens de la séquence.", + explain: "Incorrect ! La couche d'auto-attention contient des têtes d'attention mais ce ne sont pas des têtes d'adaptation." + }, + { + text: "Un composant supplémentaire, généralement constitué d'une ou plusieurs couches, pour convertir les prédictions du transformer en une sortie spécifique à la tâche.", + explain: "C'est exact. Les têtes d'adaptation, aussi appelées simplement têtes, se présentent sous différentes formes : têtes de modélisation du langage, têtes de réponse aux questions, têtes de classification des séquences, etc.", + correct: true + } + ]} +/> + +{#if fw === 'pt'} +### 5. Qu'est-ce qu'un AutoModel? + +AutoNLP product?" + }, + { + text: "An object that returns the correct architecture based on the checkpoint", + explain: "Exactly: the AutoModel only needs to know the checkpoint from which to initialize to return the correct architecture.", + correct: true + }, + { + text: "A model that automatically detects the language used for its inputs to load the correct weights", + explain: "Incorrect; while some checkpoints and models are capable of handling multiple languages, there are no built-in tools for automatic checkpoint selection according to language. You should head over to the Model Hub to find the best checkpoint for your task!" + } + ]} +/> + +{:else} +### 5. What is an AutoModel? + +checkpoints et modèles soient capables de gérer plusieurs langues, il n'existe pas d'outils intégrés pour la sélection automatique des checkpoints en fonction de la langue. Vous devez vous rendre sur le Hub des modèles pour trouver le meilleur checkpoint pour votre tâche !" + } + ]} +/> + +{/if} + +### 6. Quelles sont les techniques à connaître lors de la mise en batch de séquences de longueurs différentes ? + + +padding", + explain: "Oui, le padding est une façon correcte d'égaliser les séquences pour qu'elles tiennent dans une forme rectangulaire. Mais est-ce le seul moyen ?", + correct: true + }, + { + text: "Les masques d'attention ", + explain: "Absolument ! Les masques d'attention sont d'une importance capitale lorsqu'on manipule des séquences de longueurs différentes. Ce n'est cependant pas la seule technique à laquelle il faut faire attention.", + correct: true + } + ]} +/> + +### 7. Quel est l'intérêt d'appliquer une fonction SoftMax aux logits produits par un modèle de classification de séquences ? + + + +### 8. Autour de quelle méthode s'articule la majeure partie de l'API tokenizer ? + +encode, car elle peut encoder du texte en identifiants et des identifiants en prédictions.", + explain: "Faux ! Bien que la méthode encode existe sur les *tokenizers*, elle n'existe pas sur les modèles." + }, + { + text: "Appeler directement l'objet tokenizer", + explain: " Exactement ! La méthode __call__ du tokenizer est une méthode très puissante qui peut traiter à peu près tout. C'est également la méthode utilisée pour récupérer les prédictions d'un modèle.", + correct: true + }, + { + text: "pad", + explain: "C'est faux ! Le padding est très utile mais ce n'est qu'une partie de l'API tokenizer." + }, + { + text: "tokenize", + explain: "La méthode tokenize est est sans doute l'une des méthodes les plus utiles, mais elle ne constitue pas le cœur de l'API tokenizer." + } + ]} +/> + +### 9. Que contient la variable `result` dans cet exemple de code ? + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +result = tokenizer.tokenize("Hello!") +``` + +token.", + explain: " Absolument ! Convertissez cela en identifiants, et donnez-les à un modèle !", + correct: true + }, + { + text: "Une liste d'identifiants", + explain: "C'est faux, c'est à cela que la méthode __call__ ou la méthode convert_tokens_to_ids sert !" + }, + { + text: "Une chaîne contenant tous les tokens", + explain: "Ce serait sous-optimal car le but est de diviser la chaîne de caractères en plusieurs éléments." + } + ]} +/> + +{#if fw === 'pt'} +### 10. Y a-t-il un problème avec le code suivant ? + + +```py +from transformers import AutoTokenizer, AutoModel + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +model = AutoModel.from_pretrained("gpt2") + +encoded = tokenizer("Hey!", return_tensors="pt") +result = model(**encoded) +``` + +tokenizer qui a été entraîné avec un checkpoint différent est rarement une bonne idée. Le modèle n'a pas été entraîné pour donner du sens à la sortie de ce tokenizer donc la sortie du modèle (s'il peut même fonctionner !) n'aura aucun sens." + }, + { + text: " Le tokenizer et le modèle doivent toujours provenir du même checkpoint.", + explain: "C’est juste !", + correct: true + }, + { + text: " C'est une bonne pratique de faire du padding et de troncage avec le tokenizer car chaque entrée est un batch.", + explain: "Il est vrai que chaque entrée de modèle doit être un batch. Cependant, tronquer ou compléter cette séquence n'aurait pas nécessairement de sens puisqu'il n'y en a qu'une seule. Il s'agit là de techniques permettant de mettre en batch une liste de phrases." + } + ]} +/> + +{:else} +### 10. Y a-t-il un problème avec le code suivant ? + +```py +from transformers import AutoTokenizer, TFAutoModel + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +model = TFAutoModel.from_pretrained("gpt2") + +encoded = tokenizer("Hey!", return_tensors="pt") +result = model(**encoded) +``` + +tokenizer qui a été entraîné avec un checkpoint différent est rarement une bonne idée. Le modèle n'a pas été entraîné pour donner du sens à la sortie de ce tokenizer donc la sortie du modèle (s'il peut même fonctionner !) n'aura aucun sens." + }, + { + text: " Le tokenizer et le modèle doivent toujours provenir du même checkpoint.", + explain: "C’est juste !", + correct: true + }, + { + text: " C'est une bonne pratique de faire du padding et de troncage avec le tokenizer car chaque entrée est un batch.", + explain: "Il est vrai que chaque entrée de modèle doit être un batch. Cependant, tronquer ou compléter cette séquence n'aurait pas nécessairement de sens puisqu'il n'y en a qu'une seule. Il s'agit là de techniques permettant de mettre en batch une liste de phrases." + } + ]} +/> + +{/if} diff --git a/chapters/fr/chapter5/1.mdx b/chapters/fr/chapter5/1.mdx index 8e76cea5e..766e33082 100644 --- a/chapters/fr/chapter5/1.mdx +++ b/chapters/fr/chapter5/1.mdx @@ -1,17 +1,17 @@ # Introduction -Dans le [Chapitre 3](/course/chapter3) vous avez eu un premier aperçu de la bibliothèque 🤗 Datasets et vous avez vu qu'il y avait trois étapes principales pour affiner un modèle: +Dans le [Chapitre 3](/course/fr/chapter3) vous avez eu un premier aperçu de la bibliothèque 🤗 *Datasets* et qu'il y a trois étapes principales pour *finetuner* un modèle: -1. Chargez un jeu de données à partir de Hugging Face Hub. -2. Prétraitez les données avec `Dataset.map()`. +1. charger un jeu de données à partir du *Hub* d’Hugging Face. +2. Prétraiter les données avec `Dataset.map()`. 3. Charger et calculer des métriques. -Mais ce n'est qu'effleurer la surface de ce que 🤗 Datasets peut faire ! Dans ce chapitre, nous allons plonger profondément dans la bibliothèque. En cours de route, nous trouverons des réponses aux questions suivantes: +Mais ce n'est qu'effleurer la surface de ce que 🤗 *Datasets* peut faire ! Dans ce chapitre, nous allons plonger profondément dans cette bibliothèque. En cours de route, nous trouverons des réponses aux questions suivantes : -* Que faites-vous lorsque votre jeu de données n'est pas sur le Hub ? -* Comment pouvez-vous découper et trancher un ensemble de données ? (Et si vous avez _vraiment_ besoin d'utiliser Pandas ?) -* Que faites-vous lorsque votre ensemble de données est énorme et va faire fondre la RAM de votre ordinateur portable ? -* Qu'est-ce que c'est que le "mappage de la mémoire" et Apache Arrow ? -* Comment pouvez-vous créer votre propre ensemble de données et le pousser vers le Hub ? +* que faire lorsque votre jeu de données n'est pas sur le *Hub* ? +* comment découper et trancher un jeu de données ? (Et si on a _vraiment_ besoin d'utiliser Pandas ?) +* que faire lorsque votre jeu de données est énorme et va monopoliser la RAM de votre ordinateur portable ? +* qu'est-ce que c'est que le « *memory mapping* » et Apache Arrow ? +* comment créer votre propre jeu de données et le pousser sur le *Hub* ? -Les techniques que vous apprenez ici vous prépareront aux tâches avancées de tokenisation et de réglage fin du [Chapitre 6](/course/chapter6) et du [Chapitre 7](/course/chapter7) -- alors prenez un café et commençons ! \ No newline at end of file +Les techniques apprises dans ce chapitre vous prépareront aux tâches avancées de tokenisation et de *finetuning* du [Chapitre 6](/course/fr/chapter6) et du [Chapitre 7](/course/fr/chapter7). Alors prenez un café et commençons ! diff --git a/chapters/fr/chapter5/2.mdx b/chapters/fr/chapter5/2.mdx index 896dc8ca2..8c84d6282 100644 --- a/chapters/fr/chapter5/2.mdx +++ b/chapters/fr/chapter5/2.mdx @@ -1,4 +1,4 @@ -# Que faire si mon ensemble de données n'est pas sur le Hub ? +# Que faire si mon jeu de données n'est pas sur le *Hub* ? -Vous savez comment utiliser le [Hugging Face Hub](https://huggingface.co/datasets) pour télécharger des ensembles de données, mais vous vous retrouverez souvent à travailler avec des données stockées sur votre ordinateur portable ou sur un serveur distant. Dans cette section, nous allons vous montrer comment 🤗 Datasets peut être utilisé pour charger des ensembles de données qui ne sont pas disponibles sur le Hugging Face Hub. +Vous savez comment utiliser le [*Hub* d’Hugging Face](https://huggingface.co/datasets) pour télécharger des jeux de données mais en pratique vous vous retrouverez souvent à travailler avec des données stockées sur votre ordinateur portable ou sur un serveur distant. Dans cette section, nous allons vous montrer comment 🤗 *Datasets* peut être utilisé pour charger des jeux de données qui ne sont pas disponibles sur le *Hub* d’Hugging Face. -## Travailler avec des ensembles de données locaux et distants +## Travailler avec des jeux de données locaux et distants -🤗 Datasets fournit des scripts de chargement pour gérer le chargement des ensembles de données locaux et distants. Il prend en charge plusieurs formats de données courants, tels que : +🤗 *Datasets* fournit des scripts de chargement de jeux de données locaux et distants. Il prend en charge plusieurs formats de données courants, tels que : -| Format de données | Chargement du script | Exemple | +| Format des données | Script de chargement | Exemple | | :----------------: | :------------------: | :-----------------------------------------------------: | | CSV & TSV | `csv` | `load_dataset("csv", data_files="my_file.csv")` | | Fichiers texte | `text` | `load_dataset("text", data_files="my_file.txt")` | | JSON & Lignes JSON | `json` | `load_dataset("json", data_files="my_file.jsonl")` | -| DataFrames marinés | `pandas` | `load_dataset("pandas", data_files="my_dataframe.pkl")` | +| DataFrames en Pickle | `pandas` | `load_dataset("pandas", data_files="my_dataframe.pkl")` | -Comme indiqué dans le tableau, pour chaque format de données, nous avons juste besoin de spécifier le type de script de chargement dans la fonction `load_dataset()`, ainsi qu'un argument `data_files` qui spécifie le chemin vers un ou plusieurs fichiers. Commençons par charger un jeu de données à partir de fichiers locaux ; plus tard, nous verrons comment faire la même chose avec des fichiers distants. +Comme indiqué dans le tableau, pour chaque format de données, nous avons juste besoin de spécifier le type de script de chargement dans la fonction `load_dataset()`, ainsi qu'un argument `data_files` qui spécifie le chemin vers un ou plusieurs fichiers. Commençons par charger un jeu de données à partir de fichiers locaux puis plus tard comment faire la même chose avec des fichiers distants. ## Charger un jeu de données local -Pour cet exemple, nous utiliserons l'ensemble de données [SQuAD-it](https://github.com/crux82/squad-it/), qui est un ensemble de données à grande échelle pour répondre aux questions en Italien. +Pour cet exemple, nous utilisons le jeu de données [SQuAD-it](https://github.com/crux82/squad-it/) qui est un grand jeu de données pour la tâche de *Question Awnswering* en italien. -Les fractionnements de formation et de test sont hébergés sur GitHub, nous pouvons donc les télécharger avec une simple commande `wget` : +Les échantillons d’entraînement et de test sont hébergés sur GitHub, nous pouvons donc les télécharger avec une simple commande `wget` : ```python !wget https://github.com/crux82/squad-it/raw/master/SQuAD_it-train.json.gz !wget https://github.com/crux82/squad-it/raw/master/SQuAD_it-test.json.gz ``` -Cela téléchargera deux fichiers compressés appelés *SQuAD_it-train.json.gz* et *SQuAD_it-test.json.gz*, que nous pouvons décompresser avec la commande Linux `gzip` : +Cela télécharge deux fichiers compressés appelés *SQuAD_it-train.json.gz* et *SQuAD_it-test.json.gz* que nous pouvons décompresser avec la commande Linux `gzip` : ```python !gzip -dkv SQuAD_it-*.json.gz @@ -50,11 +50,11 @@ Nous pouvons voir que les fichiers compressés ont été remplacés par _SQuAD_i -✎ Si vous vous demandez pourquoi il y a un caractère `!` dans les commandes shell ci-dessus, c'est parce que nous les exécutons dans un cahier Jupyter. Supprimez simplement le préfixe si vous souhaitez télécharger et décompresser l'ensemble de données dans un terminal. +✎ Si vous vous demandez pourquoi il y a un caractère `!` dans les commandes shell ci-dessus, c'est parce que nous les exécutons dans un *notebook* Jupyter. Supprimez simplement le préfixe si vous souhaitez télécharger et décompresser le jeu de données dans un terminal. -Pour charger un fichier JSON avec la fonction `load_dataset()`, nous avons juste besoin de savoir si nous avons affaire à du JSON ordinaire (similaire à un dictionnaire imbriqué) ou à des lignes JSON (JSON séparé par des lignes). Comme de nombreux ensembles de données de questions-réponses, SQuAD-it utilise le format imbriqué, avec tout le texte stocké dans un champ "données". Cela signifie que nous pouvons charger le jeu de données en spécifiant l'argument `field` comme suit : +Pour charger un fichier JSON avec la fonction `load_dataset()`, nous avons juste besoin de savoir si nous avons affaire à du JSON ordinaire (similaire à un dictionnaire imbriqué) ou à des lignes JSON (JSON séparé par des lignes). Comme de nombreux jeux de données de questions-réponses, SQuAD-it utilise le format imbriqué où tout le texte est stocké dans un champ `data`. Cela signifie que nous pouvons charger le jeu de données en spécifiant l'argument `field` comme suit : ```py from datasets import load_dataset @@ -62,7 +62,7 @@ from datasets import load_dataset squad_it_dataset = load_dataset("json", data_files="SQuAD_it-train.json", field="data") ``` -Par défaut, le chargement de fichiers locaux crée un objet `DatasetDict` avec une division `train`. Nous pouvons le voir en inspectant l'objet `squad_it_dataset` : +Par défaut, le chargement de fichiers locaux crée un objet `DatasetDict` avec un échantillon `train`. Nous pouvons le voir en inspectant l'objet `squad_it_dataset` : ```py squad_it_dataset @@ -77,7 +77,7 @@ DatasetDict({ }) ``` -Cela nous montre le nombre de lignes et les noms de colonnes associés à l'ensemble d'apprentissage. Nous pouvons afficher l'un des exemples en indexant la division "train" comme suit : +Cela nous montre le nombre de lignes et les noms de colonnes associés à l’échantillon d’entraînement. Nous pouvons afficher l'un des exemples en indexant l’échantillon `train`. comme suit : ```py squad_it_dataset["train"][0] @@ -85,15 +85,15 @@ squad_it_dataset["train"][0] ```python out { - "title": "Terremoto del Sichuan del 2008", + "title": "Terremoto del Sichuan del 2008", # Séisme du Sichuan 2008 "paragraphs": [ { - "context": "Il terremoto del Sichuan del 2008 o il terremoto...", + "context": "Il terremoto del Sichuan del 2008 o il terremoto...", # Le tremblement de terre du Sichuan de 2008 ou le... "qas": [ { "answers": [{"answer_start": 29, "text": "2008"}], "id": "56cdca7862d2951400fa6826", - "question": "In quale anno si è verificato il terremoto nel Sichuan?", + "question": "In quale anno si è verificato il terremoto nel Sichuan?", # En quelle année le tremblement de terre du Sichuan a-t-il eu lieu ? }, ... ], @@ -103,7 +103,7 @@ squad_it_dataset["train"][0] } ``` -Super, nous avons chargé notre premier jeu de données local ! Mais bien que cela ait fonctionné pour l'ensemble d'entraînement, ce que nous voulons vraiment, c'est inclure à la fois les divisions `train` et `test` dans un seul objet `DatasetDict` afin que nous puissions appliquer les fonctions `Dataset.map()` sur les deux divisions à la fois . Pour ce faire, nous pouvons fournir un dictionnaire à l'argument `data_files` qui associe chaque nom de division à un fichier associé à cette division : +Super, nous avons chargé notre premier jeu de données local ! Mais ce que nous voulons vraiment, c'est inclure à la fois les échantillons `train` et `test` dans un seul objet `DatasetDict` afin que nous puissions appliquer les fonctions `Dataset.map()` sur les deux à la fois . Pour ce faire, nous pouvons fournir un dictionnaire à l'argument `data_files` qui associe chaque nom des échantillons à un fichier associé à cet échantillon : ```py data_files = {"train": "SQuAD_it-train.json", "test": "SQuAD_it-test.json"} @@ -128,24 +128,24 @@ C'est exactement ce que nous voulions. Désormais, nous pouvons appliquer divers -The `data_files` argument of the `load_dataset()` function is quite flexible and can be either a single file path, a list of file paths, or a dictionary that maps split names to file paths. You can also group files matching a specified pattern according to the rules used by the Unix shell (for example, you can group all JSON files in a directory into a single division by setting `data_files="*.json"` ). See 🤗 Datasets [documentation](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) for details. +L'argument `data_files` de la fonction `load_dataset()` est assez flexible et peut être soit un chemin de fichier unique, une liste de chemins de fichiers, ou un dictionnaire qui fait correspondre les noms des échantillons aux chemins de fichiers. Vous pouvez également regrouper les fichiers correspondant à un motif spécifié selon les règles utilisées par le shell Unix. Par exemple, vous pouvez regrouper tous les fichiers JSON d'un répertoire en une seule division en définissant `data_files="*.json"`. Voir la [documentation](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) de 🤗 *Datasets* pour plus de détails. -Les scripts de chargement dans 🤗 Datasets prend en charge la décompression automatique des fichiers d'entrée, nous aurions donc pu ignorer l'utilisation de `gzip` en pointant l'argument `data_files` directement sur les fichiers compressés : +Les scripts de chargement de 🤗 *Datasets* prennent en charge la décompression automatique des fichiers d'entrée. Nous aurions donc pu ignorer l'utilisation de `gzip` en pointant l'argument `data_files` directement sur les fichiers compressés : ```py data_files = {"train": "SQuAD_it-train.json.gz", "test": "SQuAD_it-test.json.gz"} squad_it_dataset = load_dataset("json", data_files=data_files, field="data") ``` -Cela peut être utile si vous ne souhaitez pas décompresser manuellement de nombreux fichiers GZIP. La décompression automatique s'applique également à d'autres formats courants tels que ZIP et TAR, il vous suffit donc de pointer `data_files` vers les fichiers compressés et vous êtes prêt à partir ! +Cela peut être utile si vous ne souhaitez pas décompresser manuellement de nombreux fichiers GZIP. La décompression automatique s'applique également à d'autres formats courants tels que ZIP et TAR. Il vous suffit donc de pointer `data_files` vers les fichiers compressés et vous êtes prêt à partir ! Maintenant que vous savez comment charger des fichiers locaux sur votre ordinateur portable ou de bureau, examinons le chargement de fichiers distants. ## Charger un jeu de données distant -Si vous travaillez en tant que data scientist ou codeur dans une entreprise, il y a de fortes chances que les ensembles de données que vous souhaitez analyser soient stockés sur un serveur distant. Heureusement, charger des fichiers distants est aussi simple que de charger des fichiers locaux ! Au lieu de fournir un chemin vers les fichiers locaux, nous pointons l'argument `data_files` de `load_dataset()` vers une ou plusieurs URL où les fichiers distants sont stockés. Par exemple, pour l'ensemble de données SQuAD-it hébergé sur GitHub, nous pouvons simplement faire pointer `data_files` vers les URL _SQuAD_it-*.json.gz_ comme suit : +Si vous travaillez en tant que *data scientist* ou codeur dans une entreprise, il y a de fortes chances que les juex de données que vous souhaitez analyser soient stockés sur un serveur distant. Heureusement, charger des fichiers distants est aussi simple que de charger des fichiers locaux ! Au lieu de fournir un chemin vers les fichiers locaux, nous pointons l'argument `data_files` de `load_dataset()` vers une ou plusieurs URL où les fichiers distants sont stockés. Par exemple, pour le jeux de données SQuAD-it hébergé sur GitHub, nous pouvons simplement faire pointer `data_files` vers les URL _SQuAD_it-*.json.gz_ comme suit : ```py url = "https://github.com/crux82/squad-it/raw/master/" @@ -156,12 +156,10 @@ data_files = { squad_it_dataset = load_dataset("json", data_files=data_files, field="data") ``` -Cela renvoie le même objet `DatasetDict` obtenu ci-dessus, mais nous évite de télécharger et de décompresser manuellement les fichiers _SQuAD_it-*.json.gz_. Ceci conclut notre incursion dans les différentes façons de charger des ensembles de données qui ne sont pas hébergés sur le Hugging Face Hub. Maintenant que nous avons un ensemble de données avec lequel jouer, mettons-nous la main à la pâte avec diverses techniques de gestion des données ! +Cela renvoie le même objet `DatasetDict` obtenu ci-dessus mais nous évite de télécharger et de décompresser manuellement les fichiers _SQuAD_it-*.json.gz_. Ceci conclut notre incursion dans les différentes façons de charger des jeux de données qui ne sont pas hébergés sur le *Hub* d’Hugging Face. Maintenant que nous avons un jeu de données avec lequel jouer, mettons la main à la pâte avec diverses techniques de gestion des données ! -✏️ **Essayez-le !** Choisissez un autre ensemble de données hébergé sur GitHub ou le [UCI Machine Learning Repository](https://archive.ics.uci.edu/ml/index.php) et essayez de le charger localement et à distance en utilisant les techniques présentées ci-dessus. Pour obtenir des points bonus, essayez de charger un ensemble de données stocké au format CSV ou texte (voir la [documentation](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) pour plus d'informations sur ces formats). +✏️ **Essayez !** Choisissez un autre jeu de données hébergé sur GitHub ou dans le [*UCI Machine Learning Repository*](https://archive.ics.uci.edu/ml/index.php) et essayez de le charger localement et à distance en utilisant les techniques présentées ci-dessus. Pour obtenir des points bonus, essayez de charger un jeu de données stocké au format CSV ou texte (voir la [documentation](https://huggingface.co/docs/datasets/loading.html#local-and-remote-files) pour plus d'informations sur ces formats). - - diff --git a/chapters/fr/chapter5/3.mdx b/chapters/fr/chapter5/3.mdx index 9d6a57959..455473889 100644 --- a/chapters/fr/chapter5/3.mdx +++ b/chapters/fr/chapter5/3.mdx @@ -7,24 +7,24 @@ {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/chapter5/section3.ipynb"}, ]} /> -La plupart du temps, les données avec lesquelles vous travaillez ne seront pas parfaitement préparées pour les modèles de formation. Dans cette section, nous allons explorer les différentes fonctionnalités fournies par 🤗 Datasets pour nettoyer vos ensembles de données. +La plupart du temps, les données avec lesquelles vous travaillez ne sont pas parfaitement préparées pour l’entraînements de modèles. Dans cette section, nous allons explorer les différentes fonctionnalités fournies par 🤗 *Datasets* pour nettoyer vos jeux de données. ## Trancher et découper nos données -Semblable à Pandas, 🤗 Datasets fournit plusieurs fonctions pour manipuler le contenu des objets `Dataset` et `DatasetDict`. Nous avons déjà rencontré la méthode `Dataset.map()` dans le [Chapitre 3](/course/chapter3), et dans cette section nous allons explorer certaines des autres fonctions à notre disposition. +Semblable à Pandas, 🤗 *Datasets* fournit plusieurs fonctions pour manipuler le contenu des objets `Dataset` et `DatasetDict`. Nous avons déjà rencontré la méthode `Dataset.map()` dans le [Chapitre 3](/course/fr/chapter3) et dans cette section nous allons explorer certaines des autres fonctions à notre disposition. -Pour cet exemple, nous utiliserons le [Drug Review Dataset](https://archive.ics.uci.edu/ml/datasets/Drug+Review+Dataset+%28Drugs.com%29) qui est hébergé sur [UC Irvine Machine Learning Repository] (https://archive.ics.uci.edu/ml/index.php), qui contient des avis de patients sur divers médicaments, ainsi que la condition traitée et une note de 10 étoiles sur la satisfaction du patient. +Pour cet exemple, nous utiliserons le [*Drug Review Dataset*](https://archive.ics.uci.edu/ml/datasets/Drug+Review+Dataset+%28Drugs.com%29) qui est hébergé sur [*UC Irvine Machine Learning Repository*](https://archive.ics.uci.edu/ml/index.php) et contenant des avis de patients sur divers médicaments ainsi que la condition traitée et une note de 10 étoiles sur la satisfaction du patient. -Nous devons d'abord télécharger et extraire les données, ce qui peut être fait avec les commandes `wget` et `unzip` : +Nous devons d'abord télécharger et extraire les données, ce qui peut être fait avec les commandes `wget` et `unzip` : ```py !wget "https://archive.ics.uci.edu/ml/machine-learning-databases/00462/drugsCom_raw.zip" !unzip drugsCom_raw.zip ``` -Étant donné que TSV n'est qu'une variante de CSV qui utilise des tabulations au lieu de virgules comme séparateurs, nous pouvons charger ces fichiers en utilisant le script de chargement `csv` et en spécifiant l'argument `delimiter` dans la fonction `load_dataset()` comme suit : +Étant donné que TSV n'est qu'une variante de CSV qui utilise des tabulations au lieu de virgules comme séparateurs, nous pouvons charger ces fichiers en utilisant le script de chargement `csv` et en spécifiant l'argument `delimiter` dans la fonction `load_dataset()` comme suit : ```py from datasets import load_dataset @@ -34,40 +34,40 @@ data_files = {"train": "drugsComTrain_raw.tsv", "test": "drugsComTest_raw.tsv"} drug_dataset = load_dataset("csv", data_files=data_files, delimiter="\t") ``` -Une bonne pratique lors de toute sorte d'analyse de données consiste à prélever un petit échantillon aléatoire pour avoir une idée rapide du type de données avec lesquelles vous travaillez. Dans 🤗 Datasets, nous pouvons créer un échantillon aléatoire en enchaînant les fonctions `Dataset.shuffle()` et `Dataset.select()` : +Une bonne pratique lors de toute sorte d'analyse de données consiste à prélever un petit échantillon aléatoire pour avoir une idée rapide du type de données avec lesquelles vous travaillez. Dans 🤗 *Datasets*, nous pouvons créer un échantillon aléatoire en enchaînant les fonctions `Dataset.shuffle()` et `Dataset.select()` : ```py drug_sample = drug_dataset["train"].shuffle(seed=42).select(range(1000)) -# Peek at the first few examples +# Un coup d'œil sur les premiers exemples drug_sample[:3] ``` ```python out {'Unnamed: 0': [87571, 178045, 80482], 'drugName': ['Naproxen', 'Duloxetine', 'Mobic'], - 'condition': ['Gout, Acute', 'ibromyalgia', 'Inflammatory Conditions'], - 'review': ['"like the previous person mention, I'm a strong believer of aleve, it works faster for my gout than the prescription meds I take. No more going to the doctor for refills.....Aleve works!"', - '"I have taken Cymbalta for about a year and a half for fibromyalgia pain. It is great\r\nas a pain reducer and an anti-depressant, however, the side effects outweighed \r\nany benefit I got from it. I had trouble with restlessness, being tired constantly,\r\ndizziness, dry mouth, numbness and tingling in my feet, and horrible sweating. I am\r\nbeing weaned off of it now. Went from 60 mg to 30mg and now to 15 mg. I will be\r\noff completely in about a week. The fibro pain is coming back, but I would rather deal with it than the side effects."', - '"I have been taking Mobic for over a year with no side effects other than an elevated blood pressure. I had severe knee and ankle pain which completely went away after taking Mobic. I attempted to stop the medication however pain returned after a few days."'], + 'condition': ['Gout, Acute', 'ibromyalgia', 'Inflammatory Conditions'], #['Goutte aiguë', 'ibromyalgie', 'Affections inflammatoires'] + 'review': ['"like the previous person mention, I'm a strong believer of aleve, it works faster for my gout than the prescription meds I take. No more going to the doctor for refills.....Aleve works!"', # comme la personne précédente l'a mentionné, je suis un fervent partisan de l'aleve, il fonctionne plus rapidement pour ma goutte que les médicaments sur ordonnance que je prends. Je n'ai plus besoin d'aller chez le médecin pour des renouvellements.....Aleve fonctionne !" + '"I have taken Cymbalta for about a year and a half for fibromyalgia pain. It is great\r\nas a pain reducer and an anti-depressant, however, the side effects outweighed \r\nany benefit I got from it. I had trouble with restlessness, being tired constantly,\r\ndizziness, dry mouth, numbness and tingling in my feet, and horrible sweating. I am\r\nbeing weaned off of it now. Went from 60 mg to 30mg and now to 15 mg. I will be\r\noff completely in about a week. The fibro pain is coming back, but I would rather deal with it than the side effects."', # J'ai pris du Cymbalta pendant environ un an et demi pour des douleurs de la fibromyalgie. C'est un excellent analgésique et un antidépresseur, mais les effets secondaires l'ont emporté sur tous les avantages que j'en ai tirés. J'ai eu des problèmes d'agitation, de fatigue constante, de vertiges, de bouche sèche, d'engourdissement, de picotements dans les pieds, et de transpiration horrible. Je suis en train de m'en sevrer maintenant. Je suis passée de 60 mg à 30 mg et maintenant à 15 mg. Je l'arrêterai complètement dans environ une semaine. La douleur de la fibrose revient, mais je préfère la supporter plutôt que les effets secondaires. + '"I have been taking Mobic for over a year with no side effects other than an elevated blood pressure. I had severe knee and ankle pain which completely went away after taking Mobic. I attempted to stop the medication however pain returned after a few days."'], # J'ai pris Mobic pendant plus d'un an sans effets secondaires autres qu'une pression sanguine élevée. J'avais de fortes douleurs au genou et à la cheville qui ont complètement disparu après avoir pris Mobic. J'ai essayé d'arrêter le médicament mais la douleur est revenue après quelques jours." 'rating': [9.0, 3.0, 10.0], - 'date': ['September 2, 2015', 'November 7, 2011', 'June 5, 2013'], + 'date': ['September 2, 2015', 'November 7, 2011', 'June 5, 2013'], #['2 septembre 2015', '7 novembre 2011', '5 juin 2013'] 'usefulCount': [36, 13, 128]} ``` -Notez que nous avons corrigé la graine dans `Dataset.shuffle()` à des fins de reproductibilité. `Dataset.select()` attend un itérable d'indices, nous avons donc passé `range(1000)` pour récupérer les 1 000 premiers exemples de l'ensemble de données mélangé. À partir de cet échantillon, nous pouvons déjà voir quelques bizarreries dans notre ensemble de données : +Notez que nous avons corrigé la graine dans `Dataset.shuffle()` à des fins de reproductibilité. `Dataset.select()` attend un itérable d'indices, nous avons donc passé `range(1000)` pour récupérer les 1 000 premiers exemples du jeu de données mélangé. À partir de cet échantillon, nous pouvons déjà voir quelques bizarreries dans notre jeu de données : -* La colonne "Sans nom : 0" ressemble étrangement à un identifiant anonyme pour chaque patient. -* La colonne "condition" comprend un mélange d'étiquettes en majuscules et en minuscules. -* Les avis sont de longueur variable et contiennent un mélange de séparateurs de lignes Python (`\r\n`) ainsi que des codes de caractères HTML comme `&\#039;`. +* la colonne `Unnamed: 0` ressemble étrangement à un identifiant anonyme pour chaque patient, +* la colonne `condition` comprend un mélange d'étiquettes en majuscules et en minuscules, +* les avis sont de longueur variable et contiennent un mélange de séparateurs de lignes Python (`\r\n`) ainsi que des codes de caractères HTML comme `&\#039;`. -Voyons comment nous pouvons utiliser 🤗 Datasets pour traiter chacun de ces problèmes. Pour tester l'hypothèse de l'ID patient pour la colonne `Unnamed : 0`, nous pouvons utiliser la fonction `Dataset.unique()` pour vérifier que le nombre d'ID correspond au nombre de lignes dans chaque division : +Voyons comment nous pouvons utiliser 🤗 *Datasets* pour traiter chacun de ces problèmes. Pour tester l'hypothèse de l'ID patient pour la colonne `Unnamed : 0`, nous pouvons utiliser la fonction `Dataset.unique()` pour vérifier que le nombre d'ID correspond au nombre de lignes dans chaque division : ```py for split in drug_dataset.keys(): assert len(drug_dataset[split]) == len(drug_dataset[split].unique("Unnamed: 0")) ``` -Cela semble confirmer notre hypothèse, alors nettoyons un peu l'ensemble de données en renommant la colonne `Unnamed: 0` en quelque chose d'un peu plus interprétable. Nous pouvons utiliser la fonction `DatasetDict.rename_column()` pour renommer la colonne sur les deux divisions en une seule fois : +Cela semble confirmer notre hypothèse, alors nettoyons un peu en renommant la colonne `Unnamed: 0` en quelque chose d'un peu plus interprétable. Nous pouvons utiliser la fonction `DatasetDict.rename_column()` pour renommer la colonne sur les deux divisions en une seule fois : ```py drug_dataset = drug_dataset.rename_column( @@ -91,11 +91,11 @@ DatasetDict({ -✏️ **Essayez-le !** Utilisez la fonction "Dataset.unique()" pour trouver le nombre de médicaments et de conditions uniques dans les ensembles d'entraînement et de test. +✏️ **Essayez !** Utilisez la fonction ` Dataset.unique()` pour trouver le nombre de médicaments et de conditions uniques dans les échantillons d'entraînement et de test. -Ensuite, normalisons toutes les étiquettes `condition` en utilisant `Dataset.map()`. Comme nous l'avons fait avec la tokenisation dans le [chapitre 3](/course/chapter3), nous pouvons définir une fonction simple qui peut être appliquée sur toutes les lignes de chaque division dans `drug_dataset` : +Ensuite, normalisons toutes les étiquettes `condition` en utilisant `Dataset.map()`. Comme nous l'avons fait avec la tokenisation dans le [chapitre 3](/course/fr/chapter3), nous pouvons définir une fonction simple qui peut être appliquée sur toutes les lignes de chaque division dans `drug_dataset` : ```py def lowercase_condition(example): @@ -109,26 +109,26 @@ drug_dataset.map(lowercase_condition) AttributeError: 'NoneType' object has no attribute 'lower' ``` -Oh non, nous avons rencontré un problème avec notre fonction de carte ! À partir de l'erreur, nous pouvons déduire que certaines des entrées de la colonne "condition" sont "Aucune", qui ne peuvent pas être mises en minuscules car ce ne sont pas des chaînes. Supprimons ces lignes en utilisant `Dataset.filter()`, qui fonctionne de manière similaire à `Dataset.map()` et attend une fonction qui reçoit un seul exemple de l'ensemble de données. Au lieu d'écrire une fonction explicite comme : +Oh non, nous rencontrons un problème avec notre fonction ! À partir de l'erreur, nous pouvons déduire que certaines des entrées de la colonne `condition` sont `None` ne pouvant donc pas être mises en minuscules car ce ne sont pas des chaînes. Supprimons ces lignes en utilisant `Dataset.filter()`, qui fonctionne de manière similaire à `Dataset.map()` et attend une fonction qui reçoit un seul exemple issu du jeu de données. Au lieu d'écrire une fonction explicite comme : ```py def filter_nones(x): return x["condition"] is not None ``` -puis en exécutant `drug_dataset.filter(filter_nones)`, nous pouvons le faire en une seule ligne en utilisant une _lambda function_. En Python, les fonctions lambda sont de petites fonctions que vous pouvez définir sans les nommer explicitement. Ils prennent la forme générale : +puis éxécuter `drug_dataset.filter(filter_nones)`, nous pouvons le faire en une seule ligne en utilisant une _fonction lambda_. En Python, les fonctions lambda sont de petites fonctions que vous pouvez définir sans les nommer explicitement. Ils prennent la forme générale : ``` lambda : ``` -où `lambda` est l'un des [mots clés] spéciaux de Python (https://docs.python.org/3/reference/lexical_analysis.html#keywords), `` est une liste/ensemble de valeurs séparées par des virgules qui définissent les entrées de la fonction et `` représente les opérations que vous souhaitez exécuter. Par exemple, nous pouvons définir une simple fonction lambda qui met au carré un nombre comme suit : +où `lambda` est l'un des [mots clés](https://docs.python.org/3/reference/lexical_analysis.html#keywords) spéciaux de Python, `` est une liste/ensemble de valeurs séparées par des virgules qui définissent les entrées de la fonction et `` représente les opérations que vous souhaitez exécuter. Par exemple, nous pouvons définir une simple fonction lambda qui met au carré un nombre comme suit : ``` lambda x : x * x ``` -Pour appliquer cette fonction à une entrée, nous devons l'envelopper ainsi que l'entrée entre parenthèses : +Pour appliquer cette fonction à une entrée, nous devons l'envelopper ainsi que l'entrée entre parenthèses : ```py (lambda x: x * x)(3) @@ -148,17 +148,17 @@ De même, nous pouvons définir des fonctions lambda avec plusieurs arguments en 16.0 ``` -Les fonctions Lambda sont pratiques lorsque vous souhaitez définir de petites fonctions à usage unique (pour plus d'informations à leur sujet, nous vous recommandons de lire l'excellent [tutoriel Real Python](https://realpython.com/python-lambda/) d'André Burgaud) . Dans le contexte 🤗 Datasets, nous pouvons utiliser des fonctions lambda pour définir des opérations simples de mappage et de filtrage, alors utilisons cette astuce pour éliminer les entrées "None" dans notre jeu de données : +Les fonctions lambda sont pratiques lorsque vous souhaitez définir de petites fonctions à usage unique (pour plus d'informations à leur sujet, nous vous recommandons de lire l'excellent [tutoriel Real Python](https://realpython.com/python-lambda/) d'André Burgaud) . Dans le contexte de la bibliothèque 🤗 *Datasets*, nous pouvons utiliser des fonctions lambda pour définir des opérations simples de mappage et de filtrage. Utilisons cette astuce pour éliminer les entrées `None` dans notre jeu de données : ```py drug_dataset = drug_dataset.filter(lambda x: x["condition"] is not None) ``` -Avec les entrées "None" supprimées, nous pouvons normaliser notre colonne "condition" : +Avec les entrées `None` supprimées, nous pouvons normaliser notre colonne `condition` : ```py drug_dataset = drug_dataset.map(lowercase_condition) -# Check that lowercasing worked +# Vérification que la mise en minuscule a fonctionné drug_dataset["train"]["condition"][:3] ``` @@ -170,35 +170,35 @@ drug_dataset["train"]["condition"][:3] ## Création de nouvelles colonnes -Chaque fois que vous avez affaire à des avis de clients, une bonne pratique consiste à vérifier le nombre de mots dans chaque avis. Une critique peut être un simple mot comme "Génial !" ou un essai complet avec des milliers de mots, et selon le cas d'utilisation, vous devrez gérer ces extrêmes différemment. Pour calculer le nombre de mots dans chaque révision, nous utiliserons une heuristique approximative basée sur la division de chaque texte par des espaces. +Chaque fois que vous avez affaire à des avis de clients, une bonne pratique consiste à vérifier le nombre de mots dans chaque avis. Une critique peut être un simple mot comme « Génial ! » ou un essai complet avec des milliers de mots. Selon le cas d'usage, vous devrez gérer ces extrêmes différemment. Pour calculer le nombre de mots dans chaque révision, nous utiliserons une heuristique approximative basée sur la division de chaque texte par des espaces. -Définissons une fonction simple qui compte le nombre de mots dans chaque avis : +Définissons une fonction simple qui compte le nombre de mots dans chaque avis : ```py def compute_review_length(example): return {"review_length": len(example["review"].split())} ``` -Contrairement à notre fonction `lowercase_condition()`, `compute_review_length()` renvoie un dictionnaire dont la clé ne correspond pas à l'un des noms de colonne de l'ensemble de données. Dans ce cas, lorsque `compute_review_length()` est passé à `Dataset.map()`, il sera appliqué à toutes les lignes du jeu de données pour créer une nouvelle colonne `review_length` : +Contrairement à notre fonction `lowercase_condition()`, `compute_review_length()` renvoie un dictionnaire dont la clé ne correspond pas à l'un des noms de colonne du jeu de données. Dans ce cas, lorsque `compute_review_length()` est passé à `Dataset.map()`, il est appliqué à toutes les lignes du jeu de données pour créer une nouvelle colonne `review_length` : ```py drug_dataset = drug_dataset.map(compute_review_length) -# Inspect the first training example +# Inspecter le premier exemple d'entraînement drug_dataset["train"][0] ``` ```python out {'patient_id': 206461, 'drugName': 'Valsartan', - 'condition': 'left ventricular dysfunction', - 'review': '"It has no side effect, I take it in combination of Bystolic 5 Mg and Fish Oil"', + 'condition': 'left ventricular dysfunction', # dysfonctionnement du ventricule gauche + 'review': '"It has no side effect, I take it in combination of Bystolic 5 Mg and Fish Oil"', # Il n'a aucun effet secondaire, je le prends en combinaison avec Bystolic 5 mg et de l'huile de poisson. 'rating': 9.0, - 'date': 'May 20, 2012', + 'date': 'May 20, 2012', # 20 mai 2012 'usefulCount': 27, 'review_length': 17} ``` -Comme prévu, nous pouvons voir qu'une colonne "review_length" a été ajoutée à notre ensemble d'entraînement. Nous pouvons trier cette nouvelle colonne avec `Dataset.sort()` pour voir à quoi ressemblent les valeurs extrêmes : +Comme prévu, nous pouvons voir qu'une colonne `review_length` a été ajoutée à notre jeu d'entraînement. Nous pouvons trier cette nouvelle colonne avec `Dataset.sort()` pour voir à quoi ressemblent les valeurs extrêmes : ```py drug_dataset["train"].sort("review_length")[:3] @@ -207,23 +207,23 @@ drug_dataset["train"].sort("review_length")[:3] ```python out {'patient_id': [103488, 23627, 20558], 'drugName': ['Loestrin 21 1 / 20', 'Chlorzoxazone', 'Nucynta'], - 'condition': ['birth control', 'muscle spasm', 'pain'], - 'review': ['"Excellent."', '"useless"', '"ok"'], + 'condition': ['birth control', 'muscle spasm', 'pain'], # contraception, spasme musculaire, douleur. + 'review': ['"Excellent."', '"useless"', '"ok"'], # Excellent, inutile, ok 'rating': [10.0, 1.0, 6.0], - 'date': ['November 4, 2008', 'March 24, 2017', 'August 20, 2016'], + 'date': ['November 4, 2008', 'March 24, 2017', 'August 20, 2016'], # 4 novembre 2008, 24 mars 2017, 20 août 2016 'usefulCount': [5, 2, 10], 'review_length': [1, 1, 1]} ``` -Comme nous le soupçonnions, certaines critiques ne contiennent qu'un seul mot, ce qui, bien que cela puisse convenir à l'analyse des sentiments, ne serait pas informatif si nous voulons prédire la condition. +Comme nous le soupçonnions, certaines critiques ne contiennent qu'un seul mot, ce qui, bien que cela puisse convenir à l'analyse des sentiments, n’est pas informatif si nous voulons prédire la condition. -🙋 Une autre façon d'ajouter de nouvelles colonnes à un ensemble de données consiste à utiliser la fonction `Dataset.add_column()`. Cela vous permet de fournir la colonne sous forme de liste Python ou de tableau NumPy et peut être utile dans les situations où `Dataset.map()` n'est pas bien adapté à votre analyse. +🙋 Une autre façon d'ajouter de nouvelles colonnes à un jeu de données consiste à utiliser la fonction `Dataset.add_column()`. Cela vous permet de donner la colonne sous forme de liste Python ou de tableau NumPy et peut être utile dans les situations où `Dataset.map()` n'est pas bien adapté à votre analyse. -Utilisons la fonction `Dataset.filter()` pour supprimer les avis contenant moins de 30 mots. De la même manière que nous l'avons fait avec la colonne "condition", nous pouvons filtrer les avis très courts en exigeant que les avis aient une longueur supérieure à ce seuil : +Utilisons la fonction `Dataset.filter()` pour supprimer les avis contenant moins de 30 mots. De la même manière que nous l'avons fait avec la colonne `condition`, nous pouvons filtrer les avis très courts en exigeant que les avis aient une longueur supérieure à ce seuil : ```py drug_dataset = drug_dataset.filter(lambda x: x["review_length"] > 30) @@ -234,15 +234,15 @@ print(drug_dataset.num_rows) {'train': 138514, 'test': 46108} ``` -Comme vous pouvez le constater, cela a supprimé environ 15 % des avis de nos ensembles d'entraînement et de test d'origine. +Comme vous pouvez le constater, cela a supprimé environ 15 % des avis de nos jeux d'entraînement et de test d'origine. -✏️ **Essayez-le !** Utilisez la fonction `Dataset.sort()` pour inspecter les avis avec le plus grand nombre de mots. Consultez la [documentation](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.sort) pour voir quel argument vous devez utiliser pour trier les avis par longueur dans l'ordre décroissant. +✏️ **Essayez !** Utilisez la fonction `Dataset.sort()` pour inspecter les avis avec le plus grand nombre de mots. Consultez la [documentation](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.sort) pour voir quel argument vous devez utiliser pour trier les avis par longueur dans l'ordre décroissant. -La dernière chose à laquelle nous devons faire face est la présence de codes de caractères HTML dans nos avis. Nous pouvons utiliser le module `html` de Python pour supprimer ces caractères, comme ceci : +La dernière chose à laquelle nous devons faire face est la présence de caractères HTML dans nos avis. Nous pouvons utiliser le module `html` de Python pour supprimer ces caractères, comme ceci : ```py import html @@ -255,19 +255,19 @@ html.unescape(text) "I'm a transformer called BERT" ``` -Nous utiliserons `Dataset.map()` pour démasquer tous les caractères HTML de notre corpus : +Nous utilisons `Dataset.map()` pour démasquer tous les caractères HTML de notre corpus : ```python drug_dataset = drug_dataset.map(lambda x: {"review": html.unescape(x["review"])}) ``` -Comme vous pouvez le voir, la méthode `Dataset.map()` est très utile pour le traitement des données -- et nous n'avons même pas effleuré la surface de tout ce qu'elle peut faire ! +Comme vous pouvez le voir, la méthode `Dataset.map()` est très utile pour le traitement des données. Et nous n'avons même pas effleuré la surface de tout ce qu'elle peut faire ! ## Les superpouvoirs de la méthode `map()` -La méthode `Dataset.map()` prend un argument `batched` qui, s'il est défini sur `True`, l'amène à envoyer un lot d'exemples à la fonction map en une seule fois (la taille du lot est configurable mais par défaut à 1 000). Par exemple, la fonction de carte précédente qui dégageait tout le code HTML prenait un peu de temps à s'exécuter (vous pouvez lire le temps pris dans les barres de progression). On peut accélérer cela en traitant plusieurs éléments en même temps à l'aide d'une liste en compréhension. +La méthode `Dataset.map()` prend un argument `batched` qui, s'il est défini sur `True`, l'amène à envoyer un batch d'exemples à la fonction map en une seule fois (la taille du batch est configurable mais est fixé par défaut à 1 000). Par exemple, la fonction `map()` précédente qui supprime tout le code HTML prend un peu de temps à s'exécuter (vous pouvez lire le temps pris dans les barres de progression). On peut accélérer cela en traitant plusieurs éléments en même temps à l'aide d'une compréhension de liste. -Lorsque vous spécifiez `batched=True`, la fonction reçoit un dictionnaire avec les champs de l'ensemble de données, mais chaque valeur est maintenant une _liste de valeurs_, et non plus une seule valeur. La valeur de retour de `Dataset.map()` devrait être la même : un dictionnaire avec les champs que nous voulons mettre à jour ou ajouter à notre ensemble de données, et une liste de valeurs. Par exemple, voici une autre façon de supprimer tous les caractères HTML, mais en utilisant `batched=True` : +Lorsque vous spécifiez `batched=True`, la fonction reçoit un dictionnaire avec les champs du jeu de données mais chaque valeur est maintenant une _liste de valeurs_ et non plus une seule valeur. La valeur retournée par `Dataset.map()` devrait être la même : un dictionnaire avec les champs que nous voulons mettre à jour ou ajouter à notre jeu de données, et une liste de valeurs. Par exemple, voici une autre façon de supprimer tous les caractères HTML, mais en utilisant `batched=True` : ```python new_drug_dataset = drug_dataset.map( @@ -275,9 +275,9 @@ new_drug_dataset = drug_dataset.map( ) ``` -Si vous exécutez ce code dans un notebook, vous verrez que cette commande s'exécute beaucoup plus rapidement que la précédente. Et ce n'est pas parce que nos critiques ont déjà été sans échappement HTML -- si vous ré-exécutez l'instruction de la section précédente (sans `batched=True`), cela prendra le même temps qu'avant. En effet, les compréhensions de liste sont généralement plus rapides que l'exécution du même code dans une boucle "for", et nous gagnons également en performances en accédant à de nombreux éléments en même temps au lieu d'un par un. +Si vous exécutez ce code dans un *notebook*, vous verrez que cette commande s'exécute beaucoup plus rapidement que la précédente. Et ce n'est pas parce que nos critiques ont déjà été scannées au format HTML. Si vous ré-exécutez l'instruction de la section précédente (sans `batched=True`), cela prendra le même temps qu'avant. En effet, les compréhensions de liste sont généralement plus rapides que l'exécution du même code dans une boucle `for` et nous gagnons également en performances en accédant à de nombreux éléments en même temps au lieu d'un par un. -L'utilisation de `Dataset.map()` avec `batched=True` sera essentielle pour débloquer la vitesse des tokenizers "rapides" que nous rencontrerons dans [Chapitre 6](/course/chapter6), qui peuvent rapidement tokeniser de grandes listes de textes. Par exemple, pour tokeniser toutes les revues de médicaments avec un tokenizer rapide, nous pourrions utiliser une fonction comme celle-ci : +L'utilisation de `Dataset.map()` avec `batched=True` est essentielle pour les *tokenizers rapides* que nous rencontrerons dans le [Chapitre 6](/course/fr/chapter6) et qui peuvent rapidement tokeniser de grandes listes de textes. Par exemple, pour tokeniser toutes les critiques de médicaments avec un *tokenizer* rapide nous pouvons utiliser une fonction comme celle-ci : ```python from transformers import AutoTokenizer @@ -289,32 +289,32 @@ def tokenize_function(examples): return tokenizer(examples["review"], truncation=True) ``` -Comme vous l'avez vu dans le [Chapitre 3](/course/chapter3), nous pouvons passer un ou plusieurs exemples au tokenizer, nous pouvons donc utiliser cette fonction avec ou sans `batched=True`. Profitons-en pour comparer les performances des différentes options. Dans un cahier, vous pouvez chronométrer une instruction d'une ligne en ajoutant `%time` avant la ligne de code que vous souhaitez mesurer : +Comme vous l'avez vu dans le [Chapitre 3](/course/fr/chapter3), nous pouvons passer un ou plusieurs exemples au *tokenizer*. Nous pouvons donc utiliser cette fonction avec ou sans `batched=True`. Profitons-en pour comparer les performances des différentes options. Dans un *notebook*, vous pouvez chronométrer une instruction d'une ligne en ajoutant `%time` avant la ligne de code que vous souhaitez mesurer : ```python no-format %time tokenized_dataset = drug_dataset.map(tokenize_function, batched=True) ``` -Vous pouvez également chronométrer une cellule entière en mettant `%%time` au début de la cellule. Sur le matériel sur lequel nous avons exécuté cela, il affichait 10,8 s pour cette instruction (c'est le nombre écrit après "Wall time"). +Vous pouvez également chronométrer une cellule entière en mettant `%%time` au début de la cellule. Sur le matériel sur lequel nous avons exécuté cela, cela affichait 10,8 s pour cette instruction (c'est le nombre écrit après "Wall time"). -✏️ **Essayez-le !** Exécutez la même instruction avec et sans `batched=True`, puis essayez-le avec un tokenizer lent (ajoutez `use_fast=False` dans la méthode `AutoTokenizer.from_pretrained()`) afin que vous puissiez voir quels numéros vous obtenez sur votre matériel. +✏️ **Essayez !** Exécutez la même instruction avec et sans `batched=True`, puis essayez-le avec un *tokenizer* lent (ajoutez `use_fast=False` dans la méthode `AutoTokenizer.from_pretrained()`) afin que vous puissiez voir quels temps vous obtenez sur votre matériel. -Voici les résultats que nous avons obtenus avec et sans batching, avec un tokenizer rapide et un lent : +Voici les résultats que nous avons obtenus avec et sans batching, avec un *tokenizer* rapide et un lent : -Options | Tokenizer rapide | Tokenizer lent +Options | *Tokenizer* rapide | *Tokenizer* lent :--------------:|:----------------:|:-----------------: `batched=True` | 10.8s | 4min41s `batched=False` | 59.2s | 5min3s -Cela signifie que l'utilisation d'un tokenizer rapide avec l'option `batched=True` est 30 fois plus rapide que son homologue lent sans traitement par lot -- c'est vraiment incroyable ! C'est la raison principale pour laquelle les tokenizers rapides sont la valeur par défaut lors de l'utilisation de `AutoTokenizer` (et pourquoi ils sont appelés "rapides"). Ils sont capables d'atteindre une telle accélération car dans les coulisses, le code de tokenisation est exécuté dans Rust, qui est un langage qui facilite la parallélisation de l'exécution du code. +Cela signifie que l'utilisation d'un *tokenizer* rapide avec l'option `batched=True` est 30 fois plus rapide que son homologue lent sans batch. C'est vraiment incroyable ! C'est la raison principale pour laquelle les *tokenizers* rapides sont la valeur par défaut lors de l'utilisation de `AutoTokenizer` (et pourquoi ils sont appelés « rapides »). Ils sont capables d'atteindre une telle vitesse car en coulisses le code de tokenisation est exécuté en Rust qui est un langage facilitant la parallélisation de l'exécution du code. -La parallélisation est également la raison de l'accélération de près de 6 fois obtenue par le fast tokenizer avec le traitement par lots : vous ne pouvez pas paralléliser une seule opération de tokenisation, mais lorsque vous souhaitez tokeniser de nombreux textes en même temps, vous pouvez simplement répartir l'exécution sur plusieurs processus. chacun responsable de ses propres textes. +La parallélisation est également la raison du gain de vitesse de près de 6 fois obtenue par le *tokenizer* rapide avec batch. Vous ne pouvez pas paralléliser une seule opération de tokenisation, mais lorsque vous souhaitez *tokeniser* de nombreux textes en même temps, vous pouvez simplement répartir l'exécution sur plusieurs processus. Chacun responsable de ses propres textes. -`Dataset.map()` possède également ses propres capacités de parallélisation. Comme ils ne sont pas soutenus par Rust, ils ne laisseront pas un tokenizer lent rattraper un rapide, mais ils peuvent toujours être utiles (surtout si vous utilisez un tokenizer qui n'a pas de version rapide). Pour activer le multitraitement, utilisez l'argument `num_proc` et spécifiez le nombre de processus à utiliser dans votre appel à `Dataset.map()` : +`Dataset.map()` possède aussi ses propres capacités de parallélisation. Comme elles ne sont pas soutenus par Rust, un *tokenizer* lent ne peut pas rattraper un rapide mais cela peut toujours être utile (surtout si vous utilisez un *tokenizer* qui n'a pas de version rapide). Pour activer le multitraitement, utilisez l'argument `num_proc` et spécifiez le nombre de processus à utiliser dans votre appel à `Dataset.map()` : ```py slow_tokenizer = AutoTokenizer.from_pretrained("bert-base-cased", use_fast=False) @@ -327,24 +327,24 @@ def slow_tokenize_function(examples): tokenized_dataset = drug_dataset.map(slow_tokenize_function, batched=True, num_proc=8) ``` -Vous pouvez expérimenter un peu le timing pour déterminer le nombre optimal de processus à utiliser ; dans notre cas 8 semblait produire le meilleur gain de vitesse. Voici les chiffres que nous avons obtenus avec et sans multitraitement : +Vous pouvez faire des tests pour déterminer le nombre optimal de processus à utiliser. Dans notre cas 8 semble produire le meilleur gain de vitesse. Voici les chiffres que nous avons obtenus avec et sans multitraitement : -Options | Tokenizer rapide | Tokenizer lent +Options | *Tokenizer* rapide | *Tokenizer* lent :----------------------------:|:----------------:|:---------------: `batched=True` | 10.8s | 4min41s `batched=False` | 59.2s | 5min3s `batched=True`, `num_proc=8` | 6.52s | 41.3s `batched=False`, `num_proc=8` | 9.49s | 45.2s -Ce sont des résultats beaucoup plus raisonnables pour le tokenizer lent, mais les performances du tokenizer rapide ont également été considérablement améliorées. Notez, cependant, que ce ne sera pas toujours le cas - pour les valeurs de `num_proc` autres que 8, nos tests ont montré qu'il était plus rapide d'utiliser `batched=True` sans cette option. En général, nous ne recommandons pas d'utiliser le multitraitement Python pour les tokenizers rapides avec `batched=True`. +Ce sont des résultats beaucoup plus raisonnables pour le *tokenizer* lent mais les performances du *tokenizer* rapide ont également été considérablement améliorées. Notez, cependant, que ce ne sera pas toujours le cas : pour des valeurs de `num_proc` autres que 8, nos tests ont montré qu'il était plus rapide d'utiliser `batched=True` sans cette option. En général, nous ne recommandons pas d'utiliser le multitraitement pour les *tokenizers* rapides avec `batched=True`. -Utiliser `num_proc` pour accélérer votre traitement est généralement une bonne idée, tant que la fonction que vous utilisez n'effectue pas déjà une sorte de multitraitement. +Utiliser `num_proc` pour accélérer votre traitement est généralement une bonne idée tant que la fonction que vous utilisez n'effectue pas déjà une sorte de multitraitement. -Toutes ces fonctionnalités condensées en une seule méthode sont déjà assez étonnantes, mais il y a plus ! Avec `Dataset.map()` et `batched=True` vous pouvez modifier le nombre d'éléments dans votre jeu de données. Ceci est très utile dans de nombreuses situations où vous souhaitez créer plusieurs fonctionnalités d'entraînement à partir d'un exemple, et nous devrons le faire dans le cadre du prétraitement de plusieurs des tâches NLP que nous entreprendrons dans [Chapitre 7](/course/ Chapitre 7). +Toutes ces fonctionnalités condensées en une seule méthode sont déjà assez étonnantes, mais il y a plus ! Avec `Dataset.map()` et `batched=True` vous pouvez modifier le nombre d'éléments dans votre jeu de données. Ceci est très utile dans de nombreuses situations où vous souhaitez créer plusieurs fonctionnalités d'entraînement à partir d'un exemple. Nous devrons le faire dans le cadre du prétraitement de plusieurs des tâches de traitement du langage naturel que nous entreprendrons dans le [Chapitre 7](/course/fr/chapter7). @@ -352,7 +352,7 @@ Toutes ces fonctionnalités condensées en une seule méthode sont déjà assez -Voyons comment cela fonctionne ! Ici, nous allons tokeniser nos exemples et les tronquer à une longueur maximale de 128, mais nous demanderons au tokenizer de renvoyer *tous* les morceaux des textes au lieu du premier. Cela peut être fait avec `return_overflowing_tokens=True` : +Voyons comment cela fonctionne ! Ici, nous allons tokeniser nos exemples et les tronquer à une longueur maximale de 128 mais nous demanderons au *tokenizer* de renvoyer *tous* les morceaux des textes au lieu du premier. Cela peut être fait avec `return_overflowing_tokens=True` : ```py def tokenize_and_split(examples): @@ -364,7 +364,7 @@ def tokenize_and_split(examples): ) ``` -Testons cela sur un exemple avant d'utiliser `Dataset.map()` sur l'ensemble de données : +Testons cela sur un exemple avant d'utiliser `Dataset.map()` sur le jeu de données : ```py result = tokenize_and_split(drug_dataset["train"][0]) @@ -375,7 +375,7 @@ result = tokenize_and_split(drug_dataset["train"][0]) [128, 49] ``` -Ainsi, notre premier exemple dans l'ensemble de formation est devenu deux fonctionnalités car il a été segmenté à plus que le nombre maximum de jetons que nous avons spécifié : le premier de longueur 128 et le second de longueur 49. Faisons maintenant cela pour tous les éléments du base de données! +Notre premier exemple du jeu d’entraînement est devenu deux caractéristiques car il a été segmenté à plus que le nombre maximum de *tokens* que nous avons spécifié : le premier de longueur 128 et le second de longueur 49. Faisons maintenant cela pour tous les éléments du jeu de données ! ```py tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True) @@ -385,9 +385,9 @@ tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True) ArrowInvalid: Column 1 named condition expected length 1463 but got length 1000 ``` -Oh non! Cela n'a pas fonctionné ! Pourquoi pas? L'examen du message d'erreur nous donnera un indice : il y a une incompatibilité dans les longueurs de l'une des colonnes, l'une étant de longueur 1 463 et l'autre de longueur 1 000. Si vous avez consulté la [documentation] `Dataset.map()`(https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map), vous vous souviendrez peut-être qu'il s'agit du nombre d'échantillons passés à la fonction que nous mappons ; ici, ces 1 000 exemples ont donné 1 463 nouvelles fonctionnalités, entraînant une erreur de forme. +Oh non ! Cela n'a pas fonctionné ! Pourquoi ? L'examen du message d'erreur nous donne un indice : il y a une incompatibilité dans les longueurs de l'une des colonnes. L'une étant de longueur 1 463 et l'autre de longueur 1 000. Si vous avez consulté la [documentation](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map) de `Dataset.map()`, vous vous souvenez peut-être qu'il s'agit du nombre d'échantillons passés à la fonction que nous mappons. Ici, ces 1 000 exemples ont donné 1 463 nouvelles caractéristiques, entraînant une erreur de forme. -Le problème est que nous essayons de mélanger deux ensembles de données différents de tailles différentes : les colonnes `drug_dataset` auront un certain nombre d'exemples (les 1 000 dans notre erreur), mais le `tokenized_dataset` que nous construisons en aura plus (le 1 463 dans le message d'erreur). Cela ne fonctionne pas pour un `Dataset`, nous devons donc soit supprimer les colonnes de l'ancien jeu de données, soit leur donner la même taille que dans le nouveau jeu de données. Nous pouvons faire le premier avec l'argument `remove_columns` : +Le problème est que nous essayons de mélanger deux jeux de données différents de tailles différentes : les colonnes `drug_dataset` auront un certain nombre d'exemples (les 1 000 dans notre erreur), mais le `tokenized_dataset` que nous construisons en aura plus (le 1 463 dans le message d'erreur). Cela ne fonctionne pas pour un `Dataset`, nous devons donc soit supprimer les colonnes de l'ancien jeu de données, soit leur donner la même taille que dans le nouveau jeu de données. Nous pouvons faire la première option avec l'argument `remove_columns` : ```py tokenized_dataset = drug_dataset.map( @@ -395,7 +395,7 @@ tokenized_dataset = drug_dataset.map( ) ``` -Maintenant, cela fonctionne sans erreur. Nous pouvons vérifier que notre nouveau jeu de données contient beaucoup plus d'éléments que le jeu de données d'origine en comparant les longueurs : +Maintenant, cela fonctionne sans erreur. Nous pouvons vérifier que notre nouveau jeu de données contient beaucoup plus d'éléments que le jeu de données d'origine en comparant les longueurs : ```py len(tokenized_dataset["train"]), len(drug_dataset["train"]) @@ -405,7 +405,7 @@ len(tokenized_dataset["train"]), len(drug_dataset["train"]) (206772, 138514) ``` -Nous avons mentionné que nous pouvions également résoudre le problème de longueur non concordante en donnant aux anciennes colonnes la même taille que les nouvelles. Pour ce faire, nous aurons besoin du champ `overflow_to_sample_mapping` que le tokenizer renvoie lorsque nous définissons `return_overflowing_tokens=True`. Il nous donne une correspondance entre un nouvel index de fonctionnalité et l'index de l'échantillon dont il est issu. Grâce à cela, nous pouvons associer chaque clé présente dans notre jeu de données d'origine à une liste de valeurs de la bonne taille en répétant les valeurs de chaque exemple autant de fois qu'il génère de nouvelles fonctionnalités : +Nous avons mentionné que nous pouvions également résoudre le problème de longueur non concordante en donnant aux anciennes colonnes la même taille que les nouvelles. Pour ce faire, nous avons besoin du champ `overflow_to_sample_mapping` que le *tokenizer* renvoie lorsque nous définissons `return_overflowing_tokens=True`. Il nous donne une correspondance entre un nouvel index de caractéristique et l'index de l'échantillon dont il est issu. Grâce à cela, nous pouvons associer chaque clé présente dans notre jeu de données d'origine à une liste de valeurs de la bonne taille en répétant les valeurs de chaque exemple autant de fois qu'il génère de nouvelles caractéristiques : ```py def tokenize_and_split(examples): @@ -422,7 +422,7 @@ def tokenize_and_split(examples): return result ``` -Nous pouvons voir que cela fonctionne avec `Dataset.map()` sans que nous ayons besoin de supprimer les anciennes colonnes : +Nous pouvons voir que cela fonctionne avec `Dataset.map()` sans que nous ayons besoin de supprimer les anciennes colonnes : ```py tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True) @@ -442,22 +442,21 @@ DatasetDict({ }) ``` -Nous obtenons le même nombre de fonctionnalités d'entraînement qu'auparavant, mais ici nous avons conservé tous les anciens champs. Si vous en avez besoin pour un post-traitement après l'application de votre modèle, vous pouvez utiliser cette approche. +Nous obtenons le même nombre de caractéristiques d'entraînement qu'auparavant, mais ici nous avons conservé tous les anciens champs. Si vous en avez besoin pour un post-traitement après l'application de votre modèle, vous pouvez utiliser cette approche. -Vous avez maintenant vu comment 🤗 Datasets peut être utilisé pour prétraiter un ensemble de données de différentes manières. Bien que les fonctions de traitement de 🤗 Datasets couvrent la plupart de vos besoins de formation de modèles, -il peut arriver que vous deviez passer à Pandas pour accéder à des fonctionnalités plus puissantes, telles que `DataFrame.groupby()` ou des API de haut niveau pour la visualisation. Heureusement, 🤗 Datasets est conçu pour être interopérable avec des bibliothèques telles que Pandas, NumPy, PyTorch, TensorFlow et JAX. Voyons comment cela fonctionne. +Vous avez maintenant vu comment 🤗 *Datasets* peut être utilisé pour prétraiter un jeu de données de différentes manières. Bien que les fonctions de traitement de 🤗 *Datasets* couvrent la plupart de vos besoins, il peut arriver que vous deviez passer à Pandas pour accéder à des fonctionnalités plus puissantes, telles que `DataFrame.groupby()` ou des API de haut niveau pour la visualisation. Heureusement, 🤗 *Datasets* est conçu pour être interopérable avec des bibliothèques telles que Pandas, NumPy, PyTorch, TensorFlow et JAX. Voyons comment cela fonctionne. -## De `Dataset`s à `DataFrame`s et vice versa +## De `Dataset` à `DataFrame` et vice versa -Pour permettre la conversion entre diverses bibliothèques tierces, 🤗 Datasets fournit une fonction `Dataset.set_format()`. Cette fonction ne modifie que le _format de sortie_ de l'ensemble de données, vous pouvez donc facilement passer à un autre format sans affecter le _format de données_ sous-jacent, qui est Apache Arrow. Le formatage se fait sur place. Pour démontrer, convertissons notre jeu de données en Pandas : +Pour permettre la conversion entre diverses bibliothèques tierces, 🤗 *Datasets* fournit une fonction `Dataset.set_format()`. Cette fonction ne modifie que le _format de sortie_ du jeu de données. Vous pouvez donc facilement passer à un autre format sans affecter le _format de données_ sous-jacent, qui est Apache Arrow. Le formatage se fait sur place. Pour démontrer, convertissons notre jeu de données vers Pandas : ```py drug_dataset.set_format("pandas") ``` -Maintenant, lorsque nous accédons aux éléments du jeu de données, nous obtenons un `pandas.DataFrame` au lieu d'un dictionnaire : +Maintenant, lorsque nous accédons aux éléments du jeu de données, nous obtenons un `pandas.DataFrame` au lieu d'un dictionnaire : ```py drug_dataset["train"][:3] @@ -514,7 +513,7 @@ drug_dataset["train"][:3] -Créons un `pandas.DataFrame` pour l'ensemble d'entraînement en sélectionnant tous les éléments de `drug_dataset["train"]` : +Créons un `pandas.DataFrame` pour l'ensemble d'entraînement en sélectionnant tous les éléments de `drug_dataset["train"]` : ```py train_df = drug_dataset["train"][:] @@ -522,12 +521,12 @@ train_df = drug_dataset["train"][:] -🚨 Sous le capot, `Dataset.set_format()` change le format de retour pour la méthode dunder `__getitem__()` de l'ensemble de données. Cela signifie que lorsque nous voulons créer un nouvel objet comme `train_df` à partir d'un `Dataset` au format `"pandas"`, nous devons découper tout l'ensemble de données pour obtenir un `pandas.DataFrame`. Vous pouvez vérifier par vous-même que le type de `drug_dataset["train"]` est `Dataset`, quel que soit le format de sortie. +🚨 Sous le capot, `Dataset.set_format()` change le format de retour pour la méthode `__getitem__()`. Cela signifie que lorsque nous voulons créer un nouvel objet comme `train_df` à partir d'un `Dataset` au format `"pandas"`, nous devons découper tout le jeu de données pour obtenir un `pandas.DataFrame`. Vous pouvez vérifier par vous-même que le type de `drug_dataset["train"]` est `Dataset`, quel que soit le format de sortie. -De là, nous pouvons utiliser toutes les fonctionnalités Pandas que nous voulons. Par exemple, nous pouvons faire un chaînage sophistiqué pour calculer la distribution de classe parmi les entrées `condition` : +De là, nous pouvons utiliser toutes les fonctionnalités Pandas que nous voulons. Par exemple, nous pouvons faire un chaînage sophistiqué pour calculer la distribution de classe parmi les entrées `condition` : ```py frequencies = ( @@ -578,7 +577,7 @@ frequencies.head() -Et une fois que nous avons terminé notre analyse Pandas, nous pouvons toujours créer un nouvel objet `Dataset` en utilisant la fonction `Dataset.from_pandas()` comme suit : +Et une fois que nous avons terminé notre analyse Pandas, nous pouvons toujours créer un nouvel objet `Dataset` en utilisant la fonction `Dataset.from_pandas()` comme suit : ```py @@ -597,11 +596,11 @@ Dataset({ -✏️ **Essayez-le !** Calculez la note moyenne par médicament et stockez le résultat dans un nouvel ensemble de données. +✏️ **Essayez !** Calculez la note moyenne par médicament et stockez le résultat dans un nouveau jeu de données. -Ceci conclut notre visite des différentes techniques de prétraitement disponibles dans 🤗 Datasets. Pour compléter la section, créons un ensemble de validation pour préparer l'ensemble de données pour la formation d'un classificateur. Avant cela, nous allons réinitialiser le format de sortie de `drug_dataset` de `"pandas"` à `"arrow"` : +Ceci conclut notre visite des différentes techniques de prétraitement disponibles dans 🤗 *Datasets*. Pour compléter la section, créons un ensemble de validation pour préparer le jeu de données à l’entraînement d'un classifieur. Avant cela, nous allons réinitialiser le format de sortie de `drug_dataset` de `"pandas"` à `"arrow"` : ```python drug_dataset.reset_format() @@ -609,9 +608,9 @@ drug_dataset.reset_format() ## Création d'un ensemble de validation -Bien que nous ayons un jeu de test que nous pourrions utiliser pour l'évaluation, il est recommandé de ne pas toucher au jeu de test et de créer un jeu de validation séparé pendant le développement. Une fois que vous êtes satisfait des performances de vos modèles sur l'ensemble de validation, vous pouvez effectuer une dernière vérification d'intégrité sur l'ensemble de test. Ce processus permet d'atténuer le risque de dépassement de l'ensemble de test et de déploiement d'un modèle qui échoue sur des données du monde réel. +Bien que nous ayons un jeu de test que nous pourrions utiliser pour l'évaluation, il est recommandé de ne pas toucher au jeu de test et de créer un jeu de validation séparé pendant le développement. Une fois que vous êtes satisfait des performances de vos modèles sur l'ensemble de validation, vous pouvez effectuer une dernière vérification d'intégrité sur l'ensemble test. Ce processus permet d'atténuer le risque de surentraînement sur le jeu de test et de déployer un modèle qui échoue sur des données du monde réel. -🤗 Datasets fournit une fonction `Dataset.train_test_split()` basée sur la célèbre fonctionnalité de `scikit-learn`. Utilisons-le pour diviser notre ensemble d'entraînement en divisions "train" et "validation" (nous définissons l'argument "seed" pour la reproductibilité) : +🤗 *Datasets* fournit une fonction `Dataset.train_test_split()` basée sur la célèbre fonctionnalité de `scikit-learn`. Utilisons-la pour diviser notre ensemble d'entraînement `train` et `validation` (nous définissons l'argument `seed` pour la reproductibilité) : ```py drug_dataset_clean = drug_dataset["train"].train_test_split(train_size=0.8, seed=42) @@ -639,27 +638,27 @@ DatasetDict({ }) ``` -Génial, nous avons maintenant préparé un jeu de données prêt pour l'entraînement de certains modèles ! Dans la [section 5](/course/chapter5/5), nous vous montrerons comment télécharger des ensembles de données sur le Hugging Face Hub, mais pour l'instant, terminons notre analyse en examinant quelques façons d'enregistrer des ensembles de données sur votre ordinateur local. +Génial, nous avons maintenant préparé un jeu de données prêt pour l'entraînement de certains modèles ! Dans la [section 5](/course/fr/chapter5/5), nous vous montrerons comment télécharger des jeux de données sur le *Hub*. Mais pour l'instant, terminons notre analyse en examinant quelques façons d'enregistrer des jeux de données sur votre ordinateur local. ## Enregistrer un jeu de données -Bien que 🤗 Datasets mette en cache chaque jeu de données téléchargé et les opérations qui y sont effectuées, il y a des moments où vous voudrez enregistrer un jeu de données sur le disque (par exemple, au cas où le cache serait supprimé). Comme indiqué dans le tableau ci-dessous, 🤗 Datasets fournit trois fonctions principales pour enregistrer votre jeu de données dans différents formats : +Bien que 🤗 *Datasets* mette en cache chaque jeu de données téléchargé et les opérations qui y sont effectuées, il y a des moments où vous voudrez enregistrer un jeu de données sur le disque (par exemple, au cas où le cache serait supprimé). Comme indiqué dans le tableau ci-dessous, 🤗 *Datasets* fournit trois fonctions principales pour enregistrer votre jeu de données dans différents formats : | Format de données | Fonction | | :---------------: | :----------------------: | -| Flèche | `Dataset.save_to_disk()` | +| Arrow | `Dataset.save_to_disk()` | | CSV | `Dataset.to_csv()` | | JSON | `Dataset.to_json()` | -Par exemple, enregistrons notre jeu de données nettoyé au format Arrow : +Par exemple, enregistrons notre jeu de données nettoyé au format Arrow : ```py drug_dataset_clean.save_to_disk("drug-reviews") ``` -Cela créera un répertoire avec la structure suivante : +Cela créera un répertoire avec la structure suivante : ``` drug-reviews/ @@ -680,9 +679,9 @@ drug-reviews/ └── state.json ``` -où nous pouvons voir que chaque division est associée à sa propre table * dataset.arrow * et à certaines métadonnées dans * dataset_info.json * et * state.json *. Vous pouvez considérer le format Arrow comme un tableau sophistiqué de colonnes et de lignes optimisé pour la création d'applications hautes performances qui traitent et transportent de grands ensembles de données. +où nous pouvons voir que chaque division est associée à sa propre table *dataset.arrow* et à certaines métadonnées dans *dataset_info.json* et *state.json*. Vous pouvez considérer le format Arrow comme un tableau sophistiqué de colonnes et de lignes optimisé pour la création d'applications hautes performances qui traitent et transportent de grands ensembles de données. -Une fois le jeu de données enregistré, nous pouvons le charger en utilisant la fonction `load_from_disk()` comme suit : +Une fois le jeu de données enregistré, nous pouvons le charger en utilisant la fonction `load_from_disk()` comme suit : ```py from datasets import load_from_disk @@ -708,14 +707,14 @@ DatasetDict({ }) ``` -Pour les formats CSV et JSON, nous devons stocker chaque fractionnement dans un fichier séparé. Pour ce faire, vous pouvez parcourir les clés et les valeurs de l'objet "DatasetDict" : +Pour les formats CSV et JSON, nous devons stocker chaque fractionnement dans un fichier séparé. Pour ce faire, vous pouvez parcourir les clés et les valeurs de l'objet `DatasetDict` : ```py for split, dataset in drug_dataset_clean.items(): dataset.to_json(f"drug-reviews-{split}.jsonl") ``` -Cela enregistre chaque fractionnement au [format de lignes JSON] (https://jsonlines.org), où chaque ligne de l'ensemble de données est stockée sous la forme d'une seule ligne de JSON. Voici à quoi ressemble le premier exemple : +Cela enregistre chaque fractionnement au [format JSON Lines](https://jsonlines.org), où chaque ligne du jeu de données est stockée sous la forme d'une seule ligne de JSON. Voici à quoi ressemble le premier exemple : ```py !head -n 1 drug-reviews-train.jsonl @@ -725,7 +724,7 @@ Cela enregistre chaque fractionnement au [format de lignes JSON] (https://jsonli {"patient_id":141780,"drugName":"Escitalopram","condition":"depression","review":"\"I seemed to experience the regular side effects of LEXAPRO, insomnia, low sex drive, sleepiness during the day. I am taking it at night because my doctor said if it made me tired to take it at night. I assumed it would and started out taking it at night. Strange dreams, some pleasant. I was diagnosed with fibromyalgia. Seems to be helping with the pain. Have had anxiety and depression in my family, and have tried quite a few other medications that haven't worked. Only have been on it for two weeks but feel more positive in my mind, want to accomplish more in my life. Hopefully the side effects will dwindle away, worth it to stick with it from hearing others responses. Great medication.\"","rating":9.0,"date":"May 29, 2011","usefulCount":10,"review_length":125} ``` -Nous pouvons ensuite utiliser les techniques de [section 2](/course/chapter5/2) pour charger les fichiers JSON comme suit : +Nous pouvons ensuite utiliser les techniques de [section 2](/course/fr/chapter5/2) pour charger les fichiers JSON comme suit : ```py data_files = { @@ -736,9 +735,9 @@ data_files = { drug_dataset_reloaded = load_dataset("json", data_files=data_files) ``` -Et c'est tout pour notre excursion dans le data wrangling avec 🤗 Datasets ! Maintenant que nous disposons d'un ensemble de données nettoyé pour entraîner un modèle, voici quelques idées que vous pouvez essayer : +Et c'est tout pour notre excursion dans la manipulation des données avec 🤗 *Datasets* ! Maintenant que nous disposons d'un ensemble de données nettoyé pour entraîner un modèle, voici quelques idées que vous pouvez essayer : -1. Utilisez les techniques du [Chapitre 3](/course/chapter3) pour former un classificateur capable de prédire l'état du patient en fonction de l'examen du médicament. -2. Utilisez le pipeline `summarization` du [Chapitre 1](/course/chapter1) pour générer des résumés des révisions. +1. Utilisez les techniques du [Chapitre 3](/course/fr/chapter3) pour entraîner un classifieur capable de prédire l'état du patient en fonction de l'examen du médicament. +2. Utilisez le pipeline `summarization` du [Chapitre 1](/course/fr/chapter1) pour générer des résumés des révisions. -Ensuite, nous verrons comment 🤗 Datasets peut vous permettre de travailler avec d'énormes ensembles de données sans faire exploser votre ordinateur portable ! +Ensuite, nous verrons comment 🤗 *Datasets* peut vous permettre de travailler avec d'énormes jeux de données sans faire exploser votre ordinateur portable ! diff --git a/chapters/fr/chapter5/4.mdx b/chapters/fr/chapter5/4.mdx index 63ed0be44..8657e3b62 100644 --- a/chapters/fr/chapter5/4.mdx +++ b/chapters/fr/chapter5/4.mdx @@ -1,4 +1,4 @@ -# Big Data? 🤗 Datasets à la rescousse ! +# Données massives ? 🤗 *Datasets* à la rescousse ! -De nos jours, il n'est pas rare de travailler avec des ensembles de données de plusieurs gigaoctets, surtout si vous envisagez de pré-entraîner un transformateur comme BERT ou GPT-2 à partir de zéro. Dans ces cas, même _charger_ les données peut être un défi. Par exemple, le corpus WebText utilisé pour pré-entraîner GPT-2 se compose de plus de 8 millions de documents et de 40 Go de texte - le charger dans la RAM de votre ordinateur portable est susceptible de lui donner une crise cardiaque ! +De nos jours, il n'est pas rare de travailler avec des jeux de données de plusieurs gigaoctets surtout si vous envisagez de pré-entraîner un *transformer* comme BERT ou GPT-2 à partir de zéro. Dans ces cas, même _charger_ les données peut être un défi. Par exemple, le corpus WebText utilisé pour pré-entraîner GPT-2 se compose de plus de 8 millions de documents et de 40 Go de texte. Le charger dans la RAM de votre ordinateur portable est susceptible de lui donner une crise cardiaque ! -Heureusement, 🤗 Datasets a été conçu pour surmonter ces limitations. Il vous libère des problèmes de gestion de la mémoire en traitant les ensembles de données comme des fichiers _mappés en mémoire_, et des limites du disque dur en _streaming_ les entrées dans un corpus. +Heureusement, 🤗 *Datasets* a été conçu pour surmonter ces limitations. Il vous libère des problèmes de gestion de la mémoire en traitant les jeux de données comme des fichiers _mappés en mémoire_, ainsi que des limites du disque dur en faisant du _streaming_ sur les entrées dans un corpus. -Dans cette section, nous allons explorer ces fonctionnalités de 🤗 Datasets avec un énorme corpus de 825 Go connu sous le nom de [the Pile](https://pile.eleuther.ai). Commençons! +Dans cette section, nous allons explorer ces fonctionnalités de 🤗 *Datasets* avec un énorme corpus de 825 Go connu sous le nom de [The Pile](https://pile.eleuther.ai). Commençons ! -## Qu'est-ce que The Pile ? +## Qu'est-ce que *The Pile* ? -The Pile est un corpus de texte en anglais créé par [EleutherAI](https://www.eleuther.ai) pour entraîner des modèles de langage à grande échelle. Il comprend une gamme variée d'ensembles de données, couvrant des articles scientifiques, des référentiels de code GitHub et du texte Web filtré. Le corpus de formation est disponible en [morceaux de 14 Go](https://mystic.the-eye.eu/public/AI/pile/), et vous pouvez également télécharger plusieurs des [composants individuels](https://mystic .the-eye.eu/public/AI/pile_preliminary_components/). Commençons par jeter un coup d'œil à l'ensemble de données PubMed Abstracts, qui est un corpus de résumés de 15 millions de publications biomédicales sur [PubMed](https://pubmed.ncbi.nlm.nih.gov/). L'ensemble de données est au [format JSON Lines](https://jsonlines.org) et est compressé à l'aide de la bibliothèque `zstandard`, nous devons donc d'abord l'installer : +The Pile est un corpus de texte en anglais créé par [EleutherAI](https://www.eleuther.ai) pour entraîner des modèles de langage à grande échelle. Il comprend une gamme variée de jeux de données, couvrant des articles scientifiques, des référentiels de code GitHub et du texte Web filtré. Le corpus d’entraînement est disponible en [morceaux de 14 Go](https://mystic.the-eye.eu/public/AI/pile/) et vous pouvez aussi télécharger plusieurs des [composants individuels]( https://mystic.the-eye.eu/public/AI/pile_preliminary_components/). Commençons par jeter un coup d'œil au jeu de données PubMed Abstracts, qui est un corpus de résumés de 15 millions de publications biomédicales sur [PubMed](https://pubmed.ncbi.nlm.nih.gov/). Le jeu de données est au [format JSON Lines](https://jsonlines.org) et est compressé à l'aide de la bibliothèque `zstandard`. Nous devons donc d'abord installer cette bibliothèque : ```py !pip install zstandard ``` -Ensuite, nous pouvons charger le jeu de données en utilisant la méthode pour les fichiers distants que nous avons apprise dans [section 2](/course/chapter5/2) : +Ensuite, nous pouvons charger le jeu de données en utilisant la méthode pour les fichiers distants que nous avons apprise dans [section 2](/course/fr/chapter5/2) : ```py from datasets import load_dataset @@ -42,15 +42,15 @@ Dataset({ }) ``` -Nous pouvons voir qu'il y a 15 518 009 lignes et 2 colonnes dans notre ensemble de données -- c'est beaucoup ! +Nous pouvons voir qu'il y a 15 518 009 lignes et 2 colonnes dans notre jeu de données. C'est beaucoup ! -✎ Par défaut, 🤗 Datasets décompressera les fichiers nécessaires pour charger un jeu de données. Si vous souhaitez conserver de l'espace sur le disque dur, vous pouvez passer `DownloadConfig(delete_extracted=True)` à l'argument `download_config` de `load_dataset()`. Voir la [documentation](https://huggingface.co/docs/datasets/package_reference/builder_classes.html?#datasets.utils.DownloadConfig) pour plus de détails. +✎ Par défaut, 🤗 *Datasets* décompresse les fichiers nécessaires pour charger un jeu de données. Si vous souhaitez conserver de l'espace sur le disque dur, vous pouvez passer `DownloadConfig(delete_extracted=True)` à l'argument `download_config` de `load_dataset()`. Voir la [documentation](https://huggingface.co/docs/datasets/package_reference/builder_classes.html?#datasets.utils.DownloadConfig) pour plus de détails. -Inspectons le contenu du premier exemple : +Inspectons le contenu du premier exemple : ```py pubmed_dataset[0] @@ -58,25 +58,27 @@ pubmed_dataset[0] ```python out {'meta': {'pmid': 11409574, 'language': 'eng'}, - 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection.\nTo determine the prevalence of hypoxaemia in children aged under 5 years suffering acute lower respiratory infections (ALRI), the risk factors for hypoxaemia in children under 5 years of age with ALRI, and the association of hypoxaemia with an increased risk of dying in children of the same age ...'} + 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection.\nTo determine the prevalence of hypoxaemia in children aged under 5 years suffering acute lower respiratory infections (ALRI), the risk factors for hypoxaemia in children under 5 years of age with ALRI, and the association of hypoxaemia with an increased risk of dying in children of the same age ...' +# Épidémiologie de l'hypoxémie chez les enfants souffrant d'une infection aiguë des voies respiratoires inférieures. Déterminer la prévalence de l'hypoxémie chez les enfants de moins de 5 ans souffrant d'une infection aiguë des voies respiratoires inférieures (IAVI), les facteurs de risque de l'hypoxémie chez les enfants de moins de 5 ans souffrant d'une IAVI, et l'association de l'hypoxémie à un risque accru de décès chez les enfants du même âge ... +} ``` -OK, ça ressemble au résumé d'un article médical. Voyons maintenant combien de RAM nous avons utilisé pour charger le jeu de données ! +Cela ressemble au résumé d'un article médical. Voyons maintenant combien de RAM nous avons utilisé pour charger le jeu de données ! -## La magie de la cartographie mémoire +## La magie du *memory mapping* -Un moyen simple de mesurer l'utilisation de la mémoire dans Python consiste à utiliser la bibliothèque [`psutil`](https://psutil.readthedocs.io/en/latest/), qui peut être installée avec `pip` comme suit : +Un moyen simple de mesurer l'utilisation de la mémoire dans Python consiste à utiliser la bibliothèque [`psutil`](https://psutil.readthedocs.io/en/latest/) qui peut être installée avec `pip` comme suit : ```python !pip install psutil ``` -Il fournit une classe `Process` qui nous permet de vérifier l'utilisation de la mémoire du processus en cours comme suit : +Elle fournit une classe `Process` qui permet de vérifier l'utilisation de la mémoire du processus en cours : ```py import psutil -# Process.memory_info is expressed in bytes, so convert to megabytes +# Process.memory_info est exprimé en octets, donc convertir en mégaoctets print(f"RAM used: {psutil.Process().memory_info().rss / (1024 * 1024):.2f} MB") ``` @@ -84,7 +86,7 @@ print(f"RAM used: {psutil.Process().memory_info().rss / (1024 * 1024):.2f} MB") RAM used: 5678.33 MB ``` -Ici, l'attribut `rss` fait référence à la _taille de l'ensemble résident_, qui est la fraction de mémoire qu'un processus occupe dans la RAM. Cette mesure inclut également la mémoire utilisée par l'interpréteur Python et les bibliothèques que nous avons chargées, de sorte que la quantité réelle de mémoire utilisée pour charger l'ensemble de données est un peu plus petite. À titre de comparaison, voyons la taille de l'ensemble de données sur le disque, en utilisant l'attribut `dataset_size`. Comme le résultat est exprimé en octets comme précédemment, nous devons le convertir manuellement en gigaoctets : +Ici, l'attribut `rss` fait référence à la _taille de l'ensemble résident_, qui est la fraction de mémoire qu'un processus occupe dans la RAM. Cette mesure inclut également la mémoire utilisée par l'interpréteur Python et les bibliothèques que nous avons chargées, de sorte que la quantité réelle de mémoire utilisée pour charger le jeu de données est un peu plus petite. À titre de comparaison, voyons la taille du jeu de données sur le disque en utilisant l'attribut `dataset_size`. Comme le résultat est exprimé en octets comme précédemment, nous devons le convertir manuellement en gigaoctets : ```py print(f"Number of files in dataset : {pubmed_dataset.dataset_size}") @@ -97,17 +99,17 @@ Number of files in dataset : 20979437051 Dataset size (cache file) : 19.54 GB ``` -Bien - malgré sa taille de près de 20 Go, nous pouvons charger et accéder à l'ensemble de données avec beaucoup moins de RAM ! +Malgré sa taille de près de 20 Go, nous pouvons charger et accéder au jeu de données avec beaucoup moins de RAM ! -✏️ **Essayez-le !** Choisissez l'un des [sous-ensembles](https://mystic.the-eye.eu/public/AI/pile_preliminary_components/) de la Pile qui est plus grand que la RAM de votre ordinateur portable ou de bureau, chargez avec 🤗 Datasets, et mesurez la quantité de RAM utilisée. Notez que pour obtenir une mesure précise, vous devrez le faire dans un nouveau processus. Vous pouvez trouver les tailles décompressées de chaque sous-ensemble dans le tableau 1 de [the Pile paper](https://arxiv.org/abs/2101.00027). +✏️ **Essayez !** Choisissez l'un des [sous-ensembles](https://mystic.the-eye.eu/public/AI/pile_preliminary_components/) de The Pile qui est plus grand que la RAM de votre ordinateur portable ou de bureau. Chargez le avec 🤗 *Datasets* et mesurez la quantité de RAM utilisée. Notez que pour obtenir une mesure précise, vous devrez le faire dans un nouveau processus. Vous pouvez trouver les tailles décompressées de chaque sous-ensemble dans le tableau 1 du papier de [The Pile](https://arxiv.org/abs/2101.00027). -Si vous êtes familier avec les pandas, ce résultat pourrait surprendre en raison de la célèbre [règle d'or](https://wesmckinney.com/blog/apache-arrow-pandas-internals/) de Wes Kinney selon laquelle vous avez généralement besoin de 5 à 10 fois plus de RAM que la taille de votre jeu de données. Alors, comment 🤗 Datasets résout-il ce problème de gestion de la mémoire ? 🤗 Datasets traite chaque ensemble de données comme un [fichier mappé en mémoire] (https://en.wikipedia.org/wiki/Memory-mapped_file), qui fournit un mappage entre la RAM et le stockage du système de fichiers qui permet à la bibliothèque d'accéder et d'opérer sur des éléments du jeu de données sans avoir besoin de le charger entièrement en mémoire. +Si vous êtes familier avec Pandas, ce résultat pourrait surprendre en raison de la célèbre [règle d'or](https://wesmckinney.com/blog/apache-arrow-pandas-internals/) de Wes Kinney selon laquelle vous avez généralement besoin de 5 à 10 fois plus de RAM que la taille de votre jeu de données. Alors, comment 🤗 *Datasets* résout-il ce problème de gestion de la mémoire ? 🤗 *Datasets* traite chaque jeu de données comme un [fichier mappé en mémoire](https://en.wikipedia.org/wiki/Memory-mapped_file). Cela fournit un mappage entre la RAM et le stockage du système de fichiers permettant à la bibliothèque d'accéder et d'opérer sur des éléments du jeu de données sans avoir besoin de le charger entièrement en mémoire. -Les fichiers mappés en mémoire peuvent également être partagés entre plusieurs processus, ce qui permet de paralléliser des méthodes telles que `Dataset.map()` sans avoir à déplacer ou copier l'ensemble de données. Sous le capot, ces capacités sont toutes réalisées par le format de mémoire [Apache Arrow](https://arrow.apache.org) et [`pyarrow`](https://arrow.apache.org/docs/python/index .html), qui accélèrent le chargement et le traitement des données. (Pour plus de détails sur Apache Arrow et les comparaisons avec Pandas, consultez [l'article de blog de Dejan Simic](https://towardsdatascience.com/apache-arrow-read-dataframe-with-zero-memory-69634092b1a).) Pour voir ceci en action, effectuons un petit test de vitesse en itérant sur tous les éléments du jeu de données PubMed Abstracts : +Les fichiers mappés en mémoire peuvent également être partagés entre plusieurs processus ce qui permet de paralléliser des méthodes telles que `Dataset.map()` sans avoir à déplacer ou copier le jeu de données. Sous le capot, ces capacités sont toutes réalisées par le format de mémoire [Apache Arrow](https://arrow.apache.org) et [`pyarrow`](https://arrow.apache.org/docs/python/index .html), qui accélèrent le chargement et le traitement des données. (Pour plus de détails sur Apache Arrow et les comparaisons avec Pandas, consultez [l'article de blog de Dejan Simic](https://towardsdatascience.com/apache-arrow-read-dataframe-with-zero-memory-69634092b1a).) Pour voir ceci en action, effectuons un petit test de vitesse en itérant sur tous les éléments du jeu de données PubMed Abstracts : ```py import timeit @@ -129,17 +131,17 @@ print( 'Iterated over 15518009 examples (about 19.5 GB) in 64.2s, i.e. 0.304 GB/s' ``` -Ici, nous avons utilisé le module `timeit` de Python pour mesurer le temps d'exécution pris par `code_snippet`. Vous pourrez généralement itérer sur un ensemble de données à une vitesse de quelques dixièmes de Go/s à plusieurs Go/s. Cela fonctionne très bien pour la grande majorité des applications, mais vous devrez parfois travailler avec un ensemble de données trop volumineux pour être même stocké sur le disque dur de votre ordinateur portable. Par exemple, si nous essayions de télécharger la Pile dans son intégralité, nous aurions besoin de 825 Go d'espace disque libre ! Pour gérer ces cas, 🤗 Datasets fournit une fonctionnalité de streaming qui nous permet de télécharger et d'accéder aux éléments à la volée, sans avoir besoin de télécharger l'intégralité du jeu de données. Voyons comment cela fonctionne. +Ici, nous avons utilisé le module `timeit` de Python pour mesurer le temps d'exécution pris par `code_snippet`. Vous pourrez généralement itérer sur un jeu de données à une vitesse de quelques dixièmes de Go/s à plusieurs Go/s. Cela fonctionne très bien pour la grande majorité des applications, mais vous devrez parfois travailler avec un jeu de données trop volumineux pour être même stocké sur le disque dur de votre ordinateur portable. Par exemple, si nous essayions de télécharger The Pile dans son intégralité, nous aurions besoin de 825 Go d'espace disque libre ! Pour gérer ces cas, 🤗 *Datasets* fournit une fonctionnalité de streaming qui nous permet de télécharger et d'accéder aux éléments à la volée, sans avoir besoin de télécharger l'intégralité du jeu de données. Voyons comment cela fonctionne. -💡 Dans les notebooks Jupyter, vous pouvez également chronométrer les cellules à l'aide de la fonction magique [`%%timeit`](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-timeit). +💡 Dans les *notebooks* Jupyter, vous pouvez également chronométrer les cellules à l'aide de la fonction magique [`%%timeit`](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-timeit). -## Ensembles de données en continu +## Jeux de données en continu -Pour activer le streaming de l'ensemble de données, il vous suffit de passer l'argument `streaming=True` à la fonction `load_dataset()`. Par exemple, chargeons à nouveau le jeu de données PubMed Abstracts, mais en mode streaming : +Pour activer le streaming du jeu de données, il vous suffit de passer l'argument `streaming=True` à la fonction `load_dataset()`. Par exemple, chargeons à nouveau le jeu de données PubMed Abstracts mais en mode streaming : ```py pubmed_dataset_streamed = load_dataset( @@ -147,7 +149,7 @@ pubmed_dataset_streamed = load_dataset( ) ``` -Au lieu du familier `Dataset` que nous avons rencontré ailleurs dans ce chapitre, l'objet retourné avec `streaming=True` est un `IterableDataset`. Comme son nom l'indique, pour accéder aux éléments d'un `IterableDataset`, nous devons parcourir celui-ci. Nous pouvons accéder au premier élément de notre jeu de données diffusé comme suit : +Au lieu du familier `Dataset` que nous avons rencontré ailleurs dans ce chapitre, l'objet retourné avec `streaming=True` est un `IterableDataset`. Comme son nom l'indique, pour accéder aux éléments d'un `IterableDataset`, nous devons parcourir celui-ci. Nous pouvons accéder au premier élément de notre jeu de données diffusé comme suit : ```py @@ -159,7 +161,7 @@ next(iter(pubmed_dataset_streamed)) 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection.\nTo determine the prevalence of hypoxaemia in children aged under 5 years suffering acute lower respiratory infections (ALRI), the risk factors for hypoxaemia in children under 5 years of age with ALRI, and the association of hypoxaemia with an increased risk of dying in children of the same age ...'} ``` -Les éléments d'un ensemble de données diffusé en continu peuvent être traités à la volée à l'aide de `IterableDataset.map()`, ce qui est utile pendant la formation si vous avez besoin de tokeniser les entrées. Le processus est exactement le même que celui que nous avons utilisé pour tokeniser notre jeu de données dans [Chapitre 3](/course/chapter3), à la seule différence que les sorties sont renvoyées une par une : +Les éléments d'un jeu de données diffusé en continu peuvent être traités à la volée à l'aide de `IterableDataset.map()`, ce qui est utile pendant l’entraînement si vous avez besoin de tokeniser les entrées. Le processus est exactement le même que celui que nous avons utilisé pour tokeniser notre jeu de données dans [Chapitre 3](/course/fr/chapter3), à la seule différence que les sorties sont renvoyées une par une : ```py from transformers import AutoTokenizer @@ -175,11 +177,11 @@ next(iter(tokenized_dataset)) -💡 Pour accélérer la tokenisation avec le streaming, vous pouvez passer `batched=True`, comme nous l'avons vu dans la dernière section. Il traitera les exemples lot par lot ; la taille de lot par défaut est de 1 000 et peut être spécifiée avec l'argument `batch_size`. +💡 Pour accélérer la tokenisation avec le streaming, vous pouvez passer `batched=True`, comme nous l'avons vu dans la dernière section. Il traitera les exemples batch par batch. La taille de batch par défaut est de 1 000 et peut être spécifiée avec l'argument `batch_size`. -Vous pouvez également mélanger un ensemble de données diffusé en continu à l'aide de `IterableDataset.shuffle()`, mais contrairement à `Dataset.shuffle()`, cela ne mélange que les éléments dans un `buffer_size` prédéfini : +Vous pouvez également mélanger un jeu de données diffusé en continu à l'aide de `IterableDataset.shuffle()`, mais contrairement à `Dataset.shuffle()`, cela ne mélange que les éléments dans un `buffer_size` prédéfini : ```py shuffled_dataset = pubmed_dataset_streamed.shuffle(buffer_size=10_000, seed=42) @@ -188,10 +190,12 @@ next(iter(shuffled_dataset)) ```python out {'meta': {'pmid': 11410799, 'language': 'eng'}, - 'text': 'Randomized study of dose or schedule modification of granulocyte colony-stimulating factor in platinum-based chemotherapy for elderly patients with lung cancer ...'} + 'text': 'Randomized study of dose or schedule modification of granulocyte colony-stimulating factor in platinum-based chemotherapy for elderly patients with lung cancer ...' +# Étude randomisée sur la modification de la dose ou du calendrier d'administration du facteur de stimulation des colonies de granulocytes dans le cadre d'une chimiothérapie à base de platine chez les patients âgés atteints de cancer du poumon ... +} ``` -Dans cet exemple, nous avons sélectionné un exemple aléatoire parmi les 10 000 premiers exemples du tampon. Une fois qu'un exemple est accédé, sa place dans le tampon est remplie avec l'exemple suivant dans le corpus (c'est-à-dire le 10 001e exemple dans le cas ci-dessus). Vous pouvez également sélectionner des éléments d'un ensemble de données diffusé en continu à l'aide des fonctions `IterableDataset.take()` et `IterableDataset.skip()`, qui agissent de la même manière que `Dataset.select()`. Par exemple, pour sélectionner les 5 premiers exemples dans l'ensemble de données PubMed Abstracts, nous pouvons procéder comme suit : +Dans cet exemple, nous avons sélectionné un exemple aléatoire parmi les 10 000 premiers exemples du tampon. Une fois qu'un exemple est accédé, sa place dans le tampon est remplie avec l'exemple suivant dans le corpus (c'est-à-dire le 10 001e exemple dans le cas ci-dessus). Vous pouvez également sélectionner des éléments d'un jeu de données diffusé en continu à l'aide des fonctions `IterableDataset.take()` et `IterableDataset.skip()`, qui agissent de la même manière que `Dataset.select()`. Par exemple, pour sélectionner les 5 premiers exemples dans le jeu de données PubMed Abstracts, nous pouvons procéder comme suit : ```py dataset_head = pubmed_dataset_streamed.take(5) @@ -200,27 +204,32 @@ list(dataset_head) ```python out [{'meta': {'pmid': 11409574, 'language': 'eng'}, - 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection ...'}, + 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection ...' +# Épidémiologie de l'hypoxémie chez les enfants atteints d'une infection aiguë des voies respiratoires inférieures ...}, {'meta': {'pmid': 11409575, 'language': 'eng'}, - 'text': 'Clinical signs of hypoxaemia in children with acute lower respiratory infection: indicators of oxygen therapy ...'}, + 'text': 'Clinical signs of hypoxaemia in children with acute lower respiratory infection: indicators of oxygen therapy ...' +# Signes cliniques d'hypoxémie chez les enfants atteints d'une infection aiguë des voies respiratoires inférieures : indicateurs de l'oxygénothérapie ...}, {'meta': {'pmid': 11409576, 'language': 'eng'}, - 'text': "Hypoxaemia in children with severe pneumonia in Papua New Guinea ..."}, + 'text': "Hypoxaemia in children with severe pneumonia in Papua New Guinea ..." +# Hypoxémie chez les enfants atteints de pneumonie grave en Papouasie-Nouvelle-Guinée ...}, {'meta': {'pmid': 11409577, 'language': 'eng'}, - 'text': 'Oxygen concentrators and cylinders ...'}, + 'text': 'Oxygen concentrators and cylinders ...' +# Concentrateurs et bouteilles d'oxygène...}, {'meta': {'pmid': 11409578, 'language': 'eng'}, - 'text': 'Oxygen supply in rural africa: a personal experience ...'}] + 'text': 'Oxygen supply in rural africa: a personal experience ...' +# L'approvisionnement en oxygène dans les zones rurales africaines : une expérience personnelle ...}] ``` -De même, vous pouvez utiliser la fonction `IterableDataset.skip()` pour créer des fractionnements d'entraînement et de validation à partir d'un ensemble de données mélangé comme suit : +De même, vous pouvez utiliser la fonction `IterableDataset.skip()` pour créer des fractionnements d'entraînement et de validation à partir d'un jeu de données mélangé comme suit : ```py -# Skip the first 1,000 examples and include the rest in the training set +# Ignorer les 1 000 premiers exemples et inclure le reste dans l'ensemble d'apprentissage. train_dataset = shuffled_dataset.skip(1000) -# Take the first 1,000 examples for the validation set +# Prendre les 1 000 premiers exemples pour l'ensemble de validation. validation_dataset = shuffled_dataset.take(1000) ``` -Terminons notre exploration du streaming d'ensembles de données avec une application commune : combiner plusieurs ensembles de données pour créer un seul corpus. 🤗 Datasets fournit une fonction `interleave_datasets()` qui convertit une liste d'objets `IterableDataset` en un seul `IterableDataset`, où les éléments du nouveau jeu de données sont obtenus en alternant entre les exemples source. Cette fonction est particulièrement utile lorsque vous essayez de combiner de grands ensembles de données. Par exemple, diffusons le sous-ensemble FreeLaw de la pile, qui est un ensemble de données de 51 Go d'avis juridiques de tribunaux américains : +Terminons notre exploration du streaming des jeux de données avec une application commune : combiner plusieurs jeux de données pour créer un seul corpus. 🤗 *Datasets* fournit une fonction `interleave_datasets()` qui convertit une liste d'objets `IterableDataset` en un seul `IterableDataset`, où les éléments du nouveau jeu de données sont obtenus en alternant entre les exemples source. Cette fonction est particulièrement utile lorsque vous essayez de combiner de grands jeux de données. Par exemple, streamons FreeLaw, un sous-ensemble de The Pile et qui est un jeu de données de 51 Go d'avis juridiques de tribunaux américains : ```py law_dataset_streamed = load_dataset( @@ -239,7 +248,7 @@ next(iter(law_dataset_streamed)) 'text': '\n461 U.S. 238 (1983)\nOLIM ET AL.\nv.\nWAKINEKONA\nNo. 81-1581.\nSupreme Court of United States.\nArgued January 19, 1983.\nDecided April 26, 1983.\nCERTIORARI TO THE UNITED STATES COURT OF APPEALS FOR THE NINTH CIRCUIT\n*239 Michael A. Lilly, First Deputy Attorney General of Hawaii, argued the cause for petitioners. With him on the brief was James H. Dannenberg, Deputy Attorney General...'} ``` -Cet ensemble de données est suffisamment volumineux pour solliciter la RAM de la plupart des ordinateurs portables, mais nous avons pu le charger et y accéder sans transpirer ! Combinons maintenant les exemples des jeux de données FreeLaw et PubMed Abstracts avec la fonction `interleave_datasets()` : +Ce jeu de données est suffisamment volumineux pour solliciter la RAM de la plupart des ordinateurs portables, mais nous avons pu le charger et y accéder sans transpirer ! Combinons maintenant les jeux de données FreeLaw et PubMed Abstracts avec la fonction `interleave_datasets()` : ```py from itertools import islice @@ -258,9 +267,9 @@ list(islice(combined_dataset, 2)) 'text': '\n461 U.S. 238 (1983)\nOLIM ET AL.\nv.\nWAKINEKONA\nNo. 81-1581.\nSupreme Court of United States.\nArgued January 19, 1983.\nDecided April 26, 1983.\nCERTIORARI TO THE UNITED STATES COURT OF APPEALS FOR THE NINTH CIRCUIT\n*239 Michael A. Lilly, First Deputy Attorney General of Hawaii, argued the cause for petitioners. With him on the brief was James H. Dannenberg, Deputy Attorney General...'}] ``` -Ici, nous avons utilisé la fonction `islice()` du module `itertools` de Python pour sélectionner les deux premiers exemples de l'ensemble de données combiné, et nous pouvons voir qu'ils correspondent aux premiers exemples de chacun des deux ensembles de données source. +Ici, nous avons utilisé la fonction `islice()` du module `itertools` de Python pour sélectionner les deux premiers exemples du jeu de données combiné. Nous pouvons voir qu'ils correspondent aux premiers exemples de chacun des deux jeux de données source. -Enfin, si vous souhaitez diffuser le Pile dans son intégralité de 825 Go, vous pouvez récupérer tous les fichiers préparés comme suit : +Enfin, si vous souhaitez streamer The Pile dans son intégralité de 825 Go, vous pouvez récupérer tous les fichiers préparés comme suit : ```py base_url = "https://mystic.the-eye.eu/public/AI/pile/" @@ -280,8 +289,8 @@ next(iter(pile_dataset["train"])) -✏️ **Essayez-le !** Utilisez l'un des grands corpus Common Crawl comme [`mc4`](https://huggingface.co/datasets/mc4) ou [`oscar`](https://huggingface.co /datasets/oscar) pour créer un jeu de données multilingue en continu qui représente les proportions de langues parlées dans un pays de votre choix. Par exemple, les quatre langues nationales en Suisse sont l'allemand, le français, l'italien et le romanche, vous pouvez donc essayer de créer un corpus suisse en échantillonnant les sous-ensembles Oscar en fonction de leur proportion parlée. +✏️ **Essayez !** Utilisez l'un des grands corpus Common Crawl comme [`mc4`](https://huggingface.co/datasets/mc4) ou [`oscar`](https://huggingface.co/datasets/oscar) pour créer en streaming un jeu de données multilingue représentant les proportions de langues parlées dans un pays de votre choix. Par exemple, les quatre langues nationales en Suisse sont l'allemand, le français, l'italien et le romanche. Vous pouvez donc essayer de créer un corpus suisse en échantillonnant les sous-ensembles Oscar en fonction de leur proportion parlée. -Vous disposez maintenant de tous les outils dont vous avez besoin pour charger et traiter des ensembles de données de toutes formes et tailles - mais à moins que vous ne soyez exceptionnellement chanceux, il arrivera un moment dans votre parcours PNL où vous devrez réellement créer un ensemble de données pour résoudre le problème à portée de main. C'est le sujet de la section suivante ! +Vous disposez maintenant de tous les outils dont vous avez besoin pour charger et traiter des jeux de données de toutes formes et tailles. Cependant à moins que vous ne soyez exceptionnellement chanceux, il arrivera un moment dans votre cheminement en traitement du langage naturel où vous devrez réellement créer un jeu de données pour résoudre un problème donné. C'est le sujet de la section suivante ! diff --git a/chapters/fr/chapter5/5.mdx b/chapters/fr/chapter5/5.mdx index 298f69200..42a9ffa15 100644 --- a/chapters/fr/chapter5/5.mdx +++ b/chapters/fr/chapter5/5.mdx @@ -7,37 +7,37 @@ {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/chapter5/section5.ipynb"}, ]} /> -Parfois, l'ensemble de données dont vous avez besoin pour créer une application NLP n'existe pas, vous devrez donc le créer vous-même. Dans cette section, nous allons vous montrer comment créer un corpus de [problèmes GitHub](https://github.com/features/issues/), qui sont couramment utilisés pour suivre les bogues ou les fonctionnalités dans les référentiels GitHub. Ce corpus pourrait être utilisé à diverses fins, notamment : +Parfois, le jeu de données dont vous avez besoin pour créer une application de NLP n'existe pas. Vous devrez donc le créer vous-même. Dans cette section, nous allons vous montrer comment créer un corpus de [problèmes GitHub](https://github.com/features/issues/), qui sont couramment utilisés pour suivre les bogues ou les fonctionnalités dans les dépôts GitHub. Ce corpus pourrait être utilisé à diverses fins, notamment : -* Explorer combien de temps il faut pour fermer les problèmes ouverts ou les demandes d'extraction -* Entraînement d'un _classificateur multilabel_ capable d'étiqueter les problèmes avec des métadonnées basées sur la description du problème (par exemple, "bogue", "amélioration" ou "question") -* Création d'un moteur de recherche sémantique pour trouver les problèmes correspondant à la requête d'un utilisateur +* explorer combien de temps il faut pour fermer les problèmes ouverts ou les *pull requests* +* entraîner d'un _classificateur multilabel_ capable d'étiqueter les problèmes avec des métadonnées basées sur la description du problème (par exemple, "bogue", "amélioration" ou "question") +* créer un moteur de recherche sémantique pour trouver les problèmes correspondant à la requête d'un utilisateur -Ici, nous nous concentrerons sur la création du corpus, et dans la section suivante, nous aborderons l'application de recherche sémantique. Pour garder les choses méta, nous utiliserons les problèmes GitHub associés à un projet open source populaire : 🤗 Datasets ! Voyons comment obtenir les données et explorons les informations contenues dans ces problèmes. +Ici, nous nous concentrerons sur la création du corpus, et dans la section suivante, nous aborderons l'application de recherche sémantique. Pour garder les choses méta, nous utiliserons les problèmes GitHub associés à un projet open source populaire : 🤗 *Datasets* ! Voyons comment obtenir les données et explorons les informations contenues dans ces problèmes. ## Obtenir les données -Vous pouvez trouver tous les problèmes dans 🤗 Datasets en accédant à l'[onglet Problèmes] du référentiel (https://github.com/huggingface/datasets/issues). Comme le montre la capture d'écran suivante, au moment de la rédaction, il y avait 331 problèmes ouverts et 668 problèmes fermés. +Vous pouvez trouver tous les problèmes dans 🤗 *Datasets* en accédant à l'[onglet « Issues »](https://github.com/huggingface/datasets/issues) du dépôt. Comme le montre la capture d'écran suivante, au moment de la rédaction, il y avait 331 problèmes ouverts et 668 problèmes fermés.
-Les problèmes GitHub associés aux 🤗 Datasets. +The GitHub issues associated with 🤗 Datasets.
Si vous cliquez sur l'un de ces problèmes, vous constaterez qu'il contient un titre, une description et un ensemble d'étiquettes qui caractérisent le problème. Un exemple est montré dans la capture d'écran ci-dessous.
-Un problème GitHub typique dans le référentiel 🤗 Datasets. +A typical GitHub issue in the 🤗 Datasets repository.
-Pour télécharger tous les problèmes du référentiel, nous utiliserons l'[API REST GitHub](https://docs.github.com/en/rest) pour interroger le point de terminaison [`Issues`](https://docs.github. com/en/rest/reference/issues#list-repository-issues). Ce point de terminaison renvoie une liste d'objets JSON, chaque objet contenant un grand nombre de champs qui incluent le titre et la description ainsi que des métadonnées sur l'état du problème, etc. +Pour télécharger tous les problèmes du dépôt, nous utilisons l'[API REST GitHub](https://docs.github.com/en/rest) pour interroger le point de terminaison [`Issues`](https://docs.github.com/en/rest/reference/issues#list-repository-issues). Ce point de terminaison renvoie une liste d'objets JSON. Chaque objet contenant un grand nombre de champs qui incluent le titre et la description ainsi que des métadonnées sur l'état du problème, etc. -Un moyen pratique de télécharger les problèmes consiste à utiliser la bibliothèque "requests", qui est la méthode standard pour effectuer des requêtes HTTP en Python. Vous pouvez installer la bibliothèque en exécutant : +Un moyen pratique de télécharger les problèmes consiste à utiliser la bibliothèque `requests`, qui est la méthode standard pour effectuer des requêtes HTTP en Python. Vous pouvez installer la bibliothèque en exécutant : ```python !pip install requests ``` -Une fois la bibliothèque installée, vous pouvez envoyer des requêtes GET au point de terminaison `Issues` en appelant la fonction `requests.get()`. Par exemple, vous pouvez exécuter la commande suivante pour récupérer le premier numéro sur la première page : +Une fois la bibliothèque installée, vous pouvez envoyer des requêtes GET au point de terminaison `Issues` en appelant la fonction `requests.get()`. Par exemple, vous pouvez exécuter la commande suivante pour récupérer le premier numéro sur la première page : ```py import requests @@ -46,7 +46,7 @@ url = "https://api.github.com/repos/huggingface/datasets/issues?page=1&per_page= response = requests.get(url) ``` -L'objet `response` contient de nombreuses informations utiles sur la requête, y compris le code d'état HTTP : +L'objet `response` contient de nombreuses informations utiles sur la requête, y compris le code d'état HTTP : ```py response.status_code @@ -56,7 +56,7 @@ response.status_code 200 ``` -où un statut "200" signifie que la requête a réussi (vous pouvez trouver une liste des codes de statut HTTP possibles [ici](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes)). Ce qui nous intéresse vraiment, cependant, c'est le _payload_, qui peut être consulté dans différents formats comme les octets, les chaînes ou JSON. Comme nous savons que nos problèmes sont au format JSON, examinons la charge utile comme suit : +où un statut `200` signifie que la requête a réussi (vous pouvez trouver une liste des codes de statut HTTP possibles [ici](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes)). Ce qui nous intéresse vraiment, cependant, c'est le _payload_, qui peut être consulté dans différents formats comme les octets, les chaînes ou JSON. Comme nous savons que nos problèmes sont au format JSON, examinons la charge utile comme suit : ```py response.json() @@ -115,11 +115,11 @@ Waouh, ça fait beaucoup d'informations ! Nous pouvons voir des champs utiles co -✏️ **Essayez-le !** Cliquez sur quelques-unes des URL dans la charge utile JSON ci-dessus pour avoir une idée du type d'informations auxquelles chaque problème GitHub est lié. +✏️ **Essayez !** Cliquez sur quelques-unes des URL pour avoir une idée du type d'informations auxquelles chaque problème GitHub est lié. -Comme décrit dans la [documentation] GitHub(https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting), les requêtes non authentifiées sont limitées à 60 requêtes par heure. Bien que vous puissiez augmenter le paramètre de requête `per_page` pour réduire le nombre de requêtes que vous effectuez, vous atteindrez toujours la limite de débit sur tout référentiel contenant plus de quelques milliers de problèmes. Donc, à la place, vous devez suivre les [instructions] de GitHub (https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) sur la création d'un _jeton d'accès personnel_ afin que vous peut augmenter la limite de débit à 5 000 requêtes par heure. Une fois que vous avez votre jeton, vous pouvez l'inclure dans l'en-tête de la requête : +Comme décrit dans la [documentation GitHub](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting), les requêtes non authentifiées sont limitées à 60 requêtes par heure. Bien que vous puissiez augmenter le paramètre de requête `per_page` pour réduire le nombre de requêtes que vous effectuez, vous atteindrez toujours la limite de débit sur tout dépot contenant des milliers de problèmes. Donc, à la place, vous devez suivre les [instructions de GitHub](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) sur la création d'un _jeton d'accès personnel_ afin que vous peut augmenter la limite de débit à 5 000 requêtes par heure. Une fois que vous avez votre *token*, vous pouvez l'inclure dans l'en-tête de la requête : ```py GITHUB_TOKEN = xxx # Copy your GitHub token here @@ -128,11 +128,11 @@ headers = {"Authorization": f"token {GITHUB_TOKEN}"} -⚠️ Ne partagez pas un notebook avec votre `GITHUB_TOKEN` collé dedans. Nous vous recommandons de supprimer la dernière cellule une fois que vous l'avez exécutée pour éviter de divulguer accidentellement ces informations. Mieux encore, stockez le jeton dans un fichier *.env* et utilisez la [bibliothèque `python-dotenv`](https://github.com/theskumar/python-dotenv) pour le charger automatiquement pour vous en tant que variable d'environnement. +⚠️ Ne partagez pas un *notebook* avec votre `GITHUB_TOKEN` collé dedans. Nous vous recommandons de supprimer la dernière cellule une fois que vous l'avez exécutée pour éviter de divulguer accidentellement ces informations. Mieux encore, stockez le jeton dans un fichier *.env* et utilisez la [bibliothèque `python-dotenv`](https://github.com/theskumar/python-dotenv) pour le charger automatiquement pour vous en tant que variable d'environnement. -Maintenant que nous avons notre jeton d'accès, créons une fonction qui peut télécharger tous les problèmes depuis un référentiel GitHub : +Maintenant que nous avons notre jeton d'accès, créons une fonction qui peut télécharger tous les problèmes depuis un référentiel GitHub : ```py import time @@ -178,14 +178,14 @@ def fetch_issues( ) ``` -Désormais, lorsque nous appellerons `fetch_issues()`, tous les problèmes seront téléchargés par lots pour éviter de dépasser la limite de GitHub sur le nombre de requêtes par heure ; le résultat sera stocké dans un fichier _repository_name-issues.jsonl_, où chaque ligne est un objet JSON qui représente un problème. Utilisons cette fonction pour saisir tous les problèmes de 🤗 Datasets : +Désormais, lorsque nous appellerons `fetch_issues()`, tous les problèmes seront téléchargés par batchs pour éviter de dépasser la limite de GitHub sur le nombre de requêtes par heure. Le résultat sera stocké dans un fichier _repository_name-issues.jsonl_, où chaque ligne est un objet JSON qui représente un problème. Utilisons cette fonction pour saisir tous les problèmes de 🤗 *Datasets* : ```py -# Depending on your internet connection, this can take several minutes to run... +# En fonction de votre connexion Internet, l'exécution peut prendre plusieurs minutes... fetch_issues() ``` -Une fois les problèmes téléchargés, nous pouvons les charger localement en utilisant nos nouvelles compétences de [section 2](/course/chaper5/2) : +Une fois les problèmes téléchargés, nous pouvons les charger localement en utilisant nos nouvelles compétences de [section 2](/course/fr/chaper5/2) : ```py issues_dataset = load_dataset("json", data_files="datasets-issues.jsonl", split="train") @@ -199,15 +199,15 @@ Dataset({ }) ``` -Génial, nous avons créé notre premier ensemble de données à partir de rien ! Mais pourquoi y a-t-il plusieurs milliers de problèmes alors que l'[onglet Problèmes](https://github.com/huggingface/datasets/issues) du 🤗 Datasets n'affiche qu'environ 1 000 problèmes au total 🤔 ? Comme décrit dans la [documentation] GitHub(https://docs.github.com/en/rest/reference/issues#list-issues-assigned-to-the-authenticated-user), c'est parce que nous avons téléchargé tous les les demandes d'extraction également : +Génial, nous avons créé notre premier jeu de données à partir de rien ! Mais pourquoi y a-t-il plusieurs milliers de problèmes alors que l'[onglet « Issues »](https://github.com/huggingface/datasets/issues) de la librairie 🤗 *Datasets* n'affiche qu'environ 1 000 problèmes au total 🤔 ? Comme décrit dans la [documentation GitHub](https://docs.github.com/en/rest/reference/issues#list-issues-assigned-to-the-authenticated-user), c'est parce que nous avons téléchargé toutes les *pull requests* également : -> L'API REST v3 de GitHub considère chaque demande d'extraction comme un problème, mais chaque problème n'est pas une demande d'extraction. Pour cette raison, les points de terminaison "Problèmes" peuvent renvoyer à la fois des problèmes et des demandes d'extraction dans la réponse. Vous pouvez identifier les demandes d'extraction par la clé `pull_request`. Sachez que l'identifiant d'une demande d'extraction renvoyée par les points de terminaison "Problèmes" sera un identifiant de problème. +> L'API REST v3 de GitHub considère chaque *pull request* comme un problème, mais chaque problème n'est pas une *pull request*. Pour cette raison, les points de terminaison « Issues » peuvent renvoyer à la fois des problèmes et des *pull requests* dans la réponse. Vous pouvez identifier les *pull requests* par la clé `pull_request`. Sachez que l'identifiant d'une *pull request* renvoyée par les points de terminaison « Issues » sera un identifiant de problème. -Étant donné que le contenu des problèmes et des demandes d'extraction est assez différent, procédons à un prétraitement mineur pour nous permettre de les distinguer. +Étant donné que le contenu des « Issues » et des *pull request* est assez différent, procédons à un prétraitement mineur pour nous permettre de les distinguer. ## Nettoyer les données -L'extrait ci-dessus de la documentation de GitHub nous indique que la colonne "pull_request" peut être utilisée pour différencier les problèmes et les demandes d'extraction. Regardons un échantillon aléatoire pour voir quelle est la différence. Comme nous l'avons fait dans [section 3](/course/chapter5/3), nous allons enchaîner `Dataset.shuffle()` et `Dataset.select()` pour créer un échantillon aléatoire, puis compresser `html_url` et ` pull_request` afin que nous puissions comparer les différentes URL : +L'extrait ci-dessus de la documentation de GitHub nous indique que la colonne `pull_request` peut être utilisée pour différencier les *issues* et les *pull requests*. Regardons un échantillon aléatoire pour voir quelle est la différence. Comme nous l'avons fait dans [section 3](/course/fr/chapter5/3), nous allons enchaîner `Dataset.shuffle()` et `Dataset.select()` pour créer un échantillon aléatoire, puis compresser `html_url` et ` pull_request` afin que nous puissions comparer les différentes URL : ```py sample = issues_dataset.shuffle(seed=666).select(range(3)) @@ -229,7 +229,7 @@ for url, pr in zip(sample["html_url"], sample["pull_request"]): >> Pull request: {'url': 'https://api.github.com/repos/huggingface/datasets/pulls/783', 'html_url': 'https://github.com/huggingface/datasets/pull/783', 'diff_url': 'https://github.com/huggingface/datasets/pull/783.diff', 'patch_url': 'https://github.com/huggingface/datasets/pull/783.patch'} ``` -Ici, nous pouvons voir que chaque demande d'extraction est associée à diverses URL, tandis que les problèmes ordinaires ont une entrée "Aucun". Nous pouvons utiliser cette distinction pour créer une nouvelle colonne `is_pull_request` qui vérifie si le champ `pull_request` est `None` ou non : +Ici, nous pouvons voir que chaque *pull request* est associée à diverses URL, tandis que les problèmes ordinaires ont une entrée `None`. Nous pouvons utiliser cette distinction pour créer une nouvelle colonne `is_pull_request` qui vérifie si le champ `pull_request` est `None` ou non : ```py issues_dataset = issues_dataset.map( @@ -239,23 +239,23 @@ issues_dataset = issues_dataset.map( -✏️ **Essayez-le !** Calculez le temps moyen nécessaire pour résoudre les problèmes dans 🤗 Datasets. Vous pouvez trouver la fonction `Dataset.filter()` utile pour filtrer les demandes d'extraction et les problèmes ouverts, et vous pouvez utiliser la fonction `Dataset.set_format()` pour convertir l'ensemble de données en un `DataFrame` afin que vous puissiez facilement manipuler les horodatages `created_at` et `closed_at`. Pour les points bonus, calculez le temps moyen nécessaire pour fermer les demandes d'extraction. +✏️ **Essayez !** Calculez le temps moyen nécessaire pour résoudre les problèmes dans 🤗 *Datasets*. Vous pouvez trouver la fonction `Dataset.filter()` utile pour filtrer les demandes d'extraction et les problèmes ouverts. Vous pouvez utiliser la fonction `Dataset.set_format()` pour convertir le jeu de données en un `DataFrame` afin que vous puissiez facilement manipuler les horodatages `created_at` et `closed_at`. Pour les points bonus, calculez le temps moyen nécessaire pour fermer les *pull_requests*. -Bien que nous puissions continuer à nettoyer davantage l'ensemble de données en supprimant ou en renommant certaines colonnes, il est généralement recommandé de conserver l'ensemble de données aussi "brut" que possible à ce stade afin qu'il puisse être facilement utilisé dans plusieurs applications. +Bien que nous puissions continuer à nettoyer davantage le jeu de données en supprimant ou en renommant certaines colonnes, il est généralement recommandé de le conserver aussi brut que possible à ce stade afin qu'il puisse être facilement utilisé dans plusieurs applications. -Avant de pousser notre ensemble de données vers le Hugging Face Hub, traitons d'une chose qui lui manque : les commentaires associés à chaque problème et pull request. Nous les ajouterons ensuite avec - vous l'avez deviné - l'API GitHub REST ! +Avant de pousser notre jeu de données vers le *Hub* d’Hugging Face, traitons une chose manquant : les commentaires associés à chaque problème et *pull requests*. Nous les ajouterons ensuite avec l'API GitHub REST ! ## Enrichir le jeu de données -Comme le montre la capture d'écran suivante, les commentaires associés à un problème ou à une demande d'extraction fournissent une riche source d'informations, en particulier si nous souhaitons créer un moteur de recherche pour répondre aux requêtes des utilisateurs sur la bibliothèque. +Comme le montre la capture d'écran suivante, les commentaires associés à un problème ou à une *pull request* fournissent une riche source d'informations, en particulier si nous souhaitons créer un moteur de recherche pour répondre aux requêtes des utilisateurs sur la bibliothèque.
-Commentaires associés à un problème concernant 🤗 Datasets. +Comments associated with an issue about 🤗 Datasets.
-L'API REST GitHub fournit un point de terminaison [`Comments`](https://docs.github.com/en/rest/reference/issues#list-issue-comments) qui renvoie tous les commentaires associés à un numéro de problème. Testons le point de terminaison pour voir ce qu'il renvoie : +L'API REST GitHub fournit un point de terminaison [`Comments`](https://docs.github.com/en/rest/reference/issues#list-issue-comments) qui renvoie tous les commentaires associés à un numéro de problème. Testons le point de terminaison pour voir ce qu'il renvoie : ```py issue_number = 2792 @@ -295,7 +295,7 @@ response.json() 'performed_via_github_app': None}] ``` -Nous pouvons voir que le commentaire est stocké dans le champ `body`, écrivons donc une fonction simple qui renvoie tous les commentaires associés à un problème en sélectionnant le contenu `body` pour chaque élément dans `response.json()` : +Nous pouvons voir que le commentaire est stocké dans le champ `body`. Ecrivons donc une fonction simple qui renvoie tous les commentaires associés à un problème en sélectionnant le contenu `body` pour chaque élément dans `response.json()` : ```py def get_comments(issue_number): @@ -312,7 +312,7 @@ get_comments(2792) ["@albertvillanova my tests are failing here:\r\n```\r\ndataset_name = 'gooaq'\r\n\r\n def test_load_dataset(self, dataset_name):\r\n configs = self.dataset_tester.load_all_configs(dataset_name, is_local=True)[:1]\r\n> self.dataset_tester.check_load_dataset(dataset_name, configs, is_local=True, use_local_dummy_data=True)\r\n\r\ntests/test_dataset_common.py:234: \r\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \r\ntests/test_dataset_common.py:187: in check_load_dataset\r\n self.parent.assertTrue(len(dataset[split]) > 0)\r\nE AssertionError: False is not true\r\n```\r\nWhen I try loading dataset on local machine it works fine. Any suggestions on how can I avoid this error?"] ``` -Cela a l'air bien, alors utilisons `Dataset.map()` pour ajouter une nouvelle colonne `commentaires` à chaque problème de notre ensemble de données : +Cela a l'air bien. Utilisons `Dataset.map()` pour ajouter une nouvelle colonne `comments` à chaque problème de notre jeu de données : ```py # Selon votre connexion internet, cela peut prendre quelques minutes... @@ -321,17 +321,17 @@ issues_with_comments_dataset = issues_dataset.map( ) ``` -La dernière étape consiste à enregistrer l'ensemble de données augmentées avec nos données brutes afin que nous puissions les pousser toutes les deux vers le Hub : +La dernière étape consiste à enregistrer le jeu de données augmentées avec nos données brutes afin que nous puissions les pousser tous les deux vers le *Hub* : ```py issues_with_comments_dataset.to_json("issues-datasets-with-comments.jsonl") ``` -## Téléchargement de l'ensemble de données sur le Hugging Face Hub +## Téléchargement du jeu de données sur le *Hub* d’Hugging Face -Maintenant que nous avons notre jeu de données augmenté, il est temps de le pousser vers le Hub afin que nous puissions le partager avec la communauté ! Pour télécharger l'ensemble de données, nous utiliserons la [bibliothèque Hub 🤗](https://github.com/huggingface/huggingface_hub), qui nous permet d'interagir avec le hub Hugging Face via une API Python. 🤗 Hub est préinstallé avec 🤗 Transformers, nous pouvons donc l'utiliser directement. Par exemple, nous pouvons utiliser la fonction `list_datasets()` pour obtenir des informations sur tous les ensembles de données publics actuellement hébergés sur le Hub : +Maintenant que nous avons notre jeu de données augmenté, il est temps de le pousser vers le *Hub* afin que nous puissions le partager avec la communauté ! Pour télécharger le jeu de données, nous utilisons la [bibliothèque 🤗 *Hub*](https://github.com/huggingface/huggingface_hub), qui nous permet d'interagir avec le *Hub* d’Hugging Face via une API Python. 🤗 *Hub* est préinstallé avec 🤗 *Transformers*, nous pouvons donc l'utiliser directement. Par exemple, nous pouvons utiliser la fonction `list_datasets()` pour obtenir des informations sur tous les ensembles de données publics actuellement hébergés sur le *Hub*: ```py from huggingface_hub import list_datasets @@ -346,9 +346,9 @@ Number of datasets on Hub: 1487 Dataset Name: acronym_identification, Tags: ['annotations_creators:expert-generated', 'language_creators:found', 'languages:en', 'licenses:mit', 'multilinguality:monolingual', 'size_categories:10K -✏️ **Essayez-le !** Utilisez votre nom d'utilisateur et votre mot de passe Hugging Face Hub pour obtenir un jeton et créer un référentiel vide appelé "github-issues". N'oubliez pas de **n'enregistrez jamais vos informations d'identification** dans Colab ou tout autre référentiel, car ces informations peuvent être exploitées par de mauvais acteurs. +✏️ **Essayez !** Utilisez votre nom d'utilisateur et votre mot de passe Hugging Face pour obtenir un jeton et créer un dépôt vide appelé `github-issues`. N'oubliez pas de **n'enregistrez jamais vos informations d'identification** dans Colab ou tout autre référentiel car ces informations peuvent être exploitées par de mauvais individus.
-Ensuite, clonons le référentiel du Hub sur notre machine locale et copions-y notre fichier d'ensemble de données. 🤗 Hub fournit une classe `Repository` pratique qui encapsule de nombreuses commandes Git courantes, donc pour cloner le référentiel distant, nous devons simplement fournir l'URL et le chemin local vers lesquels nous souhaitons cloner : +Ensuite, clonons le dépôt du Hub sur notre machine locale et copions-y notre fichier jeu de données. 🤗 *Hub* fournit une classe `Repository` pratique qui encapsule de nombreuses commandes Git courantes. Donc pour cloner le dépôt distant, nous devons simplement fournir l'URL et le chemin local vers lesquels nous souhaitons cloner : ```py from huggingface_hub import Repository @@ -392,13 +392,13 @@ repo = Repository(local_dir="github-issues", clone_from=repo_url) !cp datasets-issues-with-comments.jsonl github-issues/ ``` -Par défaut, diverses extensions de fichiers (telles que *.bin*, *.gz* et *.zip*) sont suivies avec Git LFS afin que les fichiers volumineux puissent être versionnés dans le même workflow Git. Vous pouvez trouver une liste des extensions de fichiers suivis dans le fichier *.gitattributes* du référentiel. Pour inclure le format JSON Lines dans la liste, nous pouvons exécuter la commande suivante : +Par défaut, diverses extensions de fichiers (telles que *.bin*, *.gz* et *.zip*) sont suivies avec Git LFS afin que les fichiers volumineux puissent être versionnés dans le même workflow Git. Vous pouvez trouver une liste des extensions de fichiers suivis dans le fichier *.gitattributes* du référentiel. Pour inclure le format JSON Lines dans la liste, nous pouvons exécuter la commande suivante : ```py repo.lfs_track("*.jsonl") ``` -Ensuite, nous pouvons utiliser `Repository.push_to_hub()` pour pousser l'ensemble de données vers le Hub : +Ensuite, nous pouvons utiliser `Repository.push_to_hub()` pour pousser le jeu de données vers le *Hub* : ```py repo.push_to_hub() @@ -407,10 +407,10 @@ repo.push_to_hub() Si nous naviguons vers l'URL contenue dans `repo_url`, nous devrions maintenant voir que notre fichier de jeu de données a été téléchargé.
-Notre référentiel d'ensembles de données sur le Hugging Face Hub. +Our dataset repository on the Hugging Face Hub.
-À partir de là, n'importe qui peut télécharger l'ensemble de données en fournissant simplement `load_dataset()` avec l'ID du référentiel comme argument `path` : +À partir de là, n'importe qui peut télécharger le jeu de données en fournissant simplement `load_dataset()` avec l'ID du référentiel comme argument `path` : ```py remote_dataset = load_dataset("lewtun/github-issues", split="train") @@ -424,46 +424,44 @@ Dataset({ }) ``` -Cool, nous avons poussé notre jeu de données vers le Hub et il est disponible pour que d'autres puissent l'utiliser ! Il ne reste plus qu'une chose importante à faire : ajouter une _carte de jeu de données_ qui explique comment le corpus a été créé et fournit d'autres informations utiles à la communauté. +Cool, nous avons poussé notre jeu de données vers le *Hub* et il est disponible pour que d'autres puissent l'utiliser ! Il ne reste plus qu'une chose importante à faire : ajouter une _carte de jeu de données_ qui explique comment le corpus a été créé et fournit d'autres informations utiles à la communauté. -💡 Vous pouvez également télécharger un ensemble de données sur le Hugging Face Hub directement depuis le terminal en utilisant `huggingface-cli` et un peu de magie Git. Consultez le [🤗 Datasets guide](https://huggingface.co/docs/datasets/share.html#add-a-community-dataset) pour savoir comment procéder. +💡 Vous pouvez également télécharger un jeu de données sur le *Hub* directement depuis le terminal en utilisant `huggingface-cli` et un peu de magie Git. Consultez le [guide de 🤗 *Datasets*](https://huggingface.co/docs/datasets/share.html#add-a-community-dataset) pour savoir comment procéder. -## Création d'une fiche de jeu de données +## Création d'une carte pour un jeu de données -Des ensembles de données bien documentés sont plus susceptibles d'être utiles aux autres (y compris à votre futur moi !), car ils fournissent le contexte permettant aux utilisateurs de décider si l'ensemble de données est pertinent pour leur tâche et d'évaluer les biais potentiels ou les risques associés à l'utilisation l'ensemble de données. +Des jeux de données bien documentés sont plus susceptibles d'être utiles aux autres (y compris à vous-même) car ils fournissent le contexte permettant aux utilisateurs de décider si le jeu de données est pertinent pour leur tâche et d'évaluer les biais potentiels ou les risques associés à l'utilisation du jeu de données. -Sur le Hugging Face Hub, ces informations sont stockées dans le fichier *README.md* de chaque référentiel d'ensembles de données. Il y a deux étapes principales que vous devez suivre avant de créer ce fichier : +Sur le *Hub*, ces informations sont stockées dans le fichier *README.md* de chaque dépôt de jeux de données. Il y a deux étapes principales que vous devez suivre avant de créer ce fichier : -1. Utilisez l'[application `datasets-tagging`](https://huggingface.co/datasets/tagging/) pour créer des balises de métadonnées au format YAML. Ces balises sont utilisées pour une variété de fonctionnalités de recherche sur le Hugging Face Hub et garantissent que votre ensemble de données peut être facilement trouvé par les membres de la communauté. Puisque nous avons créé un ensemble de données personnalisé ici, vous devrez cloner le référentiel `datasets-tagging` et exécuter l'application localement. Voici à quoi ressemble l'interface : +1. Utilisez l'[application `datasets-tagging`](https://huggingface.co/datasets/tagging/) pour créer des balises de métadonnées au format YAML. Ces balises sont utilisées pour une variété de fonctionnalités de recherche sur le *Hub* d’Hugging Face et garantissent que votre jeu de données peut être facilement trouvé par les membres de la communauté. Puisque nous avons créé un jeu de données personnalisé ici, vous devrez cloner le référentiel `datasets-tagging` et exécuter l'application localement. Voici à quoi ressemble l'interface :
-L'interface `datasets-tagging`. +The `datasets-tagging` interface.
-2. Lisez le [🤗 Datasets guide](https://github.com/huggingface/datasets/blob/master/templates/README_guide.md) sur la création de cartes d'ensemble de données informatives et utilisez-le comme modèle. +2. Lisez le [guide de 🤗 *Datasets*](https://github.com/huggingface/datasets/blob/master/templates/README_guide.md) sur la création des cartes informatives des jeux de données et utilisez-le comme modèle. + +Vous pouvez créer le fichier *README.md* directement sur le *Hub* et vous pouvez trouver un modèle de carte dans le dépot `lewtun/github-issues`. Une capture d'écran de la carte remplie est illustrée ci-dessous. -Vous pouvez créer le fichier *README.md* directement sur le Hub, et vous pouvez trouver un modèle de carte d'ensemble de données dans le référentiel d'ensemble de données `lewtun/github-issues`. Une capture d'écran de la carte de jeu de données remplie est illustrée ci-dessous.
-Une carte de jeu de données. +A dataset card.
-* Fichier README.md* pour votre ensemble de données de problèmes GitHub. - +✏️ **Essayez !** Utilisez l'application `dataset-tagging` et [le guide de 🤗 *Datasets*](https://github.com/huggingface/datasets/blob/master/templates/README_guide.md) pour compléter le fichier *README.md* de votre jeu de données de problèmes GitHub. -C'est ça! Nous avons vu dans cette section que la création d'un bon ensemble de données peut être assez complexe, mais heureusement, le télécharger et le partager avec la communauté ne l'est pas. Dans la section suivante, nous utiliserons notre nouvel ensemble de données pour créer un moteur de recherche sémantique avec 🤗 Deatasets qui peut faire correspondre les questions aux problèmes et commentaires les plus pertinents. +C’ets tout ! Nous avons vu dans cette section que la création d'un bon jeu de données peut être assez complexe, mais heureusement, le télécharger et le partager avec la communauté ne l'est pas. Dans la section suivante, nous utiliserons notre nouveau jeu de données pour créer un moteur de recherche sémantique avec 🤗 *Datasets* qui peut faire correspondre les questions aux problèmes et commentaires les plus pertinents. -✏️ **Essayez-le !** Suivez les étapes que nous avons suivies dans cette section pour créer un ensemble de données de problèmes GitHub pour votre bibliothèque open source préférée (choisissez autre chose que 🤗 Datasets, bien sûr !). Pour obtenir des points bonus, ajustez un classificateur multilabel pour prédire les balises présentes dans le champ "labels". +✏️ **Essayez !** Suivez les étapes que nous avons suivies dans cette section pour créer un jeu de données de problèmes GitHub pour votre bibliothèque open source préférée (choisissez autre chose que 🤗 *Datasets*, bien sûr !). Pour obtenir des points bonus, *finetunez* un classifieur multilabel pour prédire les balises présentes dans le champ `labels`. - - diff --git a/chapters/fr/chapter5/6.mdx b/chapters/fr/chapter5/6.mdx index fb055ccb8..68cf7373e 100644 --- a/chapters/fr/chapter5/6.mdx +++ b/chapters/fr/chapter5/6.mdx @@ -22,15 +22,15 @@ {/if} -Dans [section 5](/course/chapter5/5), nous avons créé un ensemble de données de problèmes et de commentaires GitHub à partir du référentiel 🤗 Datasets. Dans cette section, nous utiliserons ces informations pour créer un moteur de recherche qui peut nous aider à trouver des réponses à nos questions les plus urgentes sur la bibliothèque ! +Dans [section 5](/course/fr/chapter5/5), nous avons créé un jeu de données de problèmes et de commentaires GitHub à partir du dépôt 🤗 *Datasets*. Dans cette section, nous utilisons ces informations pour créer un moteur de recherche qui peut nous aider à trouver des réponses à nos questions les plus urgentes sur la bibliothèque ! -## Utilisation des représentations vectorielles continues pour la recherche sémantique +## Utilisation des enchâssements pour la recherche sémantique -Comme nous l'avons vu dans le [Chapitre 1](/course/chapter1), les modèles de langage basés sur Transformer représentent chaque jeton dans une étendue de texte sous la forme d'un _vecteur d'intégration_. Il s'avère que l'on peut "regrouper" les incorporations individuelles pour créer une représentation vectorielle pour des phrases entières, des paragraphes ou (dans certains cas) des documents. Ces intégrations peuvent ensuite être utilisées pour trouver des documents similaires dans le corpus en calculant la similarité du produit scalaire (ou une autre métrique de similarité) entre chaque intégration et en renvoyant les documents avec le plus grand chevauchement. +Comme nous l'avons vu dans le [Chapitre 1](/course/fr/chapter1), les modèles de langage basés sur les *transformers* représentent chaque *token* dans une étendue de texte sous la forme d'un _enchâssement_. Il s'avère que l'on peut regrouper les enchâssements individuels pour créer une représentation vectorielle pour des phrases entières, des paragraphes ou (dans certains cas) des documents. Ces enchâssements peuvent ensuite être utilisés pour trouver des documents similaires dans le corpus en calculant la similarité du produit scalaire (ou une autre métrique de similarité) entre chaque enchâssement et en renvoyant les documents avec le plus grand chevauchement. -Dans cette section, nous utiliserons les incorporations pour développer un moteur de recherche sémantique. Ces moteurs de recherche offrent plusieurs avantages par rapport aux approches conventionnelles basées sur la correspondance des mots-clés dans une requête avec les documents. +Dans cette section, nous utilisons les enchâssements pour développer un moteur de recherche sémantique. Ces moteurs de recherche offrent plusieurs avantages par rapport aux approches conventionnelles basées sur la correspondance des mots-clés dans une requête avec les documents.
Recherche sémantique. @@ -39,7 +39,7 @@ Dans cette section, nous utiliserons les incorporations pour développer un mote ## Chargement et préparation du jeu de données -La première chose que nous devons faire est de télécharger notre ensemble de données de problèmes GitHub, alors utilisons la bibliothèque 🤗 Hub pour résoudre l'URL où notre fichier est stocké sur le Hugging Face Hub : +La première chose que nous devons faire est de télécharger notre jeu de données de problèmes GitHub. Utilisons la bibliothèque 🤗 *Hub* pour résoudre l'URL où notre fichier est stocké sur le *Hib* d’Hugging Face : ```py from huggingface_hub import hf_hub_url @@ -51,7 +51,7 @@ data_files = hf_hub_url( ) ``` -Avec l'URL stockée dans `data_files`, nous pouvons ensuite charger le jeu de données distant en utilisant la méthode introduite dans [section 2](/course/chapter5/2) : +Avec l'URL stocké dans `data_files`, nous pouvons ensuite charger le jeu de données distant en utilisant la méthode introduite dans [section 2](/course/fr/chapter5/2) : ```py from datasets import load_dataset @@ -67,7 +67,7 @@ Dataset({ }) ``` -Ici, nous avons spécifié la division `train` par défaut dans `load_dataset()`, de sorte qu'elle renvoie un `Dataset` au lieu d'un `DatasetDict`. La première chose à faire est de filtrer les demandes d'extraction, car celles-ci ont tendance à être rarement utilisées pour répondre aux requêtes des utilisateurs et introduiront du bruit dans notre moteur de recherche. Comme cela devrait être familier maintenant, nous pouvons utiliser la fonction `Dataset.filter()` pour exclure ces lignes de notre ensemble de données. Pendant que nous y sommes, filtrons également les lignes sans commentaires, car celles-ci ne fournissent aucune réponse aux requêtes des utilisateurs : +Ici, nous avons spécifié l’échantillon `train` par défaut dans `load_dataset()`, de sorte que cela renvoie un `Dataset` au lieu d'un `DatasetDict`. La première chose à faire est de filtrer les *pull requests* car celles-ci ont tendance à être rarement utilisées pour répondre aux requêtes des utilisateurs et introduiront du bruit dans notre moteur de recherche. Comme cela devrait être familier maintenant, nous pouvons utiliser la fonction `Dataset.filter()` pour exclure ces lignes de notre jeu de données. Pendant que nous y sommes, filtrons également les lignes sans commentaires, car celles-ci ne fournissent aucune réponse aux requêtes des utilisateurs : ```py issues_dataset = issues_dataset.filter( @@ -83,7 +83,7 @@ Dataset({ }) ``` -Nous pouvons voir qu'il y a beaucoup de colonnes dans notre ensemble de données, dont la plupart n'ont pas besoin de construire notre moteur de recherche. Du point de vue de la recherche, les colonnes les plus informatives sont `title`, `body` et `comments`, tandis que `html_url` nous fournit un lien vers le problème source. Utilisons la fonction `Dataset.remove_columns()` pour supprimer le reste : +Nous pouvons voir qu'il y a beaucoup de colonnes dans notre jeu de données, dont la plupart n'ont pas besoin de construire notre moteur de recherche. Du point de vue de la recherche, les colonnes les plus informatives sont `title`, `body` et `comments`, tandis que `html_url` nous fournit un lien vers le problème source. Utilisons la fonction `Dataset.remove_columns()` pour supprimer le reste : ```py columns = issues_dataset.column_names @@ -100,14 +100,14 @@ Dataset({ }) ``` -Pour créer nos intégrations, nous ajouterons à chaque commentaire le titre et le corps du problème, car ces champs contiennent souvent des informations contextuelles utiles. Étant donné que notre colonne `comments` est actuellement une liste de commentaires pour chaque problème, nous devons "éclater" la colonne afin que chaque ligne se compose d'un tuple `(html_url, title, body, comment)`. Dans Pandas, nous pouvons le faire avec la fonction [`DataFrame.explode()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.explode.html), qui crée une nouvelle ligne pour chaque élément dans une colonne de type liste, tout en répliquant toutes les autres valeurs de colonne. Pour voir cela en action, passons d'abord au format "DataFrame" de Pandas : +Pour créer nos enchâssements, nous ajoutons à chaque commentaire le titre et le corps du problème, car ces champs contiennent des informations contextuelles utiles. Étant donné que notre colonne `comments` est actuellement une liste de commentaires pour chaque problème, nous devons « éclater » la colonne afin que chaque ligne se compose d'un *tuple* `(html_url, title, body, comment)`. Dans Pandas, nous pouvons le faire avec la fonction [`DataFrame.explode()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.explode.html), qui crée une nouvelle ligne pour chaque élément dans une colonne de type liste, tout en répliquant toutes les autres valeurs de colonne. Pour voir cela en action, passons d'abord au format `DataFrame` de Pandas : ```py issues_dataset.set_format("pandas") df = issues_dataset[:] ``` -Si nous inspectons la première ligne de ce `DataFrame`, nous pouvons voir qu'il y a quatre commentaires associés à ce problème : +Si nous inspectons la première ligne de ce `DataFrame`, nous pouvons voir qu'il y a quatre commentaires associés à ce problème : ```py df["comments"][0].tolist() @@ -169,7 +169,7 @@ comments_df.head(4) -Génial, nous pouvons voir que les lignes ont été répliquées, avec la colonne "commentaires" contenant les commentaires individuels ! Maintenant que nous en avons fini avec Pandas, nous pouvons rapidement revenir à un `Dataset` en chargeant le `DataFrame` en mémoire : +Génial, nous pouvons voir que les lignes ont été répliquées, avec la colonne `comments` contenant les commentaires individuels ! Maintenant que nous en avons fini avec Pandas, nous pouvons rapidement revenir à un `Dataset` en chargeant le `DataFrame` en mémoire : ```py from datasets import Dataset @@ -185,16 +185,16 @@ Dataset({ }) ``` -D'accord, cela nous a donné quelques milliers de commentaires avec lesquels travailler ! +D'accord, cela nous a donné quelques milliers de commentaires avec lesquels travailler ! -✏️ **Essayez-le !** Voyez si vous pouvez utiliser `Dataset.map()` pour exploser la colonne `comments` de `issues_dataset` _sans_ recourir à l'utilisation de Pandas. C'est un peu délicat; vous pourriez trouver la section ["Batch mapping"](https://huggingface.co/docs/datasets/v1.12.1/about_map_batch.html?batch-mapping#batch-mapping) de la documentation 🤗 Datasets utile pour cette tâche. +✏️ **Essayez !** Voyez si vous pouvez utiliser `Dataset.map()` pour exploser la colonne `comments` de `issues_dataset` _sans_ recourir à l'utilisation de Pandas. C'est un peu délicat. La section [« Batch mapping »](https://huggingface.co/docs/datasets/v1.12.1/about_map_batch.html?batch-mapping#batch-mapping) de la documentation 🤗 *Datasets* peut être utile pour cette tâche. -Maintenant que nous avons un commentaire par ligne, créons une nouvelle colonne `comments_length` contenant le nombre de mots par commentaire : +Maintenant que nous avons un commentaire par ligne, créons une nouvelle colonne `comments_length` contenant le nombre de mots par commentaire : ```py comments_dataset = comments_dataset.map( @@ -202,7 +202,7 @@ comments_dataset = comments_dataset.map( ) ``` -Nous pouvons utiliser cette nouvelle colonne pour filtrer les commentaires courts, qui incluent généralement des éléments tels que "cc @lewtun" ou "Merci !" qui ne sont pas pertinents pour notre moteur de recherche. Il n'y a pas de nombre précis à sélectionner pour le filtre, mais environ 15 mots semblent être un bon début : +Nous pouvons utiliser cette nouvelle colonne pour filtrer les commentaires courts incluant généralement des éléments tels que « cc @lewtun » ou « Merci ! » qui ne sont pas pertinents pour notre moteur de recherche. Il n'y a pas de nombre précis à sélectionner pour le filtre mais 15 mots semblent être un bon début : ```py comments_dataset = comments_dataset.filter(lambda x: x["comment_length"] > 15) @@ -216,7 +216,7 @@ Dataset({ }) ``` -Après avoir un peu nettoyé notre ensemble de données, concaténons le titre, la description et les commentaires du problème dans une nouvelle colonne "texte". Comme d'habitude, nous allons écrire une fonction simple que nous pouvons passer à `Dataset.map()` : +Après avoir un peu nettoyé notre jeu de données, concaténons le titre, la description et les commentaires du problème dans une nouvelle colonne `text`. Comme d'habitude, nous allons écrire une fonction simple que nous pouvons passer à `Dataset.map()` : ```py def concatenate_text(examples): @@ -232,11 +232,11 @@ def concatenate_text(examples): comments_dataset = comments_dataset.map(concatenate_text) ``` -Nous sommes enfin prêts à créer des embeddings ! Nous allons jeter un coup d'oeil. +Nous sommes enfin prêts à créer des enchâssements ! Jetons un coup d'œil. -## Création d'incorporations de texte +## Création d’enchâssements pour les textes -Nous avons vu dans [Chapitre 2](/course/chapter2) que nous pouvons obtenir des incorporations de jetons en utilisant la classe `AutoModel`. Tout ce que nous avons à faire est de choisir un point de contrôle approprié à partir duquel charger le modèle. Heureusement, il existe une bibliothèque appelée `sentence-transformers` dédiée à la création d'incorporations. Comme décrit dans la [documentation] de la bibliothèque (https://www.sbert.net/examples/applications/semantic-search/README.html#symmetric-vs-asymmetric-semantic-search), notre cas d'utilisation est un exemple de _asymmetric recherche sémantique_ car nous avons une requête courte dont nous aimerions trouver la réponse dans un document plus long, comme un commentaire sur un problème. Le [tableau de présentation des modèles] (https://www.sbert.net/docs/pretrained_models.html#model-overview) pratique de la documentation indique que le point de contrôle `multi-qa-mpnet-base-dot-v1` a le meilleures performances pour la recherche sémantique, nous l'utiliserons donc pour notre application. Nous allons également charger le tokenizer en utilisant le même point de contrôle : +Nous avons vu dans [Chapitre 2](/course/fr/chapter2) que nous pouvons obtenir des enchâssements de *tokens* en utilisant la classe `AutoModel`. Tout ce que nous avons à faire est de choisir un *checkpoint* approprié à partir duquel charger le modèle. Heureusement, il existe une bibliothèque appelée `sentence-transformers` dédiée à la création d’enchâssements. Comme décrit dans la [documentation de la bibliothèque](https://www.sbert.net/examples/applications/semantic-search/README.html#symmetric-vs-asymmetric-semantic-search), notre cas d'utilisation est un exemple de _recherche sémantique asymétrique_. En effet, nous avons une requête courte dont nous aimerions trouver la réponse dans un document plus long, par exemple un commentaire à un problème. Le [tableau de présentation des modèles](https://www.sbert.net/docs/pretrained_models.html#model-overview) de la documentation indique que le *checkpoint* `multi-qa-mpnet-base-dot-v1` a les meilleures performances pour la recherche sémantique. Utilisons donc le pour notre application. Nous allons également charger le *tokenizer* en utilisant le même *checkpoint* : {#if fw === 'pt'} @@ -248,7 +248,7 @@ tokenizer = AutoTokenizer.from_pretrained(model_ckpt) model = AutoModel.from_pretrained(model_ckpt) ``` -Pour accélérer le processus d'intégration, il est utile de placer le modèle et les entrées sur un périphérique GPU, alors faisons-le maintenant : +Pour accélérer le processus, il est utile de placer le modèle et les entrées sur un périphérique GPU, alors faisons-le maintenant : ```py import torch @@ -267,18 +267,18 @@ tokenizer = AutoTokenizer.from_pretrained(model_ckpt) model = TFAutoModel.from_pretrained(model_ckpt, from_pt=True) ``` -Notez que nous avons défini `from_pt=True` comme argument de la méthode `from_pretrained()`. C'est parce que le point de contrôle `multi-qa-mpnet-base-dot-v1` n'a que des poids PyTorch, donc définir `from_pt=True` les convertira automatiquement au format TensorFlow pour nous. Comme vous pouvez le voir, il est très simple de passer d'un framework à l'autre dans 🤗 Transformers ! +Notez que nous avons défini `from_pt=True` comme argument de la méthode `from_pretrained()`. C'est parce que le point de contrôle `multi-qa-mpnet-base-dot-v1` n'a que des poids PyTorch. Donc définir `from_pt=True` converti automatiquement au format TensorFlow pour nous. Comme vous pouvez le voir, il est très simple de passer d'un *framework* à l'autre dans 🤗 *Transformers* ! {/if} -Comme nous l'avons mentionné précédemment, nous aimerions représenter chaque entrée dans notre corpus de problèmes GitHub comme un vecteur unique, nous devons donc "regrouper" ou faire la moyenne de nos incorporations de jetons d'une manière ou d'une autre. Une approche populaire consiste à effectuer un * regroupement CLS * sur les sorties de notre modèle, où nous collectons simplement le dernier état caché pour le jeton spécial `[CLS]`. La fonction suivante fait l'affaire pour nous : +Comme nous l'avons mentionné précédemment, nous aimerions représenter chaque entrée dans notre corpus de problèmes GitHub comme un vecteur unique. Nous devons donc regrouper ou faire la moyenne de nos enchâssements de *tokens* d'une manière ou d'une autre. Une approche populaire consiste à effectuer un *regroupement CLS* sur les sorties de notre modèle, où nous collectons simplement le dernier état caché pour le *token* spécial `[CLS]`. La fonction suivante fait ça pour nous : ```py def cls_pooling(model_output): return model_output.last_hidden_state[:, 0] ``` -Ensuite, nous allons créer une fonction d'assistance qui va tokeniser une liste de documents, placer les tenseurs sur le GPU, les alimenter au modèle et enfin appliquer le regroupement CLS aux sorties : +Ensuite, nous allons créer une fonction utile qui va tokeniser une liste de documents, placer les tenseurs dans le GPU, les donner au modèle et enfin appliquer le regroupement CLS aux sorties : {#if fw === 'pt'} @@ -292,7 +292,7 @@ def get_embeddings(text_list): return cls_pooling(model_output) ``` -Nous pouvons tester le fonctionnement de la fonction en lui fournissant la première entrée de texte dans notre corpus et en inspectant la forme de sortie : +Nous pouvons tester le fonctionnement de la fonction en lui donnant la première entrée textuelle de notre corpus et en inspectant la forme de sortie : ```py embedding = get_embeddings(comments_dataset["text"][0]) @@ -303,7 +303,7 @@ embedding.shape torch.Size([1, 768]) ``` -Super, nous avons converti la première entrée de notre corpus en un vecteur à 768 dimensions ! Nous pouvons utiliser `Dataset.map()` pour appliquer notre fonction `get_embeddings()` à chaque ligne de notre corpus, créons donc une nouvelle colonne `embeddings` comme suit : +Super ! Nous avons converti la première entrée de notre corpus en un vecteur à 768 dimensions. Nous pouvons utiliser `Dataset.map()` pour appliquer notre fonction `get_embeddings()` à chaque ligne de notre corpus. Créons donc une nouvelle colonne `embeddings` comme suit : ```py embeddings_dataset = comments_dataset.map( @@ -323,7 +323,7 @@ def get_embeddings(text_list): return cls_pooling(model_output) ``` -Nous pouvons tester le fonctionnement de la fonction en lui fournissant la première entrée de texte dans notre corpus et en inspectant la forme de sortie : +Nous pouvons tester le fonctionnement de la fonction en lui donnant la première entrée textuelle de notre corpus et en inspectant la forme de sortie : ```py embedding = get_embeddings(comments_dataset["text"][0]) @@ -334,7 +334,7 @@ embedding.shape TensorShape([1, 768]) ``` -Super, nous avons converti la première entrée de notre corpus en un vecteur à 768 dimensions ! Nous pouvons utiliser `Dataset.map()` pour appliquer notre fonction `get_embeddings()` à chaque ligne de notre corpus, créons donc une nouvelle colonne `embeddings` comme suit : +Super ! Nous avons converti la première entrée de notre corpus en un vecteur à 768 dimensions. Nous pouvons utiliser `Dataset.map()` pour appliquer notre fonction `get_embeddings()` à chaque ligne de notre corpus. Créons donc une nouvelle colonne `embeddings` comme suit : ```py embeddings_dataset = comments_dataset.map( @@ -345,19 +345,19 @@ embeddings_dataset = comments_dataset.map( {/if} -Notez que nous avons converti les intégrations en tableaux NumPy -- c'est parce que 🤗 Datasets nécessite ce format lorsque nous essayons de les indexer avec FAISS, ce que nous ferons ensuite. +Notez que nous avons converti les enchâssements en tableaux NumPy. C'est parce que 🤗 *Datasets* nécessite ce format lorsque nous essayons de les indexer avec FAISS, ce que nous ferons ensuite. ## Utilisation de FAISS pour une recherche de similarité efficace -Maintenant que nous avons un ensemble de données d'incorporations, nous avons besoin d'un moyen de les rechercher. Pour ce faire, nous utiliserons une structure de données spéciale dans 🤗 Datasets appelée _FAISS index_. [FAISS](https://faiss.ai/) (abréviation de Facebook AI Similarity Search) est une bibliothèque qui fournit des algorithmes efficaces pour rechercher et regrouper rapidement des vecteurs d'intégration. +Maintenant que nous avons un jeu de données d'incorporations, nous avons besoin d'un moyen de les rechercher. Pour ce faire, nous utiliserons une structure de données spéciale dans 🤗 *Datasets* appelée _FAISS index_. [FAISS](https://faiss.ai/) (abréviation de Facebook AI Similarity Search) est une bibliothèque qui fournit des algorithmes efficaces pour rechercher et regrouper rapidement des vecteurs d'intégration. -L'idée de base derrière FAISS est de créer une structure de données spéciale appelée un _index_ qui permet de trouver quels plongements sont similaires à un plongement d'entrée. Créer un index FAISS dans 🤗 Datasets est simple -- nous utilisons la fonction `Dataset.add_faiss_index()` et spécifions quelle colonne de notre jeu de données nous aimerions indexer : +L'idée de base derrière FAISS est de créer une structure de données spéciale appelée un _index_ qui permet de trouver quels plongements sont similaires à un plongement d'entrée. Créer un index FAISS dans 🤗 *Datasets* est simple -- nous utilisons la fonction `Dataset.add_faiss_index()` et spécifions quelle colonne de notre jeu de données nous aimerions indexer : ```py embeddings_dataset.add_faiss_index(column="embeddings") ``` -Nous pouvons maintenant effectuer des requêtes sur cet index en effectuant une recherche de voisin le plus proche avec la fonction `Dataset.get_nearest_examples()`. Testons cela en intégrant d'abord une question comme suit : +Nous pouvons maintenant effectuer des requêtes sur cet index en effectuant une recherche des voisins les plus proches avec la fonction `Dataset.get_nearest_examples()`. Testons cela en enchâssant d'abord une question comme suit : {#if fw === 'pt'} @@ -385,7 +385,7 @@ question_embedding.shape {/if} -Tout comme avec les documents, nous avons maintenant un vecteur de 768 dimensions représentant la requête, que nous pouvons comparer à l'ensemble du corpus pour trouver les plongements les plus similaires : +Tout comme avec les documents, nous avons maintenant un vecteur de 768 dimensions représentant la requête. Nous pouvons le comparer à l’ensemble du corpus pour trouver les enchâssements les plus similaires : ```py scores, samples = embeddings_dataset.get_nearest_examples( @@ -393,7 +393,7 @@ scores, samples = embeddings_dataset.get_nearest_examples( ) ``` -La fonction `Dataset.get_nearest_examples()` renvoie un tuple de scores qui classent le chevauchement entre la requête et le document, et un ensemble correspondant d'échantillons (ici, les 5 meilleures correspondances). Collectons-les dans un `pandas.DataFrame` afin de pouvoir les trier facilement : +La fonction `Dataset.get_nearest_examples()` renvoie un *tuple* de scores qui classent le chevauchement entre la requête et le document, et un jeu correspondant d'échantillons (ici, les 5 meilleures correspondances). Collectons-les dans un `pandas.DataFrame` afin de pouvoir les trier facilement : ```py import pandas as pd @@ -403,7 +403,7 @@ samples_df["scores"] = scores samples_df.sort_values("scores", ascending=False, inplace=True) ``` -Nous pouvons maintenant parcourir les premières lignes pour voir dans quelle mesure notre requête correspond aux commentaires disponibles : +Nous pouvons maintenant parcourir les premières lignes pour voir dans quelle mesure notre requête correspond aux commentaires disponibles : ```py for _, row in samples_df.iterrows(): @@ -521,10 +521,10 @@ URL: https://github.com/huggingface/datasets/issues/824 """ ``` -Pas mal! Notre deuxième résultat semble correspondre à la requête. +Pas mal ! Notre deuxième résultat semble correspondre à la requête. -✏️ **Essayez-le !** Créez votre propre requête et voyez si vous pouvez trouver une réponse dans les documents récupérés. Vous devrez peut-être augmenter le paramètre `k` dans `Dataset.get_nearest_examples()` pour élargir la recherche. +✏️ **Essayez !** Créez votre propre requête et voyez si vous pouvez trouver une réponse dans les documents récupérés. Vous devrez peut-être augmenter le paramètre `k` dans `Dataset.get_nearest_examples()` pour élargir la recherche. - \ No newline at end of file + diff --git a/chapters/fr/chapter5/7.mdx b/chapters/fr/chapter5/7.mdx index a4da397e5..5321adb82 100644 --- a/chapters/fr/chapter5/7.mdx +++ b/chapters/fr/chapter5/7.mdx @@ -1,11 +1,10 @@ -# 🤗 Datasets, vérifié ! +# 🤗 *Datasets*, vérifié ! -Eh bien, ce fut toute une visite de la 🤗 Datasets -- félicitations pour être arrivé jusqu'ici ! Avec les connaissances que vous avez acquises dans ce chapitre, vous devriez être en mesure de : +Eh bien, ce fut une sacrée visite de la bibliothèque 🤗 *Datasets*. Félicitations d’être arrivé jusqu'ici ! Avec les connaissances que vous avez acquises dans ce chapitre, vous devriez être en mesure de : +- charger des jeux de données depuis n'importe où, que ce soit le *Hub* d’Hugging Face, votre ordinateur portable ou un serveur distant de votre entreprise. +- manipuler vos données en utilisant un mélange des fonctions Dataset.map() et Dataset.filter(). +- passer rapidement d'un format de données à un autre, comme Pandas et NumPy, en utilisant Dataset.set_format(). +- créer votre propre jeu de données et l’envoyer vers le *Hub*. +- enchâsser vos documents en utilisant un *transformer* et construire un moteur de recherche sémantique en utilisant FAISS. -- Chargez des ensembles de données de n'importe où, que ce soit le Hugging Face Hub, votre ordinateur portable ou un serveur distant de votre entreprise. -- Démêlez vos données en utilisant un mélange des fonctions `Dataset.map()` et `Dataset.filter()`. -- Basculez rapidement entre les formats de données comme Pandas et NumPy en utilisant `Dataset.set_format()`. -- Créez votre propre ensemble de données et transférez-le vers le Hugging Face Hub. -- Intégrez vos documents à l'aide d'un modèle Transformer et créez un moteur de recherche sémantique à l'aide de FAISS. - -Dans le [Chapitre 7](/course/chapter7), nous mettrons tout cela à profit en approfondissant les principales tâches de la PNL pour lesquelles les modèles Transformer sont parfaits. Avant de vous lancer, mettez à l'épreuve vos connaissances sur 🤗 Datasets avec un quiz rapide ! +Dans le [Chapter 7](/course/fr/chapter7), nous mettrons tout cela à profit en plongeant dans les tâches de traitement du langage neturel de base pour lesquelles les *transformers* sont parfaits. Avant cela mettez vos connaissances sur la librairie 🤗 *Datasets* à l'épreuve avec un petit quiz ! diff --git a/chapters/fr/chapter5/8.mdx b/chapters/fr/chapter5/8.mdx index 19bb1d08a..e61777100 100644 --- a/chapters/fr/chapter5/8.mdx +++ b/chapters/fr/chapter5/8.mdx @@ -2,33 +2,33 @@ # Quiz de fin de chapitre -Ce chapitre a couvert beaucoup de terrain! Ne vous inquiétez pas si vous n'avez pas saisi tous les détails ; les prochains chapitres vous aideront à comprendre comment les choses fonctionnent sous le capot. +Ce chapitre a couvert beaucoup de terrain ! Ne vous inquiétez pas si vous n'avez pas saisi tous les détails, les chapitres suivants vous aideront à comprendre comment les choses fonctionnent sous le capot. Avant de poursuivre, testons ce que vous avez appris dans ce chapitre. -### 1. La fonction `load_dataset()` dans 🤗 Datasets vous permet de charger un jeu de données depuis lequel des emplacements suivants ? +### 1. La fonction `load_dataset()` dans 🤗 *Datasets* vous permet de charger un jeu de données depuis lequel des emplacements suivants ? data_files de load_dataset() pour charger les jeux de données locaux.", + text: "Localement, par exemple depuis son ordinateur portable", + explain: "Correct ! Vous pouvez passer les chemins des fichiers locaux à l'argument data_files de load_dataset() pour charger les jeux de données locaux.", correct: true }, { - text: "Le hub du visage étreignant", - explain: "Correct! Vous pouvez charger des ensembles de données sur le Hub en fournissant l'ID de l'ensemble de données, par ex. load_dataset('emotion').", + text: "Le Hub> d’Hugging Face", + explain: "Correct ! Vous pouvez charger des jeux de données sur le Hub> en fournissant l'ID du jeu de données. Par exemple : load_dataset('emotion').", correct: true }, { text: "Un serveur distant", - explain: "Correct! Vous pouvez passer des URL à l'argument data_files de load_dataset() pour charger des fichiers distants.", + explain: "Correct ! Vous pouvez passer des URLs à l'argument data_files de load_dataset() pour charger des fichiers distants.", correct: true }, ]} /> -### 2. Supposons que vous chargiez l'une des tâches GLUE comme suit : +### 2. Supposons que vous chargiez l'une des tâches du jeu de données GLUE comme suit : ```py from datasets import load_dataset @@ -36,89 +36,89 @@ from datasets import load_dataset dataset = load_dataset("glue", "mrpc", split="train") ``` -Laquelle des commandes suivantes produira un échantillon aléatoire de 50 éléments à partir de `dataset` ? +Laquelle des commandes suivantes produira un échantillon aléatoire de 50 éléments à partir de `dataset` ? dataset.sample(50)", - explain: "Ceci est incorrect -- il n'y a pas de méthode Dataset.sample()." + explain: "Ceci est incorrect, il n'y a pas de méthode Dataset.sample()." }, { text: "dataset.shuffle().select(range(50))", - explain: "Correct! Comme vous l'avez vu dans ce chapitre, vous mélangez d'abord l'ensemble de données, puis sélectionnez les échantillons à partir de celui-ci.", + explain: "Correct ! Comme vous l'avez vu dans ce chapitre, vous mélangez d'abord le jeu de données puis sélectionnez les échantillons à partir de celui-ci.", correct: true }, { text: "dataset.select(range(50)).shuffle()", - explain: "Ceci est incorrect - bien que le code s'exécute, il ne mélange que les 50 premiers éléments de l'ensemble de données." + explain: "Ceci est incorrect. Bien que le code s'exécute, il ne mélange que les 50 premiers éléments du jeu de données." } ]} /> -### 3. Supposons que vous disposiez d'un ensemble de données sur les animaux domestiques appelé "pets_dataset", qui comporte une colonne "name" indiquant le nom de chaque animal. Parmi les approches suivantes, laquelle vous permettrait de filtrer l'ensemble de données pour tous les animaux dont le nom commence par la lettre "L" ? +### 3. Supposons que vous disposiez d'un jeu de données sur les animaux domestiques appelé `pets_dataset` qui comporte une colonne `name` indiquant le nom de chaque animal. Parmi les approches suivantes, laquelle vous permettrait de filtrer le jeu de données pour tous les animaux dont le nom commence par la lettre « L » ? pets_dataset.filter(lambda x : x['name'].startswith('L'))", - explain: "Correct! L'utilisation d'une fonction Python lambda pour ces filtres rapides est une excellente idée. Pouvez-vous penser à une autre solution?", + explain: "Correct ! L'utilisation d'une fonction Python lambda pour ces filtres rapides est une excellente idée. Pouvez-vous penser à une autre solution ?", correct: true }, { text: "pets_dataset.filter(lambda x['name'].startswith('L'))", - explain: "Ceci est incorrect -- une fonction lambda prend la forme générale lambda *arguments* : *expression*, vous devez donc fournir des arguments dans ce cas." + explain: "Ceci est incorrect. Une fonction lambda prend la forme générale lambda *arguments* : *expression*, vous devez donc fournir des arguments dans ce cas." }, { - text: "Créez une fonction comme def filter_names(x): return x['name'].startswith('L') et exécutez pets_dataset.filter(filter_names).", - explain: "Correct! Tout comme avec Dataset.map(), vous pouvez passer des fonctions explicites à Dataset.filter(). Ceci est utile lorsque vous avez une logique complexe qui ne convient pas à une fonction lambda courte. Parmi les autres solutions, laquelle fonctionnerait ?", + text: "Créer une fonction comme def filter_names(x): return x['name'].startswith('L') et exécuter pets_dataset.filter(filter_names).", + explain: "Correct ! Tout comme avec Dataset.map(), vous pouvez passer des fonctions explicites à Dataset.filter(). Ceci est utile lorsque vous avez une logique complexe qui ne convient pas à une fonction lambda courte. Parmi les autres solutions, laquelle fonctionnerait ?", correct: true } ]} /> -### 4. Qu'est-ce que la cartographie mémoire ? +### 4. Qu'est-ce que le *memory mapping* ? mapping entre la RAM CPU et GPU", + explain: "Ce n'est pas ça, réessayez !", }, { - text: "Un mappage entre la RAM et le stockage du système de fichiers", - explain: "Correct! 🤗 Datasets traite chaque ensemble de données comme un fichier mappé en mémoire. Cela permet à la bibliothèque d'accéder et d'opérer sur des éléments de l'ensemble de données sans avoir à le charger complètement en mémoire.", + text: "Un mappaging entre la RAM et le stockage du système de fichiers", + explain: "Correct ! 🤗 Datasets traite chaque jeu de données comme un fichier mappé en mémoire. Cela permet à la bibliothèque d'accéder et d'opérer sur des éléments du jeu de données sans avoir à le charger complètement en mémoire.", correct: true }, { - text: "Un mappage entre deux fichiers dans le cache 🤗 Datasets", - explain: "Ce n'est pas correct - réessayez !" + text: "Un mappaging entre deux fichiers dans le cache 🤗 Datasets", + explain: "Ce n'est pas correct, réessayez !" } ]} /> -### 5. Parmi les éléments suivants, lesquels sont les principaux avantages du mappage mémoire ? +### 5. Parmi les éléments suivants, lesquels sont les principaux avantages du *memory mapping* ? Datasets d'être extrêmement rapide. Ce n'est cependant pas le seul avantage.", correct: true }, { text: "Les applications peuvent accéder à des segments de données dans un fichier extrêmement volumineux sans avoir à lire tout le fichier dans la RAM au préalable.", - explain: "Correct! Cela permet à 🤗 Datasets de charger des ensembles de données de plusieurs gigaoctets sur votre ordinateur portable sans faire exploser votre CPU. Quel autre avantage le mappage mémoire offre-t-il ?", + explain: "Correct ! Cela permet à 🤗 Datasets de charger des jeux de données de plusieurs Go sur votre ordinateur portable sans faire exploser votre CPU. Quel autre avantage cette technique offre-t-elle ?", correct: true }, { - text: "Il consomme moins d'énergie, donc votre batterie dure plus longtemps.", - explain: "Ce n'est pas correct - réessayez !" + text: "Cela consomme moins d'énergie, donc votre batterie dure plus longtemps.", + explain: "Ce n'est pas correct, réessayez !" } ]} /> -### 6. Pourquoi le code suivant échoue-t-il ? +### 6. Pourquoi le code suivant échoue-t-il ? ```py from datasets import load_dataset @@ -130,38 +130,38 @@ dataset[0] IterableDataset.", - explain: "Correct! Un IterableDataset est un générateur, pas un conteneur, vous devez donc accéder à ses éléments en utilisant next(iter(dataset)).", + explain: "Correct! Un IterableDataset est un générateur, pas un conteneur. Vous devez donc accéder à ses éléments en utilisant next(iter(dataset)).", correct: true }, { - text: "L'ensemble de données allocine n'a pas de division train.", - explain: "Ceci est incorrect - consultez la [fiche de l'ensemble de données allocine](https://huggingface.co/datasets/allocine) sur le Hub pour voir quelles divisions elle contient." + text: "Le jeu de données allocine n'a pas d’échantillon train.", + explain: "Ceci est incorrect. Consultez la [fiche d’ allocine](https://huggingface.co/datasets/allocine) sur le Hub pour voir quels échantillons il contient." } ]} /> -### 7. Parmi les avantages suivants, lesquels sont les principaux avantages de la création d'une fiche d'ensemble de données ? +### 7. Parmi les avantages suivants, lesquels sont les principaux pour la création d'une fiche pour les jeux de données ? -### 9. Pour la recherche sémantique asymétrique, vous avez généralement : +### 9. Pour la recherche sémantique asymétrique, vous avez généralement : -### 10. Puis-je utiliser 🤗 Datasets pour charger des données à utiliser dans d'autres domaines, comme le traitement de la parole ? +### 10. Puis-je utiliser 🤗 *Datasets* pour charger des données à utiliser dans d'autres domaines, comme le traitement de la parole ? MNIST dataset sur le Hub pour un exemple de vision par ordinateur." + explain: "Ceci est incorrect. 🤗 Datasets prend actuellement en charge les données tabulaires, l'audio et la vision par ordinateur. Consultez le jeu de donnéesMNIST sur le Hub pour un exemple de vision par ordinateur." }, { text: "Oui", - explain: "Correct! Découvrez les développements passionnants avec la parole et la vision dans la bibliothèque 🤗 Transformers pour voir comment 🤗 Datasets est utilisé dans ces domaines.", + explain: "Correct ! Découvrez les développements passionnants concernant la parole et la vision dans la bibliothèque 🤗 Transformers pour voir comment 🤗 Datasets est utilisé dans ces domaines.", correct : true }, ]} From a3de4dcfc389b630552209cc989095bdcee6ef12 Mon Sep 17 00:00:00 2001 From: Cherdsak Kingkan Date: Wed, 13 Apr 2022 21:23:29 +0700 Subject: [PATCH 72/73] [th] Translated Chapter2/1 (#83) * Finish chapter2/1 * Update _toctree.yml --- chapters/th/_toctree.yml | 7 ++++++- chapters/th/chapter2/1.mdx | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 chapters/th/chapter2/1.mdx diff --git a/chapters/th/_toctree.yml b/chapters/th/_toctree.yml index 39b7a199d..ffd290a33 100644 --- a/chapters/th/_toctree.yml +++ b/chapters/th/_toctree.yml @@ -8,6 +8,11 @@ - local: chapter1/1 title: บทนำ +- title: 2. การใช้ 🤗 Transformers + sections: + - local: chapter2/1 + title: บทนำ + - title: 3. การ fine-tune โมเดลที่ผ่านการเทรนมาแล้ว (pretrained model) sections: - local: chapter3/1 @@ -27,4 +32,4 @@ title: จบพาร์ทที่ 1! - local: chapter4/6 title: คำถามท้ายบท - quiz: 4 \ No newline at end of file + quiz: 4 diff --git a/chapters/th/chapter2/1.mdx b/chapters/th/chapter2/1.mdx new file mode 100644 index 000000000..8c354032d --- /dev/null +++ b/chapters/th/chapter2/1.mdx @@ -0,0 +1,19 @@ +# บทนำ + +อย่างที่คุณเห็นใน [Chapter 1](/course/chapter1), โดยปกติแล้วโมเดล Transformer นั้นจะมีขนาดใหญ่มาก การเทรนและการใช้งานโมเดลเหล่านี้ที่มีตัวแปร (parameters) เป็นล้านไปจนถึง *หมื่นล้าน* ตัวแปรนั้นเป็นเรื่องที่ค่อนข้างซับซ้อน นอกจากนั้นแล้วการที่มีโมเดลใหม่ๆปล่อยออกมาเกือบทุกวันและแต่ละโมเดลก็มีวิธีการสร้าง (implementation) เป็นของตัวเอง ดังนั้นการจะลองทุกโมเดลนั้นไม่ใช่เรื่องที่ง่ายเลย +🤗 Transformers library สร้างขึ้นมาเพื่อแก้ปัญหานี้ จุดประสงค์ก็คือ การทำให้ไม่ว่าจะโมเดล Transformer ใดก็ตามสามารถโหลด, เทรน, และบันทึก ได้ด้วยการใช้ API เพียงอันเดียว จุดเด่นหลักๆของ library ประกอบด้วย + +- **ใช้งานง่าย**: การดาวน์โหลด, การโหลด, และการใช้งานโมเดล NLP ที่ประสิทธิภาพดีที่สุด (state-of-the-art) สำหรับการอนุมาน (inference) นั้นสามารถทำได้ด้วยโค้ดเพียง 2 บรรทัด +- **ความยืดหยุ่น**: โดยแก่นแท้แล้วทุกโมเดลนั้นก็เป็นเพียคลาส `nn.Module` ง่ายๆของ PyTorch หรือ `tf.keras.Model` ของ TensorFlow และสามารถถูกจัดการได้เหมือนโมเดลอื่นๆ ใน machine learning (ML) frameworks นั้นๆ +- **ความเรียบง่าย**: การประกาศ abstractions ใดๆข้ามไปมาใน libraries นั้นน้อยมากๆ แนวคิดหลัก (core concept) ก็คือ "ทุกอย่างอยู่ในไฟล์เดียว (All in one file)" เช่น ขั้นตอนการเรียนรู้ของโมเดลใน forward pass นั้นสามารถประกาศทั้งหมดได้ในไฟล์เดียว ดังนั้นตัวโค้ดนั้นสามารถเป็นที่เข้าใจและแก้ไขได้ในตัวมันเอง + +จุดเด่นข้อสุดท้ายนี่เองที่ทำให้ 🤗 Transformers ต่างจาก ML libraries อื่นๆ โมเดลต่างๆไม่ได้ถูกสร้างขึ้นมาจากโมดูลต่างๆที่ต้องแชร์ข้ามไฟล์กันไปมา แต่กลับกัน แต่ละโมเดลจะมี layers ของตัวเอง +นอกจากจะทำให้โมเดลเข้าถึงและเข้าใจได้ง่ายแล้ว ยังทำให้คุณสามารถทดลองโมเดลๆหนึ่งโดยที่ไม่กระทบโมเดลอื่นๆ + +บทนี้จะเริ่มด้วยตัวอย่างแบบ end-to-end ซึ่งเราจะใช้โมเดลและ tokenizer ร่วมกันเพื่อทำซ้ำ(เลียนแบบ) ฟังก์ชัน `pipeline()` จากที่เรียนใน [Chapter 1](/course/chapter1) หลังจากนั้นเราจะมาเรียนเกี่ยวกับ API ของโมเดล โดยเราจะเจาะลึกในคลาสของโมเดลและการตั้งค่า (configuration) และจะแสดงวิธีการโหลดโมเดลและกระบวนการที่โมเดลทำการทำนายผลจากชุดข้อมูลเชิงตัวเลข ว่าทำอย่างไร + +หลังจากนั้นเราจะไปดูกันที่ tokenizer API ซึ่งเป็นอีกหนึ่งส่วนประกอบหลักของฟังก์ชัน `pipeline()`, Tokenizers จะรับผิดชอบการประมวลขั้นแรกและขั้นสุดท้าย ซึ่งก็คือ การแปลงข้อมูลที่เป็นข้อความให้เป็นข้อมูลเชิงตัวเลข เพื่อใช้กับ neural network, และการแปลงข้อมูลกลับไปเป็นตัวอักษร ในกรณีที่จำเป็น และสุดท้ายเราจะแสดงวิธีการจัดการกับการส่งข้อความทีละหลายๆประโยคแบบที่เตรียมไว้เป็นชุดๆ (batch) ไปยังโมเดล และปิดท้ายด้วยฟังก์ชัน `tokenizer()` + + +⚠️ เพื่อให้ได้ประโยชน์สูงสุดจากคุณลักษณะเด่นทั้งหมดที่มีใน Model Hub และ 🤗 Transformers, เราแนะนำให้คุณ สร้างบัญชี. + \ No newline at end of file From 0e39d95a82226560446cfd637064b0d538f7c83d Mon Sep 17 00:00:00 2001 From: lewtun Date: Wed, 13 Apr 2022 22:01:24 +0200 Subject: [PATCH 73/73] Add Hindi to CI (#116) --- .github/workflows/build_documentation.yml | 2 +- .github/workflows/build_pr_documentation.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_documentation.yml b/.github/workflows/build_documentation.yml index 8e0f0b7e9..1b7f31778 100644 --- a/.github/workflows/build_documentation.yml +++ b/.github/workflows/build_documentation.yml @@ -14,6 +14,6 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: ar bn en es fa fr he ko pt ru th tr zh + languages: ar bn en es fa fr he hi ko pt ru th tr zh secrets: token: ${{ secrets.HUGGINGFACE_PUSH }} \ No newline at end of file diff --git a/.github/workflows/build_pr_documentation.yml b/.github/workflows/build_pr_documentation.yml index ff5039db9..2e3c06441 100644 --- a/.github/workflows/build_pr_documentation.yml +++ b/.github/workflows/build_pr_documentation.yml @@ -16,5 +16,5 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: ar bn en es fa fr he ko pt ru th tr zh + languages: ar bn en es fa fr he hi ko pt ru th tr zh hub_base_path: https://moon-ci-docs.huggingface.co/course