# پشت صحنه خط تولید

{#if fw === 'pt'}

<CourseFloatingBanner chapter={2}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/fa/chapter2/section2_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/fa/chapter2/section2_pt.ipynb"},
]} />

{:else}

<CourseFloatingBanner chapter={2}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/fa/chapter2/section2_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/fa/chapter2/section2_tf.ipynb"},
]} />

{/if}

<Tip>
این اولین بخشی است که محتوای آن بسته به اینکه از پایتورچ یا تِنسورفِلو استفاده می‌کنید کمی متفاوت است. از سویچ بالای صفحه برای انتخاب پلتفرمی که ترجیح می‌دهید استفاده کنید!
</Tip>


{#if fw === 'pt'}
<Youtube id="1pedAIvTWXk"/>
{:else}
<Youtube id="wVN12smEvqg"/>
{/if}

بگذارید با یک مثال کامل شروع کنیم. نگاهی می‌اندازیم به آنچه در پشت صحنه در اثر اجرای این قطعه کد در [فصل اول](/course/chapter1) رخ داد:

<div dir="ltr">

```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!",
    ]
)
```

</div>

این خروجی را دریافت کردیم:

<div dir="ltr">

```python out
[{'label': 'POSITIVE', 'score': 0.9598047137260437},
 {'label': 'NEGATIVE', 'score': 0.9994558095932007}]
```

</div>


همان طور که در در فصل اول دیدیم، این خط تولید از سه مرحله تشکیل شده است: پیش‌پردازش، پردازش ورودی‌ها در مدل و پس‌پردازش.

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/full_nlp_pipeline.svg" alt="The full NLP pipeline: tokenization of text, conversion to IDs, and inference through the Transformer model and the model head."/>
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/full_nlp_pipeline-dark.svg" alt="The full NLP pipeline: tokenization of text, conversion to IDs, and inference through the Transformer model and the model head."/>
</div>

به صورت خلاصه هرکدام از این مراحل را بررسی می‌کنیم.

## پیش‌پردازش با توکِنایزر

مثل شبکه‌های عصبی دیگر، مدل‌های ترنسفورمر هم نمی‌توانند نوشته خام را پردازش کنند. پس اولین قدم در خط تولید ما، تبدیل نوشته خام ورودی به اعدادی است که مدل قادر به فهم آنها باشد. برای این کار از یک *توکِنایزر* استفاده می‌کنیم، که مسئولیت‌های زیر را بر عهده دارد:

- شکستن نوشته به کلمات، زیرکلمات و علامت‌ها (مانند علائم نگارشی) که به آنها ‌*توکِن* می‌گوییم.
- انتخاب عدد صحیح معادل برای هر توکِن.
- اضافه‌کردن ورودی‌های دیگری که ممکن است برای مدل مفید باشند.

همه مراحل این پیش‌پردازش باید دقیقا همان طور که قبلا هنگام تعلیم مدل انجام شده، دنبال شوند. این اطلاعات در [هاب مدل‌ها](https://huggingface.co/models) موجود است و توسط تابع <span dir="ltr">`from_pretrained()`</span> از کلاس `AutoTokenizer` دانلود می‌شود. با استفاده از نام کامل مدل که شامل نقطه تعلیم است، این تابع به صورت خودکار داده‌های توکِنایزر مدل را دریافت نموده و در سیستم شما ذخیره می‌کند. به این ترتیب این داده‌ها فقط بار اولی که کد زیر را اجرا می‌کنید دانلود می‌شوند.

خط تولید `تحلیل احساسات` نقطه تعلیم پیش‌فرضی به نام `distilbert-base-uncased-finetuned-sst-2-english` دارد. صفحه توضیحات این مدل را می‌توانید در [اینجا مشاهده کنید](https://huggingface.co/distilbert-base-uncased-finetuned-sst-2-english). با اجرای کد زیر آن را دانلود می‌کنیم:




<div dir="ltr">

```python
from transformers import AutoTokenizer

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
```

</div>

پس از دریافت توکِنایزر، می‌توانیم جملات خود را مستقیماً وارد آن کنیم و دیکشنری خروجی را دریافت کنیم که آماده است تا به عنوان ورودی مدل مورد استفاده قرار گیرد! تنها کار باقی مانده، تبدیل لیست شناسه‌های ورودی به تِنسور است.

شما می‌توانید از ترنسفورمرهای هاگینگ‌فِیس بدون اطلاع از اینکه کدام فریمورک یادگیری ماشین در پشت صحنه درگیر می‌شود استفاده کنید. ممکن است از پایتورچ، تِنسورفِلو یا حتی فلَکس برای بعضی مدل‌ها استفاده شده باشد. با این وجود، مدل‌های ترسفورمر فقط *تِنسور*‌ها را به عنوان ورودی قبول می‌کنند. اگر این بار اولی است که کلمه تِنسور را می‌شنوید، تصور کنید مانند آرایه‌های NumPy هستند. این آرایه‌ها می‌توانند عددی (تک بُعدی)، برداری (یک بُعدی)، ماتریس (دو بُعدی) یا با ابعاد بیشتر باشند. آن‌ها در واقع تِنسور هستند و تِنسورها در فریمورک‌های یادگیری ماشین رفتاری شبیه به آرایه‌های NumPy دارند و به همان سادگی هم ساخته می‌شوند.

برای مشخص کردن نوع تِنسوری که می‌خواهیم به عنوان خروجی دریافت کنیم (پایتورچ، تِنسورفِلو یا NumPy ساده)، از آرگومان `return_tensors` استفاده می‌کنیم:

<div dir="ltr">

{#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}

</div>


هنوز لازم نیست نگران آرگومان‌های `padding` و `truncation` باشید؛ زیرا بعدتر به آنها خواهیم پرداخت. مسئله اصلی که باید به به خاطر بسپارید، امکان دادن جمله یا آرایه‌ای از جمله‌ها به عنوان ورودی و مشخص کردن نوع تِنسورهای خروجی است. اگر نوع خروجی را مشخص نکنید، لیستی از لیست‌ها را دریافت خواهید کرد.

{#if fw === 'pt'}

خروجی تِنسورهای پایتورچ به این شکل است:

<div dir="ltr">

```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]
    ])
}
```

</div>

{:else}

خروجی تِنسورهای تِنسورفِلو به این شکل است:

<div dir="ltr">

```python out
{
    'input_ids': <tf.Tensor: shape=(2, 16), dtype=int32, numpy=
        array([
            [  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]
        ], dtype=int32)>,
    'attention_mask': <tf.Tensor: shape=(2, 16), dtype=int32, numpy=
        array([
            [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]
        ], dtype=int32)>
}
```

</div>

{/if}


خروجی یک دیکشنری با دو کلید `input_ids` و `attention_mask` است. `input_ids` دو ردیف عدد صحیح (یک ردیف برای هر جمله) است که شناسه‌های منحصر به فرد توکِن‌های هر جمله هستند. `attention_mask` را بعدتر در همین فصل توضیح خواهیم داد.

## گذر از مدل

{#if fw === 'pt'}

می‌توانیم مدل از پیش تعلیم دیده را، همانند آن چه در مورد توکِنایزر انجام شد، دانلود کنیم. ترنسوفورمرهای هاگینگ‌فِیس کلاس `AutoModel` را ارا‌ئه می‌دهد که آن هم تابعی به نام <span dir="ltr">`from_pretrained()`</span> دارد:

<div dir="ltr">

```python
from transformers import AutoModel

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = AutoModel.from_pretrained(checkpoint)
```

</div>

{:else}

می‌توانیم مدل از پیش تعلیم دیده را، همانند آنچه در مورد توکِنایزر انجام شد، دانلود کنیم. ترنسوفورمرهای هاگینگ‌فِیس کلاس `TFAutoModel` را ارا‌ئه می‌دهد که آن هم تابعی به نام <span dir="ltr">`from_pretrained()`</span> دارد:

<div dir="ltr">

```python
from transformers import TFAutoModel

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = TFAutoModel.from_pretrained(checkpoint)
```

</div>

{/if}

در این قطعه کد، همان نقطه تعلیمی که  قبلا در خط تولید استفاده کردیم را دانلود کرده و مدلی جدید بر اساس آن می‌سازیم. این نقطه تعلیم احتمالا قبلا دانلود شده و در سیستم شما موجود است؛ پس نیازی به دانلود مجدد ندارد.

این معماری تنها شامل ماژول پایهٔ ترنسفورمر است: با دریافت ورودی،‌ تنها *وضعیت پنهان* را در خروجی تحویل می‌دهد. به این وضعیت‌های پنهان، *فیچر* هم می‌گوییم. برای هر ورودی مدل، برداری با بُعد بالا دریافت می‌کنیم که معادل «درک کلی مدل ترنسفورمر از آن ورودی» است.

نگران نباشید اگر درک این مفاهیم سخت است. همه آنها را بعدتر توضیح خواهیم داد.

با وجود آنکه وضعیت‌های پنهان به خودی خود هم مفید هستند، آن‌ها معمولا ورودی بخش دیگری از مدل به نام *سَر مدل* هستند. در [فصل اول](/course/chapter1)، می‌توانستیم همه مسائل مختلف را توسط تنها یک معماری حل کنیم، و سپس خروجی را به سر متفاوتی در ادامه مدل پاس بدهیم.

### بردار‌های با بُعد بالا؟

خروجی ماژول `Transformer` معمولا تِنسوری بزرگ است که اکثراً سه بُعد دارد:

- **اندازه بتچ**: تعداد رشته‌های مورد پردازش در یک دسته، که در مثال ما دو عدد است.
- **طول رشته**: تعداد بردار‌های عددی معادل هر رشته‌، که در مثال ما ۱۶ است.
- **اندازه پنهان**: ابعاد بردار نماینده هر ورودی مدل.

به خاطر همین مقدار آخر به این تِنسور «بُعد بالا» می‌گوییم. اندازه پنهان می‌تواند بسیار بزرگ باشد (معمولا ۷۶۸ برای مدل‌های کوچک‌تر، و در مدل‌های بزرگ‌تر این عدد به ۳۰۷۲ یا بیشتر هم می‌رسد).

با پاس دادن ورودی‌های پیش‌پردازش شده به مدل خود می‌توانیم این تِنسور را ببینیم:

<div dir="ltr">


{#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}


</div>


توجه کنید که خروجی‌های ترنسفورمرهای هاگینگ‌فِیس، رفتاری شبیه `namedtuple`‌ یا دیکشنری‌ دارند. شما می‌توانید به هر عضو، با استفاده از نامش (مانند آنچه ما انجام دادیم) یا با کلیدش (`outputs["last_hidden_state"]`) یا حتی اگر دقیقاً از مکان آن اطلاع دارید با اندیس‌اش (`outputs[0]`) دسترسی پیدا کنید.

### سَر مدل: درک اعداد درون مدل

قسمت سَر، بردارهای بُعد بالای وضعیت پنهان را به عنوان ورودی می‌پذیرد و آنها را به بُعدی دیگر می‌برد. سَرها معمولا از یک یا چند لایه خطی تشکیل شده‌اند.


<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/transformer_and_head.svg" alt="A Transformer network alongside its head."/>
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/transformer_and_head-dark.svg" alt="A Transformer network alongside its head."/>
</div>

خروجی مدل ترنسفورمر، مستقیماً به سَر مدل برای پردازش پاس داده می‌شود. در این نمودار، مدل ترنسفورمر به لایه embeddings و لایه‌های بعدی آن تقسیم شده است. لایه embeddings هر شناسه ورودی در ورودی توکِن‌شده را به یک بردار که نماینده آن توکِن است تبدیل می‌کند. لایه‌های بعدی با دستکاری در این بردار‌ها توسط مکانیزم توجه، شکل پایانی بردار نماینده جملات را تولید می‌کنند.

تعداد زیادی از معماری‌‌های مختلف در ترنسفورمر‌های هاگینگ‌فِیس موجود است و هرکدام برای حل یک مسئله خاص طراحی شده‌اند. در این‌جا فهرست کوتاهی از‌ آنها را می‌آوریم:

- `*Model` (برای دسترسی به وضعیت‌های پنهان)
- `*ForCausalLM`
- `*ForMaskedLM`
- `*ForMultipleChoice`
- `*ForQuestionAnswering`
- `*ForSequenceClassification`
- `*ForTokenClassification`
- و نمونه‌های دیگر در ‌هاگینگ‌فِیس

{#if fw === 'pt'}
برای این مثال، نیازمند مدلی با سَر مخصوص دسته‌بندی رشته‌ها (برای تشخیص منفی یا مثبت بودن جملات) هستیم. پس به جای کلاس `AutoModel` از کلاس `AutoModelForSequenceClassification` استفاده می‌کنیم:

<div dir="ltr">

```python
from transformers import AutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)
outputs = model(**inputs)
```

</div>

{:else}
برای این مثال، نیازمند مدلی با سَر مخصوص دسته‌بندی رشته‌ها (برای تشخیص منفی یا مثبت بودن جملات) هستیم. پس به جای کلاس `TFAutoModel` از کلاس `TFAutoModelForSequenceClassification` استفاده می‌کنیم:

<div dir="ltr">

```python
from transformers import TFAutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint)
outputs = model(inputs)
```

</div>

{/if}


اگر نگاهی به شکل ورودی‌ها بیاندازیم، خواهیم دید که حالا تعداد ابعاد آنها بسیار کمتر است: قسمت سَر مدل، بردارهای بُعد بالایی که قبلا دیدیم را به عنوان ورودی دریافت کرده و در خروجی خود، بردارهایی با دو عضو (یکی به ازای هر برچسب دسته‌بندی) تولید می‌کند.

<div dir="ltr">


```python
print(outputs.logits.shape)
```

{#if fw === 'pt'}
```python out
torch.Size([2, 2])
```
{:else}
```python out
(2, 2)
```

{/if}

</div>

از آنجا که ما تنها دو جمله و دو برچسب ممکن داشتیم، خروجی مدل ما شکل ۲ در ۲ دارد.

## پس‌پردازش خروجی

مقادیری که به عنوان خروجی از مدل‌ دریافت می‌کنیم به خودی خود قابل درک نیستند. بگذارید نگاهی به آن‌ها بیندازیم:

<div dir="ltr">


```python
print(outputs.logits)
```

{#if fw === 'pt'}
```python out
tensor([[-1.5607,  1.6123],
        [ 4.1692, -3.3464]], grad_fn=<AddmmBackward>)
```
{:else}
```python out
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
    array([[-1.5606991,  1.6122842],
           [ 4.169231 , -3.3464472]], dtype=float32)>
```
{/if}

</div>



پیش‌بینی مدل ما برای جمله اول <span dir="ltr">`[-1.5607, 1.6123]`</span> و برای جمله دوم <span dir="ltr">`[4.1692, -3.3464]`</span> است. این‌ خروجی‌ها مقادیر آماری نیستند. به این مقادیر *لوجیت* می‌گوییم. مقادیری خام و نرمال‌نشده که خروجی آخرین لایه مدل هستند. برای تبدیل به مقادیر آماری باید این مقادیر را از یک لایه‌ [سافت‌مکس](https://en.wikipedia.org/wiki/Softmax_function) بگذرانیم. تمام ترنسفورمرهای هاگینگ‌فِیس در خروجی لوجیت تولید می‌کنند زیرا معمولا تابع هزینه مورد استفاده در تعلیم مدل، آخرین تابع فعال‌سازی (مانند سافت‌مکس‌) را با تابع هزینه مدل (مانند آنتروپی متقابل) ترکیب می‌کند.


<div dir="ltr">

{#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=<SoftmaxBackward>)
```
{:else}
```python out
tf.Tensor(
[[4.01951671e-02 9.59804833e-01]
 [9.9945587e-01 5.4418424e-04]], shape=(2, 2), dtype=float32)
```
{/if}

</div>


حالا می‌ببینیم که پیش‌بینی مدل برای جمله اول <span dir="ltr">`[0.0402, 0.9598]`</span> و برای جمله دوم <span dir="ltr">`[0.9995, 0.0005]`</span> است. این‌ها مقادیر آشنای آماری (به فرم احتمال) هستند.

برای تبدیل این مقادیر به برچسب دسته تشخیص داده شده می‌توانیم از ویژگی `id2label` تنظیمات مدل استفاده کنیم (در بخش بعدی بیشتر در این مورد صحبت خواهیم کرد):


<div dir="ltr">

```python
model.config.id2label
```

```python out
{0: 'NEGATIVE', 1: 'POSITIVE'}
```

</div>

اکنون مشخص است که پیش‌بینی‌های مدل از این قرار هستند:

- جمله اول: NEGATIVE: 0.0402, POSITIVE: 0.9598
- جمله دوم: NEGATIVE: 0.9995, POSITIVE: 0.0005


ما با موفقیت سه مرحله خط تولید را در اینجا نشان دادیم: پیش‌پردازش توسط توکِنایزرها، گذر ورودی‌ها از مدل و پس‌پردازش! اکنون زمان آن فرا رسیده که به شکلی عمیق‌تر وارد هر یک از این مراحل شویم.

<Tip>

✏️ **خودتان امتحان کنید!** دو نوشته از خودتان (یا حتی بیشتر) را از خط تولید `sentiment-analysis` بگذرانید. سپس مراحلی که در اینجا دیدیم را تکرار کنید و بررسی کنید که نتایج همان هستند!

</Tip>

</div>



<EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/fa/chapter2/2.mdx" />